-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
Fix which behavior when passed an empty string #33150
Conversation
@@ -459,6 +459,9 @@ for executable permissions only (with `.exe` and `.com` extensions added on | |||
Windows platforms); no searching of `PATH` is performed. | |||
""" | |||
function which(program_name::String) | |||
if isempty(program_name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's nip things like " "
in the bud as well; do isempty(strip(program_name))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So it turns out that this already works with the current code (at least on Linux).
The reason is that isexecutable("/usr/bin/ ") == false
while isexecutable("/usr/bin/") == true
.
It makes sense to add the test though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In that case, I think it makes more sense to change isexecutable()
to isfile() && isexecutable()
. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I agree that makes sense.
I think we might as well keep the early exit for an empty string though. There's no point in searching a bunch of directories for something they can't possibly contain.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While "" isn't a valid file name, " " is perfectly legal (if a bit insane) as an executable name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, though I think it's OK to include a test for that because the odds of there being such a file on a test system is very low.
There are currently no other tests for Sys.which and in general it's a bit complicated to write them because it would require controlling environment variables as well as the filesystem. However testing that Sys.which(" ") == nothing is easy and almost certain to be right.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW, it's not so hard to make bulletproof tests for this:
mktempdir() do temp_dir
my_bin = joinpath(temp_dir, "my_bin")
touch(my_bin)
chmod(my_bin, 0o755)
withenv("PATH" => temp_dir) do
@test abspath(Sys.which("my_bin")) == abspath(my_bin)
@test Sys.which(" ") == nothing
@test Sys.which("") == nothing
end
end
Something like that should work, modulo chmod()
issues on Windows. (E.g. don't try to do test creating non-executable files on windows.... everything is executable on windows from Julia's perspective ;) )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We already have tests for that (in test/spawn.jl), we just need tests for the new code (empty string case).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great. Good to merge from my perspective then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not clear on why the tests are there. I thought the convention was that functions in base/foo.jl were tested in test/foo.jl.
But since that's where the other which tests are I should probably move the new ones into test/spawn.jl which will also allow using the existing testing framework to ensure that the blank filename test is correct.
test/sysinfo.jl
Outdated
@@ -6,3 +6,6 @@ | |||
sprint(Base.Sys.cpu_summary) | |||
@test Base.Sys.uptime() > 0 | |||
Base.Sys.loadavg() | |||
|
|||
# Check that which behaves correctly when passed an empty string | |||
@test isnothing(Base.Sys.which("")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's test isnothing(Base.Sys.which(" "))
as well
I think commit a264f01 should complete this PR. Should be OK to merge if the tests pass. |
It looks like the tests are failing due to download problems. |
Thanks for your contribution @tgflynn! |
* Fix behavior of Sys.which when passed an empty String argument * Added test to check for fixed Sys.which behavior with empty string input * Added test to check that Sys.which returns nothing when passed a blank string * Ensure that Sys.which returns a regular file and never a directory * Moved new Sys.which tests into test/spawn.jl alongside the existing ones * Remove new which tests from test/sysinfo.jl (they've moved to test/spawn.jl) (cherry picked from commit fa235cc)
# Test that completely missing files also return nothing | ||
@test Sys.which("this_is_not_a_command") === nothing | ||
|
||
# Check that which behaves correctly when passed a blank string | ||
@test isnothing(Base.Sys.which(" ")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a bit late to the party, but should we also test that when there actually is an executable named
in the path we can find it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are existing tests for that. I just added a test for a blank string and made sure that the tests that should return nothing are independent of what's on the filesystem.
* Fix behavior of Sys.which when passed an empty String argument * Added test to check for fixed Sys.which behavior with empty string input * Added test to check that Sys.which returns nothing when passed a blank string * Ensure that Sys.which returns a regular file and never a directory * Moved new Sys.which tests into test/spawn.jl alongside the existing ones * Remove new which tests from test/sysinfo.jl (they've moved to test/spawn.jl) (cherry picked from commit fa235cc)
* Fix behavior of Sys.which when passed an empty String argument * Added test to check for fixed Sys.which behavior with empty string input * Added test to check that Sys.which returns nothing when passed a blank string * Ensure that Sys.which returns a regular file and never a directory * Moved new Sys.which tests into test/spawn.jl alongside the existing ones * Remove new which tests from test/sysinfo.jl (they've moved to test/spawn.jl) (cherry picked from commit fa235cc)
* Fix behavior of Sys.which when passed an empty String argument * Added test to check for fixed Sys.which behavior with empty string input * Added test to check that Sys.which returns nothing when passed a blank string * Ensure that Sys.which returns a regular file and never a directory * Moved new Sys.which tests into test/spawn.jl alongside the existing ones * Remove new which tests from test/sysinfo.jl (they've moved to test/spawn.jl) (cherry picked from commit fa235cc)
Currently when passed an argument that is the empty string Sys.which() returns the path of a directory.
For example:
This is not correct since the empty string is not a valid path component on any OS of which I am aware.
This PR fixes this issue so that Sys.which("") returns nothing in accord with its documentation.