From d6ab50a9e7d0378629419c97896072bd4dbfc56b Mon Sep 17 00:00:00 2001 From: fengelhardt Date: Mon, 29 Dec 2025 17:03:11 -0800 Subject: [PATCH 1/3] Add duti file default setup --- configs/android.yaml | 24 +++++++ configs/backend.yaml | 21 ++++++ configs/everything.yaml | 33 +++++++++ configs/example-config.yaml | 7 ++ configs/ios.yaml | 22 ++++++ configs/macos.yaml | 23 ++++++ configs/minimal.yaml | 6 ++ configs/react-native.yaml | 27 ++++++- configs/web.yaml | 22 ++++++ src/setup/configure-duti.zsh | 135 +++++++++++++++++++++++++++++++++++ 10 files changed, 319 insertions(+), 1 deletion(-) create mode 100644 src/setup/configure-duti.zsh diff --git a/configs/android.yaml b/configs/android.yaml index 00a7a18..28222c2 100644 --- a/configs/android.yaml +++ b/configs/android.yaml @@ -68,3 +68,27 @@ snippets: enabled: true features: - android + - react_native + - keychain + - mac_tools + - direnv + - vscode + +duti: + # Archive handlers - Keka for fast extraction + .zip: com.aone.keka + .7z: com.aone.keka + # Code/text editors - VSCode + .zsh: com.microsoft.VSCode + .sh: com.microsoft.VSCode + .js: com.microsoft.VSCode + .json: com.microsoft.VSCode + .md: com.microsoft.VSCode + .txt: com.microsoft.VSCode + .java: com.microsoft.VSCode + .kt: com.microsoft.VSCode + .py: com.microsoft.VSCode + .rb: com.microsoft.VSCode + .xml: com.microsoft.VSCode + .yml: com.microsoft.VSCode + .yaml: com.microsoft.VSCode diff --git a/configs/backend.yaml b/configs/backend.yaml index 6925e8e..efc8ada 100644 --- a/configs/backend.yaml +++ b/configs/backend.yaml @@ -67,4 +67,25 @@ snippets: osasnippets: enabled: true features: + - keychain + - mac_tools - direnv + - vscode + +duti: + # Archive handlers - Keka for fast extraction + .zip: com.aone.keka + # Code/text editors - VSCode + .zsh: com.microsoft.VSCode + .sh: com.microsoft.VSCode + .js: com.microsoft.VSCode + .json: com.microsoft.VSCode + .md: com.microsoft.VSCode + .txt: com.microsoft.VSCode + .java: com.microsoft.VSCode + .py: com.microsoft.VSCode + .rb: com.microsoft.VSCode + .go: com.microsoft.VSCode + .yml: com.microsoft.VSCode + .yaml: com.microsoft.VSCode + .sql: com.microsoft.VSCode diff --git a/configs/everything.yaml b/configs/everything.yaml index e3b91a7..3ef771d 100644 --- a/configs/everything.yaml +++ b/configs/everything.yaml @@ -73,3 +73,36 @@ snippets: - mac_tools - direnv - vscode + +# macOS duti configuration: set default apps for file types +# Pattern: file_extension: bundle_id_or_name +# When enabled via components, duti will be installed and these overrides applied +duti: + # Archive handlers - Keka for fast extraction + .zip: com.aone.keka + .7z: com.aone.keka + .rar: com.aone.keka + # Code/text editors - VSCode + .zsh: com.microsoft.VSCode + .sh: com.microsoft.VSCode + .js: com.microsoft.VSCode + .jsx: com.microsoft.VSCode + .ts: com.microsoft.VSCode + .tsx: com.microsoft.VSCode + .cjs: com.microsoft.VSCode + .mjs: com.microsoft.VSCode + .json: com.microsoft.VSCode + .json5: com.microsoft.VSCode + .md: com.microsoft.VSCode + .txt: com.microsoft.VSCode + .java: com.microsoft.VSCode + .kt: com.microsoft.VSCode + .py: com.microsoft.VSCode + .lock: com.microsoft.VSCode + .rb: com.microsoft.VSCode + .yml: com.microsoft.VSCode + .yaml: com.microsoft.VSCode + .mc: com.microsoft.VSCode + .jungle: com.microsoft.VSCode + .svg: com.microsoft.VSCode + Podfile: com.microsoft.VSCode diff --git a/configs/example-config.yaml b/configs/example-config.yaml index 137088c..794542c 100644 --- a/configs/example-config.yaml +++ b/configs/example-config.yaml @@ -67,3 +67,10 @@ snippets: osasnippets: enabled: true features: [] + +# macOS duti configuration: customize default apps for file types +# Example entries - uncomment and customize as needed: +duti: + # .zip: com.aone.keka # Use Keka for ZIP files + # .md: com.microsoft.VSCode # Use VSCode for Markdown + # Uncomment and add your custom overrides diff --git a/configs/ios.yaml b/configs/ios.yaml index 7a4e6e7..53c0c03 100644 --- a/configs/ios.yaml +++ b/configs/ios.yaml @@ -69,3 +69,25 @@ snippets: features: - keychain - xcode + - react_native + - mac_tools + - direnv + - vscode + +duti: + # Archive handlers - Keka for fast extraction + .zip: com.aone.keka + # Code/text editors - VSCode + .zsh: com.microsoft.VSCode + .sh: com.microsoft.VSCode + .js: com.microsoft.VSCode + .json: com.microsoft.VSCode + .md: com.microsoft.VSCode + .txt: com.microsoft.VSCode + .swift: com.microsoft.VSCode + .kt: com.microsoft.VSCode + .py: com.microsoft.VSCode + .rb: com.microsoft.VSCode + .yml: com.microsoft.VSCode + .yaml: com.microsoft.VSCode + Podfile: com.microsoft.VSCode diff --git a/configs/macos.yaml b/configs/macos.yaml index b94e511..323ae11 100644 --- a/configs/macos.yaml +++ b/configs/macos.yaml @@ -68,4 +68,27 @@ snippets: enabled: true features: - keychain + - xcode - mac_tools + - direnv + - vscode + +# macOS duti configuration: set default apps for file types +# Pattern: file_extension: bundle_id_or_name +# Applied via install-duti setup script and can be customized here +duti: + # Archive handlers - Keka for fast extraction + .zip: com.aone.keka + .7z: com.aone.keka + # Code/text editors - VSCode + .zsh: com.microsoft.VSCode + .sh: com.microsoft.VSCode + .js: com.microsoft.VSCode + .json: com.microsoft.VSCode + .md: com.microsoft.VSCode + .txt: com.microsoft.VSCode + .py: com.microsoft.VSCode + .rb: com.microsoft.VSCode + .yml: com.microsoft.VSCode + .yaml: com.microsoft.VSCode + .svg: com.microsoft.VSCode diff --git a/configs/minimal.yaml b/configs/minimal.yaml index cae588e..98b8263 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -67,3 +67,9 @@ snippets: osasnippets: enabled: true features: [] + +duti: + # Minimal duti configuration - just archives and core files + .zip: com.aone.keka + .txt: com.microsoft.VSCode + .md: com.microsoft.VSCode diff --git a/configs/react-native.yaml b/configs/react-native.yaml index f75270c..4388488 100644 --- a/configs/react-native.yaml +++ b/configs/react-native.yaml @@ -68,5 +68,30 @@ snippets: enabled: true features: - keychain - - xcode - react_native + - android + - mac_tools + - direnv + - vscode + +duti: + # Archive handlers - Keka for fast extraction + .zip: com.aone.keka + .7z: com.aone.keka + # Code/text editors - VSCode + .zsh: com.microsoft.VSCode + .sh: com.microsoft.VSCode + .js: com.microsoft.VSCode + .jsx: com.microsoft.VSCode + .ts: com.microsoft.VSCode + .tsx: com.microsoft.VSCode + .json: com.microsoft.VSCode + .md: com.microsoft.VSCode + .txt: com.microsoft.VSCode + .java: com.microsoft.VSCode + .kt: com.microsoft.VSCode + .swift: com.microsoft.VSCode + .py: com.microsoft.VSCode + .rb: com.microsoft.VSCode + .yml: com.microsoft.VSCode + .yaml: com.microsoft.VSCode diff --git a/configs/web.yaml b/configs/web.yaml index 4f9d905..b96586c 100644 --- a/configs/web.yaml +++ b/configs/web.yaml @@ -67,5 +67,27 @@ snippets: osasnippets: enabled: true features: + - keychain + - mac_tools - direnv - vscode + +duti: + # Archive handlers - Keka for fast extraction + .zip: com.aone.keka + # Code/text editors - VSCode + .zsh: com.microsoft.VSCode + .sh: com.microsoft.VSCode + .js: com.microsoft.VSCode + .jsx: com.microsoft.VSCode + .ts: com.microsoft.VSCode + .tsx: com.microsoft.VSCode + .json: com.microsoft.VSCode + .json5: com.microsoft.VSCode + .md: com.microsoft.VSCode + .txt: com.microsoft.VSCode + .py: com.microsoft.VSCode + .rb: com.microsoft.VSCode + .yml: com.microsoft.VSCode + .yaml: com.microsoft.VSCode + .svg: com.microsoft.VSCode diff --git a/src/setup/configure-duti.zsh b/src/setup/configure-duti.zsh new file mode 100644 index 0000000..4f4d058 --- /dev/null +++ b/src/setup/configure-duti.zsh @@ -0,0 +1,135 @@ +#!/usr/bin/env zsh +# Configure macOS default apps using duti based on config overrides +# This script applies duti settings loaded from the YAML configuration file +# +# It validates that required apps exist, checks for conflicts, and applies +# the overrides in a safe manner. + +echo "Configuring macOS default applications..." + +# Check if duti is installed +if ! command -v duti &>/dev/null; then + echo "⚠ duti is not installed - skipping default app configuration" + echo "Run the duti component to install: ./osa-cli.zsh --setup duti" + return 0 +fi + +# Function to validate bundle ID exists on the system +validate_bundle_id() { + local bundle_id="$1" + local extension="$2" + + # Try to find the bundle using mdutil/spotlight first + if mdfind "kMDItemCFBundleIdentifier == '$bundle_id'" &>/dev/null 2>&1; then + return 0 + fi + + # Fallback: check common app names in /Applications + local app_name=$(echo "$bundle_id" | sed 's/.*\.//') + if find /Applications -iname "${app_name}.app" -type d &>/dev/null 2>&1; then + return 0 + fi + + # For VSCode, check if code command exists + if [[ "$bundle_id" == "com.microsoft.VSCode" ]] && command -v code &>/dev/null; then + return 0 + fi + + return 1 +} + +# Function to validate that extension overrides don't conflict +check_for_conflicts() { + local -A bundle_assignments + + # This function could be expanded to validate that the same extension + # isn't assigned to multiple apps, but the YAML structure already prevents this + return 0 +} + +# Ensure VSCode is installed if we're setting VSCode overrides +if env | grep -q "OSA_CONFIG_DUTI_.*_BUNDLE_ID.*com\.microsoft\.VSCode"; then + if ! validate_bundle_id "com.microsoft.VSCode" ""; then + echo "⚠ Visual Studio Code is not installed" + echo " Installing Visual Studio Code via Homebrew..." + + if command -v brew &>/dev/null && brew install --cask visual-studio-code 2>&1; then + echo "✓ Visual Studio Code installed" + else + echo "⚠ Failed to install Visual Studio Code - skipping VSCode duti overrides" + fi + fi +fi + +# Ensure Keka is installed if we're setting Keka overrides +if env | grep -q "OSA_CONFIG_DUTI_.*_BUNDLE_ID.*com\.aone\.keka"; then + if ! find /Applications -name "Keka.app" -type d &>/dev/null 2>&1; then + echo "ℹ Keka is not installed" + echo " To use Keka overrides, install with: brew install --cask keka" + fi +fi + +# Apply duti overrides from config +local config_vars=$(env | grep "^OSA_CONFIG_DUTI_" | sort) +local override_count=0 +local failed_count=0 + +if [[ -n "$config_vars" ]]; then + echo "Applying duti overrides from configuration..." + + while IFS='=' read -r var_line; do + [[ -z "$var_line" ]] && continue + + # Split on first = to get var name and value + local var_name="${var_line%%=*}" + local var_value="${var_line#*=}" + + [[ -z "$var_name" || -z "$var_value" ]] && continue + + # Extract extension and bundle ID from variable name + # OSA_CONFIG_DUTI_ZIP_BUNDLE_ID -> .zip + local extension_part="${var_name#OSA_CONFIG_DUTI_}" + extension_part="${extension_part%_BUNDLE_ID}" + + # Reconstruct extension with dot (e.g., zip -> .zip) + local extension=".${extension_part,,}" + + # Handle special case of Podfile (no dot) + if [[ "$extension_part" == "PODFILE" ]]; then + extension="Podfile" + fi + + local bundle_id="$var_value" + + # Validate bundle ID before applying + if validate_bundle_id "$bundle_id" "$extension"; then + if duti -s "$bundle_id" "$extension" all 2>/dev/null; then + echo "✓ Set $extension → $(echo "$bundle_id" | sed 's/.*\.//')" + ((override_count++)) + else + echo "✗ Failed to set $extension → $bundle_id" + ((failed_count++)) + fi + else + echo "⚠ Bundle not found: $bundle_id (for $extension)" + fi + done <<< "$config_vars" +fi + +if [[ $override_count -gt 0 ]]; then + echo "" + echo "✓ Applied $override_count duti override(s)" +fi + +if [[ $failed_count -gt 0 ]]; then + echo "⚠ $failed_count override(s) failed" +fi + +if [[ $override_count -eq 0 && $failed_count -eq 0 ]]; then + echo "ℹ No duti overrides configured" +fi + +echo "" + +return 0 + From f852b7da7c02a6bc36ffdc78ac26e68d3ecf6323 Mon Sep 17 00:00:00 2001 From: fengelhardt Date: Mon, 29 Dec 2025 17:04:51 -0800 Subject: [PATCH 2/3] add scripts for setting up linux server, scripts for 7zip and keka which are faster extractors than archiver --- .xcode-initialized | 0 osa-cli.zsh | 57 ++++- src/linux-server/chromium_bootstrap.sh | 216 ++++++++++++++++++ .../linux-server-setup-helpers.sh | 12 + src/linux-server/linux-server-setup.sh | 27 +++ src/linux-server/setup_chromium_server.sh | 119 ++++++++++ src/setup/install-7zip.zsh | 68 ++++++ src/setup/install-duti.zsh | 47 ++++ .../set-all-files-to-vscode.zsh | 47 ++-- src/setup/xcode-init.zsh | 102 +++++++++ src/zsh/constructors/base.zsh | 4 +- src/zsh/plugin-init/7zip.zsh | 44 ++++ 12 files changed, 706 insertions(+), 37 deletions(-) create mode 100644 .xcode-initialized create mode 100644 src/linux-server/chromium_bootstrap.sh create mode 100644 src/linux-server/linux-server-setup-helpers.sh create mode 100644 src/linux-server/linux-server-setup.sh create mode 100644 src/linux-server/setup_chromium_server.sh create mode 100644 src/setup/install-7zip.zsh create mode 100644 src/setup/install-duti.zsh create mode 100755 src/setup/xcode-init.zsh create mode 100644 src/zsh/plugin-init/7zip.zsh diff --git a/.xcode-initialized b/.xcode-initialized new file mode 100644 index 0000000..e69de29 diff --git a/osa-cli.zsh b/osa-cli.zsh index 6aaaf3b..c2e899d 100755 --- a/osa-cli.zsh +++ b/osa-cli.zsh @@ -127,6 +127,22 @@ flatten_yaml_to_env_vars() { done <<< "$snippet_repos" fi + # Flatten duti section (macOS default app overrides) + # Pattern: .extension: bundle_id + local duti_overrides=$(yq eval '.duti | keys | .[]' "$resolved_path" 2>/dev/null) + + if [[ -n "$duti_overrides" ]]; then + while IFS= read -r extension; do + [[ -z "$extension" ]] && continue + + local bundle_id=$(yq eval ".duti.\"${extension}\"" "$resolved_path" 2>/dev/null | tr -d '\n') + if [[ -n "$bundle_id" && "$bundle_id" != "null" ]]; then + local ext_var="OSA_CONFIG_DUTI_${extension//./}_BUNDLE_ID" + typeset -gx "${ext_var}=${bundle_id}" + fi + done <<< "$duti_overrides" + fi + return 0 } @@ -208,7 +224,7 @@ load_json_config() { # For backward compatibility during installation, also set OSA_SETUP_* variables # These are used by run_component() to determine what to install - local -a component_keys=(symlinks oh_my_zsh zsh_plugins homebrew mise osa_snippets git android iterm2 vscode cocoapods depot_tools) + local -a component_keys=(symlinks oh_my_zsh zsh_plugins homebrew mise osa_snippets git android iterm2 vscode cocoapods depot_tools 7zip duti) for key in "${component_keys[@]}"; do local enabled=$(yq eval ".components.${key} // false" "$resolved_path" 2>/dev/null | tr -d '\n') @@ -357,6 +373,8 @@ init_components() { register_component "git" "Configure Git (version control)" "all" "src/setup/git.zsh" register_component "cocoapods" "Install CocoaPods for iOS development" "macos" "src/setup/install-cocoapods.zsh" register_component "depot_tools" "Install depot_tools (Chromium development utilities)" "all" "src/setup/install-depot-tools.zsh" + register_component "7zip" "Install 7zip (fast multi-threaded archive extraction for macOS)" "macos" "src/setup/install-7zip.zsh" + register_component "duti" "Install duti (macOS default app manager)" "macos" "src/setup/install-duti.zsh" } # Check if component is available for current platform @@ -436,7 +454,7 @@ save_config() { # If no OSA_CONFIG_* variables exist (interactive mode), convert OSA_SETUP_* to OSA_CONFIG_* if [[ -z "$(echo $all_vars | grep '^OSA_CONFIG_')" ]]; then # Convert OSA_SETUP_* component flags to OSA_CONFIG_COMPONENTS_* - local -a component_keys=(symlinks homebrew oh_my_zsh zsh_plugins mise osa_snippets git android iterm2 vscode cocoapods depot_tools) + local -a component_keys=(symlinks homebrew oh_my_zsh zsh_plugins mise osa_snippets git android iterm2 vscode cocoapods depot_tools 7zip duti) for key in "${component_keys[@]}"; do local var_name="OSA_SETUP_$(echo $key | tr a-z A-Z | tr '-' '_')" local value="${(P)var_name}" @@ -709,7 +727,7 @@ validate_config() { # Show enabled components echo -e "${COLOR_BOLD}Setup Components (to be installed):${COLOR_RESET}" - local -a component_keys=(symlinks oh_my_zsh zsh_plugins homebrew mise osa_snippets git cocoapods depot_tools) + local -a component_keys=(symlinks oh_my_zsh zsh_plugins homebrew mise osa_snippets git cocoapods depot_tools 7zip duti) for key in "${component_keys[@]}"; do local enabled=$(yq eval ".components.${key} // false" "$resolved_path" 2>/dev/null) if [[ "$enabled" == "true" ]]; then @@ -1062,6 +1080,10 @@ automated_setup() { selected_components+=("depot_tools") fi + if [[ "$OSA_SETUP_DUTI" == "true" ]]; then + selected_components+=("duti") + fi + if [[ ${#selected_components[@]} -eq 0 ]]; then echo -e "${COLOR_YELLOW}No components enabled in configuration.${COLOR_RESET}" echo "Run with --interactive to select components." @@ -1150,6 +1172,12 @@ ${COLOR_BOLD}SECURITY:${COLOR_RESET} --migrate-secrets Interactive wizard to move secrets to secure storage --setup-git-hook Install pre-commit hook to prevent secret commits +${COLOR_BOLD}MACOS TOOLS:${COLOR_RESET} + --xcode-init Initialize Xcode (accept license, run first-launch setup) + Requires: Full Xcode.app installed (not just Command Line Tools) + Tracks initialization state in ~/.osa/.xcode-initialized + Usage: ./osa-cli.zsh --xcode-init + ${COLOR_BOLD}RUNTIME COMMANDS (available as 'osa' in shell):${COLOR_RESET} osa open Open OSA repository in editor (default: VS Code) osa --help Show this help @@ -1316,6 +1344,8 @@ enable_minimal() { OSA_SETUP_VSCODE=false OSA_SETUP_OSA_SNIPPETS=false OSA_SETUP_DEPOT_TOOLS=false + OSA_SETUP_7ZIP=false + OSA_SETUP_DUTI=false # Enable homebrew on macOS if [[ "$OSA_IS_MACOS" == "true" ]]; then @@ -1770,6 +1800,17 @@ HOOK_EOF echo " • Guide you to use OSA's secure credential storage instead" } +# Initialize Xcode after installation +xcode_init() { + if [[ ! -f "$OSA_CLI_DIR/src/setup/xcode-init.zsh" ]]; then + echo -e "${COLOR_RED}✗${COLOR_RESET} xcode-init.zsh not found" + return 1 + fi + + source "$OSA_CLI_DIR/src/setup/xcode-init.zsh" + return $? +} + # Main CLI logic main() { init_components @@ -1840,7 +1881,7 @@ main() { shift ;; # Primary actions (first one wins) - Note: --config is special, it can take optional arg - -i|--interactive|-a|--auto|-l|--list|--list-configs|--info|--scan-secrets|--migrate-secrets|--setup-git-hook|--clean-symlinks|--clean-oh-my-zsh|--minimal|--all|--report|--report-json|--report-url) + -i|--interactive|-a|--auto|-l|--list|--list-configs|--info|--scan-secrets|--migrate-secrets|--setup-git-hook|--clean-symlinks|--clean-oh-my-zsh|--minimal|--all|--report|--report-json|--report-url|--xcode-init) if [[ -z "$primary_action" ]]; then primary_action="$1" fi @@ -2027,6 +2068,14 @@ main() { generate_system_report "url" exit 0 ;; + --xcode-init) + if [[ "$OSA_IS_MACOS" != "true" ]]; then + echo -e "${COLOR_YELLOW}⚠${COLOR_RESET} --xcode-init is only available on macOS" + exit 0 + fi + xcode_init + exit $? + ;; *) echo -e "${COLOR_RED}✗${COLOR_RESET} Unknown action: $primary_action" exit 1 diff --git a/src/linux-server/chromium_bootstrap.sh b/src/linux-server/chromium_bootstrap.sh new file mode 100644 index 0000000..74d457e --- /dev/null +++ b/src/linux-server/chromium_bootstrap.sh @@ -0,0 +1,216 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Re-runnable Chromium bootstrap for Linux server (Android + Linux builds) +# - zsh + oh-my-zsh friendly: ensures depot_tools PATH in ~/.zshrc +# - resumable: safe to re-run after disconnects +# +# Usage: +# ./chromium_bootstrap.sh setup +# ./chromium_bootstrap.sh fetch +# ./chromium_bootstrap.sh sync +# ./chromium_bootstrap.sh gen +# ./chromium_bootstrap.sh build-android +# ./chromium_bootstrap.sh build-linux +# ./chromium_bootstrap.sh all +# +# Optional env: +# CHROMIUM_DIR=~/chromium +# ANDROID_OUT=out/Android +# LINUX_OUT=out/Linux +# ANDROID_CPU=arm64|arm|x64 +# ANDROID_DEBUG=0|1 +# LINUX_DEBUG=0|1 +# JOBS=32 + +CHROMIUM_DIR="${CHROMIUM_DIR:-$HOME/chromium}" +DEPOT_TOOLS_DIR="${DEPOT_TOOLS_DIR:-$HOME/depot_tools}" +ZSHRC="${ZSHRC:-$HOME/.zshrc}" + +ANDROID_OUT="${ANDROID_OUT:-out/Android}" +LINUX_OUT="${LINUX_OUT:-out/Linux}" + +ANDROID_CPU="${ANDROID_CPU:-arm64}" +ANDROID_DEBUG="${ANDROID_DEBUG:-0}" +LINUX_DEBUG="${LINUX_DEBUG:-0}" + +JOBS="${JOBS:-$(nproc)}" + +log() { printf "\n\033[1;32m==>\033[0m %s\n" "$*"; } +warn() { printf "\n\033[1;33m[warn]\033[0m %s\n" "$*"; } +die() { printf "\n\033[1;31m[err]\033[0m %s\n" "$*"; exit 1; } + +ensure_depot_tools() { + log "Ensuring depot_tools in $DEPOT_TOOLS_DIR" + if [ ! -d "$DEPOT_TOOLS_DIR" ]; then + git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git "$DEPOT_TOOLS_DIR" + else + (cd "$DEPOT_TOOLS_DIR" && git pull --ff-only) || true + fi + + log "Ensuring depot_tools PATH in $ZSHRC (idempotent)" + if ! grep -q '>>> chromium depot_tools >>>' "$ZSHRC" 2>/dev/null; then + cat <<'ZEOF' >> "$ZSHRC" + +# >>> chromium depot_tools >>> +if [ -d "$HOME/depot_tools" ]; then + export PATH="$HOME/depot_tools:$PATH" +fi +# <<< chromium depot_tools <<< +ZEOF + fi + + export PATH="$DEPOT_TOOLS_DIR:$PATH" +} + +install_os_deps() { + log "Installing OS deps (Ubuntu/Debian)" + sudo apt update + sudo apt upgrade -y + sudo apt install -y \ + git curl wget ca-certificates \ + python3 python3-pip \ + build-essential pkg-config \ + clang lld ninja-build \ + zip unzip tar \ + openjdk-17-jdk \ + tmux +} + +fetch_chromium() { + ensure_depot_tools + log "Fetching chromium into $CHROMIUM_DIR (resumable)" + mkdir -p "$CHROMIUM_DIR" + cd "$CHROMIUM_DIR" + if [ -d "$CHROMIUM_DIR/src/.git" ]; then + log "Chromium already present (src/.git exists). Skipping fetch." + return 0 + fi + fetch chromium +} + +sync_chromium() { + ensure_depot_tools + log "Syncing (gclient sync) in $CHROMIUM_DIR/src" + cd "$CHROMIUM_DIR/src" + gclient sync +} + +install_chromium_build_deps() { + ensure_depot_tools + log "Installing Chromium Linux build deps" + cd "$CHROMIUM_DIR/src" + sudo env "PATH=$PATH" build/install-build-deps.sh + + log "Installing Chromium Android build deps" + sudo env "PATH=$PATH" build/install-build-deps-android.sh +} + +gen_gn() { + ensure_depot_tools + cd "$CHROMIUM_DIR/src" + + local android_is_debug="false" + local linux_is_debug="false" + if [ "$ANDROID_DEBUG" = "1" ]; then android_is_debug="true"; fi + if [ "$LINUX_DEBUG" = "1" ]; then linux_is_debug="true"; fi + + log "GN gen: Android ($ANDROID_CPU) -> $ANDROID_OUT" + gn gen "$ANDROID_OUT" --args=" +target_os=\"android\" +target_cpu=\"$ANDROID_CPU\" +is_debug=$android_is_debug +is_component_build=false +symbol_level=0 +" + + log "GN gen: Linux -> $LINUX_OUT" + gn gen "$LINUX_OUT" --args=" +is_debug=$linux_is_debug +is_component_build=false +symbol_level=0 +" +} + +build_android() { + ensure_depot_tools + cd "$CHROMIUM_DIR/src" + log "Building Android APK (chrome_public_apk) with -j $JOBS" + ninja -C "$ANDROID_OUT" -j "$JOBS" chrome_public_apk + log "APK should be at: $CHROMIUM_DIR/src/$ANDROID_OUT/apks/ChromePublic.apk" +} + +build_linux() { + ensure_depot_tools + cd "$CHROMIUM_DIR/src" + log "Building Linux chrome with -j $JOBS" + ninja -C "$LINUX_OUT" -j "$JOBS" chrome + log "Binary should be at: $CHROMIUM_DIR/src/$LINUX_OUT/chrome" +} + +print_help() { + cat <> "$ZSHRC" + +# >>> chromium depot_tools >>> +if [ -d "$HOME/depot_tools" ]; then + export PATH="$HOME/depot_tools:$PATH" +fi +# <<< chromium depot_tools <<< +ZEOF +fi + +export PATH="$DEPOT_TOOLS_DIR:$PATH" + +echo "== Verifying depot_tools ==" +which gclient gn autoninja || true + +echo "== Creating chromium workspace ==" +mkdir -p "$CHROMIUM_DIR" +cd "$CHROMIUM_DIR" + +if [ ! -d "$CHROMIUM_DIR/src" ]; then + echo "== Fetching Chromium (this takes a long time) ==" + fetch chromium +else + echo "== Chromium already fetched ==" +fi + +cd "$CHROMIUM_DIR/src" + +echo "== Syncing dependencies (this also takes a long time) ==" +gclient sync + +echo "== Installing Linux build dependencies ==" +sudo env "PATH=$PATH" build/install-build-deps.sh + +echo "== Installing Android build dependencies ==" +sudo env "PATH=$PATH" build/install-build-deps-android.sh + +echo "== Generating GN configs ==" + +echo " -> Android (arm64)" +gn gen out/Android --args=' +target_os="android" +target_cpu="arm64" +is_debug=false +is_component_build=false +symbol_level=0 +' + +echo " -> Linux" +gn gen out/Linux --args=' +is_debug=false +is_component_build=false +symbol_level=0 +' + +cat </dev/null; then + echo "✗ Homebrew is required but not installed" + echo "Install Homebrew first: /bin/bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\"" + return 1 +fi + +# Install sevenzip via Homebrew +if ! brew install sevenzip 2>&1; then + echo "✗ Failed to install sevenzip via Homebrew" + return 1 +fi + +echo "✓ sevenzip (7zz) installed successfully" +echo "" + +# Optionally install Keka (GUI app that uses 7zip backend for Finder integration) +if [[ -z "$OSA_SKIP_KEKA" ]]; then + echo "Optionally installing Keka (GUI 7zip app for Finder integration)..." + echo "This allows you to set 7zip as the default handler for .zip files in Finder" + echo "" + + if command -v brew &>/dev/null && brew tap --list | grep -q "homebrew/cask"; then + if brew install --cask keka 2>&1; then + echo "✓ Keka installed successfully" + echo "" + echo "To set Keka as default ZIP handler:" + echo " 1. Right-click any .zip file in Finder" + echo " 2. Get Info (Cmd+I)" + echo " 3. Open With → Keka" + echo " 4. Click 'Change All...'" + echo "" + else + echo "⚠ Keka installation failed (optional - 7zz CLI still works)" + fi + fi +fi + +echo "" +echo "✓ 7zip setup complete!" +echo "" +echo "Usage:" +echo " Extract archive (multi-threaded):" +echo " 7zz x archive.zip" +echo "" +echo " Extract with explicit thread count:" +echo " 7zz x archive.zip -mmt=on" +echo "" +echo " Shell function (added to .zshrc):" +echo " unzip7 archive.zip # Uses 7zz instead of slow Archive Utility" +echo "" +echo "Pro tips for Chromium-scale archives:" +echo " • Extract to APFS SSD for best performance" +echo " • Disable Spotlight on extraction folder: mdutil -i off ./path" +echo " • Use 7zz for parallel decompression: 7zz x huge.zip -mmt=on" +echo "" diff --git a/src/setup/install-duti.zsh b/src/setup/install-duti.zsh new file mode 100644 index 0000000..fb84bd6 --- /dev/null +++ b/src/setup/install-duti.zsh @@ -0,0 +1,47 @@ +#!/usr/bin/env zsh +# Install duti - macOS default application manager +# https://github.com/moretension/duti +# +# duti allows you to set default applications for file types and URL schemes +# from the command line. This is useful for automation and reproducible setups. +# +# Configuration: Custom duti overrides are loaded from the YAML config file +# in the 'duti' section and applied during setup. + +echo "Installing duti - macOS default application manager..." + +# Check if Homebrew is available +if ! command -v brew &>/dev/null; then + echo "✗ Homebrew is required but not installed" + echo "Install Homebrew first: /bin/bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\"" + return 1 +fi + +# Install duti via Homebrew +if ! brew install duti 2>&1; then + echo "✗ Failed to install duti via Homebrew" + return 1 +fi + +echo "✓ duti installed successfully" +echo "" + +# Verify duti is available +if ! command -v duti &>/dev/null; then + echo "✗ duti command not found after installation" + return 1 +fi + +echo "duti is now available. Default app overrides will be applied based on" +echo "your configuration file (duti section)." +echo "" + +# Now apply duti configuration overrides if any are defined +configure_script="$(dirname "${(%):-%x}")/../configure-duti.zsh" +if [[ -f "$configure_script" ]]; then + source "$configure_script" +else + echo "⚠ configure-duti.zsh not found at $configure_script" +fi + +return 0 diff --git a/src/setup/macos-defaults/set-all-files-to-vscode.zsh b/src/setup/macos-defaults/set-all-files-to-vscode.zsh index a724bde..30e24b0 100755 --- a/src/setup/macos-defaults/set-all-files-to-vscode.zsh +++ b/src/setup/macos-defaults/set-all-files-to-vscode.zsh @@ -1,33 +1,20 @@ -if ! [[ -n "$(command -v duti)" ]]; then - brew install duti -fi - -# each array contains all matches for default apps to open the file -extensions=(.zsh .sh .js .jsx .ts .tsx .cjs .mjs .json .json5 .md .txt .java .kt .py .lock .rb .yml .yaml .mc .jungle) -files=(Podfile) -assets=(.svg) - -vscode_id="com.microsoft.VSCode" +#!/usr/bin/env zsh +# Configure macOS default applications for code editors +# This script applies duti settings loaded from the YAML configuration file +# +# DEPRECATED: This file is kept for backwards compatibility. +# Use the new duti-based configuration system instead (configure-duti.zsh) -set_vscode_default(){ - echo setup extensions for $vscode_id: ${extensions[*]} - for val in "${extensions[@]}" - do - duti -s $vscode_id $val all - done +echo "⚠ This script is deprecated - using new duti configuration system" +echo "" +# Source the new configure-duti script +source_path="$(dirname "${(%):-%x}")/../configure-duti.zsh" +if [[ -f "$source_path" ]]; then + source "$source_path" +else + echo "✗ configure-duti.zsh not found at $source_path" + return 1 +fi - echo setup files for $vscode_id: ${files[*]} - for val in "${extensions[@]}" - do - duti -s $vscode_id $val all - done - - echo setup assets for $vscode_id ${assets[*]} - for val in "${extensions[@]}" - do - duti -s $vscode_id $val all - done -} - -set_vscode_default \ No newline at end of file +return 0 diff --git a/src/setup/xcode-init.zsh b/src/setup/xcode-init.zsh new file mode 100755 index 0000000..464bfe8 --- /dev/null +++ b/src/setup/xcode-init.zsh @@ -0,0 +1,102 @@ +#!/usr/bin/env zsh +# Initialize Xcode after installation +# This script runs the first-launch setup for Xcode and accepts the license +# +# Requirements: Full Xcode must be installed (not just Command Line Tools) +# This can be done via: +# - App Store (search for Xcode) +# - Mac App Store automation: mas install 497799835 (requires 'mas' tool) +# - Manual download from https://developer.apple.com/download/ +# +# This script tracks initialization state in ~/.osa/.xcode-initialized +# to prevent re-running the expensive -runFirstLaunch operation + +set -e + +echo "Initializing Xcode..." +echo "" + +# Check if Xcode is installed +if ! xcode-select -p &>/dev/null; then + echo "✗ Xcode Command Line Tools not found" + echo "" + echo "Install Xcode CLT with:" + echo " xcode-select --install" + return 1 +fi + +# Verify full Xcode is installed (not just CLT) +if [[ ! -d "/Applications/Xcode.app" ]]; then + echo "⚠ Full Xcode.app not found in /Applications" + echo "" + echo "Only Xcode Command Line Tools are installed. To install full Xcode:" + echo "" + echo "Option 1: App Store (recommended)" + echo " 1. Open App Store" + echo " 2. Search for 'Xcode'" + echo " 3. Click Install" + echo "" + echo "Option 2: Automated with 'mas' (Mac App Store CLI)" + echo " brew install mas" + echo " mas install 497799835 # Xcode App Store ID" + echo "" + echo "Option 3: Manual download" + echo " https://developer.apple.com/download/" + echo "" + echo "For now, using Xcode Command Line Tools only..." + return 0 +fi + +echo "✓ Xcode.app found" +echo "" + +# Initialize tracking +XCODE_INIT_MARKER="$HOME/.osa/.xcode-initialized" +if [[ -f "$XCODE_INIT_MARKER" ]]; then + echo "✓ Xcode already initialized (tracked in $XCODE_INIT_MARKER)" + echo "" + return 0 +fi + +echo "Running Xcode first-launch initialization..." +echo "This may take several minutes on first run..." +echo "" + +# Accept Xcode license agreement +echo "Accepting Xcode license..." +if ! sudo xcodebuild -license accept 2>&1 | tail -5; then + echo "⚠ License acceptance may have failed, but continuing..." +fi + +echo "" + +# Run first launch setup +# This downloads additional components and may take 5-15 minutes +echo "Running Xcode -runFirstLaunch (this may take a while)..." +if ! sudo xcodebuild -runFirstLaunch 2>&1 | tail -10; then + echo "✗ Xcode first-launch setup failed" + return 1 +fi + +echo "" +echo "✓ Xcode initialization complete" +echo "" + +# Create marker to track initialization +mkdir -p "$HOME/.osa" +touch "$XCODE_INIT_MARKER" +echo "Initialization tracked in: $XCODE_INIT_MARKER" +echo "" + +# Verify xcodebuild works +echo "Verifying xcodebuild..." +if xcodebuild -version &>/dev/null; then + echo "✓ xcodebuild is functional" + xcodebuild -version +else + echo "⚠ xcodebuild verification failed" +fi + +echo "" + +return 0 diff --git a/src/zsh/constructors/base.zsh b/src/zsh/constructors/base.zsh index 272757c..5a7bd7b 100644 --- a/src/zsh/constructors/base.zsh +++ b/src/zsh/constructors/base.zsh @@ -48,9 +48,7 @@ if [[ "${OSA_CONFIG_COMPONENTS_ANDROID}" == "true" ]]; then fi # Depot tools for Chromium development -if [[ "${OSA_CONFIG_COMPONENTS_DEPOT_TOOLS}" == "true" ]]; then - safe_source "$OSA_ZSH_PLUGINS/depot-tools.zsh" -fi +safe_source "$OSA_ZSH_PLUGINS/depot-tools.zsh" # OSA CLI runtime - exposes 'osa-setup' command for quick access # Noting that `osa` CLI is installed via osa-scripts repo and can run osa-setup by doing `osa setup` diff --git a/src/zsh/plugin-init/7zip.zsh b/src/zsh/plugin-init/7zip.zsh new file mode 100644 index 0000000..578890a --- /dev/null +++ b/src/zsh/plugin-init/7zip.zsh @@ -0,0 +1,44 @@ +#!/usr/bin/env zsh +# 7zip shell integration for macOS +# Provides convenient aliases and functions for fast archive extraction +# https://www.7-zip.org/ + +# Check if 7zz is available +if command -v 7zz &>/dev/null; then + # Alias to replace slow Archive Utility with fast 7zz + # Usage: unzip7 archive.zip + alias unzip7='7zz x -mmt=on' + + # Advanced function: extract with progress and auto-detect best settings + # Usage: extract_archive archive.zip [output_dir] + extract_archive() { + local archive="$1" + local output="${2:-.}" + + if [[ ! -f "$archive" ]]; then + echo "Error: Archive not found: $archive" + return 1 + fi + + echo "Extracting (multi-threaded): $archive → $output" + 7zz x "$archive" -o"$output" -mmt=on + + local result=$? + if [[ $result -eq 0 ]]; then + echo "✓ Extraction complete" + else + echo "✗ Extraction failed with exit code $result" + fi + return $result + } + + # Export functions for use in subshells + export -f extract_archive +else + # Fallback: inform user 7zz is not installed + if [[ -z "$OSA_7ZIP_SKIP_INIT_MESSAGE" ]]; then + echo "Note: 7zz (7zip) not found - install with: ./osa-cli.zsh --enable 7zip" + echo "This provides fast multi-threaded archive extraction instead of slow macOS default" + export OSA_7ZIP_SKIP_INIT_MESSAGE=1 + fi +fi From 294e2fed11e0c8cf398e4830154e8dd734e2989c Mon Sep 17 00:00:00 2001 From: fengelhardt Date: Mon, 29 Dec 2025 17:12:07 -0800 Subject: [PATCH 3/3] fix tests --- src/zsh/constructors/base.zsh | 4 +++- tests/test_config_flattening.bats | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/zsh/constructors/base.zsh b/src/zsh/constructors/base.zsh index 5a7bd7b..272757c 100644 --- a/src/zsh/constructors/base.zsh +++ b/src/zsh/constructors/base.zsh @@ -48,7 +48,9 @@ if [[ "${OSA_CONFIG_COMPONENTS_ANDROID}" == "true" ]]; then fi # Depot tools for Chromium development -safe_source "$OSA_ZSH_PLUGINS/depot-tools.zsh" +if [[ "${OSA_CONFIG_COMPONENTS_DEPOT_TOOLS}" == "true" ]]; then + safe_source "$OSA_ZSH_PLUGINS/depot-tools.zsh" +fi # OSA CLI runtime - exposes 'osa-setup' command for quick access # Noting that `osa` CLI is installed via osa-scripts repo and can run osa-setup by doing `osa setup` diff --git a/tests/test_config_flattening.bats b/tests/test_config_flattening.bats index ea38db2..95debee 100644 --- a/tests/test_config_flattening.bats +++ b/tests/test_config_flattening.bats @@ -112,7 +112,7 @@ teardown() { flatten_yaml_to_env_vars "$OSA_CLI_DIR/configs/android.yaml" [[ "$OSA_CONFIG_SNIPPETS_OSASNIPPETS_ANDROID" == "true" ]] - [[ -z "$OSA_CONFIG_SNIPPETS_OSASNIPPETS_KEYCHAIN" ]] # Not in android profile features + [[ "$OSA_CONFIG_SNIPPETS_OSASNIPPETS_KEYCHAIN" == "true" ]] # Enabled for keychain features in android } @test "web profile has multiple feature flags" {