nh icon indicating copy to clipboard operation
nh copied to clipboard

Spaces in PATH break clean all

Open pcarrier opened this issue 6 months ago • 6 comments

I have confirmed that this is a bug related to nh

  • [x] This is a bug, and not an user error or a support request. I understand that my issue will be closed if it is not a bug in NH.
  • [x] I have checked the issues tab and confirmed that my issue has not yet been reported. I understand that my issue will be closed if it is a duplicate.

Description

Can't run nh clean all on my WSL installs.

~ ❱ nh clean all
env: 'VS': No such file or directory
~ | 127 ❱ env | grep VS
WSLPATH=/mnt/c/WINDOWS/system32:/mnt/c/WINDOWS:/mnt/c/WINDOWS/System32/Wbem:/mnt/c/WINDOWS/System32/WindowsPowerShell/v1.0/:/mnt/c/WINDOWS/System32/OpenSSH/:/mnt/c/Program Files/NVIDIA Corporation/NVIDIA App/NvDLISR:/mnt/c/Users/pierr/AppData/Local/Programs/cursor/resources/app/bin:/mnt/c/Users/pierr/AppData/Local/Programs/cursor/resources/app/bin:/mnt/c/Program Files/dotnet/:/mnt/c/Program Files/Tailscale/:/mnt/c/Program Files (x86)/NVIDIA Corporation/PhysX/Common:/mnt/c/Users/pierr/go/bin:/mnt/c/Users/pierr/scoop/apps/ruby/current/bin:/mnt/c/Users/pierr/scoop/apps/ruby/current/gems/bin:/mnt/c/Users/pierr/scoop/apps/rustup/current/.cargo/bin:/mnt/c/Users/pierr/scoop/apps/mpv/current:/mnt/c/Users/pierr/scoop/shims:/mnt/c/Users/pierr/AppData/Local/Microsoft/WindowsApps:/mnt/c/Users/pierr/AppData/Local/JetBrains/Toolbox/scripts:/mnt/c/Users/pierr/AppData/Local/Programs/cursor/resources/app/bin:/mnt/c/Users/pierr/AppData/Local/Programs/Microsoft VS Code/bin
PATH=/mnt/c/Users/pierr/AppData/Local/Programs/Microsoft VS Code/bin:/run/wrappers/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/lib/wsl/lib:/home/pcarrier/.nix-profile/bin:/nix/profile/bin:/home/pcarrier/.local/state/nix/profile/bin:/etc/profiles/per-user/pcarrier/bin:/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin:/mnt/c/WINDOWS/system32:/mnt/c/WINDOWS:/mnt/c/WINDOWS/System32/Wbem:/mnt/c/WINDOWS/System32/WindowsPowerShell/v1.0/:/mnt/c/WINDOWS/System32/OpenSSH/:/mnt/c/Program Files/NVIDIA Corporation/NVIDIA App/NvDLISR:/mnt/c/Users/pierr/AppData/Local/Programs/cursor/resources/app/bin:/mnt/c/Users/pierr/AppData/Local/Programs/cursor/resources/app/bin:/mnt/c/Program Files/dotnet/:/mnt/c/Program Files/Tailscale/:/mnt/c/Program Files (x86)/NVIDIA Corporation/PhysX/Common:/mnt/c/Users/pierr/go/bin:/mnt/c/Users/pierr/scoop/apps/ruby/current/bin:/mnt/c/Users/pierr/scoop/apps/ruby/current/gems/bin:/mnt/c/Users/pierr/scoop/apps/rustup/current/.cargo/bin:/mnt/c/Users/pierr/scoop/apps/mpv/current:/mnt/c/Users/pierr/scoop/shims:/mnt/c/Users/pierr/AppData/Local/Microsoft/WindowsApps:/mnt/c/Users/pierr/AppData/Local/JetBrains/Toolbox/scripts:/mnt/c/Users/pierr/AppData/Local/Programs/cursor/resources/app/bin:/mnt/c/Users/pierr/AppData/Local/Programs/Microsoft VS Code/bin
~ ❱
~ ❱ nh clean all
env: 'VS': No such file or directory
~ | 127 ❱ env | grep VS
WSLPATH=/mnt/c/WINDOWS/system32:/mnt/c/WINDOWS:/mnt/c/WINDOWS/System32/Wbem:/mnt/c/WINDOWS/System32/WindowsPowerShell/v1.0/:/mnt/c/WINDOWS/System32/OpenSSH/:/mnt/c/Program Files/NVIDIA Corporation/NVIDIA App/NvDLISR:/mnt/c/Users/pierr/AppData/Local/Programs/cursor/resources/app/bin:/mnt/c/Users/pierr/AppData/Local/Programs/cursor/resources/app/bin:/mnt/c/Program Files/dotnet/:/mnt/c/Program Files/Tailscale/:/mnt/c/Program Files (x86)/NVIDIA Corporation/PhysX/Common:/mnt/c/Users/pierr/go/bin:/mnt/c/Users/pierr/scoop/apps/ruby/current/bin:/mnt/c/Users/pierr/scoop/apps/ruby/current/gems/bin:/mnt/c/Users/pierr/scoop/apps/rustup/current/.cargo/bin:/mnt/c/Users/pierr/scoop/apps/mpv/current:/mnt/c/Users/pierr/scoop/shims:/mnt/c/Users/pierr/AppData/Local/Microsoft/WindowsApps:/mnt/c/Users/pierr/AppData/Local/JetBrains/Toolbox/scripts:/mnt/c/Users/pierr/AppData/Local/Programs/cursor/resources/app/bin:/mnt/c/Users/pierr/AppData/Local/Programs/Microsoft VS Code/bin
PATH=/mnt/c/Users/pierr/AppData/Local/Programs/Microsoft VS Code/bin:/run/wrappers/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/lib/wsl/lib:/home/pcarrier/.nix-profile/bin:/nix/profile/bin:/home/pcarrier/.local/state/nix/profile/bin:/etc/profiles/per-user/pcarrier/bin:/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin:/mnt/c/WINDOWS/system32:/mnt/c/WINDOWS:/mnt/c/WINDOWS/System32/Wbem:/mnt/c/WINDOWS/System32/WindowsPowerShell/v1.0/:/mnt/c/WINDOWS/System32/OpenSSH/:/mnt/c/Program Files/NVIDIA Corporation/NVIDIA App/NvDLISR:/mnt/c/Users/pierr/AppData/Local/Programs/cursor/resources/app/bin:/mnt/c/Users/pierr/AppData/Local/Programs/cursor/resources/app/bin:/mnt/c/Program Files/dotnet/:/mnt/c/Program Files/Tailscale/:/mnt/c/Program Files (x86)/NVIDIA Corporation/PhysX/Common:/mnt/c/Users/pierr/go/bin:/mnt/c/Users/pierr/scoop/apps/ruby/current/bin:/mnt/c/Users/pierr/scoop/apps/ruby/current/gems/bin:/mnt/c/Users/pierr/scoop/apps/rustup/current/.cargo/bin:/mnt/c/Users/pierr/scoop/apps/mpv/current:/mnt/c/Users/pierr/scoop/shims:/mnt/c/Users/pierr/AppData/Local/Microsoft/WindowsApps:/mnt/c/Users/pierr/AppData/Local/JetBrains/Toolbox/scripts:/mnt/c/Users/pierr/AppData/Local/Programs/cursor/resources/app/bin:/mnt/c/Users/pierr/AppData/Local/Programs/Microsoft VS Code/bin
~ ❱

