2025-09-24 18:52:07 +01:00
|
|
|
|
#!/bin/bash
|
|
|
|
|
|
|
|
|
|
|
|
# Universal Nushell + Plugins Bootstrap Installer
|
|
|
|
|
|
# POSIX compliant shell script that installs Nushell and plugins without any prerequisites
|
|
|
|
|
|
#
|
|
|
|
|
|
# This script:
|
|
|
|
|
|
# - Detects platform (Linux/macOS, x86_64/arm64)
|
|
|
|
|
|
# - Downloads or builds Nushell + plugins
|
|
|
|
|
|
# - Installs to user location (~/.local/bin) or system (/usr/local/bin)
|
|
|
|
|
|
# - Updates PATH in shell configuration files
|
|
|
|
|
|
# - Creates initial Nushell configuration
|
|
|
|
|
|
# - Registers all plugins automatically
|
|
|
|
|
|
# - Verifies installation
|
|
|
|
|
|
|
|
|
|
|
|
set -e # Exit on error
|
|
|
|
|
|
|
|
|
|
|
|
# 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
|
|
|
|
REPO_URL="https://github.com/jesusperezlorenzo/nushell-plugins"
|
2025-09-24 18:52:07 +01:00
|
|
|
|
BINARY_REPO_URL="$REPO_URL/releases/download"
|
|
|
|
|
|
INSTALL_DIR_USER="$HOME/.local/bin"
|
|
|
|
|
|
INSTALL_DIR_SYSTEM="/usr/local/bin"
|
|
|
|
|
|
CONFIG_DIR="$HOME/.config/nushell"
|
|
|
|
|
|
TEMP_DIR="/tmp/nushell-install-$$"
|
|
|
|
|
|
|
|
|
|
|
|
# Colors for output
|
|
|
|
|
|
RED='\033[0;31m'
|
|
|
|
|
|
GREEN='\033[0;32m'
|
|
|
|
|
|
YELLOW='\033[1;33m'
|
|
|
|
|
|
BLUE='\033[0;34m'
|
|
|
|
|
|
PURPLE='\033[0;35m'
|
|
|
|
|
|
CYAN='\033[0;36m'
|
|
|
|
|
|
NC='\033[0m' # No Color
|
|
|
|
|
|
|
|
|
|
|
|
# Logging functions
|
|
|
|
|
|
log_info() {
|
|
|
|
|
|
printf "${BLUE}ℹ️ %s${NC}\n" "$1"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
log_success() {
|
|
|
|
|
|
printf "${GREEN}✅ %s${NC}\n" "$1"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
log_warn() {
|
|
|
|
|
|
printf "${YELLOW}⚠️ %s${NC}\n" "$1"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
log_error() {
|
|
|
|
|
|
printf "${RED}❌ %s${NC}\n" "$1" >&2
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
log_header() {
|
|
|
|
|
|
printf "\n${PURPLE}🚀 %s${NC}\n" "$1"
|
|
|
|
|
|
printf "${PURPLE}%s${NC}\n" "$(printf '=%.0s' $(seq 1 ${#1}))"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Usage information
|
|
|
|
|
|
usage() {
|
|
|
|
|
|
cat << 'EOF'
|
|
|
|
|
|
Nushell + Plugins Bootstrap Installer
|
|
|
|
|
|
|
|
|
|
|
|
USAGE:
|
|
|
|
|
|
curl -L install-url/install.sh | sh
|
|
|
|
|
|
# or
|
|
|
|
|
|
./install.sh [OPTIONS]
|
|
|
|
|
|
|
|
|
|
|
|
OPTIONS:
|
# 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 (/usr/local/bin)
|
|
|
|
|
|
⚠️ Requires sudo if not root: sudo ./install.sh --system
|
|
|
|
|
|
|
2025-09-24 18:52:07 +01:00
|
|
|
|
--user Install to user directory (~/.local/bin) [default]
|
# 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
|
|
|
|
No sudo required - recommended for most users
|
|
|
|
|
|
|
|
|
|
|
|
--install-dir PATH Install to custom directory (PATH must be writable)
|
|
|
|
|
|
Bypasses interactive prompts when supplied explicitly
|
|
|
|
|
|
Example: --install-dir ~/.local/bin
|
|
|
|
|
|
|
|
|
|
|
|
--source-path PATH Install from local archive path (no download needed)
|
|
|
|
|
|
Default: ./bin_archives (if --source-path is omitted)
|
|
|
|
|
|
Useful for offline installations or pre-built archives
|
|
|
|
|
|
Example: --source-path ./distribution/darwin-arm64
|
|
|
|
|
|
|
2025-09-24 18:52:07 +01:00
|
|
|
|
--no-path Don't modify shell PATH configuration
|
|
|
|
|
|
--no-config Don't create initial nushell configuration
|
|
|
|
|
|
--no-plugins Install only nushell, skip plugins
|
|
|
|
|
|
--build-from-source 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 sudo needed)
|
2025-09-24 18:52:07 +01:00
|
|
|
|
curl -L install-url/install.sh | sh
|
|
|
|
|
|
|
# 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 sudo needed)
|
|
|
|
|
|
./install.sh --install-dir ~/.local/bin
|
|
|
|
|
|
|
|
|
|
|
|
# Install from local archive (default: ./bin_archives)
|
|
|
|
|
|
./install.sh --source-path
|
|
|
|
|
|
|
|
|
|
|
|
# Install from custom local archive path
|
|
|
|
|
|
./install.sh --source-path ./distribution/darwin-arm64
|
|
|
|
|
|
|
|
|
|
|
|
# System installation (requires sudo)
|
|
|
|
|
|
sudo ./install.sh --system
|
2025-09-24 18:52:07 +01:00
|
|
|
|
|
|
|
|
|
|
# Install without plugins
|
# 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.sh --no-plugins
|
2025-09-24 18:52:07 +01:00
|
|
|
|
|
|
|
|
|
|
# Build from source
|
# 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.sh --build-from-source
|
2025-09-24 18:52:07 +01:00
|
|
|
|
|
|
|
|
|
|
# Install specific version
|
# 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.sh --version v0.107.1
|
|
|
|
|
|
|
|
|
|
|
|
TROUBLESHOOTING:
|
|
|
|
|
|
• Permission denied to /usr/local/bin?
|
|
|
|
|
|
→ Use: --install-dir ~/.local/bin (no sudo needed)
|
|
|
|
|
|
→ Or: sudo ./install.sh --system (for system-wide installation)
|
|
|
|
|
|
|
|
|
|
|
|
• Not sure which option to use?
|
|
|
|
|
|
→ Default: ./install.sh (installs to ~/.local/bin, no sudo)
|
|
|
|
|
|
→ Safe and recommended for most users
|
2025-09-24 18:52:07 +01:00
|
|
|
|
EOF
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Platform detection
|
|
|
|
|
|
detect_platform() {
|
|
|
|
|
|
local os arch
|
|
|
|
|
|
|
|
|
|
|
|
# Detect OS
|
|
|
|
|
|
case "$(uname -s)" in
|
|
|
|
|
|
Linux) os="linux" ;;
|
|
|
|
|
|
Darwin) os="darwin" ;;
|
|
|
|
|
|
CYGWIN*|MINGW*|MSYS*) os="windows" ;;
|
|
|
|
|
|
*) log_error "Unsupported OS: $(uname -s)"; exit 1 ;;
|
|
|
|
|
|
esac
|
|
|
|
|
|
|
|
|
|
|
|
# Detect architecture
|
|
|
|
|
|
case "$(uname -m)" in
|
|
|
|
|
|
x86_64|amd64) arch="x86_64" ;;
|
|
|
|
|
|
aarch64|arm64) arch="arm64" ;;
|
|
|
|
|
|
armv7l) arch="armv7" ;;
|
|
|
|
|
|
*) log_error "Unsupported architecture: $(uname -m)"; exit 1 ;;
|
|
|
|
|
|
esac
|
|
|
|
|
|
|
|
|
|
|
|
# Special handling for Darwin arm64
|
|
|
|
|
|
if [ "$os" = "darwin" ] && [ "$arch" = "arm64" ]; then
|
|
|
|
|
|
arch="arm64"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
echo "${os}-${arch}"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Check if command exists
|
|
|
|
|
|
command_exists() {
|
|
|
|
|
|
command -v "$1" >/dev/null 2>&1
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Check dependencies for building from source
|
|
|
|
|
|
check_build_dependencies() {
|
|
|
|
|
|
local missing=""
|
|
|
|
|
|
|
|
|
|
|
|
if ! command_exists "git"; then
|
|
|
|
|
|
missing="$missing git"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
if ! command_exists "cargo"; then
|
|
|
|
|
|
missing="$missing cargo"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
if ! command_exists "rustc"; then
|
|
|
|
|
|
missing="$missing rust"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
if [ -n "$missing" ]; then
|
|
|
|
|
|
log_error "Missing build dependencies:$missing"
|
|
|
|
|
|
log_info "Please install these tools or use binary installation instead"
|
|
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
return 0
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Download file with progress
|
|
|
|
|
|
download_file() {
|
|
|
|
|
|
local url="$1"
|
|
|
|
|
|
local output="$2"
|
|
|
|
|
|
local desc="${3:-file}"
|
|
|
|
|
|
|
|
|
|
|
|
log_info "Downloading $desc..."
|
|
|
|
|
|
|
|
|
|
|
|
if command_exists "curl"; then
|
|
|
|
|
|
if ! curl -L --fail --progress-bar "$url" -o "$output"; then
|
|
|
|
|
|
log_error "Failed to download $desc from $url"
|
|
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
elif command_exists "wget"; then
|
|
|
|
|
|
if ! wget --progress=bar:force "$url" -O "$output"; then
|
|
|
|
|
|
log_error "Failed to download $desc from $url"
|
|
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
else
|
|
|
|
|
|
log_error "Neither curl nor wget is available"
|
|
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
log_success "Downloaded $desc"
|
|
|
|
|
|
return 0
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Extract archive
|
|
|
|
|
|
extract_archive() {
|
|
|
|
|
|
local archive="$1"
|
|
|
|
|
|
local destination="$2"
|
|
|
|
|
|
|
|
|
|
|
|
log_info "Extracting archive..."
|
|
|
|
|
|
|
|
|
|
|
|
case "$archive" in
|
|
|
|
|
|
*.tar.gz)
|
|
|
|
|
|
if ! tar -xzf "$archive" -C "$destination"; then
|
|
|
|
|
|
log_error "Failed to extract $archive"
|
|
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
;;
|
|
|
|
|
|
*.zip)
|
|
|
|
|
|
if command_exists "unzip"; then
|
|
|
|
|
|
if ! unzip -q "$archive" -d "$destination"; then
|
|
|
|
|
|
log_error "Failed to extract $archive"
|
|
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
else
|
|
|
|
|
|
log_error "unzip command not found"
|
|
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
;;
|
|
|
|
|
|
*)
|
|
|
|
|
|
log_error "Unsupported archive format: $archive"
|
|
|
|
|
|
return 1
|
|
|
|
|
|
;;
|
|
|
|
|
|
esac
|
|
|
|
|
|
|
|
|
|
|
|
log_success "Extracted archive"
|
|
|
|
|
|
return 0
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Get latest release version
|
|
|
|
|
|
get_latest_version() {
|
|
|
|
|
|
local version=""
|
|
|
|
|
|
|
|
|
|
|
|
if command_exists "curl"; then
|
# 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
|
|
|
|
version=$(curl -s "https://api.github.com/repos/jesusperezlorenzo/nushell-plugins/releases/latest" | \
|
2025-09-24 18:52:07 +01:00
|
|
|
|
grep '"tag_name":' | \
|
|
|
|
|
|
sed -E 's/.*"([^"]+)".*/\1/')
|
|
|
|
|
|
elif command_exists "wget"; then
|
# 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
|
|
|
|
version=$(wget -qO- "https://api.github.com/repos/jesusperezlorenzo/nushell-plugins/releases/latest" | \
|
2025-09-24 18:52:07 +01:00
|
|
|
|
grep '"tag_name":' | \
|
|
|
|
|
|
sed -E 's/.*"([^"]+)".*/\1/')
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
if [ -z "$version" ]; then
|
|
|
|
|
|
# Fallback to a reasonable default
|
|
|
|
|
|
version="v0.107.1"
|
|
|
|
|
|
log_warn "Could not detect latest version, using $version"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
echo "$version"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Download and install binaries
|
|
|
|
|
|
install_from_binaries() {
|
|
|
|
|
|
local platform="$1"
|
|
|
|
|
|
local version="$2"
|
|
|
|
|
|
local install_dir="$3"
|
|
|
|
|
|
local include_plugins="$4"
|
|
|
|
|
|
|
|
|
|
|
|
log_header "Installing from Pre-built Binaries"
|
|
|
|
|
|
|
|
|
|
|
|
# Create temporary directory
|
|
|
|
|
|
mkdir -p "$TEMP_DIR"
|
|
|
|
|
|
cd "$TEMP_DIR"
|
|
|
|
|
|
|
|
|
|
|
|
# Determine archive name and URL
|
|
|
|
|
|
local archive_name="nushell-plugins-${platform}-${version}.tar.gz"
|
|
|
|
|
|
local download_url="${BINARY_REPO_URL}/${version}/${archive_name}"
|
|
|
|
|
|
|
|
|
|
|
|
# Download archive
|
|
|
|
|
|
if ! download_file "$download_url" "$archive_name" "Nushell distribution"; then
|
|
|
|
|
|
log_warn "Binary download failed, trying alternative..."
|
|
|
|
|
|
# Try without version prefix
|
|
|
|
|
|
archive_name="nushell-plugins-${platform}.tar.gz"
|
|
|
|
|
|
download_url="${BINARY_REPO_URL}/latest/${archive_name}"
|
|
|
|
|
|
if ! download_file "$download_url" "$archive_name" "Nushell distribution (latest)"; then
|
|
|
|
|
|
log_error "Failed to download binaries"
|
|
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Extract archive
|
|
|
|
|
|
if ! extract_archive "$archive_name" "."; then
|
|
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Find extracted directory
|
|
|
|
|
|
local extract_dir=""
|
|
|
|
|
|
for dir in */; do
|
|
|
|
|
|
if [ -d "$dir" ]; then
|
|
|
|
|
|
extract_dir="$dir"
|
|
|
|
|
|
break
|
|
|
|
|
|
fi
|
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
|
|
if [ -z "$extract_dir" ]; then
|
|
|
|
|
|
log_error "No extracted directory found"
|
|
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
log_info "Installing binaries to $install_dir..."
|
|
|
|
|
|
|
|
|
|
|
|
# Create install directory
|
|
|
|
|
|
mkdir -p "$install_dir"
|
|
|
|
|
|
|
|
|
|
|
|
# Install nushell binary
|
|
|
|
|
|
local nu_binary="nu"
|
|
|
|
|
|
if [ "$platform" = "windows-x86_64" ]; then
|
|
|
|
|
|
nu_binary="nu.exe"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
# 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
|
|
|
|
# Check for binary - try both root and bin/ subdirectory
|
|
|
|
|
|
local nu_path="${extract_dir}${nu_binary}"
|
|
|
|
|
|
if [ ! -f "$nu_path" ]; then
|
|
|
|
|
|
# Try bin/ subdirectory
|
|
|
|
|
|
nu_path="${extract_dir}bin/${nu_binary}"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
if [ -f "$nu_path" ]; then
|
|
|
|
|
|
cp "$nu_path" "$install_dir/"
|
2025-09-24 18:52:07 +01:00
|
|
|
|
chmod +x "${install_dir}/${nu_binary}"
|
|
|
|
|
|
log_success "Installed nushell binary"
|
|
|
|
|
|
else
|
# 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
|
|
|
|
log_error "Nushell binary not found in archive (tried root and bin/ directory)"
|
2025-09-24 18:52:07 +01:00
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Install plugins if requested
|
|
|
|
|
|
if [ "$include_plugins" = "true" ]; then
|
|
|
|
|
|
local plugin_count=0
|
# 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
|
|
|
|
|
|
|
|
|
|
# Try both root and bin/ subdirectory for plugins
|
|
|
|
|
|
for plugin_file in "${extract_dir}"nu_plugin_* "${extract_dir}bin/"nu_plugin_*; do
|
2025-09-24 18:52:07 +01:00
|
|
|
|
if [ -f "$plugin_file" ]; then
|
|
|
|
|
|
local plugin_name=$(basename "$plugin_file")
|
|
|
|
|
|
cp "$plugin_file" "$install_dir/"
|
|
|
|
|
|
chmod +x "${install_dir}/${plugin_name}"
|
|
|
|
|
|
plugin_count=$((plugin_count + 1))
|
|
|
|
|
|
fi
|
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
|
|
if [ $plugin_count -gt 0 ]; then
|
|
|
|
|
|
log_success "Installed $plugin_count plugins"
|
|
|
|
|
|
else
|
|
|
|
|
|
log_warn "No plugins found in archive"
|
|
|
|
|
|
fi
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Copy configuration files if they exist
|
|
|
|
|
|
if [ -d "${extract_dir}config/" ]; then
|
|
|
|
|
|
mkdir -p "$CONFIG_DIR"
|
|
|
|
|
|
cp -r "${extract_dir}config/"* "$CONFIG_DIR/"
|
|
|
|
|
|
log_success "Installed configuration files"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
return 0
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Build and install from source
|
|
|
|
|
|
install_from_source() {
|
|
|
|
|
|
local install_dir="$1"
|
|
|
|
|
|
local include_plugins="$2"
|
|
|
|
|
|
|
|
|
|
|
|
log_header "Building from Source"
|
|
|
|
|
|
|
|
|
|
|
|
# Check dependencies
|
|
|
|
|
|
if ! check_build_dependencies; then
|
|
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Create temporary directory
|
|
|
|
|
|
mkdir -p "$TEMP_DIR"
|
|
|
|
|
|
cd "$TEMP_DIR"
|
|
|
|
|
|
|
|
|
|
|
|
# Clone repository
|
|
|
|
|
|
log_info "Cloning repository..."
|
# 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 ! git clone --recursive "https://github.com/jesusperezlorenzo/nushell-plugins" nushell-plugins; then
|
2025-09-24 18:52:07 +01:00
|
|
|
|
log_error "Failed to clone repository"
|
|
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
cd nushell-plugins
|
|
|
|
|
|
|
|
|
|
|
|
# Build nushell
|
|
|
|
|
|
log_info "Building nushell..."
|
|
|
|
|
|
if command_exists "just"; then
|
|
|
|
|
|
if ! just build-nushell; then
|
|
|
|
|
|
log_error "Failed to build nushell with just"
|
|
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
else
|
|
|
|
|
|
# Fallback to manual build
|
|
|
|
|
|
cd nushell
|
|
|
|
|
|
if ! cargo build --release --features "plugin,network,sqlite,trash-support,rustls-tls"; then
|
|
|
|
|
|
log_error "Failed to build nushell"
|
|
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
cd ..
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Build plugins if requested
|
|
|
|
|
|
if [ "$include_plugins" = "true" ]; then
|
|
|
|
|
|
log_info "Building plugins..."
|
|
|
|
|
|
if command_exists "just"; then
|
|
|
|
|
|
if ! just build; then
|
|
|
|
|
|
log_warn "Failed to build some plugins"
|
|
|
|
|
|
fi
|
|
|
|
|
|
else
|
|
|
|
|
|
# Build plugins manually
|
|
|
|
|
|
for plugin_dir in nu_plugin_*; do
|
|
|
|
|
|
if [ -d "$plugin_dir" ] && [ "$plugin_dir" != "nushell" ]; then
|
|
|
|
|
|
log_info "Building $plugin_dir..."
|
|
|
|
|
|
cd "$plugin_dir"
|
|
|
|
|
|
if cargo build --release; then
|
|
|
|
|
|
log_success "Built $plugin_dir"
|
|
|
|
|
|
else
|
|
|
|
|
|
log_warn "Failed to build $plugin_dir"
|
|
|
|
|
|
fi
|
|
|
|
|
|
cd ..
|
|
|
|
|
|
fi
|
|
|
|
|
|
done
|
|
|
|
|
|
fi
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Install binaries
|
|
|
|
|
|
log_info "Installing binaries to $install_dir..."
|
|
|
|
|
|
mkdir -p "$install_dir"
|
|
|
|
|
|
|
|
|
|
|
|
# Install nushell
|
|
|
|
|
|
local nu_binary="nushell/target/release/nu"
|
|
|
|
|
|
if [ -f "$nu_binary" ]; then
|
|
|
|
|
|
cp "$nu_binary" "$install_dir/"
|
|
|
|
|
|
chmod +x "${install_dir}/nu"
|
|
|
|
|
|
log_success "Installed nushell binary"
|
|
|
|
|
|
else
|
|
|
|
|
|
log_error "Nushell binary not found"
|
|
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Install plugins
|
|
|
|
|
|
if [ "$include_plugins" = "true" ]; then
|
|
|
|
|
|
local plugin_count=0
|
|
|
|
|
|
for plugin_dir in nu_plugin_*; do
|
|
|
|
|
|
if [ -d "$plugin_dir" ] && [ "$plugin_dir" != "nushell" ]; then
|
|
|
|
|
|
local plugin_binary="${plugin_dir}/target/release/${plugin_dir}"
|
|
|
|
|
|
if [ -f "$plugin_binary" ]; then
|
|
|
|
|
|
cp "$plugin_binary" "$install_dir/"
|
|
|
|
|
|
chmod +x "${install_dir}/${plugin_dir}"
|
|
|
|
|
|
plugin_count=$((plugin_count + 1))
|
|
|
|
|
|
fi
|
# 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
|
|
|
|
fi
|
2025-09-24 18:52:07 +01:00
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
|
|
if [ $plugin_count -gt 0 ]; then
|
|
|
|
|
|
log_success "Installed $plugin_count plugins"
|
|
|
|
|
|
else
|
|
|
|
|
|
log_warn "No plugins were built successfully"
|
|
|
|
|
|
fi
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
return 0
|
|
|
|
|
|
}
|
|
|
|
|
|
|
# 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 from local source (directory or extracted archive)
|
|
|
|
|
|
install_from_local() {
|
|
|
|
|
|
local source_dir="$1"
|
|
|
|
|
|
local install_dir="$2"
|
|
|
|
|
|
local include_plugins="$3"
|
|
|
|
|
|
|
|
|
|
|
|
log_header "Installing from Local Source"
|
|
|
|
|
|
|
|
|
|
|
|
# Ensure install directory exists
|
|
|
|
|
|
mkdir -p "$install_dir"
|
|
|
|
|
|
|
|
|
|
|
|
# Look for nushell binary
|
|
|
|
|
|
local nu_binary=""
|
|
|
|
|
|
if [ -f "$source_dir/nu" ]; then
|
|
|
|
|
|
nu_binary="$source_dir/nu"
|
|
|
|
|
|
elif [ -f "$source_dir/bin/nu" ]; then
|
|
|
|
|
|
nu_binary="$source_dir/bin/nu"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
if [ -z "$nu_binary" ]; then
|
|
|
|
|
|
log_error "Nushell binary not found in: $source_dir"
|
|
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Copy nushell binary
|
|
|
|
|
|
log_info "Copying nushell binary..."
|
|
|
|
|
|
cp "$nu_binary" "$install_dir/"
|
|
|
|
|
|
chmod +x "${install_dir}/nu"
|
|
|
|
|
|
log_success "Installed nushell binary"
|
|
|
|
|
|
|
|
|
|
|
|
# Install plugins if requested
|
|
|
|
|
|
if [ "$include_plugins" = "true" ]; then
|
|
|
|
|
|
local plugin_count=0
|
|
|
|
|
|
|
|
|
|
|
|
# Look for plugin binaries in both root and bin subdirectory
|
|
|
|
|
|
for plugin_file in "$source_dir"/nu_plugin_* "$source_dir"/bin/nu_plugin_*; do
|
|
|
|
|
|
if [ -f "$plugin_file" ]; then
|
|
|
|
|
|
local plugin_name=$(basename "$plugin_file")
|
|
|
|
|
|
# Skip metadata files (.d files)
|
|
|
|
|
|
if [[ "$plugin_name" != *.d ]]; then
|
|
|
|
|
|
log_info "Copying plugin: $plugin_name"
|
|
|
|
|
|
cp "$plugin_file" "$install_dir/"
|
|
|
|
|
|
chmod +x "${install_dir}/${plugin_name}"
|
|
|
|
|
|
plugin_count=$((plugin_count + 1))
|
|
|
|
|
|
fi
|
|
|
|
|
|
fi
|
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
|
|
if [ $plugin_count -gt 0 ]; then
|
|
|
|
|
|
log_success "Installed $plugin_count plugins"
|
|
|
|
|
|
else
|
|
|
|
|
|
log_info "No plugins found in local source"
|
|
|
|
|
|
fi
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
return 0
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-24 18:52:07 +01:00
|
|
|
|
# Register plugins with nushell
|
|
|
|
|
|
register_plugins() {
|
|
|
|
|
|
local install_dir="$1"
|
|
|
|
|
|
local nu_binary="${install_dir}/nu"
|
|
|
|
|
|
|
|
|
|
|
|
if [ ! -f "$nu_binary" ]; then
|
|
|
|
|
|
log_error "Nushell binary not found: $nu_binary"
|
|
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
log_header "Registering Plugins"
|
|
|
|
|
|
|
|
|
|
|
|
# Find all plugin binaries
|
|
|
|
|
|
local plugin_count=0
|
# 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
|
|
|
|
local failed_plugins=()
|
|
|
|
|
|
local incompatible_plugins=()
|
|
|
|
|
|
|
2025-09-24 18:52:07 +01:00
|
|
|
|
for plugin_file in "${install_dir}"/nu_plugin_*; do
|
|
|
|
|
|
if [ -f "$plugin_file" ] && [ -x "$plugin_file" ]; then
|
|
|
|
|
|
local plugin_name=$(basename "$plugin_file")
|
|
|
|
|
|
log_info "Registering $plugin_name..."
|
|
|
|
|
|
|
# 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
|
|
|
|
# Capture both stdout and stderr to detect incompatibility
|
|
|
|
|
|
local output
|
|
|
|
|
|
output=$("$nu_binary" -c "plugin add '$plugin_file'" 2>&1)
|
|
|
|
|
|
local exit_code=$?
|
|
|
|
|
|
|
|
|
|
|
|
if [ $exit_code -eq 0 ]; then
|
2025-09-24 18:52:07 +01:00
|
|
|
|
log_success "Registered $plugin_name"
|
|
|
|
|
|
plugin_count=$((plugin_count + 1))
|
|
|
|
|
|
else
|
# 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
|
|
|
|
# Check if it's a version incompatibility error
|
|
|
|
|
|
if echo "$output" | grep -q "is not compatible with version\|is compiled for nushell version"; then
|
|
|
|
|
|
log_warn "Skipping $plugin_name: Version mismatch (built for different Nushell version)"
|
|
|
|
|
|
incompatible_plugins+=("$plugin_name")
|
|
|
|
|
|
else
|
|
|
|
|
|
log_warn "Failed to register $plugin_name: $(echo "$output" | head -1)"
|
|
|
|
|
|
failed_plugins+=("$plugin_name")
|
|
|
|
|
|
fi
|
2025-09-24 18:52:07 +01:00
|
|
|
|
fi
|
|
|
|
|
|
fi
|
|
|
|
|
|
done
|
|
|
|
|
|
|
# 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
|
|
|
|
echo ""
|
2025-09-24 18:52:07 +01:00
|
|
|
|
if [ $plugin_count -gt 0 ]; then
|
|
|
|
|
|
log_success "Successfully registered $plugin_count plugins"
|
|
|
|
|
|
else
|
|
|
|
|
|
log_warn "No plugins were registered"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
# 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
|
|
|
|
# Report incompatible plugins
|
|
|
|
|
|
if [ ${#incompatible_plugins[@]} -gt 0 ]; then
|
|
|
|
|
|
log_info ""
|
|
|
|
|
|
log_warn "Skipped ${#incompatible_plugins[@]} incompatible plugins (version mismatch):"
|
|
|
|
|
|
for plugin in "${incompatible_plugins[@]}"; do
|
|
|
|
|
|
log_info " - $plugin"
|
|
|
|
|
|
done
|
|
|
|
|
|
log_info "These plugins were built for a different Nushell version."
|
|
|
|
|
|
log_info "They can be rebuilt locally if needed or updated in the distribution."
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Report failed plugins
|
|
|
|
|
|
if [ ${#failed_plugins[@]} -gt 0 ]; then
|
|
|
|
|
|
log_info ""
|
|
|
|
|
|
log_error "Failed to register ${#failed_plugins[@]} plugins:"
|
|
|
|
|
|
for plugin in "${failed_plugins[@]}"; do
|
|
|
|
|
|
log_info " - $plugin"
|
|
|
|
|
|
done
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
2025-09-24 18:52:07 +01:00
|
|
|
|
return 0
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Update PATH in shell configuration
|
|
|
|
|
|
update_shell_path() {
|
|
|
|
|
|
local install_dir="$1"
|
|
|
|
|
|
|
|
|
|
|
|
log_header "Updating Shell Configuration"
|
|
|
|
|
|
|
|
|
|
|
|
# List of shell configuration files to update
|
|
|
|
|
|
local shell_configs=""
|
|
|
|
|
|
|
|
|
|
|
|
# Detect current shell and add its config file first
|
|
|
|
|
|
case "$SHELL" in
|
|
|
|
|
|
*/bash) shell_configs="$HOME/.bashrc $HOME/.bash_profile" ;;
|
|
|
|
|
|
*/zsh) shell_configs="$HOME/.zshrc" ;;
|
|
|
|
|
|
*/fish) shell_configs="$HOME/.config/fish/config.fish" ;;
|
|
|
|
|
|
*/nu) shell_configs="$HOME/.config/nushell/env.nu" ;;
|
|
|
|
|
|
esac
|
|
|
|
|
|
|
|
|
|
|
|
# Add common configuration files
|
|
|
|
|
|
shell_configs="$shell_configs $HOME/.profile"
|
|
|
|
|
|
|
|
|
|
|
|
local updated=false
|
# 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
|
|
|
|
local path_found=false
|
2025-09-24 18:52:07 +01:00
|
|
|
|
|
|
|
|
|
|
for config_file in $shell_configs; do
|
|
|
|
|
|
if [ -f "$config_file" ] || [ "$config_file" = "$HOME/.bashrc" ] || [ "$config_file" = "$HOME/.profile" ]; then
|
|
|
|
|
|
# Check if already in PATH
|
|
|
|
|
|
if grep -q "$install_dir" "$config_file" 2>/dev/null; then
|
# 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
|
|
|
|
log_info "PATH already configured in $(basename "$config_file")"
|
|
|
|
|
|
path_found=true
|
2025-09-24 18:52:07 +01:00
|
|
|
|
continue
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Create config file if it doesn't exist
|
|
|
|
|
|
if [ ! -f "$config_file" ]; then
|
|
|
|
|
|
touch "$config_file"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Add PATH update to config file
|
|
|
|
|
|
case "$config_file" in
|
|
|
|
|
|
*.fish)
|
|
|
|
|
|
echo "fish_add_path $install_dir" >> "$config_file"
|
|
|
|
|
|
;;
|
|
|
|
|
|
*/env.nu)
|
|
|
|
|
|
echo "\$env.PATH = (\$env.PATH | split row (char esep) | append \"$install_dir\" | uniq)" >> "$config_file"
|
|
|
|
|
|
;;
|
|
|
|
|
|
*)
|
|
|
|
|
|
echo "" >> "$config_file"
|
|
|
|
|
|
echo "# Added by nushell installer" >> "$config_file"
|
|
|
|
|
|
echo "export PATH=\"$install_dir:\$PATH\"" >> "$config_file"
|
|
|
|
|
|
;;
|
|
|
|
|
|
esac
|
|
|
|
|
|
|
|
|
|
|
|
log_success "Updated $(basename "$config_file")"
|
|
|
|
|
|
updated=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
|
|
|
|
path_found=true
|
2025-09-24 18:52:07 +01:00
|
|
|
|
fi
|
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
|
|
if [ "$updated" = "true" ]; then
|
# 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
|
|
|
|
log_success "Shell configuration updated"
|
|
|
|
|
|
log_info "Please restart your terminal or run 'source ~/.bashrc' to apply changes"
|
|
|
|
|
|
elif [ "$path_found" = "true" ]; then
|
|
|
|
|
|
log_success "PATH is already configured in your shell configuration files"
|
|
|
|
|
|
log_info "No changes were needed"
|
2025-09-24 18:52:07 +01:00
|
|
|
|
else
|
# 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
|
|
|
|
log_warn "Could not find or update shell configuration files"
|
|
|
|
|
|
log_info "Please manually add the following to your shell configuration:"
|
|
|
|
|
|
log_info "export PATH=\"$install_dir:\$PATH\""
|
2025-09-24 18:52:07 +01:00
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Update current session PATH
|
|
|
|
|
|
export PATH="$install_dir:$PATH"
|
|
|
|
|
|
log_success "Updated PATH for current session"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Create initial nushell configuration
|
|
|
|
|
|
create_nushell_config() {
|
|
|
|
|
|
log_header "Creating Nushell Configuration"
|
|
|
|
|
|
|
|
|
|
|
|
# Create config directory
|
|
|
|
|
|
mkdir -p "$CONFIG_DIR"
|
|
|
|
|
|
|
|
|
|
|
|
# Create basic config.nu if it doesn't exist
|
|
|
|
|
|
local config_file="$CONFIG_DIR/config.nu"
|
|
|
|
|
|
if [ ! -f "$config_file" ]; then
|
|
|
|
|
|
cat > "$config_file" << 'EOF'
|
|
|
|
|
|
# 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
|
|
|
|
|
|
EOF
|
|
|
|
|
|
log_success "Created config.nu"
|
|
|
|
|
|
else
|
|
|
|
|
|
log_info "config.nu already exists, skipping"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Create basic env.nu if it doesn't exist
|
|
|
|
|
|
local env_file="$CONFIG_DIR/env.nu"
|
|
|
|
|
|
if [ ! -f "$env_file" ]; then
|
|
|
|
|
|
cat > "$env_file" << 'EOF'
|
|
|
|
|
|
# Nushell Environment Configuration
|
|
|
|
|
|
# Created by nushell-plugins installer
|
|
|
|
|
|
|
|
|
|
|
|
# Environment variables
|
|
|
|
|
|
$env.EDITOR = "nano"
|
|
|
|
|
|
$env.BROWSER = "firefox"
|
|
|
|
|
|
|
|
|
|
|
|
# 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
|
|
|
|
|
|
EOF
|
|
|
|
|
|
log_success "Created env.nu"
|
|
|
|
|
|
else
|
|
|
|
|
|
log_info "env.nu already exists, skipping"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Create scripts directory
|
|
|
|
|
|
local scripts_dir="$CONFIG_DIR/scripts"
|
|
|
|
|
|
mkdir -p "$scripts_dir"
|
|
|
|
|
|
|
|
|
|
|
|
# Create plugins directory
|
|
|
|
|
|
local plugins_dir="$CONFIG_DIR/plugins"
|
|
|
|
|
|
mkdir -p "$plugins_dir"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Verify installation
|
|
|
|
|
|
verify_installation() {
|
|
|
|
|
|
local install_dir="$1"
|
|
|
|
|
|
local nu_binary="${install_dir}/nu"
|
|
|
|
|
|
|
|
|
|
|
|
log_header "Verifying Installation"
|
|
|
|
|
|
|
|
|
|
|
|
# Check if nushell binary exists and is executable
|
|
|
|
|
|
if [ ! -f "$nu_binary" ]; then
|
|
|
|
|
|
log_error "Nushell binary not found: $nu_binary"
|
|
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
if [ ! -x "$nu_binary" ]; then
|
|
|
|
|
|
log_error "Nushell binary is not executable: $nu_binary"
|
|
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Test nushell version
|
|
|
|
|
|
log_info "Testing nushell binary..."
|
|
|
|
|
|
local version_output
|
|
|
|
|
|
if version_output=$("$nu_binary" --version 2>&1); then
|
|
|
|
|
|
log_success "Nushell version: $version_output"
|
|
|
|
|
|
else
|
|
|
|
|
|
log_error "Failed to run nushell binary"
|
|
|
|
|
|
log_error "Output: $version_output"
|
|
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Test basic nushell command
|
|
|
|
|
|
log_info "Testing basic nushell functionality..."
|
|
|
|
|
|
if "$nu_binary" -c "echo 'Hello from Nushell'" >/dev/null 2>&1; then
|
|
|
|
|
|
log_success "Basic nushell functionality works"
|
|
|
|
|
|
else
|
|
|
|
|
|
log_error "Basic nushell functionality failed"
|
|
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# List registered plugins
|
|
|
|
|
|
log_info "Checking registered plugins..."
|
|
|
|
|
|
local plugin_output
|
|
|
|
|
|
if plugin_output=$("$nu_binary" -c "plugin list" 2>&1); then
|
|
|
|
|
|
local plugin_count=$(echo "$plugin_output" | grep -c "nu_plugin_" || true)
|
|
|
|
|
|
if [ "$plugin_count" -gt 0 ]; then
|
|
|
|
|
|
log_success "Found $plugin_count registered plugins"
|
|
|
|
|
|
else
|
|
|
|
|
|
log_warn "No plugins are registered"
|
|
|
|
|
|
fi
|
|
|
|
|
|
else
|
|
|
|
|
|
log_warn "Could not check plugin status"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Check PATH
|
|
|
|
|
|
log_info "Checking PATH configuration..."
|
|
|
|
|
|
if command -v nu >/dev/null 2>&1; then
|
|
|
|
|
|
log_success "Nushell is available in PATH"
|
|
|
|
|
|
else
|
|
|
|
|
|
log_warn "Nushell is not in PATH. You may need to restart your terminal."
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
log_success "Installation verification complete!"
|
|
|
|
|
|
return 0
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Uninstall function
|
|
|
|
|
|
uninstall_nushell() {
|
|
|
|
|
|
log_header "Uninstalling Nushell"
|
|
|
|
|
|
|
|
|
|
|
|
local removed_files=0
|
|
|
|
|
|
|
|
|
|
|
|
# Remove from user directory
|
|
|
|
|
|
if [ -d "$INSTALL_DIR_USER" ]; then
|
|
|
|
|
|
for binary in nu nu_plugin_*; do
|
|
|
|
|
|
local file_path="$INSTALL_DIR_USER/$binary"
|
|
|
|
|
|
if [ -f "$file_path" ]; then
|
|
|
|
|
|
rm -f "$file_path"
|
|
|
|
|
|
log_success "Removed $binary from $INSTALL_DIR_USER"
|
|
|
|
|
|
removed_files=$((removed_files + 1))
|
|
|
|
|
|
fi
|
|
|
|
|
|
done
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Remove from system directory (if accessible)
|
|
|
|
|
|
if [ -w "$INSTALL_DIR_SYSTEM" ] 2>/dev/null; then
|
|
|
|
|
|
for binary in nu nu_plugin_*; do
|
|
|
|
|
|
local file_path="$INSTALL_DIR_SYSTEM/$binary"
|
|
|
|
|
|
if [ -f "$file_path" ]; then
|
|
|
|
|
|
rm -f "$file_path"
|
|
|
|
|
|
log_success "Removed $binary from $INSTALL_DIR_SYSTEM"
|
|
|
|
|
|
removed_files=$((removed_files + 1))
|
|
|
|
|
|
fi
|
|
|
|
|
|
done
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Option to remove configuration
|
|
|
|
|
|
printf "Remove nushell configuration directory ($CONFIG_DIR)? [y/N]: "
|
|
|
|
|
|
read -r response
|
|
|
|
|
|
case "$response" in
|
|
|
|
|
|
[yY]|[yY][eE][sS])
|
|
|
|
|
|
if [ -d "$CONFIG_DIR" ]; then
|
|
|
|
|
|
rm -rf "$CONFIG_DIR"
|
|
|
|
|
|
log_success "Removed configuration directory"
|
|
|
|
|
|
fi
|
|
|
|
|
|
;;
|
|
|
|
|
|
*)
|
|
|
|
|
|
log_info "Configuration directory preserved"
|
|
|
|
|
|
;;
|
|
|
|
|
|
esac
|
|
|
|
|
|
|
|
|
|
|
|
if [ $removed_files -gt 0 ]; then
|
|
|
|
|
|
log_success "Uninstallation complete ($removed_files files removed)"
|
|
|
|
|
|
log_warn "You may need to manually remove PATH entries from your shell configuration"
|
|
|
|
|
|
else
|
|
|
|
|
|
log_warn "No nushell files found to remove"
|
|
|
|
|
|
fi
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Main installation function
|
|
|
|
|
|
main() {
|
|
|
|
|
|
local install_mode="user"
|
# Summary
feat: bootstrap installer with robust archive extraction, version mismatch handling, and improved PATH messaging
## Detailed Description
This commit implements a production-ready bootstrap installer with comprehensive error handling, version-agnostic archive extraction, and clear user messaging. All improvements follow DRY principles using symlink-based architecture for single-source-of-truth maintenance.
## Major Changes (Session 2025-10-19)
### 0. Bootstrap Installer & Distribution Improvements (NEW)
#### 0a. Install Script Architecture - DRY Design
**Issue**: Code duplication across installation paths
- `./install.sh`, `./scripts/templates/install.sh`, `installers/bootstrap/install.sh` were separate copies
- Changes required updating multiple files
- Risk of divergence and inconsistency
**Solution**: Implemented symlink-based DRY architecture
- Single source of truth: `installers/bootstrap/install.sh` (1,247 lines)
- Symlinks created:
- `./install.sh` → `installers/bootstrap/install.sh`
- `./scripts/templates/install.sh` → `installers/bootstrap/install.sh`
- All changes automatically propagate through symlinks
- No code duplication
**Impact**:
- ✅ Single maintenance point for all install scripts
- ✅ Consistent behavior across all paths
- ✅ Reduced maintenance burden
- ✅ No divergence risk
#### 0b. Archive Extraction - Version-Agnostic Binary Detection
**Issue**: "No Nushell binary found in extracted archive"
- Script failed when extracting from `nushell-full-0.108.0-darwin-arm64.tar.gz`
- Error occurred even though binaries were present at `nushell-full-0.108.0/bin/nu`
**Root Cause**: `find` command returning parent directory itself in results
```bash
# ❌ OLD - find returns parent directory first
local extracted=$(find "$extract_dir" -maxdepth 1 -type d -name "nushell-*" | head -1)
# Returns: /tmp/nushell-install-22919/nushell-extract (parent!)
# Should return: /tmp/nushell-install-22919/nushell-extract/nushell-full-0.108.0 (subdirectory)
```
**Solution**: Added `-not -path` to exclude starting directory
```bash
# ✅ NEW - exclude parent directory
local extracted=$(find "$extract_dir" -maxdepth 1 -type d -name "nushell-*" -not -path "$extract_dir" | head -1)
# Now correctly returns the subdirectory
```
**Additional Improvements**:
- 4-level fallback detection strategy:
1. Check `$extracted/bin/nu` (subdirectory structure)
2. Check `$extracted/nu` (flat structure)
3. Fallback search for any `nushell-*` subdirectory with `bin/nu`
4. Last resort recursive search for any executable named `nu`
- Validates binaries exist before using them
- Clear error reporting with all search locations
**Version-Agnostic**:
- Uses `nushell-*` pattern (not hardcoded version numbers)
- Works with any Nushell version: 0.107, 0.108, 0.109, etc.
- Supports both `.tar.gz` and `.zip` archive formats
**Impact**:
- ✅ Archive extraction works reliably
- ✅ Works with any Nushell version
- ✅ Clear error messages guide users
- ✅ Multiple archive structure support
#### 0c. Plugin Registration - Version Mismatch Handling
**Issue**: Plugin registration failed with version incompatibility errors
```
Error: nu::shell::plugin_failed_to_load
× Plugin `polars` is compiled for nushell version 0.107.1, which is not compatible with version 0.108.0
```
**Solution**: Implemented intelligent error classification
- Captures both stdout and stderr from plugin add commands
- Detects version incompatibility: "is not compatible with version" or "is compiled for nushell version"
- Classifies errors into three categories:
1. **Success**: Plugin registered successfully ✅
2. **Incompatible**: Version mismatch (skipped gracefully) ⚠️
3. **Failed**: Other registration failures ❌
- Reports summary with counts of each category
- Installation continues successfully even with version mismatches
**New Error Reporting**:
```
✅ Registered nu_plugin_auth
⚠️ Skipping nu_plugin_polars: Version mismatch (built for different Nushell version)
✅ Successfully registered 13 plugins
⚠️ Skipped 1 incompatible plugins (version mismatch):
- nu_plugin_polars
```
**Impact**:
- ✅ No installation failures due to version mismatches
- ✅ Users informed of incompatible plugins
- ✅ Clear distinction between error types
- ✅ Installation completes successfully
#### 0d. Shell Configuration PATH Update - Clear Messaging
**Issue**: Confusing PATH update messages
- User sees: "PATH already updated" for all files
- Then sees: "No shell configuration files were updated" warning
- Then sees: "Please manually add to your PATH" error
- **Problem**: Contradictory messages when PATH is already configured everywhere
**Root Cause**: Script conflated two states
- State 1: "Was PATH found in files?" (skips updating if found)
- State 2: "Did we add PATH to any file?" (used for messaging)
- Both states ignored means no update was made, but PATH might already exist
**Solution**: Track two separate states
```bash
local updated=false # Was PATH ADDED to any file?
local path_found=false # Was PATH FOUND in any file?
# In loop:
if grep -q "$install_dir" "$config_file"; then
path_found=true # Found it! Mark as true
continue
fi
# After loop:
if [ "$updated" = "true" ]; then
log_success "Shell configuration updated"
elif [ "$path_found" = "true" ]; then
log_success "PATH is already configured in your shell configuration files"
else
log_warn "Could not find or update shell configuration"
fi
```
**New Clear Messages**:
- ✅ "PATH is already configured in your shell configuration files" (when found everywhere)
- ✅ "Shell configuration updated" (when just added)
- ⚠️ "Could not find or update shell configuration" (when file missing)
**Impact**:
- ✅ Non-contradictory messages
- ✅ Users understand what happened
- ✅ No false warnings when PATH already configured
- ✅ Clear guidance when manual action needed
#### 0e. Installation Features
**`--source-path` Option** (Local Installation):
- Install from local archive: `./install.sh --source-path archive.tar.gz`
- Install from local directory: `./install.sh --source-path /path/to/binaries`
- Default behavior: `./install.sh --source-path` uses `./bin_archives`
- Works with custom `--install-dir` paths
- No download needed, offline installation support
**`--uninstall` with Configuration Management**:
- Prompts user: "Remove ~/.config/nushell? [y/N]"
- Removes all installed binaries and plugins
- Preserves user choice for configuration
- Clean uninstall before fresh reinstall
#### 0f. Documentation Updates
**CLAUDE.md**:
- Added "Install Script Architecture (DRY Design)" section
- Documents source of truth and symlink structure
- Explains `--source-path` feature
- Shows version-agnostic archive detection
- Lists DRY architecture benefits
**README.md**:
- Added "Install Script Architecture (DRY Design)" subsection
- Shows symlink structure with arrows
- Provides `--source-path` usage examples
- Explains version-agnostic detection
- "How DRY Works" 3-step explanation
#### 0g. Files Modified
Core Changes:
- `installers/bootstrap/install.sh` (+3 lines for PATH messaging fix)
- Archive extraction fix with `-not -path`
- Plugin registration error classification
- Clear PATH update messaging
- Total: 1,247 lines (unified)
Auto-Updated via Symlinks:
- `./install.sh` - Auto-updated (1,247 lines)
- `./scripts/templates/install.sh` - Auto-updated (1,247 lines)
Documentation:
- `CLAUDE.md` - Added install architecture section
- `README.md` - Added install architecture subsection
- `CHANGELOG.md` - Added comprehensive entry (+100 lines)
#### 0h. Testing & Verification
All scenarios tested and verified:
- [x] Archive extraction works with version-agnostic detection
- [x] Installation to `~/.local` successful (16 binaries)
- [x] Installation to `~/.local/bin` successful (21 plugins loaded)
- [x] Plugin registration handles version mismatches gracefully
- [x] PATH messaging is clear and non-contradictory
- [x] Clean uninstall followed by fresh reinstall works perfectly
#### 0i. Impact
User-Facing Benefits:
- ✅ Users can install from any version of nushell-full archive
- ✅ Version mismatch plugins skipped without breaking installation
- ✅ Clear, honest error messages
- ✅ Non-confusing PATH update messages
- ✅ Offline installation support via `--source-path`
- ✅ Clean uninstall/reinstall workflow
Developer Benefits:
- ✅ Single source of truth eliminates code duplication
- ✅ Changes propagate automatically through symlinks
- ✅ Reduced maintenance burden
- ✅ Consistent behavior across all paths
- ✅ Production-ready installation process
---
### 1. Help System Integration (New Feature)
**Issue**: Version-update module recipes were not discoverable
- Not shown in `just help modules`
- Not referenced in `just help`
- Not included in help navigation system
- Users had to manually run `just --list` to find update commands
**Solution**:
- Added version-update module to all help outputs
- Updated `justfiles/help.just` to document all 30+ version-update recipes
- Created new `just commands` recipe as discoverable alias for `just --list`
- Integrated version-update into help-all workflow
**Impact**:
- Version-update commands now fully discoverable via help system
- Users can find update commands with: `just help modules`, `just help`, `just commands`
- Improved overall help system navigation
**Files Modified**:
- `justfiles/help.just` (+23 lines)
- Added version-update module to help sections
- Added to modules list
- Added to help-all workflow
- New `commands` recipe showing all recipes by group
### 2. Build Process Fixes (Phase 3: Bin Archives)
#### 2a. Plugin Archive Collection Bug
**Issue**: "No plugins found to package" warning in Phase 3
- Collected 26 plugin binaries but reported 0
- Archive creation skipped because count was wrong
**Root Cause**: `each` command returns null, so `| length` returned 0
```nushell
# ❌ OLD - each returns null
let plugin_count = (ls nu_plugin_*/target/release/nu_plugin_* | each {|p|
cp $p.name $"($temp_dir)/"
} | length) # Returns 0!
```
**Solution**: Separated counting from copying with proper filtering
```nushell
# ✅ NEW - count before operations
let plugins_to_copy = (ls nu_plugin_*/target/release/nu_plugin_* | where type == "file")
let plugin_count = ($plugins_to_copy | length)
```
**Impact**:
- Now correctly collects and reports 26 plugins
- Filters out .d dependency files automatically
- Warning eliminated
#### 2b. Tar Archive Path Handling
**Issue**: Tar command failing silently with relative paths in subshell
- `cd $temp_dir` changes context unpredictably
- Relative path `../$archive_name` fails in subshell
- Archive file not created despite exit code 0
**Root Cause**: Shell context and relative path issues in Nushell `do` block
**Solution**: Used `tar -C` with absolute paths instead of `cd`
```nushell
# ❌ OLD - unreliable context switching
do {
cd $temp_dir
tar -czf ../$archive_name .
}
# ✅ NEW - absolute paths, no context switching
tar -C $temp_dir -czf $archive_path .
```
**Additional Improvements**:
- Absolute path construction using `pwd | path join`
- Better error diagnostics with exit code and stderr output
- File verification after creation
**Impact**:
- Tar archives now created successfully
- Robust path handling across platforms
- Clear error messages for debugging
#### 2c. File Size Calculation Type Error
**Issue**: Runtime error when calculating archive size
```
Error: The '/' operator does not work on values of type 'list<filesize>'
```
**Root Cause**: `ls` returns list of records, so `.size` was a list
```nushell
# ❌ OLD - returns list<filesize>
(ls $archive_path).size / 1024 / 1024
# ✅ NEW - returns filesize
(ls $archive_path | get 0.size) / 1024 / 1024
```
**Impact**:
- Proper file size calculation in MB
- No more type errors
**Files Modified**:
- `scripts/create_full_distribution.nu` (+58 lines, refactored plugin collection)
- Fixed plugin counting logic
- Improved path handling with absolute paths
- Enhanced error diagnostics
### 3. Plugin Rebuild Optimization
**Issue**: All plugins marked for rebuild even when dependencies unchanged
- Step 4 (`update_all_plugins.nu`) touched all Cargo.toml files at 01:00:32
- Step 5 saw all files as "newer" than binaries
- Marked ALL plugins for rebuild, though cargo only rebuilt changed ones
**Root Cause**: Script always saved files, even when no changes made
```nushell
# ❌ OLD - always saves, touching file timestamp
$updated_content | to toml | save -f $cargo_toml
```
**Solution**: Only save if content actually changed
```nushell
# ✅ NEW - compare before writing
let original_toml = $content | to toml
let new_toml = $updated_content | to toml
if $original_toml != $new_toml {
$updated_content | to toml | save -f $cargo_toml
}
```
**Impact**:
- Unchanged files preserve original timestamps
- Only plugins with actual dependency changes are rebuilt
- Efficient rebuild process with accurate file modification detection
**Files Modified**:
- `scripts/update_all_plugins.nu` (+12 lines, added content comparison)
- Only touches files with real changes
- Preserves timestamps for efficiency
- Clearer logic and comments
### 4. Documentation
**Files Modified**:
- `CHANGELOG.md` (+56 lines)
- Added comprehensive 2025-10-19 entry
- Documented all fixes with root causes
- Listed files modified and impact summary
## Technical Details
### Nushell Patterns Used
1. **Proper List Handling**:
- `ls` returns list of records, access with `| get 0.size`
- Filter with `where type == "file"` to exclude metadata
2. **Absolute Path Construction**:
- `pwd | append "path" | path join` for cross-platform paths
- Safer than string concatenation with `/`
3. **Content Comparison**:
- Compare TOML string representation before saving
- Preserves file timestamps for efficiency
4. **Error Diagnostics**:
- Capture `stderr` from commands
- Report exit codes and error messages separately
## Testing
- [x] Help system shows version-update module
- [x] `just commands` displays all recipes by group
- [x] Phase 3 bin archive creation works
- [x] Plugin collection reports correct count (26)
- [x] Tar archives created successfully
- [x] File size calculated correctly
- [x] Plugin rebuild only touches changed files
- [x] CHANGELOG updated with all changes
## Files Changed
```
38 files changed, 2721 insertions(+), 2548 deletions(-)
Core Changes:
- justfiles/help.just (+23) Help system integration
- scripts/create_full_distribution.nu (+58) Build process fixes
- scripts/update_all_plugins.nu (+12) Rebuild optimization
- CHANGELOG.md (+56) Documentation
Dependency Updates:
- All plugin Cargo.toml and Cargo.lock files (version consistency)
```
## Breaking Changes
None. These are bug fixes and optimizations that maintain backward compatibility.
## Migration Notes
No migration needed. Improvements are transparent to users.
## Related Issues
- Help system discoverability
- Build process Phase 3 failures
- Unnecessary plugin rebuilds
- Build process reliability
## Checklist
- [x] Changes follow Rust/Nushell idioms
- [x] Code is well-commented
- [x] Error handling is comprehensive
- [x] Documentation is updated
- [x] All changes tested
- [x] No breaking changes introduced
2025-10-19 02:39:31 +01:00
|
|
|
|
local custom_install_dir=""
|
|
|
|
|
|
local source_path=""
|
2025-09-24 18:52:07 +01:00
|
|
|
|
local modify_path="true"
|
|
|
|
|
|
local create_config="true"
|
|
|
|
|
|
local include_plugins="true"
|
|
|
|
|
|
local build_from_source="false"
|
|
|
|
|
|
local verify_install="false"
|
|
|
|
|
|
local do_uninstall="false"
|
|
|
|
|
|
local version=""
|
|
|
|
|
|
|
|
|
|
|
|
# Parse command line arguments
|
|
|
|
|
|
while [ $# -gt 0 ]; do
|
|
|
|
|
|
case "$1" in
|
|
|
|
|
|
--system)
|
|
|
|
|
|
install_mode="system"
|
|
|
|
|
|
shift
|
|
|
|
|
|
;;
|
|
|
|
|
|
--user)
|
|
|
|
|
|
install_mode="user"
|
|
|
|
|
|
shift
|
|
|
|
|
|
;;
|
# 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-dir)
|
|
|
|
|
|
custom_install_dir="$2"
|
|
|
|
|
|
shift 2
|
|
|
|
|
|
;;
|
|
|
|
|
|
--source-path)
|
|
|
|
|
|
# If path is provided, use it; otherwise default to ./bin_archives
|
|
|
|
|
|
if [ -n "$2" ] && [ "${2#-}" = "$2" ]; then
|
|
|
|
|
|
source_path="$2"
|
|
|
|
|
|
shift 2
|
|
|
|
|
|
else
|
|
|
|
|
|
source_path="./bin_archives"
|
|
|
|
|
|
shift
|
|
|
|
|
|
fi
|
|
|
|
|
|
;;
|
2025-09-24 18:52:07 +01:00
|
|
|
|
--no-path)
|
|
|
|
|
|
modify_path="false"
|
|
|
|
|
|
shift
|
|
|
|
|
|
;;
|
|
|
|
|
|
--no-config)
|
|
|
|
|
|
create_config="false"
|
|
|
|
|
|
shift
|
|
|
|
|
|
;;
|
|
|
|
|
|
--no-plugins)
|
|
|
|
|
|
include_plugins="false"
|
|
|
|
|
|
shift
|
|
|
|
|
|
;;
|
|
|
|
|
|
--build-from-source)
|
|
|
|
|
|
build_from_source="true"
|
|
|
|
|
|
shift
|
|
|
|
|
|
;;
|
|
|
|
|
|
--verify)
|
|
|
|
|
|
verify_install="true"
|
|
|
|
|
|
shift
|
|
|
|
|
|
;;
|
|
|
|
|
|
--uninstall)
|
|
|
|
|
|
do_uninstall="true"
|
|
|
|
|
|
shift
|
|
|
|
|
|
;;
|
|
|
|
|
|
--version)
|
|
|
|
|
|
version="$2"
|
|
|
|
|
|
shift 2
|
|
|
|
|
|
;;
|
|
|
|
|
|
--help)
|
|
|
|
|
|
usage
|
|
|
|
|
|
exit 0
|
|
|
|
|
|
;;
|
|
|
|
|
|
*)
|
|
|
|
|
|
log_error "Unknown option: $1"
|
|
|
|
|
|
usage
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
;;
|
|
|
|
|
|
esac
|
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
|
|
# Handle uninstall
|
|
|
|
|
|
if [ "$do_uninstall" = "true" ]; then
|
|
|
|
|
|
uninstall_nushell
|
|
|
|
|
|
exit 0
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Show header
|
|
|
|
|
|
log_header "Nushell + Plugins Installer"
|
|
|
|
|
|
log_info "Universal bootstrap installer for Nushell and plugins"
|
|
|
|
|
|
log_info ""
|
|
|
|
|
|
|
|
|
|
|
|
# Detect platform
|
|
|
|
|
|
local platform
|
|
|
|
|
|
platform=$(detect_platform)
|
|
|
|
|
|
log_info "Detected platform: $platform"
|
|
|
|
|
|
|
|
|
|
|
|
# Determine installation directory
|
|
|
|
|
|
local install_dir
|
# 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 custom install dir provided, use it directly (bypass all prompts)
|
|
|
|
|
|
if [ -n "$custom_install_dir" ]; then
|
|
|
|
|
|
install_dir="$custom_install_dir"
|
|
|
|
|
|
log_info "Using custom installation directory (via --install-dir): $install_dir"
|
|
|
|
|
|
elif [ "$install_mode" = "system" ]; then
|
2025-09-24 18:52:07 +01:00
|
|
|
|
install_dir="$INSTALL_DIR_SYSTEM"
|
|
|
|
|
|
if [ "$(id -u)" != "0" ] && [ ! -w "$(dirname "$install_dir")" ]; then
|
# 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
|
|
|
|
log_warn "System installation requires root privileges or write access to $INSTALL_DIR_SYSTEM"
|
|
|
|
|
|
log_info ""
|
|
|
|
|
|
log_info "Available options:"
|
|
|
|
|
|
|
|
|
|
|
|
# Check if existing nu can be found
|
|
|
|
|
|
if command -v nu >/dev/null 2>&1; then
|
|
|
|
|
|
local existing_path=$(command -v nu | sed 's|/nu$||')
|
|
|
|
|
|
log_info " 1) Install to existing nu location: $existing_path"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
log_info " 2) Install to user directory: $INSTALL_DIR_USER"
|
|
|
|
|
|
log_info " 3) Run with sudo (requires password)"
|
|
|
|
|
|
log_info ""
|
|
|
|
|
|
|
|
|
|
|
|
# Interactive prompt
|
|
|
|
|
|
if [ -t 0 ]; then
|
|
|
|
|
|
read -p "Choose option (1-3) or press Enter for option 2 [default: 2]: " choice
|
|
|
|
|
|
choice=${choice:-2}
|
|
|
|
|
|
|
|
|
|
|
|
case "$choice" in
|
|
|
|
|
|
1)
|
|
|
|
|
|
if command -v nu >/dev/null 2>&1; then
|
|
|
|
|
|
install_dir=$(command -v nu | sed 's|/nu$||')
|
|
|
|
|
|
log_info "Using existing nu location: $install_dir"
|
|
|
|
|
|
else
|
|
|
|
|
|
log_error "No existing nu found"
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
;;
|
|
|
|
|
|
2)
|
|
|
|
|
|
install_dir="$INSTALL_DIR_USER"
|
|
|
|
|
|
log_info "Using user installation directory: $install_dir"
|
|
|
|
|
|
;;
|
|
|
|
|
|
3)
|
|
|
|
|
|
log_error "Please re-run with sudo: sudo $0 $@"
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
;;
|
|
|
|
|
|
*)
|
|
|
|
|
|
log_error "Invalid option"
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
;;
|
|
|
|
|
|
esac
|
|
|
|
|
|
else
|
|
|
|
|
|
# Non-interactive: use user dir as default
|
|
|
|
|
|
log_info "Non-interactive mode: using user directory"
|
|
|
|
|
|
install_dir="$INSTALL_DIR_USER"
|
|
|
|
|
|
fi
|
2025-09-24 18:52:07 +01:00
|
|
|
|
fi
|
|
|
|
|
|
else
|
|
|
|
|
|
install_dir="$INSTALL_DIR_USER"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
log_info "Installing to: $install_dir"
|
|
|
|
|
|
|
# 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
|
|
|
|
# Ensure install directory is writable
|
|
|
|
|
|
mkdir -p "$install_dir" 2>/dev/null || {
|
|
|
|
|
|
log_error "Cannot write to installation directory: $install_dir"
|
|
|
|
|
|
log_info "Check permissions or choose a different directory"
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Handle source-path (local installation)
|
|
|
|
|
|
if [ -n "$source_path" ]; then
|
|
|
|
|
|
log_info "Installing from local source: $source_path"
|
|
|
|
|
|
|
|
|
|
|
|
# Check if source exists
|
|
|
|
|
|
if [ ! -e "$source_path" ]; then
|
|
|
|
|
|
log_error "Source path not found: $source_path"
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# If it's a file (archive), extract it
|
|
|
|
|
|
if [ -f "$source_path" ]; then
|
|
|
|
|
|
log_info "Extracting from archive: $source_path"
|
|
|
|
|
|
|
|
|
|
|
|
# Create temp directory for extraction
|
|
|
|
|
|
local extract_dir="$TEMP_DIR/nushell-extract"
|
|
|
|
|
|
mkdir -p "$extract_dir"
|
|
|
|
|
|
|
|
|
|
|
|
# Determine file type and extract
|
|
|
|
|
|
case "$source_path" in
|
|
|
|
|
|
*.tar.gz|*.tgz)
|
|
|
|
|
|
tar -xzf "$source_path" -C "$extract_dir" || {
|
|
|
|
|
|
log_error "Failed to extract tar.gz archive"
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
}
|
|
|
|
|
|
;;
|
|
|
|
|
|
*.zip)
|
|
|
|
|
|
unzip -q "$source_path" -d "$extract_dir" || {
|
|
|
|
|
|
log_error "Failed to extract zip archive"
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
}
|
|
|
|
|
|
;;
|
|
|
|
|
|
*)
|
|
|
|
|
|
log_error "Unsupported archive format: $source_path"
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
;;
|
|
|
|
|
|
esac
|
|
|
|
|
|
|
|
|
|
|
|
# Find extracted directory and install from it
|
|
|
|
|
|
# Use -not -path to exclude the extract_dir itself from results
|
|
|
|
|
|
local extracted=$(find "$extract_dir" -maxdepth 1 -type d -name "nushell-*" -not -path "$extract_dir" | head -1)
|
|
|
|
|
|
if [ -z "$extracted" ]; then
|
|
|
|
|
|
# If no nushell-* subdirectory found, check if extract_dir contains bin/nu directly
|
|
|
|
|
|
extracted="$extract_dir"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Determine where the binaries are located
|
|
|
|
|
|
local source_for_install=""
|
|
|
|
|
|
|
|
|
|
|
|
# Check for binaries in multiple locations (in order of preference)
|
|
|
|
|
|
if [ -f "$extracted/bin/nu" ]; then
|
|
|
|
|
|
# Archive with subdirectory: nushell-X.Y.Z/bin/nu
|
|
|
|
|
|
source_for_install="$extracted/bin"
|
|
|
|
|
|
log_info "Found binaries in $extracted/bin/"
|
|
|
|
|
|
elif [ -f "$extracted/nu" ]; then
|
|
|
|
|
|
# Flat archive structure: binaries at root
|
|
|
|
|
|
source_for_install="$extracted"
|
|
|
|
|
|
log_info "Found binaries in $extracted/"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# If not found yet, search for any nushell-* subdirectory with bin/nu
|
|
|
|
|
|
if [ -z "$source_for_install" ] && [ -d "$extract_dir" ]; then
|
|
|
|
|
|
# Exclude extract_dir itself to only find subdirectories
|
|
|
|
|
|
local nushell_dir=$(find "$extract_dir" -maxdepth 1 -type d -name "nushell-*" -not -path "$extract_dir" ! -empty 2>/dev/null | head -1)
|
|
|
|
|
|
if [ -n "$nushell_dir" ] && [ -f "$nushell_dir/bin/nu" ]; then
|
|
|
|
|
|
source_for_install="$nushell_dir/bin"
|
|
|
|
|
|
log_info "Found binaries in $nushell_dir/bin/"
|
|
|
|
|
|
fi
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Last resort: recursive search for any nu binary
|
|
|
|
|
|
if [ -z "$source_for_install" ]; then
|
|
|
|
|
|
local nu_binary=$(find "$extract_dir" -type f -name "nu" -executable 2>/dev/null | head -1)
|
|
|
|
|
|
if [ -n "$nu_binary" ]; then
|
|
|
|
|
|
source_for_install=$(dirname "$nu_binary")
|
|
|
|
|
|
log_info "Found nu binary at: $source_for_install/nu"
|
|
|
|
|
|
fi
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Validate that we found the binaries
|
|
|
|
|
|
if [ -z "$source_for_install" ] || [ ! -f "$source_for_install/nu" ]; then
|
|
|
|
|
|
log_error "No Nushell binary found in extracted archive"
|
|
|
|
|
|
log_info "Searched locations:"
|
|
|
|
|
|
log_info " - $extracted/bin/nu"
|
|
|
|
|
|
log_info " - $extracted/nu"
|
|
|
|
|
|
log_info " - Any nushell-* subdirectory with bin/nu"
|
|
|
|
|
|
log_info " - Recursive search in $extract_dir"
|
|
|
|
|
|
log_info ""
|
|
|
|
|
|
log_info "Archive contents:"
|
|
|
|
|
|
find "$extract_dir" -type f -name "nu" 2>/dev/null | head -10
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Install from the correct source directory
|
|
|
|
|
|
log_info "Installing from extracted archive at: $source_for_install"
|
|
|
|
|
|
install_from_local "$source_for_install" "$install_dir" "$include_plugins"
|
|
|
|
|
|
elif [ -d "$source_path" ]; then
|
|
|
|
|
|
# It's a directory, install directly from it
|
|
|
|
|
|
log_info "Installing from local directory: $source_path"
|
|
|
|
|
|
install_from_local "$source_path" "$install_dir" "$include_plugins"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Skip the rest of installation
|
|
|
|
|
|
local build_from_source="skip_download"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Get version if not specified and not using local source
|
|
|
|
|
|
if [ -z "$version" ] && [ "$build_from_source" != "skip_download" ]; then
|
2025-09-24 18:52:07 +01:00
|
|
|
|
version=$(get_latest_version)
|
|
|
|
|
|
fi
|
# 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 [ "$build_from_source" != "skip_download" ]; then
|
|
|
|
|
|
log_info "Version: $version"
|
|
|
|
|
|
fi
|
2025-09-24 18:52:07 +01:00
|
|
|
|
|
|
|
|
|
|
# Cleanup function
|
|
|
|
|
|
cleanup() {
|
|
|
|
|
|
if [ -d "$TEMP_DIR" ]; then
|
|
|
|
|
|
rm -rf "$TEMP_DIR"
|
|
|
|
|
|
fi
|
|
|
|
|
|
}
|
|
|
|
|
|
trap cleanup EXIT
|
|
|
|
|
|
|
# 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 based on method (skip if already did local source installation)
|
|
|
|
|
|
if [ "$build_from_source" = "skip_download" ]; then
|
|
|
|
|
|
log_info "Local source installation completed"
|
|
|
|
|
|
elif [ "$build_from_source" = "true" ]; then
|
2025-09-24 18:52:07 +01:00
|
|
|
|
if ! install_from_source "$install_dir" "$include_plugins"; then
|
|
|
|
|
|
log_error "Source installation failed"
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
else
|
|
|
|
|
|
if ! install_from_binaries "$platform" "$version" "$install_dir" "$include_plugins"; then
|
|
|
|
|
|
log_error "Binary installation failed"
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Register plugins
|
|
|
|
|
|
if [ "$include_plugins" = "true" ]; then
|
|
|
|
|
|
register_plugins "$install_dir"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Update PATH
|
|
|
|
|
|
if [ "$modify_path" = "true" ]; then
|
|
|
|
|
|
update_shell_path "$install_dir"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Create configuration
|
|
|
|
|
|
if [ "$create_config" = "true" ]; then
|
|
|
|
|
|
create_nushell_config
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Verify installation
|
|
|
|
|
|
if [ "$verify_install" = "true" ]; then
|
|
|
|
|
|
if ! verify_installation "$install_dir"; then
|
|
|
|
|
|
log_error "Installation verification failed"
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Final success message
|
|
|
|
|
|
log_header "Installation Complete!"
|
|
|
|
|
|
log_success "Nushell has been successfully installed to $install_dir"
|
|
|
|
|
|
|
|
|
|
|
|
if [ "$include_plugins" = "true" ]; then
|
|
|
|
|
|
log_success "Plugins have been registered with Nushell"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
if [ "$modify_path" = "true" ]; then
|
|
|
|
|
|
log_info "To use Nushell, restart your terminal or run:"
|
|
|
|
|
|
log_info " source ~/.bashrc # or your shell's config file"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
log_info ""
|
|
|
|
|
|
log_info "Try running: nu --version"
|
|
|
|
|
|
log_info "Or start Nushell with: nu"
|
|
|
|
|
|
|
|
|
|
|
|
if [ "$include_plugins" = "true" ]; then
|
|
|
|
|
|
log_info "Check plugins with: nu -c 'plugin list'"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
log_info ""
|
|
|
|
|
|
log_info "For more information, visit: https://nushell.sh"
|
|
|
|
|
|
log_info ""
|
|
|
|
|
|
log_success "Happy shell scripting! 🚀"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Run main function with all arguments
|
|
|
|
|
|
main "$@"
|