Skip to content

Commit 5f4bdad

Browse files
authored
Merge pull request #2 from freepicheep/install-scripts
Install scripts either globally or in a project
2 parents 51dc4de + 6042a7f commit 5f4bdad

10 files changed

Lines changed: 2532 additions & 163 deletions

File tree

CHANGELOG.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,24 @@
11
# Unreleased
22

3-
Nothing yet!
3+
## Added
4+
5+
- Added first-class script dependencies via `[dependencies.scripts]` with
6+
`nuance add-script` and `nuance remove-script`.
7+
- Added script installation into `.nu_scripts/` from a specific path in a git
8+
repo or gist clone URL.
9+
- Added lockfile artifact kinds (`module` / `script`) and script `path`
10+
tracking for reproducible frozen installs.
11+
12+
## Changed
13+
14+
- Switched module declarations from `[dependencies]` to
15+
`[dependencies.modules]`.
16+
- Updated `activate.nu` generation and `nuance hook` output to support both
17+
module and script dependency paths.
18+
- Updated module install/activation to detect real module entry paths (including
19+
nupm-style nested layouts) by reading `nupm.nuon` metadata hints and scanning
20+
for `mod.nu`, then generating `export use` statements with the discovered
21+
path (for example `nu-salesforce/nu-salesforce`).
422

523
# Version 0.1.1 (2026-02-21)
624

README.md

Lines changed: 74 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# nuance
22