Installation Method

Stable Release (nixpkgs, pkgs.nh from nixos-unstable or nixos-yy-mm)

Installation Method (Other)

No response

NH Version

4.2.0 nice

System Information

  • system: "x86_64-linux"
  • host os: Linux 6.6.87.1-microsoft-standard-WSL2, NixOS, 25.11 (Xantusia), 25.11.20250914.af74579
  • multi-user?: yes
  • sandbox: yes
  • version: nix-env (Nix) 2.28.5
  • channels(root): "nixos-25.05, nixos-wsl-25.05.tar.gz"
  • nixpkgs: /nix/store/25fmgjh4xzcjmr3nxfnqm261di13v1vc-source

pcarrier avatar Sep 15 '25 15:09 pcarrier

Please post the output with --verbose.

viperML avatar Sep 22 '25 09:09 viperML

Same for me on macOS.

~/nix-config on  master [$+⇡] took 5m2s
nu ❯ nh clean all --verbose
DEBUG Main {
    verbosity: Verbosity {
        verbose: 1,
        quiet: 0,
        phantom: PhantomData<clap_verbosity_flag::InfoLevel>,
    },
    elevation_program: None,
    command: Clean(
        CleanProxy {
            command: All(
                CleanArgs {
                    keep: 1,
                    keep_since: Duration(
                        0ns,
                    ),
                    dry: false,
                    ask: false,
                    no_gc: false,
                    no_gcroots: false,
                    optimise: false,
                    max: None,
                },
            ),
        },
    ),
} (nh/src/main.rs:29)
DEBUG NH_VERSION=4.2.0 NH_REV=Some("v4.2.0") (nh/src/main.rs:30)
DEBUG cmd=Exec { nix --version } (nh/src/commands.rs:577)
DEBUG cmd=Exec { nix --version } (nh/src/commands.rs:577)
DEBUG Version normalized: 'nix (Nix) 2.28.5' -> '2.28.5' (nh/src/util.rs:106)
DEBUG Configured envs: NIX_SSL_CERT_FILE=<preserved>, USER=shgew, NIX_PATH=<preserved>, PATH=<preserved> (nh/src/commands.rs:295)
DEBUG sudo path found path="/usr/bin/sudo" (nh/src/commands.rs:131)
DEBUG "/usr/bin/sudo" "env" "\'NIX_SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt\'" "\'USER=shgew\'" "\'NIX_PATH=nixpkgs=flake:nixpkgs:/nix/var/nix/profiles/per-user/root/channels\'" "\'PATH=/nix/store/4zwlxqk3dxcjy4py540n7zn9a4kgf0bn-nix-output-monitor-2.1.6/bin:/Users/shgew/Library/Application" "Support/carapace/bin:/Users/shgew/.nix-profile/bin:/etc/profiles/per-user/shgew/bin:/run/current-system/sw/bin/:/nix/var/nix/profiles/default/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/Applications/Visual" "Studio" "Code.app/Contents/Resources/app/bin:/Applications/Cursor.app/Contents/Resources/app/bin:/Applications/Carbon" "Copy" "Cloner.app/Contents/MacOS:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Ghostty.app/Contents/MacOS\'" "/nix/store/kmgln8yj17dzwd14ggs7pr81sp44cyjr-nh-4.2.0/bin/.nh-wrapped" "clean" "all" "--verbose" (nh/src/util.rs:286)
Password:
env: Support/carapace/bin:/Users/shgew/.nix-profile/bin:/etc/profiles/per-user/shgew/bin:/run/current-system/sw/bin/:/nix/var/nix/profiles/default/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/Applications/Visual: No such file or directory

