-
Notifications
You must be signed in to change notification settings - Fork 13.5k
Add os::split_paths #14544
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
Add os::split_paths #14544
Conversation
#[cfg(unix)] | ||
/// Parse the `path` environment variable according to the platform's conventions. | ||
pub fn path_env() -> Vec<Path> { | ||
let paths = getenv("PATH").unwrap_or("".to_owned()); |
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.
_PATH_DEFPATH
in <paths.h>
defines the default path to use when $PATH
is unset to be /usr/bin:bin
. Perhaps this should follow suite?
If you don't want to provide a default then I think Option<Vec<Path>>
should be considered.
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.
Good idea; I'll change the default.
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.
Option
may be the right approach here because what's the default to use for Windows? I have no idea.
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 looks like we should do something similar for Windows: http://superuser.com/questions/124239/what-is-the-default-path-environment-variable-setting-on-fresh-install-of-window
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.
According to that, it changes based on the Windows version. Vista has the path in that answer, one comment confirms that the PowerShell path was added in Windows 7, and it's plausible that Windows 8 added something else.
But that's actually beside the point. That's the path that %PATH%
defaults to, which isn't what we want here. My /usr/bin:bin
suggestion was based on the PATH that execvp()
uses if $PATH
is unset. That's not actually the path that's used by default on a fresh system (that usually includes at least /usr/local/bin
).
It might be better to rework this to have a function that parses a |
@kballard Thanks for the feedback on this. I've switched to use an Option type, as you suggested, and changed the tests to reset the PATH variable when complete. To address your other concerns:
|
That's only going to work if the tests succeed. If a test fails, it won't reset the PATH. I think you should break it out regardless. You could leave it as a private function for now, which the tests could use, and then we could consider making it public if someone has a compelling use-case. |
|
||
for s in oldpath.iter() { | ||
setenv("PATH", s.as_slice()) | ||
} |
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.
This is not a good style for dealing with Option
. It makes oldpath
look like it's a sequence. It also won't un-set PATH
if it wasn't set in the first place.
match oldpath {
Some(p) => setenv("PATH", p.as_slice())
None => unsetenv("PATH")
}
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, I was trying to follow the style of the existing tests, e.g. homedir
...
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.
You can consider those tests to be written in a bad style, then. They should be updated (though that's out of scope of this PR).
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.
OK, I'll clean those tests up in a separate PR once we settle on the right approach to dealing with environment variables in these. (I do agree regarding the style, and especially about missing the unset 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.
@kballard, think you're a bit forceful saying that this isn't good style for Option
. I have seen no consensus of this, I know some people don't like it, but others do. (In any case, I agree that this specific use of Option.iter
is poor.)
I can break out the parse function privately, as you suggest, but presumably we'll want some test to ensure that the public API is actually reading from the $PATH variable. As you point out, this will fail to reset $PATH on failure, but this is already the case with other tests in the module, like |
@@ -1754,5 +1817,78 @@ mod tests { | |||
fs::unlink(&path).unwrap(); | |||
} | |||
|
|||
#[test] | |||
#[cfg(windows)] | |||
fn path_env_windows() { |
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.
You may want to put these tests in a run-pass
test instead of in the standard library. At least on windows the value of PATH
affects how dynamic libraries are opened up, so this test executing at the same time as those tests may cause badness to arise.
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 can do that; what do you think of @kballard's suggestion to instead break out the parsing into a private function that does not actually read $PATH, and test that instead?
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.
(My only worry is: this fails to test that the public API successfully reads $PATH.)
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.
Either way is fine by me
You can write such a test and have it reset PATH correctly even on failure: #[test]
fn test_read_from_path() {
let oldpath = getenv("PATH");
setenv("PATH", "foo:bar:baz");
let result = path_env();
match oldpath {
Some(p) => setenv("PATH", p.as_slice()),
None => unsetenv("PATH")
}
assert_eq!(result, vec!["foo".to_string(), "bar".to_string(), "baz".to_string()]);
} If you use a |
@kballard @alexcrichton thanks both for the feedback, will adjust, repush, and ping. |
After considering @alexcrichton's point about |
@kballard Agreed, that's what I'm doing. Once we're happy with this patch, I can clean up the other tests in this module to follow suit. |
/// conventions, dropping empty paths. | ||
/// Returns `None` if `PATH` is not set. | ||
pub fn path_env() -> Option<Vec<Path>> { | ||
getenv("PATH").map(|unparsed| { |
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 think this should probably use getenv_as_bytes
, since it's possible to have non-UTF8 paths.
(Also, btw, using just .split(':')
will be faster for strings.)
I would like path_env() to handle "CLASS_PATH" and many more similar |
I've pushed a new version which exposes the API as |
LGTM, but the test functions need to be renamed. |
Good work, I like the new split_paths(). |
Pushed new version with renamed test functions, and more precise doc comments not using "$PATH". |
["c:\\", "c:\\Program Files\\"])); | ||
assert!(check_parse("c:\\;c:\\\"foo\"\\", ["c:\\", "c:\\foo\\"])); | ||
assert!(check_parse("c:\\;c:\\\"foo;bar\"\\;c:\\baz", | ||
["c:\\", "c:\\foo;bar\\", "c:\\baz"])); |
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.
All these paths would be easier to read using raw strings.
assert!(check_parse(r#"c:\;c:\"foo;bar"\;c:\baz"#, [r"c:\", r"c:\foo;bar\", r"c:\baz"]));
r=me with the one comment about the windows test paths. |
Adds a platform-specific function, `split_paths` to the `os` module. This function can be used to parse PATH-like environment variables according to local platform conventions. Closes rust-lang#14352.
Changed Windows test paths to raw string literals. |
Adds a platform-specific function, `split_paths` to the `os` module. This function can be used to parse PATH-like environment variables according to local platform conventions. Closes #14352.
Infer types of nested RPITs fix rust-lang/rust-analyzer#14474 (comment)
Adds a platform-specific function,
split_paths
to theos
module. Thisfunction can be used to parse PATH-like environment variables according to
local platform conventions.
Closes #14352.