nushell-plugins/scripts/update_installed_plugins.nu

414 lines
12 KiB
Plaintext
Raw Normal View History

#!/usr/bin/env nu
# Update Installed Plugins - Remove Old & Install New Versions
#
# This script updates plugins that are already installed in ~/.local/bin:
# 1. Detects installed plugins in ~/.local/bin
# 2. Removes old plugin binaries
# 3. Rebuilds them from source
# 4. Installs new versions to ~/.local/bin
# 5. Registers with nushell
#
# Usage:
# update_installed_plugins.nu # Update all installed plugins
# update_installed_plugins.nu --check # Check only, don't update
# update_installed_plugins.nu --plugin NAME # Update specific plugin
# update_installed_plugins.nu --verify # Verify registration after update
use lib/common_lib.nu *
# Configuration
def get-install-dir []: nothing -> string {
$"($env.HOME)/.local/bin"
}
def get-plugin-dirs []: nothing -> list<record> {
ls nu_plugin_*
| where type == "dir"
| each {|row|
{
name: $row.name
path: $row.name
cargo_toml: $"($row.name)/Cargo.toml"
}
}
}
# Main entry point
def main [
--check (-c) # Check only, don't modify
--plugin: string = "" # Update specific plugin (optional)
--verify (-v) # Verify registration after update
--no-register # Skip registration step
--force (-f) # Force rebuild even if no changes
] {
log_info "🔄 Plugin Update Manager - Remove Old & Install New"
log_info "=================================================================="
let install_dir = (get-install-dir)
# Check install directory exists
if not ($install_dir | path exists) {
log_error $"Install directory not found: ($install_dir)"
log_info "Creating directory..."
mkdir $install_dir
}
log_info $"📍 Install directory: ($install_dir)"
# Step 1: Find installed plugins
log_info "\n📋 Step 1: Detecting installed plugins..."
let installed = detect_installed_plugins $install_dir
if ($installed | length) == 0 {
log_warn $"No installed plugins found in ($install_dir)"
return
}
log_success $"Found ($installed | length) installed plugin\(s\):"
for plugin in $installed {
log_info $" • ($plugin.name) \(installed: ($plugin.install_path)\)"
}
# Step 2: Find source plugins
log_info "\n🔍 Step 2: Finding plugin sources..."
let sources = (get-plugin-dirs)
if ($sources | length) == 0 {
log_error "No plugin sources found in current directory"
exit 1
}
log_success $"Found ($sources | length) plugin source\(s\)"
# Step 3: Match installed with sources
log_info "\n🔗 Step 3: Matching installed plugins with sources..."
let to_update = match_plugins_with_sources $installed $sources $plugin
if ($to_update | length) == 0 {
if ($plugin | is-not-empty) {
log_error $"Plugin not found or not installed: ($plugin)"
} else {
log_warn "No plugins to update"
}
return
}
log_success $"Ready to update ($to_update | length) plugin\(s\):"
for item in $to_update {
log_info $" • ($item.name)"
log_info $" Source: ($item.source.path)"
log_info $" Target: ($item.install_path)"
}
# Confirmation
if not $check {
print ""
log_info "🤔 Proceed with update? (yes/no): "
let response = try {
input ""
} catch {
"yes"
}
if $response != "yes" {
log_info "Update cancelled"
return
}
}
# Step 4: Remove old binaries
if not $check {
log_info "\n🗑 Step 4: Removing old plugin binaries..."
remove_old_plugins $to_update $install_dir
} else {
log_info "\n🗑 Step 4 \(DRY RUN\): Would remove old plugin binaries..."
for item in $to_update {
log_info $" Would remove: ($item.install_path)"
}
}
# Step 5: Rebuild plugins
if not $check {
log_info "\n🔨 Step 5: Building updated plugins..."
build_plugins $to_update $force
} else {
log_info "\n🔨 Step 5 \(DRY RUN\): Would build plugins..."
for item in $to_update {
log_info $" Would build: ($item.name) in ($item.source.path)"
}
}
# Step 6: Install new binaries
if not $check {
log_info "\n📦 Step 6: Installing new plugin binaries..."
install_new_plugins $to_update $install_dir
} else {
log_info "\n📦 Step 6 \(DRY RUN\): Would install new binaries..."
for item in $to_update {
let binary_name = if ($item.source.name | str starts-with "nu_plugin_") {
$item.source.name
} else {
$"nu_plugin_($item.source.name)"
}
log_info $" Would install: ($item.source.path)/target/release/($binary_name)"
}
}
# Step 7: Register plugins
if not $check and not $no_register {
log_info "\n🔌 Step 7: Registering plugins with nushell..."
register_updated_plugins $to_update $install_dir $verify
} else if not $check {
log_info "\n🔌 Step 7: Skipped (--no-register)"
} else {
log_info "\n🔌 Step 7 \(DRY RUN\): Would register plugins..."
}
# Final summary
log_info "\n=================================================================="
if $check {
log_info "✅ DRY RUN COMPLETE - No changes made"
} else {
log_success "✅ Plugin update complete!"
}
log_info "Next steps:"
log_info " 1. Restart nushell: exit && nu"
log_info " 2. Verify plugins: nu -c 'plugin list'"
}
# Detect installed plugins in ~/.local/bin
def detect_installed_plugins [
install_dir: string
]: nothing -> list<record> {
try {
ls $install_dir
| where type == "file"
| where {|row|
let basename = $row.name | path basename
$basename =~ "^nu_plugin_"
}
| each {|row|
let basename = $row.name | path basename
{
name: $basename
install_path: $row.name
}
}
} catch {
[]
}
}
# Match installed plugins with source directories
def match_plugins_with_sources [
installed: list<record>
sources: list<record>
filter_plugin: string
]: nothing -> list<record> {
let filtered_sources = if ($filter_plugin | is-not-empty) {
$sources | where {|s|
if $s.name == $filter_plugin {
true
} else {
$s.name | str ends-with $filter_plugin
}
}
} else {
$sources
}
$installed
| where {|inst|
let match = $filtered_sources | where {|src|
if $inst.name == $src.name {
true
} else if $inst.name == ($src.name | str replace "^nu_plugin_" "") {
true
} else {
false
}
} | first
$match != null
}
| each {|inst|
let source = $filtered_sources | where {|src|
if $inst.name == $src.name {
true
} else if $inst.name == ($src.name | str replace "^nu_plugin_" "") {
true
} else {
false
}
} | first
{
name: $inst.name
install_path: $inst.install_path
source: $source
}
}
}
# Remove old plugin binaries
def remove_old_plugins [
to_update: list<record>
install_dir: string
] {
for item in $to_update {
if ($item.install_path | path exists) {
log_info $" Removing: ($item.name)"
try {
rm $item.install_path
log_success $" ✓ Deleted"
} catch {|err|
log_error $" ✗ Failed: ($err.msg)"
}
}
}
}
# Build plugins from source
def build_plugins [
to_update: list<record>
force: bool
] {
for item in $to_update {
let plugin_name = $item.source.name
let plugin_path = $item.source.path
log_info $" Building: ($plugin_name)"
try {
cd $plugin_path
# Clean if force rebuild
if $force {
log_info $" Cleaning build artifacts..."
cargo clean
}
# Build release version
log_info $" Compiling..."
try {
cargo build --release out+err>| grep -E "(Compiling|Finished)"
} catch {
log_info $" Build output not parseable, continuing..."
}
cd - | ignore
log_success $" ✓ Built successfully"
} catch {|err|
log_error $" ✗ Build failed: ($err.msg)"
}
}
}
# Install new plugin binaries
def install_new_plugins [
to_update: list<record>
install_dir: string
] {
for item in $to_update {
let plugin_name = $item.source.name
let plugin_path = $item.source.path
let plugin_binary = $"($plugin_path)/target/release/($plugin_name)"
let target_path = $item.install_path
if not ($plugin_binary | path exists) {
log_error $" Build artifact not found: ($plugin_binary)"
continue
}
try {
log_info $" Installing: ($plugin_name)"
cp $plugin_binary $target_path
chmod +x $target_path
log_success $" ✓ Installed to ($target_path)"
} catch {|err|
log_error $" ✗ Installation failed: ($err.msg)"
}
}
}
# Register updated plugins with nushell
def register_updated_plugins [
to_update: list<record>
install_dir: string
verify: bool
] {
let results = $to_update | each {|item|
let plugin_path = $item.install_path
let plugin_name = ($item.name | str replace "^nu_plugin_" "")
log_info $" Registering: ($item.name)"
let reg_result = try {
# Remove old registration if exists
try {
nu -c $"plugin rm ($plugin_name)" out+err>| null
} catch {
# Ignore if plugin doesn't exist
}
# Add new registration
nu -c $"plugin add ($plugin_path)"
log_success $" ✓ Registered"
# Verify if requested
if $verify {
try {
let found = nu -c $"plugin list | where name =~ ($plugin_name) | length" | into int
if $found > 0 {
log_success $" ✓ Verified"
{success: true, verified: true}
} else {
log_warn $" ⚠️ Could not verify"
{success: true, verified: false}
}
} catch {
log_warn $" ⚠️ Verification failed"
{success: true, verified: false}
}
} else {
{success: true, verified: null}
}
} catch {|err|
log_error $" ✗ Registration failed: ($err.msg)"
{success: false, verified: false}
}
$reg_result
}
let registered = ($results | where success | length)
let failed = ($results | where {|r| not $r.success} | length)
print ""
log_success $"📊 Registration Summary:"
log_success $" ✅ Registered: ($registered) plugins"
if $failed > 0 {
log_error $" ❌ Failed: ($failed) plugins"
}
}
# Common library functions (fallback if not available)
def log_info [msg: string] {
print $" ($msg)"
}
def log_success [msg: string] {
print $"✅ ($msg)"
}
def log_error [msg: string] {
print $"❌ ($msg)"
}
def log_warn [msg: string] {
print $"⚠️ ($msg)"
}
# Call main function
main