nushell-plugins/scripts/update_nushell.nu
Jesús Pérez b99dcc83c3 feat: major repository modernization and tracking cleanup
## Summary

Comprehensive repository cleanup focusing on plugin dependency management, documentation improvements, and git tracking optimization.

## Key Changes

### 🔧 Core Infrastructure
- Synchronized all nu-* dependencies across plugins for version consistency
- Enhanced upstream tracking and automation systems
- Removed nushell directory from git tracking for cleaner repository management

### 📚 Documentation
- Significantly expanded README.md with comprehensive development guides
- Added detailed workflow documentation and command references
- Improved plugin collection overview and usage examples

### 🧹 Repository Cleanup
- Removed legacy bash scripts (build-all.sh, collect-install.sh, make_plugin.sh)
- Streamlined automation through unified justfile and nushell script approach
- Updated .gitignore with nushell directory and archive patterns
- Removed nushell directory from git tracking to prevent unwanted changes

### 🔌 Plugin Updates
- **nu_plugin_image**: Major refactoring with modular architecture improvements
- **nu_plugin_hashes**: Enhanced functionality and build system improvements
- **nu_plugin_highlight**: Updated for new plugin API compatibility
- **nu_plugin_clipboard**: Dependency synchronization
- **nu_plugin_desktop_notifications**: Version alignment
- **nu_plugin_port_extension & nu_plugin_qr_maker**: Consistency updates
- **nu_plugin_kcl & nu_plugin_tera**: Submodule synchronization

### 🏗️ Git Tracking Optimization
- Removed nushell directory from version control for cleaner repository management
- Added comprehensive .gitignore patterns for build artifacts and archives

## Statistics
- 2,082 files changed
- 2,373 insertions, 339,936 deletions
- Net reduction of 337,563 lines (primarily from removing nushell directory tracking)

## Benefits
- Complete version consistency across all plugins
- Cleaner repository with optimized git tracking
- Improved developer experience with streamlined workflows
- Enhanced documentation and automation
- Reduced repository size and complexity

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-20 15:18:58 +01:00

436 lines
14 KiB
Plaintext
Executable File

