##// END OF EJS Templates
WIP docker compose support
cin -
r11:cf3a5b9d59a9 default
parent child
Show More
@@ -38,6 +38,14 gradlePlugin {
38 implementationClass = 'org.implab.gradle.containers.ContainerBasePlugin'
38 implementationClass = 'org.implab.gradle.containers.ContainerBasePlugin'
39 tags.set(['containers', 'image', 'docker', 'podman'])
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
@@ -12,7 +12,7 import org.implab.gradle.containers.task
12 public class ContainerBasePlugin implements Plugin<Project> {
12 public class ContainerBasePlugin implements Plugin<Project> {
13 public static final String CONTAINER_EXTENSION_NAME = "container";
13 public static final String CONTAINER_EXTENSION_NAME = "container";
14
14
15 ContainerExtension containerExtension;
15 private ContainerExtension containerExtension;
16
16
17 ContainerExtension getContainerExtension() {
17 ContainerExtension getContainerExtension() {
18 if (containerExtension == null)
18 if (containerExtension == null)
@@ -37,13 +37,17 public class ContainerBasePlugin impleme
37 containerExtension.getImageGroup()
37 containerExtension.getImageGroup()
38 .convention(project.provider(() -> (String) project.getProperties().get("imagesGroup")));
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 project.getExtensions().add(CONTAINER_EXTENSION_NAME, containerExtension);
45 project.getExtensions().add(CONTAINER_EXTENSION_NAME, containerExtension);
41
46
42 exportClasses(
47 exportClasses(
43 project,
48 project,
44 BuildImage.class, PushImage.class, SaveImage.class, TagImage.class, RunImage.class);
49 BuildImage.class, PushImage.class, SaveImage.class, TagImage.class, RunImage.class);
45
50
46
47 }
51 }
48
52
49 }
53 }
@@ -10,21 +10,18 import javax.inject.Inject;
10 import org.gradle.api.Project;
10 import org.gradle.api.Project;
11 import org.gradle.api.file.DirectoryProperty;
11 import org.gradle.api.file.DirectoryProperty;
12 import org.gradle.api.file.ProjectLayout;
12 import org.gradle.api.file.ProjectLayout;
13 import org.gradle.api.file.RegularFileProperty;
14 import org.gradle.api.provider.Property;
13 import org.gradle.api.provider.Property;
15 import org.gradle.api.provider.Provider;
14 import org.gradle.api.provider.Provider;
16 import org.implab.gradle.containers.cli.ImageName;
15 import org.implab.gradle.containers.cli.ImageName;
17 import org.implab.gradle.containers.cli.ImageRef;
16 import org.implab.gradle.containers.cli.ImageRef;
18 import org.implab.gradle.containers.cli.Utils;
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 public abstract Property<String> getCliCmd();
21 public abstract Property<String> getCliCmd();
23
22
24 public abstract DirectoryProperty getContextDirectory();
23 public abstract DirectoryProperty getContextDirectory();
25
24
26 public abstract RegularFileProperty getImageIdFile();
27
28 /**
25 /**
29 * Specifies the name of the registry where the image is located
26 * Specifies the name of the registry where the image is located
30 * {@code registry.my-company.org}
27 * {@code registry.my-company.org}
@@ -36,7 +33,9 public abstract class ContainerExtension
36 */
33 */
37 public abstract Property<String> getImageGroup();
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 * Specifies local image part like {@code httpd}
41 * Specifies local image part like {@code httpd}
@@ -57,25 +56,19 public abstract class ContainerExtension
57 public ContainerExtension(ProjectLayout layout, Project project) {
56 public ContainerExtension(ProjectLayout layout, Project project) {
58 getContextDirectory().convention(layout.getBuildDirectory().dir("context"));
57 getContextDirectory().convention(layout.getBuildDirectory().dir("context"));
59
58
60 getImageIdFile().convention(layout.getBuildDirectory().file("iid.json"));
61
62 getCliCmd().set("docker");
63
64 getImageLocalName().convention(project.getName());
59 getImageLocalName().convention(project.getName());
65
60
66 getImageTag().set(project
61 getImageTag().set(provider(() -> Optional.ofNullable(project.getVersion())
67 .provider(() -> Optional.ofNullable(project.getVersion()).map(v -> v.toString()).orElse("latest")));
62 .map(Object::toString)
68
63 .orElse("latest")));
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())));
75 }
64 }
76
65
77 public ImageName createImageName() {
66 ImageName createImageName() {
78 return new ImageName();
67 return new ImageName(
68 getImageAuthority().getOrNull(),
69 getImageGroup().getOrNull(),
70 getImageLocalName().get(),
71 getImageTag().getOrNull());
79 }
72 }
80
73
81 public ImageRef readImageRef(File file) throws FileNotFoundException, IOException {
74 public ImageRef readImageRef(File file) throws FileNotFoundException, IOException {
@@ -19,8 +19,6 public class ContainerPlugin implements
19
19
20 public static final String ARCHIVE_CONFIGURATION = "archive";
20 public static final String ARCHIVE_CONFIGURATION = "archive";
21
21
22 ContainerExtension containerExtension;
23
24 public void apply(Project project) {
22 public void apply(Project project) {
25 ProjectLayout layout = project.getLayout();
23 ProjectLayout layout = project.getLayout();
26
24
@@ -53,9 +51,9 public class ContainerPlugin implements
53 t.dependsOn(processResourcesTask);
51 t.dependsOn(processResourcesTask);
54
52
55 t.getContextDirectory().set(containerExtension.getContextDirectory());
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 project.getTasks().register("clean", Delete.class, t -> {
59 project.getTasks().register("clean", Delete.class, t -> {
@@ -74,7 +72,7 public class ContainerPlugin implements
74
72
75 project.getTasks().register("saveImage", SaveImage.class, t -> {
73 project.getTasks().register("saveImage", SaveImage.class, t -> {
76 t.dependsOn(buildImageTask);
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 project.getArtifacts().add(Dependency.DEFAULT_CONFIGURATION, buildImageTask);
78 project.getArtifacts().add(Dependency.DEFAULT_CONFIGURATION, buildImageTask);
@@ -2,7 +2,6 package org.implab.gradle.containers.cli
2
2
3 import java.io.File;
3 import java.io.File;
4 import java.io.IOException;
4 import java.io.IOException;
5 import java.nio.file.Files;
6 import java.util.ArrayList;
5 import java.util.ArrayList;
7 import java.util.Arrays;
6 import java.util.Arrays;
8 import java.util.List;
7 import java.util.List;
@@ -1,6 +1,7
1 package org.implab.gradle.containers.cli;
1 package org.implab.gradle.containers.cli;
2
2
3 import java.io.Serializable;
3 import java.io.Serializable;
4 import java.util.ArrayList;
4 import java.util.Optional;
5 import java.util.Optional;
5
6
6 import com.fasterxml.jackson.annotation.JsonCreator;
7 import com.fasterxml.jackson.annotation.JsonCreator;
@@ -12,60 +13,71 public class ImageName implements Serial
12
13
13 final String authority;
14 final String authority;
14
15
15 final String name;
16 final String groupName;
17
18 final String localName;
16
19
17 final String tag;
20 final String tag;
18
21
19 public ImageName() {
22 @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
20 name = null;
23 public ImageName(
21 authority = null;
24 @JsonProperty("authority") String authority,
22 tag = null;
25 @JsonProperty("groupName") String groupName,
23 }
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 this.authority = authority;
31 this.authority = authority;
29 this.name = name;
32 this.groupName = groupName;
33 this.localName = localName;
30 this.tag = tag;
34 this.tag = tag;
31 }
35 }
32
36
33 public String getAuthority() {
37 public Optional<String> getAuthority() {
34 return authority;
38 return Optional.ofNullable(authority);
35 }
39 }
36
40
37 public ImageName authority(String authority) {
41 public ImageName withAuthority(String authority) {
38 return new ImageName(authority, name, tag);
42 return new ImageName(authority, groupName, localName, tag);
39 }
43 }
40
44
41 public String getName() {
45 public Optional<String> getGroupName() {
42 return name;
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) {
53 public String getLocalName() {
46 return new ImageName(authority, name, tag);
54 return localName;
47 }
55 }
48
56
49 public String getTag() {
57 public ImageName withLocalName(String localName) {
50 return tag;
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) {
63 public Optional<String> getTag() {
54 return new ImageName(authority, name, tag);
64 return Optional.ofNullable(tag);
55 }
65 }
56
66
57 public ImageName copy() {
67 public ImageName withTag(String tag) {
58 return new ImageName(authority, name, tag);
68 return new ImageName(authority, groupName, localName, tag);
59 }
69 }
60
70
61 @Override
71 @Override
62 public String toString() {
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("/"));
75 getAuthority().ifPresent(path::add);
66 Optional.ofNullable(name).ifPresent(s -> sb.append(s));
76 getGroupName().ifPresent(path::add);
67 Optional.ofNullable(tag).ifPresent(s -> sb.append(":").append(s));
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 }
@@ -22,7 +22,6 import org.gradle.api.tasks.SkipWhenEmpt
22 import org.gradle.api.tasks.TaskAction;
22 import org.gradle.api.tasks.TaskAction;
23 import java.io.File;
23 import java.io.File;
24
24
25 import org.implab.gradle.containers.cli.ImageName;
26 import org.implab.gradle.containers.cli.ImageRef;
25 import org.implab.gradle.containers.cli.ImageRef;
27 import org.implab.gradle.containers.cli.Utils;
26 import org.implab.gradle.containers.cli.Utils;
28 import org.implab.gradle.containers.dsl.MapPropertyEntry;
27 import org.implab.gradle.containers.dsl.MapPropertyEntry;
@@ -31,6 +30,7 import org.implab.gradle.containers.dsl.
31 import groovy.lang.Closure;
30 import groovy.lang.Closure;
32
31
33 public abstract class BuildImage extends DockerCliTask implements OptionsMixin {
32 public abstract class BuildImage extends DockerCliTask implements OptionsMixin {
33
34 @InputDirectory
34 @InputDirectory
35 @SkipWhenEmpty
35 @SkipWhenEmpty
36 public abstract DirectoryProperty getContextDirectory();
36 public abstract DirectoryProperty getContextDirectory();
@@ -43,7 +43,7 public abstract class BuildImage extends
43 public abstract Property<String> getBuildTarget();
43 public abstract Property<String> getBuildTarget();
44
44
45 @Input
45 @Input
46 public abstract Property<ImageName> getImageName();
46 public abstract Property<String> getImageName();
47
47
48 @Internal
48 @Internal
49 public abstract RegularFileProperty getImageIdFile();
49 public abstract RegularFileProperty getImageIdFile();
@@ -101,7 +101,7 public abstract class BuildImage extends
101 // add extra parameters
101 // add extra parameters
102 getOptions().get().forEach(args::add);
102 getOptions().get().forEach(args::add);
103
103
104 var imageTag = getImageName().map(ImageName::toString).get();
104 var imageTag = getImageName().get();
105
105
106 // build image
106 // build image
107 docker().buildImage(
107 docker().buildImage(
@@ -111,6 +111,6 public abstract class BuildImage extends
111
111
112 // read the built image id and store image ref metadata
112 // read the built image id and store image ref metadata
113 var imageRef = new ImageRef(imageTag, Utils.readAll(iidFile));
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 }
@@ -7,13 +7,12 import org.gradle.api.provider.Property;
7 import org.gradle.api.tasks.Input;
7 import org.gradle.api.tasks.Input;
8 import org.gradle.api.tasks.Optional;
8 import org.gradle.api.tasks.Optional;
9 import org.gradle.api.tasks.TaskAction;
9 import org.gradle.api.tasks.TaskAction;
10 import org.implab.gradle.containers.cli.ImageName;
11 import org.implab.gradle.containers.dsl.OptionsMixin;
10 import org.implab.gradle.containers.dsl.OptionsMixin;
12
11
13 public abstract class PushImage extends DockerCliTask implements OptionsMixin {
12 public abstract class PushImage extends DockerCliTask implements OptionsMixin {
14
13
15 @Input
14 @Input
16 public abstract Property<ImageName> getImageName();
15 public abstract Property<String> getImageName();
17
16
18 @Input
17 @Input
19 @Optional
18 @Optional
@@ -27,7 +26,7 public abstract class PushImage extends
27 public void run() throws InterruptedException, IOException {
26 public void run() throws InterruptedException, IOException {
28
27
29 docker().pushImage(
28 docker().pushImage(
30 getImageName().get().toString(),
29 getImageName().get(),
31 getOptions().get());
30 getOptions().get());
32 }
31 }
33 }
32 }
@@ -6,14 +6,13 import org.gradle.api.provider.ListPrope
6 import org.gradle.api.provider.Property;
6 import org.gradle.api.provider.Property;
7 import org.gradle.api.tasks.Input;
7 import org.gradle.api.tasks.Input;
8 import org.gradle.api.tasks.Optional;
8 import org.gradle.api.tasks.Optional;
9 import org.implab.gradle.containers.cli.ImageName;
10 import org.implab.gradle.containers.dsl.OptionsMixin;
9 import org.implab.gradle.containers.dsl.OptionsMixin;
11 import org.implab.gradle.containers.dsl.VolumeSpec;
10 import org.implab.gradle.containers.dsl.VolumeSpec;
12
11
13 public abstract class RunImage extends DockerCliTask implements OptionsMixin {
12 public abstract class RunImage extends DockerCliTask implements OptionsMixin {
14
13
15 @Input
14 @Input
16 public abstract Property<ImageName> getImageName();
15 public abstract Property<String> getImageName();
17
16
18 @Input
17 @Input
19 @Optional
18 @Optional
@@ -35,7 +34,7 public abstract class RunImage extends D
35
34
36 public void run() throws InterruptedException, IOException {
35 public void run() throws InterruptedException, IOException {
37 docker().runImage(
36 docker().runImage(
38 getImageName().get().toString(),
37 getImageName().get(),
39 getOptions().get(),
38 getOptions().get(),
40 getCommandLine().get());
39 getCommandLine().get());
41 }
40 }
@@ -4,19 +4,18 import java.io.IOException;
4 import org.gradle.api.provider.Property;
4 import org.gradle.api.provider.Property;
5 import org.gradle.api.tasks.Input;
5 import org.gradle.api.tasks.Input;
6 import org.gradle.api.tasks.TaskAction;
6 import org.gradle.api.tasks.TaskAction;
7 import org.implab.gradle.containers.cli.ImageName;
8
7
9 public abstract class TagImage extends DockerCliTask {
8 public abstract class TagImage extends DockerCliTask {
10 @Input
9 @Input
11 public abstract Property<ImageName> getSrcImage();
10 public abstract Property<String> getSrcImage();
12
11
13 @Input
12 @Input
14 public abstract Property<ImageName> getDestImage();
13 public abstract Property<String> getDestImage();
15
14
16 @TaskAction
15 @TaskAction
17 public void run() throws InterruptedException, IOException {
16 public void run() throws InterruptedException, IOException {
18 docker().tagImage(
17 docker().tagImage(
19 getSrcImage().map(ImageName::toString).get(),
18 getSrcImage().get(),
20 getDestImage().map(ImageName::toString).get());
19 getDestImage().get());
21 }
20 }
22 }
21 }
General Comments 0
You need to be logged in to leave comments. Login now