Skip to content

Commit ec30edc

Browse files
authored
Merge pull request docker-java#835 from KostyaSha/pr/739
Reworked PR docker-java#739 (multiple tags)
2 parents 4604067 + c82b92d commit ec30edc

File tree

7 files changed

+189
-32
lines changed

7 files changed

+189
-32
lines changed

src/main/java/com/github/dockerjava/api/command/BuildImageCmd.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import java.io.InputStream;
55
import java.net.URI;
66
import java.util.Map;
7+
import java.util.Set;
78

89
import javax.annotation.CheckForNull;
910
import javax.annotation.Nonnull;
@@ -34,10 +35,21 @@ public interface BuildImageCmd extends AsyncDockerCmd<BuildImageCmd, BuildRespon
3435

3536
/**
3637
* "t" in API
38+
*
39+
* @deprecated since docker API version 1.21 there can be multiple tags
40+
* specified so use {@link #getTags()}
3741
*/
3842
@CheckForNull
43+
@Deprecated
3944
String getTag();
4045

46+
/**
47+
* Multple "t" tags.
48+
* @since {@link RemoteApiVersion#VERSION_1_21}
49+
*/
50+
@CheckForNull
51+
Set<String> getTags();
52+
4153
/**
4254
* "remote" in API
4355
*/
@@ -109,8 +121,15 @@ public interface BuildImageCmd extends AsyncDockerCmd<BuildImageCmd, BuildRespon
109121

110122
// setters
111123

124+
/**
125+
* @deprecated since docker API version 1.21 there can be multiple tags
126+
* specified so use {@link #withTags(Set<String>)}
127+
*/
128+
@Deprecated
112129
BuildImageCmd withTag(String tag);
113130

131+
BuildImageCmd withTags(Set<String> tags);
132+
114133
BuildImageCmd withRemote(URI remote);
115134

116135
BuildImageCmd withBaseDirectory(File baseDirectory);

src/main/java/com/github/dockerjava/core/command/BuildImageCmdImpl.java

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,28 @@
88
import java.net.URI;
99
import java.util.HashMap;
1010
import java.util.Map;
11+
import java.util.Set;
1112

1213
import com.github.dockerjava.api.command.BuildImageCmd;
1314
import com.github.dockerjava.api.model.AuthConfigurations;
1415
import com.github.dockerjava.api.model.BuildResponseItem;
1516
import com.github.dockerjava.core.dockerfile.Dockerfile;
1617
import com.github.dockerjava.core.util.FilePathUtil;
1718

