541 lines
20 KiB
Plaintext
Executable File
541 lines
20 KiB
Plaintext
Executable File
#!/usr/bin/env nu
|
|
|
|
# Collect Install Script
|
|
# Collects built plugins and prepares them for installation/distribution
|
|
|
|
# Load environment variables from env file
|
|
def load_env_vars [] {
|
|
let env_file = "env"
|
|
if ($env_file | path exists) {
|
|
let content = open $env_file | lines
|
|
| where ($it | str trim | str length) > 0
|
|
| where not ($it | str starts-with "#")
|
|
| each {|line|
|
|
if ($line | str contains "=") {
|
|
let parts = ($line | split row "=")
|
|
if ($parts | length) >= 2 {
|
|
let key = ($parts | get 0 | str replace "export " "" | str trim)
|
|
let raw_value = ($parts | get 1 | str trim)
|
|
# Handle bash-style default values like ${VAR:-default}
|
|
let value = if ($raw_value | str starts-with "${") and ($raw_value | str contains ":-") {
|
|
# Extract default value from ${VAR:-default}
|
|
let parts = ($raw_value | str replace "${" "" | str replace "}" "" | split row ":-")
|
|
if ($parts | length) >= 2 {
|
|
$parts | get 1
|
|
} else {
|
|
$raw_value
|
|
}
|
|
} else {
|
|
$raw_value
|
|
}
|
|
{$key: $value}
|
|
} else {
|
|
{}
|
|
}
|
|
} else {
|
|
{}
|
|
}
|
|
}
|
|
| reduce -f {} {|item, acc|
|
|
if ($item | is-empty) {
|
|
$acc
|
|
} else {
|
|
$acc | merge $item
|
|
}
|
|
}
|
|
|
|
$content
|
|
} else {
|
|
{
|
|
TARGET_PATH: "distribution",
|
|
INSTALL_BIN_PATH: "/usr/local/bin",
|
|
ARCHIVE_DIR_PATH: "/tmp",
|
|
BIN_ARCHIVES_DIR_PATH: "bin_archives"
|
|
}
|
|
}
|
|
}
|
|
|
|
# Load build targets configuration
|
|
def load_targets_config [] {
|
|
if ("etc/build_targets.toml" | path exists) {
|
|
open etc/build_targets.toml
|
|
} else {
|
|
{targets: {}}
|
|
}
|
|
}
|
|
|
|
# Get host platform information
|
|
def get_host_info [] {
|
|
let arch = match (^uname -m) {
|
|
"x86_64" => "amd64",
|
|
"aarch64" => "arm64",
|
|
"arm64" => "arm64",
|
|
$arch if ($arch | str starts-with "arm") => "arm64",
|
|
$other => $other
|
|
}
|
|
|
|
let platform = match (^uname -s | str downcase) {
|
|
$os if ($os | str contains "linux") => "linux",
|
|
$os if ($os | str contains "darwin") => "darwin",
|
|
$os if ($os | str contains "windows") => "windows",
|
|
$other => $other
|
|
}
|
|
|
|
{platform: $platform, arch: $arch, full: $"($platform)-($arch)"}
|
|
}
|
|
|
|
# Get all built plugin binaries for a specific target or all targets
|
|
def get_built_plugins [target: string = ""] {
|
|
let config = load_targets_config
|
|
let host_info = get_host_info
|
|
|
|
if ($target | str length) > 0 {
|
|
# Special handling for "host" target or detected host platform
|
|
if ($target == "host") or ($target == $host_info.full) {
|
|
# Get plugins for host platform (native build)
|
|
glob "nu_plugin_*/target/release/nu_plugin_*"
|
|
| where ($it | path type) == "file"
|
|
| where ($it | path exists)
|
|
| where not ($it | str ends-with ".d")
|
|
| each {|path|
|
|
let plugin_name = $path | path basename
|
|
let plugin_dir = $path | path dirname | path dirname | path dirname
|
|
{
|
|
name: $plugin_name,
|
|
path: $path,
|
|
source_dir: $plugin_dir,
|
|
target: $host_info.full,
|
|
size: (ls $path | get size | get 0)
|
|
}
|
|
}
|
|
} else if ($target in ($config.targets | transpose name config | get name)) {
|
|
# Get plugins for specific target
|
|
let target_config = $config.targets | get $target
|
|
get_plugins_for_target $target $target_config
|
|
} else {
|
|
print $"❌ Unknown target: ($target)"
|
|
[]
|
|
}
|
|
} else {
|
|
# Get plugins for host platform - use actual detected platform
|
|
glob "nu_plugin_*/target/release/nu_plugin_*"
|
|
| where ($it | path type) == "file"
|
|
| where ($it | path exists)
|
|
| where not ($it | str ends-with ".d")
|
|
| each {|path|
|
|
let plugin_name = $path | path basename
|
|
let plugin_dir = $path | path dirname | path dirname | path dirname
|
|
{
|
|
name: $plugin_name,
|
|
path: $path,
|
|
source_dir: $plugin_dir,
|
|
target: $host_info.full,
|
|
size: (ls $path | get 0.size)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Get plugins for a specific target
|
|
def get_plugins_for_target [target_name: string, target_config: record] {
|
|
let rust_target = $target_config.rust_target
|
|
let binary_ext = $target_config | get binary_extension? | default ""
|
|
|
|
# Look for binaries in target-specific directories
|
|
let target_pattern = $"nu_plugin_*/target/($rust_target)/release/nu_plugin_*"
|
|
|
|
glob $target_pattern
|
|
| where ($it | path type) == "file"
|
|
| where ($it | path exists)
|
|
| where not ($it | str ends-with ".d")
|
|
| each {|path|
|
|
let plugin_name = $path | path basename
|
|
let plugin_dir = $path | path dirname | path dirname | path dirname | path dirname
|
|
{
|
|
name: $plugin_name,
|
|
path: $path,
|
|
source_dir: $plugin_dir,
|
|
target: $target_name,
|
|
size: (ls $path | get 0.size)
|
|
}
|
|
}
|
|
}
|
|
|
|
# Get all available built targets
|
|
def get_available_targets [] {
|
|
let config = load_targets_config
|
|
let host_info = get_host_info
|
|
|
|
mut available = []
|
|
|
|
# Check host platform first
|
|
let host_plugins = glob "nu_plugin_*/target/release/nu_plugin_*" | where not ($it | str ends-with ".d")
|
|
if ($host_plugins | length) > 0 {
|
|
$available = ($available | append {
|
|
name: $host_info.full,
|
|
platform_name: $host_info.full,
|
|
count: ($host_plugins | length),
|
|
description: "Host platform binaries"
|
|
})
|
|
}
|
|
|
|
# Check cross-compiled targets
|
|
for target in ($config.targets | transpose name config) {
|
|
let rust_target = $target.config.rust_target
|
|
let target_plugins = glob $"nu_plugin_*/target/($rust_target)/release/nu_plugin_*" | where not ($it | str ends-with ".d")
|
|
if ($target_plugins | length) > 0 {
|
|
$available = ($available | append {
|
|
name: $target.name,
|
|
platform_name: $target.config.platform_name,
|
|
count: ($target_plugins | length),
|
|
description: $target.config.description
|
|
})
|
|
}
|
|
}
|
|
|
|
$available
|
|
}
|
|
|
|
# Create target directory structure
|
|
def create_target_structure [target_path: string] {
|
|
if not ($target_path | path exists) {
|
|
mkdir $target_path
|
|
print $"📁 Created target directory: ($target_path)"
|
|
}
|
|
|
|
# Create subdirectories if needed
|
|
let subdirs = ["scripts", "docs"]
|
|
for subdir in $subdirs {
|
|
let subdir_path = $"($target_path)/($subdir)"
|
|
if not ($subdir_path | path exists) {
|
|
mkdir $subdir_path
|
|
}
|
|
}
|
|
}
|
|
|
|
# Copy plugin binaries to target
|
|
def copy_plugins [plugins: list, target_path: string] {
|
|
print $"📦 Copying ($plugins | length) plugin binaries..."
|
|
|
|
for plugin in $plugins {
|
|
let dest_path = $"($target_path)/($plugin.name)"
|
|
cp $plugin.path $dest_path
|
|
|
|
# Make executable
|
|
chmod +x $dest_path
|
|
|
|
print $" ✅ ($plugin.name) (($plugin.size))"
|
|
}
|
|
}
|
|
|
|
# Copy additional files
|
|
def copy_additional_files [target_path: string] {
|
|
let files_to_copy = [
|
|
{src: "LICENSE", dest: "LICENSE", required: false},
|
|
{src: "README.md", dest: "README", required: false},
|
|
{src: "env", dest: "env", required: false}
|
|
]
|
|
|
|
for file in $files_to_copy {
|
|
if ($file.src | path exists) {
|
|
cp $file.src $"($target_path)/($file.dest)"
|
|
print $" 📄 Copied ($file.src) → ($file.dest)"
|
|
} else if $file.required {
|
|
print $" ⚠️ Required file not found: ($file.src)"
|
|
}
|
|
}
|
|
}
|
|
|
|
# Create installation script
|
|
def create_install_script [target_path: string, install_file: string] {
|
|
let timestamp = (date now | format date "%Y-%m-%d %H:%M:%S")
|
|
let install_script_content = "#!/usr/bin/env nu
|
|
|
|
# Auto-generated installation script for nushell plugins
|
|
# Generated at: " + $timestamp + "
|
|
|
|
def main [
|
|
--bin-path (-b): string = \"/usr/local/bin\" # Installation path
|
|
--plugins (-p): list<string> = [] # Specific plugins to install
|
|
--list (-l) # List available plugins
|
|
--dry-run (-d) # Show what would be done
|
|
--register-only (-r) # Only register plugins, don't copy binaries
|
|
--no-register # Copy binaries but don't register with nushell
|
|
--verify (-v) # Verify plugin registration after installation
|
|
] {
|
|
let available_plugins = ls | where type == file and name =~ \"nu_plugin_\" | get name
|
|
|
|
if " + '$list' + " {
|
|
print \"📦 Available plugins:\"
|
|
for plugin in " + '$available_plugins' + " {
|
|
print " + '$" - ($plugin)"' + "
|
|
}
|
|
return
|
|
}
|
|
|
|
let plugins_to_install = if (" + '$plugins' + " | length) > 0 {
|
|
" + '$plugins' + " | where " + '$it' + " in " + '$available_plugins' + "
|
|
} else {
|
|
" + '$available_plugins' + "
|
|
}
|
|
|
|
if (" + '$plugins_to_install' + " | length) == 0 {
|
|
print \"❓ No plugins to install\"
|
|
return
|
|
}
|
|
|
|
print " + '$"🚀 Processing ($plugins_to_install | length) plugins..."' + "
|
|
|
|
# Step 1: Copy binaries (unless register-only mode)
|
|
if not " + '$register_only' + " {
|
|
print " + '$"\\n📦 Installing binaries to ($bin_path)..."' + "
|
|
for plugin in " + '$plugins_to_install' + " {
|
|
if " + '$dry_run' + " {
|
|
print " + '$"Would install: ($plugin) → ($bin_path)/($plugin)"' + "
|
|
} else {
|
|
try {
|
|
cp " + '$plugin' + " " + '$"($bin_path)/($plugin)"' + "
|
|
chmod +x " + '$"($bin_path)/($plugin)"' + "
|
|
print " + '$" ✅ Installed ($plugin)"' + "
|
|
} catch {|err|
|
|
print " + '$" ❌ Failed to install ($plugin): ($err.msg)"' + "
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Step 2: Register plugins with nushell (unless disabled)
|
|
if not " + '$no_register' + " {
|
|
print \"\\n🔌 Registering plugins with nushell...\"
|
|
for plugin in " + '$plugins_to_install' + " {
|
|
let plugin_path = if " + '$register_only' + " {
|
|
# Use current directory path for register-only mode
|
|
" + '$"./($plugin)"' + "
|
|
} else {
|
|
# Use installation path for normal mode
|
|
" + '$"($bin_path)/($plugin)"' + "
|
|
}
|
|
|
|
if " + '$dry_run' + " {
|
|
print " + '$"Would register: plugin add ($plugin_path)"' + "
|
|
} else {
|
|
try {
|
|
nu -c " + '$"plugin add ($plugin_path)"' + "
|
|
print " + '$" ✅ Registered ($plugin)"' + "
|
|
} catch {|err|
|
|
print " + '$" ⚠️ Failed to register ($plugin): ($err.msg)"' + "
|
|
print " + '$" You can manually register with: plugin add ($plugin_path)"' + "
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Step 3: Verify plugin registration (if requested and plugins were registered)
|
|
if " + '$verify' + " and not " + '$no_register' + " and not " + '$dry_run' + " {
|
|
print \"\\n🔍 Verifying plugin registration...\"
|
|
for plugin in " + '$plugins_to_install' + " {
|
|
let plugin_name = (" + '$plugin' + " | str replace \"nu_plugin_\" \"\")
|
|
try {
|
|
let found = (nu -c " + '$"plugin list | where name =~ ($plugin_name) | length"' + " | into int)
|
|
if " + '$found' + " > 0 {
|
|
print " + '$" ✅ Verified ($plugin)"' + "
|
|
} else {
|
|
print " + '$" ❌ Not found in plugin list: ($plugin)"' + "
|
|
}
|
|
} catch {|err|
|
|
print " + '$" ⚠️ Could not verify ($plugin): ($err.msg)"' + "
|
|
}
|
|
}
|
|
}
|
|
|
|
# Summary
|
|
if not " + '$dry_run' + " {
|
|
if " + '$register_only' + " {
|
|
print \"\\n✅ Plugin registration completed!\"
|
|
if " + '$verify' + " {
|
|
print \"💡 Run 'plugin list' to see all registered plugins\"
|
|
}
|
|
} else if " + '$no_register' + " {
|
|
print \"\\n✅ Plugin installation completed!\"
|
|
print \"💡 To register plugins, run: nu install_nu_plugins.nu --register-only\"
|
|
} else {
|
|
print \"\\n✅ Plugin installation and registration completed!\"
|
|
if " + '$verify' + " {
|
|
print \"💡 All plugins verified. Run 'plugin list' to see details\"
|
|
} else {
|
|
print \"💡 Restart nushell or run 'plugin list' to see registered plugins\"
|
|
print \" Add --verify to automatically check registration next time\"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
"
|
|
|
|
$install_script_content | save --force ($target_path | path join $install_file)
|
|
chmod +x ($target_path | path join $install_file)
|
|
print $"📜 Created installation script: ($install_file)"
|
|
}
|
|
|
|
# Main function
|
|
def main [
|
|
--target-path (-t): string = "" # Override target path
|
|
--platform (-p): string = "" # Specific platform to collect (e.g., linux-amd64)
|
|
--all-platforms (-a) # Collect all available platforms
|
|
--force (-f) # Force overwrite existing files
|
|
--list (-l) # List available plugins only
|
|
--list-platforms # List available platforms
|
|
] {
|
|
# Ensure we're in the repository root directory
|
|
if not ("nu_plugin_clipboard" | path exists) {
|
|
error make {msg: "Please run this script from the nushell-plugins repository root directory"}
|
|
}
|
|
|
|
print "📦 Nushell Plugin Collection & Installation Preparation"
|
|
|
|
# Load environment variables
|
|
let env_vars = load_env_vars
|
|
let base_target_path = if ($target_path | str length) > 0 { $target_path } else { $env_vars.TARGET_PATH? | default "distribution" }
|
|
let install_file = $env_vars.INSTALL_FILE? | default "install_nu_plugins.nu"
|
|
|
|
# List platforms mode
|
|
if $list_platforms {
|
|
let available = get_available_targets
|
|
if ($available | length) == 0 {
|
|
print "❓ No built platforms found"
|
|
print "💡 Run cross-compilation builds first"
|
|
} else {
|
|
print "📊 Available built platforms:"
|
|
for target in $available {
|
|
print $" ✅ ($target.name) ($target.platform_name): ($target.count) plugins"
|
|
print $" ($target.description)"
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
# Determine platforms to collect
|
|
let available_targets = get_available_targets
|
|
let host_info = get_host_info
|
|
|
|
let platforms_to_collect = if $all_platforms {
|
|
$available_targets
|
|
} else if ($platform | str length) > 0 {
|
|
# Handle "host" as a special case - map to actual platform
|
|
let target_to_find = if ($platform == "host") { $host_info.full } else { $platform }
|
|
let selected = $available_targets | where name == $target_to_find
|
|
if ($selected | length) == 0 {
|
|
print $"❌ Platform not found: ($platform)"
|
|
print $"💡 Available platforms: ($available_targets | get name | str join ', ')"
|
|
exit 1
|
|
}
|
|
$selected
|
|
} else {
|
|
# Default to host platform if available
|
|
let host_info = get_host_info
|
|
let host_target = $available_targets | where name == $host_info.full
|
|
if ($host_target | length) > 0 {
|
|
$host_target
|
|
} else {
|
|
# Fallback to first available platform
|
|
$available_targets | first 1
|
|
}
|
|
}
|
|
|
|
if ($platforms_to_collect | length) == 0 {
|
|
print "❓ No platforms to collect"
|
|
print "💡 Build plugins first with: just build or just build-cross-all"
|
|
exit 1
|
|
}
|
|
|
|
print $"🎯 Platforms to collect: ($platforms_to_collect | length)"
|
|
for platform in $platforms_to_collect {
|
|
print $" - ($platform.name): ($platform.count) plugins"
|
|
}
|
|
|
|
# Process each platform
|
|
mut total_collected = 0
|
|
for platform_info in $platforms_to_collect {
|
|
let platform_name = $platform_info.name
|
|
let plugins = get_built_plugins $platform_name
|
|
|
|
if $list {
|
|
if ($plugins | length) == 0 {
|
|
print $"❓ No built plugins found for ($platform_name)"
|
|
} else {
|
|
print $"\n📦 ($platform_name) - ($plugins | length) built plugins:"
|
|
for plugin in $plugins {
|
|
print $" ✅ ($plugin.name) (($plugin.size)) from ($plugin.source_dir)"
|
|
}
|
|
}
|
|
continue
|
|
}
|
|
|
|
if ($plugins | length) == 0 {
|
|
print $"⚠️ No plugins found for platform: ($platform_name)"
|
|
continue
|
|
}
|
|
|
|
# Create platform-specific directory structure
|
|
let platform_target_path = if $all_platforms {
|
|
$"($base_target_path)/($platform_name)"
|
|
} else {
|
|
$base_target_path
|
|
}
|
|
|
|
print $"\n📦 Collecting ($plugins | length) plugins for ($platform_name)..."
|
|
print $"📁 Target: ($platform_target_path)"
|
|
|
|
# Check if target exists and handle accordingly
|
|
if ($platform_target_path | path exists) and not $force {
|
|
print $"⚠️ Target directory '($platform_target_path)' already exists"
|
|
let confirm = input "Continue and overwrite? [y/N]: "
|
|
if ($confirm | str downcase) != "y" {
|
|
print "❌ Skipping ($platform_name)"
|
|
continue
|
|
}
|
|
}
|
|
|
|
# Create target structure
|
|
create_target_structure $platform_target_path
|
|
|
|
# Copy plugins
|
|
copy_plugins $plugins $platform_target_path
|
|
|
|
# Copy additional files
|
|
print "📄 Copying additional files..."
|
|
copy_additional_files $platform_target_path
|
|
|
|
# Create platform-specific installation script
|
|
create_install_script $platform_target_path $install_file
|
|
|
|
$total_collected = $total_collected + ($plugins | length)
|
|
|
|
print $"✅ Collected ($plugins | length) plugins for ($platform_name)"
|
|
}
|
|
|
|
# List mode summary
|
|
if $list {
|
|
return
|
|
}
|
|
|
|
# Summary
|
|
print $"\n🎉 Collection completed!"
|
|
print $"📁 Base directory: ($base_target_path)"
|
|
print $"📦 Total plugins collected: ($total_collected)"
|
|
print $"🎯 Platforms: ($platforms_to_collect | get name | str join ', ')"
|
|
|
|
print "\n💡 Next steps:"
|
|
if $all_platforms {
|
|
print " 1. Package all platforms: just pack-cross"
|
|
print " 2. Test individual platforms: cd distribution/PLATFORM && nu install_nu_plugins.nu --dry-run"
|
|
} else {
|
|
let final_path = if $all_platforms { $"($base_target_path)/($platforms_to_collect.0.name)" } else { $base_target_path }
|
|
print $" 1. Test installation: cd ($final_path) && nu ($install_file) --dry-run"
|
|
print $" 2. Package for distribution: just pack"
|
|
print $" 3. Install locally: cd ($final_path) && nu ($install_file)"
|
|
}
|
|
}
|
|
|
|
if ($env.NUSHELL_EXECUTION_CONTEXT? | default "" | str contains "run") {
|
|
main
|
|
} |