##// END OF EJS Templates
WIP docker compose support
cin -
r11:cf3a5b9d59a9 default
parent child
Show More
@@ -1,57 +1,65
1 1 plugins {
2 2 id "java-gradle-plugin"
3 3 id "com.gradle.plugin-publish" version "1.2.1"
4 4 // Maven Publish Plugin applied by com.gradle.plugin-publish > 1.0
5 5 id "ivy-publish"
6 6 }
7 7
8 8 dependencies {
9 9 implementation "com.fasterxml.jackson.core:jackson-core:2.13.5",
10 10 "com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.13.5"
11 11 }
12 12
13 13 java {
14 14 targetCompatibility = 11
15 15 sourceCompatibility = 11
16 16 }
17 17
18 18
19 19 repositories {
20 20 mavenCentral()
21 21 }
22 22
23 23 gradlePlugin {
24 24 website = 'https://code.implab.org/implab/gradle-container-plugin'
25 25 vcsUrl = 'https://code.implab.org/implab/gradle-container-plugin'
26 26 plugins {
27 27 containerPlugin {
28 28 id = 'org.implab.gradle-container'
29 29 displayName = "Provdes convetional configuration to build a container image"
30 30 description = 'Build and publish container images with docker or podman. Simple wrapper around cli.'
31 31 implementationClass = 'org.implab.gradle.containers.ContainerPlugin'
32 32 tags.set(['containers', 'image', 'docker', 'podman'])
33 33 }
34 34 containerBasePlugin {
35 35 id = 'org.implab.gradle-container-base'
36 36 displayName = "Provides tasks to build manipulate container images"
37 37 description = 'Build and publish container images with docker or podman. Simple wrapper around cli.'
38 38 implementationClass = 'org.implab.gradle.containers.ContainerBasePlugin'
39 39 tags.set(['containers', 'image', 'docker', 'podman'])
40 40 }
41
42 conmposePlugin {
43 id = 'org.implab.gradle-container-compose'
44 displayName = "Provdes tasks to start and stop compose"
45 description = 'Build and publish container images with docker or podman. Simple wrapper around cli.'
46 implementationClass = 'org.implab.gradle.containers.ComposePlugin'
47 tags.set(['containers', 'image', 'docker', 'podman'])
48 }
41 49 }
42 50 }
43 51
44 52
45 53 task printVersion {
46 54 doLast {
47 55 println "${->jar.archiveFileName.get()}"
48 56 }
49 57 }
50 58
51 59 publishing {
52 60 repositories {
53 61 ivy {
54 62 url "${System.properties["user.home"]}/ivy-repo"
55 63 }
56 64 }
57 65 }
@@ -1,49 +1,53
1 1 package org.implab.gradle.containers;
2 2
3 3 import org.gradle.api.Plugin;
4 4 import org.gradle.api.Project;
5 5 import org.gradle.api.plugins.ExtraPropertiesExtension;
6 6 import org.implab.gradle.containers.tasks.BuildImage;
7 7 import org.implab.gradle.containers.tasks.PushImage;
8 8 import org.implab.gradle.containers.tasks.RunImage;
9 9 import org.implab.gradle.containers.tasks.SaveImage;
10 10 import org.implab.gradle.containers.tasks.TagImage;
11 11
12 public class ContainerBasePlugin implements Plugin<Project> {
12 public class ContainerBasePlugin implements Plugin<Project> {
13 13 public static final String CONTAINER_EXTENSION_NAME = "container";
14 14
15 ContainerExtension containerExtension;
15 private ContainerExtension containerExtension;
16 16
17 17 ContainerExtension getContainerExtension() {
18 18 if (containerExtension == null)
19 19 throw new IllegalStateException();
20 20 return containerExtension;
21 21 }
22 22
23 23 void exportClasses(Project project, Class<?>... classes) {
24 24 ExtraPropertiesExtension extras = project.getExtensions().getExtraProperties();
25 25 for (var clazz : classes)
26 26 extras.set(clazz.getSimpleName(), clazz);
27 27 }
28 28
29 29 @Override
30 30 public void apply(Project project) {
31 31
32 32 containerExtension = project.getObjects().newInstance(ContainerExtension.class);
33 33
34 34 containerExtension.getImageAuthority()
35 35 .convention(project.provider(() -> (String) project.getProperties().get("imagesAuthority")));
36 36
37 37 containerExtension.getImageGroup()
38 38 .convention(project.provider(() -> (String) project.getProperties().get("imagesGroup")));
39 39
40 containerExtension.getCliCmd()
41 .convention(project
42 .provider(() -> (String) project.getProperties().get("containerCli"))
43 .orElse("docker"));
44
40 45 project.getExtensions().add(CONTAINER_EXTENSION_NAME, containerExtension);
41 46
42 47 exportClasses(
43 48 project,
44 49 BuildImage.class, PushImage.class, SaveImage.class, TagImage.class, RunImage.class);
45 50
51 }
46 52
47 }
48
49 53 }
@@ -1,85 +1,78
1 1 package org.implab.gradle.containers;
2 2
3 3 import java.io.File;
4 4 import java.io.FileNotFoundException;
5 5 import java.io.IOException;
6 6 import java.util.Optional;
7 7
8 8 import javax.inject.Inject;
9 9
10 10 import org.gradle.api.Project;
11 11 import org.gradle.api.file.DirectoryProperty;
12 12 import org.gradle.api.file.ProjectLayout;
13 import org.gradle.api.file.RegularFileProperty;
14 13 import org.gradle.api.provider.Property;
15 14 import org.gradle.api.provider.Provider;
16 15 import org.implab.gradle.containers.cli.ImageName;
17 16 import org.implab.gradle.containers.cli.ImageRef;
18 17 import org.implab.gradle.containers.cli.Utils;
19 18
20 public abstract class ContainerExtension {
19 public abstract class ContainerExtension implements PropertiesMixin {
21 20
22 21 public abstract Property<String> getCliCmd();
23 22
24 23 public abstract DirectoryProperty getContextDirectory();
25 24
26 public abstract RegularFileProperty getImageIdFile();
27
28 25 /**
29 26 * Specifies the name of the registry where the image is located
30 27 * {@code registry.my-company.org}
31 28 */
32 29 public abstract Property<String> getImageAuthority();
33 30
34 31 /**
35 32 * Specified the path of the image like {@code my-company}
36 33 */
37 34 public abstract Property<String> getImageGroup();
38 35
39 public abstract Property<ImageName> getImageName();
36 public Provider<ImageName> getImageName() {
37 return provider(this::createImageName);
38 }
40 39
41 40 /**
42 41 * Specifies local image part like {@code httpd}
43 42 */
44 43 public abstract Property<String> getImageLocalName();
45 44
46 45 /**
47 46 * This property is deprecated use imageLocalName
48 47 */
49 48 @Deprecated
50 49 public Property<String> getImageShortName() {
51 50 return getImageLocalName();
52 51 }
53 52
54 53 public abstract Property<String> getImageTag();
55 54
56 55 @Inject
57 56 public ContainerExtension(ProjectLayout layout, Project project) {
58 57 getContextDirectory().convention(layout.getBuildDirectory().dir("context"));
59 58
60 getImageIdFile().convention(layout.getBuildDirectory().file("iid.json"));
61
62 getCliCmd().set("docker");
63
64 59 getImageLocalName().convention(project.getName());
65 60
66 getImageTag().set(project
67 .provider(() -> Optional.ofNullable(project.getVersion()).map(v -> v.toString()).orElse("latest")));
68
69 Provider<String> imageRepository = getImageGroup().map(g -> g + "/" + getImageLocalName().get())
70 .orElse(getImageLocalName());
71
72 getImageName().convention(project.provider(
73 () -> new ImageName().authority(getImageAuthority().get()).name(imageRepository.get())
74 .tag(getImageTag().get())));
61 getImageTag().set(provider(() -> Optional.ofNullable(project.getVersion())
62 .map(Object::toString)
63 .orElse("latest")));
75 64 }
76 65
77 public ImageName createImageName() {
78 return new ImageName();
66 ImageName createImageName() {
67 return new ImageName(
68 getImageAuthority().getOrNull(),
69 getImageGroup().getOrNull(),
70 getImageLocalName().get(),
71 getImageTag().getOrNull());
79 72 }
80 73
81 74 public ImageRef readImageRef(File file) throws FileNotFoundException, IOException {
82 75 return Utils.readImageRef(file);
83 76 }
84 77
85 78 } No newline at end of file
@@ -1,82 +1,80
1 1 package org.implab.gradle.containers;
2 2
3 3 import org.gradle.api.GradleException;
4 4 import org.gradle.api.Plugin;
5 5 import org.gradle.api.Project;
6 6 import org.gradle.api.artifacts.Dependency;
7 7 import org.gradle.api.file.ProjectLayout;
8 8 import org.gradle.api.tasks.Copy;
9 9 import org.gradle.api.tasks.Delete;
10 10 import org.gradle.api.tasks.TaskProvider;
11 11 import org.implab.gradle.containers.cli.ImageName;
12 12 import org.implab.gradle.containers.tasks.BuildImage;
13 13 import org.implab.gradle.containers.tasks.PushImage;
14 14 import org.implab.gradle.containers.tasks.SaveImage;
15 15
16 16 public class ContainerPlugin implements Plugin<Project> {
17 17
18 18 public static final String BUILD_GROUP = "build";
19 19
20 20 public static final String ARCHIVE_CONFIGURATION = "archive";
21 21
22 ContainerExtension containerExtension;
23
24 22 public void apply(Project project) {
25 23 ProjectLayout layout = project.getLayout();
26 24
27 25 project.getPluginManager().apply(ContainerBasePlugin.class);
28 26
29 27 var basePlugin = project.getPlugins().findPlugin(ContainerBasePlugin.class);
30 28 if (basePlugin == null)
31 29 throw new GradleException("The container-base plugin fails to be applied");
32 30
33 31 var containerExtension = basePlugin.getContainerExtension();
34 32
35 33 project.getConfigurations().create(Dependency.DEFAULT_CONFIGURATION, c -> {
36 34 c.setCanBeConsumed(true);
37 35 c.setCanBeResolved(false);
38 36 });
39 37
40 38 project.getConfigurations().create(ARCHIVE_CONFIGURATION, c -> {
41 39 c.setCanBeConsumed(true);
42 40 c.setCanBeResolved(false);
43 41 });
44 42
45 43 TaskProvider<Copy> processResourcesTask = project.getTasks().register("processResources", Copy.class, t -> {
46 44 t.setGroup(BUILD_GROUP);
47 45 t.from(layout.getProjectDirectory().dir("src/main"));
48 46 t.into(containerExtension.getContextDirectory());
49 47 });
50 48
51 49 TaskProvider<BuildImage> buildImageTask = project.getTasks().register("buildImage", BuildImage.class, t -> {
52 50 t.setGroup(BUILD_GROUP);
53 51 t.dependsOn(processResourcesTask);
54 52
55 53 t.getContextDirectory().set(containerExtension.getContextDirectory());
56 t.getImageIdFile().set(containerExtension.getImageIdFile());
54 t.getImageIdFile().set(project.getLayout().getBuildDirectory().file("iid.json"));
57 55
58 t.getImageName().set(containerExtension.getImageName());
56 t.getImageName().set(containerExtension.getImageName().map(ImageName::toString));
59 57 });
60 58
61 59 project.getTasks().register("clean", Delete.class, t -> {
62 60 t.delete(layout.getBuildDirectory());
63 61 });
64 62
65 63 project.getTasks().register("build", t -> {
66 64 t.setGroup(BUILD_GROUP);
67 65 t.dependsOn(buildImageTask);
68 66 });
69 67
70 68 project.getTasks().register("pushImage", PushImage.class, t -> {
71 69 t.dependsOn(buildImageTask);
72 70 t.getImageName().set(buildImageTask.flatMap(BuildImage::getImageName));
73 71 });
74 72
75 73 project.getTasks().register("saveImage", SaveImage.class, t -> {
76 74 t.dependsOn(buildImageTask);
77 t.getExportImages().add(buildImageTask.flatMap(BuildImage::getImageName).map(ImageName::toString));
75 t.getExportImages().add(buildImageTask.flatMap(BuildImage::getImageName));
78 76 });
79 77
80 78 project.getArtifacts().add(Dependency.DEFAULT_CONFIGURATION, buildImageTask);
81 79 }
82 80 }
@@ -1,142 +1,141
1 1 package org.implab.gradle.containers.cli;
2 2
3 3 import java.io.File;
4 4 import java.io.IOException;
5 import java.nio.file.Files;
6 5 import java.util.ArrayList;
7 6 import java.util.Arrays;
8 7 import java.util.List;
9 8 import java.util.Optional;
10 9
11 10 import org.gradle.api.logging.Logger;
12 11
13 12 public abstract class DockerTraits {
14 13
15 14 public final String BUILD_COMMAND = "build";
16 15 public final String PUSH_COMMAND = "push";
17 16 public final String RUN_COMMAND = "run";
18 17 public final String SAVE_COMMAND = "save";
19 18 public final String INSPECT_COMMAND = "inspect";
20 19 public final String IMAGE_COMMAND = "image";
21 20 public final String TAG_COMMAND = "tag";
22 21
23 22 public abstract Logger getLogger();
24 23
25 24 public abstract Optional<File> getWorkingDir();
26 25
27 26 public abstract String getCliCmd();
28 27
29 28 Process startProcess(ProcessBuilder builder) throws IOException {
30 29 getLogger().info("Starting: {}", builder.command());
31 30 return builder.start();
32 31 }
33 32
34 33 protected boolean checkRetCode(Process proc, int code) throws InterruptedException {
35 34 if (getLogger().isInfoEnabled()) {
36 35 Utils.redirectIO(proc.getInputStream(), getLogger()::info);
37 36 Utils.redirectIO(proc.getErrorStream(), getLogger()::info);
38 37 }
39 38
40 39 return proc.waitFor() == code;
41 40 }
42 41
43 42 protected void complete(Process proc) throws InterruptedException, IOException {
44 43 if (getLogger().isInfoEnabled())
45 44 Utils.redirectIO(proc.getInputStream(), getLogger()::info);
46 45
47 46 if (getLogger().isErrorEnabled())
48 47 Utils.redirectIO(proc.getErrorStream(), getLogger()::error);
49 48
50 49 var code = proc.waitFor();
51 50 if (code != 0) {
52 51 getLogger().error("The process exited with code {}", code);
53 52 throw new IOException("The process exited with error code " + code);
54 53 }
55 54 }
56 55
57 56 protected ProcessBuilder builder(String... args) {
58 57 var argsList = new ArrayList<String>(args.length + 1);
59 58 Arrays.stream(args).forEach(argsList::add);
60 59
61 60 return builder(argsList);
62 61 }
63 62
64 63 protected ProcessBuilder builder(List<String> args) {
65 64 var command = new ArrayList<String>(args.size() + 1);
66 65
67 66 command.add(getCliCmd());
68 67 args.forEach(command::add);
69 68
70 69 var builder = new ProcessBuilder(command);
71 70
72 71 getWorkingDir().ifPresent(builder::directory);
73 72 return builder;
74 73 }
75 74
76 75 public void buildImage(String imageName, File contextDirectory, List<String> options)
77 76 throws IOException, InterruptedException {
78 77 var args = new ArrayList<String>();
79 78 args.add(BUILD_COMMAND);
80 79 args.addAll(options);
81 80 args.add("-t");
82 81 args.add(imageName);
83 82 args.add(contextDirectory.getAbsolutePath());
84 83 complete(startProcess(builder(args)));
85 84 }
86 85
87 86 public void pushImage(String image, List<String> options) throws InterruptedException, IOException {
88 87 var args = new ArrayList<String>();
89 88 args.add(PUSH_COMMAND);
90 89 args.addAll(options);
91 90 args.add(image);
92 91 complete(startProcess(builder(args)));
93 92 }
94 93
95 94 public void runImage(String image, List<String> options, List<String> command)
96 95 throws InterruptedException, IOException {
97 96 var args = new ArrayList<String>();
98 97 args.add(RUN_COMMAND);
99 98 args.addAll(options);
100 99 args.add(image);
101 100 args.addAll(command);
102 101 complete(startProcess(builder(args)));
103 102 }
104 103
105 104 public void saveImage(List<String> images, File output) throws InterruptedException, IOException {
106 105 if (output.exists())
107 106 output.delete();
108 107
109 108 var args = new ArrayList<String>();
110 109 args.add(SAVE_COMMAND);
111 110 args.add("-o");
112 111 args.add(output.getAbsolutePath());
113 112 images.forEach(args::add);
114 113
115 114 complete(startProcess(builder(args)));
116 115 }
117 116
118 117 public void tagImage(String source, String target) throws InterruptedException, IOException {
119 118 complete(startProcess(builder(TAG_COMMAND, source, target)));
120 119 }
121 120
122 121 public boolean imageExists(String imageId) throws InterruptedException, IOException {
123 122 getLogger().info("Check image {} exists", imageId);
124 123
125 124 return checkRetCode(
126 125 startProcess(builder(IMAGE_COMMAND, INSPECT_COMMAND, "--format", "image-exists", imageId)),
127 126 0);
128 127 }
129 128
130 129 public boolean imageExists(File imageIdFile) {
131 130 if (imageIdFile.exists()) {
132 131 try {
133 132 var imageId = Utils.readImageRef(imageIdFile);
134 133 return imageExists(imageId.getId());
135 134 } catch (IOException | InterruptedException e) {
136 135 getLogger().error("Failed to read imageId {}: {}", imageIdFile, e);
137 136 return false;
138 137 }
139 138 }
140 139 return false;
141 140 }
142 141 }
@@ -1,71 +1,83
1 1 package org.implab.gradle.containers.cli;
2 2
3 3 import java.io.Serializable;
4 import java.util.ArrayList;
4 5 import java.util.Optional;
5 6
6 7 import com.fasterxml.jackson.annotation.JsonCreator;
7 8 import com.fasterxml.jackson.annotation.JsonProperty;
8 9
9 10 public class ImageName implements Serializable {
10 11
11 12 private static final long serialVersionUID = -1990105923537254552L;
12 13
13 14 final String authority;
14 15
15 final String name;
16 final String groupName;
17
18 final String localName;
16 19
17 20 final String tag;
18 21
19 public ImageName() {
20 name = null;
21 authority = null;
22 tag = null;
23 }
22 @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
23 public ImageName(
24 @JsonProperty("authority") String authority,
25 @JsonProperty("groupName") String groupName,
26 @JsonProperty("localName") String localName,
27 @JsonProperty("tag") String tag) {
28 if (localName == null || localName.isBlank())
29 throw new IllegalArgumentException("localName can't be null or blank string");
24 30
25 @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
26 private ImageName(@JsonProperty("authority") String authority, @JsonProperty("name") String name,
27 @JsonProperty("tag") String tag) {
28 31 this.authority = authority;
29 this.name = name;
32 this.groupName = groupName;
33 this.localName = localName;
30 34 this.tag = tag;
31 35 }
32 36
33 public String getAuthority() {
34 return authority;
37 public Optional<String> getAuthority() {
38 return Optional.ofNullable(authority);
35 39 }
36 40
37 public ImageName authority(String authority) {
38 return new ImageName(authority, name, tag);
41 public ImageName withAuthority(String authority) {
42 return new ImageName(authority, groupName, localName, tag);
39 43 }
40 44
41 public String getName() {
42 return name;
45 public Optional<String> getGroupName() {
46 return Optional.ofNullable(groupName);
47 }
48
49 public ImageName withGroupName(String groupName) {
50 return new ImageName(authority, groupName, localName, tag);
43 51 }
44 52
45 public ImageName name(String name) {
46 return new ImageName(authority, name, tag);
53 public String getLocalName() {
54 return localName;
47 55 }
48 56
49 public String getTag() {
50 return tag;
57 public ImageName withLocalName(String localName) {
58 if (localName == null || localName.isBlank())
59 throw new IllegalArgumentException("localName can't be null or blank string");
60 return new ImageName(authority, groupName, localName, tag);
51 61 }
52 62
53 public ImageName tag(String tag) {
54 return new ImageName(authority, name, tag);
63 public Optional<String> getTag() {
64 return Optional.ofNullable(tag);
55 65 }
56 66
57 public ImageName copy() {
58 return new ImageName(authority, name, tag);
67 public ImageName withTag(String tag) {
68 return new ImageName(authority, groupName, localName, tag);
59 69 }
60 70
61 71 @Override
62 72 public String toString() {
63 StringBuilder sb = new StringBuilder();
73 var path = new ArrayList<String>();
64 74
65 Optional.ofNullable(authority).ifPresent(s -> sb.append(s).append("/"));
66 Optional.ofNullable(name).ifPresent(s -> sb.append(s));
67 Optional.ofNullable(tag).ifPresent(s -> sb.append(":").append(s));
75 getAuthority().ifPresent(path::add);
76 getGroupName().ifPresent(path::add);
77 path.add(getLocalName());
68 78
69 return sb.toString();
79 var repo = String.join("/", path);
80
81 return getTag().map(tag -> String.join(":", repo, tag)).orElse(repo);
70 82 }
71 83 }
@@ -1,116 +1,116
1 1 package org.implab.gradle.containers.tasks;
2 2
3 3 import java.util.ArrayList;
4 4 import java.util.HashMap;
5 5 import java.util.List;
6 6 import java.util.Map;
7 7
8 8 import org.gradle.api.Action;
9 9 import org.gradle.api.file.Directory;
10 10 import org.gradle.api.file.DirectoryProperty;
11 11 import org.gradle.api.file.RegularFile;
12 12 import org.gradle.api.file.RegularFileProperty;
13 13 import org.gradle.api.provider.MapProperty;
14 14 import org.gradle.api.provider.Property;
15 15 import org.gradle.api.provider.Provider;
16 16 import org.gradle.api.tasks.Input;
17 17 import org.gradle.api.tasks.InputDirectory;
18 18 import org.gradle.api.tasks.Internal;
19 19 import org.gradle.api.tasks.Optional;
20 20 import org.gradle.api.tasks.OutputFile;
21 21 import org.gradle.api.tasks.SkipWhenEmpty;
22 22 import org.gradle.api.tasks.TaskAction;
23 23 import java.io.File;
24 24
25 import org.implab.gradle.containers.cli.ImageName;
26 25 import org.implab.gradle.containers.cli.ImageRef;
27 26 import org.implab.gradle.containers.cli.Utils;
28 27 import org.implab.gradle.containers.dsl.MapPropertyEntry;
29 28 import org.implab.gradle.containers.dsl.OptionsMixin;
30 29
31 30 import groovy.lang.Closure;
32 31
33 32 public abstract class BuildImage extends DockerCliTask implements OptionsMixin {
33
34 34 @InputDirectory
35 35 @SkipWhenEmpty
36 36 public abstract DirectoryProperty getContextDirectory();
37 37
38 38 @Input
39 39 public abstract MapProperty<String, String> getBuildArgs();
40 40
41 41 @Input
42 42 @Optional
43 43 public abstract Property<String> getBuildTarget();
44 44
45 45 @Input
46 public abstract Property<ImageName> getImageName();
46 public abstract Property<String> getImageName();
47 47
48 48 @Internal
49 49 public abstract RegularFileProperty getImageIdFile();
50 50
51 51 @OutputFile
52 52 public Provider<File> getImageIdFileOutput() {
53 53 return getImageIdFile().map(RegularFile::getAsFile);
54 54 }
55 55
56 56 public BuildImage() {
57 57 getOutputs().upToDateWhen(task -> getImageIdFile()
58 58 .map(RegularFile::getAsFile)
59 59 .map(docker()::imageExists)
60 60 .getOrElse(false));
61 61 }
62 62
63 63 public void buildArgs(Action<Map<String, String>> spec) {
64 64 getBuildArgs().putAll(provider(() -> {
65 65 Map<String, String> args = new HashMap<>();
66 66 spec.execute(args);
67 67 getLogger().info("add buildArgs {}", args);
68 68 return args;
69 69 }));
70 70 }
71 71
72 72 public void buildArgs(Closure<Map<String, String>> spec) {
73 73 buildArgs(Utils.wrapClosure(spec));
74 74 }
75 75
76 76 public MapPropertyEntry<String, String> buildArg(String key) {
77 77 return new MapPropertyEntry<String, String>(getBuildArgs(), key, getProviders());
78 78 }
79 79
80 80 @TaskAction
81 81 public void run() throws Exception {
82 82 List<String> args = new ArrayList<>();
83 83
84 84 // create a temp file to store image id
85 85 var iidFile = new File(this.getTemporaryDir(), "iid");
86 86
87 87 // specify where to write image id
88 88 args.addAll(List.of("--iidfile", iidFile.getAbsolutePath()));
89 89
90 90 getBuildArgs().get().forEach((k, v) -> {
91 91 args.add("--build-arg");
92 92 args.add(String.format("%s=%s", k, v));
93 93 });
94 94
95 95 // add --target if specified for multi-stage build
96 96 if (getBuildTarget().isPresent()) {
97 97 args.add("--target");
98 98 args.add(getBuildTarget().get());
99 99 }
100 100
101 101 // add extra parameters
102 102 getOptions().get().forEach(args::add);
103 103
104 var imageTag = getImageName().map(ImageName::toString).get();
104 var imageTag = getImageName().get();
105 105
106 106 // build image
107 107 docker().buildImage(
108 108 imageTag,
109 109 getContextDirectory().map(Directory::getAsFile).get(),
110 110 args);
111 111
112 112 // read the built image id and store image ref metadata
113 113 var imageRef = new ImageRef(imageTag, Utils.readAll(iidFile));
114 Utils.writeJson(getImageIdFileOutput().get(), imageRef);
114 Utils.writeJson(getImageIdFile().map(RegularFile::getAsFile).get(), imageRef);
115 115 }
116 116 }
@@ -1,33 +1,32
1 1 package org.implab.gradle.containers.tasks;
2 2
3 3 import java.io.IOException;
4 4
5 5 import org.gradle.api.provider.ListProperty;
6 6 import org.gradle.api.provider.Property;
7 7 import org.gradle.api.tasks.Input;
8 8 import org.gradle.api.tasks.Optional;
9 9 import org.gradle.api.tasks.TaskAction;
10 import org.implab.gradle.containers.cli.ImageName;
11 10 import org.implab.gradle.containers.dsl.OptionsMixin;
12 11
13 12 public abstract class PushImage extends DockerCliTask implements OptionsMixin {
14 13
15 14 @Input
16 public abstract Property<ImageName> getImageName();
15 public abstract Property<String> getImageName();
17 16
18 17 @Input
19 18 @Optional
20 19 public abstract Property<String> getTransport();
21 20
22 21 @Input
23 22 @Optional
24 23 public abstract ListProperty<String> getOptions();
25 24
26 25 @TaskAction
27 26 public void run() throws InterruptedException, IOException {
28 27
29 28 docker().pushImage(
30 getImageName().get().toString(),
29 getImageName().get(),
31 30 getOptions().get());
32 31 }
33 32 }
@@ -1,43 +1,42
1 1 package org.implab.gradle.containers.tasks;
2 2
3 3 import java.io.IOException;
4 4 import org.gradle.api.Action;
5 5 import org.gradle.api.provider.ListProperty;
6 6 import org.gradle.api.provider.Property;
7 7 import org.gradle.api.tasks.Input;
8 8 import org.gradle.api.tasks.Optional;
9 import org.implab.gradle.containers.cli.ImageName;
10 9 import org.implab.gradle.containers.dsl.OptionsMixin;
11 10 import org.implab.gradle.containers.dsl.VolumeSpec;
12 11
13 12 public abstract class RunImage extends DockerCliTask implements OptionsMixin {
14 13
15 14 @Input
16 public abstract Property<ImageName> getImageName();
15 public abstract Property<String> getImageName();
17 16
18 17 @Input
19 18 @Optional
20 19 public abstract ListProperty<String> getCommandLine();
21 20
22 21
23 22 public void volume(Action<VolumeSpec> configure) {
24 23 getOptions().add("-v");
25 24 getOptions().add(provider(() -> {
26 25 var volumeSpec = getObjectFactory().newInstance(VolumeSpec.class);
27 26 configure.execute(volumeSpec);
28 27 return volumeSpec.resolveSpec();
29 28 }));
30 29 }
31 30
32 31 void commandLine(String ...args) {
33 32 getCommandLine().addAll(args);
34 33 }
35 34
36 35 public void run() throws InterruptedException, IOException {
37 36 docker().runImage(
38 getImageName().get().toString(),
37 getImageName().get(),
39 38 getOptions().get(),
40 39 getCommandLine().get());
41 40 }
42 41
43 42 }
@@ -1,22 +1,21
1 1 package org.implab.gradle.containers.tasks;
2 2
3 3 import java.io.IOException;
4 4 import org.gradle.api.provider.Property;
5 5 import org.gradle.api.tasks.Input;
6 6 import org.gradle.api.tasks.TaskAction;
7 import org.implab.gradle.containers.cli.ImageName;
8 7
9 8 public abstract class TagImage extends DockerCliTask {
10 9 @Input
11 public abstract Property<ImageName> getSrcImage();
10 public abstract Property<String> getSrcImage();
12 11
13 12 @Input
14 public abstract Property<ImageName> getDestImage();
13 public abstract Property<String> getDestImage();
15 14
16 15 @TaskAction
17 16 public void run() throws InterruptedException, IOException {
18 17 docker().tagImage(
19 getSrcImage().map(ImageName::toString).get(),
20 getDestImage().map(ImageName::toString).get());
18 getSrcImage().get(),
19 getDestImage().get());
21 20 }
22 21 }
General Comments 0
You need to be logged in to leave comments. Login now