19+
import javax.annotation.CheckForNull;
20+
1821
/**
19-
*
2022
* Build an image from Dockerfile.
21-
*
2223
*/
2324
public class BuildImageCmdImpl extends AbstrAsyncDockerCmd<BuildImageCmd, BuildResponseItem> implements BuildImageCmd {
2425

2526
private InputStream tarInputStream;
2627

28+
@Deprecated
2729
private String tag;
2830

31+
private Set<String> tags;
32+
2933
private Boolean noCache;
3034

3135
private Boolean remove = true;
@@ -84,11 +88,17 @@ public BuildImageCmdImpl(BuildImageCmd.Exec exec, InputStream tarInputStream) {
8488

8589
// getters API
8690

91+
@Deprecated
8792
@Override
8893
public String getTag() {
8994
return tag;
9095
}
9196

97+
@CheckForNull
98+
public Set<String> getTags() {
99+
return tags;
100+
}
101+
92102
@Override
93103
public URI getRemote() {
94104
return remote;
@@ -182,13 +192,23 @@ public Long getShmsize() {
182192

183193
// setters
184194

195+
/**
196+
* @deprecated use #withTags()
197+
*/
198+
@Deprecated
185199
@Override
186200
public BuildImageCmdImpl withTag(String tag) {
187201
checkNotNull(tag, "Tag is null");
188202
this.tag = tag;
189203
return this;
190204
}
191205

206+
@Override
207+
public BuildImageCmd withTags(Set<String> tags) {
208+
this.tags = tags;
209+
return this;
210+
}
211+
192212
@Override
193213
public BuildImageCmd withRemote(URI remote) {
194214
this.remote = remote;

src/main/java/com/github/dockerjava/jaxrs/BuildImageCmdExec.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.github.dockerjava.jaxrs;
22

33
import static javax.ws.rs.client.Entity.entity;
4+
import static org.apache.commons.lang.StringUtils.isNotBlank;
45

56
import javax.ws.rs.client.Invocation;
67
import javax.ws.rs.client.WebTarget;
@@ -65,9 +66,15 @@ protected AbstractCallbackNotifier<BuildResponseItem> callbackNotifier(BuildImag
6566
if (dockerFilePath != null && command.getRemote() == null && !"Dockerfile".equals(dockerFilePath)) {
6667
webTarget = webTarget.queryParam("dockerfile", dockerFilePath);
6768
}
68-
if (command.getTag() != null) {
69+
70+
if (command.getTags() != null && !command.getTags().isEmpty()) {
71+
for (String t : command.getTags()) {
72+
webTarget = webTarget.queryParam("t", t);
73+
}
74+
} else if (isNotBlank(command.getTag())) {
6975
webTarget = webTarget.queryParam("t", command.getTag());
7076
}
77+
7178
if (command.getRemote() != null) {
7279
webTarget = webTarget.queryParam("remote", command.getRemote().toString());
7380
}

src/main/java/com/github/dockerjava/netty/WebTarget.java

Lines changed: 77 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,59 @@
11
package com.github.dockerjava.netty;
22

3+
import java.io.IOException;
4+
import java.io.UnsupportedEncodingException;
5+
import java.net.URLEncoder;
6+
import java.nio.charset.Charset;
7+
import java.nio.charset.UnsupportedCharsetException;
38
import java.util.ArrayList;
49
import java.util.Arrays;
510
import java.util.List;
611
import java.util.Map;
12+
import java.util.Set;
713

14+
import com.fasterxml.jackson.databind.ObjectMapper;
15+
import com.google.common.collect.ImmutableSet;
16+
import io.netty.handler.codec.http.HttpConstants;
817
import org.apache.commons.lang.StringUtils;
918

1019
import com.google.common.collect.ImmutableList;
1120
import com.google.common.collect.ImmutableMap;
1221

1322
/**
14-
* This class is basically a replacement of javax.ws.rs.client.WebTarget to allow simpler migration of JAX-RS code to a netty based
23+
* This class is basically a replacement of {@link javax.ws.rs.client.WebTarget} to allow simpler migration of JAX-RS code to a netty based
1524
* implementation.
1625
*
1726
* @author Marcus Linke
1827
*/
1928
public class WebTarget {
29+
private static final ObjectMapper MAPPER = new ObjectMapper();
2030

2131
private final ChannelProvider channelProvider;
2232

2333
private final ImmutableList<String> path;
2434

2535
private final ImmutableMap<String, String> queryParams;
2636

37+
/**
38+
* Multiple values for the same name param.
39+
*/
40+
private final ImmutableMap<String, Set<String>> queryParamsSet;
41+
2742
private static final String PATH_SEPARATOR = "/";
2843

2944
public WebTarget(ChannelProvider channelProvider) {
30-
this(channelProvider, ImmutableList.<String>of(), ImmutableMap.<String, String>of());
45+
this(channelProvider, ImmutableList.<String>of(), ImmutableMap.<String, String>of(),
46+
ImmutableMap.<String, Set<String>>of());
3147
}
3248

3349
private WebTarget(ChannelProvider channelProvider,
3450
ImmutableList<String> path,
35-
ImmutableMap<String, String> queryParams) {
51+
ImmutableMap<String, String> queryParams,
52+
ImmutableMap<String, Set<String>> queryParamsSet) {
3653
this.channelProvider = channelProvider;
3754
this.path = path;
3855
this.queryParams = queryParams;
56+
this.queryParamsSet = queryParamsSet;
3957
}
4058

4159
public WebTarget path(String... components) {
@@ -45,15 +63,21 @@ public WebTarget path(String... components) {
4563
newPath.addAll(Arrays.asList(StringUtils.split(component, PATH_SEPARATOR)));
4664
}
4765

48-
return new WebTarget(channelProvider, newPath.build(), queryParams);
66+
return new WebTarget(channelProvider, newPath.build(), queryParams, queryParamsSet);
4967
}
5068

5169
public InvocationBuilder request() {
5270
String resource = PATH_SEPARATOR + StringUtils.join(path, PATH_SEPARATOR);
5371

5472
List<String> params = new ArrayList<>();
5573
for (Map.Entry<String, String> entry : queryParams.entrySet()) {
56-
params.add(entry.getKey() + "=" + entry.getValue());
74+
params.add(entry.getKey() + "=" + encodeComponent(entry.getValue(), HttpConstants.DEFAULT_CHARSET));
75+
}
76+
77+
for (Map.Entry<String, Set<String>> entry : queryParamsSet.entrySet()) {
78+
for (String entryValueValue : entry.getValue()) {
79+
params.add(entry.getKey() + "=" + encodeComponent(entryValueValue, HttpConstants.DEFAULT_CHARSET));
80+
}
5781
}
5882

5983
if (!params.isEmpty()) {
@@ -63,21 +87,58 @@ public InvocationBuilder request() {
6387
return new InvocationBuilder(channelProvider, resource);
6488
}
6589

90+
/**
91+
* @see io.netty.handler.codec.http.QueryStringEncoder
92+
*/
93+
private static String encodeComponent(String s, Charset charset) {
94+
// TODO: Optimize me.
95+
try {
96+
return URLEncoder.encode(s, charset.name()).replace("+", "%20");
97+
} catch (UnsupportedEncodingException ignored) {
98+
throw new UnsupportedCharsetException(charset.name());
99+
}
100+
}
101+
66102
public WebTarget resolveTemplate(String name, Object value) {
67103
ImmutableList.Builder<String> newPath = ImmutableList.builder();
68104
for (String component : path) {
69105
component = component.replaceAll("\\{" + name + "\\}", value.toString());
70106
newPath.add(component);
71107
}
72-
return new WebTarget(channelProvider, newPath.build(), queryParams);
108+
return new WebTarget(channelProvider, newPath.build(), queryParams, queryParamsSet);
73109
}
74110

75111
public WebTarget queryParam(String name, Object value) {
76112
ImmutableMap.Builder<String, String> builder = ImmutableMap.<String, String>builder().putAll(queryParams);
77113
if (value != null) {
78114
builder.put(name, value.toString());
79115
}
80-
return new WebTarget(channelProvider, path, builder.build());
116+
return new WebTarget(channelProvider, path, builder.build(), queryParamsSet);
117+
}
118+
119+
public WebTarget queryParamsSet(String name, Set<?> values) {
120+
ImmutableMap.Builder<String, Set<String>> builder = ImmutableMap.<String, Set<String>>builder().putAll(queryParamsSet);
121+
if (values != null) {
122+
ImmutableSet.Builder<String> valueBuilder = ImmutableSet.builder();
123+
for (Object value : values) {
124+
valueBuilder.add(value.toString());
125+
}
126+
builder.put(name, valueBuilder.build());
127+
}
128+
return new WebTarget(channelProvider, path, queryParams, builder.build());
129+
}
130+
131+
public WebTarget queryParamsJsonMap(String name, Map<String, String> values) {
132+
if (values != null && !values.isEmpty()) {
133+
try {
134+
// when param value is JSON string
135+
return queryParam(name, MAPPER.writeValueAsString(values));
136+
} catch (IOException e) {
137+
throw new RuntimeException(e);
138+
}
139+
} else {
140+
return this;
141+
}
81142
}
82143

83144
@Override
@@ -97,14 +158,22 @@ public boolean equals(Object o) {
97158
if (path != null ? !path.equals(webTarget.path) : webTarget.path != null) {
98159
return false;
99160
}
100-
return queryParams != null ? queryParams.equals(webTarget.queryParams) : webTarget.queryParams == null;
161+
if (queryParams != null ? !queryParams.equals(webTarget.queryParams) : webTarget.queryParams != null) {
162+
return false;
163+
}
164+
if (queryParamsSet != null ? !queryParamsSet.equals(webTarget.queryParamsSet) : webTarget.queryParamsSet != null) {
165+
return false;
166+
}
167+
168+
return true;
101169
}
102170

103171
@Override
104172
public int hashCode() {
105173
int result = channelProvider != null ? channelProvider.hashCode() : 0;
106174
result = 31 * result + (path != null ? path.hashCode() : 0);
107175
result = 31 * result + (queryParams != null ? queryParams.hashCode() : 0);
176+
result = 31 * result + (queryParamsSet != null ? queryParamsSet.hashCode() : 0);
108177
return result;
109178
}
110179
}

src/main/java/com/github/dockerjava/netty/exec/BuildImageCmdExec.java

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.github.dockerjava.netty.exec;
22

3-
import com.fasterxml.jackson.databind.ObjectMapper;
43
import org.slf4j.Logger;
54
import org.slf4j.LoggerFactory;
65

@@ -14,15 +13,12 @@
1413
import com.github.dockerjava.netty.MediaType;
1514
import com.github.dockerjava.netty.WebTarget;
1615

17-
import java.io.IOException;
18-
import java.util.Map;
16+
import static org.apache.commons.lang.StringUtils.isNotBlank;
1917

2018
public class BuildImageCmdExec extends AbstrAsyncDockerCmdExec<BuildImageCmd, BuildResponseItem> implements
2119
BuildImageCmd.Exec {
2220
private static final Logger LOGGER = LoggerFactory.getLogger(BuildImageCmdExec.class);
2321

24-
private static final ObjectMapper MAPPER = new ObjectMapper();
25-
2622
public BuildImageCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) {
2723
super(baseResource, dockerClientConfig);
2824
}
@@ -55,9 +51,13 @@ protected Void execute0(BuildImageCmd command, ResultCallback<BuildResponseItem>
5551
if (dockerFilePath != null && command.getRemote() == null && !"Dockerfile".equals(dockerFilePath)) {
5652
webTarget = webTarget.queryParam("dockerfile", dockerFilePath);
5753
}
58-
if (command.getTag() != null) {
59-
webTarget = webTarget.queryParam("t", command.getTag());
54+
55+
if (command.getTags() != null && !command.getTags().isEmpty()) {
56+
webTarget = webTarget.queryParamsSet("t", command.getTags());
57+
} else if (isNotBlank(command.getTag())) {
58+
webTarget = webTarget.queryParam("t", command.getTags());
6059
}
60+
6161
if (command.getRemote() != null) {
6262
webTarget = webTarget.queryParam("remote", command.getRemote().toString());
6363
}
@@ -86,13 +86,17 @@ protected Void execute0(BuildImageCmd command, ResultCallback<BuildResponseItem>
8686
webTarget = webTarget.queryParam("cpusetcpus", command.getCpusetcpus());
8787
}
8888

89-
webTarget = writeMap(webTarget, "buildargs", command.getBuildArgs());
89+
if (command.getBuildArgs() != null) {
90+
webTarget = webTarget.queryParamsJsonMap("buildargs", command.getBuildArgs());
91+
}
9092

9193
if (command.getShmsize() != null) {
9294
webTarget = webTarget.queryParam("shmsize", command.getShmsize());
9395
}
9496

95-
webTarget = writeMap(webTarget, "labels", command.getLabels());
97+
if (command.getLabels() != null) {
98+
webTarget = webTarget.queryParamsJsonMap("labels", command.getLabels());
99+
}
96100

97101
LOGGER.trace("POST: {}", webTarget);
98102

@@ -106,16 +110,4 @@ protected Void execute0(BuildImageCmd command, ResultCallback<BuildResponseItem>
106110

107111
return null;
108112
}
109-
110-
private WebTarget writeMap(WebTarget webTarget, String name, Map<String, String> value) {
111-
if (value != null && !value.isEmpty()) {
112-
try {
113-
return webTarget.queryParam(name, MAPPER.writeValueAsString(value));
114-
} catch (IOException e) {
115-
throw new RuntimeException(e);
116-
}
117-
} else {
118-
return webTarget;
119-
}
120-
}
121113
}

0 commit comments

Comments
 (0)