Easily turn Nushell modules into cross-shell CLI tools
library
nu
nushell
1# SPDX-License-Identifier: AGPL-3.0-only
2# Copyright (c) 2026 MatrixFurry <matrix@matrixfurry.com>
3
4const template: path = path self ./template.nu
5
6export def install [
7 src: path # Module source path
8 prefix?: path = ~/.local # installation prefix
9 --force (-f) # Overwrite existing files
10 --install-module (-i) # Install module in Nushell library directory
11 --bin-name (-b): string # Override final binary name
12 --module-name (-m): string # Override module name
13 --print-usage # [EXPERIMENTAL] Print command usage when executing --help or --list
14] {
15 let src = $src | path expand
16 let prefix = $prefix | path expand
17 let mod_name = $module_name | default ($src | path basename)
18 let installed_mod_path = $prefix | path join "share" $mod_name "module" $mod_name
19 let bin_name = $bin_name | default $mod_name
20 let installed_bin_path = $prefix | path join "bin" $bin_name
21
22 if $force {
23 rm -rf $installed_mod_path
24 rm -f $installed_bin_path
25 } else if ($installed_mod_path | path exists) or ($installed_bin_path | path exists) {
26 error make -u {
27 msg: "It looks like this tool is already installed, or there are conflicting files installed"
28 help: "If you're attempting to update or re-install the tool, use --force"
29 }
30 }
31
32 # Module
33 mkdir ($installed_mod_path | path dirname)
34 cp -r $src $installed_mod_path
35
36 if $install_module {
37 let nu_lib_dir = $env.NU_LIB_DIRS | first
38 if $force {rm -f ($nu_lib_dir | path join $mod_name)}
39 ln -s $installed_mod_path $nu_lib_dir
40 }
41
42 # Create & install binary
43 mkdir ($installed_bin_path | path dirname)
44
45 open $template --raw
46 | str replace "@MODULE_PATH@" $installed_mod_path
47 | str replace "@PRINT_USAGE@" ($print_usage | into string)
48 | save --progress $installed_bin_path
49
50 chmod +x $installed_bin_path
51}
52
53export def uninstall [
54 name: string # CLI tool to uninstall
55 prefix?: path = ~/.local # installation prefix
56 --bin-name (-b): string # Override binary name
57 --remove-module (-m) # Remove module in Nushell library directory
58] {
59 let prefix = $prefix | path expand
60 let mod_name = $name
61 let installed_mod_path = $prefix | path join "share" $mod_name "module" $mod_name
62 let bin_name = $bin_name | default $name
63 let installed_bin_path = $prefix | path join "bin" $bin_name
64
65 rm -rf $installed_mod_path
66 rm -f $installed_bin_path
67
68 if $remove_module {
69 let nu_lib_dir = $env.NU_LIB_DIRS | first
70 rm -f ($nu_lib_dir | path join $mod_name)
71 }
72}
73