Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
4d9d899
init commit
mkatychev Jun 13, 2025
573100b
changed const
mkatychev Jun 13, 2025
5409a71
get_index impl
mkatychev Jun 13, 2025
3bcf1e9
removed TODOs for callout of registry subcommand
mkatychev Jun 13, 2025
87ed5d1
Merge branch 'main' into feat/registry-submodule
mkatychev Jun 20, 2025
26c3444
made nupm config declarative
mkatychev Jun 24, 2025
67c2826
Merge branch 'main' into feat/registry-submodule
mkatychev Jun 24, 2025
fce3057
updated NUPM_ variables to match nested structure
mkatychev Jun 24, 2025
354dc8e
typos
mkatychev Jun 24, 2025
2efd004
updated initial test variables
mkatychev Jun 24, 2025
5e96f1a
fixed registry typo
mkatychev Jun 24, 2025
0821712
renamed tmp to temp
mkatychev Jun 24, 2025
445be0f
revert temp
mkatychev Jun 24, 2025
1f12490
fixed tmp-dir variable resolution issue
mkatychev Jun 26, 2025
f33f29e
updated with workaround
mkatychev Jun 26, 2025
7d3a1cf
updated test cases for exitsting registry subcommands
mkatychev Jun 26, 2025
12d95c1
initial naive registry describe impl
mkatychev Jun 26, 2025
fe5b26c
registry describe passing test
mkatychev Jun 26, 2025
2907762
moved open-index to module root
mkatychev Jun 26, 2025
11a7a38
removed log calls intest
mkatychev Jun 26, 2025
b054db3
update registry header comment
mkatychev Jun 26, 2025
aa12a95
update registry init shim
mkatychev Jun 26, 2025
d5d6699
partial test pass
mkatychev Jun 27, 2025
bac9659
all tests pass
mkatychev Jun 27, 2025
baaf4f4
revert test mod closuer
mkatychev Jun 27, 2025
8542850
simplify variable setting
mkatychev Jun 28, 2025
af2a6ad
reverted nested nupm config
mkatychev Jul 7, 2025
081677b
remove flaten-nupm-env
mkatychev Jul 7, 2025
01b33b2
added registry_filename constants
mkatychev Jul 7, 2025
b2e85f2
removed fetch command
mkatychev Jul 10, 2025
4c55581
remoted editorconfig
mkatychev Jul 10, 2025
102d970
PR feedback on addtion of registry values
mkatychev Jul 16, 2025
78848fe
revert README
mkatychev Jul 16, 2025
919865b
updated formatting messages
mkatychev Jul 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
```
Expand Down
26 changes: 13 additions & 13 deletions docs/design/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ 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
- [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)
Expand All @@ -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
```
Expand All @@ -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).
Expand All @@ -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.
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)
* 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**
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion docs/design/registry.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 9 additions & 1 deletion nupm/install.nu
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,14 @@ def install-path [

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
Expand Down Expand Up @@ -235,12 +242,13 @@ 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
--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
}
Expand Down
53 changes: 31 additions & 22 deletions nupm/mod.nu
Original file line number Diff line number Diff line change
@@ -1,33 +1,41 @@
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
export module registry.nu
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-registries: {
nupm: 'https://raw.githubusercontent.com/nushell/nupm/main/registry/registry.nuon'
}
}

# 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)
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"))
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")
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 []
}
Expand All @@ -38,8 +46,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 }
Expand All @@ -52,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
}
2 changes: 1 addition & 1 deletion nupm/publish.nu
Original file line number Diff line number Diff line change
Expand Up @@ -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<name: string, path: string, url: string> {
Expand Down
123 changes: 123 additions & 0 deletions nupm/registry.nu
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# 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 {
$env.nupm.registries | transpose name url | sort-by name
}


# 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 {
# }

# Add a new registry
@example "Add a new registry" { nupm registry add my-registry https://example.com/registry.nuon }
export def --env add [
name: string, # Name of the registry
url: string, # URL or path to the registry
--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

if $save {
$env.nupm.registries | save --force $env.nupm.index-path
}

print $"Registry '($name)' added successfully."
Comment thread
mkatychev marked this conversation as resolved.
Outdated
}

# Remove a registry
@example "Remove a registry" { nupm registry remove my-registry }
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

if $save {
$env.nupm.registries | save --force $env.nupm.index-path
}

print $"Registry '($name)' removed successfully."
}

# 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
]: nothing -> nothing {
$env.nupm.registries = $env.nupm.registries | update $name $url

if $save {
$env.nupm.registries | save --force $env.nupm.index-path
}

print $"Registry '($name)' URL updated successfully."
}

# 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
] {
$env.nupm.registries = $env.nupm.registries | ^rename --column { $name: $new_name }

if $save {
$env.nupm.registries | save --force $env.nupm.index-path
}

print $"Registry '($name)' renamed successfully."
}


# Initialize registry_idx.nuon with default registries
@example "Initialize registry list" { nupm registry init-index }
export def init-index [

registry?: record<name: string, url: string, enabled: bool>
] {
if not (nupm-home-prompt) {
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)"
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_idx_path

print $"Registry list initialized at ($registry_idx_path)"
}
2 changes: 1 addition & 1 deletion nupm/search.nu
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion nupm/utils/completions.nu
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export def complete-registries [] {
$env.NUPM_REGISTRIES? | default {} | columns
$env.nupm.registries? | default {} | columns
}
Loading
Loading