Skip to content

Commit 5aa67c2

Browse files
UkloskrohanKanojia
authored andcommitted
Allow saving multiple images in docker:save using new parameters list saveNames and saveAliases.
1 parent 19f2ac6 commit 5aa67c2

6 files changed

Lines changed: 261 additions & 43 deletions

File tree

src/main/asciidoc/inc/_docker-save.adoc

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,19 @@ Note that using overriding the default to use `docker` or `docker-%a` may lead t
4141
| Element | Description | Property
4242

4343
| *saveName*
44-
| The name of the image configuration to save. Must not be used together with `alias`.
44+
| The name of the image configuration to save. Must not be used together with `alias`, `aliases` or `names`.
4545
| `docker.save.name`
4646

47+
| *saveNames*
48+
| The name list of the image configurations to save. Must not be used together with `alias`, `aliases` or `name`.
49+
| `docker.save.names`
50+
4751
| *saveAlias*
48-
| The alias of the image configuration to save. Must not be used together with `name`.
52+
| The alias of the image configuration to save. Must not be used together with `name`, `names` or `aliases`.
53+
| `docker.save.alias`
54+
55+
| *saveAliases*
56+
| The alias list of the image configurations to save. Must not be used together with `name`, `names` or `alias`.
4957
| `docker.save.alias`
5058

5159
| *saveFile*

src/main/java/io/fabric8/maven/docker/SaveMojo.java

Lines changed: 115 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,23 @@
22

33
import java.io.File;
44
import java.util.ArrayList;
5+
import java.util.Arrays;
56
import java.util.List;
67
import java.util.Properties;
8+
import java.util.stream.Collectors;
79

8-
import io.fabric8.maven.docker.config.ArchiveCompression;
9-
import io.fabric8.maven.docker.util.EnvUtil;
10-
import io.fabric8.maven.docker.util.ImageName;
1110
import org.apache.maven.plugin.MojoExecutionException;
1211
import org.apache.maven.plugins.annotations.Component;
1312
import org.apache.maven.plugins.annotations.Mojo;
1413
import org.apache.maven.plugins.annotations.Parameter;
1514
import org.apache.maven.project.MavenProjectHelper;
1615

1716
import io.fabric8.maven.docker.access.DockerAccessException;
17+
import io.fabric8.maven.docker.config.ArchiveCompression;
1818
import io.fabric8.maven.docker.config.ImageConfiguration;
1919
import io.fabric8.maven.docker.service.ServiceHub;
20+
import io.fabric8.maven.docker.util.EnvUtil;
21+
import io.fabric8.maven.docker.util.ImageName;
2022

