Some checks failed
Build and Test / Validate Setup (push) Has been cancelled
Build and Test / Build (darwin-amd64) (push) Has been cancelled
Build and Test / Build (darwin-arm64) (push) Has been cancelled
Build and Test / Build (linux-amd64) (push) Has been cancelled
Build and Test / Build (windows-amd64) (push) Has been cancelled
Build and Test / Build (linux-arm64) (push) Has been cancelled
Build and Test / Security Audit (push) Has been cancelled
Build and Test / Package Results (push) Has been cancelled
Build and Test / Quality Gate (push) Has been cancelled
414 lines
12 KiB
Plaintext
Executable File
414 lines
12 KiB
Plaintext
Executable File
#!/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
|