##// END OF EJS Templates
Implemented compose
cin -
r12:c7d470187afa v1.2.0 default
parent child
Show More
@@ -0,0 +1,17
1 package org.implab.gradle.containers;
2
3 import org.gradle.api.provider.Property;
4 import org.gradle.api.provider.SetProperty;
5
6 public abstract class ComposeExtension {
7 public final String COMPOSE_FILE = "compose.yaml";
8
9 public abstract SetProperty<String> getProfiles();
10
11 public abstract Property<String> getComposeFileName();
12
13 public ComposeExtension() {
14 getComposeFileName().convention(COMPOSE_FILE);
15 }
16
17 }
@@ -0,0 +1,159
1 package org.implab.gradle.containers;
2
3 import java.io.IOException;
4 import java.util.HashMap;
5 import java.util.Map;
6
7 import org.gradle.api.DefaultTask;
8 import org.gradle.api.Plugin;
9 import org.gradle.api.Project;
10 import org.gradle.api.artifacts.Configuration;
11 import org.gradle.api.artifacts.Configuration.State;
12 import org.gradle.api.logging.Logger;
13 import org.gradle.api.tasks.Copy;
14 import org.gradle.api.tasks.Delete;
15 import org.implab.gradle.containers.cli.Utils;
16 import org.implab.gradle.containers.tasks.ComposeRm;
17 import org.implab.gradle.containers.tasks.ComposeStop;
18 import org.implab.gradle.containers.tasks.ComposeUp;
19 import org.implab.gradle.containers.tasks.WriteEnv;
20
21 public abstract class ComposePlugin implements Plugin<Project>, ProjectMixin {
22 public final String COMPOSE_IMAGES_CONFIGURATION = "composeImages";
23
24 public final String COMPOSE_EXTENSION = "compose";
25
26 public final String COMPOSE_UP_TASK = "up";
27
28 public final String COMPOSE_STOP_TASK = "stop";
29
30 public final String COMPOSE_RM_TASK = "rm";
31
32 public final String CLEAN_TASK = "clean";
33
34 public final String BUILD_TASK = "build";
35
36 public final String PROCESS_RESOURCES_TASK = "processResources";
37
38 public final String WRITE_ENV_TASK = "writeEnv";
39
40 public final String COMPOSE_VAR = "composeVar";
41
42 public final String ENV_FILE_NAME = ".env";
43
44 public Logger getLogger() {
45 return getProject().getLogger();
46 }
47
48 @Override
49 public void apply(Project project) {
50 var containerImages = configuration(COMPOSE_IMAGES_CONFIGURATION, Configurations.RESOLVABLE);
51
52 // basic configuration, register extension
53 var basePlugin = plugin(ContainerBasePlugin.class);
54 var containerExtension = basePlugin.getContainerExtension();
55
56 var composeExtension = extension(COMPOSE_EXTENSION, ComposeExtension.class);
57
58 var composeFile = containerExtension.getContextDirectory()
59 .file(composeExtension.getComposeFileName());
60 var composeProfiles = composeExtension.getProfiles();
61
62 var cleanTask = task(CLEAN_TASK, Delete.class, t -> {
63 t.delete(containerExtension.getContextDirectory());
64 });
65
66 // copy task from src/main
67 var processResources = task(PROCESS_RESOURCES_TASK, Copy.class, t -> {
68 t.mustRunAfter(cleanTask);
69 t.from(projectDirectory().dir("src/main"));
70 t.into(containerExtension.getContextDirectory());
71 });
72
73 // write .env
74 var writeEnvTask = task(WRITE_ENV_TASK, WriteEnv.class, t -> {
75 t.dependsOn(processResources, containerImages);
76 t.getEnvFile().set(containerExtension.getContextDirectory().file(ENV_FILE_NAME));
77
78 t.getEnvironment().putAll(containerImages.map(this::extractComposeEnv));
79
80 });
81
82 var buildTask = task(BUILD_TASK, DefaultTask.class, t -> {
83 t.dependsOn(writeEnvTask);
84 });
85
86 var stopTask = task(COMPOSE_STOP_TASK, ComposeStop.class, t -> {
87 // stop must run after build
88 t.mustRunAfter(buildTask);
89
90 t.getProfiles().addAll(composeProfiles);
91 t.getComposeFile().set(composeFile);
92 });
93
94 var rmTask = task(COMPOSE_RM_TASK, ComposeRm.class, t -> {
95 // rm must run after build and stop
96 t.mustRunAfter(buildTask, stopTask);
97
98 t.getProfiles().addAll(composeProfiles);
99 t.getComposeFile().set(composeFile);
100 });
101
102 task(COMPOSE_UP_TASK, ComposeUp.class, t -> {
103 t.dependsOn(buildTask);
104 // up must run after stop and rm
105 t.mustRunAfter(stopTask, rmTask);
106
107 t.getProfiles().addAll(composeProfiles);
108 t.getComposeFile().set(composeFile);
109 });
110 }
111
112 /**
113 * Processed the configurations, extracts composeVar extra property from
114 * each dependency in this configuration and adds a value to the resulting
115 * map. The values in the nap will contain image tags.
116 */
117 private Map<String, String> extractComposeEnv(Configuration config) {
118 if (config.getState() != State.UNRESOLVED) {
119 getLogger().error("extractComposeEnv: The configuration {} isn't resolved.", config.getName());
120 throw new IllegalStateException("The specified configuration isn't resolved");
121 }
122
123 getLogger().info("extractComposeEnv {}", config.getName());
124
125 var map = new HashMap<String, String>();
126
127 for (var dependency : config.getDependencies()) {
128 // get extra composeVar if present
129 extra(dependency, COMPOSE_VAR, String.class).optional().ifPresent(varName -> {
130 // if we have a composeVar extra attribute on this dependency
131
132 // get files for the dependency
133 var files = config.files(dependency);
134 if (files.size() == 1) {
135 // should bw exactly 1 file
136 var file = files.stream().findAny().get();
137 getLogger().info("Processing {}: {}", dependency, file);
138
139 try {
140 // try read imageRef
141 Utils.readImageRef(file).getTag()
142 .ifPresentOrElse(
143 tag -> map.put(varName, tag),
144 () -> getLogger().error("ImageRef doesn't have a tag: {}", file));
145
146 } catch (IOException e) {
147 getLogger().error("Failed to read ImageRef {}: {}", file, e);
148 }
149
150 } else {
151 getLogger().warn("Dependency {} must have exactly 1 file", dependency);
152 }
153 });
154 }
155
156 return map;
157 }
158
159 }
@@ -0,0 +1,24
1 package org.implab.gradle.containers;
2
3 import org.gradle.api.Action;
4 import org.gradle.api.artifacts.Configuration;
5
6 public final class Configurations {
7
8 public static final Action<Configuration> RESOLVABLE = Configurations::resolvable;
9
10 public static final Action<Configuration> CONSUMABLE = Configurations::consumable;
11
12 private Configurations() {
13 }
14
15 private static void resolvable(Configuration configuration) {
16 configuration.setCanBeResolved(true);
17 configuration.setCanBeConsumed(false);
18 }
19
20 private static void consumable(Configuration configuration) {
21 configuration.setCanBeResolved(false);
22 configuration.setCanBeConsumed(true);
23 }
24 }
@@ -0,0 +1,69
1 package org.implab.gradle.containers;
2
3 import java.util.Collections;
4 import java.util.Optional;
5
6 import javax.inject.Inject;
7
8 import org.gradle.api.Action;
9 import org.gradle.api.NamedDomainObjectProvider;
10 import org.gradle.api.Plugin;
11 import org.gradle.api.Project;
12 import org.gradle.api.Task;
13 import org.gradle.api.artifacts.Configuration;
14 import org.gradle.api.file.Directory;
15 import org.gradle.api.tasks.TaskProvider;
16 import org.implab.gradle.containers.dsl.ExtraProps;
17 import org.implab.gradle.containers.dsl.MapEntry;
18
19 /** Project configuration traits */
20 public interface ProjectMixin {
21 @Inject
22 Project getProject();
23
24 /** registers the new task */
25 default <T extends Task> TaskProvider<T> task(String name, Class<T> clazz, Action<? super T> configure) {
26 return getProject().getTasks().register(name, clazz, configure);
27 }
28
29 /** Registers the new configuration */
30 default NamedDomainObjectProvider<Configuration> configuration(String name, Action<? super Configuration> configure) {
31 return getProject().getConfigurations().register(name, configure);
32 }
33
34 /** Returns the project directory */
35 default Directory projectDirectory() {
36 return getProject().getLayout().getProjectDirectory();
37 }
38
39 /** Applies and returns the specified plugin, plugin is applied only once. */
40 default <T extends Plugin<Project>> T plugin(Class<T> clazz) {
41 getProject().getPluginManager().apply(clazz);
42 return getProject().getPlugins().findPlugin(clazz);
43 }
44
45 /** Creates and register a new project extension.
46 *
47 * @param <T> The type of the extension
48 * @param extensionName The name of the extension in the project
49 * @param clazz The class of the extension
50 * @return the newly created extension
51 */
52 default <T> T extension(String extensionName, Class<T> clazz) {
53 T extension = getProject().getObjects().newInstance(clazz);
54 getProject().getExtensions().add(extensionName, extension);
55 return extension;
56 }
57
58 /** Return extra properties container for the specified object */
59 default Optional<ExtraProps> extra(Object target) {
60 return ExtraProps.extra(target);
61 }
62
63 /** Returns accessor for the specified extra property name */
64 default <T> MapEntry<T> extra(Object target, String prop, Class<T> clazz) {
65 return ExtraProps.extra(target)
66 .map(x -> x.prop(prop, clazz))
67 .orElseGet(() -> new MapEntry<T>(Collections.emptyMap(), prop, clazz));
68 }
69 }
@@ -0,0 +1,42
1 package org.implab.gradle.containers.dsl;
2
3 import java.util.Optional;
4
5 import org.codehaus.groovy.runtime.DefaultGroovyMethods;
6 import org.gradle.api.plugins.ExtensionAware;
7 import org.gradle.api.plugins.ExtraPropertiesExtension;
8
9 public class ExtraProps {
10 private final ExtraPropertiesExtension extraProps;
11
12 protected ExtraProps(ExtraPropertiesExtension extraProps) {
13 this.extraProps = extraProps;
14 }
15
16 public <T> Optional<T> get(String key, Class<T> clazz) {
17 if (!extraProps.has(key))
18 return Optional.empty();
19
20 return Optional.ofNullable(DefaultGroovyMethods.asType(extraProps.get(key), clazz));
21 }
22
23 public <T> void put(String key, T value) {
24 extraProps.set(key, value);
25 }
26
27 public void delete(String key) {
28 extraProps.getProperties().remove(key);
29 }
30
31 public <T> MapEntry<T> prop(String key, Class<T> clazz) {
32 return new MapEntry<>(extraProps.getProperties(), key, clazz);
33 }
34
35 public static Optional<ExtraProps> extra(Object target) {
36 return target instanceof ExtensionAware
37 ? Optional.of(new ExtraProps(
38 ((ExtensionAware) target).getExtensions().getExtraProperties()))
39 : Optional.empty();
40
41 }
42 }
@@ -0,0 +1,39
1 package org.implab.gradle.containers.dsl;
2
3 import java.util.Map;
4 import java.util.Optional;
5
6 public class MapEntry<T> {
7 private final Map<String, Object> map;
8 private final String key;
9 private final Class<T> clazz;
10
11 public MapEntry(Map<String, Object> map, String key, Class<T> clazz) {
12 this.map = map;
13 this.key = key;
14 this.clazz = clazz;
15 }
16
17 public boolean has() {
18 var value = map.get(key);
19 return value != null;
20 }
21
22 public T get() {
23 if (!has())
24 throw new IllegalStateException();
25 return clazz.cast(map.get(key));
26 }
27
28 public void put(T value) {
29 map.put(key, value);
30 }
31
32 public void remove() {
33 map.remove(key);
34 }
35
36 public Optional<T> optional() {
37 return has() ? Optional.of(get()) : Optional.empty();
38 }
39 }
@@ -0,0 +1,22
1 package org.implab.gradle.containers.tasks;
2
3 import java.io.IOException;
4
5 import org.gradle.api.provider.Property;
6 import org.gradle.api.tasks.Internal;
7 import org.gradle.api.tasks.TaskAction;
8
9 public abstract class ComposeRm extends ComposeStop {
10
11 @Internal
12 public abstract Property<Boolean> getRemoveVolumes();
13
14 public ComposeRm() {
15 getRemoveVolumes().convention(true);
16 }
17
18 @TaskAction
19 public void run() throws InterruptedException, IOException {
20 docker().composeRm(getComposeFile().get().getAsFile(), getProfiles().get(), getRemoveVolumes().get());
21 }
22 }
@@ -0,0 +1,13
1 package org.implab.gradle.containers.tasks;
2
3 import java.io.IOException;
4
5 import org.gradle.api.tasks.TaskAction;
6
7 public abstract class ComposeStop extends ComposeTask {
8
9 @TaskAction
10 public void run() throws InterruptedException, IOException {
11 docker().composeStop(getComposeFile().getAsFile().get(), getProfiles().get());
12 }
13 } No newline at end of file
@@ -0,0 +1,33
1 package org.implab.gradle.containers.tasks;
2
3 import org.gradle.api.file.RegularFileProperty;
4 import org.gradle.api.provider.SetProperty;
5 import org.gradle.api.tasks.Internal;
6
7 /**
8 * Base task for compose subtasks like 'uo', 'rm', 'stop', etc.
9 */
10 public abstract class ComposeTask extends DockerCliTask {
11
12 /** The list of profiles to use with the compose commands */
13 @Internal
14 public abstract SetProperty<String> getProfiles();
15
16 /**
17 * The primary compose files. This task is executed regardless whether these
18 * files was changed.
19 */
20 @Internal
21 public abstract RegularFileProperty getComposeFile();
22
23 protected ComposeTask() {
24 // the task can only be evaluated if the compose file is present
25 setOnlyIf(self -> {
26 var composeFile = getComposeFile().get().getAsFile();
27 var exists = composeFile.exists();
28 getLogger().info("file: {} {}", composeFile.toString(), exists ? "exists" : "doesn't exist");
29 return exists;
30 });
31 }
32
33 }
@@ -0,0 +1,13
1 package org.implab.gradle.containers.tasks;
2
3 import java.io.IOException;
4
5 import org.gradle.api.tasks.TaskAction;
6
7 public abstract class ComposeUp extends ComposeTask {
8
9 @TaskAction
10 public void run() throws InterruptedException, IOException {
11 docker().composeUp(getComposeFile().getAsFile().get(), getProfiles().get());
12 }
13 }
@@ -0,0 +1,59
1 package org.implab.gradle.containers.tasks;
2
3 import org.gradle.api.Action;
4 import org.gradle.api.DefaultTask;
5 import org.gradle.api.file.RegularFileProperty;
6 import org.gradle.api.provider.MapProperty;
7 import org.gradle.api.tasks.Input;
8 import org.gradle.api.tasks.OutputFile;
9 import org.gradle.api.tasks.TaskAction;
10 import org.implab.gradle.containers.PropertiesMixin;
11 import org.implab.gradle.containers.cli.Utils;
12 import org.implab.gradle.containers.dsl.MapPropertyEntry;
13
14 import java.io.FileWriter;
15 import java.io.IOException;
16 import java.util.HashMap;
17 import java.util.Map;
18
19 import groovy.lang.Closure;
20
21 public abstract class WriteEnv extends DefaultTask implements PropertiesMixin {
22
23 @Input
24 public abstract MapProperty<String, String> getEnvironment();
25
26 @OutputFile
27 public abstract RegularFileProperty getEnvFile();
28
29 public void env(Action<Map<String, String>> spec) {
30 getEnvironment().putAll(provider(() -> {
31 Map<String, String> args = new HashMap<>();
32 spec.execute(args);
33 getLogger().info("add buildArgs {}", args);
34 return args;
35 }));
36 }
37
38 public void env(Closure<Map<String, String>> spec) {
39 env(Utils.wrapClosure(spec));
40 }
41
42 public MapPropertyEntry<String, String> env(String key) {
43 return new MapPropertyEntry<String, String>(getEnvironment(), key, getProviders());
44 }
45
46 @TaskAction
47 public void run() throws IOException {
48 try (var writer = new FileWriter(getEnvFile().get().getAsFile())) {
49 for (var entry : getEnvironment().get().entrySet()) {
50 writer.write(entry.getKey());
51 writer.write("=");
52 writer.write(entry.getValue().replace("\n", "\\n"));
53 writer.write("\n");
54 }
55 }
56 }
57
58
59 }
@@ -1,2 +1,2
1 1 group=org.implab.gradle
2 version=1.1.2 No newline at end of file
2 version=1.2.0 No newline at end of file
@@ -1,53 +1,54
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 12 public class ContainerBasePlugin implements Plugin<Project> {
13 13 public static final String CONTAINER_EXTENSION_NAME = "container";
14 14
15 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 // TODO: move properties initialization into the constructor
34 35 containerExtension.getImageAuthority()
35 36 .convention(project.provider(() -> (String) project.getProperties().get("imagesAuthority")));
36 37
37 38 containerExtension.getImageGroup()
38 39 .convention(project.provider(() -> (String) project.getProperties().get("imagesGroup")));
39 40
40 41 containerExtension.getCliCmd()
41 42 .convention(project
42 43 .provider(() -> (String) project.getProperties().get("containerCli"))
43 44 .orElse("docker"));
44 45
45 46 project.getExtensions().add(CONTAINER_EXTENSION_NAME, containerExtension);
46 47
47 48 exportClasses(
48 49 project,
49 50 BuildImage.class, PushImage.class, SaveImage.class, TagImage.class, RunImage.class);
50 51
51 52 }
52 53
53 54 }
@@ -1,141 +1,186
1 1 package org.implab.gradle.containers.cli;
2 2
3 3 import java.io.File;
4 4 import java.io.IOException;
5 5 import java.util.ArrayList;
6 6 import java.util.Arrays;
7 7 import java.util.List;
8 8 import java.util.Optional;
9 import java.util.Set;
9 10
10 11 import org.gradle.api.logging.Logger;
11 12
12 13 public abstract class DockerTraits {
13 14
14 15 public final String BUILD_COMMAND = "build";
15 16 public final String PUSH_COMMAND = "push";
16 17 public final String RUN_COMMAND = "run";
17 18 public final String SAVE_COMMAND = "save";
18 19 public final String INSPECT_COMMAND = "inspect";
19 20 public final String IMAGE_COMMAND = "image";
20 21 public final String TAG_COMMAND = "tag";
22 public final String COMPOSE_COMMAND = "compose";
23 public final String UP_COMMAND = "up";
24 public final String STOP_COMMAND = "stop";
25 public final String RM_COMMAND = "rm";
21 26
22 27 public abstract Logger getLogger();
23 28
24 29 public abstract Optional<File> getWorkingDir();
25 30
26 31 public abstract String getCliCmd();
27 32
28 33 Process startProcess(ProcessBuilder builder) throws IOException {
29 34 getLogger().info("Starting: {}", builder.command());
30 35 return builder.start();
31 36 }
32 37
33 38 protected boolean checkRetCode(Process proc, int code) throws InterruptedException {
34 39 if (getLogger().isInfoEnabled()) {
35 40 Utils.redirectIO(proc.getInputStream(), getLogger()::info);
36 41 Utils.redirectIO(proc.getErrorStream(), getLogger()::info);
37 42 }
38 43
39 44 return proc.waitFor() == code;
40 45 }
41 46
42 47 protected void complete(Process proc) throws InterruptedException, IOException {
43 48 if (getLogger().isInfoEnabled())
44 49 Utils.redirectIO(proc.getInputStream(), getLogger()::info);
45 50
46 51 if (getLogger().isErrorEnabled())
47 52 Utils.redirectIO(proc.getErrorStream(), getLogger()::error);
48 53
49 54 var code = proc.waitFor();
50 55 if (code != 0) {
51 56 getLogger().error("The process exited with code {}", code);
52 57 throw new IOException("The process exited with error code " + code);
53 58 }
54 59 }
55 60
56 61 protected ProcessBuilder builder(String... args) {
57 62 var argsList = new ArrayList<String>(args.length + 1);
58 63 Arrays.stream(args).forEach(argsList::add);
59 64
60 65 return builder(argsList);
61 66 }
62 67
63 68 protected ProcessBuilder builder(List<String> args) {
64 69 var command = new ArrayList<String>(args.size() + 1);
65 70
66 71 command.add(getCliCmd());
67 72 args.forEach(command::add);
68 73
69 74 var builder = new ProcessBuilder(command);
70 75
71 76 getWorkingDir().ifPresent(builder::directory);
72 77 return builder;
73 78 }
74 79
75 80 public void buildImage(String imageName, File contextDirectory, List<String> options)
76 81 throws IOException, InterruptedException {
77 82 var args = new ArrayList<String>();
78 83 args.add(BUILD_COMMAND);
79 84 args.addAll(options);
80 85 args.add("-t");
81 86 args.add(imageName);
82 87 args.add(contextDirectory.getAbsolutePath());
83 88 complete(startProcess(builder(args)));
84 89 }
85 90
86 91 public void pushImage(String image, List<String> options) throws InterruptedException, IOException {
87 92 var args = new ArrayList<String>();
88 93 args.add(PUSH_COMMAND);
89 94 args.addAll(options);
90 95 args.add(image);
91 96 complete(startProcess(builder(args)));
92 97 }
93 98
94 99 public void runImage(String image, List<String> options, List<String> command)
95 100 throws InterruptedException, IOException {
96 101 var args = new ArrayList<String>();
97 102 args.add(RUN_COMMAND);
98 103 args.addAll(options);
99 104 args.add(image);
100 105 args.addAll(command);
101 106 complete(startProcess(builder(args)));
102 107 }
103 108
104 109 public void saveImage(List<String> images, File output) throws InterruptedException, IOException {
105 110 if (output.exists())
106 111 output.delete();
107 112
108 113 var args = new ArrayList<String>();
109 114 args.add(SAVE_COMMAND);
110 115 args.add("-o");
111 116 args.add(output.getAbsolutePath());
112 117 images.forEach(args::add);
113 118
114 119 complete(startProcess(builder(args)));
115 120 }
116 121
117 122 public void tagImage(String source, String target) throws InterruptedException, IOException {
118 123 complete(startProcess(builder(TAG_COMMAND, source, target)));
119 124 }
120 125
121 126 public boolean imageExists(String imageId) throws InterruptedException, IOException {
122 127 getLogger().info("Check image {} exists", imageId);
123 128
124 129 return checkRetCode(
125 130 startProcess(builder(IMAGE_COMMAND, INSPECT_COMMAND, "--format", "image-exists", imageId)),
126 131 0);
127 132 }
128 133
129 134 public boolean imageExists(File imageIdFile) {
130 135 if (imageIdFile.exists()) {
131 136 try {
132 137 var imageId = Utils.readImageRef(imageIdFile);
133 138 return imageExists(imageId.getId());
134 139 } catch (IOException | InterruptedException e) {
135 140 getLogger().error("Failed to read imageId {}: {}", imageIdFile, e);
136 141 return false;
137 142 }
138 143 }
139 144 return false;
140 145 }
146
147 List<String> composeArgs(File primaryCompose, Set<String> profiles, String... extra) {
148 var args = new ArrayList<String>();
149
150 args.add(COMPOSE_COMMAND);
151 args.add("--file");
152 args.add(primaryCompose.getAbsolutePath());
153
154 if (profiles.size() > 0) {
155 for (var profile : profiles) {
156 args.add("--profile");
157 args.add(profile);
158 }
159 }
160
161 args.addAll(List.of(extra));
162
163 return args;
164 }
165
166 public void composeUp(File primaryCompose, Set<String> profiles) throws InterruptedException, IOException {
167 var args = composeArgs(primaryCompose, profiles, UP_COMMAND, "--detach");
168
169 complete(startProcess(builder(args)));
170 }
171
172 public void composeStop(File primaryCompose, Set<String> profiles) throws InterruptedException, IOException {
173 var args = composeArgs(primaryCompose, profiles, STOP_COMMAND);
174 complete(startProcess(builder(args)));
175 }
176
177 public void composeRm(File primaryCompose, Set<String> profiles, boolean removeVolumes)
178 throws InterruptedException, IOException {
179 var args = composeArgs(primaryCompose, profiles, RM_COMMAND, "--force", "--stop");
180
181 if (removeVolumes)
182 args.add("--volumes");
183
184 complete(startProcess(builder(args)));
185 }
141 186 }
@@ -1,61 +1,61
1 1 package org.implab.gradle.containers.tasks;
2 2
3 3 import java.io.File;
4 4 import java.util.Optional;
5 5
6 6 import org.gradle.api.DefaultTask;
7 import org.gradle.api.file.Directory;
8 import org.gradle.api.file.DirectoryProperty;
9 7 import org.gradle.api.logging.Logger;
10 8 import org.gradle.api.provider.Property;
11 9 import org.gradle.api.tasks.Input;
12 10 import org.gradle.api.tasks.Internal;
13 11 import org.implab.gradle.containers.ContainerExtension;
14 12 import org.implab.gradle.containers.PropertiesMixin;
15 13 import org.implab.gradle.containers.cli.DockerTraits;
16 14
17 15 public abstract class DockerCliTask extends DefaultTask implements PropertiesMixin {
18 16
19 17 @Input
20 18 public abstract Property<String> getCliCmd();
21 19
20 /**
21 * Returns working directory for docker commands
22 */
22 23 @Input
23 24 @org.gradle.api.tasks.Optional
24 public abstract DirectoryProperty getWorkingDirectory();
25 public abstract Property<File> getWorkingDirectory();
25 26
26 27 @Internal
27 28 protected ContainerExtension getContainerExtension() {
28 29 return getProject().getExtensions().getByType(ContainerExtension.class);
29 30 }
30 31
31 32 public DockerCliTask() {
32 33 getCliCmd().convention(getContainerExtension().getCliCmd());
33 34
34 35 }
35 36
36 37 protected DockerTraits docker() {
37 38 return new TaskDockerTraits();
38 39 }
39 40
40 41 class TaskDockerTraits extends DockerTraits {
41 42
42 43 @Override
43 44 public Logger getLogger() {
44 45 return DockerCliTask.this.getLogger();
45 46 }
46 47
47 48 @Override
48 49 public Optional<File> getWorkingDir() {
49 50 return getWorkingDirectory()
50 .map(Directory::getAsFile)
51 51 .map(Optional::of)
52 52 .getOrElse(Optional.empty());
53 53 }
54 54
55 55 @Override
56 56 public String getCliCmd() {
57 57 return DockerCliTask.this.getCliCmd().get();
58 58 }
59 59
60 60 }
61 61 }
General Comments 0
You need to be logged in to leave comments. Login now