559 lines
17 KiB
PowerShell
Raw Normal View History

feat: Add complete Nushell full distribution system ## Major Features Added - **Complete distribution infrastructure**: Build, package, and distribute Nushell binary alongside plugins - **Zero-prerequisite installation**: Bootstrap installers work on fresh systems without Rust/Cargo/Nushell - **Cross-platform support**: Linux, macOS, Windows (x86_64, ARM64) - **Self-contained packages**: Everything needed for complete Nushell environment ## New Components ### Build System - `scripts/build_nushell.nu` - Build nushell with all workspace plugins - `scripts/collect_full_binaries.nu` - Collect nu binary + all plugins - `justfiles/full_distro.just` - 40+ new recipes for distribution workflows ### Bootstrap Installers (Zero Prerequisites) - `installers/bootstrap/install.sh` - Universal POSIX installer (900+ lines) - `installers/bootstrap/install.ps1` - Windows PowerShell installer (800+ lines) - Complete platform detection, PATH setup, plugin registration ### Distribution System - `scripts/create_distribution_packages.nu` - Multi-platform package creator - `scripts/install_full_nushell.nu` - Advanced nu-based installer - `scripts/verify_installation.nu` - Installation verification suite - `scripts/lib/common_lib.nu` - Shared utilities and logging ### Configuration Management - `scripts/templates/default_config.nu` - Complete nushell configuration (500+ lines) - `scripts/templates/default_env.nu` - Cross-platform environment setup - `etc/distribution_config.toml` - Central distribution settings - `scripts/templates/uninstall.sh` & `uninstall.ps1` - Clean removal ## Key Workflows ```bash just build-full # Build nushell + all plugins just pack-full-all # Create packages for all platforms just verify-full # Verify installation just release-full-cross # Complete cross-platform release ``` ## Installation Experience - One-liner: `curl -sSf https://your-url/install.sh | sh` - Multiple modes: user, system, portable installation - Automatic plugin registration with verification - Professional uninstall capability ## Benefits - ✅ Solves bootstrap problem - no prerequisites needed - ✅ Production-ready distribution system - ✅ Complete cross-platform support - ✅ Professional installation experience - ✅ Integrates seamlessly with existing plugin workflows - ✅ Enterprise-grade verification and logging
2025-09-24 18:52:07 +01:00
# Universal Nushell + Plugins Uninstaller for Windows
# PowerShell script that cleanly removes Nushell and plugins installation
#
# This script:
# - Detects installation locations (user or system Program Files)
# - Removes Nushell binary and plugin binaries
# - Cleans up configuration files (with backup option)
# - Removes PATH entries from environment variables
# - Unregisters plugins from Nushell
# - Provides detailed removal report
param(
[switch]$Help,
[switch]$Yes,
[switch]$KeepConfig,
[switch]$BackupConfig,
[switch]$System,
[switch]$User,
# Summary feat: bootstrap installer with robust archive extraction, version mismatch handling, and improved PATH messaging ## Detailed Description This commit implements a production-ready bootstrap installer with comprehensive error handling, version-agnostic archive extraction, and clear user messaging. All improvements follow DRY principles using symlink-based architecture for single-source-of-truth maintenance. ## Major Changes (Session 2025-10-19) ### 0. Bootstrap Installer & Distribution Improvements (NEW) #### 0a. Install Script Architecture - DRY Design **Issue**: Code duplication across installation paths - `./install.sh`, `./scripts/templates/install.sh`, `installers/bootstrap/install.sh` were separate copies - Changes required updating multiple files - Risk of divergence and inconsistency **Solution**: Implemented symlink-based DRY architecture - Single source of truth: `installers/bootstrap/install.sh` (1,247 lines) - Symlinks created: - `./install.sh` → `installers/bootstrap/install.sh` - `./scripts/templates/install.sh` → `installers/bootstrap/install.sh` - All changes automatically propagate through symlinks - No code duplication **Impact**: - ✅ Single maintenance point for all install scripts - ✅ Consistent behavior across all paths - ✅ Reduced maintenance burden - ✅ No divergence risk #### 0b. Archive Extraction - Version-Agnostic Binary Detection **Issue**: "No Nushell binary found in extracted archive" - Script failed when extracting from `nushell-full-0.108.0-darwin-arm64.tar.gz` - Error occurred even though binaries were present at `nushell-full-0.108.0/bin/nu` **Root Cause**: `find` command returning parent directory itself in results ```bash # ❌ OLD - find returns parent directory first local extracted=$(find "$extract_dir" -maxdepth 1 -type d -name "nushell-*" | head -1) # Returns: /tmp/nushell-install-22919/nushell-extract (parent!) # Should return: /tmp/nushell-install-22919/nushell-extract/nushell-full-0.108.0 (subdirectory) ``` **Solution**: Added `-not -path` to exclude starting directory ```bash # ✅ NEW - exclude parent directory local extracted=$(find "$extract_dir" -maxdepth 1 -type d -name "nushell-*" -not -path "$extract_dir" | head -1) # Now correctly returns the subdirectory ``` **Additional Improvements**: - 4-level fallback detection strategy: 1. Check `$extracted/bin/nu` (subdirectory structure) 2. Check `$extracted/nu` (flat structure) 3. Fallback search for any `nushell-*` subdirectory with `bin/nu` 4. Last resort recursive search for any executable named `nu` - Validates binaries exist before using them - Clear error reporting with all search locations **Version-Agnostic**: - Uses `nushell-*` pattern (not hardcoded version numbers) - Works with any Nushell version: 0.107, 0.108, 0.109, etc. - Supports both `.tar.gz` and `.zip` archive formats **Impact**: - ✅ Archive extraction works reliably - ✅ Works with any Nushell version - ✅ Clear error messages guide users - ✅ Multiple archive structure support #### 0c. Plugin Registration - Version Mismatch Handling **Issue**: Plugin registration failed with version incompatibility errors ``` Error: nu::shell::plugin_failed_to_load × Plugin `polars` is compiled for nushell version 0.107.1, which is not compatible with version 0.108.0 ``` **Solution**: Implemented intelligent error classification - Captures both stdout and stderr from plugin add commands - Detects version incompatibility: "is not compatible with version" or "is compiled for nushell version" - Classifies errors into three categories: 1. **Success**: Plugin registered successfully ✅ 2. **Incompatible**: Version mismatch (skipped gracefully) ⚠️ 3. **Failed**: Other registration failures ❌ - Reports summary with counts of each category - Installation continues successfully even with version mismatches **New Error Reporting**: ``` ✅ Registered nu_plugin_auth ⚠️ Skipping nu_plugin_polars: Version mismatch (built for different Nushell version) ✅ Successfully registered 13 plugins ⚠️ Skipped 1 incompatible plugins (version mismatch): - nu_plugin_polars ``` **Impact**: - ✅ No installation failures due to version mismatches - ✅ Users informed of incompatible plugins - ✅ Clear distinction between error types - ✅ Installation completes successfully #### 0d. Shell Configuration PATH Update - Clear Messaging **Issue**: Confusing PATH update messages - User sees: "PATH already updated" for all files - Then sees: "No shell configuration files were updated" warning - Then sees: "Please manually add to your PATH" error - **Problem**: Contradictory messages when PATH is already configured everywhere **Root Cause**: Script conflated two states - State 1: "Was PATH found in files?" (skips updating if found) - State 2: "Did we add PATH to any file?" (used for messaging) - Both states ignored means no update was made, but PATH might already exist **Solution**: Track two separate states ```bash local updated=false # Was PATH ADDED to any file? local path_found=false # Was PATH FOUND in any file? # In loop: if grep -q "$install_dir" "$config_file"; then path_found=true # Found it! Mark as true continue fi # After loop: if [ "$updated" = "true" ]; then log_success "Shell configuration updated" elif [ "$path_found" = "true" ]; then log_success "PATH is already configured in your shell configuration files" else log_warn "Could not find or update shell configuration" fi ``` **New Clear Messages**: - ✅ "PATH is already configured in your shell configuration files" (when found everywhere) - ✅ "Shell configuration updated" (when just added) - ⚠️ "Could not find or update shell configuration" (when file missing) **Impact**: - ✅ Non-contradictory messages - ✅ Users understand what happened - ✅ No false warnings when PATH already configured - ✅ Clear guidance when manual action needed #### 0e. Installation Features **`--source-path` Option** (Local Installation): - Install from local archive: `./install.sh --source-path archive.tar.gz` - Install from local directory: `./install.sh --source-path /path/to/binaries` - Default behavior: `./install.sh --source-path` uses `./bin_archives` - Works with custom `--install-dir` paths - No download needed, offline installation support **`--uninstall` with Configuration Management**: - Prompts user: "Remove ~/.config/nushell? [y/N]" - Removes all installed binaries and plugins - Preserves user choice for configuration - Clean uninstall before fresh reinstall #### 0f. Documentation Updates **CLAUDE.md**: - Added "Install Script Architecture (DRY Design)" section - Documents source of truth and symlink structure - Explains `--source-path` feature - Shows version-agnostic archive detection - Lists DRY architecture benefits **README.md**: - Added "Install Script Architecture (DRY Design)" subsection - Shows symlink structure with arrows - Provides `--source-path` usage examples - Explains version-agnostic detection - "How DRY Works" 3-step explanation #### 0g. Files Modified Core Changes: - `installers/bootstrap/install.sh` (+3 lines for PATH messaging fix) - Archive extraction fix with `-not -path` - Plugin registration error classification - Clear PATH update messaging - Total: 1,247 lines (unified) Auto-Updated via Symlinks: - `./install.sh` - Auto-updated (1,247 lines) - `./scripts/templates/install.sh` - Auto-updated (1,247 lines) Documentation: - `CLAUDE.md` - Added install architecture section - `README.md` - Added install architecture subsection - `CHANGELOG.md` - Added comprehensive entry (+100 lines) #### 0h. Testing & Verification All scenarios tested and verified: - [x] Archive extraction works with version-agnostic detection - [x] Installation to `~/.local` successful (16 binaries) - [x] Installation to `~/.local/bin` successful (21 plugins loaded) - [x] Plugin registration handles version mismatches gracefully - [x] PATH messaging is clear and non-contradictory - [x] Clean uninstall followed by fresh reinstall works perfectly #### 0i. Impact User-Facing Benefits: - ✅ Users can install from any version of nushell-full archive - ✅ Version mismatch plugins skipped without breaking installation - ✅ Clear, honest error messages - ✅ Non-confusing PATH update messages - ✅ Offline installation support via `--source-path` - ✅ Clean uninstall/reinstall workflow Developer Benefits: - ✅ Single source of truth eliminates code duplication - ✅ Changes propagate automatically through symlinks - ✅ Reduced maintenance burden - ✅ Consistent behavior across all paths - ✅ Production-ready installation process --- ### 1. Help System Integration (New Feature) **Issue**: Version-update module recipes were not discoverable - Not shown in `just help modules` - Not referenced in `just help` - Not included in help navigation system - Users had to manually run `just --list` to find update commands **Solution**: - Added version-update module to all help outputs - Updated `justfiles/help.just` to document all 30+ version-update recipes - Created new `just commands` recipe as discoverable alias for `just --list` - Integrated version-update into help-all workflow **Impact**: - Version-update commands now fully discoverable via help system - Users can find update commands with: `just help modules`, `just help`, `just commands` - Improved overall help system navigation **Files Modified**: - `justfiles/help.just` (+23 lines) - Added version-update module to help sections - Added to modules list - Added to help-all workflow - New `commands` recipe showing all recipes by group ### 2. Build Process Fixes (Phase 3: Bin Archives) #### 2a. Plugin Archive Collection Bug **Issue**: "No plugins found to package" warning in Phase 3 - Collected 26 plugin binaries but reported 0 - Archive creation skipped because count was wrong **Root Cause**: `each` command returns null, so `| length` returned 0 ```nushell # ❌ OLD - each returns null let plugin_count = (ls nu_plugin_*/target/release/nu_plugin_* | each {|p| cp $p.name $"($temp_dir)/" } | length) # Returns 0! ``` **Solution**: Separated counting from copying with proper filtering ```nushell # ✅ NEW - count before operations let plugins_to_copy = (ls nu_plugin_*/target/release/nu_plugin_* | where type == "file") let plugin_count = ($plugins_to_copy | length) ``` **Impact**: - Now correctly collects and reports 26 plugins - Filters out .d dependency files automatically - Warning eliminated #### 2b. Tar Archive Path Handling **Issue**: Tar command failing silently with relative paths in subshell - `cd $temp_dir` changes context unpredictably - Relative path `../$archive_name` fails in subshell - Archive file not created despite exit code 0 **Root Cause**: Shell context and relative path issues in Nushell `do` block **Solution**: Used `tar -C` with absolute paths instead of `cd` ```nushell # ❌ OLD - unreliable context switching do { cd $temp_dir tar -czf ../$archive_name . } # ✅ NEW - absolute paths, no context switching tar -C $temp_dir -czf $archive_path . ``` **Additional Improvements**: - Absolute path construction using `pwd | path join` - Better error diagnostics with exit code and stderr output - File verification after creation **Impact**: - Tar archives now created successfully - Robust path handling across platforms - Clear error messages for debugging #### 2c. File Size Calculation Type Error **Issue**: Runtime error when calculating archive size ``` Error: The '/' operator does not work on values of type 'list<filesize>' ``` **Root Cause**: `ls` returns list of records, so `.size` was a list ```nushell # ❌ OLD - returns list<filesize> (ls $archive_path).size / 1024 / 1024 # ✅ NEW - returns filesize (ls $archive_path | get 0.size) / 1024 / 1024 ``` **Impact**: - Proper file size calculation in MB - No more type errors **Files Modified**: - `scripts/create_full_distribution.nu` (+58 lines, refactored plugin collection) - Fixed plugin counting logic - Improved path handling with absolute paths - Enhanced error diagnostics ### 3. Plugin Rebuild Optimization **Issue**: All plugins marked for rebuild even when dependencies unchanged - Step 4 (`update_all_plugins.nu`) touched all Cargo.toml files at 01:00:32 - Step 5 saw all files as "newer" than binaries - Marked ALL plugins for rebuild, though cargo only rebuilt changed ones **Root Cause**: Script always saved files, even when no changes made ```nushell # ❌ OLD - always saves, touching file timestamp $updated_content | to toml | save -f $cargo_toml ``` **Solution**: Only save if content actually changed ```nushell # ✅ NEW - compare before writing let original_toml = $content | to toml let new_toml = $updated_content | to toml if $original_toml != $new_toml { $updated_content | to toml | save -f $cargo_toml } ``` **Impact**: - Unchanged files preserve original timestamps - Only plugins with actual dependency changes are rebuilt - Efficient rebuild process with accurate file modification detection **Files Modified**: - `scripts/update_all_plugins.nu` (+12 lines, added content comparison) - Only touches files with real changes - Preserves timestamps for efficiency - Clearer logic and comments ### 4. Documentation **Files Modified**: - `CHANGELOG.md` (+56 lines) - Added comprehensive 2025-10-19 entry - Documented all fixes with root causes - Listed files modified and impact summary ## Technical Details ### Nushell Patterns Used 1. **Proper List Handling**: - `ls` returns list of records, access with `| get 0.size` - Filter with `where type == "file"` to exclude metadata 2. **Absolute Path Construction**: - `pwd | append "path" | path join` for cross-platform paths - Safer than string concatenation with `/` 3. **Content Comparison**: - Compare TOML string representation before saving - Preserves file timestamps for efficiency 4. **Error Diagnostics**: - Capture `stderr` from commands - Report exit codes and error messages separately ## Testing - [x] Help system shows version-update module - [x] `just commands` displays all recipes by group - [x] Phase 3 bin archive creation works - [x] Plugin collection reports correct count (26) - [x] Tar archives created successfully - [x] File size calculated correctly - [x] Plugin rebuild only touches changed files - [x] CHANGELOG updated with all changes ## Files Changed ``` 38 files changed, 2721 insertions(+), 2548 deletions(-) Core Changes: - justfiles/help.just (+23) Help system integration - scripts/create_full_distribution.nu (+58) Build process fixes - scripts/update_all_plugins.nu (+12) Rebuild optimization - CHANGELOG.md (+56) Documentation Dependency Updates: - All plugin Cargo.toml and Cargo.lock files (version consistency) ``` ## Breaking Changes None. These are bug fixes and optimizations that maintain backward compatibility. ## Migration Notes No migration needed. Improvements are transparent to users. ## Related Issues - Help system discoverability - Build process Phase 3 failures - Unnecessary plugin rebuilds - Build process reliability ## Checklist - [x] Changes follow Rust/Nushell idioms - [x] Code is well-commented - [x] Error handling is comprehensive - [x] Documentation is updated - [x] All changes tested - [x] No breaking changes introduced
2025-10-19 02:39:31 +01:00
[string]$UninstallDir = "",
feat: Add complete Nushell full distribution system ## Major Features Added - **Complete distribution infrastructure**: Build, package, and distribute Nushell binary alongside plugins - **Zero-prerequisite installation**: Bootstrap installers work on fresh systems without Rust/Cargo/Nushell - **Cross-platform support**: Linux, macOS, Windows (x86_64, ARM64) - **Self-contained packages**: Everything needed for complete Nushell environment ## New Components ### Build System - `scripts/build_nushell.nu` - Build nushell with all workspace plugins - `scripts/collect_full_binaries.nu` - Collect nu binary + all plugins - `justfiles/full_distro.just` - 40+ new recipes for distribution workflows ### Bootstrap Installers (Zero Prerequisites) - `installers/bootstrap/install.sh` - Universal POSIX installer (900+ lines) - `installers/bootstrap/install.ps1` - Windows PowerShell installer (800+ lines) - Complete platform detection, PATH setup, plugin registration ### Distribution System - `scripts/create_distribution_packages.nu` - Multi-platform package creator - `scripts/install_full_nushell.nu` - Advanced nu-based installer - `scripts/verify_installation.nu` - Installation verification suite - `scripts/lib/common_lib.nu` - Shared utilities and logging ### Configuration Management - `scripts/templates/default_config.nu` - Complete nushell configuration (500+ lines) - `scripts/templates/default_env.nu` - Cross-platform environment setup - `etc/distribution_config.toml` - Central distribution settings - `scripts/templates/uninstall.sh` & `uninstall.ps1` - Clean removal ## Key Workflows ```bash just build-full # Build nushell + all plugins just pack-full-all # Create packages for all platforms just verify-full # Verify installation just release-full-cross # Complete cross-platform release ``` ## Installation Experience - One-liner: `curl -sSf https://your-url/install.sh | sh` - Multiple modes: user, system, portable installation - Automatic plugin registration with verification - Professional uninstall capability ## Benefits - ✅ Solves bootstrap problem - no prerequisites needed - ✅ Production-ready distribution system - ✅ Complete cross-platform support - ✅ Professional installation experience - ✅ Integrates seamlessly with existing plugin workflows - ✅ Enterprise-grade verification and logging
2025-09-24 18:52:07 +01:00
[switch]$DryRun,
[switch]$Debug
)
# Configuration
$InstallDirUser = "$env:USERPROFILE\.local\bin"
$InstallDirSystem = "$env:ProgramFiles\nushell"
$ConfigDir = "$env:APPDATA\nushell"
$BackupSuffix = "uninstall-backup-$(Get-Date -Format 'yyyyMMdd_HHmmss')"
# Logging functions
function Write-Info {
param([string]$Message)
Write-Host " $Message" -ForegroundColor Blue
}
function Write-Success {
param([string]$Message)
Write-Host "$Message" -ForegroundColor Green
}
function Write-Warning {
param([string]$Message)
Write-Host "⚠️ $Message" -ForegroundColor Yellow
}
function Write-Error {
param([string]$Message)
Write-Host "$Message" -ForegroundColor Red
}
function Write-Debug {
param([string]$Message)
if ($Debug) {
Write-Host "🐛 DEBUG: $Message" -ForegroundColor Magenta
}
}
# Usage information
function Show-Usage {
Write-Host @"
Nushell Full Distribution Uninstaller for Windows
USAGE:
.\uninstall.ps1 [OPTIONS]
OPTIONS:
-Help Show this help message
-Yes Non-interactive mode (assume yes to prompts)
# Summary feat: bootstrap installer with robust archive extraction, version mismatch handling, and improved PATH messaging ## Detailed Description This commit implements a production-ready bootstrap installer with comprehensive error handling, version-agnostic archive extraction, and clear user messaging. All improvements follow DRY principles using symlink-based architecture for single-source-of-truth maintenance. ## Major Changes (Session 2025-10-19) ### 0. Bootstrap Installer & Distribution Improvements (NEW) #### 0a. Install Script Architecture - DRY Design **Issue**: Code duplication across installation paths - `./install.sh`, `./scripts/templates/install.sh`, `installers/bootstrap/install.sh` were separate copies - Changes required updating multiple files - Risk of divergence and inconsistency **Solution**: Implemented symlink-based DRY architecture - Single source of truth: `installers/bootstrap/install.sh` (1,247 lines) - Symlinks created: - `./install.sh` → `installers/bootstrap/install.sh` - `./scripts/templates/install.sh` → `installers/bootstrap/install.sh` - All changes automatically propagate through symlinks - No code duplication **Impact**: - ✅ Single maintenance point for all install scripts - ✅ Consistent behavior across all paths - ✅ Reduced maintenance burden - ✅ No divergence risk #### 0b. Archive Extraction - Version-Agnostic Binary Detection **Issue**: "No Nushell binary found in extracted archive" - Script failed when extracting from `nushell-full-0.108.0-darwin-arm64.tar.gz` - Error occurred even though binaries were present at `nushell-full-0.108.0/bin/nu` **Root Cause**: `find` command returning parent directory itself in results ```bash # ❌ OLD - find returns parent directory first local extracted=$(find "$extract_dir" -maxdepth 1 -type d -name "nushell-*" | head -1) # Returns: /tmp/nushell-install-22919/nushell-extract (parent!) # Should return: /tmp/nushell-install-22919/nushell-extract/nushell-full-0.108.0 (subdirectory) ``` **Solution**: Added `-not -path` to exclude starting directory ```bash # ✅ NEW - exclude parent directory local extracted=$(find "$extract_dir" -maxdepth 1 -type d -name "nushell-*" -not -path "$extract_dir" | head -1) # Now correctly returns the subdirectory ``` **Additional Improvements**: - 4-level fallback detection strategy: 1. Check `$extracted/bin/nu` (subdirectory structure) 2. Check `$extracted/nu` (flat structure) 3. Fallback search for any `nushell-*` subdirectory with `bin/nu` 4. Last resort recursive search for any executable named `nu` - Validates binaries exist before using them - Clear error reporting with all search locations **Version-Agnostic**: - Uses `nushell-*` pattern (not hardcoded version numbers) - Works with any Nushell version: 0.107, 0.108, 0.109, etc. - Supports both `.tar.gz` and `.zip` archive formats **Impact**: - ✅ Archive extraction works reliably - ✅ Works with any Nushell version - ✅ Clear error messages guide users - ✅ Multiple archive structure support #### 0c. Plugin Registration - Version Mismatch Handling **Issue**: Plugin registration failed with version incompatibility errors ``` Error: nu::shell::plugin_failed_to_load × Plugin `polars` is compiled for nushell version 0.107.1, which is not compatible with version 0.108.0 ``` **Solution**: Implemented intelligent error classification - Captures both stdout and stderr from plugin add commands - Detects version incompatibility: "is not compatible with version" or "is compiled for nushell version" - Classifies errors into three categories: 1. **Success**: Plugin registered successfully ✅ 2. **Incompatible**: Version mismatch (skipped gracefully) ⚠️ 3. **Failed**: Other registration failures ❌ - Reports summary with counts of each category - Installation continues successfully even with version mismatches **New Error Reporting**: ``` ✅ Registered nu_plugin_auth ⚠️ Skipping nu_plugin_polars: Version mismatch (built for different Nushell version) ✅ Successfully registered 13 plugins ⚠️ Skipped 1 incompatible plugins (version mismatch): - nu_plugin_polars ``` **Impact**: - ✅ No installation failures due to version mismatches - ✅ Users informed of incompatible plugins - ✅ Clear distinction between error types - ✅ Installation completes successfully #### 0d. Shell Configuration PATH Update - Clear Messaging **Issue**: Confusing PATH update messages - User sees: "PATH already updated" for all files - Then sees: "No shell configuration files were updated" warning - Then sees: "Please manually add to your PATH" error - **Problem**: Contradictory messages when PATH is already configured everywhere **Root Cause**: Script conflated two states - State 1: "Was PATH found in files?" (skips updating if found) - State 2: "Did we add PATH to any file?" (used for messaging) - Both states ignored means no update was made, but PATH might already exist **Solution**: Track two separate states ```bash local updated=false # Was PATH ADDED to any file? local path_found=false # Was PATH FOUND in any file? # In loop: if grep -q "$install_dir" "$config_file"; then path_found=true # Found it! Mark as true continue fi # After loop: if [ "$updated" = "true" ]; then log_success "Shell configuration updated" elif [ "$path_found" = "true" ]; then log_success "PATH is already configured in your shell configuration files" else log_warn "Could not find or update shell configuration" fi ``` **New Clear Messages**: - ✅ "PATH is already configured in your shell configuration files" (when found everywhere) - ✅ "Shell configuration updated" (when just added) - ⚠️ "Could not find or update shell configuration" (when file missing) **Impact**: - ✅ Non-contradictory messages - ✅ Users understand what happened - ✅ No false warnings when PATH already configured - ✅ Clear guidance when manual action needed #### 0e. Installation Features **`--source-path` Option** (Local Installation): - Install from local archive: `./install.sh --source-path archive.tar.gz` - Install from local directory: `./install.sh --source-path /path/to/binaries` - Default behavior: `./install.sh --source-path` uses `./bin_archives` - Works with custom `--install-dir` paths - No download needed, offline installation support **`--uninstall` with Configuration Management**: - Prompts user: "Remove ~/.config/nushell? [y/N]" - Removes all installed binaries and plugins - Preserves user choice for configuration - Clean uninstall before fresh reinstall #### 0f. Documentation Updates **CLAUDE.md**: - Added "Install Script Architecture (DRY Design)" section - Documents source of truth and symlink structure - Explains `--source-path` feature - Shows version-agnostic archive detection - Lists DRY architecture benefits **README.md**: - Added "Install Script Architecture (DRY Design)" subsection - Shows symlink structure with arrows - Provides `--source-path` usage examples - Explains version-agnostic detection - "How DRY Works" 3-step explanation #### 0g. Files Modified Core Changes: - `installers/bootstrap/install.sh` (+3 lines for PATH messaging fix) - Archive extraction fix with `-not -path` - Plugin registration error classification - Clear PATH update messaging - Total: 1,247 lines (unified) Auto-Updated via Symlinks: - `./install.sh` - Auto-updated (1,247 lines) - `./scripts/templates/install.sh` - Auto-updated (1,247 lines) Documentation: - `CLAUDE.md` - Added install architecture section - `README.md` - Added install architecture subsection - `CHANGELOG.md` - Added comprehensive entry (+100 lines) #### 0h. Testing & Verification All scenarios tested and verified: - [x] Archive extraction works with version-agnostic detection - [x] Installation to `~/.local` successful (16 binaries) - [x] Installation to `~/.local/bin` successful (21 plugins loaded) - [x] Plugin registration handles version mismatches gracefully - [x] PATH messaging is clear and non-contradictory - [x] Clean uninstall followed by fresh reinstall works perfectly #### 0i. Impact User-Facing Benefits: - ✅ Users can install from any version of nushell-full archive - ✅ Version mismatch plugins skipped without breaking installation - ✅ Clear, honest error messages - ✅ Non-confusing PATH update messages - ✅ Offline installation support via `--source-path` - ✅ Clean uninstall/reinstall workflow Developer Benefits: - ✅ Single source of truth eliminates code duplication - ✅ Changes propagate automatically through symlinks - ✅ Reduced maintenance burden - ✅ Consistent behavior across all paths - ✅ Production-ready installation process --- ### 1. Help System Integration (New Feature) **Issue**: Version-update module recipes were not discoverable - Not shown in `just help modules` - Not referenced in `just help` - Not included in help navigation system - Users had to manually run `just --list` to find update commands **Solution**: - Added version-update module to all help outputs - Updated `justfiles/help.just` to document all 30+ version-update recipes - Created new `just commands` recipe as discoverable alias for `just --list` - Integrated version-update into help-all workflow **Impact**: - Version-update commands now fully discoverable via help system - Users can find update commands with: `just help modules`, `just help`, `just commands` - Improved overall help system navigation **Files Modified**: - `justfiles/help.just` (+23 lines) - Added version-update module to help sections - Added to modules list - Added to help-all workflow - New `commands` recipe showing all recipes by group ### 2. Build Process Fixes (Phase 3: Bin Archives) #### 2a. Plugin Archive Collection Bug **Issue**: "No plugins found to package" warning in Phase 3 - Collected 26 plugin binaries but reported 0 - Archive creation skipped because count was wrong **Root Cause**: `each` command returns null, so `| length` returned 0 ```nushell # ❌ OLD - each returns null let plugin_count = (ls nu_plugin_*/target/release/nu_plugin_* | each {|p| cp $p.name $"($temp_dir)/" } | length) # Returns 0! ``` **Solution**: Separated counting from copying with proper filtering ```nushell # ✅ NEW - count before operations let plugins_to_copy = (ls nu_plugin_*/target/release/nu_plugin_* | where type == "file") let plugin_count = ($plugins_to_copy | length) ``` **Impact**: - Now correctly collects and reports 26 plugins - Filters out .d dependency files automatically - Warning eliminated #### 2b. Tar Archive Path Handling **Issue**: Tar command failing silently with relative paths in subshell - `cd $temp_dir` changes context unpredictably - Relative path `../$archive_name` fails in subshell - Archive file not created despite exit code 0 **Root Cause**: Shell context and relative path issues in Nushell `do` block **Solution**: Used `tar -C` with absolute paths instead of `cd` ```nushell # ❌ OLD - unreliable context switching do { cd $temp_dir tar -czf ../$archive_name . } # ✅ NEW - absolute paths, no context switching tar -C $temp_dir -czf $archive_path . ``` **Additional Improvements**: - Absolute path construction using `pwd | path join` - Better error diagnostics with exit code and stderr output - File verification after creation **Impact**: - Tar archives now created successfully - Robust path handling across platforms - Clear error messages for debugging #### 2c. File Size Calculation Type Error **Issue**: Runtime error when calculating archive size ``` Error: The '/' operator does not work on values of type 'list<filesize>' ``` **Root Cause**: `ls` returns list of records, so `.size` was a list ```nushell # ❌ OLD - returns list<filesize> (ls $archive_path).size / 1024 / 1024 # ✅ NEW - returns filesize (ls $archive_path | get 0.size) / 1024 / 1024 ``` **Impact**: - Proper file size calculation in MB - No more type errors **Files Modified**: - `scripts/create_full_distribution.nu` (+58 lines, refactored plugin collection) - Fixed plugin counting logic - Improved path handling with absolute paths - Enhanced error diagnostics ### 3. Plugin Rebuild Optimization **Issue**: All plugins marked for rebuild even when dependencies unchanged - Step 4 (`update_all_plugins.nu`) touched all Cargo.toml files at 01:00:32 - Step 5 saw all files as "newer" than binaries - Marked ALL plugins for rebuild, though cargo only rebuilt changed ones **Root Cause**: Script always saved files, even when no changes made ```nushell # ❌ OLD - always saves, touching file timestamp $updated_content | to toml | save -f $cargo_toml ``` **Solution**: Only save if content actually changed ```nushell # ✅ NEW - compare before writing let original_toml = $content | to toml let new_toml = $updated_content | to toml if $original_toml != $new_toml { $updated_content | to toml | save -f $cargo_toml } ``` **Impact**: - Unchanged files preserve original timestamps - Only plugins with actual dependency changes are rebuilt - Efficient rebuild process with accurate file modification detection **Files Modified**: - `scripts/update_all_plugins.nu` (+12 lines, added content comparison) - Only touches files with real changes - Preserves timestamps for efficiency - Clearer logic and comments ### 4. Documentation **Files Modified**: - `CHANGELOG.md` (+56 lines) - Added comprehensive 2025-10-19 entry - Documented all fixes with root causes - Listed files modified and impact summary ## Technical Details ### Nushell Patterns Used 1. **Proper List Handling**: - `ls` returns list of records, access with `| get 0.size` - Filter with `where type == "file"` to exclude metadata 2. **Absolute Path Construction**: - `pwd | append "path" | path join` for cross-platform paths - Safer than string concatenation with `/` 3. **Content Comparison**: - Compare TOML string representation before saving - Preserves file timestamps for efficiency 4. **Error Diagnostics**: - Capture `stderr` from commands - Report exit codes and error messages separately ## Testing - [x] Help system shows version-update module - [x] `just commands` displays all recipes by group - [x] Phase 3 bin archive creation works - [x] Plugin collection reports correct count (26) - [x] Tar archives created successfully - [x] File size calculated correctly - [x] Plugin rebuild only touches changed files - [x] CHANGELOG updated with all changes ## Files Changed ``` 38 files changed, 2721 insertions(+), 2548 deletions(-) Core Changes: - justfiles/help.just (+23) Help system integration - scripts/create_full_distribution.nu (+58) Build process fixes - scripts/update_all_plugins.nu (+12) Rebuild optimization - CHANGELOG.md (+56) Documentation Dependency Updates: - All plugin Cargo.toml and Cargo.lock files (version consistency) ``` ## Breaking Changes None. These are bug fixes and optimizations that maintain backward compatibility. ## Migration Notes No migration needed. Improvements are transparent to users. ## Related Issues - Help system discoverability - Build process Phase 3 failures - Unnecessary plugin rebuilds - Build process reliability ## Checklist - [x] Changes follow Rust/Nushell idioms - [x] Code is well-commented - [x] Error handling is comprehensive - [x] Documentation is updated - [x] All changes tested - [x] No breaking changes introduced
2025-10-19 02:39:31 +01:00
-KeepConfig Keep configuration files (don't remove config directory)
feat: Add complete Nushell full distribution system ## Major Features Added - **Complete distribution infrastructure**: Build, package, and distribute Nushell binary alongside plugins - **Zero-prerequisite installation**: Bootstrap installers work on fresh systems without Rust/Cargo/Nushell - **Cross-platform support**: Linux, macOS, Windows (x86_64, ARM64) - **Self-contained packages**: Everything needed for complete Nushell environment ## New Components ### Build System - `scripts/build_nushell.nu` - Build nushell with all workspace plugins - `scripts/collect_full_binaries.nu` - Collect nu binary + all plugins - `justfiles/full_distro.just` - 40+ new recipes for distribution workflows ### Bootstrap Installers (Zero Prerequisites) - `installers/bootstrap/install.sh` - Universal POSIX installer (900+ lines) - `installers/bootstrap/install.ps1` - Windows PowerShell installer (800+ lines) - Complete platform detection, PATH setup, plugin registration ### Distribution System - `scripts/create_distribution_packages.nu` - Multi-platform package creator - `scripts/install_full_nushell.nu` - Advanced nu-based installer - `scripts/verify_installation.nu` - Installation verification suite - `scripts/lib/common_lib.nu` - Shared utilities and logging ### Configuration Management - `scripts/templates/default_config.nu` - Complete nushell configuration (500+ lines) - `scripts/templates/default_env.nu` - Cross-platform environment setup - `etc/distribution_config.toml` - Central distribution settings - `scripts/templates/uninstall.sh` & `uninstall.ps1` - Clean removal ## Key Workflows ```bash just build-full # Build nushell + all plugins just pack-full-all # Create packages for all platforms just verify-full # Verify installation just release-full-cross # Complete cross-platform release ``` ## Installation Experience - One-liner: `curl -sSf https://your-url/install.sh | sh` - Multiple modes: user, system, portable installation - Automatic plugin registration with verification - Professional uninstall capability ## Benefits - ✅ Solves bootstrap problem - no prerequisites needed - ✅ Production-ready distribution system - ✅ Complete cross-platform support - ✅ Professional installation experience - ✅ Integrates seamlessly with existing plugin workflows - ✅ Enterprise-grade verification and logging
2025-09-24 18:52:07 +01:00
-BackupConfig Backup configuration before removal
# Summary feat: bootstrap installer with robust archive extraction, version mismatch handling, and improved PATH messaging ## Detailed Description This commit implements a production-ready bootstrap installer with comprehensive error handling, version-agnostic archive extraction, and clear user messaging. All improvements follow DRY principles using symlink-based architecture for single-source-of-truth maintenance. ## Major Changes (Session 2025-10-19) ### 0. Bootstrap Installer & Distribution Improvements (NEW) #### 0a. Install Script Architecture - DRY Design **Issue**: Code duplication across installation paths - `./install.sh`, `./scripts/templates/install.sh`, `installers/bootstrap/install.sh` were separate copies - Changes required updating multiple files - Risk of divergence and inconsistency **Solution**: Implemented symlink-based DRY architecture - Single source of truth: `installers/bootstrap/install.sh` (1,247 lines) - Symlinks created: - `./install.sh` → `installers/bootstrap/install.sh` - `./scripts/templates/install.sh` → `installers/bootstrap/install.sh` - All changes automatically propagate through symlinks - No code duplication **Impact**: - ✅ Single maintenance point for all install scripts - ✅ Consistent behavior across all paths - ✅ Reduced maintenance burden - ✅ No divergence risk #### 0b. Archive Extraction - Version-Agnostic Binary Detection **Issue**: "No Nushell binary found in extracted archive" - Script failed when extracting from `nushell-full-0.108.0-darwin-arm64.tar.gz` - Error occurred even though binaries were present at `nushell-full-0.108.0/bin/nu` **Root Cause**: `find` command returning parent directory itself in results ```bash # ❌ OLD - find returns parent directory first local extracted=$(find "$extract_dir" -maxdepth 1 -type d -name "nushell-*" | head -1) # Returns: /tmp/nushell-install-22919/nushell-extract (parent!) # Should return: /tmp/nushell-install-22919/nushell-extract/nushell-full-0.108.0 (subdirectory) ``` **Solution**: Added `-not -path` to exclude starting directory ```bash # ✅ NEW - exclude parent directory local extracted=$(find "$extract_dir" -maxdepth 1 -type d -name "nushell-*" -not -path "$extract_dir" | head -1) # Now correctly returns the subdirectory ``` **Additional Improvements**: - 4-level fallback detection strategy: 1. Check `$extracted/bin/nu` (subdirectory structure) 2. Check `$extracted/nu` (flat structure) 3. Fallback search for any `nushell-*` subdirectory with `bin/nu` 4. Last resort recursive search for any executable named `nu` - Validates binaries exist before using them - Clear error reporting with all search locations **Version-Agnostic**: - Uses `nushell-*` pattern (not hardcoded version numbers) - Works with any Nushell version: 0.107, 0.108, 0.109, etc. - Supports both `.tar.gz` and `.zip` archive formats **Impact**: - ✅ Archive extraction works reliably - ✅ Works with any Nushell version - ✅ Clear error messages guide users - ✅ Multiple archive structure support #### 0c. Plugin Registration - Version Mismatch Handling **Issue**: Plugin registration failed with version incompatibility errors ``` Error: nu::shell::plugin_failed_to_load × Plugin `polars` is compiled for nushell version 0.107.1, which is not compatible with version 0.108.0 ``` **Solution**: Implemented intelligent error classification - Captures both stdout and stderr from plugin add commands - Detects version incompatibility: "is not compatible with version" or "is compiled for nushell version" - Classifies errors into three categories: 1. **Success**: Plugin registered successfully ✅ 2. **Incompatible**: Version mismatch (skipped gracefully) ⚠️ 3. **Failed**: Other registration failures ❌ - Reports summary with counts of each category - Installation continues successfully even with version mismatches **New Error Reporting**: ``` ✅ Registered nu_plugin_auth ⚠️ Skipping nu_plugin_polars: Version mismatch (built for different Nushell version) ✅ Successfully registered 13 plugins ⚠️ Skipped 1 incompatible plugins (version mismatch): - nu_plugin_polars ``` **Impact**: - ✅ No installation failures due to version mismatches - ✅ Users informed of incompatible plugins - ✅ Clear distinction between error types - ✅ Installation completes successfully #### 0d. Shell Configuration PATH Update - Clear Messaging **Issue**: Confusing PATH update messages - User sees: "PATH already updated" for all files - Then sees: "No shell configuration files were updated" warning - Then sees: "Please manually add to your PATH" error - **Problem**: Contradictory messages when PATH is already configured everywhere **Root Cause**: Script conflated two states - State 1: "Was PATH found in files?" (skips updating if found) - State 2: "Did we add PATH to any file?" (used for messaging) - Both states ignored means no update was made, but PATH might already exist **Solution**: Track two separate states ```bash local updated=false # Was PATH ADDED to any file? local path_found=false # Was PATH FOUND in any file? # In loop: if grep -q "$install_dir" "$config_file"; then path_found=true # Found it! Mark as true continue fi # After loop: if [ "$updated" = "true" ]; then log_success "Shell configuration updated" elif [ "$path_found" = "true" ]; then log_success "PATH is already configured in your shell configuration files" else log_warn "Could not find or update shell configuration" fi ``` **New Clear Messages**: - ✅ "PATH is already configured in your shell configuration files" (when found everywhere) - ✅ "Shell configuration updated" (when just added) - ⚠️ "Could not find or update shell configuration" (when file missing) **Impact**: - ✅ Non-contradictory messages - ✅ Users understand what happened - ✅ No false warnings when PATH already configured - ✅ Clear guidance when manual action needed #### 0e. Installation Features **`--source-path` Option** (Local Installation): - Install from local archive: `./install.sh --source-path archive.tar.gz` - Install from local directory: `./install.sh --source-path /path/to/binaries` - Default behavior: `./install.sh --source-path` uses `./bin_archives` - Works with custom `--install-dir` paths - No download needed, offline installation support **`--uninstall` with Configuration Management**: - Prompts user: "Remove ~/.config/nushell? [y/N]" - Removes all installed binaries and plugins - Preserves user choice for configuration - Clean uninstall before fresh reinstall #### 0f. Documentation Updates **CLAUDE.md**: - Added "Install Script Architecture (DRY Design)" section - Documents source of truth and symlink structure - Explains `--source-path` feature - Shows version-agnostic archive detection - Lists DRY architecture benefits **README.md**: - Added "Install Script Architecture (DRY Design)" subsection - Shows symlink structure with arrows - Provides `--source-path` usage examples - Explains version-agnostic detection - "How DRY Works" 3-step explanation #### 0g. Files Modified Core Changes: - `installers/bootstrap/install.sh` (+3 lines for PATH messaging fix) - Archive extraction fix with `-not -path` - Plugin registration error classification - Clear PATH update messaging - Total: 1,247 lines (unified) Auto-Updated via Symlinks: - `./install.sh` - Auto-updated (1,247 lines) - `./scripts/templates/install.sh` - Auto-updated (1,247 lines) Documentation: - `CLAUDE.md` - Added install architecture section - `README.md` - Added install architecture subsection - `CHANGELOG.md` - Added comprehensive entry (+100 lines) #### 0h. Testing & Verification All scenarios tested and verified: - [x] Archive extraction works with version-agnostic detection - [x] Installation to `~/.local` successful (16 binaries) - [x] Installation to `~/.local/bin` successful (21 plugins loaded) - [x] Plugin registration handles version mismatches gracefully - [x] PATH messaging is clear and non-contradictory - [x] Clean uninstall followed by fresh reinstall works perfectly #### 0i. Impact User-Facing Benefits: - ✅ Users can install from any version of nushell-full archive - ✅ Version mismatch plugins skipped without breaking installation - ✅ Clear, honest error messages - ✅ Non-confusing PATH update messages - ✅ Offline installation support via `--source-path` - ✅ Clean uninstall/reinstall workflow Developer Benefits: - ✅ Single source of truth eliminates code duplication - ✅ Changes propagate automatically through symlinks - ✅ Reduced maintenance burden - ✅ Consistent behavior across all paths - ✅ Production-ready installation process --- ### 1. Help System Integration (New Feature) **Issue**: Version-update module recipes were not discoverable - Not shown in `just help modules` - Not referenced in `just help` - Not included in help navigation system - Users had to manually run `just --list` to find update commands **Solution**: - Added version-update module to all help outputs - Updated `justfiles/help.just` to document all 30+ version-update recipes - Created new `just commands` recipe as discoverable alias for `just --list` - Integrated version-update into help-all workflow **Impact**: - Version-update commands now fully discoverable via help system - Users can find update commands with: `just help modules`, `just help`, `just commands` - Improved overall help system navigation **Files Modified**: - `justfiles/help.just` (+23 lines) - Added version-update module to help sections - Added to modules list - Added to help-all workflow - New `commands` recipe showing all recipes by group ### 2. Build Process Fixes (Phase 3: Bin Archives) #### 2a. Plugin Archive Collection Bug **Issue**: "No plugins found to package" warning in Phase 3 - Collected 26 plugin binaries but reported 0 - Archive creation skipped because count was wrong **Root Cause**: `each` command returns null, so `| length` returned 0 ```nushell # ❌ OLD - each returns null let plugin_count = (ls nu_plugin_*/target/release/nu_plugin_* | each {|p| cp $p.name $"($temp_dir)/" } | length) # Returns 0! ``` **Solution**: Separated counting from copying with proper filtering ```nushell # ✅ NEW - count before operations let plugins_to_copy = (ls nu_plugin_*/target/release/nu_plugin_* | where type == "file") let plugin_count = ($plugins_to_copy | length) ``` **Impact**: - Now correctly collects and reports 26 plugins - Filters out .d dependency files automatically - Warning eliminated #### 2b. Tar Archive Path Handling **Issue**: Tar command failing silently with relative paths in subshell - `cd $temp_dir` changes context unpredictably - Relative path `../$archive_name` fails in subshell - Archive file not created despite exit code 0 **Root Cause**: Shell context and relative path issues in Nushell `do` block **Solution**: Used `tar -C` with absolute paths instead of `cd` ```nushell # ❌ OLD - unreliable context switching do { cd $temp_dir tar -czf ../$archive_name . } # ✅ NEW - absolute paths, no context switching tar -C $temp_dir -czf $archive_path . ``` **Additional Improvements**: - Absolute path construction using `pwd | path join` - Better error diagnostics with exit code and stderr output - File verification after creation **Impact**: - Tar archives now created successfully - Robust path handling across platforms - Clear error messages for debugging #### 2c. File Size Calculation Type Error **Issue**: Runtime error when calculating archive size ``` Error: The '/' operator does not work on values of type 'list<filesize>' ``` **Root Cause**: `ls` returns list of records, so `.size` was a list ```nushell # ❌ OLD - returns list<filesize> (ls $archive_path).size / 1024 / 1024 # ✅ NEW - returns filesize (ls $archive_path | get 0.size) / 1024 / 1024 ``` **Impact**: - Proper file size calculation in MB - No more type errors **Files Modified**: - `scripts/create_full_distribution.nu` (+58 lines, refactored plugin collection) - Fixed plugin counting logic - Improved path handling with absolute paths - Enhanced error diagnostics ### 3. Plugin Rebuild Optimization **Issue**: All plugins marked for rebuild even when dependencies unchanged - Step 4 (`update_all_plugins.nu`) touched all Cargo.toml files at 01:00:32 - Step 5 saw all files as "newer" than binaries - Marked ALL plugins for rebuild, though cargo only rebuilt changed ones **Root Cause**: Script always saved files, even when no changes made ```nushell # ❌ OLD - always saves, touching file timestamp $updated_content | to toml | save -f $cargo_toml ``` **Solution**: Only save if content actually changed ```nushell # ✅ NEW - compare before writing let original_toml = $content | to toml let new_toml = $updated_content | to toml if $original_toml != $new_toml { $updated_content | to toml | save -f $cargo_toml } ``` **Impact**: - Unchanged files preserve original timestamps - Only plugins with actual dependency changes are rebuilt - Efficient rebuild process with accurate file modification detection **Files Modified**: - `scripts/update_all_plugins.nu` (+12 lines, added content comparison) - Only touches files with real changes - Preserves timestamps for efficiency - Clearer logic and comments ### 4. Documentation **Files Modified**: - `CHANGELOG.md` (+56 lines) - Added comprehensive 2025-10-19 entry - Documented all fixes with root causes - Listed files modified and impact summary ## Technical Details ### Nushell Patterns Used 1. **Proper List Handling**: - `ls` returns list of records, access with `| get 0.size` - Filter with `where type == "file"` to exclude metadata 2. **Absolute Path Construction**: - `pwd | append "path" | path join` for cross-platform paths - Safer than string concatenation with `/` 3. **Content Comparison**: - Compare TOML string representation before saving - Preserves file timestamps for efficiency 4. **Error Diagnostics**: - Capture `stderr` from commands - Report exit codes and error messages separately ## Testing - [x] Help system shows version-update module - [x] `just commands` displays all recipes by group - [x] Phase 3 bin archive creation works - [x] Plugin collection reports correct count (26) - [x] Tar archives created successfully - [x] File size calculated correctly - [x] Plugin rebuild only touches changed files - [x] CHANGELOG updated with all changes ## Files Changed ``` 38 files changed, 2721 insertions(+), 2548 deletions(-) Core Changes: - justfiles/help.just (+23) Help system integration - scripts/create_full_distribution.nu (+58) Build process fixes - scripts/update_all_plugins.nu (+12) Rebuild optimization - CHANGELOG.md (+56) Documentation Dependency Updates: - All plugin Cargo.toml and Cargo.lock files (version consistency) ``` ## Breaking Changes None. These are bug fixes and optimizations that maintain backward compatibility. ## Migration Notes No migration needed. Improvements are transparent to users. ## Related Issues - Help system discoverability - Build process Phase 3 failures - Unnecessary plugin rebuilds - Build process reliability ## Checklist - [x] Changes follow Rust/Nushell idioms - [x] Code is well-commented - [x] Error handling is comprehensive - [x] Documentation is updated - [x] All changes tested - [x] No breaking changes introduced
2025-10-19 02:39:31 +01:00
-System Remove from system location (Program Files)
Requires administrator privileges (run as admin)
-User Remove from user location (~\.local\bin) [default]
No admin required - recommended
-UninstallDir PATH Remove from custom directory (directory must be writable)
Bypasses interactive prompts when supplied explicitly
Example: -UninstallDir "C:\Tools\nushell"
feat: Add complete Nushell full distribution system ## Major Features Added - **Complete distribution infrastructure**: Build, package, and distribute Nushell binary alongside plugins - **Zero-prerequisite installation**: Bootstrap installers work on fresh systems without Rust/Cargo/Nushell - **Cross-platform support**: Linux, macOS, Windows (x86_64, ARM64) - **Self-contained packages**: Everything needed for complete Nushell environment ## New Components ### Build System - `scripts/build_nushell.nu` - Build nushell with all workspace plugins - `scripts/collect_full_binaries.nu` - Collect nu binary + all plugins - `justfiles/full_distro.just` - 40+ new recipes for distribution workflows ### Bootstrap Installers (Zero Prerequisites) - `installers/bootstrap/install.sh` - Universal POSIX installer (900+ lines) - `installers/bootstrap/install.ps1` - Windows PowerShell installer (800+ lines) - Complete platform detection, PATH setup, plugin registration ### Distribution System - `scripts/create_distribution_packages.nu` - Multi-platform package creator - `scripts/install_full_nushell.nu` - Advanced nu-based installer - `scripts/verify_installation.nu` - Installation verification suite - `scripts/lib/common_lib.nu` - Shared utilities and logging ### Configuration Management - `scripts/templates/default_config.nu` - Complete nushell configuration (500+ lines) - `scripts/templates/default_env.nu` - Cross-platform environment setup - `etc/distribution_config.toml` - Central distribution settings - `scripts/templates/uninstall.sh` & `uninstall.ps1` - Clean removal ## Key Workflows ```bash just build-full # Build nushell + all plugins just pack-full-all # Create packages for all platforms just verify-full # Verify installation just release-full-cross # Complete cross-platform release ``` ## Installation Experience - One-liner: `curl -sSf https://your-url/install.sh | sh` - Multiple modes: user, system, portable installation - Automatic plugin registration with verification - Professional uninstall capability ## Benefits - ✅ Solves bootstrap problem - no prerequisites needed - ✅ Production-ready distribution system - ✅ Complete cross-platform support - ✅ Professional installation experience - ✅ Integrates seamlessly with existing plugin workflows - ✅ Enterprise-grade verification and logging
2025-09-24 18:52:07 +01:00
-DryRun Show what would be removed without actually removing
-Debug Enable debug output
EXAMPLES:
# Summary feat: bootstrap installer with robust archive extraction, version mismatch handling, and improved PATH messaging ## Detailed Description This commit implements a production-ready bootstrap installer with comprehensive error handling, version-agnostic archive extraction, and clear user messaging. All improvements follow DRY principles using symlink-based architecture for single-source-of-truth maintenance. ## Major Changes (Session 2025-10-19) ### 0. Bootstrap Installer & Distribution Improvements (NEW) #### 0a. Install Script Architecture - DRY Design **Issue**: Code duplication across installation paths - `./install.sh`, `./scripts/templates/install.sh`, `installers/bootstrap/install.sh` were separate copies - Changes required updating multiple files - Risk of divergence and inconsistency **Solution**: Implemented symlink-based DRY architecture - Single source of truth: `installers/bootstrap/install.sh` (1,247 lines) - Symlinks created: - `./install.sh` → `installers/bootstrap/install.sh` - `./scripts/templates/install.sh` → `installers/bootstrap/install.sh` - All changes automatically propagate through symlinks - No code duplication **Impact**: - ✅ Single maintenance point for all install scripts - ✅ Consistent behavior across all paths - ✅ Reduced maintenance burden - ✅ No divergence risk #### 0b. Archive Extraction - Version-Agnostic Binary Detection **Issue**: "No Nushell binary found in extracted archive" - Script failed when extracting from `nushell-full-0.108.0-darwin-arm64.tar.gz` - Error occurred even though binaries were present at `nushell-full-0.108.0/bin/nu` **Root Cause**: `find` command returning parent directory itself in results ```bash # ❌ OLD - find returns parent directory first local extracted=$(find "$extract_dir" -maxdepth 1 -type d -name "nushell-*" | head -1) # Returns: /tmp/nushell-install-22919/nushell-extract (parent!) # Should return: /tmp/nushell-install-22919/nushell-extract/nushell-full-0.108.0 (subdirectory) ``` **Solution**: Added `-not -path` to exclude starting directory ```bash # ✅ NEW - exclude parent directory local extracted=$(find "$extract_dir" -maxdepth 1 -type d -name "nushell-*" -not -path "$extract_dir" | head -1) # Now correctly returns the subdirectory ``` **Additional Improvements**: - 4-level fallback detection strategy: 1. Check `$extracted/bin/nu` (subdirectory structure) 2. Check `$extracted/nu` (flat structure) 3. Fallback search for any `nushell-*` subdirectory with `bin/nu` 4. Last resort recursive search for any executable named `nu` - Validates binaries exist before using them - Clear error reporting with all search locations **Version-Agnostic**: - Uses `nushell-*` pattern (not hardcoded version numbers) - Works with any Nushell version: 0.107, 0.108, 0.109, etc. - Supports both `.tar.gz` and `.zip` archive formats **Impact**: - ✅ Archive extraction works reliably - ✅ Works with any Nushell version - ✅ Clear error messages guide users - ✅ Multiple archive structure support #### 0c. Plugin Registration - Version Mismatch Handling **Issue**: Plugin registration failed with version incompatibility errors ``` Error: nu::shell::plugin_failed_to_load × Plugin `polars` is compiled for nushell version 0.107.1, which is not compatible with version 0.108.0 ``` **Solution**: Implemented intelligent error classification - Captures both stdout and stderr from plugin add commands - Detects version incompatibility: "is not compatible with version" or "is compiled for nushell version" - Classifies errors into three categories: 1. **Success**: Plugin registered successfully ✅ 2. **Incompatible**: Version mismatch (skipped gracefully) ⚠️ 3. **Failed**: Other registration failures ❌ - Reports summary with counts of each category - Installation continues successfully even with version mismatches **New Error Reporting**: ``` ✅ Registered nu_plugin_auth ⚠️ Skipping nu_plugin_polars: Version mismatch (built for different Nushell version) ✅ Successfully registered 13 plugins ⚠️ Skipped 1 incompatible plugins (version mismatch): - nu_plugin_polars ``` **Impact**: - ✅ No installation failures due to version mismatches - ✅ Users informed of incompatible plugins - ✅ Clear distinction between error types - ✅ Installation completes successfully #### 0d. Shell Configuration PATH Update - Clear Messaging **Issue**: Confusing PATH update messages - User sees: "PATH already updated" for all files - Then sees: "No shell configuration files were updated" warning - Then sees: "Please manually add to your PATH" error - **Problem**: Contradictory messages when PATH is already configured everywhere **Root Cause**: Script conflated two states - State 1: "Was PATH found in files?" (skips updating if found) - State 2: "Did we add PATH to any file?" (used for messaging) - Both states ignored means no update was made, but PATH might already exist **Solution**: Track two separate states ```bash local updated=false # Was PATH ADDED to any file? local path_found=false # Was PATH FOUND in any file? # In loop: if grep -q "$install_dir" "$config_file"; then path_found=true # Found it! Mark as true continue fi # After loop: if [ "$updated" = "true" ]; then log_success "Shell configuration updated" elif [ "$path_found" = "true" ]; then log_success "PATH is already configured in your shell configuration files" else log_warn "Could not find or update shell configuration" fi ``` **New Clear Messages**: - ✅ "PATH is already configured in your shell configuration files" (when found everywhere) - ✅ "Shell configuration updated" (when just added) - ⚠️ "Could not find or update shell configuration" (when file missing) **Impact**: - ✅ Non-contradictory messages - ✅ Users understand what happened - ✅ No false warnings when PATH already configured - ✅ Clear guidance when manual action needed #### 0e. Installation Features **`--source-path` Option** (Local Installation): - Install from local archive: `./install.sh --source-path archive.tar.gz` - Install from local directory: `./install.sh --source-path /path/to/binaries` - Default behavior: `./install.sh --source-path` uses `./bin_archives` - Works with custom `--install-dir` paths - No download needed, offline installation support **`--uninstall` with Configuration Management**: - Prompts user: "Remove ~/.config/nushell? [y/N]" - Removes all installed binaries and plugins - Preserves user choice for configuration - Clean uninstall before fresh reinstall #### 0f. Documentation Updates **CLAUDE.md**: - Added "Install Script Architecture (DRY Design)" section - Documents source of truth and symlink structure - Explains `--source-path` feature - Shows version-agnostic archive detection - Lists DRY architecture benefits **README.md**: - Added "Install Script Architecture (DRY Design)" subsection - Shows symlink structure with arrows - Provides `--source-path` usage examples - Explains version-agnostic detection - "How DRY Works" 3-step explanation #### 0g. Files Modified Core Changes: - `installers/bootstrap/install.sh` (+3 lines for PATH messaging fix) - Archive extraction fix with `-not -path` - Plugin registration error classification - Clear PATH update messaging - Total: 1,247 lines (unified) Auto-Updated via Symlinks: - `./install.sh` - Auto-updated (1,247 lines) - `./scripts/templates/install.sh` - Auto-updated (1,247 lines) Documentation: - `CLAUDE.md` - Added install architecture section - `README.md` - Added install architecture subsection - `CHANGELOG.md` - Added comprehensive entry (+100 lines) #### 0h. Testing & Verification All scenarios tested and verified: - [x] Archive extraction works with version-agnostic detection - [x] Installation to `~/.local` successful (16 binaries) - [x] Installation to `~/.local/bin` successful (21 plugins loaded) - [x] Plugin registration handles version mismatches gracefully - [x] PATH messaging is clear and non-contradictory - [x] Clean uninstall followed by fresh reinstall works perfectly #### 0i. Impact User-Facing Benefits: - ✅ Users can install from any version of nushell-full archive - ✅ Version mismatch plugins skipped without breaking installation - ✅ Clear, honest error messages - ✅ Non-confusing PATH update messages - ✅ Offline installation support via `--source-path` - ✅ Clean uninstall/reinstall workflow Developer Benefits: - ✅ Single source of truth eliminates code duplication - ✅ Changes propagate automatically through symlinks - ✅ Reduced maintenance burden - ✅ Consistent behavior across all paths - ✅ Production-ready installation process --- ### 1. Help System Integration (New Feature) **Issue**: Version-update module recipes were not discoverable - Not shown in `just help modules` - Not referenced in `just help` - Not included in help navigation system - Users had to manually run `just --list` to find update commands **Solution**: - Added version-update module to all help outputs - Updated `justfiles/help.just` to document all 30+ version-update recipes - Created new `just commands` recipe as discoverable alias for `just --list` - Integrated version-update into help-all workflow **Impact**: - Version-update commands now fully discoverable via help system - Users can find update commands with: `just help modules`, `just help`, `just commands` - Improved overall help system navigation **Files Modified**: - `justfiles/help.just` (+23 lines) - Added version-update module to help sections - Added to modules list - Added to help-all workflow - New `commands` recipe showing all recipes by group ### 2. Build Process Fixes (Phase 3: Bin Archives) #### 2a. Plugin Archive Collection Bug **Issue**: "No plugins found to package" warning in Phase 3 - Collected 26 plugin binaries but reported 0 - Archive creation skipped because count was wrong **Root Cause**: `each` command returns null, so `| length` returned 0 ```nushell # ❌ OLD - each returns null let plugin_count = (ls nu_plugin_*/target/release/nu_plugin_* | each {|p| cp $p.name $"($temp_dir)/" } | length) # Returns 0! ``` **Solution**: Separated counting from copying with proper filtering ```nushell # ✅ NEW - count before operations let plugins_to_copy = (ls nu_plugin_*/target/release/nu_plugin_* | where type == "file") let plugin_count = ($plugins_to_copy | length) ``` **Impact**: - Now correctly collects and reports 26 plugins - Filters out .d dependency files automatically - Warning eliminated #### 2b. Tar Archive Path Handling **Issue**: Tar command failing silently with relative paths in subshell - `cd $temp_dir` changes context unpredictably - Relative path `../$archive_name` fails in subshell - Archive file not created despite exit code 0 **Root Cause**: Shell context and relative path issues in Nushell `do` block **Solution**: Used `tar -C` with absolute paths instead of `cd` ```nushell # ❌ OLD - unreliable context switching do { cd $temp_dir tar -czf ../$archive_name . } # ✅ NEW - absolute paths, no context switching tar -C $temp_dir -czf $archive_path . ``` **Additional Improvements**: - Absolute path construction using `pwd | path join` - Better error diagnostics with exit code and stderr output - File verification after creation **Impact**: - Tar archives now created successfully - Robust path handling across platforms - Clear error messages for debugging #### 2c. File Size Calculation Type Error **Issue**: Runtime error when calculating archive size ``` Error: The '/' operator does not work on values of type 'list<filesize>' ``` **Root Cause**: `ls` returns list of records, so `.size` was a list ```nushell # ❌ OLD - returns list<filesize> (ls $archive_path).size / 1024 / 1024 # ✅ NEW - returns filesize (ls $archive_path | get 0.size) / 1024 / 1024 ``` **Impact**: - Proper file size calculation in MB - No more type errors **Files Modified**: - `scripts/create_full_distribution.nu` (+58 lines, refactored plugin collection) - Fixed plugin counting logic - Improved path handling with absolute paths - Enhanced error diagnostics ### 3. Plugin Rebuild Optimization **Issue**: All plugins marked for rebuild even when dependencies unchanged - Step 4 (`update_all_plugins.nu`) touched all Cargo.toml files at 01:00:32 - Step 5 saw all files as "newer" than binaries - Marked ALL plugins for rebuild, though cargo only rebuilt changed ones **Root Cause**: Script always saved files, even when no changes made ```nushell # ❌ OLD - always saves, touching file timestamp $updated_content | to toml | save -f $cargo_toml ``` **Solution**: Only save if content actually changed ```nushell # ✅ NEW - compare before writing let original_toml = $content | to toml let new_toml = $updated_content | to toml if $original_toml != $new_toml { $updated_content | to toml | save -f $cargo_toml } ``` **Impact**: - Unchanged files preserve original timestamps - Only plugins with actual dependency changes are rebuilt - Efficient rebuild process with accurate file modification detection **Files Modified**: - `scripts/update_all_plugins.nu` (+12 lines, added content comparison) - Only touches files with real changes - Preserves timestamps for efficiency - Clearer logic and comments ### 4. Documentation **Files Modified**: - `CHANGELOG.md` (+56 lines) - Added comprehensive 2025-10-19 entry - Documented all fixes with root causes - Listed files modified and impact summary ## Technical Details ### Nushell Patterns Used 1. **Proper List Handling**: - `ls` returns list of records, access with `| get 0.size` - Filter with `where type == "file"` to exclude metadata 2. **Absolute Path Construction**: - `pwd | append "path" | path join` for cross-platform paths - Safer than string concatenation with `/` 3. **Content Comparison**: - Compare TOML string representation before saving - Preserves file timestamps for efficiency 4. **Error Diagnostics**: - Capture `stderr` from commands - Report exit codes and error messages separately ## Testing - [x] Help system shows version-update module - [x] `just commands` displays all recipes by group - [x] Phase 3 bin archive creation works - [x] Plugin collection reports correct count (26) - [x] Tar archives created successfully - [x] File size calculated correctly - [x] Plugin rebuild only touches changed files - [x] CHANGELOG updated with all changes ## Files Changed ``` 38 files changed, 2721 insertions(+), 2548 deletions(-) Core Changes: - justfiles/help.just (+23) Help system integration - scripts/create_full_distribution.nu (+58) Build process fixes - scripts/update_all_plugins.nu (+12) Rebuild optimization - CHANGELOG.md (+56) Documentation Dependency Updates: - All plugin Cargo.toml and Cargo.lock files (version consistency) ``` ## Breaking Changes None. These are bug fixes and optimizations that maintain backward compatibility. ## Migration Notes No migration needed. Improvements are transparent to users. ## Related Issues - Help system discoverability - Build process Phase 3 failures - Unnecessary plugin rebuilds - Build process reliability ## Checklist - [x] Changes follow Rust/Nushell idioms - [x] Code is well-commented - [x] Error handling is comprehensive - [x] Documentation is updated - [x] All changes tested - [x] No breaking changes introduced
2025-10-19 02:39:31 +01:00
# Interactive removal (from user location)
.\uninstall.ps1
# Non-interactive removal (from user location)
.\uninstall.ps1 -Yes
# Remove with config backup
.\uninstall.ps1 -BackupConfig -Yes
# Remove from custom directory
.\uninstall.ps1 -UninstallDir "C:\Tools\nushell" -Yes
# Remove system installation (requires admin - right-click and 'Run as administrator')
.\uninstall.ps1 -System -Yes
# Preview what would be removed
.\uninstall.ps1 -DryRun
TROUBLESHOOTING:
Access denied to Program Files?
Default uses %USERPROFILE%\.local\bin (no admin needed)
Or: -UninstallDir "%USERPROFILE%\.local\bin" (explicit custom path)
Unsure what to do?
Run with -DryRun first to see what would be removed
Default removal is safest: .\uninstall.ps1 -Yes
feat: Add complete Nushell full distribution system ## Major Features Added - **Complete distribution infrastructure**: Build, package, and distribute Nushell binary alongside plugins - **Zero-prerequisite installation**: Bootstrap installers work on fresh systems without Rust/Cargo/Nushell - **Cross-platform support**: Linux, macOS, Windows (x86_64, ARM64) - **Self-contained packages**: Everything needed for complete Nushell environment ## New Components ### Build System - `scripts/build_nushell.nu` - Build nushell with all workspace plugins - `scripts/collect_full_binaries.nu` - Collect nu binary + all plugins - `justfiles/full_distro.just` - 40+ new recipes for distribution workflows ### Bootstrap Installers (Zero Prerequisites) - `installers/bootstrap/install.sh` - Universal POSIX installer (900+ lines) - `installers/bootstrap/install.ps1` - Windows PowerShell installer (800+ lines) - Complete platform detection, PATH setup, plugin registration ### Distribution System - `scripts/create_distribution_packages.nu` - Multi-platform package creator - `scripts/install_full_nushell.nu` - Advanced nu-based installer - `scripts/verify_installation.nu` - Installation verification suite - `scripts/lib/common_lib.nu` - Shared utilities and logging ### Configuration Management - `scripts/templates/default_config.nu` - Complete nushell configuration (500+ lines) - `scripts/templates/default_env.nu` - Cross-platform environment setup - `etc/distribution_config.toml` - Central distribution settings - `scripts/templates/uninstall.sh` & `uninstall.ps1` - Clean removal ## Key Workflows ```bash just build-full # Build nushell + all plugins just pack-full-all # Create packages for all platforms just verify-full # Verify installation just release-full-cross # Complete cross-platform release ``` ## Installation Experience - One-liner: `curl -sSf https://your-url/install.sh | sh` - Multiple modes: user, system, portable installation - Automatic plugin registration with verification - Professional uninstall capability ## Benefits - ✅ Solves bootstrap problem - no prerequisites needed - ✅ Production-ready distribution system - ✅ Complete cross-platform support - ✅ Professional installation experience - ✅ Integrates seamlessly with existing plugin workflows - ✅ Enterprise-grade verification and logging
2025-09-24 18:52:07 +01:00
"@
}
# Show usage and exit if help requested
if ($Help) {
Show-Usage
exit 0
}
# Determine installation directory
$Interactive = -not $Yes
$IsSystemInstall = $System
# Summary feat: bootstrap installer with robust archive extraction, version mismatch handling, and improved PATH messaging ## Detailed Description This commit implements a production-ready bootstrap installer with comprehensive error handling, version-agnostic archive extraction, and clear user messaging. All improvements follow DRY principles using symlink-based architecture for single-source-of-truth maintenance. ## Major Changes (Session 2025-10-19) ### 0. Bootstrap Installer & Distribution Improvements (NEW) #### 0a. Install Script Architecture - DRY Design **Issue**: Code duplication across installation paths - `./install.sh`, `./scripts/templates/install.sh`, `installers/bootstrap/install.sh` were separate copies - Changes required updating multiple files - Risk of divergence and inconsistency **Solution**: Implemented symlink-based DRY architecture - Single source of truth: `installers/bootstrap/install.sh` (1,247 lines) - Symlinks created: - `./install.sh` → `installers/bootstrap/install.sh` - `./scripts/templates/install.sh` → `installers/bootstrap/install.sh` - All changes automatically propagate through symlinks - No code duplication **Impact**: - ✅ Single maintenance point for all install scripts - ✅ Consistent behavior across all paths - ✅ Reduced maintenance burden - ✅ No divergence risk #### 0b. Archive Extraction - Version-Agnostic Binary Detection **Issue**: "No Nushell binary found in extracted archive" - Script failed when extracting from `nushell-full-0.108.0-darwin-arm64.tar.gz` - Error occurred even though binaries were present at `nushell-full-0.108.0/bin/nu` **Root Cause**: `find` command returning parent directory itself in results ```bash # ❌ OLD - find returns parent directory first local extracted=$(find "$extract_dir" -maxdepth 1 -type d -name "nushell-*" | head -1) # Returns: /tmp/nushell-install-22919/nushell-extract (parent!) # Should return: /tmp/nushell-install-22919/nushell-extract/nushell-full-0.108.0 (subdirectory) ``` **Solution**: Added `-not -path` to exclude starting directory ```bash # ✅ NEW - exclude parent directory local extracted=$(find "$extract_dir" -maxdepth 1 -type d -name "nushell-*" -not -path "$extract_dir" | head -1) # Now correctly returns the subdirectory ``` **Additional Improvements**: - 4-level fallback detection strategy: 1. Check `$extracted/bin/nu` (subdirectory structure) 2. Check `$extracted/nu` (flat structure) 3. Fallback search for any `nushell-*` subdirectory with `bin/nu` 4. Last resort recursive search for any executable named `nu` - Validates binaries exist before using them - Clear error reporting with all search locations **Version-Agnostic**: - Uses `nushell-*` pattern (not hardcoded version numbers) - Works with any Nushell version: 0.107, 0.108, 0.109, etc. - Supports both `.tar.gz` and `.zip` archive formats **Impact**: - ✅ Archive extraction works reliably - ✅ Works with any Nushell version - ✅ Clear error messages guide users - ✅ Multiple archive structure support #### 0c. Plugin Registration - Version Mismatch Handling **Issue**: Plugin registration failed with version incompatibility errors ``` Error: nu::shell::plugin_failed_to_load × Plugin `polars` is compiled for nushell version 0.107.1, which is not compatible with version 0.108.0 ``` **Solution**: Implemented intelligent error classification - Captures both stdout and stderr from plugin add commands - Detects version incompatibility: "is not compatible with version" or "is compiled for nushell version" - Classifies errors into three categories: 1. **Success**: Plugin registered successfully ✅ 2. **Incompatible**: Version mismatch (skipped gracefully) ⚠️ 3. **Failed**: Other registration failures ❌ - Reports summary with counts of each category - Installation continues successfully even with version mismatches **New Error Reporting**: ``` ✅ Registered nu_plugin_auth ⚠️ Skipping nu_plugin_polars: Version mismatch (built for different Nushell version) ✅ Successfully registered 13 plugins ⚠️ Skipped 1 incompatible plugins (version mismatch): - nu_plugin_polars ``` **Impact**: - ✅ No installation failures due to version mismatches - ✅ Users informed of incompatible plugins - ✅ Clear distinction between error types - ✅ Installation completes successfully #### 0d. Shell Configuration PATH Update - Clear Messaging **Issue**: Confusing PATH update messages - User sees: "PATH already updated" for all files - Then sees: "No shell configuration files were updated" warning - Then sees: "Please manually add to your PATH" error - **Problem**: Contradictory messages when PATH is already configured everywhere **Root Cause**: Script conflated two states - State 1: "Was PATH found in files?" (skips updating if found) - State 2: "Did we add PATH to any file?" (used for messaging) - Both states ignored means no update was made, but PATH might already exist **Solution**: Track two separate states ```bash local updated=false # Was PATH ADDED to any file? local path_found=false # Was PATH FOUND in any file? # In loop: if grep -q "$install_dir" "$config_file"; then path_found=true # Found it! Mark as true continue fi # After loop: if [ "$updated" = "true" ]; then log_success "Shell configuration updated" elif [ "$path_found" = "true" ]; then log_success "PATH is already configured in your shell configuration files" else log_warn "Could not find or update shell configuration" fi ``` **New Clear Messages**: - ✅ "PATH is already configured in your shell configuration files" (when found everywhere) - ✅ "Shell configuration updated" (when just added) - ⚠️ "Could not find or update shell configuration" (when file missing) **Impact**: - ✅ Non-contradictory messages - ✅ Users understand what happened - ✅ No false warnings when PATH already configured - ✅ Clear guidance when manual action needed #### 0e. Installation Features **`--source-path` Option** (Local Installation): - Install from local archive: `./install.sh --source-path archive.tar.gz` - Install from local directory: `./install.sh --source-path /path/to/binaries` - Default behavior: `./install.sh --source-path` uses `./bin_archives` - Works with custom `--install-dir` paths - No download needed, offline installation support **`--uninstall` with Configuration Management**: - Prompts user: "Remove ~/.config/nushell? [y/N]" - Removes all installed binaries and plugins - Preserves user choice for configuration - Clean uninstall before fresh reinstall #### 0f. Documentation Updates **CLAUDE.md**: - Added "Install Script Architecture (DRY Design)" section - Documents source of truth and symlink structure - Explains `--source-path` feature - Shows version-agnostic archive detection - Lists DRY architecture benefits **README.md**: - Added "Install Script Architecture (DRY Design)" subsection - Shows symlink structure with arrows - Provides `--source-path` usage examples - Explains version-agnostic detection - "How DRY Works" 3-step explanation #### 0g. Files Modified Core Changes: - `installers/bootstrap/install.sh` (+3 lines for PATH messaging fix) - Archive extraction fix with `-not -path` - Plugin registration error classification - Clear PATH update messaging - Total: 1,247 lines (unified) Auto-Updated via Symlinks: - `./install.sh` - Auto-updated (1,247 lines) - `./scripts/templates/install.sh` - Auto-updated (1,247 lines) Documentation: - `CLAUDE.md` - Added install architecture section - `README.md` - Added install architecture subsection - `CHANGELOG.md` - Added comprehensive entry (+100 lines) #### 0h. Testing & Verification All scenarios tested and verified: - [x] Archive extraction works with version-agnostic detection - [x] Installation to `~/.local` successful (16 binaries) - [x] Installation to `~/.local/bin` successful (21 plugins loaded) - [x] Plugin registration handles version mismatches gracefully - [x] PATH messaging is clear and non-contradictory - [x] Clean uninstall followed by fresh reinstall works perfectly #### 0i. Impact User-Facing Benefits: - ✅ Users can install from any version of nushell-full archive - ✅ Version mismatch plugins skipped without breaking installation - ✅ Clear, honest error messages - ✅ Non-confusing PATH update messages - ✅ Offline installation support via `--source-path` - ✅ Clean uninstall/reinstall workflow Developer Benefits: - ✅ Single source of truth eliminates code duplication - ✅ Changes propagate automatically through symlinks - ✅ Reduced maintenance burden - ✅ Consistent behavior across all paths - ✅ Production-ready installation process --- ### 1. Help System Integration (New Feature) **Issue**: Version-update module recipes were not discoverable - Not shown in `just help modules` - Not referenced in `just help` - Not included in help navigation system - Users had to manually run `just --list` to find update commands **Solution**: - Added version-update module to all help outputs - Updated `justfiles/help.just` to document all 30+ version-update recipes - Created new `just commands` recipe as discoverable alias for `just --list` - Integrated version-update into help-all workflow **Impact**: - Version-update commands now fully discoverable via help system - Users can find update commands with: `just help modules`, `just help`, `just commands` - Improved overall help system navigation **Files Modified**: - `justfiles/help.just` (+23 lines) - Added version-update module to help sections - Added to modules list - Added to help-all workflow - New `commands` recipe showing all recipes by group ### 2. Build Process Fixes (Phase 3: Bin Archives) #### 2a. Plugin Archive Collection Bug **Issue**: "No plugins found to package" warning in Phase 3 - Collected 26 plugin binaries but reported 0 - Archive creation skipped because count was wrong **Root Cause**: `each` command returns null, so `| length` returned 0 ```nushell # ❌ OLD - each returns null let plugin_count = (ls nu_plugin_*/target/release/nu_plugin_* | each {|p| cp $p.name $"($temp_dir)/" } | length) # Returns 0! ``` **Solution**: Separated counting from copying with proper filtering ```nushell # ✅ NEW - count before operations let plugins_to_copy = (ls nu_plugin_*/target/release/nu_plugin_* | where type == "file") let plugin_count = ($plugins_to_copy | length) ``` **Impact**: - Now correctly collects and reports 26 plugins - Filters out .d dependency files automatically - Warning eliminated #### 2b. Tar Archive Path Handling **Issue**: Tar command failing silently with relative paths in subshell - `cd $temp_dir` changes context unpredictably - Relative path `../$archive_name` fails in subshell - Archive file not created despite exit code 0 **Root Cause**: Shell context and relative path issues in Nushell `do` block **Solution**: Used `tar -C` with absolute paths instead of `cd` ```nushell # ❌ OLD - unreliable context switching do { cd $temp_dir tar -czf ../$archive_name . } # ✅ NEW - absolute paths, no context switching tar -C $temp_dir -czf $archive_path . ``` **Additional Improvements**: - Absolute path construction using `pwd | path join` - Better error diagnostics with exit code and stderr output - File verification after creation **Impact**: - Tar archives now created successfully - Robust path handling across platforms - Clear error messages for debugging #### 2c. File Size Calculation Type Error **Issue**: Runtime error when calculating archive size ``` Error: The '/' operator does not work on values of type 'list<filesize>' ``` **Root Cause**: `ls` returns list of records, so `.size` was a list ```nushell # ❌ OLD - returns list<filesize> (ls $archive_path).size / 1024 / 1024 # ✅ NEW - returns filesize (ls $archive_path | get 0.size) / 1024 / 1024 ``` **Impact**: - Proper file size calculation in MB - No more type errors **Files Modified**: - `scripts/create_full_distribution.nu` (+58 lines, refactored plugin collection) - Fixed plugin counting logic - Improved path handling with absolute paths - Enhanced error diagnostics ### 3. Plugin Rebuild Optimization **Issue**: All plugins marked for rebuild even when dependencies unchanged - Step 4 (`update_all_plugins.nu`) touched all Cargo.toml files at 01:00:32 - Step 5 saw all files as "newer" than binaries - Marked ALL plugins for rebuild, though cargo only rebuilt changed ones **Root Cause**: Script always saved files, even when no changes made ```nushell # ❌ OLD - always saves, touching file timestamp $updated_content | to toml | save -f $cargo_toml ``` **Solution**: Only save if content actually changed ```nushell # ✅ NEW - compare before writing let original_toml = $content | to toml let new_toml = $updated_content | to toml if $original_toml != $new_toml { $updated_content | to toml | save -f $cargo_toml } ``` **Impact**: - Unchanged files preserve original timestamps - Only plugins with actual dependency changes are rebuilt - Efficient rebuild process with accurate file modification detection **Files Modified**: - `scripts/update_all_plugins.nu` (+12 lines, added content comparison) - Only touches files with real changes - Preserves timestamps for efficiency - Clearer logic and comments ### 4. Documentation **Files Modified**: - `CHANGELOG.md` (+56 lines) - Added comprehensive 2025-10-19 entry - Documented all fixes with root causes - Listed files modified and impact summary ## Technical Details ### Nushell Patterns Used 1. **Proper List Handling**: - `ls` returns list of records, access with `| get 0.size` - Filter with `where type == "file"` to exclude metadata 2. **Absolute Path Construction**: - `pwd | append "path" | path join` for cross-platform paths - Safer than string concatenation with `/` 3. **Content Comparison**: - Compare TOML string representation before saving - Preserves file timestamps for efficiency 4. **Error Diagnostics**: - Capture `stderr` from commands - Report exit codes and error messages separately ## Testing - [x] Help system shows version-update module - [x] `just commands` displays all recipes by group - [x] Phase 3 bin archive creation works - [x] Plugin collection reports correct count (26) - [x] Tar archives created successfully - [x] File size calculated correctly - [x] Plugin rebuild only touches changed files - [x] CHANGELOG updated with all changes ## Files Changed ``` 38 files changed, 2721 insertions(+), 2548 deletions(-) Core Changes: - justfiles/help.just (+23) Help system integration - scripts/create_full_distribution.nu (+58) Build process fixes - scripts/update_all_plugins.nu (+12) Rebuild optimization - CHANGELOG.md (+56) Documentation Dependency Updates: - All plugin Cargo.toml and Cargo.lock files (version consistency) ``` ## Breaking Changes None. These are bug fixes and optimizations that maintain backward compatibility. ## Migration Notes No migration needed. Improvements are transparent to users. ## Related Issues - Help system discoverability - Build process Phase 3 failures - Unnecessary plugin rebuilds - Build process reliability ## Checklist - [x] Changes follow Rust/Nushell idioms - [x] Code is well-commented - [x] Error handling is comprehensive - [x] Documentation is updated - [x] All changes tested - [x] No breaking changes introduced
2025-10-19 02:39:31 +01:00
if ($UninstallDir) {
# Custom uninstall directory provided - use it directly (bypass all checks)
$InstallDir = $UninstallDir
Write-Info "Using custom uninstall directory (via -UninstallDir): $InstallDir"
} elseif ($IsSystemInstall) {
feat: Add complete Nushell full distribution system ## Major Features Added - **Complete distribution infrastructure**: Build, package, and distribute Nushell binary alongside plugins - **Zero-prerequisite installation**: Bootstrap installers work on fresh systems without Rust/Cargo/Nushell - **Cross-platform support**: Linux, macOS, Windows (x86_64, ARM64) - **Self-contained packages**: Everything needed for complete Nushell environment ## New Components ### Build System - `scripts/build_nushell.nu` - Build nushell with all workspace plugins - `scripts/collect_full_binaries.nu` - Collect nu binary + all plugins - `justfiles/full_distro.just` - 40+ new recipes for distribution workflows ### Bootstrap Installers (Zero Prerequisites) - `installers/bootstrap/install.sh` - Universal POSIX installer (900+ lines) - `installers/bootstrap/install.ps1` - Windows PowerShell installer (800+ lines) - Complete platform detection, PATH setup, plugin registration ### Distribution System - `scripts/create_distribution_packages.nu` - Multi-platform package creator - `scripts/install_full_nushell.nu` - Advanced nu-based installer - `scripts/verify_installation.nu` - Installation verification suite - `scripts/lib/common_lib.nu` - Shared utilities and logging ### Configuration Management - `scripts/templates/default_config.nu` - Complete nushell configuration (500+ lines) - `scripts/templates/default_env.nu` - Cross-platform environment setup - `etc/distribution_config.toml` - Central distribution settings - `scripts/templates/uninstall.sh` & `uninstall.ps1` - Clean removal ## Key Workflows ```bash just build-full # Build nushell + all plugins just pack-full-all # Create packages for all platforms just verify-full # Verify installation just release-full-cross # Complete cross-platform release ``` ## Installation Experience - One-liner: `curl -sSf https://your-url/install.sh | sh` - Multiple modes: user, system, portable installation - Automatic plugin registration with verification - Professional uninstall capability ## Benefits - ✅ Solves bootstrap problem - no prerequisites needed - ✅ Production-ready distribution system - ✅ Complete cross-platform support - ✅ Professional installation experience - ✅ Integrates seamlessly with existing plugin workflows - ✅ Enterprise-grade verification and logging
2025-09-24 18:52:07 +01:00
$InstallDir = $InstallDirSystem
Write-Info "Targeting system installation: $InstallDir"
# Check if we have admin privileges
$currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
$isAdmin = $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin -and -not $DryRun) {
Write-Warning "System installation requires administrative privileges"
if ($Interactive) {
$response = Read-Host "Continue with elevated privileges? [y/N]"
if ($response -notmatch '^[yY]([eE][sS])?$') {
Write-Info "Uninstallation cancelled"
exit 0
}
}
# Re-run as administrator
if (-not $isAdmin) {
Write-Info "Re-running with elevated privileges..."
$arguments = $MyInvocation.BoundParameters.Keys | ForEach-Object { "-$_" }
Start-Process PowerShell.exe -Argument "-File `"$PSCommandPath`" $($arguments -join ' ')" -Verb RunAs
exit 0
}
}
} else {
$InstallDir = $InstallDirUser
Write-Info "Targeting user installation: $InstallDir"
}
# Detection functions
function Get-NushellInstallation {
param([string]$InstallDir)
$foundItems = @()
Write-Debug "Detecting Nushell installation in $InstallDir"
# Check for nu binary
$nuPath = Join-Path $InstallDir "nu.exe"
if (Test-Path $nuPath) {
$foundItems += "nu.exe"
Write-Debug "Found nu binary: $nuPath"
}
# Check for plugin binaries
$pluginPattern = Join-Path $InstallDir "nu_plugin_*.exe"
$pluginBinaries = Get-ChildItem -Path $pluginPattern -ErrorAction SilentlyContinue
foreach ($plugin in $pluginBinaries) {
$foundItems += $plugin.Name
Write-Debug "Found plugin binary: $($plugin.FullName)"
}
return $foundItems
}
function Get-ConfigInstallation {
param([string]$ConfigDir)
$foundItems = @()
Write-Debug "Detecting configuration in $ConfigDir"
if (Test-Path $ConfigDir) {
# Check for main config files
$configFiles = @("config.nu", "env.nu", "distribution_config.toml")
foreach ($configFile in $configFiles) {
$configPath = Join-Path $ConfigDir $configFile
if (Test-Path $configPath) {
$foundItems += $configFile
Write-Debug "Found config file: $configPath"
}
}
# Check for plugin registration
$pluginFiles = @("plugin.nu", "registry.dat")
foreach ($pluginFile in $pluginFiles) {
$pluginPath = Join-Path $ConfigDir $pluginFile
if (Test-Path $pluginPath) {
$foundItems += "plugin-registry"
Write-Debug "Found plugin registry files"
break
}
}
}
return $foundItems
}
function Get-PathEntries {
param([string]$InstallDir)
Write-Debug "Detecting PATH entries for $InstallDir"
$foundIn = @()
# Check user PATH
$userPath = [Environment]::GetEnvironmentVariable("Path", [EnvironmentVariableTarget]::User)
if ($userPath -and $userPath.Contains($InstallDir)) {
$foundIn += "User PATH"
Write-Debug "Found in User PATH"
}
# Check system PATH (if we have access)
try {
$systemPath = [Environment]::GetEnvironmentVariable("Path", [EnvironmentVariableTarget]::Machine)
if ($systemPath -and $systemPath.Contains($InstallDir)) {
$foundIn += "System PATH"
Write-Debug "Found in System PATH"
}
} catch {
Write-Debug "Cannot access System PATH (insufficient privileges)"
}
return $foundIn
}
# Removal functions
function Remove-Binaries {
param(
[string]$InstallDir,
[array]$Binaries
)
Write-Info "Removing binaries from $InstallDir..."
$removedCount = 0
foreach ($binary in $Binaries) {
$binaryPath = Join-Path $InstallDir $binary
if (Test-Path $binaryPath) {
Write-Info "Removing binary: $binary"
if (-not $DryRun) {
try {
Remove-Item -Path $binaryPath -Force
Write-Success "Removed: $binary"
$removedCount++
} catch {
Write-Error "Failed to remove: $binary - $($_.Exception.Message)"
}
} else {
Write-Info "[DRY RUN] Would remove: $binaryPath"
$removedCount++
}
}
}
Write-Success "Removed $removedCount binaries"
}
function Backup-Configuration {
param([string]$ConfigDir)
if (Test-Path $ConfigDir) {
$backupDir = "$ConfigDir.$BackupSuffix"
Write-Info "Backing up configuration to: $backupDir"
if (-not $DryRun) {
try {
Copy-Item -Path $ConfigDir -Destination $backupDir -Recurse -Force
Write-Success "Configuration backed up successfully"
} catch {
Write-Error "Failed to backup configuration: $($_.Exception.Message)"
return $false
}
} else {
Write-Info "[DRY RUN] Would backup configuration to: $backupDir"
}
return $true
} else {
Write-Info "No configuration directory to backup"
return $true
}
}
function Remove-Configuration {
param(
[string]$ConfigDir,
[array]$ConfigFiles
)
if ($KeepConfig) {
Write-Info "Keeping configuration files as requested"
return
}
if ($BackupConfig) {
Backup-Configuration $ConfigDir
}
if (Test-Path $ConfigDir) {
Write-Info "Removing configuration directory: $ConfigDir"
# Ask for confirmation if interactive and not just removing empty dir
if ($Interactive -and $ConfigFiles.Count -gt 0) {
$response = Read-Host "Remove configuration directory $ConfigDir? [y/N]"
if ($response -notmatch '^[yY]([eE][sS])?$') {
Write-Info "Keeping configuration directory"
return
}
}
if (-not $DryRun) {
try {
Remove-Item -Path $ConfigDir -Recurse -Force
Write-Success "Configuration directory removed"
} catch {
Write-Error "Failed to remove configuration directory: $($_.Exception.Message)"
}
} else {
Write-Info "[DRY RUN] Would remove configuration directory: $ConfigDir"
}
} else {
Write-Info "No configuration directory found"
}
}
function Remove-PathEntries {
param(
[string]$InstallDir,
[array]$PathLocations
)
if ($PathLocations.Count -eq 0) {
Write-Info "No PATH entries found"
return
}
Write-Info "Removing PATH entries..."
foreach ($location in $PathLocations) {
Write-Info "Cleaning PATH entries from: $location"
$target = if ($location -eq "User PATH") {
[EnvironmentVariableTarget]::User
} else {
[EnvironmentVariableTarget]::Machine
}
if (-not $DryRun) {
try {
$currentPath = [Environment]::GetEnvironmentVariable("Path", $target)
$pathEntries = $currentPath -split ';'
$newPathEntries = $pathEntries | Where-Object { $_ -ne $InstallDir }
$newPath = $newPathEntries -join ';'
[Environment]::SetEnvironmentVariable("Path", $newPath, $target)
Write-Success "Cleaned PATH entries from: $location"
} catch {
Write-Error "Failed to clean PATH entries from: $location - $($_.Exception.Message)"
}
} else {
Write-Info "[DRY RUN] Would remove PATH entries from: $location"
}
}
}
function Unregister-Plugins {
param([string]$InstallDir)
# Only try to unregister if nu is still available somewhere
$nuBinary = $null
if (Get-Command nu -ErrorAction SilentlyContinue) {
$nuBinary = (Get-Command nu).Path
} elseif (Test-Path (Join-Path $InstallDir "nu.exe")) {
$nuBinary = Join-Path $InstallDir "nu.exe"
} else {
Write-Info "Nushell not available for plugin unregistration"
return
}
Write-Info "Attempting to unregister plugins..."
if (-not $DryRun) {
try {
# Try to get list of registered plugins
$registeredPlugins = & $nuBinary -c "plugin list | get name" 2>$null
if ($registeredPlugins) {
Write-Info "Unregistering plugins from nushell..."
foreach ($plugin in $registeredPlugins) {
try {
& $nuBinary -c "plugin rm $plugin" 2>$null
} catch {
Write-Warning "Could not unregister plugin: $plugin"
}
}
Write-Success "Plugin unregistration completed"
} else {
Write-Info "No registered plugins found"
}
} catch {
Write-Warning "Could not retrieve plugin list"
}
} else {
Write-Info "[DRY RUN] Would attempt to unregister plugins"
}
}
# Main uninstallation process
function Main {
Write-Info "🗑️ Nushell Full Distribution Uninstaller"
Write-Info "========================================"
if ($DryRun) {
Write-Warning "DRY RUN MODE - No files will be modified"
}
# Detect current installation
Write-Info ""
Write-Info "🔍 Detecting current installation..."
$userBinaries = Get-NushellInstallation $InstallDirUser
$systemBinaries = Get-NushellInstallation $InstallDirSystem
$configFiles = Get-ConfigInstallation $ConfigDir
$userPathEntries = Get-PathEntries $InstallDirUser
$systemPathEntries = Get-PathEntries $InstallDirSystem
# Determine what we're removing based on target
if ($IsSystemInstall) {
$binaries = $systemBinaries
$pathEntries = $systemPathEntries
} else {
$binaries = $userBinaries
$pathEntries = $userPathEntries
}
# Show detection results
Write-Info "Installation Status:"
if ($userBinaries.Count -gt 0) {
Write-Info " 📁 User binaries ($InstallDirUser): $($userBinaries -join ', ')"
} else {
Write-Info " 📁 User binaries ($InstallDirUser): none found"
}
if ($systemBinaries.Count -gt 0) {
Write-Info " 📁 System binaries ($InstallDirSystem): $($systemBinaries -join ', ')"
} else {
Write-Info " 📁 System binaries ($InstallDirSystem): none found"
}
if ($configFiles.Count -gt 0) {
Write-Info " ⚙️ Configuration ($ConfigDir): $($configFiles -join ', ')"
} else {
Write-Info " ⚙️ Configuration ($ConfigDir): none found"
}
if ($pathEntries.Count -gt 0) {
Write-Info " 🛣️ PATH entries: $($pathEntries -join ', ')"
} else {
Write-Info " 🛣️ PATH entries: none found"
}
# Check if anything was found
if ($binaries.Count -eq 0 -and $configFiles.Count -eq 0 -and $pathEntries.Count -eq 0) {
Write-Warning "No Nushell installation detected"
if ($Interactive) {
$response = Read-Host "Continue anyway? [y/N]"
if ($response -notmatch '^[yY]([eE][sS])?$') {
Write-Info "Uninstallation cancelled"
exit 0
}
} else {
Write-Info "Nothing to remove"
exit 0
}
}
# Confirmation prompt
if ($Interactive) {
Write-Info ""
Write-Warning "This will remove the detected Nushell installation components."
if ($KeepConfig) {
Write-Info "Configuration files will be kept as requested."
} elseif ($BackupConfig) {
Write-Info "Configuration files will be backed up before removal."
}
$response = Read-Host "Proceed with uninstallation? [y/N]"
if ($response -notmatch '^[yY]([eE][sS])?$') {
Write-Info "Uninstallation cancelled"
exit 0
}
}
# Perform uninstallation
Write-Info ""
Write-Info "🗑️ Starting uninstallation..."
# Unregister plugins before removing binaries
if ($binaries.Count -gt 0) {
Unregister-Plugins $InstallDir
}
# Remove binaries
if ($binaries.Count -gt 0) {
Remove-Binaries $InstallDir $binaries
}
# Remove configuration
if ($configFiles.Count -gt 0) {
Remove-Configuration $ConfigDir $configFiles
}
# Clean PATH entries
if ($pathEntries.Count -gt 0) {
Remove-PathEntries $InstallDir $pathEntries
}
# Final summary
Write-Info ""
Write-Success "🎉 Uninstallation completed!"
Write-Info "Summary:"
Write-Info " 🗑️ Removed from: $InstallDir"
if ($configFiles.Count -gt 0 -and -not $KeepConfig) {
Write-Info " 🗑️ Configuration removed: $ConfigDir"
} elseif ($KeepConfig) {
Write-Info " 💾 Configuration kept: $ConfigDir"
}
if ($BackupConfig) {
Write-Info " 💾 Configuration backed up with suffix: .$BackupSuffix"
}
Write-Info ""
Write-Info "🔄 To complete removal:"
Write-Info "1. Restart your terminal or refresh environment variables"
Write-Info "2. Verify removal: Get-Command nu (should return nothing)"
if ($KeepConfig -or $BackupConfig) {
Write-Info ""
Write-Info "📝 Note: Configuration files were preserved as requested"
}
}
# Run main function
Main