Skip to content

Commit 809e6e0

Browse files
committed
revert HostConfig.Builder.binds() behavior that appended to list
Partially revert behavior introduced in 1f4d0c7 where the `HostConfig.Builder.binds(..)` method appends to the existing list instead of replaces it. We found a bunch of internal Spotify code that assumed that this method always did a replacement, and we found it easier to revert the change here in docker-client (while adding new methods for appending to the list).
1 parent eacd14a commit 809e6e0

File tree

4 files changed

+89
-23
lines changed

4 files changed

+89
-23
lines changed

docs/user_manual.md

+9-9
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ try (OutputStream imageOutput = new BufferedOutputStream(new FileOutputStream(im
439439
}
440440
}
441441
```
442-
442+
443443

444444
### Get a tarball containing all images.
445445

@@ -448,7 +448,7 @@ Not implemented yet. PRs welcome.
448448
### Load a tarball with a set of images and tags into docker
449449

450450
Not implemented yet. PRs welcome.
451-
451+
452452
### Exec Create
453453

454454
```java
@@ -488,19 +488,19 @@ There are two ways to make a bind:
488488
2. Create a `Bind` object and pass it to `binds()`.
489489

490490
If you only need to create a volume in a container, and you don't need it to mount any
491-
particular directory on the host, you can use the `volumes()` method on the
491+
particular directory on the host, you can use the `volumes()` method on the
492492
`ContainerConfig.Builder`.
493493

494494
```java
495-
final HostConfig hostConfig =
495+
final HostConfig hostConfig =
496496
HostConfig.builder()
497-
.binds("/local/path:/remote/path")
498-
.binds(Bind.from("/another/local/path")
497+
.appendBinds("/local/path:/remote/path")
498+
.appendBinds(Bind.from("/another/local/path")
499499
.to("/another/remote/path")
500500
.readOnly(true)
501501
.build())
502502
.build();
503-
final ContainerConfig volumeConfig =
503+
final ContainerConfig volumeConfig =
504504
ContainerConfig.builder()
505505
.image("busybox:latest")
506506
.volumes("/foo") // This volume will not mount any host directory
@@ -509,8 +509,8 @@ final ContainerConfig volumeConfig =
509509
```
510510

511511
#### A note on mounts
512-
Be aware that, starting with API version 1.20 (docker version 1.8.x), information
513-
about a container's volumes is returned with the key `"Mounts"`, not `"Volumes"`.
512+
Be aware that, starting with API version 1.20 (docker version 1.8.x), information
513+
about a container's volumes is returned with the key `"Mounts"`, not `"Volumes"`.
514514
As such, the `ContainerInfo.volumes()` method is deprecated. Instead, use
515515
`ContainerInfo.mounts()`.
516516

src/main/java/com/spotify/docker/client/messages/HostConfig.java

+43-9
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@
1717

1818
package com.spotify.docker.client.messages;
1919

20+
import com.fasterxml.jackson.annotation.JsonAutoDetect;
21+
import com.fasterxml.jackson.annotation.JsonProperty;
2022
import com.google.common.base.MoreObjects;
2123
import com.google.common.collect.ImmutableList;
2224
import com.google.common.collect.Lists;
2325
import com.google.common.collect.Maps;
2426

25-
import com.fasterxml.jackson.annotation.JsonAutoDetect;
26-
import com.fasterxml.jackson.annotation.JsonProperty;
27-
27+
import java.util.ArrayList;
2828
import java.util.Collections;
2929
import java.util.List;
3030
import java.util.Map;
@@ -152,7 +152,7 @@ public String networkMode() {
152152
public List<String> securityOpt() {
153153
return securityOpt;
154154
}
155-
155+
156156
public List<Device> devices() {
157157
return devices;
158158
}
@@ -524,17 +524,22 @@ private Builder(final HostConfig hostConfig) {
524524
this.ipcMode = hostConfig.ipcMode;
525525
}
526526

527+
/**
528+
* Set the list of binds to the parameter, replacing any existing value.
529+
* <p>To append to the list instead, use one of the appendBinds() methods.</p>
530+
*/
527531
public Builder binds(final List<String> binds) {
528532
if (binds != null && !binds.isEmpty()) {
529-
if (this.binds != null) {
530-
binds.addAll(0, this.binds);
531-
}
532533
this.binds = ImmutableList.copyOf(binds);
533534
}
534535

535536
return this;
536537
}
537538

539+
/**
540+
* Set the list of binds to the parameter, replacing any existing value.
541+
* <p>To append to the list instead, use one of the appendBinds() methods.</p>
542+
*/
538543
public Builder binds(final String... binds) {
539544
if (binds != null && binds.length > 0) {
540545
return binds(Lists.newArrayList(binds));
@@ -543,16 +548,45 @@ public Builder binds(final String... binds) {
543548
return this;
544549
}
545550

551+
/**
552+
* Set the list of binds to the parameter, replacing any existing value.
553+
* <p>To append to the list instead, use one of the appendBinds() methods.</p>
554+
*/
546555
public Builder binds(final Bind... binds) {
547556
if (binds == null || binds.length == 0) {
548557
return this;
549558
}
550559

560+
return binds(toStringList(binds));
561+
}
562+
563+
private static List<String> toStringList(final Bind[] binds) {
551564
final List<String> bindStrings = Lists.newArrayList();
552565
for (final Bind bind : binds) {
553566
bindStrings.add(bind.toString());
554567
}
555-
return binds(bindStrings);
568+
return bindStrings;
569+
}
570+
571+
/** Append binds to the existing list in this builder. */
572+
public Builder appendBinds(final Iterable<String> newBinds) {
573+
final List<String> list = new ArrayList<>(this.binds);
574+
list.addAll(Lists.newArrayList(newBinds));
575+
this.binds = ImmutableList.copyOf(list);
576+
577+
return this;
578+
}
579+
580+
/** Append binds to the existing list in this builder. */
581+
public Builder appendBinds(final Bind... binds) {
582+
appendBinds(toStringList(binds));
583+
return this;
584+
}
585+
586+
/** Append binds to the existing list in this builder. */
587+
public Builder appendBinds(final String... binds) {
588+
appendBinds(Lists.newArrayList(binds));
589+
return this;
556590
}
557591

558592
public List<String> binds() {
@@ -803,7 +837,7 @@ public Builder devices(final Device... devices) {
803837
public List<Device> devices() {
804838
return devices;
805839
}
806-
840+
807841
public Builder memory(final Long memory) {
808842
this.memory = memory;
809843
return this;

src/test/java/com/spotify/docker/client/DefaultDockerClientTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -1760,8 +1760,8 @@ public void testContainerVolumes() throws Exception {
17601760
.readOnly(true)
17611761
.build();
17621762
final HostConfig hostConfig = HostConfig.builder()
1763-
.binds("/local/path:/remote/path")
1764-
.binds(bind)
1763+
.appendBinds("/local/path:/remote/path")
1764+
.appendBinds(bind)
17651765
.build();
17661766
final ContainerConfig volumeConfig = ContainerConfig.builder()
17671767
.image(BUSYBOX_LATEST)

src/test/java/com/spotify/docker/client/messages/HostConfigTest.java

+35-3
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,18 @@
1717

1818
package com.spotify.docker.client.messages;
1919

20-
import com.fasterxml.jackson.databind.ObjectMapper;
20+
import com.spotify.docker.client.ObjectMapperProvider;
2121

22+
import com.fasterxml.jackson.databind.ObjectMapper;
2223
import com.google.common.base.Charsets;
24+
import com.google.common.collect.ImmutableList;
2325
import com.google.common.io.Resources;
2426

25-
import com.spotify.docker.client.ObjectMapperProvider;
26-
2727
import org.junit.Before;
2828
import org.junit.Test;
2929

3030
import java.io.IOException;
31+
import java.util.List;
3132

3233
import static org.hamcrest.CoreMatchers.is;
3334
import static org.junit.Assert.assertThat;
@@ -68,4 +69,35 @@ public void testJsonOnFailure() throws Exception {
6869
private static String fixture(String filename) throws IOException {
6970
return Resources.toString(Resources.getResource(filename), Charsets.UTF_8).trim();
7071
}
72+
73+
@Test
74+
public void testReplaceBinds() {
75+
final List<String> initialBinds = ImmutableList.of("/one:/one", "/two:/two");
76+
final HostConfig hostConfig = HostConfig.builder()
77+
.binds(initialBinds)
78+
.binds(initialBinds)
79+
.build();
80+
81+
assertThat("Calling .binds() multiple times should replace the list each time",
82+
hostConfig.binds(), is(initialBinds));
83+
}
84+
85+
@Test
86+
public void testAppendBinds() {
87+
final List<String> initialBinds = ImmutableList.of("/one:/one", "/two:/two");
88+
final HostConfig hostConfig = HostConfig.builder()
89+
.binds(initialBinds)
90+
.appendBinds("/three:/three")
91+
.appendBinds("/four:/four")
92+
.build();
93+
94+
final List<String> expected = ImmutableList.<String>builder()
95+
.addAll(initialBinds)
96+
.add("/three:/three")
97+
.add("/four:/four")
98+
.build();
99+
100+
assertThat("Calling .appendBinds should append to the list, not replace",
101+
hostConfig.binds(), is(expected));
102+
}
71103
}

0 commit comments

Comments
 (0)