3-
A module manager for [Nushell](https://www.nushell.sh/).
3+
A dependency manager for [Nushell](https://www.nushell.sh/).
44

5-
nuance handles dependency resolution, fetching, and lockfile management for Nushell modules distributed as git repositories.
5+
nuance handles dependency resolution, fetching, and lockfile management for Nushell modules and script dependencies distributed as git repositories.
66

77
## Install
88

@@ -37,16 +37,34 @@ nuance add https://github.com/user/nu-some-module
3737
# Or use owner/repo shorthand (defaults to github)
3838
nuance add user/nu-some-module
3939

40+
# Add a script dependency (single file from a repo or gist)
41+
nuance add-script user/nu-toolbox scripts/quickfix.nu
42+
43+
# Or pass a full blob URL directly
44+
nuance add-script https://github.com/nushell/nu_scripts/blob/main/sourced/webscraping/twitter.nu
45+
4046
# Install all dependencies from mod.toml
4147
nuance install
4248

49+
# Add a global script dependency (prompts for autoload placement)
50+
nuance add-script -g user/nu-toolbox scripts/quickfix.nu
51+
52+
# Skip the prompt and install directly into autoload
53+
nuance add-script -g --autoload user/nu-toolbox scripts/quickfix.nu
54+
55+
# Install all global dependencies from ~/.config/nuance/config.toml
56+
nuance install -g
57+
4358
# Re-resolve everything (ignore lockfile)
4459
nuance update
4560

4661
# Remove a dependency
4762
nuance remove nu-some-module
4863

49-
# List installed modules (project-local if mod.toml exists, otherwise global)
64+
# Remove a script dependency
65+
nuance remove-script quickfix
66+
67+
# List installed dependencies (project-local if mod.toml exists, otherwise global)
5068
nuance list
5169
```
5270

@@ -58,24 +76,33 @@ A nuance project is a directory containing:
5876
- **`mod.nu`** — the Nushell module entry point
5977
- **`mod.lock`** — auto-generated lockfile pinning exact commits (commit this to version control)
6078

61-
Running `nuance install` fetches dependencies into `.nu_modules/`.
79+
Running `nuance install` fetches module dependencies into `.nu_modules/` and script dependencies into `.nu_scripts/`.
6280

6381
## Activation
6482

65-
To make the installed modules available to `use` in Nushell without specifying their full `.nu_modules/` paths, you need to add the project's modules directory to your `$env.NU_LIB_DIRS`.
83+
To make installed modules/scripts available to `use` in Nushell without full paths, add the project's dependency directories to `$env.NU_LIB_DIRS`.
6684

6785
Nuance provides two ways to do this:
6886

69-
### 1. Manual Overlay (Recommended)
70-
`nuance install` and `nuance init` automatically generate an `activate.nu` script inside the `.nu_modules` directory. This script adds `.nu_modules/` to your `$env.NU_LIB_DIRS` **and automatically imports** all installed modules into your active scope using `export use <module> *`.
87+
### 1. Manual Activation (Recommended)
88+
`nuance install` and `nuance init` generate activation scripts for both dependency kinds:
7189

72-
You can activate it using Nushell's `overlay` command:
90+
- `.nu_modules/activate.nu` (module overlay): updates `$env.NU_LIB_DIRS` and imports module dependencies with `export use <name> *`
91+
- `.nu_scripts/activate.nu` (sourceable script loader): sources script dependencies with `source <name>.nu`
92+
93+
Activate modules with an overlay:
7394

7495
```nu
7596
overlay use .nu_modules/activate.nu
7697
```
7798

78-
All commands from all installed modules are now available. When you're done, simply run `deactivate` (or `overlay hide activate`) to revert the environment changes and unload the modules.
99+
If you installed script dependencies, source their activate file:
100+
101+
```nu
102+
source .nu_scripts/activate.nu
103+
```
104+
105+
When you're done, run `deactivate` (or `overlay hide activate`) to unload the module overlay.
79106

80107
### 2. Auto-activation Hook
81108
If you want nuance projects to automatically update your module path when you `cd` into their directory (and remove it when you leave), add the nuance env_change hook to your `config.nu` or `env.nu`:
@@ -85,7 +112,7 @@ If you want nuance projects to automatically update your module path when you `c
85112
nuance hook
86113
```
87114

88-
> **Note**: Due to Nushell's static scoping rules, the auto-activation hook can only update `$env.NU_LIB_DIRS`. It cannot automatically import the module commands (you must still type `use <module> *` interactively). For fully automatic loading, use the Manual Overlay approach above.
115+
> **Note**: Due to Nushell's static scoping rules, the auto-activation hook only updates `$env.NU_LIB_DIRS`. It cannot auto-import module/script commands. For automatic loading, use the manual activation approach above.
89116
90117
## mod.toml
91118

@@ -95,34 +122,66 @@ name = "my-module"
95122
version = "0.1.0"
96123
description = "a wonderful nu module anyone can use"
97124

98-
[dependencies]
125+
[dependencies.modules]
99126
nu-utils = { git = "https://github.com/user/nu-utils", tag = "v1.0.0" }
100127
other-lib = { git = "https://github.com/user/other-lib", branch = "main" }
101128
pinned = { git = "https://github.com/user/pinned", rev = "a3f9c12" }
129+
130+
[dependencies.scripts]
131+
quickfix = { git = "https://github.com/user/nu-toolbox", path = "scripts/quickfix.nu", tag = "v0.4.0" }
132+
from-gist = { git = "https://gist.github.com/<id>.git", path = "quickfix.nu", rev = "d34db33f" }
102133
```
103134

104-
Each dependency must specify exactly one of `tag`, `branch`, or `rev`.
135+
Module dependencies must specify exactly one of `tag`, `branch`, or `rev`.
136+
Script dependencies must include `path` and exactly one of `tag`, `branch`, or `rev`.
105137

106138
## Commands
107139

108140
| Command | Description |
109141
|---------|-------------|
110142
| `nuance init` | Create a new `mod.toml` in the current directory |
111-
| `nuance add <source>` | Add a dependency from a URL or owner/repo shorthand (auto-detects latest tag) |
143+
| `nuance add <source>` | Add a module dependency from a URL or owner/repo shorthand (auto-detects latest tag) |
144+
| `nuance add-script [-g] [--autoload] <source> [path]` | Add a script dependency locally (`mod.toml`) or globally (`config.toml`) |
112145
| `nuance install` | Install dependencies from `mod.toml` |
146+
| `nuance install -g` | Install global dependencies from `~/.config/nuance/config.toml` |
113147
| `nuance install --frozen` | Install from lockfile only (CI-friendly) |
114148
| `nuance update` | Re-resolve all dependencies |
115-
| `nuance remove <name>` / `nuance rm <name>` | Remove a dependency |
116-
| `nuance list` / `nuance ls` | List installed modules (project-local or global) |
149+
| `nuance remove <name>` / `nuance rm <name>` | Remove a module dependency |
150+
| `nuance remove-script [-g] <name>` | Remove a script dependency locally or globally |
151+
| `nuance list` / `nuance ls` | List installed dependencies (project) or modules/scripts (global) |
117152
| `nuance version` / `nuance -v` / `nuance -V` / `nuance --version` | Print nuance version |
118153
| `nuance hook` | Print the auto-activate hook for config.nu |
119154

120155
## Global config (`~/.config/nuance/config.toml`)
121156

122157
You can set a default git provider used for `owner/repo` shorthand in `nuance add`.
158+
Global config manages global module dependencies and global script dependencies.
159+
160+
Global scripts install into:
161+
162+
- `~/.config/nushell/vendor/nuance/scripts/` (Linux)
163+
- `~/Library/Application Support/nushell/vendor/nuance/scripts/` (macOS)
164+
165+
Global scripts marked for autoload install into:
166+
167+
- `~/.config/nushell/vendor/nuance/scripts/autoload/` (Linux)
168+
- `~/Library/Application Support/nushell/vendor/nuance/scripts/autoload/` (macOS)
169+
170+
When you run `nuance add-script -g`, nuance always prompts whether to install into autoload.
171+
Pass `--autoload` to skip the prompt and install directly to autoload.
123172

124173
```toml
125174
default_git_provider = "github" # default
175+
176+
# optional overrides
177+
# modules_dir = "/custom/modules"
178+
# scripts_dir = "/custom/scripts"
179+
180+
[dependencies]
181+
nu-utils = { git = "https://github.com/user/nu-utils", tag = "v1.0.0" }
182+
183+
[scripts]
184+
quickfix = { git = "https://github.com/user/nu-toolbox", path = "scripts/quickfix.nu", tag = "v0.4.0", autoload = true }
126185
```
127186

128187
Supported provider aliases are `github`, `gitlab`, `codeberg`, and `bitbucket`.

src/checksum.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ pub fn hash_directory(dir: &Path) -> Result<String> {
3333
Ok(hex::encode(hasher.finalize()))
3434
}
3535

36+
/// Compute SHA-256 over a single file's contents.
37+
pub fn hash_file(path: &Path) -> Result<String> {
38+
let mut hasher = Sha256::new();
39+
let contents = std::fs::read(path)?;
40+
hasher.update(&contents);
41+
Ok(hex::encode(hasher.finalize()))
42+
}
43+
3644
#[cfg(test)]
3745
mod tests {
3846
use super::*;
@@ -69,4 +77,22 @@ mod tests {
6977

7078
let _ = fs::remove_dir_all(&dir);
7179
}
80+
81+
#[test]
82+
fn file_hash_changes_with_content() {
83+
let dir = std::env::temp_dir().join("nuance_test_checksum_file");
84+
let _ = fs::remove_dir_all(&dir);
85+
fs::create_dir_all(&dir).unwrap();
86+
let file = dir.join("script.nu");
87+
88+
fs::write(&file, "print 'a'").unwrap();
89+
let h1 = hash_file(&file).unwrap();
90+
91+
fs::write(&file, "print 'b'").unwrap();
92+
let h2 = hash_file(&file).unwrap();
93+
94+
assert_ne!(h1, h2);
95+
96+
let _ = fs::remove_dir_all(&dir);
97+
}
7298
}

0 commit comments

Comments
 (0)