
## Summary Comprehensive repository cleanup focusing on plugin dependency management, documentation improvements, and git tracking optimization. ## Key Changes ### 🔧 Core Infrastructure - Synchronized all nu-* dependencies across plugins for version consistency - Enhanced upstream tracking and automation systems - Removed nushell directory from git tracking for cleaner repository management ### 📚 Documentation - Significantly expanded README.md with comprehensive development guides - Added detailed workflow documentation and command references - Improved plugin collection overview and usage examples ### 🧹 Repository Cleanup - Removed legacy bash scripts (build-all.sh, collect-install.sh, make_plugin.sh) - Streamlined automation through unified justfile and nushell script approach - Updated .gitignore with nushell directory and archive patterns - Removed nushell directory from git tracking to prevent unwanted changes ### 🔌 Plugin Updates - **nu_plugin_image**: Major refactoring with modular architecture improvements - **nu_plugin_hashes**: Enhanced functionality and build system improvements - **nu_plugin_highlight**: Updated for new plugin API compatibility - **nu_plugin_clipboard**: Dependency synchronization - **nu_plugin_desktop_notifications**: Version alignment - **nu_plugin_port_extension & nu_plugin_qr_maker**: Consistency updates - **nu_plugin_kcl & nu_plugin_tera**: Submodule synchronization ### 🏗️ Git Tracking Optimization - Removed nushell directory from version control for cleaner repository management - Added comprehensive .gitignore patterns for build artifacts and archives ## Statistics - 2,082 files changed - 2,373 insertions, 339,936 deletions - Net reduction of 337,563 lines (primarily from removing nushell directory tracking) ## Benefits - Complete version consistency across all plugins - Cleaner repository with optimized git tracking - Improved developer experience with streamlined workflows - Enhanced documentation and automation - Reduced repository size and complexity 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
550 lines
19 KiB
Plaintext
Executable File
550 lines
19 KiB
Plaintext
Executable File
#!/usr/bin/env nu
|
|
|
|
# Nu Version Manager - Nushell implementation
|
|
# Usage: nu update_nu_versions.nu [list|ls|update|help]
|
|
|
|
# Function to get version from nushell Cargo.toml files
|
|
def get_nushell_version [cargo_file: path] {
|
|
if ($cargo_file | path exists) {
|
|
try {
|
|
open --raw $cargo_file | lines | where $it =~ '^version = ' | first | parse 'version = "{version}"' | get version.0
|
|
} catch { null }
|
|
} else {
|
|
null
|
|
}
|
|
}
|
|
|
|
# Function to find version for a nu-* dependency in nushell crates
|
|
def get_target_version_for_dependency [dep_name: string, nushell_dir: string] {
|
|
let target_path = ($nushell_dir | path join $"crates/($dep_name)/Cargo.toml")
|
|
if ($target_path | path exists) {
|
|
get_nushell_version $target_path
|
|
} else {
|
|
null
|
|
}
|
|
}
|
|
|
|
# Function to extract the correct dependency name from a path
|
|
def get_correct_dep_name_from_path [line: string] {
|
|
try {
|
|
let path_match = ($line | parse --regex 'path = "([^"]*)"' | get capture0.0)
|
|
# Extract the crate name from the path (last component after /crates/)
|
|
$path_match | str replace --regex '.*/crates/' '' | str replace --regex '/.*' ''
|
|
} catch {
|
|
null
|
|
}
|
|
}
|
|
|
|
# Function to fix dependency name conflicts
|
|
def fix_dependency_name_conflicts [content: list<string>] {
|
|
mut updated_content = $content
|
|
mut changes = []
|
|
|
|
# Find lines with nu-* dependencies that have paths
|
|
let conflicts = (
|
|
$content
|
|
| enumerate
|
|
| where ($it.item | str contains "nu-") and ($it.item | str contains "path =")
|
|
| each { |line|
|
|
let declared_name = try {
|
|
$line.item | parse --regex '^[[:space:]]*(nu-[a-zA-Z0-9_-]+)[[:space:]]*=' | get capture0.0
|
|
} catch { null }
|
|
|
|
let correct_name = get_correct_dep_name_from_path $line.item
|
|
|
|
if ($declared_name | is-not-empty) and ($correct_name | is-not-empty) and $declared_name != $correct_name {
|
|
{
|
|
index: $line.index,
|
|
declared_name: $declared_name,
|
|
correct_name: $correct_name,
|
|
line: $line.item
|
|
}
|
|
} else {
|
|
null
|
|
}
|
|
}
|
|
| where $it != null
|
|
)
|
|
|
|
for $conflict in $conflicts {
|
|
let new_line = ($conflict.line | str replace $conflict.declared_name $conflict.correct_name)
|
|
$updated_content = ($updated_content | update $conflict.index $new_line)
|
|
$changes = ($changes | append $"⚠ Fixed dependency name conflict: ($conflict.declared_name) -> ($conflict.correct_name)")
|
|
}
|
|
|
|
{ content: $updated_content, changes: $changes }
|
|
}
|
|
|
|
# Auto-detect versions from nushell source
|
|
let NUSHELL_DIR = if ("nushell" | path exists) {
|
|
if ("nushell" | path type) == "symlink" {
|
|
# Follow symlink to get actual directory
|
|
"nushell" | path expand
|
|
} else {
|
|
"nushell"
|
|
}
|
|
} else {
|
|
error make { msg: "Nushell directory not found" }
|
|
}
|
|
|
|
# Get target versions from nushell source
|
|
let NU_PLUGIN_VERSION = get_nushell_version ($NUSHELL_DIR | path join "crates/nu-plugin/Cargo.toml")
|
|
let NU_PROTOCOL_VERSION = get_nushell_version ($NUSHELL_DIR | path join "crates/nu-protocol/Cargo.toml")
|
|
let NU_PLUGIN_TEST_VERSION = get_nushell_version ($NUSHELL_DIR | path join "crates/nu-plugin-test-support/Cargo.toml")
|
|
|
|
# Use nu-plugin version as the primary version (they should all be the same)
|
|
let NEW_VERSION = $NU_PLUGIN_VERSION
|
|
|
|
if ($NEW_VERSION | is-empty) {
|
|
error make { msg: "Could not determine target version from nushell source. Make sure the nushell directory exists and contains the expected Cargo.toml files" }
|
|
}
|
|
|
|
# Function to get all unique versions currently used in plugin Cargo.toml files for nu-* dependencies
|
|
def get_current_versions [] {
|
|
let plugin_dirs = get_plugin_dirs
|
|
|
|
$plugin_dirs
|
|
| each { |dir|
|
|
let cargo_file = ($dir | path join "Cargo.toml")
|
|
if ($cargo_file | path exists) {
|
|
try {
|
|
open --raw $cargo_file
|
|
| lines
|
|
| where $it =~ 'nu-[a-zA-Z0-9_-]+.*version = '
|
|
| each { |line|
|
|
try {
|
|
$line | parse --regex 'version = "([^"]*)"' | get capture0.0
|
|
} catch { null }
|
|
}
|
|
| where $it != null
|
|
} catch { [] }
|
|
} else { [] }
|
|
}
|
|
| flatten
|
|
| uniq
|
|
| where $it != $NEW_VERSION
|
|
}
|
|
|
|
# Function to show usage information
|
|
def show_usage [] {
|
|
print $"(ansi blue)Nu Version Manager(ansi reset)"
|
|
print ""
|
|
print "Usage: nu update_nu_versions.nu [command]"
|
|
print ""
|
|
print "Commands:"
|
|
print $" (ansi green)list, ls(ansi reset) Show current versions in all Cargo.toml files"
|
|
print $" (ansi green)update(ansi reset) Update versions to match nushell source ((ansi green)($NEW_VERSION)(ansi reset))"
|
|
print $" (ansi green)help, -h(ansi reset) Show this help message"
|
|
print ""
|
|
print "If no command is specified, 'update' is assumed."
|
|
print ""
|
|
}
|
|
|
|
# Function to extract version from a line
|
|
def extract_version [line: string] {
|
|
let version_match = ($line | parse --regex 'version = "([^"]*)"')
|
|
if ($version_match | length) > 0 {
|
|
$version_match.0.capture0
|
|
} else {
|
|
null
|
|
}
|
|
}
|
|
|
|
# Function to check if line has path dependency
|
|
def has_path_dependency [line: string] {
|
|
$line | str contains "path ="
|
|
}
|
|
|
|
# Function to get plugin directories
|
|
def get_plugin_dirs [] {
|
|
glob "nu_plugin_*" | where ($it | path type) == "dir" | sort
|
|
}
|
|
|
|
# Function to parse cargo.toml for version information
|
|
def parse_cargo_toml [cargo_file: path] {
|
|
if not ($cargo_file | path exists) {
|
|
return {
|
|
package_version: null
|
|
nu_plugin: null
|
|
nu_protocol: null
|
|
nu_json: null
|
|
nu_plugin_test_support: null
|
|
error: "Cargo.toml not found"
|
|
}
|
|
}
|
|
|
|
let content = open --raw $cargo_file | lines
|
|
|
|
# Get package version
|
|
let package_version = try {
|
|
$content
|
|
| where $it =~ '^version = '
|
|
| first
|
|
| extract_version $in
|
|
} catch { null }
|
|
|
|
# Get nu-plugin version
|
|
let nu_plugin_line = try {
|
|
$content
|
|
| where ($it =~ 'nu-plugin' and not ($it =~ 'nu-plugin-test-support'))
|
|
| first
|
|
} catch { null }
|
|
|
|
let nu_plugin_info = if $nu_plugin_line != null {
|
|
let version = extract_version $nu_plugin_line
|
|
let has_path = has_path_dependency $nu_plugin_line
|
|
{
|
|
version: $version
|
|
has_path: $has_path
|
|
status: (if $version != null {
|
|
if $has_path { "version_with_path" } else { "version_only" }
|
|
} else {
|
|
if $has_path { "path_only" } else { "not_found" }
|
|
})
|
|
}
|
|
} else {
|
|
{ version: null, has_path: false, status: "not_found" }
|
|
}
|
|
|
|
# Get nu-protocol version
|
|
let nu_protocol_line = try {
|
|
$content
|
|
| where $it =~ 'nu-protocol'
|
|
| first
|
|
} catch { null }
|
|
|
|
let nu_protocol_info = if $nu_protocol_line != null {
|
|
let version = extract_version $nu_protocol_line
|
|
let has_path = has_path_dependency $nu_protocol_line
|
|
{
|
|
version: $version
|
|
has_path: $has_path
|
|
status: (if $version != null {
|
|
if $has_path { "version_with_path" } else { "version_only" }
|
|
} else {
|
|
if $has_path { "path_only" } else { "not_found" }
|
|
})
|
|
}
|
|
} else {
|
|
{ version: null, has_path: false, status: "not_found" }
|
|
}
|
|
|
|
# Get nu-json version
|
|
let nu_json_line = try {
|
|
$content
|
|
| where $it =~ 'nu-json'
|
|
| first
|
|
} catch { null }
|
|
|
|
let nu_json_info = if $nu_json_line != null {
|
|
let version = extract_version $nu_json_line
|
|
let has_path = has_path_dependency $nu_json_line
|
|
{
|
|
version: $version
|
|
has_path: $has_path
|
|
status: (if $version != null {
|
|
if $has_path { "version_with_path" } else { "version_only" }
|
|
} else {
|
|
if $has_path { "path_only" } else { "not_found" }
|
|
})
|
|
}
|
|
} else {
|
|
{ version: null, has_path: false, status: "not_found" }
|
|
}
|
|
|
|
# Get nu-plugin-test-support version
|
|
let nu_test_line = try {
|
|
$content
|
|
| where $it =~ 'nu-plugin-test-support'
|
|
| first
|
|
} catch { null }
|
|
|
|
let nu_test_info = if $nu_test_line != null {
|
|
let version = extract_version $nu_test_line
|
|
let has_path = has_path_dependency $nu_test_line
|
|
{
|
|
version: $version
|
|
has_path: $has_path
|
|
status: (if $version != null {
|
|
if $has_path { "version_with_path" } else { "version_only" }
|
|
} else {
|
|
if $has_path { "path_only" } else { "not_found" }
|
|
})
|
|
}
|
|
} else {
|
|
{ version: null, has_path: false, status: "not_found" }
|
|
}
|
|
|
|
{
|
|
package_version: $package_version
|
|
nu_plugin: $nu_plugin_info
|
|
nu_protocol: $nu_protocol_info
|
|
nu_json: $nu_json_info
|
|
nu_plugin_test_support: $nu_test_info
|
|
error: null
|
|
}
|
|
}
|
|
|
|
# Function to format dependency info for display
|
|
def format_dependency [dep_info: record] {
|
|
match $dep_info.status {
|
|
"version_with_path" => ($dep_info.version + " " + (ansi yellow) + "(path)" + (ansi reset))
|
|
"version_only" => $dep_info.version
|
|
"path_only" => ((ansi yellow) + "path dependency only" + (ansi reset))
|
|
"not_found" => ((ansi red) + "not found" + (ansi reset))
|
|
}
|
|
}
|
|
|
|
# Function to list current versions
|
|
def list_versions [] {
|
|
print $"(ansi blue)Nu Version Listing(ansi reset)"
|
|
print "Current versions in all nu_plugin_* directories:"
|
|
print ""
|
|
|
|
let plugin_dirs = get_plugin_dirs
|
|
|
|
if ($plugin_dirs | length) == 0 {
|
|
print $"(ansi yellow)No nu_plugin_* directories found(ansi reset)"
|
|
return
|
|
}
|
|
|
|
for $dir in $plugin_dirs {
|
|
let plugin_name = ($dir | path basename)
|
|
let cargo_file = ($dir | path join "Cargo.toml")
|
|
|
|
print $"(ansi cyan) ($plugin_name)(ansi reset):"
|
|
|
|
let cargo_info = parse_cargo_toml $cargo_file
|
|
|
|
if $cargo_info.error != null {
|
|
print $" (ansi red)Error: ($cargo_info.error)(ansi reset)"
|
|
print ""
|
|
continue
|
|
}
|
|
|
|
# Package version
|
|
let pkg_version = if $cargo_info.package_version != null {
|
|
$cargo_info.package_version
|
|
} else {
|
|
$"(ansi yellow)not specified(ansi reset)"
|
|
}
|
|
print $" (ansi purple)Package(ansi reset): ($pkg_version)"
|
|
|
|
# nu-plugin
|
|
print $" (ansi purple)nu-plugin(ansi reset): (format_dependency $cargo_info.nu_plugin)"
|
|
|
|
# nu-protocol
|
|
print $" (ansi purple)nu-protocol(ansi reset): (format_dependency $cargo_info.nu_protocol)"
|
|
|
|
# nu-json (only if found)
|
|
if $cargo_info.nu_json.status != "not_found" {
|
|
print $" (ansi purple)nu-json(ansi reset): (format_dependency $cargo_info.nu_json)"
|
|
}
|
|
|
|
# nu-plugin-test-support (only if found)
|
|
if $cargo_info.nu_plugin_test_support.status != "not_found" {
|
|
print $" (ansi purple)nu-plugin-test-support(ansi reset): (format_dependency $cargo_info.nu_plugin_test_support)"
|
|
}
|
|
|
|
print ""
|
|
}
|
|
}
|
|
|
|
# Function to update a line with version replacement
|
|
def update_version_line [line: string, old_version: string, new_version: string] {
|
|
$line | str replace $'version = "($old_version)"' $'version = "($new_version)"'
|
|
}
|
|
|
|
# Function to update a single cargo.toml file
|
|
def update_cargo_toml [cargo_file: path, nushell_dir: string] {
|
|
if not ($cargo_file | path exists) {
|
|
return { success: false, message: "Cargo.toml not found", changes: [] }
|
|
}
|
|
|
|
let content = open --raw $cargo_file | lines
|
|
let backup_file = $"($cargo_file).backup"
|
|
|
|
# Create backup
|
|
$content | str join (char newline) | save -f --raw $backup_file
|
|
|
|
# First, fix any dependency name conflicts
|
|
let conflict_fix = fix_dependency_name_conflicts $content
|
|
mut updated_content = $conflict_fix.content
|
|
mut changes = $conflict_fix.changes
|
|
|
|
# Find all nu-* dependencies in the file (use updated content after conflict fixes)
|
|
let nu_dependencies = (
|
|
$updated_content
|
|
| enumerate
|
|
| where $it.item =~ '^[[:space:]]*nu-[a-zA-Z0-9_-]+[[:space:]]*='
|
|
| each { |line|
|
|
let dep_name = ($line.item | parse --regex '^[[:space:]]*(nu-[a-zA-Z0-9_-]+)[[:space:]]*=' | get capture0.0)
|
|
{ index: $line.index, dep_name: $dep_name, line: $line.item }
|
|
}
|
|
| group-by dep_name
|
|
| transpose dep_name lines
|
|
| each { |group| { dep_name: $group.dep_name, lines: $group.lines } }
|
|
)
|
|
|
|
for $dep_group in $nu_dependencies {
|
|
let dep_name = $dep_group.dep_name
|
|
let target_version = get_target_version_for_dependency $dep_name $nushell_dir
|
|
|
|
if ($target_version | is-empty) {
|
|
$changes = ($changes | append $"⚠ ($dep_name): No corresponding crate found in nushell source - skipping")
|
|
continue
|
|
}
|
|
|
|
# Process each line for this dependency
|
|
for $line_info in $dep_group.lines {
|
|
let current_line = $line_info.line
|
|
let line_index = $line_info.index
|
|
|
|
# Check if it already has a path dependency
|
|
if ($current_line | str contains "path =") {
|
|
# Update version but keep path
|
|
if ($current_line | str contains "version =") {
|
|
let old_version = try {
|
|
$current_line | parse --regex 'version = "([^"]*)"' | get capture0.0
|
|
} catch { null }
|
|
|
|
if ($old_version | is-not-empty) and $old_version != $target_version {
|
|
let new_line = ($current_line | str replace $'version = "($old_version)"' $'version = "($target_version)"')
|
|
$updated_content = ($updated_content | update $line_index $new_line)
|
|
$changes = ($changes | append $"✓ Updated ($dep_name) version from ($old_version) to ($target_version) path preserved")
|
|
} else if ($old_version | is-not-empty) and $old_version == $target_version {
|
|
$changes = ($changes | append $"→ ($dep_name): Already at target version ($target_version) with path")
|
|
}
|
|
} else {
|
|
# Add version to existing path dependency
|
|
let new_line = ($current_line | str replace "{" $'{ version = "($target_version)",')
|
|
$updated_content = ($updated_content | update $line_index $new_line)
|
|
$changes = ($changes | append $"✓ Added version ($target_version) to ($dep_name) path dependency")
|
|
}
|
|
} else {
|
|
# No path dependency - add both version and path
|
|
let current_version = try {
|
|
$current_line | parse --regex 'version = "([^"]*)"' | get capture0.0
|
|
} catch { null }
|
|
|
|
if ($current_version | is-not-empty) {
|
|
# Replace version-only dependency with version + path
|
|
let relative_path = $"../nushell/crates/($dep_name)"
|
|
let new_line = ($current_line | str replace $'version = "($current_version)"' $'version = "($target_version)", path = "($relative_path)"')
|
|
$updated_content = ($updated_content | update $line_index $new_line)
|
|
$changes = ($changes | append $"✓ Updated ($dep_name) from ($current_version) to ($target_version) and added path dependency")
|
|
} else {
|
|
$changes = ($changes | append $"⚠ ($dep_name): Could not parse current version - skipping")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Save updated content if changes were made
|
|
let actual_changes = ($changes | where not ($it | str starts-with "→") and not ($it | str starts-with "⚠"))
|
|
if ($actual_changes | length) > 0 {
|
|
$updated_content | str join (char newline) | save -f --raw $cargo_file
|
|
{
|
|
success: true
|
|
message: $"Backup created: ($backup_file)"
|
|
changes: $changes
|
|
}
|
|
} else {
|
|
# Remove backup if no changes
|
|
rm $backup_file
|
|
{
|
|
success: true
|
|
message: "No version updates needed"
|
|
changes: $changes
|
|
}
|
|
}
|
|
}
|
|
|
|
# Function to run the update process
|
|
def run_update [] {
|
|
print $"(ansi blue)Nu Version Updater(ansi reset)"
|
|
print $"Target version from nushell source: (ansi green)($NEW_VERSION)(ansi reset)"
|
|
|
|
# Show detected current versions
|
|
let current_versions = get_current_versions
|
|
if ($current_versions | length) > 0 {
|
|
print $"Current versions found in plugins: (ansi red)($current_versions | str join ', ')(ansi reset)"
|
|
} else {
|
|
print $"(ansi yellow)All plugins are already at target version(ansi reset)"
|
|
}
|
|
print ""
|
|
|
|
let plugin_dirs = get_plugin_dirs
|
|
|
|
if ($plugin_dirs | length) == 0 {
|
|
print $"(ansi yellow)No nu_plugin_* directories found(ansi reset)"
|
|
return
|
|
}
|
|
|
|
print $"(ansi blue)Found plugin directories:(ansi reset)"
|
|
for $dir in $plugin_dirs {
|
|
print $" - ($dir)"
|
|
}
|
|
print ""
|
|
|
|
# Process each plugin directory
|
|
for $dir in $plugin_dirs {
|
|
print $"(ansi blue)Processing ($dir)...(ansi reset)"
|
|
|
|
let cargo_file = ($dir | path join "Cargo.toml")
|
|
let result = update_cargo_toml $cargo_file $NUSHELL_DIR
|
|
|
|
for $change in $result.changes {
|
|
print $" (ansi green)✓(ansi reset) ($change)"
|
|
}
|
|
|
|
if ($result.changes | length) > 0 {
|
|
print $" (ansi blue)($result.message)(ansi reset)"
|
|
} else {
|
|
print $" (ansi yellow)($result.message)(ansi reset)"
|
|
}
|
|
|
|
print ""
|
|
}
|
|
|
|
print $"(ansi green)Version update process completed!(ansi reset)"
|
|
print ""
|
|
print ((ansi yellow) + "Note:" + (ansi reset) + " Backup files (.backup) have been created for modified files.")
|
|
print ("You can restore them with: " + (ansi blue) + "mv file.backup file" + (ansi reset))
|
|
print ""
|
|
print $"(ansi yellow)Don't forget to:(ansi reset)"
|
|
print "1. Test the plugins after the update"
|
|
print "2. Update any documentation if needed"
|
|
print "3. Commit the changes to version control"
|
|
}
|
|
|
|
# Main function
|
|
def main [command?: string] {
|
|
# Ensure we're in the right directory (assume script is in the plugin directory)
|
|
# cd (pwd)
|
|
|
|
let cmd = $command | default "update"
|
|
|
|
match $cmd {
|
|
"list" | "ls" => { list_versions }
|
|
"update" => { run_update }
|
|
"help" | "-h" | "--help" => { show_usage }
|
|
_ => {
|
|
print $"(ansi red)Error: Unknown command '($cmd)'(ansi reset)"
|
|
print ""
|
|
show_usage
|
|
}
|
|
}
|
|
}
|
|
|
|
# Export functions for use
|
|
export def "nu-version list" [] { list_versions }
|
|
export def "nu-version ls" [] { list_versions }
|
|
export def "nu-version update" [] { run_update }
|
|
export def "nu-version help" [] { show_usage }
|
|
|
|
# Main entry point function
|
|
export def "nu-version" [command?: string] {
|
|
main ($command | default "help")
|
|
}
|