-
Notifications
You must be signed in to change notification settings - Fork 90
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
Feature/look in path #175
base: master
Are you sure you want to change the base?
Feature/look in path #175
Conversation
This searches through the path variable's directories for the docker commands, instead of looking in predetermined OS-specific locations or requiring new environmental variables to be set. This also renames DockerCommandLocations to DockerCommandLocator, which better reflects what it is.
….com/samwright/docker-compose-rule into samwright-feature/use-path-to-find-executables
@@ -1,47 +1,75 @@ | |||
/* | |||
* Copyright 2016 Palantir Technologies, Inc. All rights reserved. |
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.
Are we keeping or removing the License? It's removed here but kept in the following file.
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 files should have the Apache licence. I'll fix the ones that had it removed.
return Stream.concat(Stream.of(locationOverride()), pathLocations); | ||
} | ||
|
||
public Stream<Path> forCommand() { |
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.
Why are we returning Stream
? They have use once semantics
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.
Purely because it was extracted out the middle of a stream, I'll make it a list.
protected abstract String command(); | ||
|
||
@Value.Default | ||
protected boolean isWindows() { |
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.
returning a constant to represent a default where the constant is framed as a question is somewhat misleading (I still don't know what the default is)
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.
The default is to allow it to be overriden in tests, otherwise it should behave as a constant.
Would "useWindowsExecutableNaming" have been easier to understand?
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.
isWindows
is fine, but I'm starting to think that making it a default doesn't really make any sense. Whoever creates this builder will know at the time what environment they're in, and it feels odd to be like "I'm not going to specify if I'm running on windows because defaults"
Unless of course this is for backcompat and it's used in client code then nevermind.
.orElseThrow(() -> new IllegalStateException( | ||
"Could not find docker-compose, looked in: " + DOCKER_COMPOSE_LOCATIONS)); | ||
|
||
DockerCommandLocator commandLocator = DockerCommandLocator.forCommand("docker-compose") |
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.
returning a builder just to do this looks kinda meh, might as well do the entire builder from here and delete the forCommand
method
} | ||
|
||
public Optional<String> preferredLocation() { | ||
@Value.Derived | ||
protected String 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.
This doesn't work on Windows, where the path variable is "Path". You could add another if (path == null) path = env().get("Path")
, or iterate through the env() map to find any key that equals "path" ignoring case, e.g.
String path = getEnv().entrySet().stream()
.filter(e -> e.getKey().equalsIgnoreCase("path"))
.findFirst()
.map(Map.Entry::getValue)
.orElseThrow(() -> new IllegalStateException("Could not find path variable in env"));
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.
Okay, this should now cover PATH, path and Path.
} | ||
|
||
@Test public void | ||
fail_when_no_paths_contain_command() { |
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 no longer true
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.
Sorry, ignore this one. I got an error running this but I now can't recreate 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.
Ah, found it again (I had @ignore'd the test, woops!)
Expected: (an instance of java.lang.IllegalStateException and exception with message a string containing "Could not find not-a-real-command! in [/usr/local/bin, /usr/bin]") but: exception with message a string containing "Could not find not-a-real-command! in [/usr/local/bin, /usr/bin]" message was "Could not find not-a-real-command! in [\usr\local\bin, \usr\bin]"
The "/usr/local/bin" string is converted to a Path
in DockerCommandLocations.pathLocations()
, which on Windows converts it to "\usr\local\bin" (aren't path separators fun?!)
You could change the expected message to just "Could not find " + command
, or create a List<Path> defaultPaths = ImmutableList.of(Paths.get("/usr/local/bin"), Paths.get("/usr/bin"))
and expect "Could not find " + command + " in " + defaultPaths
.
public String toString() { | ||
return "DockerCommandLocations{possiblePaths=" + possiblePaths + "}"; | ||
public static List<Path> pathLocations() { | ||
String path = Stream.of(System.getenv("PATH"), System.getenv("path"), System.getenv("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.
But what about CrazyOS that uses "pATh"? /s
return singletonList(Paths.get(locationOverride())); | ||
} | ||
|
||
public String getLocation() { |
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.
Previously DOCKER_COMPOSE_LOCATION would be the path to the binary, e.g. /path/to/docker-compose
, but the logic here requires it to point to the directory in which to find docker-compose, i.e. /path/to
. I think the previous behaviour is more obvious/expected.
You could remove the searchLocations
method, and do the check for the location override here instead, e..g
if (locationOverride() == null) {
return DockerCommandLocations.pathLocations().stream()....;
} else {
return locationOverride();
}
It might even be worth moving DockerCommandLocations.pathLocations()
to this class, but that's just a design thing.
Okay, it turns out ProcessBuilder looks for commands on the path (at least on Mac/Linux) and so there is no need to do this manually. I've updated the PR to do the simpler thing of only looking in the known Mac install locations and allow for explicitly setting it through an environment variable. @samwright could you give this a spin and see if it is actually sufficient for Windows? If not we should find a library that will give us as because as @ChrisAlice pointed out the Windows path variable can contain expansions that would require us to look at other environment variables to correctly use. |
Yep this works in Windows. I also tried just running "docker-compose.exe" without specifying its location and that worked too:
So it would probably be best to get rid of all that path variable stuff. Sorry for giving you a red herring! |
@hpryce , is this still relevant / needed to merge? Or is this overcome-by-events? |
On windows, the just-released |
This combines #170 and #152 to provide support for finding docker from the path both on Windows and in existing setups.