#!/usr/bin/env nu # Update All Plugins - Bulk Plugin Updater # Updates all nu_plugin_* Cargo.toml dependencies to a new Nushell version # # Usage: # update_all_plugins.nu 0.108.0 # Update to specific version # update_all_plugins.nu 0.108.0 --auto-approve # Skip confirmation # update_all_plugins.nu --list # List current versions use lib/common_lib.nu * # Main entry point def main [ target_version?: string # Target Nushell version (e.g., "0.108.0") --auto-approve # Skip confirmation prompts --dry-run # Show what would be updated without changing --list # List current plugin versions --plugin: string # Update only specific plugin ] { if $list { list_plugin_versions return } if ($target_version | is-empty) { log_error "Please specify a target version" show_usage exit 1 } log_info $"šŸ”„ Updating all plugins to Nushell ($target_version)" # Get all plugin directories let plugins = if ($plugin | is-not-empty) { [{ name: $plugin, path: $plugin }] } else { get_plugin_directories } if ($plugins | length) == 0 { log_error "No plugin directories found" exit 1 } log_info $"Found ($plugins | length) plugins to update" # Show current versions log_info "\nšŸ“‹ Current Versions:" for p in $plugins { let current = get_plugin_version $p.path print $" ($p.name): ($current)" } # Confirm update if not $auto_approve and not $dry_run { print "" let response = input $"Update all plugins to ($target_version)? \(yes/no\): " if $response != "yes" { log_info "Update cancelled" exit 0 } } # Update each plugin mut updated = 0 mut failed = [] print "" for p in $plugins { if $dry_run { log_info $"(DRY RUN) Would update ($p.name)" $updated = $updated + 1 } else { let result = update_plugin $p.path $target_version if $result { log_success $"āœ“ Updated ($p.name)" $updated = $updated + 1 } else { log_error $"āœ— Failed to update ($p.name)" $failed = ($failed | append $p.name) } } } # Summary print "" if ($failed | length) == 0 { log_success $"āœ… Successfully updated ($updated) plugins to ($target_version)" } else { log_warn $"āš ļø Updated ($updated) plugins, ($failed | length) failed:" for f in $failed { log_error $" • ($f)" } exit 1 } if not $dry_run { log_info "\nšŸ“ Next steps:" log_info " 1. Build plugins: just build" log_info " 2. Test plugins: just test" log_info " 3. Create distribution: just pack-full" } } # Show usage def show_usage [] { print "Usage:" print " update_all_plugins.nu # Update to version" print " update_all_plugins.nu --auto-approve" print " update_all_plugins.nu --list # List current versions" print "" print "Examples:" print " update_all_plugins.nu 0.108.0" print " update_all_plugins.nu 0.108.0 --dry-run" print " update_all_plugins.nu 0.108.0 --plugin nu_plugin_image" } # Get plugin directories def get_plugin_directories []: nothing -> list { ls nu_plugin_* | where type == dir | each {|row| { name: (get_plugin_name $row.name) path: $row.name } } } # Get plugin name from directory def get_plugin_name [dir: string]: nothing -> string { $dir | path basename } # Get current plugin version def get_plugin_version [plugin_dir: string]: nothing -> string { let cargo_toml = $"($plugin_dir)/Cargo.toml" if not ($cargo_toml | path exists) { return "N/A" } try { let cargo_data = open $cargo_toml let deps = $cargo_data | get dependencies # Try to get nu-plugin version if "nu-plugin" in ($deps | columns) { let nu_plugin_spec = $deps | get nu-plugin if ($nu_plugin_spec | describe) == "record" { return ($nu_plugin_spec | get version) } else { return $nu_plugin_spec } } return "unknown" } catch { return "error" } } # Update single plugin def update_plugin [ plugin_dir: string target_version: string ]: nothing -> bool { let cargo_toml = $"($plugin_dir)/Cargo.toml" if not ($cargo_toml | path exists) { log_error $"Cargo.toml not found in ($plugin_dir)" return false } try { # Read current Cargo.toml let content = open $cargo_toml # Update nu-* dependencies let updated_deps = update_nu_dependencies ($content | get dependencies) $target_version # Create updated content let updated_content = $content | update dependencies $updated_deps # Only save if content actually changed (avoid unnecessary file timestamp updates) let original_toml = $content | to toml let new_toml = $updated_content | to toml if $original_toml != $new_toml { # Content changed - save the file $updated_content | to toml | save -f $cargo_toml return true } else { # No changes needed - don't touch the file return true } } catch {|err| log_error $"Error updating ($plugin_dir): ($err.msg)" return false } } # Update nu-* dependencies in dependencies table def update_nu_dependencies [ deps: record target_version: string ]: nothing -> record { mut updated_deps = $deps # List of nu-* crates to update let nu_crates = [ "nu-plugin" "nu-protocol" "nu-engine" "nu-parser" "nu-cmd-base" "nu-color-config" "nu-utils" "nu-path" "nu-glob" "nu-json" "nu-pretty-hex" "nu-system" "nu-table" "nu-term-grid" ] for crate in $nu_crates { if $crate in ($deps | columns) { let spec = $deps | get $crate # Update version based on spec type if ($spec | describe) == "record" { # It's a detailed spec with version, path, features, etc. let updated_spec = $spec | update version $target_version $updated_deps = ($updated_deps | update $crate $updated_spec) } else { # It's just a version string $updated_deps = ($updated_deps | update $crate $target_version) } } } $updated_deps } # List all plugin versions def list_plugin_versions [] { log_info "šŸ“‹ Current Plugin Versions\n" let plugins = get_plugin_directories # Create table of versions let versions = $plugins | each {|p| { plugin: $p.name nu_plugin_version: (get_plugin_version $p.path) } } $versions | table print "" log_info $"Total plugins: ($plugins | length)" } # Check for version mismatches def "main check" [] { log_info "šŸ” Checking for version mismatches\n" let plugins = get_plugin_directories # Get all unique versions let versions = $plugins | each {|p| get_plugin_version $p.path} | uniq if ($versions | length) == 1 { log_success $"āœ… All plugins use consistent version: ($versions | first)" } else { log_warn $"āš ļø Version mismatch detected! Found ($versions | length) different versions:" for v in $versions { let count = $plugins | each {|p| get_plugin_version $p.path} | where {|ver| $ver == $v} | length log_info $" ($v): ($count) plugins" } # Show which plugins have which versions print "\nDetailed breakdown:" for p in $plugins { let version = get_plugin_version $p.path print $" ($p.name): ($version)" } } } # Update to match nushell submodule version def "main sync" [] { log_info "šŸ”„ Syncing plugin versions with nushell submodule\n" # Get version from nushell submodule let nushell_cargo = "./nushell/Cargo.toml" if not ($nushell_cargo | path exists) { log_error "Nushell submodule not found at ./nushell/" log_info "Download it first with: ./scripts/download_nushell.nu" exit 1 } let nushell_version = try { open $nushell_cargo | get package.version } catch { log_error "Failed to read nushell version" exit 1 } log_info $"Nushell submodule version: ($nushell_version)" log_info "Updating all plugins to match...\n" # Run main update main $nushell_version --auto-approve }