Skip to content
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

which searches $PATH for relative paths (i.e. different from *nix which command) #51

Closed
bobisageek opened this issue Mar 27, 2022 · 1 comment · Fixed by #52
Closed

Comments

@bobisageek
Copy link
Contributor

Probably a low priority, as it's a somewhat esoteric situation.
I'm reporting this here because in my opinion fs/which is sort of the root cause, but there are several layers here, and maybe a couple of options as to where to fix (if we agree it's an issue).

presenting symptom/problem statement
When running native babashka tests in my Windows environment, I found that the tests end up using my installed babashka (on my PATH) rather than the freshly-built babashka in the current directory. I believe this has been the case since a fix for babashka/babashka#1078 went in. The native tests use babashka.process and execute "./bb", but despite the explicit relative path, $PATH is still being searched.

The desired outcome (from my standpoint) would be that calling process with a relative path (not just a command/file name) would respect the relative path, to more closely mimic the behavior of the command line. With that said, the Windows PATHEXT problem (needing the tack on the exe/com/cmd extension) would still exist in that case, so maybe there's a case for separating determining candidate directory paths and checking the candidate extensions.

babashka.process
On Windows, p/process searches $PATH if program is a relative path:
https://github.com/babashka/process/blob/8d72f2097a1dc49b81a52af6733b8beb836efbdc/src/babashka/process.cljc#L167-L168

Given a situation where the current directory contains an executable with the same name as an executable on $PATH, calling process on ./executable-name will use the one from $PATH instead of the one from the current directory:

C:\Users\user\code\clojure\babashka>.\bb --version
babashka v0.7.9-SNAPSHOT

C:\Users\user\code\clojure\babashka>bb
user=> (require '[babashka.process :as p])
user=> (-> (p/process ["./bb" "--version"] {:out :string})
         deref
         (select-keys [:out :cmd]))
{:out "babashka v0.7.8\r\n", :cmd ["C:\\Users\\user\\scoop\\shims\\.\\bb.exe" "--version"]}

... note that the process invocation uses the bb executable from $PATH. In my non-windows environment, both the shell command and the process invocation use the bb from the current directory.

fs/which
fs/which always searches $PATH, whereas the which unix util appears to only search $PATH if the argument is exactly a file name (i.e. not a path that specifies any directories)

# /home/bob/code is on my $PATH
$ echo $PATH | awk -F: '{print $NF}'
/home/bob/code

# /home/bob/code/bin/bb exists
$ ls /home/bob/code/bin/bb
/home/bob/code/bin/bb

# which doesn't find 'bin/bb' on $PATH from an arbitrary directory
$ pwd
/home/bob/code/clojure
$ which bin/bb
$

# but which does find 'bin/bb' if it's relative to the current directory
$ pwd
/home/bob/code
$ which bin/bb
bin/bb

but fs/which always looks through $PATH:

$ pwd
/home/bob/code/clojure
# this which fails at the command line
$ bb "(require '[babashka.fs :as fs]) (fs/which \"bin/bb\")"
#object[sun.nio.fs.UnixPath 0x1dff8382 "/home/bob/code/bin/bb"]

Possible resolution
If the aim would be to make fs/which behave more like unix which (while still accounting for Windows extensions), then I imagine it might work something like this:

; figure out candidate paths
(let [prog-path (path program)]
   (if (= prog-path (.getFileName prog-path)) ; if the whole path is just the file name, search $PATH, otherwise treat path as relative
       (exec-paths)
       ["."]))

... and then the existing search (with windows extensions on Windows) through the newly-determined candidate paths. One possible problem with the .getFileName approach is that it would also see a directory name as just a file name, but that seems to also be true currently.

That's just an idea - I figure logic that's getting complicated like this might warrant some design discussion before acting, so I just wanted to lay out the problem statement and get some feedback.

@borkdude
Copy link
Contributor

I agree with your assessment:

The desired outcome (from my standpoint) would be that calling process with a relative path (not just a command/file name) would respect the relative path, to more closely mimic the behavior of the command line

That it doesn't behave this way is probably an oversight and a PR to fix this is welcome.

borkdude pushed a commit that referenced this issue Mar 31, 2022
- don't match directories
- don't search $PATH entries when given a relative path
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants