From 4d9d899739f7a876d2fd16109ea8f98df30b3029 Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Fri, 13 Jun 2025 13:47:00 -0500 Subject: [PATCH 01/32] init commit --- nupm/mod.nu | 1 + nupm/registry.nu | 181 +++++++++++++++++++++++++++++++++++++++++++++++ tests/mod.nu | 54 ++++++++++++++ 3 files changed, 236 insertions(+) create mode 100644 nupm/registry.nu diff --git a/nupm/mod.nu b/nupm/mod.nu index 423031c..f224a0b 100644 --- a/nupm/mod.nu +++ b/nupm/mod.nu @@ -7,6 +7,7 @@ use utils/dirs.nu [ export module install.nu export module publish.nu +export module registry.nu export module search.nu export module status.nu export module test.nu diff --git a/nupm/registry.nu b/nupm/registry.nu new file mode 100644 index 0000000..5aae779 --- /dev/null +++ b/nupm/registry.nu @@ -0,0 +1,181 @@ +# Registry management for nupm + +use utils/dirs.nu [nupm-home-prompt] +use utils/log.nu throw-error + +# Show information about configured registries +@example "List all configured registries" { nupm registry } +export def main []: nothing -> table { + list +} + +# List all configured registries +@example "List all registries with details" { nupm registry list } +export def list []: nothing -> table { + let registry_list_path = $env.NUPM_HOME | path join "registry_list.nuon" + + if not ($registry_list_path | path exists) { + init + } + + let registries = open $registry_list_path + + $registries | select name url enabled | sort-by name +} + +# Add a new registry +@example "Add a new registry" { nupm registry add my-registry https://example.com/registry.nuon } +@example "Add a disabled registry" { nupm registry add test-registry ./local-registry.nuon --enabled=false } +export def add [ + name: string, # Name of the registry + url: string, # URL or path to the registry + --enabled=true # Whether the registry should be enabled +]: nothing -> nothing { + let registry_list_path = $env.NUPM_HOME | path join "registry_list.nuon" + + if not ($registry_list_path | path exists) { + init + } + + mut registries = open $registry_list_path + + # Check if registry already exists + if ($registries | where name == $name | length) > 0 { + throw-error $"Registry '($name)' already exists. Use 'nupm registry update' to modify it." + } + + # Add new registry + $registries = ($registries | append { + name: $name, + url: $url, + enabled: $enabled + }) + + $registries | save --force $registry_list_path + + print $"Registry '($name)' added successfully." +} + +# Remove a registry +@example "Remove a registry" { nupm registry remove my-registry } +export def remove [ + name: string # Name of the registry to remove +]: nothing -> nothing { + let registry_list_path = $env.NUPM_HOME | path join "registry_list.nuon" + + if not ($registry_list_path | path exists) { + throw-error "No registry list found. Run 'nupm registry init' first." + } + + let registries = open $registry_list_path + + # Check if registry exists + if ($registries | where name == $name | length) == 0 { + throw-error $"Registry '($name)' not found." + } + + # Remove registry + let updated_registries = $registries | where name != $name + $updated_registries | save --force $registry_list_path + + print $"Registry '($name)' removed successfully." +} + +# Update registry URL or enable/disable status +@example "Update registry URL" { nupm registry update my-registry --url https://new-url.com/registry.nuon } +@example "Enable a registry" { nupm registry update my-registry --enable } +@example "Disable a registry" { nupm registry update my-registry --disable } +export def update [ + name: string, # Name of the registry to update + --url: string, # New URL for the registry + --enable, # Enable the registry + --disable # Disable the registry +]: nothing -> nothing { + let registry_list_path = $env.NUPM_HOME | path join "registry_list.nuon" + + if not ($registry_list_path | path exists) { + throw-error "No registry list found. Run 'nupm registry init' first." + } + + mut registries = open $registry_list_path + + # Check if registry exists + if ($registries | where name == $name | length) == 0 { + throw-error $"Registry '($name)' not found." + } + + # Update registry + $registries = ($registries | each {|reg| + if $reg.name == $name { + let updated_url = if ($url | is-empty) { $reg.url } else { $url } + let updated_enabled = if $enable { + true + } else if $disable { + false + } else { + $reg.enabled + } + + { + name: $reg.name, + url: $updated_url, + enabled: $updated_enabled + } + } else { + $reg + } + }) + + $registries | save --force $registry_list_path + + print $"Registry '($name)' updated successfully." +} + +# Initialize registry_list.nuon with default registries +@example "Initialize registry list" { nupm registry init } +export def init []: nothing -> nothing { + if not (nupm-home-prompt) { + throw-error "Cannot create NUPM_HOME directory." + } + + let registry_list_path = $env.NUPM_HOME | path join "registry_list.nuon" + + if ($registry_list_path | path exists) { + print $"Registry list already exists at ($registry_list_path)" + return + } + + # Initialize with the default nupm registry + let default_registries = [ + { + name: "nupm", + url: "https://raw.githubusercontent.com/nushell/nupm/main/registry/registry.nuon", + enabled: true + } + ] + + $default_registries | save $registry_list_path + + print $"Registry list initialized at ($registry_list_path)" +} + +# Show detailed information about a specific registry +@example "Show registry information" { nupm registry info nupm } +export def info [ + name: string # Name of the registry +]: nothing -> table { + let registry_list_path = $env.NUPM_HOME | path join "registry_list.nuon" + + if not ($registry_list_path | path exists) { + throw-error "No registry list found. Run 'nupm registry init' first." + } + + let registries = open $registry_list_path + let registry = $registries | where name == $name + + if ($registry | length) == 0 { + throw-error $"Registry '($name)' not found." + } + + $registry | first +} \ No newline at end of file diff --git a/tests/mod.nu b/tests/mod.nu index abee754..6340dc4 100644 --- a/tests/mod.nu +++ b/tests/mod.nu @@ -171,3 +171,57 @@ export def generate-local-registry [] { assert equal $actual $expected } } + +export def registry-list [] { + with-test-env { + # Initialize registry list + nupm registry init + + # Get list of registries + let registries = nupm registry list + + # Should have default nupm registry + assert equal ($registries | length) 1 + assert equal $registries.0.name "nupm" + assert equal $registries.0.url "https://raw.githubusercontent.com/nushell/nupm/main/registry/registry.nuon" + assert equal $registries.0.enabled true + } +} + +export def registry-add [] { + with-test-env { + # Initialize registry list + nupm registry init + + # Add a new registry + nupm registry add test-registry https://example.com/test.nuon --enabled=false + + # Verify registry was added + let registries = nupm registry list + assert equal ($registries | length) 2 + + let test_reg = $registries | where name == "test-registry" | first + assert equal $test_reg.name "test-registry" + assert equal $test_reg.url "https://example.com/test.nuon" + assert equal $test_reg.enabled false + + # Try to add duplicate registry (should fail) + let add_result = try { + nupm registry add test-registry https://duplicate.com/test.nuon + "should not reach here" + } catch {|err| + $err.msg + } + + assert ("Registry 'test-registry' already exists" in $add_result) + + # Add another registry with default enabled=true + nupm registry add another-registry ./local-registry.nuon + + let registries_final = nupm registry list + assert equal ($registries_final | length) 3 + + let another_reg = $registries_final | where name == "another-registry" | first + assert equal $another_reg.enabled true + } +} From 573100bc2eb0b8f5cfd88de3021b88984b608671 Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Fri, 13 Jun 2025 17:27:43 -0500 Subject: [PATCH 02/32] changed const --- nupm/utils/dirs.nu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nupm/utils/dirs.nu b/nupm/utils/dirs.nu index 5bcfae2..bbb147d 100644 --- a/nupm/utils/dirs.nu +++ b/nupm/utils/dirs.nu @@ -12,7 +12,7 @@ export const DEFAULT_NUPM_TEMP = ($nu.temp-path | path join "nupm") # Default registry export const DEFAULT_NUPM_REGISTRIES = { - nupm_test: 'https://raw.githubusercontent.com/nushell/nupm/main/registry/registry.nuon' + nupm: 'https://raw.githubusercontent.com/nushell/nupm/main/registry/registry.nuon' } # Prompt to create $env.NUPM_HOME if it does not exist and some sanity checks. From 5409a71804e337cea6eec458784ef116f761ca8c Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Fri, 13 Jun 2025 17:28:00 -0500 Subject: [PATCH 03/32] get_index impl --- nupm/registry.nu | 128 ++++++++++++++++++++++++++--------------------- 1 file changed, 70 insertions(+), 58 deletions(-) diff --git a/nupm/registry.nu b/nupm/registry.nu index 5aae779..adf38cd 100644 --- a/nupm/registry.nu +++ b/nupm/registry.nu @@ -1,4 +1,4 @@ -# Registry management for nupm +init-indexinit-indexinit-indexinit-indexinit-indexinit-index# Registry management for nupm use utils/dirs.nu [nupm-home-prompt] use utils/log.nu throw-error @@ -12,14 +12,14 @@ export def main []: nothing -> table { # List all configured registries @example "List all registries with details" { nupm registry list } export def list []: nothing -> table { - let registry_list_path = $env.NUPM_HOME | path join "registry_list.nuon" - - if not ($registry_list_path | path exists) { + let registry_idx_path = $env.NUPM_HOME | path join "registry_idx.nuon" + + if not ($registry_idx_path | path exists) { init } - - let registries = open $registry_list_path - + + let registries = open $registry_idx_path + $registries | select name url enabled | sort-by name } @@ -31,53 +31,62 @@ export def add [ url: string, # URL or path to the registry --enabled=true # Whether the registry should be enabled ]: nothing -> nothing { - let registry_list_path = $env.NUPM_HOME | path join "registry_list.nuon" - - if not ($registry_list_path | path exists) { + let registry_idx_path = $env.NUPM_HOME | path join "registry_idx.nuon" + + if not ($registry_idx_path | path exists) { init } - - mut registries = open $registry_list_path - + + mut registries = open $registry_idx_path + # Check if registry already exists if ($registries | where name == $name | length) > 0 { throw-error $"Registry '($name)' already exists. Use 'nupm registry update' to modify it." } - + # Add new registry $registries = ($registries | append { name: $name, url: $url, enabled: $enabled }) - - $registries | save --force $registry_list_path - + + $registries | save --force $registry_idx_path + print $"Registry '($name)' added successfully." } +# returns registry_idx path +def get_index [] { + # TODO + let idx_path = $env.NUPM_HOME | path join "registry_idx.nuon" + if not ($idx_path | path exists) { + throw-error "No registry list found. Run 'nupm registry init' first." + } +} + # Remove a registry @example "Remove a registry" { nupm registry remove my-registry } export def remove [ name: string # Name of the registry to remove ]: nothing -> nothing { - let registry_list_path = $env.NUPM_HOME | path join "registry_list.nuon" - - if not ($registry_list_path | path exists) { + let registry_idx_path = $env.NUPM_HOME | path join "registry_idx.nuon" + + if not ($registry_idx_path | path exists) { throw-error "No registry list found. Run 'nupm registry init' first." } - - let registries = open $registry_list_path - + + let registries = open $registry_idx_path + # Check if registry exists if ($registries | where name == $name | length) == 0 { throw-error $"Registry '($name)' not found." } - + # Remove registry let updated_registries = $registries | where name != $name - $updated_registries | save --force $registry_list_path - + $updated_registries | save --force $registry_idx_path + print $"Registry '($name)' removed successfully." } @@ -91,19 +100,19 @@ export def update [ --enable, # Enable the registry --disable # Disable the registry ]: nothing -> nothing { - let registry_list_path = $env.NUPM_HOME | path join "registry_list.nuon" - - if not ($registry_list_path | path exists) { + let registry_idx_path = $env.NUPM_HOME | path join "registry_idx.nuon" + + if not ($registry_idx_path | path exists) { throw-error "No registry list found. Run 'nupm registry init' first." } - - mut registries = open $registry_list_path - + + mut registries = open $registry_idx_path + # Check if registry exists if ($registries | where name == $name | length) == 0 { throw-error $"Registry '($name)' not found." } - + # Update registry $registries = ($registries | each {|reg| if $reg.name == $name { @@ -115,7 +124,7 @@ export def update [ } else { $reg.enabled } - + { name: $reg.name, url: $updated_url, @@ -125,26 +134,29 @@ export def update [ $reg } }) - - $registries | save --force $registry_list_path - + + $registries | save --force $registry_idx_path + print $"Registry '($name)' updated successfully." } -# Initialize registry_list.nuon with default registries -@example "Initialize registry list" { nupm registry init } -export def init []: nothing -> nothing { +# Initialize registry_idx.nuon with default registries +@example "Initialize registry list" { nupm registry init-index } +export def init-index [ + + registry?: record +]: nothing -> nothing { if not (nupm-home-prompt) { throw-error "Cannot create NUPM_HOME directory." } - - let registry_list_path = $env.NUPM_HOME | path join "registry_list.nuon" - - if ($registry_list_path | path exists) { - print $"Registry list already exists at ($registry_list_path)" + + let registry_idx_path = $env.NUPM_HOME | path join "registry_idx.nuon" + + if ($registry_idx_path | path exists) { + print $"Registry list already exists at ($registry_idx_path)" return } - + # Initialize with the default nupm registry let default_registries = [ { @@ -153,10 +165,10 @@ export def init []: nothing -> nothing { enabled: true } ] - - $default_registries | save $registry_list_path - - print $"Registry list initialized at ($registry_list_path)" + + $default_registries | save $registry_idx_path + + print $"Registry list initialized at ($registry_idx_path)" } # Show detailed information about a specific registry @@ -164,18 +176,18 @@ export def init []: nothing -> nothing { export def info [ name: string # Name of the registry ]: nothing -> table { - let registry_list_path = $env.NUPM_HOME | path join "registry_list.nuon" - - if not ($registry_list_path | path exists) { + let registry_idx_path = $env.NUPM_HOME | path join "registry_idx.nuon" + + if not ($registry_idx_path | path exists) { throw-error "No registry list found. Run 'nupm registry init' first." } - - let registries = open $registry_list_path + + let registries = open $registry_idx_path let registry = $registries | where name == $name - + if ($registry | length) == 0 { throw-error $"Registry '($name)' not found." } - + $registry | first -} \ No newline at end of file +} From 3bcf1e976737ed6032d4b6165e5b228f2aa2ccf5 Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Fri, 13 Jun 2025 17:29:44 -0500 Subject: [PATCH 04/32] removed TODOs for callout of registry subcommand --- nupm/mod.nu | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/nupm/mod.nu b/nupm/mod.nu index f224a0b..a87c473 100644 --- a/nupm/mod.nu +++ b/nupm/mod.nu @@ -23,13 +23,9 @@ export-env { # Ensure install cache is set $env.NUPM_CACHE = ($env.NUPM_CACHE? | default $DEFAULT_NUPM_CACHE) - # TODO: Maybe this is not the best way to set registries, but should be - # good enough for now. - # TODO: Add `nupm registry` for showing info about registries - # TODO: Add `nupm registry add/remove` to add/remove registry from the env? $env.NUPM_REGISTRIES = ($env.NUPM_REGISTRIES? | default $DEFAULT_NUPM_REGISTRIES) - + use std/log [] } From 26c3444f89b98213af942250d6ee2dac7b516c19 Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Tue, 24 Jun 2025 16:42:20 -0500 Subject: [PATCH 05/32] made nupm config declarative --- nupm/mod.nu | 43 +++++++++------ nupm/registry.nu | 128 ++++++++++++++------------------------------- nupm/utils/dirs.nu | 45 ++++++---------- 3 files changed, 82 insertions(+), 134 deletions(-) diff --git a/nupm/mod.nu b/nupm/mod.nu index a87c473..647c751 100644 --- a/nupm/mod.nu +++ b/nupm/mod.nu @@ -1,9 +1,6 @@ use std/log -use utils/dirs.nu [ - DEFAULT_NUPM_HOME DEFAULT_NUPM_TEMP DEFAULT_NUPM_CACHE - DEFAULT_NUPM_REGISTRIES nupm-home-prompt -] +use utils/dirs.nu [ nupm-home-prompt ] export module install.nu export module publish.nu @@ -12,19 +9,33 @@ export module search.nu export module status.nu export module test.nu -export-env { - # Ensure that $env.NUPM_HOME is always set when running nupm. Any missing - # $env.NUPM_HOME during nupm execution is a bug. - $env.NUPM_HOME = ($env.NUPM_HOME? | default $DEFAULT_NUPM_HOME) - - # Ensure temporary path is set. - $env.NUPM_TEMP = ($env.NUPM_TEMP? | default $DEFAULT_NUPM_TEMP) - - # Ensure install cache is set - $env.NUPM_CACHE = ($env.NUPM_CACHE? | default $DEFAULT_NUPM_CACHE) +# Base values for nupm that are used as defaults if not present in `$env.nupm` +export const BASE_NUPM_CONFIG = { + default-home: ($nu.default-config-dir | path join "nupm") + default-cache: ($nu.default-config-dir | path join nupm cache) + default-temp: ($nu.temp-path | path join "nupm") + default-registry: { + nupm: 'https://raw.githubusercontent.com/nushell/nupm/main/registry/registry.nuon' + } +} - $env.NUPM_REGISTRIES = ($env.NUPM_REGISTRIES? - | default $DEFAULT_NUPM_REGISTRIES) +export-env { + # Ensure that $env.nupm is always set when running nupm. Any missing variaables + $env.nupm = { + home: ($env.nupm.home? | default $BASE_NUPM_CONFIG.default-home) + cache: ($env.nupm.cache? | default $BASE_NUPM_CONFIG.default-cache) + temp: ($env.nupm.temp? | default $BASE_NUPM_CONFIG.default-temp) + registries: ($env.nupm.registires? | default $BASE_NUPM_CONFIG.default-registry) + } | merge $BASE_NUPM_CONFIG + # Should this filename be hardcoded for simplicity? + $env.nupm.index-path = ($env.nupm.home | path join "registry_index.nuon") + if ($env.nupm.index-path | path exists) { + if not (($env.nupm.index-path | path type) == "file") { + throw-error $"($env.nupm.index-path) is not a filepath" + } + # overwrite filevalues with those found in config + $env.nupm.registries = open $env.nupm.index-path | merge $env.nupm.registries + } use std/log [] } diff --git a/nupm/registry.nu b/nupm/registry.nu index adf38cd..e0fbfdf 100644 --- a/nupm/registry.nu +++ b/nupm/registry.nu @@ -1,4 +1,4 @@ -init-indexinit-indexinit-indexinit-indexinit-indexinit-index# Registry management for nupm +# Registry management for nupm use utils/dirs.nu [nupm-home-prompt] use utils/log.nu throw-error @@ -26,120 +26,72 @@ export def list []: nothing -> table { # Add a new registry @example "Add a new registry" { nupm registry add my-registry https://example.com/registry.nuon } @example "Add a disabled registry" { nupm registry add test-registry ./local-registry.nuon --enabled=false } -export def add [ +export def --env add [ name: string, # Name of the registry url: string, # URL or path to the registry - --enabled=true # Whether the registry should be enabled -]: nothing -> nothing { - let registry_idx_path = $env.NUPM_HOME | path join "registry_idx.nuon" - - if not ($registry_idx_path | path exists) { - init - } - - mut registries = open $registry_idx_path - - # Check if registry already exists - if ($registries | where name == $name | length) > 0 { + --save, # Whether to commit the change to the registry index +] { + if ($name in $env.nupm.registries) { throw-error $"Registry '($name)' already exists. Use 'nupm registry update' to modify it." } + $env.nupm.registries = $env.nupm.registries | insert $name $url - # Add new registry - $registries = ($registries | append { - name: $name, - url: $url, - enabled: $enabled - }) - - $registries | save --force $registry_idx_path + if ($save) { + $env.nupm.registries | save --force $env.nupm.index-path + } print $"Registry '($name)' added successfully." } -# returns registry_idx path -def get_index [] { - # TODO - let idx_path = $env.NUPM_HOME | path join "registry_idx.nuon" - if not ($idx_path | path exists) { - throw-error "No registry list found. Run 'nupm registry init' first." - } -} - # Remove a registry @example "Remove a registry" { nupm registry remove my-registry } -export def remove [ +export def --env remove [ name: string # Name of the registry to remove -]: nothing -> nothing { - let registry_idx_path = $env.NUPM_HOME | path join "registry_idx.nuon" + --save, # Whether to commit the change to the registry index +] { + $env.nupm.registires = $env.nupm.registires | reject $name - if not ($registry_idx_path | path exists) { - throw-error "No registry list found. Run 'nupm registry init' first." + if ($save) { + $env.nupm.registries | save --force $env.nupm.index-path } - let registries = open $registry_idx_path - - # Check if registry exists - if ($registries | where name == $name | length) == 0 { - throw-error $"Registry '($name)' not found." - } - - # Remove registry - let updated_registries = $registries | where name != $name - $updated_registries | save --force $registry_idx_path - print $"Registry '($name)' removed successfully." } -# Update registry URL or enable/disable status -@example "Update registry URL" { nupm registry update my-registry --url https://new-url.com/registry.nuon } -@example "Enable a registry" { nupm registry update my-registry --enable } -@example "Disable a registry" { nupm registry update my-registry --disable } -export def update [ - name: string, # Name of the registry to update - --url: string, # New URL for the registry - --enable, # Enable the registry - --disable # Disable the registry +# Update a given registry url +@example "Update registry URL" { nupm registry set-url my-registry https://new-url.com/registry.nuon } +@example "Rename a registry" { nupm registry update my-registry --set-name our-registry } +export def --env set-url [ + name: string, # Name of the registry to update + url: string, + --save, # Whether to commit the change to the registry index ]: nothing -> nothing { - let registry_idx_path = $env.NUPM_HOME | path join "registry_idx.nuon" + $env.nupm.registires = $env.nupm.registires | update $name $url - if not ($registry_idx_path | path exists) { - throw-error "No registry list found. Run 'nupm registry init' first." + if ($save) { + $env.nupm.registries | save --force $env.nupm.index-path } - mut registries = open $registry_idx_path - - # Check if registry exists - if ($registries | where name == $name | length) == 0 { - throw-error $"Registry '($name)' not found." - } + print $"Registry '($name)' URL updated successfully." +} - # Update registry - $registries = ($registries | each {|reg| - if $reg.name == $name { - let updated_url = if ($url | is-empty) { $reg.url } else { $url } - let updated_enabled = if $enable { - true - } else if $disable { - false - } else { - $reg.enabled - } - - { - name: $reg.name, - url: $updated_url, - enabled: $updated_enabled - } - } else { - $reg - } - }) +# Rename a registry +@example "Rename a registry" { nupm registry rename my-registry our-registry } +export def --env rename [ + name: string, # Name of the registry to update + new_name: string, + --save, # Whether to commit the change to the registry index +]: nothing -> nothing { + $env.nupm.registires = $env.nupm.registires | ^rename --column { $name: $new_name } - $registries | save --force $registry_idx_path + if ($save) { + $env.nupm.registries | save --force $env.nupm.index-path + } - print $"Registry '($name)' updated successfully." + print $"Registry '($name)' URL updated successfully." } + # Initialize registry_idx.nuon with default registries @example "Initialize registry list" { nupm registry init-index } export def init-index [ diff --git a/nupm/utils/dirs.nu b/nupm/utils/dirs.nu index bbb147d..41a1832 100644 --- a/nupm/utils/dirs.nu +++ b/nupm/utils/dirs.nu @@ -1,35 +1,20 @@ # Directories and related utilities used in nupm -# Default installation path for nupm packages -export const DEFAULT_NUPM_HOME = ($nu.default-config-dir | path join "nupm") - -# Default path for installation cache -export const DEFAULT_NUPM_CACHE = ($nu.default-config-dir - | path join nupm cache) - -# Default temporary path for various nupm purposes -export const DEFAULT_NUPM_TEMP = ($nu.temp-path | path join "nupm") - -# Default registry -export const DEFAULT_NUPM_REGISTRIES = { - nupm: 'https://raw.githubusercontent.com/nushell/nupm/main/registry/registry.nuon' -} - -# Prompt to create $env.NUPM_HOME if it does not exist and some sanity checks. +# Prompt to create $env.nupm.home if it does not exist and some sanity checks. # # returns true if the root directory exists or has been created, false otherwise export def nupm-home-prompt [--no-confirm]: nothing -> bool { - if 'NUPM_HOME' not-in $env { + if 'home' not-in $env.nupm { error make --unspanned { - msg: "Internal error: NUPM_HOME environment variable is not set" + msg: "Internal error: nupm.home environment variable is not set" } } - if ($env.NUPM_HOME | path exists) { - if ($env.NUPM_HOME | path type) != 'dir' { + if ($env.nupm.home | path exists) { + if ($env.nupm.home | path type) != 'dir' { error make --unspanned { - msg: ($"Root directory ($env.NUPM_HOME) exists, but is not a" - + " directory. Make sure $env.NUPM_HOME points at a valid" + msg: ($"Root directory ($env.nupm.home) exists, but is not a" + + " directory. Make sure $env.nupm.home points at a valid" + " directory and try again.") } } @@ -38,7 +23,7 @@ export def nupm-home-prompt [--no-confirm]: nothing -> bool { } if $no_confirm { - mkdir $env.NUPM_HOME + mkdir $env.nupm.home return true } @@ -46,21 +31,21 @@ export def nupm-home-prompt [--no-confirm]: nothing -> bool { while ($answer | str downcase) not-in [ y n ] { $answer = (input ( - $'Root directory "($env.NUPM_HOME)" does not exist.' + $'Root directory "($env.nupm.home)" does not exist.' + ' Do you want to create it? [y/n] ')) } - if ($answer | str downcase) != 'y' { + if ($answer | str downcase) not-in [ y Y ] { return false } - mkdir $env.NUPM_HOME + mkdir $env.nupm.home true } export def script-dir [--ensure]: nothing -> path { - let d = $env.NUPM_HOME | path join scripts + let d = $env.nupm.home | path join scripts if $ensure { mkdir $d @@ -70,7 +55,7 @@ export def script-dir [--ensure]: nothing -> path { } export def module-dir [--ensure]: nothing -> path { - let d = $env.NUPM_HOME | path join modules + let d = $env.nupm.home | path join modules if $ensure { mkdir $d @@ -80,7 +65,7 @@ export def module-dir [--ensure]: nothing -> path { } export def cache-dir [--ensure]: nothing -> path { - let d = $env.NUPM_CACHE + let d = $env.nupm.cache if $ensure { mkdir $d @@ -90,7 +75,7 @@ export def cache-dir [--ensure]: nothing -> path { } export def tmp-dir [subdir: string, --ensure]: nothing -> path { - let d = $env.NUPM_TEMP + let d = $env.nupm.cache | path join $subdir | path join (random chars -l 8) From fce3057d8c6ddb21c6e39e5385c4582fc83bae47 Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Tue, 24 Jun 2025 17:09:17 -0500 Subject: [PATCH 06/32] updated NUPM_ variables to match nested structure --- README.md | 10 ++--- docs/design/README.md | 18 ++++----- nupm/install.nu | 2 +- nupm/mod.nu | 15 ++++---- nupm/publish.nu | 2 +- nupm/registry.nu | 60 +++++++++++++---------------- nupm/search.nu | 2 +- nupm/utils/completions.nu | 2 +- nupm/utils/registry.nu | 10 ++--- tests/mod.nu | 20 +++++----- tests/packages/spam_custom/build.nu | 6 +-- toolkit.nu | 8 ++-- 12 files changed, 74 insertions(+), 81 deletions(-) diff --git a/README.md b/README.md index 761e5d3..5dd056b 100644 --- a/README.md +++ b/README.md @@ -32,27 +32,27 @@ Both of the above commands will make `nupm` and all its subcommands available in > ``` ## :gear: configuration [[toc](#table-of-content)] -One can change the location of the Nupm directory with `$env.NUPM_HOME`, e.g. +One can change the location of the Nupm directory with `$env.nupm.home`, e.g. ```nushell # env.nu -$env.NUPM_HOME = ($env.XDG_DATA_HOME | path join "nupm") +$env.nupm.home = ($env.XDG_DATA_HOME | path join "nupm") ``` -Because Nupm will install modules and scripts in `{{nupm-home}}/modules/` and `{{nupm-home}}/scripts/` respectively, it is a good idea to add these paths to `$env.NU_LIB_DIRS` and `$env.PATH` respectively, e.g. if you have `$env.NUPM_HOME` defined: +Because Nupm will install modules and scripts in `{{nupm-home}}/modules/` and `{{nupm-home}}/scripts/` respectively, it is a good idea to add these paths to `$env.NU_LIB_DIRS` and `$env.PATH` respectively, e.g. if you have `$env.nupm.home` defined: ```nushell # env.nu $env.NU_LIB_DIRS = [ ... - ($env.NUPM_HOME | path join "modules") + ($env.nupm.home | path join "modules") ] $env.PATH = ( $env.PATH | split row (char esep) | .... - | prepend ($env.NUPM_HOME | path join "scripts") + | prepend ($env.nupm.home | path join "scripts") | uniq ) ``` diff --git a/docs/design/README.md b/docs/design/README.md index 224d3c4..afaa60d 100644 --- a/docs/design/README.md +++ b/docs/design/README.md @@ -7,7 +7,7 @@ This file collects design ideas and directions. The intention is iterate on this > - `METADATA_FILE`: the file containing the metadata of a package, > e.g. `project.nuon`, `metadata.json` or `nupm.nuon` > (name inspired by Julia's `Project.toml` or Rust's `Cargo.toml`) -> - `NUPM_HOME`: the location of all the `nupm` files, overlays, scripts, libraries, ..., +> - `nupm.home`: the location of all the `nupm` files, overlays, scripts, libraries, ..., > e.g. `~/.nupm/`, `$env.XDG_DATA_HOME/nupm/` or `~/.local/share/nupm/` # Table of content @@ -37,7 +37,7 @@ spam ``` * meant as a runnable script, equivalent of Rust's binary project * could use the `.nush` extension if we agree to support it -* installed under `NUPM_HOME/bin/` +* installed under `nupm.home/bin/` 2. Module ``` @@ -47,7 +47,7 @@ spam └── mod.nu ``` * meant as a library to be `use`d or `overlay use`d, equivalent of Rust's library project -* installed under `NUPM_HOME/modules/` +* installed under `nupm.home/modules/` You can also install non-Nushell packages as well using a "custom" project type where you specify a `build.nu` installation script (e.g., you can install Nushell itself with it). @@ -69,18 +69,18 @@ Related to that is a lock file: It is intended to describe exactly the dependenc The overlays could be used to achieve all three goals at the same time. When installing a dependency for a package * `nupm` adds entry to a **lock file** (this should be the only file you need to 100% replicate the environment) -* A .nu file (module) is auto-generated from the lock file and contains export statements like `export module NUPM_HOME/cache/packages/spam-v16.4.0-124ptnpbf/spam`. Calling `overlay use` on the file will activate your virtual environment, now you have a per-project environment -* This file can be installed into a global location that's in your `NU_LIB_DIRS` (e.g., `NUPM_HOME/overlays`) -- now you have a global Python-like virtual environment - * Each overlay under `NUPM_HOME/overlays` will mimic the main NUPM_HOME structure, e.g., for an overlay `spam` there will be `NUPM_HOME/overlays/spam/bin`, `NUPM_HOME/overlays/spam/modules` (`NUPM_HOME/overlays/spam/overlays`? It might not be the best idea to have it recursive) +* A .nu file (module) is auto-generated from the lock file and contains export statements like `export module nupm.home/cache/packages/spam-v16.4.0-124ptnpbf/spam`. Calling `overlay use` on the file will activate your virtual environment, now you have a per-project environment +* This file can be installed into a global location that's in your `NU_LIB_DIRS` (e.g., `nupm.home/overlays`) -- now you have a global Python-like virtual environment + * Each overlay under `nupm.home/overlays` will mimic the main nupm.home structure, e.g., for an overlay `spam` there will be `nupm.home/overlays/spam/bin`, `nupm.home/overlays/spam/modules` (`nupm.home/overlays/spam/overlays`? It might not be the best idea to have it recursive) Each package would basically have its own overlay. This overlay file (it's just a module) could be used to also handle dependencies. If your project depends on `foo` and `bar` which both depend on `spam` but different versions, they could both import the different verions privately in their own overlay files and in your project's overlay file would be just `export use path/to/foo` and `export use path/to/bar`. This should prevent name clashing of `spam`. The only problem that needs to be figured out is how to tell `foo` to be aware of its overlay. ## Installation, bootstraping [[toc](#table-of-content)] Requires these actions from the user (this should be kept as minimal as possible): -* Add `NUPM_HOME/bin` to PATH (install location for binary projects) -* Add `NUPM_HOME/modules` to NU_LIB_DIRS -* Add `NUPM_HOME/overlays` to NU_LIB_DIRS +* Add `nupm.home/bin` to PATH (install location for binary projects) +* Add `nupm.home/modules` to NU_LIB_DIRS +* Add `nupm.home/overlays` to NU_LIB_DIRS * Make the `nupm` command available somehow (e.g., `use` inside `config.nu`) > :warning: **WIP** diff --git a/nupm/install.nu b/nupm/install.nu index e880e8c..dce94c0 100644 --- a/nupm/install.nu +++ b/nupm/install.nu @@ -235,7 +235,7 @@ def fetch-package [ export def main [ package # Name, path, or link to the package --registry: string@complete-registries # Which registry to use (either a name - # in $env.NUPM_REGISTRIES or a path) + # in $env.nupm.registries or a path) --pkg-version(-v): string # Package version to install --path # Install package from a directory with nupm.nuon given by 'name' --force(-f) # Overwrite already installed package diff --git a/nupm/mod.nu b/nupm/mod.nu index b44f56f..b93cb29 100644 --- a/nupm/mod.nu +++ b/nupm/mod.nu @@ -13,19 +13,19 @@ export module test.nu export const BASE_NUPM_CONFIG = { default-home: ($nu.default-config-dir | path join "nupm") default-cache: ($nu.default-config-dir | path join nupm cache) - default-temp: ($nu.temp-path | path join "nupm") + # default-temp: ($nu.temp-path | path join "nupm") default-registry: { nupm: 'https://raw.githubusercontent.com/nushell/nupm/main/registry/registry.nuon' } } export-env { - # Ensure that $env.nupm is always set when running nupm. Any missing variaables + # Ensure that $env.nupm is always set when running nupm. Any missing variaables are set by `$BASE_NUPM_CONFIG` $env.nupm = { - home: ($env.nupm.home? | default $BASE_NUPM_CONFIG.default-home) - cache: ($env.nupm.cache? | default $BASE_NUPM_CONFIG.default-cache) - temp: ($env.nupm.temp? | default $BASE_NUPM_CONFIG.default-temp) - registries: ($env.nupm.registires? | default $BASE_NUPM_CONFIG.default-registry) + home: ($env.nupm?.home? | default $BASE_NUPM_CONFIG.default-home) + cache: ($env.nupm?.cache? | default $BASE_NUPM_CONFIG.default-cache) + temp: ($env.nupm?.temp? | default ($nu.temp-path | path join "nupm")) + registries: ($env.nupm?.registires? | default $BASE_NUPM_CONFIG.default-registry) } | merge $BASE_NUPM_CONFIG # Should this filename be hardcoded for simplicity? $env.nupm.index-path = ($env.nupm.home | path join "registry_index.nuon") @@ -46,7 +46,7 @@ export-env { # Nushell packages including modules, scripts, and custom packages. # # Configuration: -# Set `NUPM_HOME` environment variable to change installation directory +# Set `nupm.home` environment variable to change installation directory # Set `NUPM_REGISTRIES` to configure package registries @example "Install a package from a local directory" { nupm install my-package --path } @example "Publish a package" { nupm publish my-registry.nuon --local --save } @@ -60,4 +60,5 @@ export def main [subcommand?]: nothing -> nothing { print $"(ansi green)Usage(ansi reset): nupm \(($subcommands | str join '|'))" print 'enjoy nupm!' + echo $env.nupm } diff --git a/nupm/publish.nu b/nupm/publish.nu index 9ed7d19..da9089e 100644 --- a/nupm/publish.nu +++ b/nupm/publish.nu @@ -222,7 +222,7 @@ def guess-revision []: nothing -> string { def get-registry-path []: string -> path { let registry = $in - $env.NUPM_REGISTRIES | get -i $registry | default ($registry | path expand) + $env.nupm.registries | get -i $registry | default ($registry | path expand) } def open-registry-file []: path -> table { diff --git a/nupm/registry.nu b/nupm/registry.nu index e0fbfdf..97fea9e 100644 --- a/nupm/registry.nu +++ b/nupm/registry.nu @@ -12,20 +12,33 @@ export def main []: nothing -> table { # List all configured registries @example "List all registries with details" { nupm registry list } export def list []: nothing -> table { - let registry_idx_path = $env.NUPM_HOME | path join "registry_idx.nuon" + $env.nupm.registries | select name url | sort-by name +} + + +# Show detailed information about a specific registry +@example "Show registry information" { nupm registry info nupm } +export def describe [ + name: string # Name of the registry +]: nothing -> table { + let registry_idx_path = $env.nupm.home | path join "registry_idx.nuon" if not ($registry_idx_path | path exists) { - init + throw-error "No registry list found. Run 'nupm registry init' first." } let registries = open $registry_idx_path + let registry = $registries | where name == $name - $registries | select name url enabled | sort-by name + if ($registry | length) == 0 { + throw-error $"Registry '($name)' not found." + } + + $registry | first } # Add a new registry @example "Add a new registry" { nupm registry add my-registry https://example.com/registry.nuon } -@example "Add a disabled registry" { nupm registry add test-registry ./local-registry.nuon --enabled=false } export def --env add [ name: string, # Name of the registry url: string, # URL or path to the registry @@ -36,7 +49,7 @@ export def --env add [ } $env.nupm.registries = $env.nupm.registries | insert $name $url - if ($save) { + if $save { $env.nupm.registries | save --force $env.nupm.index-path } @@ -51,7 +64,7 @@ export def --env remove [ ] { $env.nupm.registires = $env.nupm.registires | reject $name - if ($save) { + if $save { $env.nupm.registries | save --force $env.nupm.index-path } @@ -68,7 +81,7 @@ export def --env set-url [ ]: nothing -> nothing { $env.nupm.registires = $env.nupm.registires | update $name $url - if ($save) { + if $save { $env.nupm.registries | save --force $env.nupm.index-path } @@ -81,14 +94,14 @@ export def --env rename [ name: string, # Name of the registry to update new_name: string, --save, # Whether to commit the change to the registry index -]: nothing -> nothing { +] { $env.nupm.registires = $env.nupm.registires | ^rename --column { $name: $new_name } - if ($save) { + if $save { $env.nupm.registries | save --force $env.nupm.index-path } - print $"Registry '($name)' URL updated successfully." + print $"Registry '($name)' renamed successfully." } @@ -97,12 +110,12 @@ export def --env rename [ export def init-index [ registry?: record -]: nothing -> nothing { +] { if not (nupm-home-prompt) { - throw-error "Cannot create NUPM_HOME directory." + throw-error "Cannot create nupm.home directory." } - let registry_idx_path = $env.NUPM_HOME | path join "registry_idx.nuon" + let registry_idx_path = $env.nupm.home | path join "registry_idx.nuon" if ($registry_idx_path | path exists) { print $"Registry list already exists at ($registry_idx_path)" @@ -122,24 +135,3 @@ export def init-index [ print $"Registry list initialized at ($registry_idx_path)" } - -# Show detailed information about a specific registry -@example "Show registry information" { nupm registry info nupm } -export def info [ - name: string # Name of the registry -]: nothing -> table { - let registry_idx_path = $env.NUPM_HOME | path join "registry_idx.nuon" - - if not ($registry_idx_path | path exists) { - throw-error "No registry list found. Run 'nupm registry init' first." - } - - let registries = open $registry_idx_path - let registry = $registries | where name == $name - - if ($registry | length) == 0 { - throw-error $"Registry '($name)' not found." - } - - $registry | first -} diff --git a/nupm/search.nu b/nupm/search.nu index e8739f5..e62db55 100644 --- a/nupm/search.nu +++ b/nupm/search.nu @@ -21,7 +21,7 @@ use utils/version.nu filter-by-version export def main [ package # Name, path, or link to the package --registry: string@complete-registries # Which registry to use (either a name - # in $env.NUPM_REGISTRIES or a path) + # in $env.nupm.registries or a path) --pkg-version(-v): string # Package version to install --exact-match(-e) # Match package name exactly ]: nothing -> table { diff --git a/nupm/utils/completions.nu b/nupm/utils/completions.nu index d1d37ab..f371c5f 100644 --- a/nupm/utils/completions.nu +++ b/nupm/utils/completions.nu @@ -1,3 +1,3 @@ export def complete-registries [] { - $env.NUPM_REGISTRIES? | default {} | columns + $env.nupm.registries? | default {} | columns } diff --git a/nupm/utils/registry.nu b/nupm/utils/registry.nu index df7e330..aef631b 100644 --- a/nupm/utils/registry.nu +++ b/nupm/utils/registry.nu @@ -16,16 +16,16 @@ export def search-package [ --registry: string # Which registry to use (name or path) --exact-match # Searched package name must match exactly ]: nothing -> table { - let registries = if (not ($registry | is-empty)) and ($registry in $env.NUPM_REGISTRIES) { - # If $registry is a valid column in $env.NUPM_REGISTRIES, use that - { $registry : ($env.NUPM_REGISTRIES | get $registry) } + let registries = if (not ($registry | is-empty)) and ($registry in $env.nupm.registries) { + # If $registry is a valid column in $env.nupm.registries, use that + { $registry : ($env.nupm.registries | get $registry) } } else if (not ($registry | is-empty)) and ($registry | path exists) { # If $registry is a path, use that let reg_name = $registry | path parse | get stem { $reg_name: $registry } } else { - # Otherwise use $env.NUPM_REGISTRIES as-is - $env.NUPM_REGISTRIES + # Otherwise use $env.nupm.registries as-is + $env.nupm.registries } let name_matcher: closure = if $exact_match { diff --git a/tests/mod.nu b/tests/mod.nu index 6340dc4..8396186 100644 --- a/tests/mod.nu +++ b/tests/mod.nu @@ -13,7 +13,7 @@ def with-test-env [closure: closure]: nothing -> nothing { let reg = { test: $TEST_REGISTRY_PATH } with-env { - NUPM_HOME: $home + nupm.home: $home NUPM_CACHE: $cache NUPM_TEMP: $temp NUPM_REGISTRIES: $reg @@ -25,14 +25,14 @@ def with-test-env [closure: closure]: nothing -> nothing { } # Examples: -# make sure `$env.NUPM_HOME/scripts/script.nu` exists +# make sure `$env.nupm.home/scripts/script.nu` exists # > assert installed [scripts script.nu] def "assert installed" [path_tokens: list] { - assert ($path_tokens | prepend $env.NUPM_HOME | path join | path exists) + assert ($path_tokens | prepend $env.nupm.home | path join | path exists) } def check-file-content [content: string] { - let file_str = open ($env.NUPM_HOME | path join scripts spam_script.nu) + let file_str = open ($env.nupm.home | path join scripts spam_script.nu) assert ($file_str | str contains $content) } @@ -66,7 +66,7 @@ export def install-custom [] { export def install-from-local-registry [] { with-test-env { - $env.NUPM_REGISTRIES = {} + $env.nupm.registries = {} nupm install --registry $TEST_REGISTRY_PATH spam_script check-file-content 0.2.0 } @@ -91,7 +91,7 @@ export def install-with-version [] { export def install-multiple-registries-fail [] { with-test-env { - $env.NUPM_REGISTRIES.test2 = $TEST_REGISTRY_PATH + $env.nupm.registries.test2 = $TEST_REGISTRY_PATH let out = try { nupm install spam_script @@ -134,18 +134,18 @@ export def nupm-status-module [] { } export def env-vars-are-set [] { - $env.NUPM_HOME = null + $env.nupm.home = null $env.NUPM_TEMP = null $env.NUPM_CACHE = null - $env.NUPM_REGISTRIES = null + $env.nupm.registries = null use ../nupm/utils/dirs.nu use ../nupm - assert equal $env.NUPM_HOME $dirs.DEFAULT_NUPM_HOME + assert equal $env.nupm.home $dirs.DEFAULT_nupm.home assert equal $env.NUPM_TEMP $dirs.DEFAULT_NUPM_TEMP assert equal $env.NUPM_CACHE $dirs.DEFAULT_NUPM_CACHE - assert equal $env.NUPM_REGISTRIES $dirs.DEFAULT_NUPM_REGISTRIES + assert equal $env.nupm.registries $dirs.DEFAULT_NUPM_REGISTRIES } export def generate-local-registry [] { diff --git a/tests/packages/spam_custom/build.nu b/tests/packages/spam_custom/build.nu index 1c62024..45f6147 100644 --- a/tests/packages/spam_custom/build.nu +++ b/tests/packages/spam_custom/build.nu @@ -1,6 +1,6 @@ def main [package_file: path] { let package = open $package_file - print $"Installing ($package.name) to ($env.NUPM_HOME) inside ($env.PWD)" - mkdir ($env.NUPM_HOME | path join plugins) - touch ($env.NUPM_HOME | path join plugins nu_plugin_test) + print $"Installing ($package.name) to ($env.nupm.home) inside ($env.PWD)" + mkdir ($env.nupm.home | path join plugins) + touch ($env.nupm.home | path join plugins nu_plugin_test) } diff --git a/toolkit.nu b/toolkit.nu index 93de04c..dc86425 100644 --- a/toolkit.nu +++ b/toolkit.nu @@ -8,10 +8,10 @@ export def --env set-nupm-env [--clear] { rm -rf _nupm_dev } - $env.NUPM_HOME = ($env.PWD | path join _nupm_dev) + $env.nupm.home = ($env.PWD | path join _nupm_dev) $env.NUPM_CACHE = ($env.PWD | path join _nupm_dev cache) $env.NUPM_TEMP = ($env.PWD | path join _nupm_dev tmp) - $env.NUPM_REGISTRIES = { nupm_dev: ($env.PWD | path join registry registry.nuon) } + $env.nupm.registries = { nupm_dev: ($env.PWD | path join registry registry.nuon) } if $nu.os-info.family == 'windows' and 'Path' in $env { $env.Path = ($env.Path | prepend ($env.PWD | path join _nupm_dev scripts)) @@ -24,12 +24,12 @@ export def --env set-nupm-env [--clear] { } export def print-nupm-env [] { - print $'NUPM_HOME: ($env.NUPM_HOME?)' + print $'nupm.home: ($env.nupm.home?)' print $'NUPM_CACHE: ($env.NUPM_CACHE?)' print $'NUPM_TEMP: ($env.NUPM_TEMP?)' print $"PATH: ($env.PATH? | default $env.Path? | default [])" print $'NU_LIB_DIRS: ($env.NU_LIB_DIRS?)' - print $'NUPM_REGISTRIES: ($env.NUPM_REGISTRIES?)' + print $'NUPM_REGISTRIES: ($env.nupm.registries?)' } # turn on pretty diffs for NUON data files From 354dc8e57c419cbc639118392fa17bcce04b8105 Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Tue, 24 Jun 2025 17:09:45 -0500 Subject: [PATCH 07/32] typos --- docs/design/README.md | 8 ++++---- docs/design/registry.md | 2 +- nupm/utils/misc.nu | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/design/README.md b/docs/design/README.md index afaa60d..35526c8 100644 --- a/docs/design/README.md +++ b/docs/design/README.md @@ -13,7 +13,7 @@ This file collects design ideas and directions. The intention is iterate on this # Table of content - [Project Structure](#project-structure-toc) - [Separate virtual environments](#separate-virtual-environments-toc) -- [Installation, bootstraping](#installation-bootstraping-toc) +- [Installation, bootstrapping](#installation-bootstrapping-toc) - [Dependency handling](#dependency-handling-toc) - [Package repository](#package-repository-toc) - [API / CLI Interface](#api--cli-interface-toc) @@ -73,9 +73,9 @@ The overlays could be used to achieve all three goals at the same time. When ins * This file can be installed into a global location that's in your `NU_LIB_DIRS` (e.g., `nupm.home/overlays`) -- now you have a global Python-like virtual environment * Each overlay under `nupm.home/overlays` will mimic the main nupm.home structure, e.g., for an overlay `spam` there will be `nupm.home/overlays/spam/bin`, `nupm.home/overlays/spam/modules` (`nupm.home/overlays/spam/overlays`? It might not be the best idea to have it recursive) -Each package would basically have its own overlay. This overlay file (it's just a module) could be used to also handle dependencies. If your project depends on `foo` and `bar` which both depend on `spam` but different versions, they could both import the different verions privately in their own overlay files and in your project's overlay file would be just `export use path/to/foo` and `export use path/to/bar`. This should prevent name clashing of `spam`. The only problem that needs to be figured out is how to tell `foo` to be aware of its overlay. +Each package would basically have its own overlay. This overlay file (it's just a module) could be used to also handle dependencies. If your project depends on `foo` and `bar` which both depend on `spam` but different versions, they could both import the different versions privately in their own overlay files and in your project's overlay file would be just `export use path/to/foo` and `export use path/to/bar`. This should prevent name clashing of `spam`. The only problem that needs to be figured out is how to tell `foo` to be aware of its overlay. -## Installation, bootstraping [[toc](#table-of-content)] +## Installation, bootstrapping [[toc](#table-of-content)] Requires these actions from the user (this should be kept as minimal as possible): * Add `nupm.home/bin` to PATH (install location for binary projects) @@ -178,7 +178,7 @@ The following are for Python-style global overlays, we might need to re-think th ### Other CLI-related notes [[toc](#table-of-content)] * We could later think about being able to extend `nupm`, like `cargo` has plugins. -* Mutable actions (like install) have by default Y/n prompt, but can be overriden with `--yes` +* Mutable actions (like install) have by default Y/n prompt, but can be overridden with `--yes` * By default, new projects are cross-platform: * Windows * MacOS diff --git a/docs/design/registry.md b/docs/design/registry.md index dc225ed..1bc8e38 100644 --- a/docs/design/registry.md +++ b/docs/design/registry.md @@ -92,7 +92,7 @@ _See the new `registry/` directory, the following example slightly differs from It is possible to only publish to a registry stored on your file system because we don't have a web service or anything like that. -The intented workflow for publishing a package is: +The intended workflow for publishing a package is: 1. Check out the git repository with the registry 2. `cd` into the package you want to publish 3. Run `nupm publish chosen_registry` to preview the changes diff --git a/nupm/utils/misc.nu b/nupm/utils/misc.nu index 3f3e7be..e0ec943 100644 --- a/nupm/utils/misc.nu +++ b/nupm/utils/misc.nu @@ -58,7 +58,7 @@ export module url { export def update-name [new_name: string]: string -> string { url parse | update path {|url| - # skip the first '/' and replace last elemnt with the new name + # skip the first '/' and replace last element with the new name let parts = $url.path | path split | skip 1 | drop 1 $parts | append $new_name | str join '/' } From 2efd004a1a6214841d87da32d3923b7919b9b719 Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Tue, 24 Jun 2025 17:16:48 -0500 Subject: [PATCH 08/32] updated initial test variables --- tests/mod.nu | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/tests/mod.nu b/tests/mod.nu index 8396186..cb9d617 100644 --- a/tests/mod.nu +++ b/tests/mod.nu @@ -13,10 +13,12 @@ def with-test-env [closure: closure]: nothing -> nothing { let reg = { test: $TEST_REGISTRY_PATH } with-env { - nupm.home: $home - NUPM_CACHE: $cache - NUPM_TEMP: $temp - NUPM_REGISTRIES: $reg + nupm { + home: $home + cache: $cache + temp: $temp + registires: $reg + } } $closure rm --recursive $temp @@ -176,10 +178,10 @@ export def registry-list [] { with-test-env { # Initialize registry list nupm registry init - + # Get list of registries let registries = nupm registry list - + # Should have default nupm registry assert equal ($registries | length) 1 assert equal $registries.0.name "nupm" @@ -192,19 +194,19 @@ export def registry-add [] { with-test-env { # Initialize registry list nupm registry init - + # Add a new registry nupm registry add test-registry https://example.com/test.nuon --enabled=false - + # Verify registry was added let registries = nupm registry list assert equal ($registries | length) 2 - + let test_reg = $registries | where name == "test-registry" | first assert equal $test_reg.name "test-registry" assert equal $test_reg.url "https://example.com/test.nuon" assert equal $test_reg.enabled false - + # Try to add duplicate registry (should fail) let add_result = try { nupm registry add test-registry https://duplicate.com/test.nuon @@ -212,15 +214,15 @@ export def registry-add [] { } catch {|err| $err.msg } - + assert ("Registry 'test-registry' already exists" in $add_result) - + # Add another registry with default enabled=true nupm registry add another-registry ./local-registry.nuon - + let registries_final = nupm registry list assert equal ($registries_final | length) 3 - + let another_reg = $registries_final | where name == "another-registry" | first assert equal $another_reg.enabled true } From 5e96f1a6311429ab1fcee9e8275d055d11d9e070 Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Tue, 24 Jun 2025 17:22:28 -0500 Subject: [PATCH 09/32] fixed registry typo --- nupm/mod.nu | 2 +- nupm/registry.nu | 6 +++--- tests/mod.nu | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/nupm/mod.nu b/nupm/mod.nu index b93cb29..cda68d2 100644 --- a/nupm/mod.nu +++ b/nupm/mod.nu @@ -25,7 +25,7 @@ export-env { home: ($env.nupm?.home? | default $BASE_NUPM_CONFIG.default-home) cache: ($env.nupm?.cache? | default $BASE_NUPM_CONFIG.default-cache) temp: ($env.nupm?.temp? | default ($nu.temp-path | path join "nupm")) - registries: ($env.nupm?.registires? | default $BASE_NUPM_CONFIG.default-registry) + registries: ($env.nupm?.registries? | default $BASE_NUPM_CONFIG.default-registry) } | merge $BASE_NUPM_CONFIG # Should this filename be hardcoded for simplicity? $env.nupm.index-path = ($env.nupm.home | path join "registry_index.nuon") diff --git a/nupm/registry.nu b/nupm/registry.nu index 97fea9e..24347b9 100644 --- a/nupm/registry.nu +++ b/nupm/registry.nu @@ -62,7 +62,7 @@ export def --env remove [ name: string # Name of the registry to remove --save, # Whether to commit the change to the registry index ] { - $env.nupm.registires = $env.nupm.registires | reject $name + $env.nupm.registries = $env.nupm.registries | reject $name if $save { $env.nupm.registries | save --force $env.nupm.index-path @@ -79,7 +79,7 @@ export def --env set-url [ url: string, --save, # Whether to commit the change to the registry index ]: nothing -> nothing { - $env.nupm.registires = $env.nupm.registires | update $name $url + $env.nupm.registries = $env.nupm.registries | update $name $url if $save { $env.nupm.registries | save --force $env.nupm.index-path @@ -95,7 +95,7 @@ export def --env rename [ new_name: string, --save, # Whether to commit the change to the registry index ] { - $env.nupm.registires = $env.nupm.registires | ^rename --column { $name: $new_name } + $env.nupm.registries = $env.nupm.registries | ^rename --column { $name: $new_name } if $save { $env.nupm.registries | save --force $env.nupm.index-path diff --git a/tests/mod.nu b/tests/mod.nu index cb9d617..df0fdf7 100644 --- a/tests/mod.nu +++ b/tests/mod.nu @@ -17,7 +17,7 @@ def with-test-env [closure: closure]: nothing -> nothing { home: $home cache: $cache temp: $temp - registires: $reg + registries: $reg } } $closure From 0821712569d17ae45fd6b4a30c3b1defdf13acd7 Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Tue, 24 Jun 2025 18:30:56 -0500 Subject: [PATCH 10/32] renamed tmp to temp --- nupm/install.nu | 12 +++++- nupm/mod.nu | 8 ++-- nupm/registry.nu | 28 ++++---------- nupm/test.nu | 2 +- nupm/utils/dirs.nu | 4 +- tests/mod.nu | 59 ++++++++++++++--------------- tests/packages/spam_custom/build.nu | 2 + toolkit.nu | 10 ++--- 8 files changed, 60 insertions(+), 65 deletions(-) diff --git a/nupm/install.nu b/nupm/install.nu index dce94c0..0fcb26f 100644 --- a/nupm/install.nu +++ b/nupm/install.nu @@ -1,5 +1,5 @@ use utils/completions.nu complete-registries -use utils/dirs.nu [ nupm-home-prompt cache-dir module-dir script-dir tmp-dir ] +use utils/dirs.nu [ nupm-home-prompt cache-dir module-dir script-dir temp-dir ] use utils/log.nu throw-error use utils/misc.nu [check-cols hash-fn url] use utils/package.nu open-package-file @@ -102,11 +102,18 @@ def install-path [ --span (metadata $pkg_dir | get span)) } - let tmp_dir = tmp-dir build --ensure + let tmp_dir = temp-dir build --ensure do { cd $tmp_dir + # let package_file = ($pkg_dir | path join 'nupm.nuon') ^$nu.current-exe $build_file ($pkg_dir | path join 'nupm.nuon') + + # ^$nu.current-exe --no-config-file --commands $" + # $env.nupm = ($env.nupm | to nuon); + # source ($build_file | to nuon); + # main ($package_file | to nuon) + # " } rm -rf $tmp_dir @@ -241,6 +248,7 @@ export def main [ --force(-f) # Overwrite already installed package --no-confirm # Allows to bypass the interactive confirmation, useful for scripting ]: nothing -> nothing { + echo $env.nupm if not (nupm-home-prompt --no-confirm=$no_confirm) { return } diff --git a/nupm/mod.nu b/nupm/mod.nu index cda68d2..1ee593f 100644 --- a/nupm/mod.nu +++ b/nupm/mod.nu @@ -13,8 +13,8 @@ export module test.nu export const BASE_NUPM_CONFIG = { default-home: ($nu.default-config-dir | path join "nupm") default-cache: ($nu.default-config-dir | path join nupm cache) - # default-temp: ($nu.temp-path | path join "nupm") - default-registry: { + default-temp: ($nu.temp-path | path join "nupm") + default-registries: { nupm: 'https://raw.githubusercontent.com/nushell/nupm/main/registry/registry.nuon' } } @@ -25,7 +25,7 @@ export-env { home: ($env.nupm?.home? | default $BASE_NUPM_CONFIG.default-home) cache: ($env.nupm?.cache? | default $BASE_NUPM_CONFIG.default-cache) temp: ($env.nupm?.temp? | default ($nu.temp-path | path join "nupm")) - registries: ($env.nupm?.registries? | default $BASE_NUPM_CONFIG.default-registry) + registries: ($env.nupm?.registries? | default $BASE_NUPM_CONFIG.default-registries) } | merge $BASE_NUPM_CONFIG # Should this filename be hardcoded for simplicity? $env.nupm.index-path = ($env.nupm.home | path join "registry_index.nuon") @@ -47,7 +47,7 @@ export-env { # # Configuration: # Set `nupm.home` environment variable to change installation directory -# Set `NUPM_REGISTRIES` to configure package registries +# Set `nupm.registries` to configure package registries @example "Install a package from a local directory" { nupm install my-package --path } @example "Publish a package" { nupm publish my-registry.nuon --local --save } @example "Search for specific version" { nupm search my-package --pkg-version 1.2.0 } diff --git a/nupm/registry.nu b/nupm/registry.nu index 24347b9..528552c 100644 --- a/nupm/registry.nu +++ b/nupm/registry.nu @@ -12,30 +12,17 @@ export def main []: nothing -> table { # List all configured registries @example "List all registries with details" { nupm registry list } export def list []: nothing -> table { - $env.nupm.registries | select name url | sort-by name + $env.nupm.registries | transpose name url | sort-by name } +# TODO # Show detailed information about a specific registry -@example "Show registry information" { nupm registry info nupm } -export def describe [ - name: string # Name of the registry -]: nothing -> table { - let registry_idx_path = $env.nupm.home | path join "registry_idx.nuon" - - if not ($registry_idx_path | path exists) { - throw-error "No registry list found. Run 'nupm registry init' first." - } - - let registries = open $registry_idx_path - let registry = $registries | where name == $name - - if ($registry | length) == 0 { - throw-error $"Registry '($name)' not found." - } - - $registry | first -} +# @example "Show registry information" { nupm registry describe nupm } +# export def describe [ +# name: string # Name of the registry +# ]: nothing -> table { +# } # Add a new registry @example "Add a new registry" { nupm registry add my-registry https://example.com/registry.nuon } @@ -73,7 +60,6 @@ export def --env remove [ # Update a given registry url @example "Update registry URL" { nupm registry set-url my-registry https://new-url.com/registry.nuon } -@example "Rename a registry" { nupm registry update my-registry --set-name our-registry } export def --env set-url [ name: string, # Name of the registry to update url: string, diff --git a/nupm/test.nu b/nupm/test.nu index ea67e2e..a9551da 100644 --- a/nupm/test.nu +++ b/nupm/test.nu @@ -1,4 +1,4 @@ -use utils/dirs.nu [ tmp-dir find-root ] +use utils/dirs.nu [ temp-dir find-root ] use utils/log.nu throw-error # Run tests for a nupm package diff --git a/nupm/utils/dirs.nu b/nupm/utils/dirs.nu index 41a1832..d67ba3e 100644 --- a/nupm/utils/dirs.nu +++ b/nupm/utils/dirs.nu @@ -74,8 +74,8 @@ export def cache-dir [--ensure]: nothing -> path { $d } -export def tmp-dir [subdir: string, --ensure]: nothing -> path { - let d = $env.nupm.cache +export def temp-dir [subdir: string, --ensure]: nothing -> path { + let d = $env.nupm.temp | path join $subdir | path join (random chars -l 8) diff --git a/tests/mod.nu b/tests/mod.nu index df0fdf7..03a7972 100644 --- a/tests/mod.nu +++ b/tests/mod.nu @@ -1,19 +1,20 @@ use std assert -use ../nupm/utils/dirs.nu tmp-dir +use ../nupm/utils/dirs.nu temp-dir use ../nupm const TEST_REGISTRY_PATH = ([tests packages registry registry.nuon] | path join) def with-test-env [closure: closure]: nothing -> nothing { - let home = tmp-dir nupm_test --ensure - let cache = tmp-dir 'nupm_test/cache' --ensure - let temp = tmp-dir 'nupm_test/temp' --ensure + echo $nupm + let home = temp-dir nupm_test --ensure + let cache = temp-dir 'nupm_test/cache' --ensure + let temp = temp-dir 'nupm_test/temp' --ensure let reg = { test: $TEST_REGISTRY_PATH } with-env { - nupm { + nupm: { home: $home cache: $cache temp: $temp @@ -33,6 +34,12 @@ def "assert installed" [path_tokens: list] { assert ($path_tokens | prepend $env.nupm.home | path join | path exists) } +export def test-env-is-set [] { + with-test-env { + $env.nupm.home | is-empty + } +} + def check-file-content [content: string] { let file_str = open ($env.nupm.home | path join scripts spam_script.nu) assert ($file_str | str contains $content) @@ -60,6 +67,9 @@ export def install-module [] { export def install-custom [] { with-test-env { + use std/log + log info CUSTOM + log info $env.nupm.home nupm install --path tests/packages/spam_custom assert installed [plugins nu_plugin_test] @@ -136,27 +146,23 @@ export def nupm-status-module [] { } export def env-vars-are-set [] { - $env.nupm.home = null - $env.NUPM_TEMP = null - $env.NUPM_CACHE = null - $env.nupm.registries = null + $env.nupm = null - use ../nupm/utils/dirs.nu use ../nupm - assert equal $env.nupm.home $dirs.DEFAULT_nupm.home - assert equal $env.NUPM_TEMP $dirs.DEFAULT_NUPM_TEMP - assert equal $env.NUPM_CACHE $dirs.DEFAULT_NUPM_CACHE - assert equal $env.nupm.registries $dirs.DEFAULT_NUPM_REGISTRIES + assert equal $env.nupm.home $nupm.BASE_NUPM_CONFIG.default-home + assert equal $env.nupm.temp $nupm.BASE_NUPM_CONFIG.default-temp + assert equal $env.nupm.cache $nupm.BASE_NUPM_CONFIG.default-cache + assert equal $env.nupm.registries $nupm.BASE_NUPM_CONFIG.default-registries } export def generate-local-registry [] { with-test-env { - mkdir ($env.NUPM_TEMP | path join packages registry) + mkdir ($env.nupm.temp | path join packages registry) let reg_file = [tests packages registry registry.nuon] | path join let tmp_reg_file = [ - $env.NUPM_TEMP packages registry test_registry.nuon + $env.nupm.temp packages registry test_registry.nuon ] | path join @@ -176,27 +182,20 @@ export def generate-local-registry [] { export def registry-list [] { with-test-env { - # Initialize registry list - nupm registry init - # Get list of registries let registries = nupm registry list - # Should have default nupm registry + # Should have test registry from test environment assert equal ($registries | length) 1 - assert equal $registries.0.name "nupm" - assert equal $registries.0.url "https://raw.githubusercontent.com/nushell/nupm/main/registry/registry.nuon" - assert equal $registries.0.enabled true + assert equal $registries.0.name "test" + assert equal $registries.0.url $TEST_REGISTRY_PATH } } export def registry-add [] { with-test-env { - # Initialize registry list - nupm registry init - # Add a new registry - nupm registry add test-registry https://example.com/test.nuon --enabled=false + nupm registry add test-registry https://example.com/test.nuon # Verify registry was added let registries = nupm registry list @@ -205,7 +204,6 @@ export def registry-add [] { let test_reg = $registries | where name == "test-registry" | first assert equal $test_reg.name "test-registry" assert equal $test_reg.url "https://example.com/test.nuon" - assert equal $test_reg.enabled false # Try to add duplicate registry (should fail) let add_result = try { @@ -217,13 +215,14 @@ export def registry-add [] { assert ("Registry 'test-registry' already exists" in $add_result) - # Add another registry with default enabled=true + # Add another registry nupm registry add another-registry ./local-registry.nuon let registries_final = nupm registry list assert equal ($registries_final | length) 3 let another_reg = $registries_final | where name == "another-registry" | first - assert equal $another_reg.enabled true + assert equal $another_reg.name "another-registry" + assert equal $another_reg.url "./local-registry.nuon" } } diff --git a/tests/packages/spam_custom/build.nu b/tests/packages/spam_custom/build.nu index 45f6147..68d1bc0 100644 --- a/tests/packages/spam_custom/build.nu +++ b/tests/packages/spam_custom/build.nu @@ -1,4 +1,6 @@ def main [package_file: path] { + use std/log + log info $env.nupm.home let package = open $package_file print $"Installing ($package.name) to ($env.nupm.home) inside ($env.PWD)" mkdir ($env.nupm.home | path join plugins) diff --git a/toolkit.nu b/toolkit.nu index dc86425..f313026 100644 --- a/toolkit.nu +++ b/toolkit.nu @@ -9,8 +9,8 @@ export def --env set-nupm-env [--clear] { } $env.nupm.home = ($env.PWD | path join _nupm_dev) - $env.NUPM_CACHE = ($env.PWD | path join _nupm_dev cache) - $env.NUPM_TEMP = ($env.PWD | path join _nupm_dev tmp) + $env.nupm.cache = ($env.PWD | path join _nupm_dev cache) + $env.nupm.temp = ($env.PWD | path join _nupm_dev tmp) $env.nupm.registries = { nupm_dev: ($env.PWD | path join registry registry.nuon) } if $nu.os-info.family == 'windows' and 'Path' in $env { @@ -25,11 +25,11 @@ export def --env set-nupm-env [--clear] { export def print-nupm-env [] { print $'nupm.home: ($env.nupm.home?)' - print $'NUPM_CACHE: ($env.NUPM_CACHE?)' - print $'NUPM_TEMP: ($env.NUPM_TEMP?)' + print $'nupm.cache: ($env.nupm.cache?)' + print $'nupm.temp: ($env.nupm.temp?)' print $"PATH: ($env.PATH? | default $env.Path? | default [])" print $'NU_LIB_DIRS: ($env.NU_LIB_DIRS?)' - print $'NUPM_REGISTRIES: ($env.nupm.registries?)' + print $'nupm.registires: ($env.nupm.registries?)' } # turn on pretty diffs for NUON data files From 445be0f6e1ca42caa6e5f6d43ca1d8ddd9323ed7 Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Tue, 24 Jun 2025 18:35:40 -0500 Subject: [PATCH 11/32] revert temp --- nupm/install.nu | 4 ++-- nupm/test.nu | 2 +- nupm/utils/dirs.nu | 2 +- tests/mod.nu | 8 ++++---- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/nupm/install.nu b/nupm/install.nu index 0fcb26f..5f80a94 100644 --- a/nupm/install.nu +++ b/nupm/install.nu @@ -1,5 +1,5 @@ use utils/completions.nu complete-registries -use utils/dirs.nu [ nupm-home-prompt cache-dir module-dir script-dir temp-dir ] +use utils/dirs.nu [ nupm-home-prompt cache-dir module-dir script-dir tmp-dir ] use utils/log.nu throw-error use utils/misc.nu [check-cols hash-fn url] use utils/package.nu open-package-file @@ -102,7 +102,7 @@ def install-path [ --span (metadata $pkg_dir | get span)) } - let tmp_dir = temp-dir build --ensure + let tmp_dir = tmp-dir build --ensure do { cd $tmp_dir diff --git a/nupm/test.nu b/nupm/test.nu index a9551da..ea67e2e 100644 --- a/nupm/test.nu +++ b/nupm/test.nu @@ -1,4 +1,4 @@ -use utils/dirs.nu [ temp-dir find-root ] +use utils/dirs.nu [ tmp-dir find-root ] use utils/log.nu throw-error # Run tests for a nupm package diff --git a/nupm/utils/dirs.nu b/nupm/utils/dirs.nu index d67ba3e..10834e9 100644 --- a/nupm/utils/dirs.nu +++ b/nupm/utils/dirs.nu @@ -74,7 +74,7 @@ export def cache-dir [--ensure]: nothing -> path { $d } -export def temp-dir [subdir: string, --ensure]: nothing -> path { +export def tmp-dir [subdir: string, --ensure]: nothing -> path { let d = $env.nupm.temp | path join $subdir | path join (random chars -l 8) diff --git a/tests/mod.nu b/tests/mod.nu index 03a7972..9f6b2b5 100644 --- a/tests/mod.nu +++ b/tests/mod.nu @@ -1,6 +1,6 @@ use std assert -use ../nupm/utils/dirs.nu temp-dir +use ../nupm/utils/dirs.nu tmp-dir use ../nupm const TEST_REGISTRY_PATH = ([tests packages registry registry.nuon] | path join) @@ -8,9 +8,9 @@ const TEST_REGISTRY_PATH = ([tests packages registry registry.nuon] | path join) def with-test-env [closure: closure]: nothing -> nothing { echo $nupm - let home = temp-dir nupm_test --ensure - let cache = temp-dir 'nupm_test/cache' --ensure - let temp = temp-dir 'nupm_test/temp' --ensure + let home = tmp-dir nupm_test --ensure + let cache = tmp-dir 'nupm_test/cache' --ensure + let temp = tmp-dir 'nupm_test/temp' --ensure let reg = { test: $TEST_REGISTRY_PATH } with-env { From 1f1249098165c3d1ab25446642e4c769a627225a Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Wed, 25 Jun 2025 20:11:15 -0500 Subject: [PATCH 12/32] fixed tmp-dir variable resolution issue --- nupm/mod.nu | 11 +---------- nupm/utils/dirs.nu | 11 ++++++++++- tests/mod.nu | 17 +++++------------ 3 files changed, 16 insertions(+), 23 deletions(-) diff --git a/nupm/mod.nu b/nupm/mod.nu index 1ee593f..3336aea 100644 --- a/nupm/mod.nu +++ b/nupm/mod.nu @@ -1,6 +1,6 @@ use std/log -use utils/dirs.nu [ nupm-home-prompt ] +use utils/dirs.nu [ nupm-home-prompt BASE_NUPM_CONFIG ] export module install.nu export module publish.nu @@ -9,15 +9,6 @@ export module search.nu export module status.nu export module test.nu -# Base values for nupm that are used as defaults if not present in `$env.nupm` -export const BASE_NUPM_CONFIG = { - default-home: ($nu.default-config-dir | path join "nupm") - default-cache: ($nu.default-config-dir | path join nupm cache) - default-temp: ($nu.temp-path | path join "nupm") - default-registries: { - nupm: 'https://raw.githubusercontent.com/nushell/nupm/main/registry/registry.nuon' - } -} export-env { # Ensure that $env.nupm is always set when running nupm. Any missing variaables are set by `$BASE_NUPM_CONFIG` diff --git a/nupm/utils/dirs.nu b/nupm/utils/dirs.nu index 10834e9..8c42bab 100644 --- a/nupm/utils/dirs.nu +++ b/nupm/utils/dirs.nu @@ -1,3 +1,12 @@ +# Base values for nupm that are used as defaults if not present in `$env.nupm` +export const BASE_NUPM_CONFIG = { + default-home: ($nu.default-config-dir | path join "nupm") + default-cache: ($nu.default-config-dir | path join nupm cache) + default-temp: ($nu.temp-path | path join "nupm") + default-registries: { + nupm: 'https://raw.githubusercontent.com/nushell/nupm/main/registry/registry.nuon' + } +} # Directories and related utilities used in nupm # Prompt to create $env.nupm.home if it does not exist and some sanity checks. @@ -75,7 +84,7 @@ export def cache-dir [--ensure]: nothing -> path { } export def tmp-dir [subdir: string, --ensure]: nothing -> path { - let d = $env.nupm.temp + let d = $BASE_NUPM_CONFIG.default-temp | path join $subdir | path join (random chars -l 8) diff --git a/tests/mod.nu b/tests/mod.nu index 9f6b2b5..4b6521b 100644 --- a/tests/mod.nu +++ b/tests/mod.nu @@ -1,13 +1,12 @@ use std assert -use ../nupm/utils/dirs.nu tmp-dir +use ../nupm/utils/dirs.nu [ tmp-dir BASE_NUPM_CONFIG ] use ../nupm const TEST_REGISTRY_PATH = ([tests packages registry registry.nuon] | path join) def with-test-env [closure: closure]: nothing -> nothing { - echo $nupm let home = tmp-dir nupm_test --ensure let cache = tmp-dir 'nupm_test/cache' --ensure let temp = tmp-dir 'nupm_test/temp' --ensure @@ -34,12 +33,6 @@ def "assert installed" [path_tokens: list] { assert ($path_tokens | prepend $env.nupm.home | path join | path exists) } -export def test-env-is-set [] { - with-test-env { - $env.nupm.home | is-empty - } -} - def check-file-content [content: string] { let file_str = open ($env.nupm.home | path join scripts spam_script.nu) assert ($file_str | str contains $content) @@ -150,10 +143,10 @@ export def env-vars-are-set [] { use ../nupm - assert equal $env.nupm.home $nupm.BASE_NUPM_CONFIG.default-home - assert equal $env.nupm.temp $nupm.BASE_NUPM_CONFIG.default-temp - assert equal $env.nupm.cache $nupm.BASE_NUPM_CONFIG.default-cache - assert equal $env.nupm.registries $nupm.BASE_NUPM_CONFIG.default-registries + assert equal $env.nupm.home $BASE_NUPM_CONFIG.default-home + assert equal $env.nupm.temp $BASE_NUPM_CONFIG.default-temp + assert equal $env.nupm.cache $BASE_NUPM_CONFIG.default-cache + assert equal $env.nupm.registries $BASE_NUPM_CONFIG.default-registries } export def generate-local-registry [] { From f33f29e4b963859ca8c0524ab643afd97ed3540d Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Thu, 26 Jun 2025 12:02:59 -0500 Subject: [PATCH 13/32] updated with workaround --- .editorconfig | 9 +++++++++ nupm/install.nu | 11 ++--------- nupm/mod.nu | 21 ++++++++++----------- nupm/registry.nu | 28 +++++++++++++++------------- nupm/utils/misc.nu | 8 ++++++++ tests/packages/spam_custom/build.nu | 8 +++----- 6 files changed, 47 insertions(+), 38 deletions(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..d741e40 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = space +indent_size = 4 diff --git a/nupm/install.nu b/nupm/install.nu index 5f80a94..274a0d1 100644 --- a/nupm/install.nu +++ b/nupm/install.nu @@ -1,7 +1,7 @@ use utils/completions.nu complete-registries use utils/dirs.nu [ nupm-home-prompt cache-dir module-dir script-dir tmp-dir ] use utils/log.nu throw-error -use utils/misc.nu [check-cols hash-fn url] +use utils/misc.nu [check-cols hash-fn url flatten-nupm-env] use utils/package.nu open-package-file use utils/registry.nu search-package use utils/version.nu filter-by-version @@ -105,15 +105,8 @@ def install-path [ let tmp_dir = tmp-dir build --ensure do { - cd $tmp_dir - # let package_file = ($pkg_dir | path join 'nupm.nuon') + flatten-nupm-env ^$nu.current-exe $build_file ($pkg_dir | path join 'nupm.nuon') - - # ^$nu.current-exe --no-config-file --commands $" - # $env.nupm = ($env.nupm | to nuon); - # source ($build_file | to nuon); - # main ($package_file | to nuon) - # " } rm -rf $tmp_dir diff --git a/nupm/mod.nu b/nupm/mod.nu index 3336aea..964913f 100644 --- a/nupm/mod.nu +++ b/nupm/mod.nu @@ -1,6 +1,7 @@ use std/log use utils/dirs.nu [ nupm-home-prompt BASE_NUPM_CONFIG ] +use registry.nu open-index export module install.nu export module publish.nu @@ -10,25 +11,24 @@ export module status.nu export module test.nu + + export-env { # Ensure that $env.nupm is always set when running nupm. Any missing variaables are set by `$BASE_NUPM_CONFIG` $env.nupm = { home: ($env.nupm?.home? | default $BASE_NUPM_CONFIG.default-home) cache: ($env.nupm?.cache? | default $BASE_NUPM_CONFIG.default-cache) - temp: ($env.nupm?.temp? | default ($nu.temp-path | path join "nupm")) + temp: ($env.nupm?.temp? | default $BASE_NUPM_CONFIG.default-temp) registries: ($env.nupm?.registries? | default $BASE_NUPM_CONFIG.default-registries) } | merge $BASE_NUPM_CONFIG - # Should this filename be hardcoded for simplicity? + # for now, filename hardcoded for simplicity $env.nupm.index-path = ($env.nupm.home | path join "registry_index.nuon") - if ($env.nupm.index-path | path exists) { - if not (($env.nupm.index-path | path type) == "file") { - throw-error $"($env.nupm.index-path) is not a filepath" - } - # overwrite filevalues with those found in config - $env.nupm.registries = open $env.nupm.index-path | merge $env.nupm.registries + # overwrite filevalues with those found in config + $env.nupm.registries = open-index | merge $env.nupm.registries + $env.ENV_CONVERSIONS.nupm = { + from_string: { |s| $s | from nuon } + to_string: { |v| $v | to nuon } } - - use std/log [] } # Nushell Package Manager @@ -51,5 +51,4 @@ export def main [subcommand?]: nothing -> nothing { print $"(ansi green)Usage(ansi reset): nupm \(($subcommands | str join '|'))" print 'enjoy nupm!' - echo $env.nupm } diff --git a/nupm/registry.nu b/nupm/registry.nu index 528552c..53b576c 100644 --- a/nupm/registry.nu +++ b/nupm/registry.nu @@ -101,23 +101,25 @@ export def init-index [ throw-error "Cannot create nupm.home directory." } - let registry_idx_path = $env.nupm.home | path join "registry_idx.nuon" - if ($registry_idx_path | path exists) { - print $"Registry list already exists at ($registry_idx_path)" + if ($env.nupm.registries | path exists) { + print $"Registry list already exists at ($env.nupm.index-path)" return } - # Initialize with the default nupm registry - let default_registries = [ - { - name: "nupm", - url: "https://raw.githubusercontent.com/nushell/nupm/main/registry/registry.nuon", - enabled: true - } - ] + $env.nupm.registries | save $env.nupm.index-path - $default_registries | save $registry_idx_path + print $"Registry list initialized at ($env.nupm.index-path)" +} + +# Initialize nupm.registries value +export def open-index []: nothing -> record { + if ($env.nupm.index-path | path exists) { + if not (($env.nupm.index-path | path type) == "file") { + throw-error $"($env.nupm.index-path) is not a filepath" + } + open $env.nupm.index-path | return + } - print $"Registry list initialized at ($registry_idx_path)" + {} } diff --git a/nupm/utils/misc.nu b/nupm/utils/misc.nu index e0ec943..730bb0f 100644 --- a/nupm/utils/misc.nu +++ b/nupm/utils/misc.nu @@ -65,3 +65,11 @@ export module url { | url join } } + +# workaround for https://github.com/nushell/nushell/issues/16036 +export def --env flatten-nupm-env [] { + $env.NUPM_HOME = $env.nupm.home + $env.NUPM_CACHE = $env.nupm.cache + $env.NUPM_TEMP = $env.nupm.temp + $env.NUPM_REGISTRIES = $env.nupm.registries | to nuon +} diff --git a/tests/packages/spam_custom/build.nu b/tests/packages/spam_custom/build.nu index 68d1bc0..1c62024 100644 --- a/tests/packages/spam_custom/build.nu +++ b/tests/packages/spam_custom/build.nu @@ -1,8 +1,6 @@ def main [package_file: path] { - use std/log - log info $env.nupm.home let package = open $package_file - print $"Installing ($package.name) to ($env.nupm.home) inside ($env.PWD)" - mkdir ($env.nupm.home | path join plugins) - touch ($env.nupm.home | path join plugins nu_plugin_test) + print $"Installing ($package.name) to ($env.NUPM_HOME) inside ($env.PWD)" + mkdir ($env.NUPM_HOME | path join plugins) + touch ($env.NUPM_HOME | path join plugins nu_plugin_test) } From 7d3a1cf236aad66833811fae558615b3764d6d55 Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Thu, 26 Jun 2025 15:44:05 -0500 Subject: [PATCH 14/32] updated test cases for exitsting registry subcommands --- docs/design/README.md | 14 ++++---- nupm/registry.nu | 16 +++++---- tests/mod.nu | 75 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 14 deletions(-) diff --git a/docs/design/README.md b/docs/design/README.md index 35526c8..5a51a13 100644 --- a/docs/design/README.md +++ b/docs/design/README.md @@ -1,8 +1,8 @@ -# Design of `nupm` :warning: Work In Progress :warning: +# Design of `nupm` :warning: Work In Progress :warning: This file collects design ideas and directions. The intention is iterate on this document by PRs with discussion. -> **Note** +> **Note** > in the following, until we settle down on precise names, we use the following placeholders: > - `METADATA_FILE`: the file containing the metadata of a package, > e.g. `project.nuon`, `metadata.json` or `nupm.nuon` @@ -24,7 +24,7 @@ This file collects design ideas and directions. The intention is iterate on this A `nupm` project is defined by `METADATA_FILE`. This is where you define name of the project, version, dependencies, etc., and the type of the project. -> **Note** +> **Note** > see [`METADATA.md`](references/METADATA.md) for a more in-depth description of > the `METADATA_FILE` @@ -83,7 +83,7 @@ Requires these actions from the user (this should be kept as minimal as possible * Add `nupm.home/overlays` to NU_LIB_DIRS * Make the `nupm` command available somehow (e.g., `use` inside `config.nu`) -> :warning: **WIP** +> :warning: **WIP** > The disadvantage of this is that the default install location is not an overlay. We could make `nupm` itself an overlay that adds itself as a command, so that you can activate/deactivate it. We might need a few attempts to get to the right solution. There are several approaches: @@ -98,7 +98,7 @@ There are several approaches: In compiled programming languages, there are two kinds of dependencies: static and dynamic. Static are included statically and compiled when compiling the project, dynamic are pre-compiled libraries linked to the project. -> **Note** +> **Note** > Nushell is [similar to compiled languages][Nushell compiled] rather than typical dynamic languages like Python, so these concepts are relevant for Nushell. Static dependencies: @@ -120,7 +120,7 @@ as long as it has `METADATA_FILE` telling `nupm` what to do. Nushell's module design conflates CLI interface with API -- they are the same. Not all of the below are of the same priority. -> **Note** +> **Note** > commands like `list`, `install`, `search`, `uninstall`, `update`, ..., i.e. should > - print short descriptions by default > - print long descriptions with `--long-description (-l)` @@ -161,7 +161,7 @@ Nushell's module design conflates CLI interface with API -- they are the same. N - publish package to a repository - **NOT SUPPORTED FOR NOW**: the repository will be a *GitHub* repo with packages submitted by PRs to start with -The following are for Python-style global overlays, we might need to re-think this for local package overlays: +The following are for Python-style global overlays, we might need to re-think this for local package overlays: - `nupm overlay new` - create a new global overlay (Python's virtual environment style) - `--local` flag could generate an overlay locally from the currently opened project diff --git a/nupm/registry.nu b/nupm/registry.nu index 53b576c..c4bd746 100644 --- a/nupm/registry.nu +++ b/nupm/registry.nu @@ -16,13 +16,13 @@ export def list []: nothing -> table { } -# TODO # Show detailed information about a specific registry -# @example "Show registry information" { nupm registry describe nupm } -# export def describe [ -# name: string # Name of the registry -# ]: nothing -> table { -# } +# returning a list of package names, type, and version +@example "Show registry information" { nupm registry describe nupm } +export def describe [ + registry: string # Name of the registry +]: nothing -> table { +} # Add a new registry @example "Add a new registry" { nupm registry add my-registry https://example.com/registry.nuon } @@ -74,6 +74,8 @@ export def --env set-url [ print $"Registry '($name)' URL updated successfully." } +# https://www.nushell.sh/book/configuration.html#macos-keeping-usr-bin-open-as-open +alias nu-rename = rename # Rename a registry @example "Rename a registry" { nupm registry rename my-registry our-registry } export def --env rename [ @@ -81,7 +83,7 @@ export def --env rename [ new_name: string, --save, # Whether to commit the change to the registry index ] { - $env.nupm.registries = $env.nupm.registries | ^rename --column { $name: $new_name } + $env.nupm.registries = $env.nupm.registries | nu-rename --column { $name: $new_name } if $save { $env.nupm.registries | save --force $env.nupm.index-path diff --git a/tests/mod.nu b/tests/mod.nu index 4b6521b..a024f0f 100644 --- a/tests/mod.nu +++ b/tests/mod.nu @@ -219,3 +219,78 @@ export def registry-add [] { assert equal $another_reg.url "./local-registry.nuon" } } + +export def registry-set-url [] { + with-test-env { + # Add a registry first + nupm registry add test-registry https://example.com/test.nuon + + # Update the registry URL + nupm registry set-url test-registry https://updated-example.com/registry.nuon + + # Verify URL was updated + let registries = nupm registry list + let test_reg = $registries | where name == "test-registry" | first + assert equal $test_reg.url "https://updated-example.com/registry.nuon" + + # Update again to different URL + nupm registry set-url test-registry ./local-path.nuon + + let registries_updated = nupm registry list + let test_reg_updated = $registries_updated | where name == "test-registry" | first + assert equal $test_reg_updated.url "./local-path.nuon" + } +} + +export def registry-remove [] { + with-test-env { + # Add registries first + nupm registry add test-registry https://example.com/test.nuon + nupm registry add another-registry https://another.com/registry.nuon + + # Verify both were added + let registries_before = nupm registry list + assert equal ($registries_before | length) 3 # 1 default + 2 added + + # Remove one registry + nupm registry remove test-registry + + # Verify registry was removed + let registries_after = nupm registry list + assert equal ($registries_after | length) 2 + assert equal ($registries_after | where name == "test-registry" | length) 0 + assert equal ($registries_after | where name == "another-registry" | length) 1 + + # Remove the other registry + nupm registry remove another-registry + + let registries_final = nupm registry list + assert equal ($registries_final | length) 1 # Only default registry left + } +} + +export def registry-rename [] { + with-test-env { + # Add a registry first + nupm registry add test-registry https://example.com/test.nuon + + # Rename the registry + nupm registry rename test-registry renamed-registry + + # Verify registry was renamed + let registries = nupm registry list + assert equal ($registries | where name == "test-registry" | length) 0 + assert equal ($registries | where name == "renamed-registry" | length) 1 + + let renamed_reg = $registries | where name == "renamed-registry" | first + assert equal $renamed_reg.url "https://example.com/test.nuon" + + # Rename again + nupm registry rename renamed-registry final-name + + let registries_final = nupm registry list + let final_reg = $registries_final | where name == "final-name" | first + assert equal $final_reg.url "https://example.com/test.nuon" + assert equal ($registries_final | where name == "renamed-registry" | length) 0 + } +} From 12d95c114566912cf051f457cbcb183fe6ac6737 Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Thu, 26 Jun 2025 15:52:50 -0500 Subject: [PATCH 15/32] initial naive registry describe impl --- nupm/registry.nu | 32 ++++++++++++++++++++++++++++++++ tests/mod.nu | 26 ++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/nupm/registry.nu b/nupm/registry.nu index c4bd746..c8e84f7 100644 --- a/nupm/registry.nu +++ b/nupm/registry.nu @@ -22,6 +22,38 @@ export def list []: nothing -> table { export def describe [ registry: string # Name of the registry ]: nothing -> table { + if not ($registry in $env.nupm.registries) { + throw-error $"Registry '($registry)' not found" + } + + let registry_url = $env.nupm.registries | get $registry + + try { + let registry_data = if ($registry_url | path exists) { + open $registry_url + } else { + http get $registry_url + } + + $registry_data | each {|entry| + let package_data = if ($registry_url | path exists) { + let package_path = $registry_url | path dirname | path join $entry.path + open $package_path + } else { + let package_url = $registry_url | url parse | update path ($entry.path) | url join + http get $package_url + } + + { + name: $entry.name, + type: $package_data.type, + version: $package_data.version, + description: ($package_data.description? | default "") + } + } + } catch {|err| + throw-error $"Failed to fetch registry data from '($registry_url)': ($err.msg)" + } } # Add a new registry diff --git a/tests/mod.nu b/tests/mod.nu index a024f0f..cfc85c5 100644 --- a/tests/mod.nu +++ b/tests/mod.nu @@ -294,3 +294,29 @@ export def registry-rename [] { assert equal ($registries_final | where name == "renamed-registry" | length) 0 } } + +export def registry-describe [] { + with-test-env { + # Describe the test registry that's already configured + let description = nupm registry describe test + + # Verify we get package information + assert ($description | length > 0) + + # Check for expected packages from the test registry + let spam_script = $description | where name == "spam_script" | first + assert equal $spam_script.name "spam_script" + assert equal $spam_script.type "script" + assert equal $spam_script.version "0.2.0" + + # Test error case with non-existent registry + let describe_result = try { + nupm registry describe non-existent-registry + "should not reach here" + } catch {|err| + $err.msg + } + + assert ("Registry 'non-existent-registry' not found" in $describe_result) + } +} From fe5b26c352b89af61e0e58ddcd27c492e37980f2 Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Thu, 26 Jun 2025 17:03:34 -0500 Subject: [PATCH 16/32] registry describe passing test --- nupm/registry.nu | 130 ++++++++++++++++++++++++++++++++++++----- nupm/utils/registry.nu | 32 +++++----- tests/mod.nu | 79 +++++++++++++++++++++---- 3 files changed, 203 insertions(+), 38 deletions(-) diff --git a/nupm/registry.nu b/nupm/registry.nu index c8e84f7..e85c431 100644 --- a/nupm/registry.nu +++ b/nupm/registry.nu @@ -15,42 +15,72 @@ export def list []: nothing -> table { $env.nupm.registries | transpose name url | sort-by name } +def describe-comp [] { + list | get name +} # Show detailed information about a specific registry # returning a list of package names, type, and version @example "Show registry information" { nupm registry describe nupm } export def describe [ - registry: string # Name of the registry + registry: string@describe-comp # Name of the registry ]: nothing -> table { + use utils/dirs.nu cache-dir + if not ($registry in $env.nupm.registries) { throw-error $"Registry '($registry)' not found" } let registry_url = $env.nupm.registries | get $registry - + let registry_cache_dir = cache-dir --ensure | path join $registry + let cached_registry = $registry_cache_dir | path join "registry.nuon" + try { - let registry_data = if ($registry_url | path exists) { + # Always check cache first, only fall back to URL if cache doesn't exist + let registry_data = if ($cached_registry | path exists) { + open $cached_registry + } else if ($registry_url | path exists) { + # Local registry file open $registry_url } else { - http get $registry_url + # Remote registry - fetch and cache + let data = http get $registry_url + mkdir $registry_cache_dir + $data | save $cached_registry + $data } - + $registry_data | each {|entry| - let package_data = if ($registry_url | path exists) { + let package_cache_path = $registry_cache_dir | path join $"($entry.name).nuon" + + # Always check cache first for package data too + let package_file_data = if ($package_cache_path | path exists) { + open $package_cache_path + } else if ($registry_url | path exists) { + # Local package file let package_path = $registry_url | path dirname | path join $entry.path open $package_path } else { - let package_url = $registry_url | url parse | update path ($entry.path) | url join - http get $package_url + # Remote package - fetch and cache + let base_url = $registry_url | url parse + let package_url = $base_url | update path ($base_url.path | path dirname | path join $entry.path) | url join + let data = http get $package_url + $data | save $package_cache_path + $data } - - { - name: $entry.name, - type: $package_data.type, - version: $package_data.version, - description: ($package_data.description? | default "") + + # Package data is a table of versions for this package + $package_file_data | each {|pkg| + { + name: $pkg.name, + # TODO rename package metadata type field to source + # to avoid confustion with custom|script|module type enumberable + source: $pkg.type, + version: $pkg.version, + # description: ($pkg.description? | default "") + } } - } + } | flatten } catch {|err| throw-error $"Failed to fetch registry data from '($registry_url)': ($err.msg)" } @@ -124,6 +154,76 @@ export def --env rename [ print $"Registry '($name)' renamed successfully." } +# Fetch and cache registry data locally +@example "Fetch a specific registry" { nupm registry fetch nupm } +@example "Fetch all registries" { nupm registry fetch --all } +export def fetch [ + name?: string, # Name of the registry to fetch (optional if --all is used) + --all, # Fetch all configured registries +] { + use utils/dirs.nu cache-dir + + if $all { + # Fetch all registries + let registries = $env.nupm.registries | transpose name url + print $"Fetching ($registries | length) registries..." + + $registries | each {|reg| + fetch-registry $reg.name $reg.url + } + + print "All registries fetched successfully." + } else if ($name | is-empty) { + throw-error "Please specify a registry name or use --all flag" + } else { + if not ($name in $env.nupm.registries) { + throw-error $"Registry '($name)' not found" + } + + let registry_url = $env.nupm.registries | get $name + fetch-registry $name $registry_url + + print $"Registry '($name)' fetched successfully." + } +} + +# Helper function to fetch a single registry +def fetch-registry [name: string, url: string] { + use utils/dirs.nu cache-dir + + let registry_cache_dir = cache-dir --ensure | path join $name + mkdir $registry_cache_dir + + if ($url | path exists) { + print $"Registry '($name)' is local, copying to cache..." + cp $url ($registry_cache_dir | path join "registry.nuon") + + # Copy package files if they exist locally + let registry_data = open $url + $registry_data | each {|entry| + let package_path = $url | path dirname | path join $entry.path + if ($package_path | path exists) { + cp $package_path ($registry_cache_dir | path join $"($entry.name).nuon") + } + } + } else { + print $"Fetching registry '($name)' from ($url)..." + + # Fetch registry index + let registry_data = http get $url + $registry_data | save --force ($registry_cache_dir | path join "registry.nuon") + + # Fetch all package metadata files + $registry_data | each {|entry| + print $" Fetching package ($entry.name)..." + let base_url = $url | url parse + let package_url = $base_url | update path ($base_url.path | path dirname | path join $entry.path) | url join + let package_data = http get $package_url + $package_data | save --force ($registry_cache_dir | path join $"($entry.name).nuon") + } + } +} + # Initialize registry_idx.nuon with default registries @example "Initialize registry list" { nupm registry init-index } diff --git a/nupm/utils/registry.nu b/nupm/utils/registry.nu index aef631b..a4c7a9e 100644 --- a/nupm/utils/registry.nu +++ b/nupm/utils/registry.nu @@ -47,19 +47,23 @@ export def search-package [ } else { try { - let reg = http get $url_or_path - - # why didn't this line create the cache? - let reg_file = cache-dir --ensure - | path join registry $'($name).nuon' - - mkdir ($reg_file | path dirname) - $reg | save --force $reg_file + let registry_cache_dir = cache-dir --ensure | path join $name + let reg_file = $registry_cache_dir | path join "registry.nuon" + + let reg = if ($reg_file | path exists) { + open $reg_file + } else { + let data = http get $url_or_path + mkdir $registry_cache_dir + $data | save --force $reg_file + $data + } { reg: $reg path: $reg_file is_url: true + cache_dir: $registry_cache_dir } } catch { throw-error $"Cannot open '($url_or_path)' as a file or URL." @@ -72,15 +76,17 @@ export def search-package [ let pkg_files = $registry.reg | where $name_matcher let pkgs = $pkg_files | each {|row| - let pkg_file_path = $registry.path - | path dirname - | path join $row.path + let pkg_file_path = if $registry.is_url { + $registry.cache_dir | path join $"($row.name).nuon" + } else { + $registry.path | path dirname | path join $row.path + } - let hash = if ($pkg_file_path | path type) == file { + let hash = if ($pkg_file_path | path exists) { $pkg_file_path | hash-file } - if $registry.is_url and $hash != $row.hash { + if $registry.is_url and (not ($pkg_file_path | path exists) or $hash != $row.hash) { let url = $url_or_path | url update-name $row.path http get $url | save --force $pkg_file_path } diff --git a/tests/mod.nu b/tests/mod.nu index cfc85c5..893f1bb 100644 --- a/tests/mod.nu +++ b/tests/mod.nu @@ -1,4 +1,4 @@ -use std assert +use std [ assert log ] use ../nupm/utils/dirs.nu [ tmp-dir BASE_NUPM_CONFIG ] use ../nupm @@ -60,7 +60,6 @@ export def install-module [] { export def install-custom [] { with-test-env { - use std/log log info CUSTOM log info $env.nupm.home nupm install --path tests/packages/spam_custom @@ -301,14 +300,21 @@ export def registry-describe [] { let description = nupm registry describe test # Verify we get package information - assert ($description | length > 0) - + assert (($description | length) > 0) + # Check for expected packages from the test registry - let spam_script = $description | where name == "spam_script" | first - assert equal $spam_script.name "spam_script" - assert equal $spam_script.type "script" - assert equal $spam_script.version "0.2.0" - + let spam_scripts = $description | where name == "spam_script" + assert (($spam_scripts | length) > 0) + + # Check that we have the latest version + let spam_script_latest = $spam_scripts | where version == "0.2.0" + if (($spam_script_latest | length) > 0) { + let pkg = $spam_script_latest | first + assert equal $pkg.name "spam_script" + assert equal $pkg.source "local" + assert equal $pkg.version "0.2.0" + } + # Test error case with non-existent registry let describe_result = try { nupm registry describe non-existent-registry @@ -316,7 +322,60 @@ export def registry-describe [] { } catch {|err| $err.msg } - + assert ("Registry 'non-existent-registry' not found" in $describe_result) } } + +export def registry-fetch [] { + with-test-env { + # Test fetch with local registry (test registry) + let fetch_result = try { + nupm registry fetch test + "success" + } catch {|err| + $err.msg + } + + # For local registry, fetch should succeed + assert equal $fetch_result "success" + + # Verify cache directory was created + let cache_dir = $env.nupm.cache | path join test + assert ($cache_dir | path exists) + assert (($cache_dir | path join "registry.nuon") | path exists) + + # Verify package files were cached + let spam_script_cache = $cache_dir | path join "spam_script.nuon" + assert ($spam_script_cache | path exists) + + # Test --all flag (only with local registries to avoid network issues) + let fetch_all_result = try { + nupm registry fetch --all + "success" + } catch {|err| + $err.msg + } + + assert equal $fetch_all_result "success" + + # Test error cases + let no_name_result = try { + nupm registry fetch + "should not reach here" + } catch {|err| + $err.msg + } + + assert ("Please specify a registry name or use --all flag" in $no_name_result) + + let invalid_registry_result = try { + nupm registry fetch invalid-registry + "should not reach here" + } catch {|err| + $err.msg + } + + assert ("Registry 'invalid-registry' not found" in $invalid_registry_result) + } +} From 2907762ac619d79dda5a4c94b43955eefd4dbe73 Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Thu, 26 Jun 2025 17:22:47 -0500 Subject: [PATCH 17/32] moved open-index to module root --- nupm/mod.nu | 12 +++++++++++- nupm/registry.nu | 38 +++++++++++--------------------------- 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/nupm/mod.nu b/nupm/mod.nu index 964913f..ce45bca 100644 --- a/nupm/mod.nu +++ b/nupm/mod.nu @@ -1,7 +1,6 @@ use std/log use utils/dirs.nu [ nupm-home-prompt BASE_NUPM_CONFIG ] -use registry.nu open-index export module install.nu export module publish.nu @@ -10,6 +9,17 @@ export module search.nu export module status.nu export module test.nu +def open-index []: nothing -> record { + mut index = {} + if ($env.nupm.index-path | path exists) { + if not (($env.nupm.index-path | path type) == "file") { + throw-error $"($env.nupm.index-path) is not a filepath" + } + $index = open $env.nupm.index-path + } + + $index +} diff --git a/nupm/registry.nu b/nupm/registry.nu index e85c431..392f405 100644 --- a/nupm/registry.nu +++ b/nupm/registry.nu @@ -74,7 +74,7 @@ export def describe [ { name: $pkg.name, # TODO rename package metadata type field to source - # to avoid confustion with custom|script|module type enumberable + # to avoid confusion with custom|script|module type enumberable source: $pkg.type, version: $pkg.version, # description: ($pkg.description? | default "") @@ -158,11 +158,9 @@ export def --env rename [ @example "Fetch a specific registry" { nupm registry fetch nupm } @example "Fetch all registries" { nupm registry fetch --all } export def fetch [ - name?: string, # Name of the registry to fetch (optional if --all is used) + registry?: string, # Name of the registry to fetch (optional if --all is used) --all, # Fetch all configured registries ] { - use utils/dirs.nu cache-dir - if $all { # Fetch all registries let registries = $env.nupm.registries | transpose name url @@ -173,17 +171,17 @@ export def fetch [ } print "All registries fetched successfully." - } else if ($name | is-empty) { + } else if ($registry | is-empty) { throw-error "Please specify a registry name or use --all flag" } else { - if not ($name in $env.nupm.registries) { - throw-error $"Registry '($name)' not found" + if not ($registry in $env.nupm.registries) { + throw-error $"Registry '($registry)' not found" } - let registry_url = $env.nupm.registries | get $name - fetch-registry $name $registry_url + let registry_url = $env.nupm.registries | get $registry + fetch-registry $registry $registry_url - print $"Registry '($name)' fetched successfully." + print $"Registry '($registry)' fetched successfully." } } @@ -227,33 +225,19 @@ def fetch-registry [name: string, url: string] { # Initialize registry_idx.nuon with default registries @example "Initialize registry list" { nupm registry init-index } -export def init-index [ - - registry?: record -] { +export def init-index [] { if not (nupm-home-prompt) { throw-error "Cannot create nupm.home directory." } - if ($env.nupm.registries | path exists) { + if ($env.nupm.index-path | path exists) { print $"Registry list already exists at ($env.nupm.index-path)" return } $env.nupm.registries | save $env.nupm.index-path - print $"Registry list initialized at ($env.nupm.index-path)" + print $"Registry index initialized at ($env.nupm.index-path)" } -# Initialize nupm.registries value -export def open-index []: nothing -> record { - if ($env.nupm.index-path | path exists) { - if not (($env.nupm.index-path | path type) == "file") { - throw-error $"($env.nupm.index-path) is not a filepath" - } - open $env.nupm.index-path | return - } - - {} -} From 11a7a38368be754673062024203a8437c8e9d022 Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Thu, 26 Jun 2025 17:24:02 -0500 Subject: [PATCH 18/32] removed log calls intest --- tests/mod.nu | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/mod.nu b/tests/mod.nu index 893f1bb..939c555 100644 --- a/tests/mod.nu +++ b/tests/mod.nu @@ -1,4 +1,4 @@ -use std [ assert log ] +use std [ assert ] use ../nupm/utils/dirs.nu [ tmp-dir BASE_NUPM_CONFIG ] use ../nupm @@ -60,8 +60,6 @@ export def install-module [] { export def install-custom [] { with-test-env { - log info CUSTOM - log info $env.nupm.home nupm install --path tests/packages/spam_custom assert installed [plugins nu_plugin_test] From b054db3148af27462c9dbc1aa2af1163abb1a45e Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Thu, 26 Jun 2025 17:30:23 -0500 Subject: [PATCH 19/32] update registry header comment --- nupm/registry.nu | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/nupm/registry.nu b/nupm/registry.nu index 392f405..1dc9ce3 100644 --- a/nupm/registry.nu +++ b/nupm/registry.nu @@ -3,7 +3,7 @@ use utils/dirs.nu [nupm-home-prompt] use utils/log.nu throw-error -# Show information about configured registries +# Manage nupm registires @example "List all configured registries" { nupm registry } export def main []: nothing -> table { list @@ -15,10 +15,8 @@ export def list []: nothing -> table { $env.nupm.registries | transpose name url | sort-by name } -def describe-comp [] { - list | get name -} +def describe-comp [] { list | get name } # Show detailed information about a specific registry # returning a list of package names, type, and version @example "Show registry information" { nupm registry describe nupm } From aa12a95d5121c70a7a651130b5e188324fc0c992 Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Thu, 26 Jun 2025 17:40:10 -0500 Subject: [PATCH 20/32] update registry init shim --- nupm/registry.nu | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/nupm/registry.nu b/nupm/registry.nu index 1dc9ce3..95a3485 100644 --- a/nupm/registry.nu +++ b/nupm/registry.nu @@ -221,9 +221,7 @@ def fetch-registry [name: string, url: string] { } -# Initialize registry_idx.nuon with default registries -@example "Initialize registry list" { nupm registry init-index } -export def init-index [] { +def init-index [] { if not (nupm-home-prompt) { throw-error "Cannot create nupm.home directory." } @@ -239,3 +237,16 @@ export def init-index [] { print $"Registry index initialized at ($env.nupm.index-path)" } + +# Initialize a new nupm registry or a registry index if the `--index` flag is +# passed in +@example "Initialize registry index" { nupm registry init --index } +@example "Initialize registry list" { nupm registry init-index } +export def init [--index] { + if $index { + init-index + return + } + # TODO initialize registry index here +} + From d5d6699fd978248dc04549090bf80434fb4e0581 Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Fri, 27 Jun 2025 15:34:13 -0500 Subject: [PATCH 21/32] partial test pass --- nupm/install.nu | 2 +- nupm/mod.nu | 2 +- nupm/utils/completions.nu | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/nupm/install.nu b/nupm/install.nu index 274a0d1..93d6da0 100644 --- a/nupm/install.nu +++ b/nupm/install.nu @@ -106,6 +106,7 @@ def install-path [ do { flatten-nupm-env + cd $tmp_dir ^$nu.current-exe $build_file ($pkg_dir | path join 'nupm.nuon') } @@ -241,7 +242,6 @@ export def main [ --force(-f) # Overwrite already installed package --no-confirm # Allows to bypass the interactive confirmation, useful for scripting ]: nothing -> nothing { - echo $env.nupm if not (nupm-home-prompt --no-confirm=$no_confirm) { return } diff --git a/nupm/mod.nu b/nupm/mod.nu index ce45bca..6f89f3c 100644 --- a/nupm/mod.nu +++ b/nupm/mod.nu @@ -1,4 +1,3 @@ -use std/log use utils/dirs.nu [ nupm-home-prompt BASE_NUPM_CONFIG ] @@ -39,6 +38,7 @@ export-env { from_string: { |s| $s | from nuon } to_string: { |v| $v | to nuon } } + use std/log [] } # Nushell Package Manager diff --git a/nupm/utils/completions.nu b/nupm/utils/completions.nu index f371c5f..9700bbd 100644 --- a/nupm/utils/completions.nu +++ b/nupm/utils/completions.nu @@ -1,3 +1,3 @@ export def complete-registries [] { - $env.nupm.registries? | default {} | columns + $env.nupm?.registries? | default {} | columns } From bac9659fb3799c0322e172963b970dfe739644c4 Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Fri, 27 Jun 2025 15:36:03 -0500 Subject: [PATCH 22/32] all tests pass --- nupm/mod.nu | 1 + 1 file changed, 1 insertion(+) diff --git a/nupm/mod.nu b/nupm/mod.nu index 6f89f3c..cfdade0 100644 --- a/nupm/mod.nu +++ b/nupm/mod.nu @@ -1,3 +1,4 @@ +use std/log use utils/dirs.nu [ nupm-home-prompt BASE_NUPM_CONFIG ] From baaf4f42103ade7634bd15dab981a288773e3279 Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Fri, 27 Jun 2025 15:53:49 -0500 Subject: [PATCH 23/32] revert test mod closuer --- nupm/utils/registry.nu | 4 ++-- tests/mod.nu | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/nupm/utils/registry.nu b/nupm/utils/registry.nu index a4c7a9e..620ed90 100644 --- a/nupm/utils/registry.nu +++ b/nupm/utils/registry.nu @@ -49,7 +49,7 @@ export def search-package [ try { let registry_cache_dir = cache-dir --ensure | path join $name let reg_file = $registry_cache_dir | path join "registry.nuon" - + let reg = if ($reg_file | path exists) { open $reg_file } else { @@ -82,7 +82,7 @@ export def search-package [ $registry.path | path dirname | path join $row.path } - let hash = if ($pkg_file_path | path exists) { + let hash = if ($pkg_file_path | path type) == file { $pkg_file_path | hash-file } diff --git a/tests/mod.nu b/tests/mod.nu index 939c555..59f5d24 100644 --- a/tests/mod.nu +++ b/tests/mod.nu @@ -1,4 +1,4 @@ -use std [ assert ] +use std assert use ../nupm/utils/dirs.nu [ tmp-dir BASE_NUPM_CONFIG ] use ../nupm From 8542850a7d0acc45e7052bc099b626d06fe64edb Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Sat, 28 Jun 2025 15:32:49 -0500 Subject: [PATCH 24/32] simplify variable setting --- nupm/mod.nu | 32 +++++++++----------------------- nupm/utils/dirs.nu | 27 ++++++++++++++++++--------- nupm/utils/registry.nu | 13 +++++++++++++ tests/mod.nu | 10 +++++----- 4 files changed, 45 insertions(+), 37 deletions(-) diff --git a/nupm/mod.nu b/nupm/mod.nu index cfdade0..38551bd 100644 --- a/nupm/mod.nu +++ b/nupm/mod.nu @@ -1,6 +1,7 @@ use std/log use utils/dirs.nu [ nupm-home-prompt BASE_NUPM_CONFIG ] +use utils/registry.nu open-index export module install.nu export module publish.nu @@ -9,32 +10,17 @@ export module search.nu export module status.nu export module test.nu -def open-index []: nothing -> record { - mut index = {} - if ($env.nupm.index-path | path exists) { - if not (($env.nupm.index-path | path type) == "file") { - throw-error $"($env.nupm.index-path) is not a filepath" - } - $index = open $env.nupm.index-path - } - - $index -} - - export-env { # Ensure that $env.nupm is always set when running nupm. Any missing variaables are set by `$BASE_NUPM_CONFIG` - $env.nupm = { - home: ($env.nupm?.home? | default $BASE_NUPM_CONFIG.default-home) - cache: ($env.nupm?.cache? | default $BASE_NUPM_CONFIG.default-cache) - temp: ($env.nupm?.temp? | default $BASE_NUPM_CONFIG.default-temp) - registries: ($env.nupm?.registries? | default $BASE_NUPM_CONFIG.default-registries) - } | merge $BASE_NUPM_CONFIG - # for now, filename hardcoded for simplicity - $env.nupm.index-path = ($env.nupm.home | path join "registry_index.nuon") - # overwrite filevalues with those found in config - $env.nupm.registries = open-index | merge $env.nupm.registries + $env.nupm = ($env.nupm? | default {} + | merge $BASE_NUPM_CONFIG + # set missing values to default while retaining + # $env.nupm.default + | merge $BASE_NUPM_CONFIG.default + ) + # read from registry index but don't overwrite registires already present in $env.nupm.registries + $env.nupm.registries = $env.nupm.index-path | open-index | merge $env.nupm.registries $env.ENV_CONVERSIONS.nupm = { from_string: { |s| $s | from nuon } to_string: { |v| $v | to nuon } diff --git a/nupm/utils/dirs.nu b/nupm/utils/dirs.nu index 8c42bab..cb3942b 100644 --- a/nupm/utils/dirs.nu +++ b/nupm/utils/dirs.nu @@ -1,12 +1,21 @@ # Base values for nupm that are used as defaults if not present in `$env.nupm` +export const REGISTRY_IDX_FILENAME = "registry_index.nuon" export const BASE_NUPM_CONFIG = { - default-home: ($nu.default-config-dir | path join "nupm") - default-cache: ($nu.default-config-dir | path join nupm cache) - default-temp: ($nu.temp-path | path join "nupm") - default-registries: { - nupm: 'https://raw.githubusercontent.com/nushell/nupm/main/registry/registry.nuon' - } + default: { + home: ($nu.default-config-dir | path join nupm) + cache: ($nu.default-config-dir | path join nupm cache) + index-path: ($nu.default-config-dir | path join nupm $REGISTRY_IDX_FILENAME) + temp: ($nu.temp-path | path join nupm) + registries: { + nupm: 'https://raw.githubusercontent.com/nushell/nupm/main/registry/registry.nuon' + } + } } + +def env-colour [env_name: string]: nothing -> string { + $"(ansi purple)($env_name)(ansi reset)" +} + # Directories and related utilities used in nupm # Prompt to create $env.nupm.home if it does not exist and some sanity checks. @@ -15,7 +24,7 @@ export const BASE_NUPM_CONFIG = { export def nupm-home-prompt [--no-confirm]: nothing -> bool { if 'home' not-in $env.nupm { error make --unspanned { - msg: "Internal error: nupm.home environment variable is not set" + msg: $"Internal error: (env-colour "$env.nupm.home") is not set" } } @@ -23,7 +32,7 @@ export def nupm-home-prompt [--no-confirm]: nothing -> bool { if ($env.nupm.home | path type) != 'dir' { error make --unspanned { msg: ($"Root directory ($env.nupm.home) exists, but is not a" - + " directory. Make sure $env.nupm.home points at a valid" + + $" directory. Make sure (env-colour "$env.nupm.home") points at a valid" + " directory and try again.") } } @@ -84,7 +93,7 @@ export def cache-dir [--ensure]: nothing -> path { } export def tmp-dir [subdir: string, --ensure]: nothing -> path { - let d = $BASE_NUPM_CONFIG.default-temp + let d = $BASE_NUPM_CONFIG.default.temp | path join $subdir | path join (random chars -l 8) diff --git a/nupm/utils/registry.nu b/nupm/utils/registry.nu index 620ed90..469f813 100644 --- a/nupm/utils/registry.nu +++ b/nupm/utils/registry.nu @@ -108,3 +108,16 @@ export def search-package [ $regs | where not ($it.pkgs | is-empty) } + + +export def open-index []: path -> record { + let index_file = $in + if ($index_file | path exists) { + if not (($index_file | path type) == "file") { + throw-error $"($index_file) is not a filepath" + } + return (open $index_file) + } + + {} +} diff --git a/tests/mod.nu b/tests/mod.nu index 59f5d24..9760fa3 100644 --- a/tests/mod.nu +++ b/tests/mod.nu @@ -136,14 +136,14 @@ export def nupm-status-module [] { } export def env-vars-are-set [] { - $env.nupm = null + hide-env nupm --ignore-errors use ../nupm - assert equal $env.nupm.home $BASE_NUPM_CONFIG.default-home - assert equal $env.nupm.temp $BASE_NUPM_CONFIG.default-temp - assert equal $env.nupm.cache $BASE_NUPM_CONFIG.default-cache - assert equal $env.nupm.registries $BASE_NUPM_CONFIG.default-registries + assert equal $env.nupm.home $BASE_NUPM_CONFIG.default.home + assert equal $env.nupm.temp $BASE_NUPM_CONFIG.default.temp + assert equal $env.nupm.cache $BASE_NUPM_CONFIG.default.cache + assert equal $env.nupm.registries $BASE_NUPM_CONFIG.default.registries } export def generate-local-registry [] { From af2a6adf70033d5cbb8c2a006b42c725e82b6526 Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Mon, 7 Jul 2025 12:32:05 -0500 Subject: [PATCH 25/32] reverted nested nupm config --- README.md | 10 +++---- docs/design/README.md | 18 ++++++------ nupm/install.nu | 2 +- nupm/mod.nu | 40 +++++++++++++++----------- nupm/publish.nu | 2 +- nupm/registry.nu | 40 +++++++++++++------------- nupm/search.nu | 2 +- nupm/utils/completions.nu | 2 +- nupm/utils/dirs.nu | 60 +++++++++++++++++++++++---------------- nupm/utils/misc.nu | 8 +++--- nupm/utils/registry.nu | 10 +++---- tests/mod.nu | 43 +++++++++++++++------------- toolkit.nu | 16 +++++------ 13 files changed, 137 insertions(+), 116 deletions(-) diff --git a/README.md b/README.md index 5dd056b..761e5d3 100644 --- a/README.md +++ b/README.md @@ -32,27 +32,27 @@ Both of the above commands will make `nupm` and all its subcommands available in > ``` ## :gear: configuration [[toc](#table-of-content)] -One can change the location of the Nupm directory with `$env.nupm.home`, e.g. +One can change the location of the Nupm directory with `$env.NUPM_HOME`, e.g. ```nushell # env.nu -$env.nupm.home = ($env.XDG_DATA_HOME | path join "nupm") +$env.NUPM_HOME = ($env.XDG_DATA_HOME | path join "nupm") ``` -Because Nupm will install modules and scripts in `{{nupm-home}}/modules/` and `{{nupm-home}}/scripts/` respectively, it is a good idea to add these paths to `$env.NU_LIB_DIRS` and `$env.PATH` respectively, e.g. if you have `$env.nupm.home` defined: +Because Nupm will install modules and scripts in `{{nupm-home}}/modules/` and `{{nupm-home}}/scripts/` respectively, it is a good idea to add these paths to `$env.NU_LIB_DIRS` and `$env.PATH` respectively, e.g. if you have `$env.NUPM_HOME` defined: ```nushell # env.nu $env.NU_LIB_DIRS = [ ... - ($env.nupm.home | path join "modules") + ($env.NUPM_HOME | path join "modules") ] $env.PATH = ( $env.PATH | split row (char esep) | .... - | prepend ($env.nupm.home | path join "scripts") + | prepend ($env.NUPM_HOME | path join "scripts") | uniq ) ``` diff --git a/docs/design/README.md b/docs/design/README.md index 5a51a13..a8c260b 100644 --- a/docs/design/README.md +++ b/docs/design/README.md @@ -7,7 +7,7 @@ This file collects design ideas and directions. The intention is iterate on this > - `METADATA_FILE`: the file containing the metadata of a package, > e.g. `project.nuon`, `metadata.json` or `nupm.nuon` > (name inspired by Julia's `Project.toml` or Rust's `Cargo.toml`) -> - `nupm.home`: the location of all the `nupm` files, overlays, scripts, libraries, ..., +> - `NUPM_HOME`: the location of all the `nupm` files, overlays, scripts, libraries, ..., > e.g. `~/.nupm/`, `$env.XDG_DATA_HOME/nupm/` or `~/.local/share/nupm/` # Table of content @@ -37,7 +37,7 @@ spam ``` * meant as a runnable script, equivalent of Rust's binary project * could use the `.nush` extension if we agree to support it -* installed under `nupm.home/bin/` +* installed under `NUPM_HOME/bin/` 2. Module ``` @@ -47,7 +47,7 @@ spam └── mod.nu ``` * meant as a library to be `use`d or `overlay use`d, equivalent of Rust's library project -* installed under `nupm.home/modules/` +* installed under `NUPM_HOME/modules/` You can also install non-Nushell packages as well using a "custom" project type where you specify a `build.nu` installation script (e.g., you can install Nushell itself with it). @@ -69,18 +69,18 @@ Related to that is a lock file: It is intended to describe exactly the dependenc The overlays could be used to achieve all three goals at the same time. When installing a dependency for a package * `nupm` adds entry to a **lock file** (this should be the only file you need to 100% replicate the environment) -* A .nu file (module) is auto-generated from the lock file and contains export statements like `export module nupm.home/cache/packages/spam-v16.4.0-124ptnpbf/spam`. Calling `overlay use` on the file will activate your virtual environment, now you have a per-project environment -* This file can be installed into a global location that's in your `NU_LIB_DIRS` (e.g., `nupm.home/overlays`) -- now you have a global Python-like virtual environment - * Each overlay under `nupm.home/overlays` will mimic the main nupm.home structure, e.g., for an overlay `spam` there will be `nupm.home/overlays/spam/bin`, `nupm.home/overlays/spam/modules` (`nupm.home/overlays/spam/overlays`? It might not be the best idea to have it recursive) +* A .nu file (module) is auto-generated from the lock file and contains export statements like `export module NUPM_HOME/cache/packages/spam-v16.4.0-124ptnpbf/spam`. Calling `overlay use` on the file will activate your virtual environment, now you have a per-project environment +* This file can be installed into a global location that's in your `NU_LIB_DIRS` (e.g., `NUPM_HOME/overlays`) -- now you have a global Python-like virtual environment + * Each overlay under `NUPM_HOME/overlays` will mimic the main NUPM_HOME structure, e.g., for an overlay `spam` there will be `NUPM_HOME/overlays/spam/bin`, `NUPM_HOME/overlays/spam/modules` (`NUPM_HOME/overlays/spam/overlays`? It might not be the best idea to have it recursive) Each package would basically have its own overlay. This overlay file (it's just a module) could be used to also handle dependencies. If your project depends on `foo` and `bar` which both depend on `spam` but different versions, they could both import the different versions privately in their own overlay files and in your project's overlay file would be just `export use path/to/foo` and `export use path/to/bar`. This should prevent name clashing of `spam`. The only problem that needs to be figured out is how to tell `foo` to be aware of its overlay. ## Installation, bootstrapping [[toc](#table-of-content)] Requires these actions from the user (this should be kept as minimal as possible): -* Add `nupm.home/bin` to PATH (install location for binary projects) -* Add `nupm.home/modules` to NU_LIB_DIRS -* Add `nupm.home/overlays` to NU_LIB_DIRS +* Add `NUPM_HOME/bin` to PATH (install location for binary projects) +* Add `NUPM_HOME/modules` to NU_LIB_DIRS +* Add `NUPM_HOME/overlays` to NU_LIB_DIRS * Make the `nupm` command available somehow (e.g., `use` inside `config.nu`) > :warning: **WIP** diff --git a/nupm/install.nu b/nupm/install.nu index 93d6da0..540656b 100644 --- a/nupm/install.nu +++ b/nupm/install.nu @@ -236,7 +236,7 @@ def fetch-package [ export def main [ package # Name, path, or link to the package --registry: string@complete-registries # Which registry to use (either a name - # in $env.nupm.registries or a path) + # in $env.NUPM_REGISTRIES or a path) --pkg-version(-v): string # Package version to install --path # Install package from a directory with nupm.nuon given by 'name' --force(-f) # Overwrite already installed package diff --git a/nupm/mod.nu b/nupm/mod.nu index 38551bd..9b4f79d 100644 --- a/nupm/mod.nu +++ b/nupm/mod.nu @@ -1,6 +1,10 @@ use std/log -use utils/dirs.nu [ nupm-home-prompt BASE_NUPM_CONFIG ] +use utils/dirs.nu [ + DEFAULT_NUPM_HOME DEFAULT_NUPM_TEMP DEFAULT_NUPM_CACHE + DEFAULT_NUPM_REGISTRIES DEFAULT_NUPM_INDEX_PATH nupm-home-prompt +] + use utils/registry.nu open-index export module install.nu @@ -12,19 +16,23 @@ export module test.nu export-env { - # Ensure that $env.nupm is always set when running nupm. Any missing variaables are set by `$BASE_NUPM_CONFIG` - $env.nupm = ($env.nupm? | default {} - | merge $BASE_NUPM_CONFIG - # set missing values to default while retaining - # $env.nupm.default - | merge $BASE_NUPM_CONFIG.default - ) - # read from registry index but don't overwrite registires already present in $env.nupm.registries - $env.nupm.registries = $env.nupm.index-path | open-index | merge $env.nupm.registries - $env.ENV_CONVERSIONS.nupm = { - from_string: { |s| $s | from nuon } - to_string: { |v| $v | to nuon } - } + # Ensure that $env.NUPM_HOME is always set when running nupm. Any missing + # $env.NUPM_HOME during nupm execution is a bug. + $env.NUPM_HOME = ($env.NUPM_HOME? | default $DEFAULT_NUPM_HOME) + + # Ensure temporary path is set. + $env.NUPM_TEMP = ($env.NUPM_TEMP? | default $DEFAULT_NUPM_TEMP) + + # Ensure install cache is set + $env.NUPM_CACHE = ($env.NUPM_CACHE? | default $DEFAULT_NUPM_CACHE) + + # check for the index path + $env.NUPM_INDEX_PATH = ($env.NUPM_INDEX_PATH? | default $DEFAULT_NUPM_INDEX_PATH) + + # read from registry index but don't overwrite registires already present in $env.NUPM_REGISTRIES + $env.NUPM_REGISTRIES = ($env.NUPM_INDEX_PATH | open-index + | merge ($env.NUPM_REGISTRIES? | default $DEFAULT_NUPM_REGISTRIES)) + use std/log [] } @@ -34,8 +42,8 @@ export-env { # Nushell packages including modules, scripts, and custom packages. # # Configuration: -# Set `nupm.home` environment variable to change installation directory -# Set `nupm.registries` to configure package registries +# Set `NUPM_HOME` environment variable to change installation directory +# Set `NUPM_REGISTRIES` to configure package registries @example "Install a package from a local directory" { nupm install my-package --path } @example "Publish a package" { nupm publish my-registry.nuon --local --save } @example "Search for specific version" { nupm search my-package --pkg-version 1.2.0 } diff --git a/nupm/publish.nu b/nupm/publish.nu index da9089e..9ed7d19 100644 --- a/nupm/publish.nu +++ b/nupm/publish.nu @@ -222,7 +222,7 @@ def guess-revision []: nothing -> string { def get-registry-path []: string -> path { let registry = $in - $env.nupm.registries | get -i $registry | default ($registry | path expand) + $env.NUPM_REGISTRIES | get -i $registry | default ($registry | path expand) } def open-registry-file []: path -> table { diff --git a/nupm/registry.nu b/nupm/registry.nu index 95a3485..9b16cec 100644 --- a/nupm/registry.nu +++ b/nupm/registry.nu @@ -12,7 +12,7 @@ export def main []: nothing -> table { # List all configured registries @example "List all registries with details" { nupm registry list } export def list []: nothing -> table { - $env.nupm.registries | transpose name url | sort-by name + $env.NUPM_REGISTRIES | transpose name url | sort-by name } @@ -25,11 +25,11 @@ export def describe [ ]: nothing -> table { use utils/dirs.nu cache-dir - if not ($registry in $env.nupm.registries) { + if not ($registry in $env.NUPM_REGISTRIES) { throw-error $"Registry '($registry)' not found" } - let registry_url = $env.nupm.registries | get $registry + let registry_url = $env.NUPM_REGISTRIES | get $registry let registry_cache_dir = cache-dir --ensure | path join $registry let cached_registry = $registry_cache_dir | path join "registry.nuon" @@ -91,13 +91,13 @@ export def --env add [ url: string, # URL or path to the registry --save, # Whether to commit the change to the registry index ] { - if ($name in $env.nupm.registries) { + if ($name in $env.NUPM_REGISTRIES) { throw-error $"Registry '($name)' already exists. Use 'nupm registry update' to modify it." } - $env.nupm.registries = $env.nupm.registries | insert $name $url + $env.NUPM_REGISTRIES = $env.NUPM_REGISTRIES | insert $name $url if $save { - $env.nupm.registries | save --force $env.nupm.index-path + $env.NUPM_REGISTRIES | save --force $env.NUPM_INDEX_PATH } print $"Registry '($name)' added successfully." @@ -109,10 +109,10 @@ export def --env remove [ name: string # Name of the registry to remove --save, # Whether to commit the change to the registry index ] { - $env.nupm.registries = $env.nupm.registries | reject $name + $env.NUPM_REGISTRIES = $env.NUPM_REGISTRIES | reject $name if $save { - $env.nupm.registries | save --force $env.nupm.index-path + $env.NUPM_REGISTRIES | save --force $env.NUPM_INDEX_PATH } print $"Registry '($name)' removed successfully." @@ -125,10 +125,10 @@ export def --env set-url [ url: string, --save, # Whether to commit the change to the registry index ]: nothing -> nothing { - $env.nupm.registries = $env.nupm.registries | update $name $url + $env.NUPM_REGISTRIES = $env.NUPM_REGISTRIES | update $name $url if $save { - $env.nupm.registries | save --force $env.nupm.index-path + $env.NUPM_REGISTRIES | save --force $env.NUPM_INDEX_PATH } print $"Registry '($name)' URL updated successfully." @@ -143,10 +143,10 @@ export def --env rename [ new_name: string, --save, # Whether to commit the change to the registry index ] { - $env.nupm.registries = $env.nupm.registries | nu-rename --column { $name: $new_name } + $env.NUPM_REGISTRIES = $env.NUPM_REGISTRIES | nu-rename --column { $name: $new_name } if $save { - $env.nupm.registries | save --force $env.nupm.index-path + $env.NUPM_REGISTRIES | save --force $env.NUPM_INDEX_PATH } print $"Registry '($name)' renamed successfully." @@ -161,7 +161,7 @@ export def fetch [ ] { if $all { # Fetch all registries - let registries = $env.nupm.registries | transpose name url + let registries = $env.NUPM_REGISTRIES | transpose name url print $"Fetching ($registries | length) registries..." $registries | each {|reg| @@ -172,11 +172,11 @@ export def fetch [ } else if ($registry | is-empty) { throw-error "Please specify a registry name or use --all flag" } else { - if not ($registry in $env.nupm.registries) { + if not ($registry in $env.NUPM_REGISTRIES) { throw-error $"Registry '($registry)' not found" } - let registry_url = $env.nupm.registries | get $registry + let registry_url = $env.NUPM_REGISTRIES | get $registry fetch-registry $registry $registry_url print $"Registry '($registry)' fetched successfully." @@ -223,18 +223,18 @@ def fetch-registry [name: string, url: string] { def init-index [] { if not (nupm-home-prompt) { - throw-error "Cannot create nupm.home directory." + throw-error "Cannot create NUPM_HOME directory." } - if ($env.nupm.index-path | path exists) { - print $"Registry list already exists at ($env.nupm.index-path)" + if ($env.NUPM_INDEX_PATH | path exists) { + print $"Registry list already exists at ($env.NUPM_INDEX_PATH)" return } - $env.nupm.registries | save $env.nupm.index-path + $env.NUPM_REGISTRIES | save $env.NUPM_INDEX_PATH - print $"Registry index initialized at ($env.nupm.index-path)" + print $"Registry index initialized at ($env.NUPM_INDEX_PATH)" } diff --git a/nupm/search.nu b/nupm/search.nu index e62db55..e8739f5 100644 --- a/nupm/search.nu +++ b/nupm/search.nu @@ -21,7 +21,7 @@ use utils/version.nu filter-by-version export def main [ package # Name, path, or link to the package --registry: string@complete-registries # Which registry to use (either a name - # in $env.nupm.registries or a path) + # in $env.NUPM_REGISTRIES or a path) --pkg-version(-v): string # Package version to install --exact-match(-e) # Match package name exactly ]: nothing -> table { diff --git a/nupm/utils/completions.nu b/nupm/utils/completions.nu index 9700bbd..d1d37ab 100644 --- a/nupm/utils/completions.nu +++ b/nupm/utils/completions.nu @@ -1,3 +1,3 @@ export def complete-registries [] { - $env.nupm?.registries? | default {} | columns + $env.NUPM_REGISTRIES? | default {} | columns } diff --git a/nupm/utils/dirs.nu b/nupm/utils/dirs.nu index cb3942b..400432d 100644 --- a/nupm/utils/dirs.nu +++ b/nupm/utils/dirs.nu @@ -1,38 +1,48 @@ -# Base values for nupm that are used as defaults if not present in `$env.nupm` +# Directories and related utilities used in nupm + +# Default installation path for nupm packages +export const DEFAULT_NUPM_HOME = ($nu.default-config-dir | path join "nupm") + +# Default path for installation cache +export const DEFAULT_NUPM_CACHE = ($nu.default-config-dir + | path join nupm cache) + +# Default temporary path for various nupm purposes +export const DEFAULT_NUPM_TEMP = ($nu.temp-path | path join "nupm") + +# Default registry index filename export const REGISTRY_IDX_FILENAME = "registry_index.nuon" -export const BASE_NUPM_CONFIG = { - default: { - home: ($nu.default-config-dir | path join nupm) - cache: ($nu.default-config-dir | path join nupm cache) - index-path: ($nu.default-config-dir | path join nupm $REGISTRY_IDX_FILENAME) - temp: ($nu.temp-path | path join nupm) - registries: { - nupm: 'https://raw.githubusercontent.com/nushell/nupm/main/registry/registry.nuon' - } - } + +# Default registry +export const DEFAULT_NUPM_REGISTRIES = { + nupm: 'https://raw.githubusercontent.com/nushell/nupm/main/registry/registry.nuon' } +# default path for the nupm registry index +export const DEFAULT_NUPM_INDEX_PATH = ($nu.default-config-dir | path join nupm $REGISTRY_IDX_FILENAME) + + def env-colour [env_name: string]: nothing -> string { $"(ansi purple)($env_name)(ansi reset)" } # Directories and related utilities used in nupm -# Prompt to create $env.nupm.home if it does not exist and some sanity checks. +# Prompt to create $env.NUPM_HOME if it does not exist and some sanity checks. # # returns true if the root directory exists or has been created, false otherwise export def nupm-home-prompt [--no-confirm]: nothing -> bool { - if 'home' not-in $env.nupm { + if 'NUPM_HOME' not-in $env { error make --unspanned { - msg: $"Internal error: (env-colour "$env.nupm.home") is not set" + msg: $"Internal error: (env-colour "$env.NUPM_HOME") is not set" } } - if ($env.nupm.home | path exists) { - if ($env.nupm.home | path type) != 'dir' { + if ($env.NUPM_HOME | path exists) { + if ($env.NUPM_HOME | path type) != 'dir' { error make --unspanned { - msg: ($"Root directory ($env.nupm.home) exists, but is not a" - + $" directory. Make sure (env-colour "$env.nupm.home") points at a valid" + msg: ($"Root directory ($env.NUPM_HOME) exists, but is not a" + + $" directory. Make sure (env-colour "$env.NUPM_HOME") points at a valid" + " directory and try again.") } } @@ -41,7 +51,7 @@ export def nupm-home-prompt [--no-confirm]: nothing -> bool { } if $no_confirm { - mkdir $env.nupm.home + mkdir $env.NUPM_HOME return true } @@ -49,7 +59,7 @@ export def nupm-home-prompt [--no-confirm]: nothing -> bool { while ($answer | str downcase) not-in [ y n ] { $answer = (input ( - $'Root directory "($env.nupm.home)" does not exist.' + $'Root directory "($env.NUPM_HOME)" does not exist.' + ' Do you want to create it? [y/n] ')) } @@ -57,13 +67,13 @@ export def nupm-home-prompt [--no-confirm]: nothing -> bool { return false } - mkdir $env.nupm.home + mkdir $env.NUPM_HOME true } export def script-dir [--ensure]: nothing -> path { - let d = $env.nupm.home | path join scripts + let d = $env.NUPM_HOME | path join scripts if $ensure { mkdir $d @@ -73,7 +83,7 @@ export def script-dir [--ensure]: nothing -> path { } export def module-dir [--ensure]: nothing -> path { - let d = $env.nupm.home | path join modules + let d = $env.NUPM_HOME | path join modules if $ensure { mkdir $d @@ -83,7 +93,7 @@ export def module-dir [--ensure]: nothing -> path { } export def cache-dir [--ensure]: nothing -> path { - let d = $env.nupm.cache + let d = $env.NUPM_CACHE if $ensure { mkdir $d @@ -93,7 +103,7 @@ export def cache-dir [--ensure]: nothing -> path { } export def tmp-dir [subdir: string, --ensure]: nothing -> path { - let d = $BASE_NUPM_CONFIG.default.temp + let d = $DEFAULT_NUPM_TEMP | path join $subdir | path join (random chars -l 8) diff --git a/nupm/utils/misc.nu b/nupm/utils/misc.nu index 730bb0f..a24b06b 100644 --- a/nupm/utils/misc.nu +++ b/nupm/utils/misc.nu @@ -68,8 +68,8 @@ export module url { # workaround for https://github.com/nushell/nushell/issues/16036 export def --env flatten-nupm-env [] { - $env.NUPM_HOME = $env.nupm.home - $env.NUPM_CACHE = $env.nupm.cache - $env.NUPM_TEMP = $env.nupm.temp - $env.NUPM_REGISTRIES = $env.nupm.registries | to nuon + $env.NUPM_HOME = $env.NUPM_HOME + $env.NUPM_CACHE = $env.NUPM_CACHE + $env.NUPM_TEMP = $env.NUPM_TEMP + $env.NUPM_REGISTRIES = $env.NUPM_REGISTRIES | to nuon } diff --git a/nupm/utils/registry.nu b/nupm/utils/registry.nu index 469f813..4ee85ad 100644 --- a/nupm/utils/registry.nu +++ b/nupm/utils/registry.nu @@ -16,16 +16,16 @@ export def search-package [ --registry: string # Which registry to use (name or path) --exact-match # Searched package name must match exactly ]: nothing -> table { - let registries = if (not ($registry | is-empty)) and ($registry in $env.nupm.registries) { - # If $registry is a valid column in $env.nupm.registries, use that - { $registry : ($env.nupm.registries | get $registry) } + let registries = if (not ($registry | is-empty)) and ($registry in $env.NUPM_REGISTRIES) { + # If $registry is a valid column in $env.NUPM_REGISTRIES, use that + { $registry : ($env.NUPM_REGISTRIES | get $registry) } } else if (not ($registry | is-empty)) and ($registry | path exists) { # If $registry is a path, use that let reg_name = $registry | path parse | get stem { $reg_name: $registry } } else { - # Otherwise use $env.nupm.registries as-is - $env.nupm.registries + # Otherwise use $env.NUPM_REGISTRIES as-is + $env.NUPM_REGISTRIES } let name_matcher: closure = if $exact_match { diff --git a/tests/mod.nu b/tests/mod.nu index 9760fa3..dad0436 100644 --- a/tests/mod.nu +++ b/tests/mod.nu @@ -1,6 +1,7 @@ use std assert -use ../nupm/utils/dirs.nu [ tmp-dir BASE_NUPM_CONFIG ] +use ../nupm/utils/dirs.nu +use ../nupm/utils/dirs.nu tmp-dir use ../nupm const TEST_REGISTRY_PATH = ([tests packages registry registry.nuon] | path join) @@ -13,12 +14,10 @@ def with-test-env [closure: closure]: nothing -> nothing { let reg = { test: $TEST_REGISTRY_PATH } with-env { - nupm: { - home: $home - cache: $cache - temp: $temp - registries: $reg - } + NUPM_HOME: $home + NUPM_CACHE: $cache + NUPM_TEMP: $temp + NUPM_REGISTRIES: $reg } $closure rm --recursive $temp @@ -27,14 +26,14 @@ def with-test-env [closure: closure]: nothing -> nothing { } # Examples: -# make sure `$env.nupm.home/scripts/script.nu` exists +# make sure `$env.NUPM_HOME/scripts/script.nu` exists # > assert installed [scripts script.nu] def "assert installed" [path_tokens: list] { - assert ($path_tokens | prepend $env.nupm.home | path join | path exists) + assert ($path_tokens | prepend $env.NUPM_HOME | path join | path exists) } def check-file-content [content: string] { - let file_str = open ($env.nupm.home | path join scripts spam_script.nu) + let file_str = open ($env.NUPM_HOME | path join scripts spam_script.nu) assert ($file_str | str contains $content) } @@ -68,7 +67,7 @@ export def install-custom [] { export def install-from-local-registry [] { with-test-env { - $env.nupm.registries = {} + $env.NUPM_REGISTRIES = {} nupm install --registry $TEST_REGISTRY_PATH spam_script check-file-content 0.2.0 } @@ -93,7 +92,7 @@ export def install-with-version [] { export def install-multiple-registries-fail [] { with-test-env { - $env.nupm.registries.test2 = $TEST_REGISTRY_PATH + $env.NUPM_REGISTRIES.test2 = $TEST_REGISTRY_PATH let out = try { nupm install spam_script @@ -136,23 +135,27 @@ export def nupm-status-module [] { } export def env-vars-are-set [] { - hide-env nupm --ignore-errors + (hide-env --ignore-errors + NUPM_HOME + NUPM_TEMP + NUPM_CACHE + NUPM_REGISTRIES) use ../nupm - assert equal $env.nupm.home $BASE_NUPM_CONFIG.default.home - assert equal $env.nupm.temp $BASE_NUPM_CONFIG.default.temp - assert equal $env.nupm.cache $BASE_NUPM_CONFIG.default.cache - assert equal $env.nupm.registries $BASE_NUPM_CONFIG.default.registries + assert equal $env.NUPM_HOME $dirs.DEFAULT_NUPM_HOME + assert equal $env.NUPM_TEMP $dirs.DEFAULT_NUPM_TEMP + assert equal $env.NUPM_CACHE $dirs.DEFAULT_NUPM_CACHE + assert equal $env.NUPM_REGISTRIES $dirs.DEFAULT_NUPM_REGISTRIES } export def generate-local-registry [] { with-test-env { - mkdir ($env.nupm.temp | path join packages registry) + mkdir ($env.NUPM_TEMP | path join packages registry) let reg_file = [tests packages registry registry.nuon] | path join let tmp_reg_file = [ - $env.nupm.temp packages registry test_registry.nuon + $env.NUPM_TEMP packages registry test_registry.nuon ] | path join @@ -339,7 +342,7 @@ export def registry-fetch [] { assert equal $fetch_result "success" # Verify cache directory was created - let cache_dir = $env.nupm.cache | path join test + let cache_dir = $env.NUPM_CACHE | path join test assert ($cache_dir | path exists) assert (($cache_dir | path join "registry.nuon") | path exists) diff --git a/toolkit.nu b/toolkit.nu index f313026..5451374 100644 --- a/toolkit.nu +++ b/toolkit.nu @@ -8,10 +8,10 @@ export def --env set-nupm-env [--clear] { rm -rf _nupm_dev } - $env.nupm.home = ($env.PWD | path join _nupm_dev) - $env.nupm.cache = ($env.PWD | path join _nupm_dev cache) - $env.nupm.temp = ($env.PWD | path join _nupm_dev tmp) - $env.nupm.registries = { nupm_dev: ($env.PWD | path join registry registry.nuon) } + $env.NUPM_HOME = ($env.PWD | path join _nupm_dev) + $env.NUPM_CACHE = ($env.PWD | path join _nupm_dev cache) + $env.NUPM_TEMP = ($env.PWD | path join _nupm_dev tmp) + $env.NUPM_REGISTRIES = { nupm_dev: ($env.PWD | path join registry registry.nuon) } if $nu.os-info.family == 'windows' and 'Path' in $env { $env.Path = ($env.Path | prepend ($env.PWD | path join _nupm_dev scripts)) @@ -24,12 +24,12 @@ export def --env set-nupm-env [--clear] { } export def print-nupm-env [] { - print $'nupm.home: ($env.nupm.home?)' - print $'nupm.cache: ($env.nupm.cache?)' - print $'nupm.temp: ($env.nupm.temp?)' + print $'NUPM_HOME: ($env.NUPM_HOME?)' + print $'NUPM_CACHE: ($env.NUPM_CACHE?)' + print $'NUPM_TEMP: ($env.NUPM_TEMP?)' print $"PATH: ($env.PATH? | default $env.Path? | default [])" print $'NU_LIB_DIRS: ($env.NU_LIB_DIRS?)' - print $'nupm.registires: ($env.nupm.registries?)' + print $'nupm.registires: ($env.NUPM_REGISTRIES?)' } # turn on pretty diffs for NUON data files From 081677b6bb0164f900e6dc401fb3fe584c8592d9 Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Mon, 7 Jul 2025 12:34:32 -0500 Subject: [PATCH 26/32] remove flaten-nupm-env --- nupm/install.nu | 3 +-- nupm/utils/misc.nu | 7 ------- toolkit.nu | 2 +- 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/nupm/install.nu b/nupm/install.nu index 540656b..e880e8c 100644 --- a/nupm/install.nu +++ b/nupm/install.nu @@ -1,7 +1,7 @@ use utils/completions.nu complete-registries use utils/dirs.nu [ nupm-home-prompt cache-dir module-dir script-dir tmp-dir ] use utils/log.nu throw-error -use utils/misc.nu [check-cols hash-fn url flatten-nupm-env] +use utils/misc.nu [check-cols hash-fn url] use utils/package.nu open-package-file use utils/registry.nu search-package use utils/version.nu filter-by-version @@ -105,7 +105,6 @@ def install-path [ let tmp_dir = tmp-dir build --ensure do { - flatten-nupm-env cd $tmp_dir ^$nu.current-exe $build_file ($pkg_dir | path join 'nupm.nuon') } diff --git a/nupm/utils/misc.nu b/nupm/utils/misc.nu index a24b06b..2daa35d 100644 --- a/nupm/utils/misc.nu +++ b/nupm/utils/misc.nu @@ -66,10 +66,3 @@ export module url { } } -# workaround for https://github.com/nushell/nushell/issues/16036 -export def --env flatten-nupm-env [] { - $env.NUPM_HOME = $env.NUPM_HOME - $env.NUPM_CACHE = $env.NUPM_CACHE - $env.NUPM_TEMP = $env.NUPM_TEMP - $env.NUPM_REGISTRIES = $env.NUPM_REGISTRIES | to nuon -} diff --git a/toolkit.nu b/toolkit.nu index 5451374..93de04c 100644 --- a/toolkit.nu +++ b/toolkit.nu @@ -29,7 +29,7 @@ export def print-nupm-env [] { print $'NUPM_TEMP: ($env.NUPM_TEMP?)' print $"PATH: ($env.PATH? | default $env.Path? | default [])" print $'NU_LIB_DIRS: ($env.NU_LIB_DIRS?)' - print $'nupm.registires: ($env.NUPM_REGISTRIES?)' + print $'NUPM_REGISTRIES: ($env.NUPM_REGISTRIES?)' } # turn on pretty diffs for NUON data files From 01b33b2f0d29fec872eca02bc2010ac5df736c63 Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Mon, 7 Jul 2025 12:50:56 -0500 Subject: [PATCH 27/32] added registry_filename constants typos reworded pretty print name --- nupm/install.nu | 4 ++-- nupm/registry.nu | 18 +++++++++--------- nupm/test.nu | 4 ++-- nupm/utils/dirs.nu | 17 +++++++++++------ nupm/utils/package.nu | 5 +++-- nupm/utils/registry.nu | 4 ++-- tests/mod.nu | 8 ++++---- 7 files changed, 33 insertions(+), 27 deletions(-) diff --git a/nupm/install.nu b/nupm/install.nu index e880e8c..213582b 100644 --- a/nupm/install.nu +++ b/nupm/install.nu @@ -1,5 +1,5 @@ use utils/completions.nu complete-registries -use utils/dirs.nu [ nupm-home-prompt cache-dir module-dir script-dir tmp-dir ] +use utils/dirs.nu [ nupm-home-prompt cache-dir module-dir script-dir tmp-dir PACKAGE_FILENAME ] use utils/log.nu throw-error use utils/misc.nu [check-cols hash-fn url] use utils/package.nu open-package-file @@ -106,7 +106,7 @@ def install-path [ do { cd $tmp_dir - ^$nu.current-exe $build_file ($pkg_dir | path join 'nupm.nuon') + ^$nu.current-exe $build_file ($pkg_dir | path join $PACKAGE_FILENAME) } rm -rf $tmp_dir diff --git a/nupm/registry.nu b/nupm/registry.nu index 9b16cec..caa8e5c 100644 --- a/nupm/registry.nu +++ b/nupm/registry.nu @@ -1,6 +1,6 @@ # Registry management for nupm -use utils/dirs.nu [nupm-home-prompt] +use utils/dirs.nu [nupm-home-prompt REGISTRY_FILENAME] use utils/log.nu throw-error # Manage nupm registires @@ -16,12 +16,12 @@ export def list []: nothing -> table { } -def describe-comp [] { list | get name } +def registry-names [] { list | get name } # Show detailed information about a specific registry # returning a list of package names, type, and version @example "Show registry information" { nupm registry describe nupm } export def describe [ - registry: string@describe-comp # Name of the registry + registry: string@registry-names ]: nothing -> table { use utils/dirs.nu cache-dir @@ -31,7 +31,7 @@ export def describe [ let registry_url = $env.NUPM_REGISTRIES | get $registry let registry_cache_dir = cache-dir --ensure | path join $registry - let cached_registry = $registry_cache_dir | path join "registry.nuon" + let cached_registry = $registry_cache_dir | path join $REGISTRY_FILENAME try { # Always check cache first, only fall back to URL if cache doesn't exist @@ -156,8 +156,8 @@ export def --env rename [ @example "Fetch a specific registry" { nupm registry fetch nupm } @example "Fetch all registries" { nupm registry fetch --all } export def fetch [ - registry?: string, # Name of the registry to fetch (optional if --all is used) - --all, # Fetch all configured registries + registry?: string@registry-names, + --all, # Fetch all configured registries ] { if $all { # Fetch all registries @@ -192,7 +192,7 @@ def fetch-registry [name: string, url: string] { if ($url | path exists) { print $"Registry '($name)' is local, copying to cache..." - cp $url ($registry_cache_dir | path join "registry.nuon") + cp $url ($registry_cache_dir | path join $REGISTRY_FILENAME) # Copy package files if they exist locally let registry_data = open $url @@ -207,10 +207,10 @@ def fetch-registry [name: string, url: string] { # Fetch registry index let registry_data = http get $url - $registry_data | save --force ($registry_cache_dir | path join "registry.nuon") + $registry_data | save --force ($registry_cache_dir | path join $REGISTRY_FILENAME) # Fetch all package metadata files - $registry_data | each {|entry| + $registry_data | par-each {|entry| print $" Fetching package ($entry.name)..." let base_url = $url | url parse let package_url = $base_url | update path ($base_url.path | path dirname | path join $entry.path) | url join diff --git a/nupm/test.nu b/nupm/test.nu index ea67e2e..9638d49 100644 --- a/nupm/test.nu +++ b/nupm/test.nu @@ -1,4 +1,4 @@ -use utils/dirs.nu [ tmp-dir find-root ] +use utils/dirs.nu [ tmp-dir find-root PACKAGE_FILENAME ] use utils/log.nu throw-error # Run tests for a nupm package @@ -28,7 +28,7 @@ export def main [ if $pkg_root == null { throw-error "package_file_not_found" ( - $'Could not find "nupm.nuon" in ($dir) or any parent directory.' + $'Could not find "($PACKAGE_FILENAME)" in ($dir) or any parent directory.' ) } diff --git a/nupm/utils/dirs.nu b/nupm/utils/dirs.nu index 400432d..55b4244 100644 --- a/nupm/utils/dirs.nu +++ b/nupm/utils/dirs.nu @@ -10,8 +10,12 @@ export const DEFAULT_NUPM_CACHE = ($nu.default-config-dir # Default temporary path for various nupm purposes export const DEFAULT_NUPM_TEMP = ($nu.temp-path | path join "nupm") -# Default registry index filename +# registry index filename export const REGISTRY_IDX_FILENAME = "registry_index.nuon" +# registry filename +export const REGISTRY_FILENAME = "registry.nuon" +# package manifest filename +export const PACKAGE_FILENAME = "nupm.nuon" # Default registry export const DEFAULT_NUPM_REGISTRIES = { @@ -22,8 +26,9 @@ export const DEFAULT_NUPM_REGISTRIES = { export const DEFAULT_NUPM_INDEX_PATH = ($nu.default-config-dir | path join nupm $REGISTRY_IDX_FILENAME) +# pretty prints an environmental variable name def env-colour [env_name: string]: nothing -> string { - $"(ansi purple)($env_name)(ansi reset)" + $"(ansi purple)$env.($env_name)(ansi reset)" } # Directories and related utilities used in nupm @@ -34,7 +39,7 @@ def env-colour [env_name: string]: nothing -> string { export def nupm-home-prompt [--no-confirm]: nothing -> bool { if 'NUPM_HOME' not-in $env { error make --unspanned { - msg: $"Internal error: (env-colour "$env.NUPM_HOME") is not set" + msg: $"Internal error: (env-colour "NUPM_HOME") is not set" } } @@ -42,7 +47,7 @@ export def nupm-home-prompt [--no-confirm]: nothing -> bool { if ($env.NUPM_HOME | path type) != 'dir' { error make --unspanned { msg: ($"Root directory ($env.NUPM_HOME) exists, but is not a" - + $" directory. Make sure (env-colour "$env.NUPM_HOME") points at a valid" + + $" directory. Make sure (env-colour "NUPM_HOME") points at a valid" + " directory and try again.") } } @@ -119,7 +124,7 @@ export def tmp-dir [subdir: string, --ensure]: nothing -> path { export def find-root [dir: path]: [ nothing -> path, nothing -> nothing] { let root_candidate = 1..($dir | path split | length) | reduce -f $dir {|_, acc| - if ($acc | path join nupm.nuon | path exists) { + if ($acc | path join $PACKAGE_FILENAME | path exists) { $acc } else { $acc | path dirname @@ -128,7 +133,7 @@ export def find-root [dir: path]: [ nothing -> path, nothing -> nothing] { # We need to do the last check in case the reduce loop ran to the end # without finding nupm.nuon - if ($root_candidate | path join nupm.nuon | path type) == 'file' { + if ($root_candidate | path join $PACKAGE_FILENAME | path type) == 'file' { $root_candidate } else { null diff --git a/nupm/utils/package.nu b/nupm/utils/package.nu index ded8d02..4e59fc4 100644 --- a/nupm/utils/package.nu +++ b/nupm/utils/package.nu @@ -1,3 +1,4 @@ +use dirs.nu PACKAGE_FILENAME # Open nupm.nuon export def open-package-file [dir: path] { if not ($dir | path exists) { @@ -6,11 +7,11 @@ export def open-package-file [dir: path] { ) } - let package_file = $dir | path join "nupm.nuon" + let package_file = $dir | path join $PACKAGE_FILENAME if not ($package_file | path exists) { throw-error "package_file_not_found" ( - $'Could not find "nupm.nuon" in ($dir) or any parent directory.' + $'Could not find "($PACKAGE_FILENAME)" in ($dir) or any parent directory.' ) } diff --git a/nupm/utils/registry.nu b/nupm/utils/registry.nu index 4ee85ad..ea928f6 100644 --- a/nupm/utils/registry.nu +++ b/nupm/utils/registry.nu @@ -1,6 +1,6 @@ # Utilities related to nupm registries -use dirs.nu cache-dir +use dirs.nu [ cache-dir REGISTRY_FILENAME ] use log.nu throw-error use misc.nu [check-cols url hash-file hash-fn] @@ -48,7 +48,7 @@ export def search-package [ } else { try { let registry_cache_dir = cache-dir --ensure | path join $name - let reg_file = $registry_cache_dir | path join "registry.nuon" + let reg_file = $registry_cache_dir | path join $REGISTRY_FILENAME let reg = if ($reg_file | path exists) { open $reg_file diff --git a/tests/mod.nu b/tests/mod.nu index dad0436..9b95d61 100644 --- a/tests/mod.nu +++ b/tests/mod.nu @@ -1,10 +1,10 @@ use std assert use ../nupm/utils/dirs.nu -use ../nupm/utils/dirs.nu tmp-dir +use ../nupm/utils/dirs.nu [ tmp-dir REGISTRY_FILENAME ] use ../nupm -const TEST_REGISTRY_PATH = ([tests packages registry registry.nuon] | path join) +const TEST_REGISTRY_PATH = ([tests packages registry $REGISTRY_FILENAME] | path join) def with-test-env [closure: closure]: nothing -> nothing { @@ -153,7 +153,7 @@ export def generate-local-registry [] { with-test-env { mkdir ($env.NUPM_TEMP | path join packages registry) - let reg_file = [tests packages registry registry.nuon] | path join + let reg_file = $TEST_REGISTRY_PATH let tmp_reg_file = [ $env.NUPM_TEMP packages registry test_registry.nuon ] @@ -344,7 +344,7 @@ export def registry-fetch [] { # Verify cache directory was created let cache_dir = $env.NUPM_CACHE | path join test assert ($cache_dir | path exists) - assert (($cache_dir | path join "registry.nuon") | path exists) + assert (($cache_dir | path join $REGISTRY_FILENAME) | path exists) # Verify package files were cached let spam_script_cache = $cache_dir | path join "spam_script.nuon" From b2e85f2d0ba912177e7ee34201f5d7cb805e2757 Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Thu, 10 Jul 2025 12:34:32 -0500 Subject: [PATCH 28/32] removed fetch command --- nupm/registry.nu | 152 ++++++++++++----------------------------------- tests/mod.nu | 53 ----------------- 2 files changed, 39 insertions(+), 166 deletions(-) diff --git a/nupm/registry.nu b/nupm/registry.nu index caa8e5c..0068520 100644 --- a/nupm/registry.nu +++ b/nupm/registry.nu @@ -33,55 +33,51 @@ export def describe [ let registry_cache_dir = cache-dir --ensure | path join $registry let cached_registry = $registry_cache_dir | path join $REGISTRY_FILENAME - try { - # Always check cache first, only fall back to URL if cache doesn't exist - let registry_data = if ($cached_registry | path exists) { - open $cached_registry + # Always check cache first, only fall back to URL if cache doesn't exist + let registry_data = if ($cached_registry | path exists) { + open $cached_registry + } else if ($registry_url | path exists) { + # Local registry file + open $registry_url + } else { + # Remote registry - fetch and cache + let data = http get $registry_url + mkdir $registry_cache_dir + $data | save $cached_registry + $data + } + + $registry_data | each {|entry| + let package_cache_path = $registry_cache_dir | path join $"($entry.name).nuon" + + # Always check cache first for package data too + let package_file_data = if ($package_cache_path | path exists) { + open $package_cache_path } else if ($registry_url | path exists) { - # Local registry file - open $registry_url + # Local package file + let package_path = $registry_url | path dirname | path join $entry.path + open $package_path } else { - # Remote registry - fetch and cache - let data = http get $registry_url - mkdir $registry_cache_dir - $data | save $cached_registry + # Remote package - fetch and cache + let base_url = $registry_url | url parse + let package_url = $base_url | update path ($base_url.path | path dirname | path join $entry.path) | url join + let data = http get $package_url + $data | save $package_cache_path $data } - $registry_data | each {|entry| - let package_cache_path = $registry_cache_dir | path join $"($entry.name).nuon" - - # Always check cache first for package data too - let package_file_data = if ($package_cache_path | path exists) { - open $package_cache_path - } else if ($registry_url | path exists) { - # Local package file - let package_path = $registry_url | path dirname | path join $entry.path - open $package_path - } else { - # Remote package - fetch and cache - let base_url = $registry_url | url parse - let package_url = $base_url | update path ($base_url.path | path dirname | path join $entry.path) | url join - let data = http get $package_url - $data | save $package_cache_path - $data + # Package data is a table of versions for this package + $package_file_data | each {|pkg| + { + name: $pkg.name, + # TODO rename package metadata type field to source + # to avoid confusion with custom|script|module type enumberable + source: $pkg.type, + version: $pkg.version, + # description: ($pkg.description? | default "") } - - # Package data is a table of versions for this package - $package_file_data | each {|pkg| - { - name: $pkg.name, - # TODO rename package metadata type field to source - # to avoid confusion with custom|script|module type enumberable - source: $pkg.type, - version: $pkg.version, - # description: ($pkg.description? | default "") - } - } - } | flatten - } catch {|err| - throw-error $"Failed to fetch registry data from '($registry_url)': ($err.msg)" - } + } + } | flatten } # Add a new registry @@ -152,75 +148,6 @@ export def --env rename [ print $"Registry '($name)' renamed successfully." } -# Fetch and cache registry data locally -@example "Fetch a specific registry" { nupm registry fetch nupm } -@example "Fetch all registries" { nupm registry fetch --all } -export def fetch [ - registry?: string@registry-names, - --all, # Fetch all configured registries -] { - if $all { - # Fetch all registries - let registries = $env.NUPM_REGISTRIES | transpose name url - print $"Fetching ($registries | length) registries..." - - $registries | each {|reg| - fetch-registry $reg.name $reg.url - } - - print "All registries fetched successfully." - } else if ($registry | is-empty) { - throw-error "Please specify a registry name or use --all flag" - } else { - if not ($registry in $env.NUPM_REGISTRIES) { - throw-error $"Registry '($registry)' not found" - } - - let registry_url = $env.NUPM_REGISTRIES | get $registry - fetch-registry $registry $registry_url - - print $"Registry '($registry)' fetched successfully." - } -} - -# Helper function to fetch a single registry -def fetch-registry [name: string, url: string] { - use utils/dirs.nu cache-dir - - let registry_cache_dir = cache-dir --ensure | path join $name - mkdir $registry_cache_dir - - if ($url | path exists) { - print $"Registry '($name)' is local, copying to cache..." - cp $url ($registry_cache_dir | path join $REGISTRY_FILENAME) - - # Copy package files if they exist locally - let registry_data = open $url - $registry_data | each {|entry| - let package_path = $url | path dirname | path join $entry.path - if ($package_path | path exists) { - cp $package_path ($registry_cache_dir | path join $"($entry.name).nuon") - } - } - } else { - print $"Fetching registry '($name)' from ($url)..." - - # Fetch registry index - let registry_data = http get $url - $registry_data | save --force ($registry_cache_dir | path join $REGISTRY_FILENAME) - - # Fetch all package metadata files - $registry_data | par-each {|entry| - print $" Fetching package ($entry.name)..." - let base_url = $url | url parse - let package_url = $base_url | update path ($base_url.path | path dirname | path join $entry.path) | url join - let package_data = http get $package_url - $package_data | save --force ($registry_cache_dir | path join $"($entry.name).nuon") - } - } -} - - def init-index [] { if not (nupm-home-prompt) { throw-error "Cannot create NUPM_HOME directory." @@ -241,7 +168,6 @@ def init-index [] { # Initialize a new nupm registry or a registry index if the `--index` flag is # passed in @example "Initialize registry index" { nupm registry init --index } -@example "Initialize registry list" { nupm registry init-index } export def init [--index] { if $index { init-index diff --git a/tests/mod.nu b/tests/mod.nu index 9b95d61..b84beab 100644 --- a/tests/mod.nu +++ b/tests/mod.nu @@ -327,56 +327,3 @@ export def registry-describe [] { assert ("Registry 'non-existent-registry' not found" in $describe_result) } } - -export def registry-fetch [] { - with-test-env { - # Test fetch with local registry (test registry) - let fetch_result = try { - nupm registry fetch test - "success" - } catch {|err| - $err.msg - } - - # For local registry, fetch should succeed - assert equal $fetch_result "success" - - # Verify cache directory was created - let cache_dir = $env.NUPM_CACHE | path join test - assert ($cache_dir | path exists) - assert (($cache_dir | path join $REGISTRY_FILENAME) | path exists) - - # Verify package files were cached - let spam_script_cache = $cache_dir | path join "spam_script.nuon" - assert ($spam_script_cache | path exists) - - # Test --all flag (only with local registries to avoid network issues) - let fetch_all_result = try { - nupm registry fetch --all - "success" - } catch {|err| - $err.msg - } - - assert equal $fetch_all_result "success" - - # Test error cases - let no_name_result = try { - nupm registry fetch - "should not reach here" - } catch {|err| - $err.msg - } - - assert ("Please specify a registry name or use --all flag" in $no_name_result) - - let invalid_registry_result = try { - nupm registry fetch invalid-registry - "should not reach here" - } catch {|err| - $err.msg - } - - assert ("Registry 'invalid-registry' not found" in $invalid_registry_result) - } -} From 4c5558191bdc2785b692ff9607af993f8536bf42 Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Thu, 10 Jul 2025 12:35:28 -0500 Subject: [PATCH 29/32] remoted editorconfig --- .editorconfig | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index d741e40..0000000 --- a/.editorconfig +++ /dev/null @@ -1,9 +0,0 @@ -root = true - -[*] -end_of_line = lf -charset = utf-8 -trim_trailing_whitespace = true -insert_final_newline = true -indent_style = space -indent_size = 4 From 102d9701bc07102aa31eea9d0b0ddabf77eac794 Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Wed, 16 Jul 2025 15:05:07 -0500 Subject: [PATCH 30/32] PR feedback on addtion of registry values --- README.md | 27 +++++++++++---------------- nupm/registry.nu | 25 ++++++++++++++++--------- nupm/utils/log.nu | 3 +++ nupm/utils/registry.nu | 22 ++++++++++++++-------- 4 files changed, 44 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 761e5d3..48382fc 100644 --- a/README.md +++ b/README.md @@ -32,29 +32,24 @@ Both of the above commands will make `nupm` and all its subcommands available in > ``` ## :gear: configuration [[toc](#table-of-content)] -One can change the location of the Nupm directory with `$env.NUPM_HOME`, e.g. +One can change the location of the Nupm directory with `$env.nupm.home`, e.g. ```nushell # env.nu -$env.NUPM_HOME = ($env.XDG_DATA_HOME | path join "nupm") +$env.nupm.home = ($env.XDG_DATA_HOME | path join "nupm") ``` -Because Nupm will install modules and scripts in `{{nupm-home}}/modules/` and `{{nupm-home}}/scripts/` respectively, it is a good idea to add these paths to `$env.NU_LIB_DIRS` and `$env.PATH` respectively, e.g. if you have `$env.NUPM_HOME` defined: +If you would like installed modules, scripts, and plugins to show up in [nushell search +paths](https://www.nushell.sh/book/configuration.html#launch-stages), set the +`nu_search_path` to `true` before calling `use nupm`: ```nushell # env.nu - -$env.NU_LIB_DIRS = [ - ... - ($env.NUPM_HOME | path join "modules") -] - -$env.PATH = ( - $env.PATH - | split row (char esep) - | .... - | prepend ($env.NUPM_HOME | path join "scripts") - | uniq -) +$env.nupm = { + home: "path/to/my_home" + config: { nu_search_path: true } +} +# ... +use path/to/nupm ``` ## :rocket: usage [[toc](#table-of-content)] diff --git a/nupm/registry.nu b/nupm/registry.nu index 0068520..78a7d19 100644 --- a/nupm/registry.nu +++ b/nupm/registry.nu @@ -1,7 +1,8 @@ # Registry management for nupm use utils/dirs.nu [nupm-home-prompt REGISTRY_FILENAME] -use utils/log.nu throw-error +use utils/log.nu [throw-error UNIMPLEMENTED] +use utils/registry.nu registry-cache # Manage nupm registires @example "List all configured registries" { nupm registry } @@ -30,25 +31,25 @@ export def describe [ } let registry_url = $env.NUPM_REGISTRIES | get $registry - let registry_cache_dir = cache-dir --ensure | path join $registry - let cached_registry = $registry_cache_dir | path join $REGISTRY_FILENAME + let cache = registry-cache $registry + let cached_registry = $cache.dir | path join $REGISTRY_FILENAME # Always check cache first, only fall back to URL if cache doesn't exist - let registry_data = if ($cached_registry | path exists) { - open $cached_registry + let registry_data = if ($cache.file | path exists) { + open $cache.file } else if ($registry_url | path exists) { # Local registry file open $registry_url } else { # Remote registry - fetch and cache let data = http get $registry_url - mkdir $registry_cache_dir - $data | save $cached_registry + mkdir $cache.dir + $data | save $cache.file $data } $registry_data | each {|entry| - let package_cache_path = $registry_cache_dir | path join $"($entry.name).nuon" + let package_cache_path = $cache.dir | path join $"($entry.name).nuon" # Always check cache first for package data too let package_file_data = if ($package_cache_path | path exists) { @@ -91,12 +92,17 @@ export def --env add [ throw-error $"Registry '($name)' already exists. Use 'nupm registry update' to modify it." } $env.NUPM_REGISTRIES = $env.NUPM_REGISTRIES | insert $name $url + mut add_success_msg = $"Registry '($name)' added successfully" if $save { $env.NUPM_REGISTRIES | save --force $env.NUPM_INDEX_PATH + $add_success_msg = $add_success_msg | append $" and written to ($env.NUPM_INDEX_PATH)." | str join " " + + } else { + $add_success_msg = $add_success_msg | append $". To commit the change to disk, use the `--save` flag." | str join " " } - print $"Registry '($name)' added successfully." + print $add_success_msg } # Remove a registry @@ -174,5 +180,6 @@ export def init [--index] { return } # TODO initialize registry index here + throw-error UNIMPLEMENTED "`nupm registry --index` is not implemented." } diff --git a/nupm/utils/log.nu b/nupm/utils/log.nu index 9024116..bdff6ab 100644 --- a/nupm/utils/log.nu +++ b/nupm/utils/log.nu @@ -1,3 +1,6 @@ +# denotes an error msg that a section of code is yet to be implemented +export const UNIMPLEMENTED = "unimplemented" + export def throw-error [ error: string text?: string diff --git a/nupm/utils/registry.nu b/nupm/utils/registry.nu index ea928f6..0672662 100644 --- a/nupm/utils/registry.nu +++ b/nupm/utils/registry.nu @@ -10,6 +10,13 @@ export const REG_COLS = [ name path hash ] # Columns of a registry package file export const REG_PKG_COLS = [ name version path type info ] + +# return the respective registry cache directory and package index +export def registry-cache [name: string]: nothing -> record { + let dir = cache-dir --ensure | path join "registry" $name + { dir: $dir, file: ($dir | path join $REGISTRY_FILENAME) } +} + # Search for a package in a registry export def search-package [ package: string # Name of the package @@ -47,23 +54,22 @@ export def search-package [ } else { try { - let registry_cache_dir = cache-dir --ensure | path join $name - let reg_file = $registry_cache_dir | path join $REGISTRY_FILENAME + let cache = registry-cache $name - let reg = if ($reg_file | path exists) { - open $reg_file + let reg = if ($cache.file | path exists) { + open $cache.file } else { let data = http get $url_or_path - mkdir $registry_cache_dir - $data | save --force $reg_file + mkdir $cache.dir + $data | save --force $cache.file $data } { reg: $reg - path: $reg_file + path: $cache.file is_url: true - cache_dir: $registry_cache_dir + cache_dir: $cache.dir } } catch { throw-error $"Cannot open '($url_or_path)' as a file or URL." From 78848feb4a7933bf4203201cc1072dda51cc8c4e Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Wed, 16 Jul 2025 15:14:45 -0500 Subject: [PATCH 31/32] revert README --- README.md | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 48382fc..761e5d3 100644 --- a/README.md +++ b/README.md @@ -32,24 +32,29 @@ Both of the above commands will make `nupm` and all its subcommands available in > ``` ## :gear: configuration [[toc](#table-of-content)] -One can change the location of the Nupm directory with `$env.nupm.home`, e.g. +One can change the location of the Nupm directory with `$env.NUPM_HOME`, e.g. ```nushell # env.nu -$env.nupm.home = ($env.XDG_DATA_HOME | path join "nupm") +$env.NUPM_HOME = ($env.XDG_DATA_HOME | path join "nupm") ``` -If you would like installed modules, scripts, and plugins to show up in [nushell search -paths](https://www.nushell.sh/book/configuration.html#launch-stages), set the -`nu_search_path` to `true` before calling `use nupm`: +Because Nupm will install modules and scripts in `{{nupm-home}}/modules/` and `{{nupm-home}}/scripts/` respectively, it is a good idea to add these paths to `$env.NU_LIB_DIRS` and `$env.PATH` respectively, e.g. if you have `$env.NUPM_HOME` defined: ```nushell # env.nu -$env.nupm = { - home: "path/to/my_home" - config: { nu_search_path: true } -} -# ... -use path/to/nupm + +$env.NU_LIB_DIRS = [ + ... + ($env.NUPM_HOME | path join "modules") +] + +$env.PATH = ( + $env.PATH + | split row (char esep) + | .... + | prepend ($env.NUPM_HOME | path join "scripts") + | uniq +) ``` ## :rocket: usage [[toc](#table-of-content)] From 919865b6ac13fe8e287ec72698d3bac58d13f61f Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Wed, 16 Jul 2025 15:49:03 -0500 Subject: [PATCH 32/32] updated formatting messages --- nupm/registry.nu | 38 ++++++++++++++++++++++---------------- nupm/utils/log.nu | 5 +++++ 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/nupm/registry.nu b/nupm/registry.nu index 78a7d19..fd57f9c 100644 --- a/nupm/registry.nu +++ b/nupm/registry.nu @@ -1,7 +1,7 @@ # Registry management for nupm use utils/dirs.nu [nupm-home-prompt REGISTRY_FILENAME] -use utils/log.nu [throw-error UNIMPLEMENTED] +use utils/log.nu [throw-error append-help UNIMPLEMENTED] use utils/registry.nu registry-cache # Manage nupm registires @@ -16,6 +16,16 @@ export def list []: nothing -> table { $env.NUPM_REGISTRIES | transpose name url | sort-by name } +# Formatting convenience function that is passed in the presence of the `--save` flag, informing the user on +# how to make their changes permanent +export def success-msg [success_msg: string, write_path: path, saved_to_disk: bool]: nothing -> string { + if $saved_to_disk { + return $"($success_msg) and written to ($write_path)" + } + + $success_msg | append-help "To commit the change to disk, use the `--save` flag." +} + def registry-names [] { list | get name } # Show detailed information about a specific registry @@ -92,17 +102,13 @@ export def --env add [ throw-error $"Registry '($name)' already exists. Use 'nupm registry update' to modify it." } $env.NUPM_REGISTRIES = $env.NUPM_REGISTRIES | insert $name $url - mut add_success_msg = $"Registry '($name)' added successfully" if $save { $env.NUPM_REGISTRIES | save --force $env.NUPM_INDEX_PATH - $add_success_msg = $add_success_msg | append $" and written to ($env.NUPM_INDEX_PATH)." | str join " " - - } else { - $add_success_msg = $add_success_msg | append $". To commit the change to disk, use the `--save` flag." | str join " " } - print $add_success_msg + print (success-msg $"Registry '($name)' added successfully" $env.NUPM_INDEX_PATH $save) + } # Remove a registry @@ -117,15 +123,15 @@ export def --env remove [ $env.NUPM_REGISTRIES | save --force $env.NUPM_INDEX_PATH } - print $"Registry '($name)' removed successfully." + print (success-msg $"Registry '($name)' removed successfully" $env.NUPM_INDEX_PATH $save) } # Update a given registry url @example "Update registry URL" { nupm registry set-url my-registry https://new-url.com/registry.nuon } export def --env set-url [ - name: string, # Name of the registry to update - url: string, - --save, # Whether to commit the change to the registry index + name: string, # Name of the registry to update + url: string, # Registry target URL + --save, # Whether to commit the change to the registry index ]: nothing -> nothing { $env.NUPM_REGISTRIES = $env.NUPM_REGISTRIES | update $name $url @@ -133,7 +139,7 @@ export def --env set-url [ $env.NUPM_REGISTRIES | save --force $env.NUPM_INDEX_PATH } - print $"Registry '($name)' URL updated successfully." + print (success-msg $"Registry '($name)' URL updated successfully" $env.NUPM_INDEX_PATH $save) } # https://www.nushell.sh/book/configuration.html#macos-keeping-usr-bin-open-as-open @@ -141,9 +147,9 @@ alias nu-rename = rename # Rename a registry @example "Rename a registry" { nupm registry rename my-registry our-registry } export def --env rename [ - name: string, # Name of the registry to update - new_name: string, - --save, # Whether to commit the change to the registry index + name: string, # Name of the registry to update + new_name: string, # New registry name + --save, # Whether to commit the change to the registry index ] { $env.NUPM_REGISTRIES = $env.NUPM_REGISTRIES | nu-rename --column { $name: $new_name } @@ -151,7 +157,7 @@ export def --env rename [ $env.NUPM_REGISTRIES | save --force $env.NUPM_INDEX_PATH } - print $"Registry '($name)' renamed successfully." + print (success-msg $"Registry '($name)' renamed successfully" $env.NUPM_INDEX_PATH $save) } def init-index [] { diff --git a/nupm/utils/log.nu b/nupm/utils/log.nu index bdff6ab..4982e35 100644 --- a/nupm/utils/log.nu +++ b/nupm/utils/log.nu @@ -25,3 +25,8 @@ export def throw-error [ } } } + +# Append a formatted help line to mimic `error make` in core +export def append-help [help_msg: string]: string -> string { + $in + $"\n (ansi cyan)help:(ansi reset) " + $help_msg +}