##// END OF EJS Templates
WIP docker compose support
cin -
r11:cf3a5b9d59a9 default
parent child
Show More
@@ -38,6 +38,14 gradlePlugin {
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
@@ -9,10 +9,10 import org.implab.gradle.containers.task
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)
@@ -37,13 +37,17 public class ContainerBasePlugin impleme
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 }
@@ -10,21 +10,18 import javax.inject.Inject;
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}
@@ -36,7 +33,9 public abstract class ContainerExtension
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}
@@ -57,25 +56,19 public abstract class ContainerExtension
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 {
@@ -19,8 +19,6 public class ContainerPlugin implements
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
@@ -53,9 +51,9 public class ContainerPlugin implements
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 -> {
@@ -74,7 +72,7 public class ContainerPlugin implements
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);
@@ -2,7 +2,6 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;
@@ -1,6 +1,7
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;
@@ -12,60 +13,71 public class ImageName implements Serial
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 }
@@ -22,7 +22,6 import org.gradle.api.tasks.SkipWhenEmpt
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;
@@ -31,6 +30,7 import org.implab.gradle.containers.dsl.
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();
@@ -43,7 +43,7 public abstract class BuildImage extends
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();
@@ -101,7 +101,7 public abstract class BuildImage extends
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(
@@ -111,6 +111,6 public abstract class BuildImage extends
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 }
@@ -7,13 +7,12 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
@@ -27,7 +26,7 public abstract class PushImage extends
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 }
@@ -6,14 +6,13 import org.gradle.api.provider.ListPrope
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
@@ -35,7 +34,7 public abstract class RunImage extends D
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 }
@@ -4,19 +4,18 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