From 81a33c697538ae46c707bbbefd2afa8c19c641a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Warcha=C5=82?= Date: Tue, 15 Nov 2016 13:48:57 +0100 Subject: [PATCH 1/2] Allow multiple tags in build image command Several tags for image can be defined by calling multiple time withTag() method of BuildImageCmd. In Netty implementation, the WebTarget class is modified to support several query parameteres with the same name. Fix #720 --- .../dockerjava/api/command/BuildImageCmd.java | 24 +++++++++---- .../core/command/BuildImageCmdImpl.java | 34 +++++++++++++------ .../dockerjava/jaxrs/BuildImageCmdExec.java | 6 ++-- .../github/dockerjava/netty/WebTarget.java | 20 +++++++---- .../netty/exec/BuildImageCmdExec.java | 4 +-- .../core/command/BuildImageCmdImplTest.java | 22 ++++++++++++ .../netty/exec/BuildImageCmdExecTest.java | 22 ++++++++++++ 7 files changed, 103 insertions(+), 29 deletions(-) diff --git a/src/main/java/com/github/dockerjava/api/command/BuildImageCmd.java b/src/main/java/com/github/dockerjava/api/command/BuildImageCmd.java index ac98db2f9..29cfab7c5 100644 --- a/src/main/java/com/github/dockerjava/api/command/BuildImageCmd.java +++ b/src/main/java/com/github/dockerjava/api/command/BuildImageCmd.java @@ -1,16 +1,16 @@ package com.github.dockerjava.api.command; +import com.github.dockerjava.api.model.AuthConfigurations; +import com.github.dockerjava.api.model.BuildResponseItem; +import com.github.dockerjava.core.RemoteApiVersion; + +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; import java.io.File; import java.io.InputStream; import java.net.URI; import java.util.Map; - -import javax.annotation.CheckForNull; -import javax.annotation.Nonnull; - -import com.github.dockerjava.api.model.AuthConfigurations; -import com.github.dockerjava.api.model.BuildResponseItem; -import com.github.dockerjava.core.RemoteApiVersion; +import java.util.Set; /** * Build an image from Dockerfile. @@ -34,7 +34,11 @@ public interface BuildImageCmd extends AsyncDockerCmd getLabels(); + /** + * @since {@link RemoteApiVersion#VERSION_1_21} + */ + @CheckForNull + Set getTags(); + // setters BuildImageCmd withTag(String tag); diff --git a/src/main/java/com/github/dockerjava/core/command/BuildImageCmdImpl.java b/src/main/java/com/github/dockerjava/core/command/BuildImageCmdImpl.java index c34b05155..557c415b2 100644 --- a/src/main/java/com/github/dockerjava/core/command/BuildImageCmdImpl.java +++ b/src/main/java/com/github/dockerjava/core/command/BuildImageCmdImpl.java @@ -1,30 +1,30 @@ package com.github.dockerjava.core.command; -import static com.google.common.base.Preconditions.checkNotNull; +import com.github.dockerjava.api.command.BuildImageCmd; +import com.github.dockerjava.api.model.AuthConfigurations; +import com.github.dockerjava.api.model.BuildResponseItem; +import com.github.dockerjava.core.dockerfile.Dockerfile; +import com.github.dockerjava.core.util.FilePathUtil; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; -import com.github.dockerjava.api.command.BuildImageCmd; -import com.github.dockerjava.api.model.AuthConfigurations; -import com.github.dockerjava.api.model.BuildResponseItem; -import com.github.dockerjava.core.dockerfile.Dockerfile; -import com.github.dockerjava.core.util.FilePathUtil; +import static com.google.common.base.Preconditions.checkNotNull; /** - * * Build an image from Dockerfile. - * */ public class BuildImageCmdImpl extends AbstrAsyncDockerCmd implements BuildImageCmd { private InputStream tarInputStream; - private String tag; + private Set tags; private Boolean noCache; @@ -84,7 +84,11 @@ public BuildImageCmdImpl(BuildImageCmd.Exec exec, InputStream tarInputStream) { @Override public String getTag() { - return tag; + if (tags == null || tags.isEmpty()) { + return null; + } + // return first tag to be backward compatible + return tags.iterator().next(); } @Override @@ -156,6 +160,11 @@ public Map getLabels() { return labels; } + @Override + public Set getTags() { + return tags; + } + // getter lib specific @Override @@ -181,7 +190,10 @@ public Long getShmsize() { @Override public BuildImageCmdImpl withTag(String tag) { checkNotNull(tag, "Tag is null"); - this.tag = tag; + if (this.tags == null) { + this.tags = new HashSet<>(4); + } + this.tags.add(tag); return this; } diff --git a/src/main/java/com/github/dockerjava/jaxrs/BuildImageCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/BuildImageCmdExec.java index 2a7aea40e..7a203c639 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/BuildImageCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/BuildImageCmdExec.java @@ -65,8 +65,10 @@ protected AbstractCallbackNotifier callbackNotifier(BuildImag if (dockerFilePath != null && command.getRemote() == null && !"Dockerfile".equals(dockerFilePath)) { webTarget = webTarget.queryParam("dockerfile", dockerFilePath); } - if (command.getTag() != null) { - webTarget = webTarget.queryParam("t", command.getTag()); + if (command.getTags() != null && !command.getTags().isEmpty()) { + for (String t : command.getTags()) { + webTarget = webTarget.queryParam("t", t); + } } if (command.getRemote() != null) { webTarget = webTarget.queryParam("remote", command.getRemote().toString()); diff --git a/src/main/java/com/github/dockerjava/netty/WebTarget.java b/src/main/java/com/github/dockerjava/netty/WebTarget.java index ef1510f5c..d8273b55a 100644 --- a/src/main/java/com/github/dockerjava/netty/WebTarget.java +++ b/src/main/java/com/github/dockerjava/netty/WebTarget.java @@ -22,17 +22,17 @@ public class WebTarget { private final ImmutableList path; - private final ImmutableMap queryParams; + private final ImmutableMap queryParams; private static final String PATH_SEPARATOR = "/"; public WebTarget(ChannelProvider channelProvider) { - this(channelProvider, ImmutableList.of(), ImmutableMap.of()); + this(channelProvider, ImmutableList.of(), ImmutableMap.of()); } private WebTarget(ChannelProvider channelProvider, ImmutableList path, - ImmutableMap queryParams) { + ImmutableMap queryParams) { this.channelProvider = channelProvider; this.path = path; this.queryParams = queryParams; @@ -52,8 +52,14 @@ public InvocationBuilder request() { String resource = PATH_SEPARATOR + StringUtils.join(path, PATH_SEPARATOR); List params = new ArrayList<>(); - for (Map.Entry entry : queryParams.entrySet()) { - params.add(entry.getKey() + "=" + entry.getValue()); + for (Map.Entry entry : queryParams.entrySet()) { + if (entry.getValue() instanceof Iterable) { + for (Object i : (Iterable) entry.getValue()) { + params.add(entry.getKey() + "=" + i.toString()); + } + } else { + params.add(entry.getKey() + "=" + entry.getValue().toString()); + } } if (!params.isEmpty()) { @@ -73,9 +79,9 @@ public WebTarget resolveTemplate(String name, Object value) { } public WebTarget queryParam(String name, Object value) { - ImmutableMap.Builder builder = ImmutableMap.builder().putAll(queryParams); + ImmutableMap.Builder builder = ImmutableMap.builder().putAll(queryParams); if (value != null) { - builder.put(name, value.toString()); + builder.put(name, value); } return new WebTarget(channelProvider, path, builder.build()); } diff --git a/src/main/java/com/github/dockerjava/netty/exec/BuildImageCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/BuildImageCmdExec.java index 43152570e..4b3c56e10 100644 --- a/src/main/java/com/github/dockerjava/netty/exec/BuildImageCmdExec.java +++ b/src/main/java/com/github/dockerjava/netty/exec/BuildImageCmdExec.java @@ -55,8 +55,8 @@ protected Void execute0(BuildImageCmd command, ResultCallback if (dockerFilePath != null && command.getRemote() == null && !"Dockerfile".equals(dockerFilePath)) { webTarget = webTarget.queryParam("dockerfile", dockerFilePath); } - if (command.getTag() != null) { - webTarget = webTarget.queryParam("t", command.getTag()); + if (command.getTags() != null && !command.getTags().isEmpty()) { + webTarget = webTarget.queryParam("t", command.getTags()); } if (command.getRemote() != null) { webTarget = webTarget.queryParam("remote", command.getRemote().toString()); diff --git a/src/test/java/com/github/dockerjava/core/command/BuildImageCmdImplTest.java b/src/test/java/com/github/dockerjava/core/command/BuildImageCmdImplTest.java index cb4c1b2a8..6143755cd 100644 --- a/src/test/java/com/github/dockerjava/core/command/BuildImageCmdImplTest.java +++ b/src/test/java/com/github/dockerjava/core/command/BuildImageCmdImplTest.java @@ -274,6 +274,28 @@ public void labels() throws Exception { assertThat(inspectImageResponse.getConfig().getLabels().get("test"), equalTo("abc")); } + @Test + public void multipleTags() throws Exception { + if (!getVersion(dockerClient).isGreaterOrEqual(RemoteApiVersion.VERSION_1_21)) { + throw new SkipException("API version should be >= 1.21"); + } + + File baseDir = fileFromBuildTestResource("labels"); + + String imageId = dockerClient.buildImageCmd(baseDir).withNoCache(true) + .withTag("docker-java-test:tag1").withTag("docker-java-test:tag2") + .exec(new BuildImageResultCallback()) + .awaitImageId(); + + InspectImageResponse inspectImageResponse = dockerClient.inspectImageCmd(imageId).exec(); + assertThat(inspectImageResponse, not(nullValue())); + LOG.info("Image Inspect: {}", inspectImageResponse.toString()); + + assertThat(inspectImageResponse.getRepoTags().size(), equalTo(2)); + assertThat(inspectImageResponse.getRepoTags().contains("docker-java-test:tag1"), equalTo(true)); + assertThat(inspectImageResponse.getRepoTags().contains("docker-java-test:tag2"), equalTo(true)); + } + public void dockerfileNotInBaseDirectory() throws Exception { File baseDirectory = fileFromBuildTestResource("dockerfileNotInBaseDirectory"); File dockerfile = fileFromBuildTestResource("dockerfileNotInBaseDirectory/dockerfileFolder/Dockerfile"); diff --git a/src/test/java/com/github/dockerjava/netty/exec/BuildImageCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/BuildImageCmdExecTest.java index f567dcfc8..361fe1290 100644 --- a/src/test/java/com/github/dockerjava/netty/exec/BuildImageCmdExecTest.java +++ b/src/test/java/com/github/dockerjava/netty/exec/BuildImageCmdExecTest.java @@ -279,6 +279,28 @@ public void labels() throws Exception { assertThat(inspectImageResponse.getConfig().getLabels().get("test"), equalTo("abc")); } + @Test + public void multipleTags() throws Exception { + if (!getVersion(dockerClient).isGreaterOrEqual(RemoteApiVersion.VERSION_1_21)) { + throw new SkipException("API version should be >= 1.21"); + } + + File baseDir = fileFromBuildTestResource("labels"); + + String imageId = dockerClient.buildImageCmd(baseDir).withNoCache(true) + .withTag("docker-java-test:tag1").withTag("docker-java-test:tag2") + .exec(new BuildImageResultCallback()) + .awaitImageId(); + + InspectImageResponse inspectImageResponse = dockerClient.inspectImageCmd(imageId).exec(); + assertThat(inspectImageResponse, not(nullValue())); + LOG.info("Image Inspect: {}", inspectImageResponse.toString()); + + assertThat(inspectImageResponse.getRepoTags().size(), equalTo(2)); + assertThat(inspectImageResponse.getRepoTags().contains("docker-java-test:tag1"), equalTo(true)); + assertThat(inspectImageResponse.getRepoTags().contains("docker-java-test:tag2"), equalTo(true)); + } + public void dockerfileNotInBaseDirectory() throws Exception { File baseDirectory = fileFromBuildTestResource("dockerfileNotInBaseDirectory"); File dockerfile = fileFromBuildTestResource("dockerfileNotInBaseDirectory/dockerfileFolder/Dockerfile"); From 8e1f3922690478b487175affc4dd6f8802cc1c8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Warcha=C5=82?= Date: Wed, 29 Mar 2017 00:47:05 +0200 Subject: [PATCH 2/2] Preserve withTag and add withTags in build image command --- .../dockerjava/api/command/BuildImageCmd.java | 11 +++++++++- .../core/command/BuildImageCmdImpl.java | 20 +++++++++---------- .../dockerjava/jaxrs/BuildImageCmdExec.java | 3 +++ .../netty/exec/BuildImageCmdExec.java | 2 ++ .../core/command/BuildImageCmdImplTest.java | 9 ++++++--- .../netty/exec/BuildImageCmdExecTest.java | 9 ++++++--- 6 files changed, 37 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/github/dockerjava/api/command/BuildImageCmd.java b/src/main/java/com/github/dockerjava/api/command/BuildImageCmd.java index 29cfab7c5..06f4cb0cd 100644 --- a/src/main/java/com/github/dockerjava/api/command/BuildImageCmd.java +++ b/src/main/java/com/github/dockerjava/api/command/BuildImageCmd.java @@ -38,7 +38,7 @@ public interface BuildImageCmd extends AsyncDockerCmd)} + * @param tag + * @return + */ + @Deprecated BuildImageCmd withTag(String tag); + BuildImageCmd withTags(Set tags); + BuildImageCmd withRemote(URI remote); BuildImageCmd withBaseDirectory(File baseDirectory); diff --git a/src/main/java/com/github/dockerjava/core/command/BuildImageCmdImpl.java b/src/main/java/com/github/dockerjava/core/command/BuildImageCmdImpl.java index 557c415b2..87df8ecbb 100644 --- a/src/main/java/com/github/dockerjava/core/command/BuildImageCmdImpl.java +++ b/src/main/java/com/github/dockerjava/core/command/BuildImageCmdImpl.java @@ -11,7 +11,6 @@ import java.io.InputStream; import java.net.URI; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -24,6 +23,8 @@ public class BuildImageCmdImpl extends AbstrAsyncDockerCmd tags; private Boolean noCache; @@ -84,11 +85,7 @@ public BuildImageCmdImpl(BuildImageCmd.Exec exec, InputStream tarInputStream) { @Override public String getTag() { - if (tags == null || tags.isEmpty()) { - return null; - } - // return first tag to be backward compatible - return tags.iterator().next(); + return tag; } @Override @@ -190,10 +187,13 @@ public Long getShmsize() { @Override public BuildImageCmdImpl withTag(String tag) { checkNotNull(tag, "Tag is null"); - if (this.tags == null) { - this.tags = new HashSet<>(4); - } - this.tags.add(tag); + this.tag = tag; + return this; + } + + @Override + public BuildImageCmd withTags(Set tags) { + this.tags = tags; return this; } diff --git a/src/main/java/com/github/dockerjava/jaxrs/BuildImageCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/BuildImageCmdExec.java index 7a203c639..f014a2817 100644 --- a/src/main/java/com/github/dockerjava/jaxrs/BuildImageCmdExec.java +++ b/src/main/java/com/github/dockerjava/jaxrs/BuildImageCmdExec.java @@ -69,7 +69,10 @@ protected AbstractCallbackNotifier callbackNotifier(BuildImag for (String t : command.getTags()) { webTarget = webTarget.queryParam("t", t); } + } else if (command.getTag() != null) { + webTarget = webTarget.queryParam("t", command.getTag()); } + if (command.getRemote() != null) { webTarget = webTarget.queryParam("remote", command.getRemote().toString()); } diff --git a/src/main/java/com/github/dockerjava/netty/exec/BuildImageCmdExec.java b/src/main/java/com/github/dockerjava/netty/exec/BuildImageCmdExec.java index 4b3c56e10..e83da0445 100644 --- a/src/main/java/com/github/dockerjava/netty/exec/BuildImageCmdExec.java +++ b/src/main/java/com/github/dockerjava/netty/exec/BuildImageCmdExec.java @@ -57,6 +57,8 @@ protected Void execute0(BuildImageCmd command, ResultCallback } if (command.getTags() != null && !command.getTags().isEmpty()) { webTarget = webTarget.queryParam("t", command.getTags()); + } else if (command.getTag() != null) { + webTarget = webTarget.queryParam("t", command.getTag()); } if (command.getRemote() != null) { webTarget = webTarget.queryParam("remote", command.getRemote().toString()); diff --git a/src/test/java/com/github/dockerjava/core/command/BuildImageCmdImplTest.java b/src/test/java/com/github/dockerjava/core/command/BuildImageCmdImplTest.java index 6143755cd..9ba283732 100644 --- a/src/test/java/com/github/dockerjava/core/command/BuildImageCmdImplTest.java +++ b/src/test/java/com/github/dockerjava/core/command/BuildImageCmdImplTest.java @@ -7,13 +7,16 @@ import static org.hamcrest.Matchers.isEmptyString; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.nullValue; +import static org.hamcrest.Matchers.containsInAnyOrder; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.lang.reflect.Method; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.UUID; import org.apache.commons.io.FileUtils; @@ -283,7 +286,8 @@ public void multipleTags() throws Exception { File baseDir = fileFromBuildTestResource("labels"); String imageId = dockerClient.buildImageCmd(baseDir).withNoCache(true) - .withTag("docker-java-test:tag1").withTag("docker-java-test:tag2") + .withTag("fallback-when-withTags-not-called") + .withTags(new HashSet<>(Arrays.asList("docker-java-test:tag1", "docker-java-test:tag2"))) .exec(new BuildImageResultCallback()) .awaitImageId(); @@ -292,8 +296,7 @@ public void multipleTags() throws Exception { LOG.info("Image Inspect: {}", inspectImageResponse.toString()); assertThat(inspectImageResponse.getRepoTags().size(), equalTo(2)); - assertThat(inspectImageResponse.getRepoTags().contains("docker-java-test:tag1"), equalTo(true)); - assertThat(inspectImageResponse.getRepoTags().contains("docker-java-test:tag2"), equalTo(true)); + assertThat(inspectImageResponse.getRepoTags(), containsInAnyOrder("docker-java-test:tag1", "docker-java-test:tag2")); } public void dockerfileNotInBaseDirectory() throws Exception { diff --git a/src/test/java/com/github/dockerjava/netty/exec/BuildImageCmdExecTest.java b/src/test/java/com/github/dockerjava/netty/exec/BuildImageCmdExecTest.java index 361fe1290..55dcf353b 100644 --- a/src/test/java/com/github/dockerjava/netty/exec/BuildImageCmdExecTest.java +++ b/src/test/java/com/github/dockerjava/netty/exec/BuildImageCmdExecTest.java @@ -7,13 +7,16 @@ import static org.hamcrest.Matchers.isEmptyString; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.nullValue; +import static org.hamcrest.Matchers.containsInAnyOrder; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.lang.reflect.Method; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.UUID; import org.apache.commons.io.FileUtils; @@ -288,7 +291,8 @@ public void multipleTags() throws Exception { File baseDir = fileFromBuildTestResource("labels"); String imageId = dockerClient.buildImageCmd(baseDir).withNoCache(true) - .withTag("docker-java-test:tag1").withTag("docker-java-test:tag2") + .withTag("fallback-when-withTags-not-called") + .withTags(new HashSet<>(Arrays.asList("docker-java-test:tag1", "docker-java-test:tag2"))) .exec(new BuildImageResultCallback()) .awaitImageId(); @@ -297,8 +301,7 @@ public void multipleTags() throws Exception { LOG.info("Image Inspect: {}", inspectImageResponse.toString()); assertThat(inspectImageResponse.getRepoTags().size(), equalTo(2)); - assertThat(inspectImageResponse.getRepoTags().contains("docker-java-test:tag1"), equalTo(true)); - assertThat(inspectImageResponse.getRepoTags().contains("docker-java-test:tag2"), equalTo(true)); + assertThat(inspectImageResponse.getRepoTags(), containsInAnyOrder("docker-java-test:tag1", "docker-java-test:tag2")); } public void dockerfileNotInBaseDirectory() throws Exception {