#!/usr/bin/env nu
# Nushell Auto-Updater - Nushell version
# Downloads latest nushell release from GitHub, extracts, and manages symlinks
# Usage: nu update_nushell.nu [command]
# Configuration
let GITHUB_API_URL = "https://api.github.com/repos/nushell/nushell/releases/latest"
let GITHUB_RELEASES_URL = "https://github.com/nushell/nushell/releases/download"
let NUSHELL_SYMLINK = "nushell"
# Function to show usage
def show_usage [] {
print $"(ansi blue)Nushell Auto-Updater(ansi reset)"
print ""
print "Usage: nu update_nushell.nu [command]"
print ""
print "Commands:"
print $" (ansi green)check(ansi reset) Check for updates without installing"
print $" (ansi green)update(ansi reset) Download and install latest version"
print $" (ansi green)status(ansi reset) Show current installation status"
print $" (ansi green)help, -h(ansi reset) Show this help message"
print ""
print "If no command is specified, 'update' is assumed."
print ""
}
# Function to get latest version from GitHub API
def get_latest_version [] {
try {
http get $GITHUB_API_URL | get tag_name
} catch {
null
}
}
# Function to check if nushell directory is a git repository
def is_git_repository [nushell_dir: string] {
($nushell_dir | path join ".git" "config" | path exists)
}
# Function to get git repository status with origin information
def get_git_status [nushell_dir: string] {
if not (is_git_repository $nushell_dir) {
return null
}
try {
cd $nushell_dir
let current_commit = (^git rev-parse --short HEAD | str trim)
let current_branch = (^git branch --show-current | str trim)
let remote_status = (^git status --porcelain=v1 | lines | length)
let origin_url = (^git remote get-url origin | str trim)
cd ..
{
branch: $current_branch,
commit: $current_commit,
changes: $remote_status,
origin: $origin_url
}
} catch {
null
}
}
# Function to get currently installed version
def get_current_version [] {
try {
if ($NUSHELL_SYMLINK | path exists) and (($NUSHELL_SYMLINK | path type) == "symlink") {
let target = $NUSHELL_SYMLINK | path expand | path basename
# Check if target is a git repository
if (is_git_repository $target) {
"git-repo"
} else {
let version_match = ($target | parse "nushell-{version}")
if ($version_match | length) > 0 {
$version_match.0.version
} else {
null
}
}
} else if ($NUSHELL_SYMLINK | path exists) and (($NUSHELL_SYMLINK | path type) == "dir") and (is_git_repository $NUSHELL_SYMLINK) {
# Handle case where nushell is a directory (git repository)
"git-repo"
} else {
null
}
} catch {
null
}
}
# Function to get current directory name
def get_current_directory [] {
try {
if ($NUSHELL_SYMLINK | path exists) and (($NUSHELL_SYMLINK | path type) == "symlink") {
$NUSHELL_SYMLINK | path expand | path basename
} else if ($NUSHELL_SYMLINK | path exists) and (($NUSHELL_SYMLINK | path type) == "dir") {
# Return the directory name itself if it's a directory
$NUSHELL_SYMLINK
} else {
null
}
} catch {
null
}
}
# Function to check installation status
def check_status [] {
print $"(ansi blue)Nushell Installation Status(ansi reset)"
print ""
let current_version = get_current_version
let current_dir = get_current_directory
# Handle git repository case
if $current_version == "git-repo" {
print $"(ansi cyan)Git Repository Detected(ansi reset)"
print $"Currently installed: (ansi cyan)Git repository(ansi reset)"
let git_status = get_git_status $current_dir
if ($git_status | is-not-empty) {
print $"Repository: (ansi cyan)($current_dir)(ansi reset)"
print $"Origin: (ansi cyan)($git_status.origin)(ansi reset)"
print $"Branch: (ansi cyan)($git_status.branch)(ansi reset)"
print $"Commit: (ansi cyan)($git_status.commit)(ansi reset)"
if $git_status.changes > 0 {
print $"Status: (ansi yellow)($git_status.changes) uncommitted changes(ansi reset)"
} else {
print $"Status: (ansi green)Clean working directory(ansi reset)"
}
}
print ""
print $"(ansi yellow)⚠️ Git Repository Management(ansi reset)"
print "This nushell installation is a git repository."
print $"Use (ansi cyan)git pull(ansi reset) to update instead of this script."
print $"To switch to release versions, remove the current directory and use (ansi cyan)nu update_nushell.nu update(ansi reset)"
return 3
}
let latest_version = get_latest_version
if ($latest_version | is-empty) {
print $"(ansi red)Error: Could not fetch latest version from GitHub(ansi reset)"
print "Please check your internet connection and try again."
return 1
}
print $"Latest available version: (ansi green)($latest_version)(ansi reset)"
if ($current_version | is-empty) {
print $"Currently installed: (ansi yellow)None(ansi reset)"
print $"Status: (ansi yellow)Fresh installation needed(ansi reset)"
return 2
} else {
print $"Currently installed: (ansi cyan)($current_version)(ansi reset)"
if $current_version == $latest_version {
print $"Status: (ansi green)Up to date(ansi reset)"
return 0
} else {
print $"Status: (ansi yellow)Update available(ansi reset)"
return 2
}
}
}
# Function to download file
def download_file [url: string, filename: string] {
try {
print $"(ansi blue)Downloading from: ($url)(ansi reset)"
http get $url | save $filename
true
} catch { |e|
print $"(ansi red)Error downloading file: ($e.msg)(ansi reset)"
false
}
}
# Function to download and extract nushell
def download_and_extract [version: string] {
let filename = $"nushell-($version)-source.tar.gz"
let url = $"($GITHUB_RELEASES_URL)/($version)/($filename)"
let target_dir = $"nushell-($version)"
print $"(ansi blue)Downloading nushell ($version)...(ansi reset)"
# Download the file
if not (download_file $url $filename) {
return false
}
if not ($filename | path exists) {
print $"(ansi red)Error: Download failed - file not found(ansi reset)"
return false
}
print $"(ansi blue)Extracting ($filename)...(ansi reset)"
# Extract the tar.gz file
try {
^tar -xzf $filename
} catch { |e|
print $"(ansi red)Error: Failed to extract ($filename): ($e.msg)(ansi reset)"
try { rm $filename } catch { }
return false
}
# Check if extraction created the expected directory
if not ($target_dir | path exists) {
print $"(ansi red)Error: Expected directory ($target_dir) not found after extraction(ansi reset)"
try { rm $filename } catch { }
return false
}
print $"(ansi green)Successfully downloaded and extracted nushell ($version)(ansi reset)"
true
}
# Function to clean up old installations
def cleanup_old_installation [old_dir: string, old_version: string] {
if not ($old_dir | is-empty) and ($old_dir | path exists) {
print $"(ansi blue)Removing old installation: ($old_dir)(ansi reset)"
try {
rm -rf $old_dir
} catch { |e|
print $"(ansi yellow)Warning: Could not remove old directory ($old_dir): ($e.msg)(ansi reset)"
}
}
# Remove old tar.gz files
let old_tarball = $"nushell-($old_version)-source.tar.gz"
if ($old_tarball | path exists) {
print $"(ansi blue)Removing old tarball: ($old_tarball)(ansi reset)"
try {
rm $old_tarball
} catch { |e|
print $"(ansi yellow)Warning: Could not remove old tarball ($old_tarball): ($e.msg)(ansi reset)"
}
}
}
# Function to create symlink
def create_symlink [target_dir: string] {
# Remove existing symlink
if ($NUSHELL_SYMLINK | path exists) {
if (($NUSHELL_SYMLINK | path type) == "symlink") {
try { rm $NUSHELL_SYMLINK } catch { }
} else {
print $"(ansi red)Error: ($NUSHELL_SYMLINK) exists but is not a symlink(ansi reset)"
return false
}
}
# Create new symlink
try {
^ln -s $target_dir $NUSHELL_SYMLINK
print $"(ansi green)Created symlink: ($NUSHELL_SYMLINK) -> ($target_dir)(ansi reset)"
true
} catch { |e|
print $"(ansi red)Error: Failed to create symlink: ($e.msg)(ansi reset)"
false
}
}
# Function to update git repository
def update_git_repository [] {
let current_dir = get_current_directory
if ($current_dir | is-empty) or not (is_git_repository $current_dir) {
print $"(ansi red)Error: Git repository not found or invalid(ansi reset)"
return 1
}
print $"(ansi blue)Updating Git Repository(ansi reset)"
print $"Repository: (ansi cyan)($current_dir)(ansi reset)"
# Show origin and branch info
let git_status = get_git_status $current_dir
if ($git_status | is-not-empty) {
print $"Origin: (ansi cyan)($git_status.origin)(ansi reset)"
print $"Branch: (ansi cyan)($git_status.branch)(ansi reset)"
}
print ""
try {
cd $current_dir
# Check if there are uncommitted changes
let changes = (^git status --porcelain=v1 | lines | length)
if $changes > 0 {
print $"(ansi yellow)Warning: ($changes) uncommitted changes detected(ansi reset)"
print "Stashing changes before update..."
let stash_message = $"Auto-stash before nushell update (date now | format date '%Y-%m-%d %H:%M:%S')"
^git stash push -m $stash_message
}
# Update repository
print $"(ansi blue)Fetching latest changes...(ansi reset)"
^git fetch origin
print $"(ansi blue)Pulling latest changes...(ansi reset)"
^git pull origin
# Restore stashed changes if any
if $changes > 0 {
print $"(ansi blue)Restoring stashed changes...(ansi reset)"
try {
^git stash pop
} catch {
print $"(ansi yellow)Warning: Failed to restore stashed changes(ansi reset)"
print "Your changes are saved in the stash. Use 'git stash list' to see them."
}
}
cd ..
print ""
print $"(ansi green)✓ Git repository updated successfully!(ansi reset)"
let new_commit = (^git -C $current_dir rev-parse --short HEAD | str trim)
print $"Current commit: (ansi cyan)($new_commit)(ansi reset)"
0
} catch { |e|
print $"(ansi red)Error updating git repository: ($e.msg)(ansi reset)"
try { cd .. } catch { }
1
}
}
# Function to perform update
def perform_update [force_update: bool = false] {
print $"(ansi blue)Nushell Auto-Updater(ansi reset)"
print ""
# Check status first
let status_result = check_status
match $status_result {
0 => {
if not $force_update {
print ""
print $"(ansi green)Nushell is already up to date!(ansi reset)"
return 0
}
print ""
print $"(ansi yellow)Forcing update even though current version is latest...(ansi reset)"
}
1 => { return 1 }
2 => {
print ""
print $"(ansi yellow)Proceeding with installation/update...(ansi reset)"
}
3 => {
# Git repository detected
print ""
print $"(ansi blue)Git repository detected. Running git update...(ansi reset)"
print ""
return (update_git_repository)
}
}
print ""
# Get versions
let latest_version = get_latest_version
let current_version = get_current_version
let current_dir = get_current_directory
# Download and extract
if not (download_and_extract $latest_version) {
return 1
}
let new_dir = $"nushell-($latest_version)"
let new_tarball = $"nushell-($latest_version)-source.tar.gz"
# Create symlink
if not (create_symlink $new_dir) {
print $"(ansi red)Installation failed at symlink creation(ansi reset)"
return 1
}
# Clean up old installation (only if different from new one)
if (not ($current_version | is-empty)) and ($current_version != $latest_version) {
cleanup_old_installation $current_dir $current_version
}
# Remove the new tarball (keep the extracted directory)
if ($new_tarball | path exists) {
try { rm $new_tarball } catch { }
}
print ""
print $"(ansi green)✓ Nushell installation completed successfully!(ansi reset)"
print $"Version: (ansi cyan)($latest_version)(ansi reset)"
print $"Location: (ansi cyan)(pwd)/($new_dir)(ansi reset)"
print $"Symlink: (ansi cyan)(pwd)/($NUSHELL_SYMLINK)(ansi reset)"
0
}
# Main function
def main [command?: string] {
let cmd = ($command | default "update")
match $cmd {
"check" => { check_status }
"update" => { perform_update }
"force" => { perform_update true }
"status" => { check_status }
"help" | "-h" | "--help" => { show_usage }
_ => {
print $"(ansi red)Error: Unknown command '($cmd)'(ansi reset)"
print ""
show_usage
}
}
}
# Export functions for use
export def "nushell-updater check" [] { check_status }
export def "nushell-updater update" [] { perform_update }
export def "nushell-updater force" [] { perform_update true }
export def "nushell-updater status" [] { check_status }
export def "nushell-updater help" [] { show_usage }
# Main entry point function
export def "nushell-updater" [command?: string] {
main ($command | default "help")
}
# When run as script, don't execute main automatically
# Use the exported functions instead