2123
@Mojo(name = "save")
2224
public class SaveMojo extends AbstractDockerMojo {
@@ -30,9 +32,15 @@ public class SaveMojo extends AbstractDockerMojo {
3032
@Parameter(property = "docker.save.name")
3133
String saveName;
3234

35+
@Parameter(property = "docker.save.names")
36+
List<String> saveNames;
37+
3338
@Parameter(property = "docker.save.alias")
3439
String saveAlias;
3540

41+
@Parameter(property = "docker.save.aliases")
42+
List<String> saveAliases;
43+
3644
@Parameter
3745
String saveFile;
3846

@@ -50,21 +58,30 @@ protected void executeInternal(ServiceHub serviceHub) throws DockerAccessExcepti
5058
return;
5159
}
5260

53-
ImageConfiguration image = getImageToSave(images);
54-
String imageName = image.getName();
55-
String fileName = getFileName(imageName);
61+
List<ImageConfiguration> imagesToSave = getImagesToSave(images);
62+
63+
List<String> imageNames = imagesToSave.stream().map(ic -> ic.getName()).collect(Collectors.toList());
64+
String fileName = getFileName(imageNames);
5665
ensureSaveDir(fileName);
57-
log.info("Saving image %s to %s", imageName, fileName);
58-
if (!serviceHub.getQueryService().hasImage(imageName)) {
59-
throw new MojoExecutionException("No image " + imageName + " exists");
66+
for (String imageName : imageNames) {
67+
log.info("Saving image %s to %s", imageName, fileName);
68+
if (!serviceHub.getQueryService().hasImage(imageName)) {
69+
throw new MojoExecutionException("No image " + imageName + " exists");
70+
}
6071
}
6172

6273
long time = System.currentTimeMillis();
6374
ArchiveCompression compression = ArchiveCompression.fromFileName(fileName);
64-
serviceHub.getDockerAccess().saveImage(imageName, fileName, compression);
65-
log.info("%s: Saved image to %s in %s", imageName, fileName, EnvUtil.formatDurationTill(time));
75+
if(imageNames.size() == 1) {
76+
String imageName = imageNames.get(0);
77+
serviceHub.getDockerAccess().saveImage(imageName, fileName, compression);
78+
log.info("%s: Saved image to %s in %s", imageName, fileName, EnvUtil.formatDurationTill(time));
79+
} else {
80+
serviceHub.getDockerAccess().saveImages(imageNames, fileName, compression);
81+
log.info("%s: Saved image to %s in %s", imageNames, fileName, EnvUtil.formatDurationTill(time));
82+
}
6683

67-
String classifier = getClassifier(image);
84+
String classifier = getClassifier(imagesToSave.get(0));
6885
if(classifier != null) {
6986
projectHelper.attachArtifact(project, compression.getFileSuffix(), classifier, new File(fileName));
7087
}
@@ -86,7 +103,7 @@ private boolean skipSaveFor(List<ImageConfiguration> images) {
86103
return false;
87104
}
88105

89-
private String getFileName(String iName) {
106+
private String getFileName(List<String> iNames) throws MojoExecutionException {
90107
String configuredFileName = getConfiguredFileName();
91108
if (configuredFileName != null) {
92109
if (new File(configuredFileName).isAbsolute()) {
@@ -99,10 +116,13 @@ private String getFileName(String iName) {
99116
"-" + project.getVersion() +
100117
"." + STANDARD_ARCHIVE_COMPRESSION.getFileSuffix());
101118
}
102-
ImageName imageName = new ImageName(iName);
103-
return completeCalculatedFileName(imageName.getSimpleName() +
104-
"-" + imageName.getTag()) +
105-
"." + STANDARD_ARCHIVE_COMPRESSION.getFileSuffix();
119+
if (iNames.size() == 1){
120+
ImageName imageName = new ImageName(iNames.get(0));
121+
return completeCalculatedFileName(imageName.getSimpleName() +
122+
"-" + imageName.getTag()) +
123+
"." + STANDARD_ARCHIVE_COMPRESSION.getFileSuffix();
124+
}
125+
throw new MojoExecutionException("More than one image to save. Please configure a fileName.");
106126
}
107127

108128
private String getConfiguredFileName() {
@@ -130,26 +150,84 @@ private void ensureSaveDir(String fileName) throws MojoExecutionException {
130150
}
131151
}
132152

133-
private ImageConfiguration getImageToSave(List<ImageConfiguration> images) throws MojoExecutionException {
134-
// specify image by name or alias
135-
if (saveName == null && saveAlias == null) {
153+
private List<ImageConfiguration> getImagesToSave(List<ImageConfiguration> images) throws MojoExecutionException {
154+
// specify images by name or alias
155+
if (saveName == null && saveAlias == null && (saveNames == null || (saveNames != null && saveNames.isEmpty())) && (saveAliases == null || (saveAliases != null && saveAliases.isEmpty()))) {
136156
List<ImageConfiguration> buildImages = getImagesWithBuildConfig(images);
137157
if (buildImages.size() == 1) {
138-
return buildImages.get(0);
158+
return Arrays.asList(buildImages.get(0));
159+
}
160+
throw new MojoExecutionException("More than one image with build configuration is defined. Please specify the image with 'docker.save.name', 'docker.save.alias', 'docker.save.names' or 'docker.save.aliases'.");
161+
}
162+
163+
checkValidImageInputsOrThrow();
164+
List<String> saveNamesPendingToSave = getSaveNamesPendingToSave();
165+
List<String> saveAliasesPendingToSave = getSaveAliasesPendingToSave();
166+
List<ImageConfiguration> imagesToSave = new ArrayList<>();
167+
for (ImageConfiguration ic : images) {
168+
if (equalName(ic) || containsName(ic)) {
169+
imagesToSave.add(ic);
170+
saveNamesPendingToSave.remove(ic.getName());
171+
} else if (equalAlias(ic) || containsAlias(ic)) {
172+
imagesToSave.add(ic);
173+
saveAliasesPendingToSave.remove(ic.getAlias());
139174
}
140-
throw new MojoExecutionException("More than one image with build configuration is defined. Please specify the image with 'docker.name' or 'docker.alias'.");
141175
}
176+
if (!saveNamesPendingToSave.isEmpty()) {
177+
throw new MojoExecutionException(saveNamesPendingToSave.size() > 1
178+
? "Can not find images with name: " + saveNamesPendingToSave
179+
: "Can not find image with name: " + saveNamesPendingToSave.get(0));
180+
}
181+
if (!saveAliasesPendingToSave.isEmpty()) {
182+
throw new MojoExecutionException(saveAliasesPendingToSave.size() > 1
183+
? "Can not find images with alias: " + saveAliasesPendingToSave
184+
: "Can not find image with alias: " + saveAliasesPendingToSave.get(0));
185+
}
186+
187+
return imagesToSave;
188+
}
189+
190+
private void checkValidImageInputsOrThrow() throws MojoExecutionException {
142191
if (saveName != null && saveAlias != null) {
143192
throw new MojoExecutionException("Cannot specify both name and alias.");
144193
}
145-
for (ImageConfiguration ic : images) {
146-
if (equalName(ic) || equalAlias(ic)) {
147-
return ic;
148-
}
194+
if (saveName != null && saveNames != null && !saveNames.isEmpty()) {
195+
throw new MojoExecutionException("Cannot specify both name and name list.");
196+
}
197+
if (saveName != null && saveAliases != null && !saveAliases.isEmpty()) {
198+
throw new MojoExecutionException("Cannot specify both name and alias list.");
199+
}
200+
if (saveAlias != null && saveNames != null && !saveNames.isEmpty()) {
201+
throw new MojoExecutionException("Cannot specify both alias and name list.");
202+
}
203+
if (saveAlias != null && saveAliases != null && !saveAliases.isEmpty()) {
204+
throw new MojoExecutionException("Cannot specify both alias and alias list.");
205+
}
206+
if (saveNames != null && !saveNames.isEmpty() && saveAliases != null && !saveAliases.isEmpty()) {
207+
throw new MojoExecutionException("Cannot specify both name list and alias list.");
208+
}
209+
}
210+
211+
private List<String> getSaveNamesPendingToSave() {
212+
List<String> exit = new ArrayList<>();
213+
if (saveName != null) {
214+
exit.add(saveName);
149215
}
150-
throw new MojoExecutionException(saveName != null ?
151-
"Can not find image with name '" + saveName + "'" :
152-
"Can not find image with alias '"+ saveAlias + "'");
216+
if (saveNames != null && !saveNames.isEmpty()) {
217+
exit.addAll(saveNames);
218+
}
219+
return exit;
220+
}
221+
222+
private List<String> getSaveAliasesPendingToSave() {
223+
List<String> exit = new ArrayList<>();
224+
if (saveAlias != null) {
225+
exit.add(saveAlias);
226+
}
227+
if (saveAliases != null && !saveAliases.isEmpty()) {
228+
return exit;
229+
}
230+
return exit;
153231
}
154232

155233
private List<ImageConfiguration> getImagesWithBuildConfig(List<ImageConfiguration> images) {
@@ -178,4 +256,12 @@ private boolean equalAlias(ImageConfiguration ic) {
178256
private boolean equalName(ImageConfiguration ic) {
179257
return saveName != null && saveName.equals(ic.getName());
180258
}
259+
260+
private boolean containsAlias(ImageConfiguration ic) {
261+
return saveAliases != null && !saveAliases.isEmpty() && saveAliases.contains(ic.getAlias());
262+
}
263+
264+
private boolean containsName(ImageConfiguration ic) {
265+
return saveNames != null && !saveNames.isEmpty() && saveNames.contains(ic.getName());
266+
}
181267
}

src/main/java/io/fabric8/maven/docker/access/DockerAccess.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,16 @@ void copyArchiveFromContainer(String containerId, String containerPath, File arc
299299
*/
300300
void saveImage(String image, String filename, ArchiveCompression compression) throws DockerAccessException;
301301

302+
/**
303+
* Save several images to a tar file
304+
*
305+
* @param images image to save
306+
* @param filename target filename
307+
* @param compression compression to use for the archive
308+
* @throws DockerAccessException if an image cannot be removed
309+
*/
310+
void saveImages(List<String> images, String filename, ArchiveCompression compression) throws DockerAccessException;
311+
302312
/**
303313
* List all networks
304314
*

src/main/java/io/fabric8/maven/docker/access/UrlBuilder.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77
import java.net.URLEncoder;
88
import java.util.Arrays;
99
import java.util.HashMap;
10+
import java.util.List;
1011
import java.util.Map;
1112
import java.util.TreeSet;
13+
import java.util.stream.Collectors;
1214

1315
import io.fabric8.maven.docker.util.ImageName;
1416

@@ -81,6 +83,12 @@ public String getImage(ImageName name) {
8183
.build();
8284
}
8385

86+
public String getImages(List<ImageName> names) {
87+
return u("images/get").p("names", names.stream().map(n -> n.getFullName()).collect(Collectors.toList()))
88+
.build();
89+
}
90+
91+
8492
public String inspectContainer(String containerId) {
8593
return u("containers/%s/json", containerId)
8694
.build();
@@ -244,6 +252,7 @@ private void addFilters(Builder builder, String... filter) {
244252
private static class Builder {
245253

246254
private Map<String,String> queryParams = new HashMap<>();
255+
private Map<String,List<String>> queryArrayParams = new HashMap<>();
247256
private String url;
248257

249258
public Builder(String url) {
@@ -262,6 +271,13 @@ private Builder p(String key, String value) {
262271
return this;
263272
}
264273

274+
private Builder p(String key, List<String> values) {
275+
if (values!=null && !values.isEmpty()) {
276+
queryArrayParams.put(key, values);
277+
}
278+
return this;
279+
}
280+
265281
private Builder p(String key, boolean value) {
266282
return p(key,value ? "1" : "0");
267283
}
@@ -271,7 +287,7 @@ private Builder p(String key, int value) {
271287
}
272288

273289
public String build() {
274-
if (queryParams.size() > 0) {
290+
if (queryParams.size() > 0 || queryArrayParams.size() > 0) {
275291
StringBuilder ret = new StringBuilder(url);
276292
ret.append("?");
277293
// Sort to make order predictable e.g. for unit testing
@@ -281,6 +297,14 @@ public String build() {
281297
.append(encode(queryParams.get(key)))
282298
.append("&");
283299
}
300+
for (String key : new TreeSet<>(queryArrayParams.keySet())) {
301+
for(String value : queryArrayParams.get(key)){
302+
ret.append(key)
303+
.append("=")
304+
.append(encode(value))
305+
.append("&");
306+
}
307+
}
284308
return ret.substring(0,ret.length() - 1);
285309
} else {
286310
return url;

src/main/java/io/fabric8/maven/docker/access/hc/DockerAccessWithHcClient.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,21 @@ public void saveImage(String image, String filename, ArchiveCompression compress
577577
}
578578
}
579579

580+
@Override
581+
public void saveImages(List<String> images, String filename, ArchiveCompression compression) throws DockerAccessException {
582+
List<ImageName> names = new ArrayList<>();
583+
for(String image : images){
584+
names.add(new ImageName(image));
585+
}
586+
String url = urlBuilder.getImages(names);
587+
log.verbose(Logger.LogVerboseCategory.API, API_LOG_FORMAT_GET, url);
588+
try {
589+
delegate.get(url, getImageResponseHandler(filename, compression), HTTP_OK);
590+
} catch (IOException e) {
591+
throw new DockerAccessException(e, "Unable to save '%s' to '%s'", images.toArray(), filename);
592+
}
593+
}
594+
580595
private ResponseHandler<Object> getImageResponseHandler(final String filename, final ArchiveCompression compression) throws FileNotFoundException {
581596
return new ResponseHandler<Object>() {
582597
@Override

0 commit comments

Comments
 (0)