From ec72ff77a7d4d3647f596811bde35f1c49fefe78 Mon Sep 17 00:00:00 2001 From: Thomas Diamantis Date: Thu, 9 Feb 2017 16:44:55 +0200 Subject: [PATCH 1/2] look for "docker-compose" in path --- .../execution/DockerCommandLocations.java | 26 ++++++++++++++----- .../execution/DockerComposeExecutable.java | 1 + .../compose/execution/DockerExecutable.java | 1 + .../DockerCommandLocationsShould.java | 3 +++ 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/execution/DockerCommandLocations.java b/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/execution/DockerCommandLocations.java index a1e0c0a06..5bb8e63f1 100644 --- a/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/execution/DockerCommandLocations.java +++ b/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/execution/DockerCommandLocations.java @@ -18,26 +18,40 @@ import static java.util.Arrays.asList; import java.io.File; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.function.Predicate; +import java.util.stream.Stream; +import org.apache.commons.lang3.StringUtils; public class DockerCommandLocations { private static final Predicate IS_NOT_NULL = path -> path != null; private static final Predicate FILE_EXISTS = path -> new File(path).exists(); private final List possiblePaths; + private final String exeName; + private final boolean lookInPath; - public DockerCommandLocations(String... possiblePaths) { + public DockerCommandLocations(String exeName, boolean lookInPath, String... possiblePaths) { + this.exeName = exeName; + this.lookInPath = lookInPath; this.possiblePaths = asList(possiblePaths); } public Optional preferredLocation() { - - return possiblePaths.stream() - .filter(IS_NOT_NULL) - .filter(FILE_EXISTS) - .findFirst(); + List envPath = (StringUtils.isNotBlank(exeName) && lookInPath) + ? Arrays.asList(System.getenv("PATH").split(File.pathSeparator)) : + Collections.emptyList(); + + return Stream.concat( + envPath.stream().map(path -> Paths.get(path, exeName).toAbsolutePath().toString()), + possiblePaths.stream()) + .filter(IS_NOT_NULL) + .filter(FILE_EXISTS) + .findFirst(); } @Override diff --git a/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/execution/DockerComposeExecutable.java b/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/execution/DockerComposeExecutable.java index 7a580b130..716d4acbe 100644 --- a/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/execution/DockerComposeExecutable.java +++ b/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/execution/DockerComposeExecutable.java @@ -29,6 +29,7 @@ public abstract class DockerComposeExecutable implements Executable { private static final Logger log = LoggerFactory.getLogger(DockerComposeExecutable.class); private static final DockerCommandLocations DOCKER_COMPOSE_LOCATIONS = new DockerCommandLocations( + "docker-compose", true, System.getenv("DOCKER_COMPOSE_LOCATION"), "/usr/local/bin/docker-compose", "/usr/bin/docker-compose" diff --git a/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/execution/DockerExecutable.java b/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/execution/DockerExecutable.java index 1ff5cf01e..54c4c36a2 100644 --- a/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/execution/DockerExecutable.java +++ b/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/execution/DockerExecutable.java @@ -27,6 +27,7 @@ public abstract class DockerExecutable implements Executable { private static final Logger log = LoggerFactory.getLogger(DockerExecutable.class); private static final DockerCommandLocations DOCKER_LOCATIONS = new DockerCommandLocations( + "docker", true, System.getenv("DOCKER_LOCATION"), "/usr/local/bin/docker", "/usr/bin/docker" diff --git a/docker-compose-rule-core/src/test/java/com/palantir/docker/compose/execution/DockerCommandLocationsShould.java b/docker-compose-rule-core/src/test/java/com/palantir/docker/compose/execution/DockerCommandLocationsShould.java index f5b2e44eb..c92845eae 100644 --- a/docker-compose-rule-core/src/test/java/com/palantir/docker/compose/execution/DockerCommandLocationsShould.java +++ b/docker-compose-rule-core/src/test/java/com/palantir/docker/compose/execution/DockerCommandLocationsShould.java @@ -41,6 +41,7 @@ public void setup() throws IOException { @Test public void provide_the_first_docker_command_location_if_it_exists() { DockerCommandLocations dockerCommandLocations = new DockerCommandLocations( + null, false, badLocation, goodLocation, otherBadLocation); @@ -52,6 +53,7 @@ public void setup() throws IOException { @Test public void skip_paths_from_environment_variables_that_are_unset() { DockerCommandLocations dockerCommandLocations = new DockerCommandLocations( + null, false, System.getenv("AN_UNSET_DOCKER_COMPOSE_PATH"), goodLocation); @@ -62,6 +64,7 @@ public void setup() throws IOException { @Test public void have_no_preferred_path_when_all_possible_paths_are_all_invalid() { DockerCommandLocations dockerCommandLocations = new DockerCommandLocations( + null, false, badLocation); assertThat(dockerCommandLocations.preferredLocation(), From 1162fbdab4b3c3b59e40255616b57fffff3c76cf Mon Sep 17 00:00:00 2001 From: Thomas Diamantis Date: Wed, 15 Feb 2017 17:23:30 +0200 Subject: [PATCH 2/2] use immutables to build DockerCommandLocations --- .../execution/DockerCommandLocations.java | 44 ++++++---- .../execution/DockerComposeExecutable.java | 13 +-- .../compose/execution/DockerExecutable.java | 13 +-- .../DockerCommandLocationsShould.java | 87 ++++++++++++++++--- 4 files changed, 113 insertions(+), 44 deletions(-) diff --git a/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/execution/DockerCommandLocations.java b/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/execution/DockerCommandLocations.java index 5bb8e63f1..a7614cc5e 100644 --- a/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/execution/DockerCommandLocations.java +++ b/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/execution/DockerCommandLocations.java @@ -15,8 +15,6 @@ */ package com.palantir.docker.compose.execution; -import static java.util.Arrays.asList; - import java.io.File; import java.nio.file.Paths; import java.util.Arrays; @@ -24,31 +22,28 @@ import java.util.List; import java.util.Optional; import java.util.function.Predicate; +import java.util.stream.Collectors; import java.util.stream.Stream; -import org.apache.commons.lang3.StringUtils; -public class DockerCommandLocations { +import org.immutables.value.Value; + +@Value.Immutable +public abstract class DockerCommandLocations { private static final Predicate IS_NOT_NULL = path -> path != null; private static final Predicate FILE_EXISTS = path -> new File(path).exists(); - private final List possiblePaths; - private final String exeName; - private final boolean lookInPath; - - public DockerCommandLocations(String exeName, boolean lookInPath, String... possiblePaths) { - this.exeName = exeName; - this.lookInPath = lookInPath; - this.possiblePaths = asList(possiblePaths); + protected abstract String executableName(); + protected abstract List> additionalSearchLocations(); + @Value.Default protected List pathLocations() { + String envpath = System.getenv("PATH"); + return envpath == null ? Collections.emptyList() : Arrays.asList(envpath.split(File.pathSeparator)); } + @Value.Derived public Optional preferredLocation() { - List envPath = (StringUtils.isNotBlank(exeName) && lookInPath) - ? Arrays.asList(System.getenv("PATH").split(File.pathSeparator)) : - Collections.emptyList(); - return Stream.concat( - envPath.stream().map(path -> Paths.get(path, exeName).toAbsolutePath().toString()), - possiblePaths.stream()) + pathLocations().stream().map(path -> Paths.get(path, executableName()).toAbsolutePath().toString()), + additionalSearchLocations().stream().filter(Optional::isPresent).map(Optional::get)) .filter(IS_NOT_NULL) .filter(FILE_EXISTS) .findFirst(); @@ -56,6 +51,17 @@ public Optional preferredLocation() { @Override public String toString() { - return "DockerCommandLocations{possiblePaths=" + possiblePaths + "}"; + return "DockerCommandLocations{additionalSearchLocations=" + additionalSearchLocations() + "}"; + } + + public static ImmutableDockerCommandLocations.Builder builder() { + return ImmutableDockerCommandLocations.builder(); + } + + /** + * convert an array of strings to a list of optionals. used to make calling `additionalSearchLocations' a bit friendlier. + */ + public static List> optionals(String ... strings) { + return Arrays.stream(strings).map(Optional::ofNullable).collect(Collectors.toList()); } } diff --git a/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/execution/DockerComposeExecutable.java b/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/execution/DockerComposeExecutable.java index 716d4acbe..9aa3f58f2 100644 --- a/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/execution/DockerComposeExecutable.java +++ b/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/execution/DockerComposeExecutable.java @@ -28,12 +28,13 @@ public abstract class DockerComposeExecutable implements Executable { private static final Logger log = LoggerFactory.getLogger(DockerComposeExecutable.class); - private static final DockerCommandLocations DOCKER_COMPOSE_LOCATIONS = new DockerCommandLocations( - "docker-compose", true, - System.getenv("DOCKER_COMPOSE_LOCATION"), - "/usr/local/bin/docker-compose", - "/usr/bin/docker-compose" - ); + private static final DockerCommandLocations DOCKER_COMPOSE_LOCATIONS = DockerCommandLocations.builder() + .executableName("docker-compose") + .additionalSearchLocations(DockerCommandLocations.optionals( + System.getenv("DOCKER_COMPOSE_LOCATION"), + "/usr/local/bin/docker-compose", + "/usr/bin/docker-compose" + )).build(); @Value.Parameter protected abstract DockerComposeFiles dockerComposeFiles(); @Value.Parameter protected abstract DockerConfiguration dockerConfiguration(); diff --git a/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/execution/DockerExecutable.java b/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/execution/DockerExecutable.java index 54c4c36a2..014c76347 100644 --- a/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/execution/DockerExecutable.java +++ b/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/execution/DockerExecutable.java @@ -26,12 +26,13 @@ public abstract class DockerExecutable implements Executable { private static final Logger log = LoggerFactory.getLogger(DockerExecutable.class); - private static final DockerCommandLocations DOCKER_LOCATIONS = new DockerCommandLocations( - "docker", true, - System.getenv("DOCKER_LOCATION"), - "/usr/local/bin/docker", - "/usr/bin/docker" - ); + private static final DockerCommandLocations DOCKER_LOCATIONS = DockerCommandLocations.builder() + .executableName("docker") + .additionalSearchLocations(DockerCommandLocations.optionals( + System.getenv("DOCKER_LOCATION"), + "/usr/local/bin/docker", + "/usr/bin/docker" + )).build(); @Value.Parameter protected abstract DockerConfiguration dockerConfiguration(); diff --git a/docker-compose-rule-core/src/test/java/com/palantir/docker/compose/execution/DockerCommandLocationsShould.java b/docker-compose-rule-core/src/test/java/com/palantir/docker/compose/execution/DockerCommandLocationsShould.java index c92845eae..4492505b3 100644 --- a/docker-compose-rule-core/src/test/java/com/palantir/docker/compose/execution/DockerCommandLocationsShould.java +++ b/docker-compose-rule-core/src/test/java/com/palantir/docker/compose/execution/DockerCommandLocationsShould.java @@ -19,7 +19,11 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; +import java.io.File; import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -28,23 +32,33 @@ public class DockerCommandLocationsShould { private static final String badLocation = "file/that/does/not/exist"; private static final String otherBadLocation = "another/file/that/does/not/exist"; + private static final String someLocationInPath = "/folder/not/containing/docker-cmd"; + private static final String someOtherLocationInPath = "/folder/not/containing/docker-cmd"; + private static final String FILENAME = "docker-compose.yml"; + @Rule public TemporaryFolder folder = new TemporaryFolder(); private String goodLocation; + private String goodLocationParent; @Before public void setup() throws IOException { - goodLocation = folder.newFile("docker-compose.yml").getAbsolutePath(); + File file = folder.newFile(FILENAME); + goodLocation = file.getAbsolutePath(); + goodLocationParent = file.getParent(); } @Test public void provide_the_first_docker_command_location_if_it_exists() { - DockerCommandLocations dockerCommandLocations = new DockerCommandLocations( - null, false, - badLocation, - goodLocation, - otherBadLocation); + DockerCommandLocations dockerCommandLocations = DockerCommandLocations.builder() + .executableName(FILENAME) + .pathLocations(Collections.emptyList()) + .additionalSearchLocations(DockerCommandLocations.optionals( + badLocation, + goodLocation, + otherBadLocation + )).build(); assertThat(dockerCommandLocations.preferredLocation().get(), is(goodLocation)); @@ -52,10 +66,13 @@ public void setup() throws IOException { @Test public void skip_paths_from_environment_variables_that_are_unset() { - DockerCommandLocations dockerCommandLocations = new DockerCommandLocations( - null, false, - System.getenv("AN_UNSET_DOCKER_COMPOSE_PATH"), - goodLocation); + DockerCommandLocations dockerCommandLocations = DockerCommandLocations.builder() + .executableName(FILENAME) + .pathLocations(Collections.emptyList()) + .additionalSearchLocations(DockerCommandLocations.optionals( + System.getenv("AN_UNSET_DOCKER_COMPOSE_PATH"), + goodLocation + )).build(); assertThat(dockerCommandLocations.preferredLocation().get(), is(goodLocation)); @@ -63,9 +80,53 @@ public void setup() throws IOException { @Test public void have_no_preferred_path_when_all_possible_paths_are_all_invalid() { - DockerCommandLocations dockerCommandLocations = new DockerCommandLocations( - null, false, - badLocation); + DockerCommandLocations dockerCommandLocations = DockerCommandLocations.builder() + .executableName(FILENAME) + .pathLocations(Collections.emptyList()) + .additionalSearchLocations(DockerCommandLocations.optionals( + badLocation + )).build(); + + assertThat(dockerCommandLocations.preferredLocation(), + is(empty())); + } + + @Test public void + discover_docker_command_in_envpath() { + DockerCommandLocations dockerCommandLocations = DockerCommandLocations.builder() + .executableName(FILENAME) + //path will contain directories, not full path to docker cmd + .pathLocations(Arrays.asList(someLocationInPath, someOtherLocationInPath, goodLocationParent)) + .additionalSearchLocations(DockerCommandLocations.optionals( + badLocation, + otherBadLocation + )).build(); + + assertThat(dockerCommandLocations.preferredLocation().get(), + is(goodLocation)); //but result will be the full path to docker cmd + } + + @Test public void + have_no_preferred_path_when_all_possible_paths_are_all_invalid_with_envpath() { + DockerCommandLocations dockerCommandLocations = DockerCommandLocations.builder() + .executableName(FILENAME) + .pathLocations(Arrays.asList(someLocationInPath, someOtherLocationInPath)) + .additionalSearchLocations(DockerCommandLocations.optionals( + badLocation, + otherBadLocation + )).build(); + + assertThat(dockerCommandLocations.preferredLocation(), + is(empty())); + } + + @Test public void + dont_fail_for_empty_lists() { + DockerCommandLocations dockerCommandLocations = DockerCommandLocations.builder() + .executableName(FILENAME) + .pathLocations(Collections.emptyList()) + .additionalSearchLocations(Collections.emptyList()) + .build(); assertThat(dockerCommandLocations.preferredLocation(), is(empty()));