#!/usr/bin/env nu # Create Full Distribution - Complete Packaging Workflow # Creates both full distributions (nushell + plugins) and bin archives (plugins only) # # Usage: # create_full_distribution.nu # Current platform # create_full_distribution.nu --all-platforms # All platforms # create_full_distribution.nu --bin-only # Only create bin archives use lib/common_lib.nu * # Main entry point def main [ --all-platforms # Create packages for all platforms --bin-only # Only create bin archives --checksums # Generate SHA256 checksums --verify # Verify packages after creation ] { print_banner if not $bin_only { # Phase 1: Collect binaries print "╔══════════════════════════════════════════════════════════╗" print "║ Phase 1: Collect Binaries ║" print "╚══════════════════════════════════════════════════════════╝" collect_binaries $all_platforms } # Phase 2: Create full distribution packages if not $bin_only { print "" print "╔══════════════════════════════════════════════════════════╗" print "║ Phase 2: Create Full Distribution Packages ║" print "╚══════════════════════════════════════════════════════════╝" create_distribution_packages $all_platforms $checksums } # Phase 3: Create bin archives print "" print "╔══════════════════════════════════════════════════════════╗" print "║ Phase 3: Create Bin Archives ║" print "╚══════════════════════════════════════════════════════════╝" create_bin_archives # Phase 4: Verification if $verify { print "" print "╔══════════════════════════════════════════════════════════╗" print "║ Phase 4: Verify Packages ║" print "╚══════════════════════════════════════════════════════════╝" verify_packages } # Final summary generate_distribution_summary $all_platforms $bin_only } # Print banner def print_banner [] { print $" (ansi blue)╔════════════════════════════════════════════════════════════╗ ║ ║ ║ 📦 Complete Distribution Creator 📦 ║ ║ ║ ║ Creates: ║ ║ • Full distribution packages \(nu + plugins\) ║ ║ • Bin archives \(plugins only\) ║ ║ • Checksums and manifests ║ ║ ║ ╚════════════════════════════════════════════════════════════╝(ansi reset) " } # Collect binaries for distribution def collect_binaries [all_platforms: bool] { log_info "📥 Collecting binaries..." if ("./scripts/collect_full_binaries.nu" | path exists) { # Use built nu binary, not system nu (which may be broken) let built_nu = "./nushell/target/release/nu" let nu_bin = if ($built_nu | path exists) { $built_nu } else { "nu" } let result = (do { if $all_platforms { ^$nu_bin ./scripts/collect_full_binaries.nu --all-platforms --force } else { ^$nu_bin ./scripts/collect_full_binaries.nu --force } } | complete) print $result.stdout if ($result.stderr | is-not-empty) { print $result.stderr } if $result.exit_code == 0 { log_success "Binaries collected successfully" } else { log_error $"Failed to collect binaries \(exit code: ($result.exit_code)\)" if ($result.stderr | is-not-empty) { log_error $result.stderr } exit 1 } } else { log_warn "collect_full_binaries.nu not found, using fallback..." collect_binaries_fallback } } # Fallback binary collection def collect_binaries_fallback [] { let platform = detect_platform log_info $"Collecting for platform: ($platform)" # Create distribution directory let dist_dir = $"./distribution/($platform)" ensure_dir $dist_dir # Copy nushell binary if ("./nushell/target/release/nu" | path exists) { cp ./nushell/target/release/nu $dist_dir log_success "Copied nushell binary" } else { log_error "Nushell binary not found. Build it first with: just build-nushell" exit 1 } # Copy system plugins let system_plugins = (try { ls ./nushell/target/release/nu_plugin_* } catch { [] } | where type == file) for plugin in $system_plugins { cp $plugin.name $dist_dir } if ($system_plugins | length) > 0 { log_success $"Copied ($system_plugins | length) system plugins" } # Copy custom plugins let custom_plugins = (try { ls nu_plugin_*/target/release/nu_plugin_* } catch { [] } | where type == file) for plugin in $custom_plugins { cp $plugin.name $dist_dir } if ($custom_plugins | length) > 0 { log_success $"Copied ($custom_plugins | length) custom plugins" } let total = 1 + ($system_plugins | length) + ($custom_plugins | length) log_success $"Total binaries collected: ($total)" } # Create distribution packages def create_distribution_packages [ all_platforms: bool checksums: bool ] { log_info "📦 Creating distribution packages..." if ("./scripts/create_distribution_packages.nu" | path exists) { # Use project binary for consistency let built_nu = "./nushell/target/release/nu" let nu_bin = if ($built_nu | path exists) { $built_nu } else { "nu" } let result = (do { if $all_platforms and $checksums { ^$nu_bin ./scripts/create_distribution_packages.nu --all-platforms --checksums } else if $all_platforms { ^$nu_bin ./scripts/create_distribution_packages.nu --all-platforms } else if $checksums { ^$nu_bin ./scripts/create_distribution_packages.nu --checksums } else { ^$nu_bin ./scripts/create_distribution_packages.nu } } | complete) print $result.stdout if $result.exit_code == 0 { log_success "Distribution packages created" } } else { log_warn "create_distribution_packages.nu not found, using justfile..." let pack_result = (do { if $all_platforms { just pack-full-all } else { just pack-full } } | complete) if $pack_result.exit_code == 0 { log_success "Packages created via justfile" } } } # Create bin archives (plugin-only) - directly from built plugins def create_bin_archives [] { log_info "📦 Creating bin archives (plugin-only)..." # Create output directory if not ("./bin_archives" | path exists) { mkdir ./bin_archives } # Get version for naming let version = try { open ./nushell/Cargo.toml | get package.version } catch { "unknown" } # Get actually built platforms from distribution directory let built_platforms = try { ls ./distribution/*/nu | each {|p| $p.name | path dirname | path basename} } catch { [] } # If no platforms found, skip Phase 3 if ($built_platforms | length) == 0 { log_warn "No platforms found in distribution directory - skipping plugin archive creation" return } # Create archive for each built platform for platform in $built_platforms { let archive_name = $"plugins-only-($version)-($platform).tar.gz" let archive_path = (pwd | append "bin_archives" | path join | append $archive_name | path join) # Create temporary directory for archive contents let temp_dir = (pwd | append "bin_archives" | path join | append $"plugins-temp-($version)-($platform)" | path join) mkdir $temp_dir # Collect all built plugin binaries log_info $"📦 Collecting plugins for ($platform)..." # Get list of plugin binaries (exclude .d dependency files) let plugins_to_copy = ( try { ls nu_plugin_*/target/release/nu_plugin_* | where type == "file" } catch { [] } ) let plugin_count = ($plugins_to_copy | length) if $plugin_count > 0 { log_success $"Collected ($plugin_count) plugins" # Copy plugins to temp directory try { $plugins_to_copy | each {|p| cp $p.name $temp_dir } } catch { log_error "Failed to copy plugins to temp directory" } # Create archive using absolute path (tar -C changes directory safely) log_info "Creating archive..." let tar_result = (do { tar -C $temp_dir -czf $archive_path . } | complete) if $tar_result.exit_code == 0 { if ($archive_path | path exists) { let size = (ls $archive_path | get 0.size) / 1024 / 1024 log_success $"Archive created: ($archive_name) - (($size | into int))MB" } else { log_error $"Archive file exists but cannot be accessed: ($archive_path)" } } else { log_error $"Failed to create archive. Exit code: ($tar_result.exit_code)" if ($tar_result.stderr | is-not-empty) { log_error $"Tar error: ($tar_result.stderr)" } } } else { log_warn $"No plugins found to package for ($platform)" } # Clean up temp directory if ($temp_dir | path exists) { try { rm -r $temp_dir } catch { log_warn "Could not clean up temporary directory" } } } } # Verify packages def verify_packages [] { log_info "✅ Verifying packages..." # Check distribution packages if ("./distribution/packages" | path exists) { let packages = (try { ls ./distribution/packages/*.tar.gz ./distribution/packages/*.zip } catch { [] }) if ($packages | length) > 0 { log_success $"Found ($packages | length) distribution packages" for pkg in $packages { let name = $pkg.name | path basename let size = $pkg.size / 1024 / 1024 if $size < 1 { log_error $" ✗ ($name): Too small (($size | into int)MB)" } else if $size > 500 { log_warn $" ⚠ ($name): Very large (($size | into int)MB)" } else { log_success $" ✓ ($name): (($size | into int)MB)" } } } else { log_warn "No distribution packages found" } } # Check bin archives if ("./bin_archives" | path exists) { let archives = (try { ls ./bin_archives/*.tar.gz } catch { [] }) if ($archives | length) > 0 { log_success $"Found ($archives | length) bin archives" } else { log_warn "No bin archives found" } } # Verify checksums if present if ("./distribution/packages/checksums.txt" | path exists) { log_info "Verifying checksums..." let check_result = (do { cd distribution/packages shasum -c checksums.txt } | complete) if $check_result.exit_code == 0 { log_success "All checksums verified" } else { log_error "Checksum verification failed" } } } # Generate distribution summary def generate_distribution_summary [ all_platforms: bool bin_only: bool ] { log_info "\n📊 Distribution Summary\n" # Get nushell version let version = if ("./nushell/Cargo.toml" | path exists) { open ./nushell/Cargo.toml | get package.version } else { "unknown" } log_success $"Nushell version: ($version)" # Count distribution packages if not $bin_only and ("./distribution/packages" | path exists) { let packages = (try { ls ./distribution/packages/*.tar.gz ./distribution/packages/*.zip } catch { [] }) if ($packages | length) > 0 { log_success $"Distribution packages: ($packages | length)" let total_size = ($packages | get size | math sum) / 1024 / 1024 log_info $"Total size: (($total_size | into int))MB" } } # Count bin archives if ("./bin_archives" | path exists) { let archives = (try { ls ./bin_archives/*.tar.gz } catch { [] }) if ($archives | length) > 0 { log_success $"Bin archives: ($archives | length)" let total_size = ($archives | get size | math sum) / 1024 / 1024 log_info $"Total size: (($total_size | into int))MB" } } # List platforms if not $bin_only and ("./distribution" | path exists) { let platforms = (try { ls ./distribution/*/nu } catch { [] } | each {|p| $p.name | path dirname | path basename}) if ($platforms | length) > 0 { log_info $"\nPlatforms built: ($platforms | str join ', ')" # Next steps - use actual built platforms log_info "\n📝 Next Steps:" log_info " 1. Test installation:" # Show example for first built platform let first_platform = $platforms | first 1 | get 0 log_info $" cd distribution/($first_platform) && ./install.nu --verify" } } else { # If bin_only, no next steps for distribution log_info "\n📝 Next Steps:" } if not $bin_only { # Continue with other next steps } log_info " 2. Upload to release:" log_info " gh release create v($version) distribution/packages/*" log_info " 3. Update documentation:" log_info " Update README.md with new version" } # Detect current platform def detect_platform []: nothing -> string { let host_info = sys host let os = $host_info.name let arch = (sys cpu | get 0.name) if $os == "Darwin" { if $arch == "aarch64" { "darwin-arm64" } else { "darwin-x86_64" } } else if $os == "Linux" { if $arch == "aarch64" { "linux-arm64" } else { "linux-x86_64" } } else if $os == "Windows" { "windows-x86_64" } else { $"($os | str downcase)-($arch)" } } # Ensure directory exists def ensure_dir [dir: string] { if not ($dir | path exists) { mkdir $dir } } # Quick command to rebuild and redistribute def "main rebuild" [] { log_info "🔄 Rebuild and redistribute workflow\n" # Build nushell log_info "Building nushell..." let build_result = (do { just build-nushell } | complete) if $build_result.exit_code != 0 { log_error "Nushell build failed" exit 1 } # Build plugins log_info "Building plugins..." let plugins_result = (do { just build } | complete) if $plugins_result.exit_code != 0 { log_warn "Some plugins failed to build" } # Create distributions main --checksums } # Show distribution status def "main status" [] { log_info "📊 Distribution Status\n" # Check if nushell is built if ("./nushell/target/release/nu" | path exists) { let version_result = (do { ./nushell/target/release/nu -c "version | get version" } | complete) log_success $"Nushell binary: (str trim $version_result.stdout)" } else { log_warn "Nushell binary: Not built" } # Check distribution directory if ("./distribution" | path exists) { let platforms = (try { ls ./distribution/*/nu } catch { [] }) if ($platforms | length) > 0 { log_success $"Distribution platforms: ($platforms | length)" for p in $platforms { let platform = $p.name | path dirname | path basename print $" • ($platform)" } } else { log_warn "Distribution: No binaries collected" } } else { log_warn "Distribution: Not created" } # Check packages if ("./distribution/packages" | path exists) { let packages = (try { ls ./distribution/packages/*.tar.gz ./distribution/packages/*.zip } catch { [] }) if ($packages | length) > 0 { log_success $"Packages: ($packages | length) created" } else { log_warn "Packages: None created" } } # Check bin archives if ("./bin_archives" | path exists) { let archives = (try { ls ./bin_archives/*.tar.gz } catch { [] }) if ($archives | length) > 0 { log_success $"Bin archives: ($archives | length) created" } else { log_warn "Bin archives: None created" } } }