877 lines
26 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 Bootstrap Installer for Windows
# PowerShell script that installs Nushell and plugins without any prerequisites
#
# This script:
# - Detects Windows platform (x86_64/arm64)
# - Downloads or builds Nushell + plugins
# - Installs to user location (%USERPROFILE%\.local\bin) or system (C:\Program Files\Nushell)
# - Updates PATH in system/user environment
# - Creates initial Nushell configuration
# - Registers all plugins automatically
# - Verifies installation
param(
[switch]$System,
[switch]$User = $true,
# 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]$InstallDir = "",
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]$NoPath,
[switch]$NoConfig,
[switch]$NoPlugins,
[switch]$BuildFromSource,
[switch]$Verify,
[switch]$Uninstall,
[string]$Version = "",
[switch]$Help
)
# Configuration
# 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
$RepoUrl = "https://github.com/jesusperezlorenzo/nushell-plugins"
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
$BinaryRepoUrl = "$RepoUrl/releases/download"
$InstallDirUser = "$env:USERPROFILE\.local\bin"
$InstallDirSystem = "${env:ProgramFiles}\Nushell\bin"
$ConfigDir = "$env:USERPROFILE\.config\nushell"
$TempDir = "$env:TEMP\nushell-install-$(Get-Random)"
# Colors for output
$Colors = @{
Red = "Red"
Green = "Green"
Yellow = "Yellow"
Blue = "Blue"
Magenta = "Magenta"
Cyan = "Cyan"
}
# Logging functions
function Write-LogInfo {
param([string]$Message)
Write-Host " $Message" -ForegroundColor $Colors.Blue
}
function Write-LogSuccess {
param([string]$Message)
Write-Host "$Message" -ForegroundColor $Colors.Green
}
function Write-LogWarn {
param([string]$Message)
Write-Host "⚠️ $Message" -ForegroundColor $Colors.Yellow
}
function Write-LogError {
param([string]$Message)
Write-Host "$Message" -ForegroundColor $Colors.Red
}
function Write-LogHeader {
param([string]$Message)
Write-Host ""
Write-Host "🚀 $Message" -ForegroundColor $Colors.Magenta
Write-Host ("=" * $Message.Length) -ForegroundColor $Colors.Magenta
}
# Usage information
function Show-Usage {
@"
Nushell + Plugins Bootstrap Installer for Windows
USAGE:
# 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
# Download and run (PowerShell 5+):
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
Invoke-WebRequest -Uri "install-url/install.ps1" | Invoke-Expression
# Or download and run with parameters:
# 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
.\install.ps1 [-System] [-User] [-InstallDir <path>] [-NoPath] [-NoConfig] [-NoPlugins] [-BuildFromSource] [-Verify] [-Uninstall] [-Version <version>] [-Help]
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
PARAMETERS:
# 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 Install to system directory (C:\Program Files\Nushell)
Requires administrator privileges (run as admin)
-User Install to user directory (%USERPROFILE%\.local\bin) [default]
No admin required - recommended for most users
-InstallDir <path> Install to custom directory (directory must be writable)
Bypasses interactive prompts when supplied explicitly
Example: -InstallDir "C:\Tools\nushell"
-SourcePath <path> Install from local archive path (no download needed)
Default: .\bin_archives (if -SourcePath is omitted)
Useful for offline installations or pre-built archives
Example: -SourcePath ".\distribution\windows-x86_64"
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
-NoPath Don't modify PATH environment variable
-NoConfig Don't create initial nushell configuration
-NoPlugins Install only nushell, skip plugins
-BuildFromSource Build from source instead of downloading binaries
-Verify Verify installation after completion
-Uninstall Remove nushell and plugins
-Version <version> Install specific version (default: latest)
-Help Show this help message
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
# Default installation (user directory, with plugins, no admin needed)
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
.\install.ps1
# 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
# Install to custom directory (no prompts, no admin needed)
.\install.ps1 -InstallDir "C:\Tools\nushell"
# Install from local archive (default: .\bin_archives)
.\install.ps1 -SourcePath
# Install from custom local archive path
.\install.ps1 -SourcePath ".\distribution\windows-x86_64"
# System installation (requires admin - right-click and 'Run as administrator')
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
.\install.ps1 -System
# Install without plugins
.\install.ps1 -NoPlugins
# Build from source
.\install.ps1 -BuildFromSource
# Install specific version
.\install.ps1 -Version "v0.107.1"
# 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
TROUBLESHOOTING:
Access denied to C:\Program Files\Nushell?
Use: .\install.ps1 -InstallDir "%USERPROFILE%\.local\bin" (no admin needed)
Or: Right-click PowerShell and select "Run as administrator"
Not sure which option to use?
Default: .\install.ps1 (installs to %USERPROFILE%\.local\bin, no admin)
Safe and recommended for most users
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
"@
}
# Platform detection
function Get-Platform {
$arch = $env:PROCESSOR_ARCHITECTURE
switch ($arch) {
"AMD64" { return "windows-x86_64" }
"ARM64" { return "windows-aarch64" }
default {
Write-LogError "Unsupported architecture: $arch"
exit 1
}
}
}
# Check if running as administrator
function Test-Admin {
$currentUser = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = New-Object Security.Principal.WindowsPrincipal($currentUser)
return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}
# Check if command exists
function Test-Command {
param([string]$Command)
try {
Get-Command $Command -ErrorAction Stop | Out-Null
return $true
} catch {
return $false
}
}
# Check dependencies for building from source
function Test-BuildDependencies {
$missing = @()
if (-not (Test-Command "git")) {
$missing += "git"
}
if (-not (Test-Command "cargo")) {
$missing += "cargo"
}
if (-not (Test-Command "rustc")) {
$missing += "rust"
}
if ($missing.Count -gt 0) {
Write-LogError "Missing build dependencies: $($missing -join ', ')"
Write-LogInfo "Please install these tools or use binary installation instead"
return $false
}
return $true
}
# Download file with progress
function Get-FileWithProgress {
param(
[string]$Url,
[string]$OutputPath,
[string]$Description = "file"
)
Write-LogInfo "Downloading $Description..."
try {
$webClient = New-Object System.Net.WebClient
$webClient.DownloadFile($Url, $OutputPath)
Write-LogSuccess "Downloaded $Description"
return $true
} catch {
Write-LogError "Failed to download $Description from $Url"
Write-LogError $_.Exception.Message
return $false
}
}
# Extract archive
function Expand-Archive {
param(
[string]$ArchivePath,
[string]$DestinationPath
)
Write-LogInfo "Extracting archive..."
try {
if ($ArchivePath -like "*.zip") {
Expand-Archive -Path $ArchivePath -DestinationPath $DestinationPath -Force
} elseif ($ArchivePath -like "*.tar.gz") {
# Use tar if available (Windows 10 build 17063 and later)
if (Test-Command "tar") {
& tar -xzf $ArchivePath -C $DestinationPath
} else {
throw "tar command not found for .tar.gz extraction"
}
} else {
throw "Unsupported archive format: $ArchivePath"
}
Write-LogSuccess "Extracted archive"
return $true
} catch {
Write-LogError "Failed to extract $ArchivePath"
Write-LogError $_.Exception.Message
return $false
}
}
# Get latest release version
function Get-LatestVersion {
try {
$response = Invoke-RestMethod -Uri "https://api.github.com/repos/your-org/nushell-plugins/releases/latest"
return $response.tag_name
} catch {
Write-LogWarn "Could not detect latest version, using v0.107.1"
return "v0.107.1"
}
}
# Download and install binaries
function Install-FromBinaries {
param(
[string]$Platform,
[string]$Version,
[string]$InstallDir,
[bool]$IncludePlugins
)
Write-LogHeader "Installing from Pre-built Binaries"
# Create temporary directory
New-Item -ItemType Directory -Path $TempDir -Force | Out-Null
Set-Location $TempDir
# Determine archive name and URL
$archiveFormat = if ($Platform -like "*windows*") { "zip" } else { "tar.gz" }
$archiveName = "nushell-plugins-$Platform-$Version.$archiveFormat"
$downloadUrl = "$BinaryRepoUrl/$Version/$archiveName"
# Download archive
if (-not (Get-FileWithProgress -Url $downloadUrl -OutputPath $archiveName -Description "Nushell distribution")) {
Write-LogWarn "Binary download failed, trying alternative..."
# Try without version prefix
$archiveName = "nushell-plugins-$Platform.$archiveFormat"
$downloadUrl = "$BinaryRepoUrl/latest/$archiveName"
if (-not (Get-FileWithProgress -Url $downloadUrl -OutputPath $archiveName -Description "Nushell distribution (latest)")) {
Write-LogError "Failed to download binaries"
return $false
}
}
# Extract archive
if (-not (Expand-Archive -ArchivePath $archiveName -DestinationPath ".")) {
return $false
}
# Find extracted directory
$extractDir = Get-ChildItem -Directory | Select-Object -First 1
if (-not $extractDir) {
Write-LogError "No extracted directory found"
return $false
}
Write-LogInfo "Installing binaries to $InstallDir..."
# Create install directory
New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null
# Install nushell binary
$nuBinary = "nu.exe"
$nuSourcePath = Join-Path $extractDir.FullName $nuBinary
if (Test-Path $nuSourcePath) {
Copy-Item $nuSourcePath -Destination $InstallDir
Write-LogSuccess "Installed nushell binary"
} else {
Write-LogError "Nushell binary not found in archive"
return $false
}
# Install plugins if requested
if ($IncludePlugins) {
$pluginFiles = Get-ChildItem -Path $extractDir.FullName -Name "nu_plugin_*.exe"
$pluginCount = 0
foreach ($pluginFile in $pluginFiles) {
$pluginSourcePath = Join-Path $extractDir.FullName $pluginFile
Copy-Item $pluginSourcePath -Destination $InstallDir
$pluginCount++
}
if ($pluginCount -gt 0) {
Write-LogSuccess "Installed $pluginCount plugins"
} else {
Write-LogWarn "No plugins found in archive"
}
}
# Copy configuration files if they exist
$configSourceDir = Join-Path $extractDir.FullName "config"
if (Test-Path $configSourceDir) {
New-Item -ItemType Directory -Path $ConfigDir -Force | Out-Null
Copy-Item -Path "$configSourceDir\*" -Destination $ConfigDir -Recurse -Force
Write-LogSuccess "Installed configuration files"
}
return $true
}
# Build and install from source
function Install-FromSource {
param(
[string]$InstallDir,
[bool]$IncludePlugins
)
Write-LogHeader "Building from Source"
# Check dependencies
if (-not (Test-BuildDependencies)) {
return $false
}
# Create temporary directory
New-Item -ItemType Directory -Path $TempDir -Force | Out-Null
Set-Location $TempDir
# Clone repository
Write-LogInfo "Cloning repository..."
try {
& git clone --recursive $RepoUrl nushell-plugins
Set-Location nushell-plugins
} catch {
Write-LogError "Failed to clone repository"
return $false
}
# Build nushell
Write-LogInfo "Building nushell..."
try {
if (Test-Command "just") {
& just build-nushell
} else {
# Fallback to manual build
Set-Location nushell
& cargo build --release --features "plugin,network,sqlite,trash-support,rustls-tls"
Set-Location ..
}
} catch {
Write-LogError "Failed to build nushell"
return $false
}
# Build plugins if requested
if ($IncludePlugins) {
Write-LogInfo "Building plugins..."
try {
if (Test-Command "just") {
& just build
} else {
# Build plugins manually
$pluginDirs = Get-ChildItem -Directory -Name "nu_plugin_*" | Where-Object { $_ -ne "nushell" }
foreach ($pluginDir in $pluginDirs) {
Write-LogInfo "Building $pluginDir..."
Set-Location $pluginDir
try {
& cargo build --release
Write-LogSuccess "Built $pluginDir"
} catch {
Write-LogWarn "Failed to build $pluginDir"
}
Set-Location ..
}
}
} catch {
Write-LogWarn "Failed to build some plugins"
}
}
# Install binaries
Write-LogInfo "Installing binaries to $InstallDir..."
New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null
# Install nushell
$nuBinary = "nushell\target\release\nu.exe"
if (Test-Path $nuBinary) {
Copy-Item $nuBinary -Destination "$InstallDir\nu.exe"
Write-LogSuccess "Installed nushell binary"
} else {
Write-LogError "Nushell binary not found"
return $false
}
# Install plugins
if ($IncludePlugins) {
$pluginCount = 0
$pluginDirs = Get-ChildItem -Directory -Name "nu_plugin_*" | Where-Object { $_ -ne "nushell" }
foreach ($pluginDir in $pluginDirs) {
$pluginBinary = "$pluginDir\target\release\$pluginDir.exe"
if (Test-Path $pluginBinary) {
Copy-Item $pluginBinary -Destination "$InstallDir\$pluginDir.exe"
$pluginCount++
}
}
if ($pluginCount -gt 0) {
Write-LogSuccess "Installed $pluginCount plugins"
} else {
Write-LogWarn "No plugins were built successfully"
}
}
return $true
}
# Register plugins with nushell
function Register-Plugins {
param(
[string]$InstallDir
)
$nuBinary = Join-Path $InstallDir "nu.exe"
if (-not (Test-Path $nuBinary)) {
Write-LogError "Nushell binary not found: $nuBinary"
return $false
}
Write-LogHeader "Registering Plugins"
# Find all plugin binaries
$pluginFiles = Get-ChildItem -Path $InstallDir -Name "nu_plugin_*.exe"
$pluginCount = 0
foreach ($pluginFile in $pluginFiles) {
$pluginPath = Join-Path $InstallDir $pluginFile
$pluginName = [System.IO.Path]::GetFileNameWithoutExtension($pluginFile)
Write-LogInfo "Registering $pluginName..."
try {
& $nuBinary -c "plugin add '$pluginPath'"
Write-LogSuccess "Registered $pluginName"
$pluginCount++
} catch {
Write-LogWarn "Failed to register $pluginName"
}
}
if ($pluginCount -gt 0) {
Write-LogSuccess "Successfully registered $pluginCount plugins"
} else {
Write-LogWarn "No plugins were registered"
}
return $true
}
# Update PATH environment variable
function Update-PathEnvironment {
param(
[string]$InstallDir,
[bool]$SystemInstall
)
Write-LogHeader "Updating PATH Environment"
# Determine scope
$scope = if ($SystemInstall) { "Machine" } else { "User" }
try {
# Get current PATH
$currentPath = [Environment]::GetEnvironmentVariable("PATH", $scope)
# Check if already in PATH
if ($currentPath -split ';' -contains $InstallDir) {
Write-LogInfo "PATH already contains $InstallDir"
return $true
}
# Add to PATH
$newPath = "$InstallDir;$currentPath"
[Environment]::SetEnvironmentVariable("PATH", $newPath, $scope)
# Update current session
$env:PATH = "$InstallDir;$env:PATH"
Write-LogSuccess "Updated PATH environment variable"
Write-LogInfo "Restart your terminal to apply changes globally"
return $true
} catch {
Write-LogError "Failed to update PATH environment variable"
Write-LogError $_.Exception.Message
return $false
}
}
# Create initial nushell configuration
function New-NushellConfig {
Write-LogHeader "Creating Nushell Configuration"
# Create config directory
New-Item -ItemType Directory -Path $ConfigDir -Force | Out-Null
# Create basic config.nu if it doesn't exist
$configFile = Join-Path $ConfigDir "config.nu"
if (-not (Test-Path $configFile)) {
@"
# Nushell Configuration
# Created by nushell-plugins installer
# Set up basic configuration
`$env.config = {
show_banner: false
edit_mode: emacs
shell_integration: true
table: {
mode: rounded
index_mode: always
show_empty: true
padding: { left: 1, right: 1 }
}
completions: {
case_sensitive: false
quick: true
partial: true
algorithm: "prefix"
}
history: {
max_size: 10000
sync_on_enter: true
file_format: "plaintext"
}
filesize: {
metric: false
format: "auto"
}
}
# Load custom commands and aliases
# Add your custom configuration below
"@ | Out-File -FilePath $configFile -Encoding utf8
Write-LogSuccess "Created config.nu"
} else {
Write-LogInfo "config.nu already exists, skipping"
}
# Create basic env.nu if it doesn't exist
$envFile = Join-Path $ConfigDir "env.nu"
if (-not (Test-Path $envFile)) {
@"
# Nushell Environment Configuration
# Created by nushell-plugins installer
# Environment variables
`$env.EDITOR = "notepad"
`$env.BROWSER = "msedge"
# Nushell specific environment
`$env.NU_LIB_DIRS = [
(`$nu.config-path | path dirname | path join "scripts")
]
`$env.NU_PLUGIN_DIRS = [
(`$nu.config-path | path dirname | path join "plugins")
]
# Add your custom environment variables below
"@ | Out-File -FilePath $envFile -Encoding utf8
Write-LogSuccess "Created env.nu"
} else {
Write-LogInfo "env.nu already exists, skipping"
}
# Create directories
$scriptsDir = Join-Path $ConfigDir "scripts"
$pluginsDir = Join-Path $ConfigDir "plugins"
New-Item -ItemType Directory -Path $scriptsDir -Force | Out-Null
New-Item -ItemType Directory -Path $pluginsDir -Force | Out-Null
return $true
}
# Verify installation
function Test-Installation {
param(
[string]$InstallDir
)
$nuBinary = Join-Path $InstallDir "nu.exe"
Write-LogHeader "Verifying Installation"
# Check if nushell binary exists
if (-not (Test-Path $nuBinary)) {
Write-LogError "Nushell binary not found: $nuBinary"
return $false
}
# Test nushell version
Write-LogInfo "Testing nushell binary..."
try {
$versionOutput = & $nuBinary --version
Write-LogSuccess "Nushell version: $versionOutput"
} catch {
Write-LogError "Failed to run nushell binary"
Write-LogError $_.Exception.Message
return $false
}
# Test basic nushell command
Write-LogInfo "Testing basic nushell functionality..."
try {
$testOutput = & $nuBinary -c "echo 'Hello from Nushell'"
if ($testOutput -eq "Hello from Nushell") {
Write-LogSuccess "Basic nushell functionality works"
} else {
Write-LogWarn "Unexpected output from basic test"
}
} catch {
Write-LogError "Basic nushell functionality failed"
return $false
}
# List registered plugins
Write-LogInfo "Checking registered plugins..."
try {
$pluginOutput = & $nuBinary -c "plugin list"
$pluginCount = ($pluginOutput | Select-String "nu_plugin_").Count
if ($pluginCount -gt 0) {
Write-LogSuccess "Found $pluginCount registered plugins"
} else {
Write-LogWarn "No plugins are registered"
}
} catch {
Write-LogWarn "Could not check plugin status"
}
# Check PATH
Write-LogInfo "Checking PATH configuration..."
try {
$nuInPath = Get-Command nu -ErrorAction SilentlyContinue
if ($nuInPath) {
Write-LogSuccess "Nushell is available in PATH"
} else {
Write-LogWarn "Nushell is not in PATH. You may need to restart your terminal."
}
} catch {
Write-LogWarn "Could not verify PATH configuration"
}
Write-LogSuccess "Installation verification complete!"
return $true
}
# Uninstall function
function Uninstall-Nushell {
Write-LogHeader "Uninstalling Nushell"
$removedFiles = 0
# Remove from user directory
if (Test-Path $InstallDirUser) {
$userBinaries = Get-ChildItem -Path $InstallDirUser -Name "nu.exe", "nu_plugin_*.exe" -ErrorAction SilentlyContinue
foreach ($binary in $userBinaries) {
$filePath = Join-Path $InstallDirUser $binary
Remove-Item $filePath -Force -ErrorAction SilentlyContinue
Write-LogSuccess "Removed $binary from $InstallDirUser"
$removedFiles++
}
}
# Remove from system directory (if accessible)
if ((Test-Admin) -and (Test-Path $InstallDirSystem)) {
$systemBinaries = Get-ChildItem -Path $InstallDirSystem -Name "nu.exe", "nu_plugin_*.exe" -ErrorAction SilentlyContinue
foreach ($binary in $systemBinaries) {
$filePath = Join-Path $InstallDirSystem $binary
Remove-Item $filePath -Force -ErrorAction SilentlyContinue
Write-LogSuccess "Removed $binary from $InstallDirSystem"
$removedFiles++
}
}
# Option to remove configuration
$response = Read-Host "Remove nushell configuration directory ($ConfigDir)? [y/N]"
if ($response -match "^[yY]") {
if (Test-Path $ConfigDir) {
Remove-Item $ConfigDir -Recurse -Force -ErrorAction SilentlyContinue
Write-LogSuccess "Removed configuration directory"
}
} else {
Write-LogInfo "Configuration directory preserved"
}
if ($removedFiles -gt 0) {
Write-LogSuccess "Uninstallation complete ($removedFiles files removed)"
Write-LogWarn "You may need to manually remove PATH entries from your environment variables"
} else {
Write-LogWarn "No nushell files found to remove"
}
}
# Main installation function
function Main {
# Handle help
if ($Help) {
Show-Usage
exit 0
}
# Handle uninstall
if ($Uninstall) {
Uninstall-Nushell
exit 0
}
# Show header
Write-LogHeader "Nushell + Plugins Installer for Windows"
Write-LogInfo "Universal bootstrap installer for Nushell and plugins"
Write-LogInfo ""
# Detect platform
$platform = Get-Platform
Write-LogInfo "Detected platform: $platform"
# Determine installation directory and check privileges
# 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 ($InstallDir) {
# Custom install directory provided - use it directly (bypass all checks)
$installDir = $InstallDir
Write-LogInfo "Using custom installation directory (via -InstallDir): $installDir"
} elseif ($System) {
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
if (-not (Test-Admin)) {
Write-LogError "System installation requires administrator privileges"
Write-LogInfo "Run PowerShell as Administrator or use -User for user installation"
exit 1
}
} else {
$installDir = $InstallDirUser
}
Write-LogInfo "Installing to: $installDir"
# Get version if not specified
if (-not $Version) {
$Version = Get-LatestVersion
}
Write-LogInfo "Version: $Version"
# Cleanup function
$cleanup = {
if (Test-Path $TempDir) {
Remove-Item $TempDir -Recurse -Force -ErrorAction SilentlyContinue
}
}
try {
# Install based on method
if ($BuildFromSource) {
if (-not (Install-FromSource -InstallDir $installDir -IncludePlugins (-not $NoPlugins))) {
Write-LogError "Source installation failed"
exit 1
}
} else {
if (-not (Install-FromBinaries -Platform $platform -Version $Version -InstallDir $installDir -IncludePlugins (-not $NoPlugins))) {
Write-LogError "Binary installation failed"
exit 1
}
}
# Register plugins
if (-not $NoPlugins) {
Register-Plugins -InstallDir $installDir
}
# Update PATH
if (-not $NoPath) {
Update-PathEnvironment -InstallDir $installDir -SystemInstall $System
}
# Create configuration
if (-not $NoConfig) {
New-NushellConfig
}
# Verify installation
if ($Verify) {
if (-not (Test-Installation -InstallDir $installDir)) {
Write-LogError "Installation verification failed"
exit 1
}
}
# Final success message
Write-LogHeader "Installation Complete!"
Write-LogSuccess "Nushell has been successfully installed to $installDir"
if (-not $NoPlugins) {
Write-LogSuccess "Plugins have been registered with Nushell"
}
if (-not $NoPath) {
Write-LogInfo "To use Nushell, restart your terminal or start a new PowerShell session"
}
Write-LogInfo ""
Write-LogInfo "Try running: nu --version"
Write-LogInfo "Or start Nushell with: nu"
if (-not $NoPlugins) {
Write-LogInfo "Check plugins with: nu -c 'plugin list'"
}
Write-LogInfo ""
Write-LogInfo "For more information, visit: https://nushell.sh"
Write-LogInfo ""
Write-LogSuccess "Happy shell scripting! 🚀"
} finally {
& $cleanup
}
}
# Run main function
Main