-
Notifications
You must be signed in to change notification settings - Fork 737
Description
Observed Issue
Winget is packaging zoxide as a portable app.
This means that Winget puts a symlink here:
~/AppData\Local\Microsoft\WinGet\Links\zoxide.exe
The target is actually here:
~/AppData\Local\Microsoft\WinGet\Packages\ajeetdsouza.zoxide_Microsoft.Winget.Source_8wekyb3d8bbwe\zoxide.exe
This is fine for locally running zoxide, via Powershell or Nushell.
But when remoting to a Windows machine and targeting either Powershell or Nushell, neither will launch zoxide.
The error given is variations of "I/O error
╰─▶ × Could not spawn foreground child: The path cannot be traversed because it contains an untrusted mount point. (os error 448)"
Possible Workaround
I tried to just enable remote symlink evaluation, but it did not help:
fsutil behavior set SymlinkEvaluation R2L:1 R2R:1
Not sure if it needs a restart, or if it is just not the reason for the error.
It would also not be ideal to globally enable something like this anyway.
Powershell is able to bypass the symlink:
function Get-RealPath($n) {
(Get-Command $n -Type Application | Select-Object -First 1).Path |
Get-Item |
ForEach-Object { $_.Target ?? $_.FullName }
}
function Initialize-Tool($n) {
Invoke-Expression "function global:$n { & '$((Get-RealPath $n))' @args }"
& $n init powershell | Out-String | Invoke-Expression
}
Initialize-Tool zoxide
Nushell is not able to, via its built-ins.. but it can wrap Powershell or Cmd, which can:
## cmd, works over ssh
# def get-realpath [n] {
# let p = (which $n | get 0?.path?)
# if ($p | is-empty) { return $n }
# let target = (
# ^cmd /c dir /a $p |
# decode utf-8 |
# str replace --all --regex '\x1b\[[0-9;]*[mK]' '' |
# lines |
# find "[" |
# first 1 |
# parse -r '.*\[(?P<t>.*)\]' |
# get 0?.t?
# )
# if ($target | is-empty) {
# $p
# } else {
# $target | str replace --all --regex '^[0-9;]*m' ''
# }
# }
## pwsh, works over ssh
def get-realpath [n] {
let ps_cmd = ([
'(Get-Command ', $n, ' -Type Application | Select-Object -First 1).Path | ',
'Get-Item | ForEach-Object { $_.Target ?? $_.FullName }'
] | str join "")
pwsh -NoProfile -Command $ps_cmd | str trim
}
## nushell, does not work over ssh
#def get-realpath [n] {
# which $n | get 0?.path? | path expand
#}
Then for Nushell, I can mutate what zoxide init produces, force it to bypass the symlink:
def initialize-tool [n init_args] {
let p = (get-realpath $n)
$"def --env ($n) [...args] { ^'($p)' ...$args }\n(
^$p ...$init_args | str replace --all --regex $"\\^($n)\\b" $"^'($p)'"
)" | save -f ([$NU_VENDOR_DATA_DIR, $"($n).nu"] | path join)
}
## preserves external cmd calls, does not work over ssh
# def initialize-tool [n init_args] {
# ^$n ...$init_args | save -f ([$NU_VENDOR_DATA_DIR, $"($n).nu"] | path join)
# }
initialize-tool zoxide [init nushell]
But I do not really want Nushell dependent on Powershell or Cmd, just to bypass a symlink
Proposed Solution
I am not sure if there are benefits to Winget packaging zoxide as a portable app, other than a simpler installer
I would like to propose that we produce a non-portable installer for Winget to use for zoxide, so that it installs to a real path somewhere, no symlink
This would put it more in line with how starship is packaged
Then I would not have to do any workarounds as above, which are complex and slow
I can help to create a pull request for this if it would be approved
Thank you