#!/usr/bin/env nu # Download Nushell Source Script # Downloads and extracts Nushell source from GitHub tags # # Usage: # download_nushell.nu # Download specific version # download_nushell.nu --latest # Download latest release # download_nushell.nu --clean # Remove existing nushell directory use lib/common_lib.nu * # Main entry point def main [ version?: string # Nushell version (e.g., "0.108.0") --latest # Download latest release --clean # Remove existing nushell directory first --verify # Verify download integrity ] { log_info "Nushell Source Download Script" # Determine target version let target_version = if $latest { get_latest_nushell_version } else if ($version | is-empty) { log_error "Please specify a version or use --latest flag" log_info "Usage: download_nushell.nu or download_nushell.nu --latest" exit 1 } else { $version } log_info $"Target version: ($target_version)" # Check if nushell directory already exists with correct version let nushell_dir = "./nushell" if ($nushell_dir | path exists) and (not $clean) { let cargo_toml = $"($nushell_dir)/Cargo.toml" if ($cargo_toml | path exists) { let existing_version = (try { open $cargo_toml | get package.version } catch { "" }) if $existing_version == $target_version { log_success $"Nushell ($target_version) already exists - skipping download" log_info "Use --clean flag to force re-download" return } else { log_warn $"Found different version: ($existing_version) - will download ($target_version)" } } } # Clean existing directory if requested if $clean { clean_nushell_directory } # Download and extract download_nushell_tarball $target_version $verify # Verify extraction verify_nushell_source $target_version log_success $"Nushell ($target_version) downloaded and ready!" log_info $"Location: ./nushell/" log_info $"Next steps: Run 'just analyze-nushell-features' to check available features" } # Get latest nushell version from GitHub API def get_latest_nushell_version []: nothing -> string { log_info "Fetching latest Nushell version from GitHub..." let api_url = "https://api.github.com/repos/nushell/nushell/releases/latest" let response = try { http get $api_url } catch { log_error "Failed to fetch latest release from GitHub API" log_info "Falling back to manual check at: https://github.com/nushell/nushell/releases" exit 1 } let tag_name = try { $response | get tag_name | str trim } catch { log_error "Could not parse tag_name from GitHub response" exit 1 } # Remove 'v' prefix if present let version = $tag_name | str replace "^v" "" log_success $"Latest version: ($version)" $version } # Clean existing nushell directory def clean_nushell_directory [] { let nushell_dir = "./nushell" if ($nushell_dir | path exists) { log_warn "Removing existing nushell directory..." rm -rf $nushell_dir log_success "Cleaned nushell directory" } else { log_info "No existing nushell directory to clean" } } # Download nushell tarball from GitHub def download_nushell_tarball [ version: string verify_checksum: bool ] { let tarball_url = $"https://github.com/nushell/nushell/archive/refs/tags/($version).tar.gz" let download_dir = "./tmp" let tarball_path = $"($download_dir)/nushell-($version).tar.gz" # Ensure tmp directory exists ensure_dir $download_dir # Download tarball log_info $"Downloading from: ($tarball_url)" let download_result = try { http get $tarball_url | save -f $tarball_path {success: true} } catch { |err| {success: false, error: $err} } if not $download_result.success { log_error $"Failed to download tarball from GitHub" log_info $"URL: ($tarball_url)" exit 1 } # Check file was downloaded if not ($tarball_path | path exists) { log_error $"Tarball not found at ($tarball_path)" exit 1 } let file_size = (ls $tarball_path | get size.0) log_success $"Downloaded tarball: ($file_size) bytes" # Verify checksum if requested if $verify_checksum { verify_download_checksum $tarball_path $version } # Extract tarball extract_nushell_tarball $tarball_path $version } # Verify download checksum (optional) def verify_download_checksum [ tarball_path: string version: string ] { log_info "Calculating SHA256 checksum..." let checksum = open $tarball_path --raw | hash sha256 log_info $"Checksum: ($checksum)" # Note: GitHub doesn't provide checksums for source archives # This is just for verification and logging log_warn "GitHub source archives don't have published checksums" log_info "Checksum calculated for local verification only" } # Extract nushell tarball def extract_nushell_tarball [ tarball_path: string version: string ] { log_info "Extracting tarball..." let tmp_extract_dir = "./tmp/nushell-extract" ensure_dir $tmp_extract_dir # Extract to temp directory let extract_result = try { ^tar -xzf $tarball_path -C $tmp_extract_dir {success: true} } catch { |err| {success: false, error: $err} } if not $extract_result.success { log_error "Failed to extract tarball" exit 1 } # GitHub creates a directory like "nushell-0.108.0" let extracted_dir = $"($tmp_extract_dir)/nushell-($version)" if not ($extracted_dir | path exists) { log_error $"Expected directory not found: ($extracted_dir)" log_info "Checking available directories..." ls $tmp_extract_dir | each {|it| log_info $" Found: ($it.name)"} exit 1 } # Move to final location let target_dir = "./nushell" if ($target_dir | path exists) { log_warn "Target directory already exists, removing..." rm -rf $target_dir } mv $extracted_dir $target_dir log_success $"Extracted to: ($target_dir)" # Cleanup rm -rf $tmp_extract_dir rm $tarball_path log_info "Cleaned up temporary files" } # Verify nushell source was extracted correctly def verify_nushell_source [ version: string ] { log_info "Verifying nushell source..." let nushell_dir = "./nushell" let cargo_toml = $"($nushell_dir)/Cargo.toml" # Check main Cargo.toml exists if not ($cargo_toml | path exists) { log_error $"Cargo.toml not found at ($cargo_toml)" exit 1 } # Verify version in Cargo.toml let cargo_version = try { open $cargo_toml | get package.version } catch { log_error "Could not read version from Cargo.toml" exit 1 } if $cargo_version != $version { log_warn $"Version mismatch: Cargo.toml shows ($cargo_version], expected ($version)" log_info "This might be normal if the version doesn't exactly match the tag" } else { log_success $"Version verified: ($cargo_version)" } # Check workspace structure let workspace_members = try { open $cargo_toml | get workspace.members } catch { log_error "Could not read workspace members from Cargo.toml" exit 1 } let member_count = $workspace_members | length log_success $"Found ($member_count) workspace members" # Check for system plugins let system_plugins = $workspace_members | where {|it| $it | str starts-with "crates/nu_plugin_"} let plugin_count = $system_plugins | length log_info $"System plugins: ($plugin_count)" # List system plugins if $plugin_count > 0 { log_info "System plugins found:" $system_plugins | each {|plugin| let plugin_name = $plugin | str replace "crates/" "" log_info $" • ($plugin_name)" } } } # Show current nushell source info def "main info" [] { let nushell_dir = "./nushell" if not ($nushell_dir | path exists) { log_error "Nushell source not found" log_info "Run: download_nushell.nu " exit 1 } let cargo_toml = $"($nushell_dir)/Cargo.toml" let version = open $cargo_toml | get package.version log_info "Nushell Source Information" log_info $" Version: ($version)" log_info $" Location: ($nushell_dir)" let workspace_members = open $cargo_toml | get workspace.members let member_count = $workspace_members | length log_info $" Workspace members: ($member_count)" let system_plugins = $workspace_members | where {|it| $it | str starts-with "crates/nu_plugin_"} log_info $" System plugins: ($system_plugins | length)" } # Clean up downloaded files def "main clean" [] { clean_nushell_directory let tmp_dir = "./tmp" if ($tmp_dir | path exists) { rm -rf $tmp_dir log_success "Removed tmp directory" } }