Skip to content

feat(config): add $env.nupm.config #124

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 30 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 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
b22bbc6
initial commit
mkatychev Jun 28, 2025
72fb22e
passing tests
mkatychev Jun 28, 2025
37bccc5
use constant filenames
mkatychev Jun 30, 2025
996c984
remove errant example
mkatychev Jun 30, 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
9 changes: 9 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -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
27 changes: 11 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
40 changes: 20 additions & 20 deletions docs/design/README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
# 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`
> (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 @@ -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`

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,21 +69,21 @@ 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**
> :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:
Expand All @@ -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:
Expand All @@ -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)`
Expand Down Expand Up @@ -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
Expand All @@ -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
9 changes: 5 additions & 4 deletions nupm/install.nu
Original file line number Diff line number Diff line change
@@ -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/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/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
Expand Down Expand Up @@ -105,8 +105,9 @@ 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')
^$nu.current-exe $build_file ($pkg_dir | path join $PACKAGE_FILENAME)
}

rm -rf $tmp_dir
Expand Down Expand Up @@ -235,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
Expand Down
46 changes: 23 additions & 23 deletions nupm/mod.nu
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
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 BASE_NUPM_CONFIG ]
use utils/registry.nu open-index

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)

# 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)

# Ensure that $env.nupm is always set when running nupm. Any missing variaables are set by `$BASE_NUPM_CONFIG`
$env.nupm = $BASE_NUPM_CONFIG | merge deep ($env.nupm? | default {})
# set missing values to default while
# retaining defaults in $env.nupm.default
$env.nupm.default = $BASE_NUPM_CONFIG
# 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 }
}
if $env.nupm.config.nu_search_path {
let nupm_lib_dirs = [modules, scripts] | each {|s| $env.nupm.home | path join $s }
$env.NU_LIB_DIRS = $env.NU_LIB_DIRS | prepend $nupm_lib_dirs | uniq

let nupm_plugin_dir = $env.nupm.home| path join "plugins"
$env.NU_PLUGIN_DIRS = $env.NU_PLUGIN_DIRS | prepend $nupm_plugin_dir | uniq
}
use std/log []
}

Expand All @@ -38,8 +38,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 Down
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
Loading