~/nix-config on  master [$+⇡] took 5s
nu ❯ $env.PATH
╭────┬─────────────────────────────────────────────────────────────────╮
│  0 │ /Users/shgew/Library/Application Support/carapace/bin           │
│  1 │ /Users/shgew/.nix-profile/bin                                   │
│  2 │ /etc/profiles/per-user/shgew/bin                                │
│  3 │ /run/current-system/sw/bin/                                     │
│  4 │ /nix/var/nix/profiles/default/bin                               │
│  5 │ /opt/homebrew/bin                                               │
│  6 │ /opt/homebrew/sbin                                              │
│  7 │ /Applications/Visual Studio Code.app/Contents/Resources/app/bin │
│  8 │ /Applications/Cursor.app/Contents/Resources/app/bin             │
│  9 │ /Applications/Carbon Copy Cloner.app/Contents/MacOS             │
│ 10 │ /usr/local/bin                                                  │
│ 11 │ /usr/bin                                                        │
│ 12 │ /bin                                                            │
│ 13 │ /usr/sbin                                                       │
│ 14 │ /sbin                                                           │
│ 15 │ /Applications/Ghostty.app/Contents/MacOS                        │
╰────┴─────────────────────────────────────────────────────────────────╯

shgew avatar Sep 22 '25 15:09 shgew

I spent some time digging into the problem and the culprit is how self_elevate_cmd converts from subprocess::Exec to process::Command. More specifically, it just splits the resulting cmdline string by whitespace:

// ...
let cmdline = final_exec.to_cmdline_lossy();
let parts: Vec<&str> = cmdline.split_whitespace().collect();
// ...

Possible solutions I see here are:

  1. Use process::Command solely in this flow
  2. Parse the cmdline string with some lexer that understands shell syntax like shlex and convert to process::Command that way.

shgew avatar Sep 22 '25 16:09 shgew

Implemented solution 2 in https://github.com/nix-community/nh/pull/425.

shgew avatar Sep 22 '25 17:09 shgew

I'm pretty sure we could avoid to begin with having to collapse the command to a string, and always treat it as a vec.

viperML avatar Sep 22 '25 18:09 viperML

Yep, that would be a much better solution! I tried achieving this, but my Rust skills are not there yet :) Feel free to close the PR whenever needed.

shgew avatar Sep 22 '25 19:09 shgew