1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 |
@@ -0,0 +1,34 | |||||
|
1 | plugins { | |||
|
2 | id "java-gradle-plugin" | |||
|
3 | id "com.gradle.plugin-publish" version "0.15.0" | |||
|
4 | } | |||
|
5 | ||||
|
6 | ||||
|
7 | repositories { | |||
|
8 | mavenCentral() | |||
|
9 | } | |||
|
10 | ||||
|
11 | gradlePlugin { | |||
|
12 | website = 'https://code.implab.org/implab/gradle-container-plugin' | |||
|
13 | vcsUrl = 'https://code.implab.org/implab/gradle-container-plugin' | |||
|
14 | ||||
|
15 | plugins { | |||
|
16 | containerPlugin { | |||
|
17 | id = 'org.implab.gradle-container' | |||
|
18 | implementationClass = 'org.implab.gradle.containers.ContainerPlugin' | |||
|
19 | } | |||
|
20 | } | |||
|
21 | } | |||
|
22 | ||||
|
23 | pluginBundle { | |||
|
24 | website = 'https://code.implab.org/implab/gradle-container-plugin' | |||
|
25 | vcsUrl = 'https://code.implab.org/implab/gradle-container-plugin' | |||
|
26 | ||||
|
27 | tags = ['containers', 'image', 'docker', 'podman'] | |||
|
28 | ||||
|
29 | plugins { | |||
|
30 | containerPlugin { | |||
|
31 | description = 'Build and publish container images with docker or podman' | |||
|
32 | } | |||
|
33 | } | |||
|
34 | } |
@@ -0,0 +1,89 | |||||
|
1 | package org.implab.gradle; | |||
|
2 | ||||
|
3 | import java.io.ByteArrayOutputStream; | |||
|
4 | import java.io.Closeable; | |||
|
5 | import java.io.File; | |||
|
6 | import java.io.FileOutputStream; | |||
|
7 | import java.io.IOException; | |||
|
8 | import java.io.InputStream; | |||
|
9 | import java.io.OutputStream; | |||
|
10 | import java.util.Scanner; | |||
|
11 | ||||
|
12 | import org.gradle.api.Action; | |||
|
13 | import groovy.json.JsonGenerator; | |||
|
14 | import groovy.json.JsonOutput; | |||
|
15 | import groovy.json.JsonGenerator.Converter; | |||
|
16 | import groovy.lang.Closure; | |||
|
17 | ||||
|
18 | public final class Utils { | |||
|
19 | public static void redirectIO(final InputStream src, final Action<String> consumer) { | |||
|
20 | new Thread(() -> { | |||
|
21 | try (Scanner sc = new Scanner(src)) { | |||
|
22 | while (sc.hasNextLine()) { | |||
|
23 | consumer.execute(sc.nextLine()); | |||
|
24 | } | |||
|
25 | } | |||
|
26 | }).start(); | |||
|
27 | } | |||
|
28 | ||||
|
29 | public static void redirectIO(final InputStream src, final File file) { | |||
|
30 | new Thread(() -> { | |||
|
31 | try (OutputStream out = new FileOutputStream(file)) { | |||
|
32 | src.transferTo(out); | |||
|
33 | } catch(Exception e) { | |||
|
34 | // silence! | |||
|
35 | } | |||
|
36 | }).start(); | |||
|
37 | } | |||
|
38 | ||||
|
39 | public static String readAll(final InputStream src) throws IOException { | |||
|
40 | ByteArrayOutputStream out = new ByteArrayOutputStream(); | |||
|
41 | src.transferTo(out); | |||
|
42 | return out.toString(); | |||
|
43 | } | |||
|
44 | ||||
|
45 | public static String readAll(final InputStream src, String charset) throws IOException { | |||
|
46 | ByteArrayOutputStream out = new ByteArrayOutputStream(); | |||
|
47 | src.transferTo(out); | |||
|
48 | return out.toString(charset); | |||
|
49 | } | |||
|
50 | ||||
|
51 | public static JsonGenerator createDefaultJsonGenerator() { | |||
|
52 | return new JsonGenerator.Options() | |||
|
53 | .excludeNulls() | |||
|
54 | .addConverter(new Converter() { | |||
|
55 | public boolean handles(Class<?> type) { | |||
|
56 | return (File.class == type); | |||
|
57 | } | |||
|
58 | public Object convert(Object value, String key) { | |||
|
59 | return ((File)value).getPath(); | |||
|
60 | } | |||
|
61 | }) | |||
|
62 | .build(); | |||
|
63 | } | |||
|
64 | ||||
|
65 | public static void closeSilent(Closeable handle) { | |||
|
66 | try { | |||
|
67 | handle.close(); | |||
|
68 | } catch(Exception e) { | |||
|
69 | // silence! | |||
|
70 | } | |||
|
71 | } | |||
|
72 | ||||
|
73 | public static String toJsonPretty(Object value) { | |||
|
74 | return JsonOutput.prettyPrint(createDefaultJsonGenerator().toJson(value)); | |||
|
75 | } | |||
|
76 | ||||
|
77 | public static boolean isNullOrEmptyString(String value) { | |||
|
78 | return (value == null || value.length() == 0); | |||
|
79 | } | |||
|
80 | ||||
|
81 | public static <T> Action<T> wrapClosure(Closure<?> closure) { | |||
|
82 | return x -> { | |||
|
83 | closure.setDelegate(x); | |||
|
84 | closure.setResolveStrategy(Closure.DELEGATE_FIRST); | |||
|
85 | closure.call(x); | |||
|
86 | }; | |||
|
87 | } | |||
|
88 | ||||
|
89 | } |
@@ -0,0 +1,58 | |||||
|
1 | package org.implab.gradle.containers; | |||
|
2 | ||||
|
3 | import org.gradle.api.file.DirectoryProperty; | |||
|
4 | import org.gradle.api.file.ProjectLayout; | |||
|
5 | import org.gradle.api.file.RegularFileProperty; | |||
|
6 | import org.gradle.api.model.ObjectFactory; | |||
|
7 | import org.gradle.api.provider.Property; | |||
|
8 | ||||
|
9 | public class ContainerExtension { | |||
|
10 | ||||
|
11 | private final Property<String> cliCmd; | |||
|
12 | ||||
|
13 | private final Property<String> imageAuthority; | |||
|
14 | ||||
|
15 | private final Property<String> imageGroup; | |||
|
16 | ||||
|
17 | private final DirectoryProperty contextDir; | |||
|
18 | ||||
|
19 | private final RegularFileProperty imageIdFile; | |||
|
20 | ||||
|
21 | public ContainerExtension(ObjectFactory factory, ProjectLayout layout) { | |||
|
22 | contextDir = factory.directoryProperty(); | |||
|
23 | contextDir.convention(layout.getBuildDirectory().dir("context")); | |||
|
24 | ||||
|
25 | imageIdFile = factory.fileProperty(); | |||
|
26 | imageIdFile.convention(layout.getBuildDirectory().file("imageId")); | |||
|
27 | ||||
|
28 | cliCmd = factory.property(String.class); | |||
|
29 | cliCmd.set("docker"); | |||
|
30 | ||||
|
31 | imageAuthority = factory.property(String.class); | |||
|
32 | imageGroup = factory.property(String.class); | |||
|
33 | } | |||
|
34 | ||||
|
35 | public Property<String> getCliCmd() { | |||
|
36 | return cliCmd; | |||
|
37 | } | |||
|
38 | ||||
|
39 | public void setCliCmd(String cliCmd) { | |||
|
40 | this.cliCmd.set(cliCmd); | |||
|
41 | } | |||
|
42 | ||||
|
43 | public DirectoryProperty getContextDirectory() { | |||
|
44 | return contextDir; | |||
|
45 | } | |||
|
46 | ||||
|
47 | public RegularFileProperty getImageIdFile() { | |||
|
48 | return imageIdFile; | |||
|
49 | } | |||
|
50 | ||||
|
51 | public Property<String> getImageAuthority() { | |||
|
52 | return imageAuthority; | |||
|
53 | } | |||
|
54 | ||||
|
55 | public Property<String> getImageGroup() { | |||
|
56 | return imageGroup; | |||
|
57 | } | |||
|
58 | } No newline at end of file |
@@ -0,0 +1,102 | |||||
|
1 | package org.implab.gradle.containers; | |||
|
2 | ||||
|
3 | import java.util.Optional; | |||
|
4 | ||||
|
5 | import org.gradle.api.Plugin; | |||
|
6 | import org.gradle.api.Project; | |||
|
7 | import org.gradle.api.artifacts.Dependency; | |||
|
8 | import org.gradle.api.file.ProjectLayout; | |||
|
9 | import org.gradle.api.model.ObjectFactory; | |||
|
10 | import org.gradle.api.plugins.ExtraPropertiesExtension; | |||
|
11 | import org.gradle.api.provider.Provider; | |||
|
12 | import org.gradle.api.tasks.Copy; | |||
|
13 | import org.gradle.api.tasks.Delete; | |||
|
14 | import org.gradle.api.tasks.TaskProvider; | |||
|
15 | import org.implab.gradle.containers.tasks.BuildImage; | |||
|
16 | import org.implab.gradle.containers.tasks.PushImage; | |||
|
17 | import org.implab.gradle.containers.tasks.SaveImage; | |||
|
18 | ||||
|
19 | public class ContainerPlugin implements Plugin<Project> { | |||
|
20 | ||||
|
21 | public static final String BUILD_GROUP = "build"; | |||
|
22 | ||||
|
23 | public static final String CONTAINER_EXTENSION_NAME = "container"; | |||
|
24 | ||||
|
25 | public static final String ARCHIVE_CONFIGURATION = "archive"; | |||
|
26 | ||||
|
27 | private ContainerExtension containerExtension; | |||
|
28 | ||||
|
29 | public void apply(Project project) { | |||
|
30 | ObjectFactory factory = project.getObjects(); | |||
|
31 | ProjectLayout layout = project.getLayout(); | |||
|
32 | containerExtension = new ContainerExtension(factory, layout); | |||
|
33 | ||||
|
34 | containerExtension.getImageAuthority() | |||
|
35 | .convention(project.provider(() -> (String) project.getProperties().get("imagesAuthority"))); | |||
|
36 | ||||
|
37 | containerExtension.getImageGroup() | |||
|
38 | .convention(project.provider(() -> (String) project.getProperties().get("imagesGroup"))); | |||
|
39 | ||||
|
40 | project.getExtensions().add(CONTAINER_EXTENSION_NAME, containerExtension); | |||
|
41 | ||||
|
42 | ExtraPropertiesExtension extras = project.getExtensions().getExtraProperties(); | |||
|
43 | extras.set(BuildImage.class.getSimpleName(), BuildImage.class); | |||
|
44 | extras.set(PushImage.class.getSimpleName(), PushImage.class); | |||
|
45 | extras.set(SaveImage.class.getSimpleName(), SaveImage.class); | |||
|
46 | ||||
|
47 | project.getConfigurations().create(Dependency.DEFAULT_CONFIGURATION, c -> { | |||
|
48 | c.setCanBeConsumed(true); | |||
|
49 | c.setCanBeResolved(false); | |||
|
50 | }); | |||
|
51 | ||||
|
52 | project.getConfigurations().create(ARCHIVE_CONFIGURATION, c -> { | |||
|
53 | c.setCanBeConsumed(true); | |||
|
54 | c.setCanBeResolved(false); | |||
|
55 | }); | |||
|
56 | ||||
|
57 | TaskProvider<Copy> processResourcesTask = project.getTasks().register("processResources", Copy.class, t -> { | |||
|
58 | t.setGroup(BUILD_GROUP); | |||
|
59 | t.from(layout.getProjectDirectory().dir("src/main")); | |||
|
60 | t.into(containerExtension.getContextDirectory()); | |||
|
61 | }); | |||
|
62 | ||||
|
63 | TaskProvider<BuildImage> buildImageTask = project.getTasks().register("buildImage", BuildImage.class, t -> { | |||
|
64 | t.setGroup(BUILD_GROUP); | |||
|
65 | t.dependsOn(processResourcesTask); | |||
|
66 | ||||
|
67 | t.getContextDirectory().set(containerExtension.getContextDirectory()); | |||
|
68 | t.getImageIdFile().set(containerExtension.getImageIdFile()); | |||
|
69 | ||||
|
70 | Provider<String> imageName = containerExtension.getImageGroup().map(g -> g + "/" + project.getName()) | |||
|
71 | .orElse(project.getName()); | |||
|
72 | ||||
|
73 | t.getImageAuthority().set(containerExtension.getImageAuthority()); | |||
|
74 | t.getImageQName().convention(imageName); | |||
|
75 | t.getImageVersion() | |||
|
76 | .convention(Optional.ofNullable(project.getVersion()).map(v -> v.toString()).orElse("latest")); | |||
|
77 | }); | |||
|
78 | ||||
|
79 | project.getTasks().register("clean", Delete.class, t -> { | |||
|
80 | t.delete(layout.getBuildDirectory()); | |||
|
81 | }); | |||
|
82 | ||||
|
83 | project.getTasks().register("build", t -> { | |||
|
84 | t.setGroup(BUILD_GROUP); | |||
|
85 | t.dependsOn(buildImageTask); | |||
|
86 | }); | |||
|
87 | ||||
|
88 | project.getTasks().register("pushImage", PushImage.class, t -> { | |||
|
89 | t.dependsOn(buildImageTask); | |||
|
90 | t.getSrcImage().set(buildImageTask.flatMap(b -> b.getImageTag())); | |||
|
91 | }); | |||
|
92 | ||||
|
93 | project.getTasks().register("saveImage", SaveImage.class, t -> { | |||
|
94 | t.dependsOn(buildImageTask); | |||
|
95 | t.getImage().set(buildImageTask.flatMap(b -> b.getImageTag())); | |||
|
96 | }); | |||
|
97 | ||||
|
98 | project.getArtifacts().add(Dependency.DEFAULT_CONFIGURATION, buildImageTask.flatMap(x -> x.getImageIdFile()), t -> { | |||
|
99 | t.builtBy(buildImageTask); | |||
|
100 | }); | |||
|
101 | } | |||
|
102 | } |
@@ -0,0 +1,74 | |||||
|
1 | package org.implab.gradle.containers; | |||
|
2 | ||||
|
3 | import java.io.Serializable; | |||
|
4 | import java.util.Optional; | |||
|
5 | ||||
|
6 | public class ImageTag implements Serializable { | |||
|
7 | ||||
|
8 | private static final long serialVersionUID = -1990105923537254552L; | |||
|
9 | ||||
|
10 | String authority; | |||
|
11 | ||||
|
12 | String qName; | |||
|
13 | ||||
|
14 | String version; | |||
|
15 | ||||
|
16 | public ImageTag() { | |||
|
17 | } | |||
|
18 | ||||
|
19 | public ImageTag(ImageTag base) { | |||
|
20 | authority = base.authority; | |||
|
21 | qName = base.qName; | |||
|
22 | version = base.version; | |||
|
23 | } | |||
|
24 | ||||
|
25 | public String getAuthority() { | |||
|
26 | return authority; | |||
|
27 | } | |||
|
28 | ||||
|
29 | public void setAuthority(String authority) { | |||
|
30 | this.authority = authority; | |||
|
31 | } | |||
|
32 | ||||
|
33 | public ImageTag authority(String authority) { | |||
|
34 | this.authority = authority; | |||
|
35 | return this; | |||
|
36 | } | |||
|
37 | ||||
|
38 | public String getQName() { | |||
|
39 | return qName; | |||
|
40 | } | |||
|
41 | ||||
|
42 | public void setQName(String qName) { | |||
|
43 | this.qName = qName; | |||
|
44 | } | |||
|
45 | ||||
|
46 | public ImageTag qName(String qName) { | |||
|
47 | this.qName = qName; | |||
|
48 | return this; | |||
|
49 | } | |||
|
50 | ||||
|
51 | public String getVersion() { | |||
|
52 | return version; | |||
|
53 | } | |||
|
54 | ||||
|
55 | public void setVersion(String version) { | |||
|
56 | this.version = version; | |||
|
57 | } | |||
|
58 | ||||
|
59 | public ImageTag version(String version) { | |||
|
60 | this.version = version; | |||
|
61 | return this; | |||
|
62 | } | |||
|
63 | ||||
|
64 | @Override | |||
|
65 | public String toString() { | |||
|
66 | StringBuilder sb = new StringBuilder(); | |||
|
67 | ||||
|
68 | Optional.ofNullable(authority).ifPresent(s -> sb.append(s).append("/")); | |||
|
69 | Optional.ofNullable(qName).ifPresent(s -> sb.append(s)); | |||
|
70 | Optional.ofNullable(version).ifPresent(s-> sb.append(":").append(s)); | |||
|
71 | ||||
|
72 | return sb.toString(); | |||
|
73 | } | |||
|
74 | } |
@@ -0,0 +1,62 | |||||
|
1 | package org.implab.gradle.containers.tasks; | |||
|
2 | ||||
|
3 | import java.util.List; | |||
|
4 | ||||
|
5 | import org.gradle.api.file.DirectoryProperty; | |||
|
6 | import org.gradle.api.file.RegularFileProperty; | |||
|
7 | import org.gradle.api.provider.Property; | |||
|
8 | import org.gradle.api.provider.Provider; | |||
|
9 | import org.gradle.api.tasks.Input; | |||
|
10 | import org.gradle.api.tasks.InputDirectory; | |||
|
11 | import org.gradle.api.tasks.Internal; | |||
|
12 | import org.gradle.api.tasks.OutputFile; | |||
|
13 | import org.gradle.api.tasks.SkipWhenEmpty; | |||
|
14 | import org.implab.gradle.Utils; | |||
|
15 | import org.implab.gradle.containers.ImageTag; | |||
|
16 | ||||
|
17 | public abstract class BuildImage extends CliTask { | |||
|
18 | @InputDirectory | |||
|
19 | @SkipWhenEmpty | |||
|
20 | public abstract DirectoryProperty getContextDirectory(); | |||
|
21 | ||||
|
22 | @Internal | |||
|
23 | public abstract Property<String> getImageQName(); | |||
|
24 | ||||
|
25 | @Internal | |||
|
26 | public abstract Property<String> getImageVersion(); | |||
|
27 | ||||
|
28 | @Internal | |||
|
29 | public abstract Property<String> getImageAuthority(); | |||
|
30 | ||||
|
31 | @Input | |||
|
32 | public Provider<ImageTag> getImageTag() { | |||
|
33 | return getProject().provider(() -> { | |||
|
34 | ImageTag tag = new ImageTag(); | |||
|
35 | tag.setQName(getImageQName().getOrNull()); | |||
|
36 | tag.setAuthority(getImageAuthority().getOrNull()); | |||
|
37 | tag.setVersion(getImageVersion().getOrNull()); | |||
|
38 | return tag; | |||
|
39 | }); | |||
|
40 | } | |||
|
41 | ||||
|
42 | @OutputFile | |||
|
43 | public abstract RegularFileProperty getImageIdFile(); | |||
|
44 | ||||
|
45 | public BuildImage() { | |||
|
46 | ||||
|
47 | setWorkingDir(getContextDirectory().getAsFile()); | |||
|
48 | } | |||
|
49 | ||||
|
50 | @Override | |||
|
51 | protected void preparingCommand(List<String> commandLine) { | |||
|
52 | super.preparingCommand(commandLine); | |||
|
53 | ||||
|
54 | commandLine.addAll(List.of("build", ".", "-q", "-t")); | |||
|
55 | commandLine.add(getImageTag().get().toString()); | |||
|
56 | } | |||
|
57 | ||||
|
58 | @Override | |||
|
59 | protected void processStarted(Process p) { | |||
|
60 | Utils.redirectIO(p.getInputStream(), getImageIdFile().get().getAsFile()); | |||
|
61 | } | |||
|
62 | } |
@@ -0,0 +1,93 | |||||
|
1 | package org.implab.gradle.containers.tasks; | |||
|
2 | ||||
|
3 | import java.io.File; | |||
|
4 | import java.util.ArrayList; | |||
|
5 | import java.util.List; | |||
|
6 | ||||
|
7 | import org.gradle.api.DefaultTask; | |||
|
8 | import org.gradle.api.logging.Logger; | |||
|
9 | import org.gradle.api.provider.Property; | |||
|
10 | import org.gradle.api.provider.Provider; | |||
|
11 | import org.gradle.api.tasks.Input; | |||
|
12 | import org.gradle.api.tasks.Internal; | |||
|
13 | import org.gradle.api.tasks.TaskAction; | |||
|
14 | import org.implab.gradle.Utils; | |||
|
15 | import org.implab.gradle.containers.ContainerExtension; | |||
|
16 | ||||
|
17 | public abstract class CliTask extends DefaultTask { | |||
|
18 | ||||
|
19 | private final Property<String> cliCmd; | |||
|
20 | ||||
|
21 | private final Property<File> workingDir; | |||
|
22 | ||||
|
23 | public CliTask() { | |||
|
24 | cliCmd = getProject().getObjects().property(String.class); | |||
|
25 | cliCmd.convention(getContainerExtension().getCliCmd()); | |||
|
26 | ||||
|
27 | workingDir = getProject().getObjects().property(File.class); | |||
|
28 | } | |||
|
29 | ||||
|
30 | @Input | |||
|
31 | public Property<String> getCliCmd() { | |||
|
32 | return cliCmd; | |||
|
33 | } | |||
|
34 | ||||
|
35 | public void setCliCmd(String cliCmd) { | |||
|
36 | this.cliCmd.set(cliCmd); | |||
|
37 | } | |||
|
38 | ||||
|
39 | @Internal | |||
|
40 | protected ContainerExtension getContainerExtension() { | |||
|
41 | return getProject().getExtensions().getByType(ContainerExtension.class); | |||
|
42 | } | |||
|
43 | ||||
|
44 | @TaskAction | |||
|
45 | public void Run() throws Exception { | |||
|
46 | final Logger log = getLogger(); | |||
|
47 | ||||
|
48 | List<String> args = new ArrayList<>(); | |||
|
49 | preparingCommand(args); | |||
|
50 | ||||
|
51 | ProcessBuilder builder = new ProcessBuilder(args); | |||
|
52 | if (workingDir.isPresent()) | |||
|
53 | builder.directory(workingDir.get()); | |||
|
54 | ||||
|
55 | log.info("Starting: {}", builder.command()); | |||
|
56 | ||||
|
57 | Process p = builder.start(); | |||
|
58 | ||||
|
59 | processStarted(p); | |||
|
60 | ||||
|
61 | if (log.isErrorEnabled()) { | |||
|
62 | Utils.redirectIO(p.getErrorStream(), log::error); | |||
|
63 | } | |||
|
64 | ||||
|
65 | int code = p.waitFor(); | |||
|
66 | if (code != 0) | |||
|
67 | throw new Exception("Process exited with the error: " + code); | |||
|
68 | } | |||
|
69 | ||||
|
70 | protected void preparingCommand(List<String> commandLine) { | |||
|
71 | commandLine.add(cliCmd.get()); | |||
|
72 | } | |||
|
73 | ||||
|
74 | protected void setWorkingDir(Provider<File> workingDir) { | |||
|
75 | this.workingDir.set(workingDir); | |||
|
76 | } | |||
|
77 | ||||
|
78 | protected void setWorkingDir(File workingDir) { | |||
|
79 | this.workingDir.set(workingDir); | |||
|
80 | } | |||
|
81 | ||||
|
82 | ||||
|
83 | /** Invoked after the process is started, can be used to handle the process output. | |||
|
84 | * | |||
|
85 | * Default implemetation redirects output to the logger as INFO messages. | |||
|
86 | * | |||
|
87 | * @param p The current process. | |||
|
88 | */ | |||
|
89 | protected void processStarted(Process p) { | |||
|
90 | final Logger log = getLogger(); | |||
|
91 | Utils.redirectIO(p.getInputStream(), log::info); | |||
|
92 | } | |||
|
93 | } |
@@ -0,0 +1,51 | |||||
|
1 | package org.implab.gradle.containers.tasks; | |||
|
2 | ||||
|
3 | import java.util.List; | |||
|
4 | import java.util.concurrent.Callable; | |||
|
5 | ||||
|
6 | import org.gradle.api.provider.ListProperty; | |||
|
7 | import org.gradle.api.provider.Property; | |||
|
8 | import org.gradle.api.provider.Provider; | |||
|
9 | import org.gradle.api.tasks.Input; | |||
|
10 | import org.gradle.api.tasks.Internal; | |||
|
11 | import org.gradle.api.tasks.Optional; | |||
|
12 | import org.implab.gradle.containers.ImageTag; | |||
|
13 | ||||
|
14 | public abstract class PushImage extends CliTask { | |||
|
15 | ||||
|
16 | @Input | |||
|
17 | public abstract Property<ImageTag> getSrcImage(); | |||
|
18 | ||||
|
19 | @Input | |||
|
20 | @Optional | |||
|
21 | public abstract Property<ImageTag> getDestImage(); | |||
|
22 | ||||
|
23 | @Input | |||
|
24 | @Optional | |||
|
25 | public abstract Property<String> getTransport(); | |||
|
26 | ||||
|
27 | @Input | |||
|
28 | @Optional | |||
|
29 | public abstract ListProperty<String> getOptions(); | |||
|
30 | ||||
|
31 | public PushImage option(Callable<String> provider) { | |||
|
32 | getOptions().add(getProject().provider(provider)); | |||
|
33 | return this; | |||
|
34 | } | |||
|
35 | ||||
|
36 | @Internal | |||
|
37 | public Provider<String> getDestination() { | |||
|
38 | return getDestImage().flatMap(tag -> getTransport().orElse("").map(t -> t + tag.toString())); | |||
|
39 | } | |||
|
40 | ||||
|
41 | @Override | |||
|
42 | protected void preparingCommand(List<String> commandLine) { | |||
|
43 | super.preparingCommand(commandLine); | |||
|
44 | ||||
|
45 | commandLine.add("push"); | |||
|
46 | commandLine.addAll(getOptions().get()); | |||
|
47 | commandLine.add(getSrcImage().get().toString()); | |||
|
48 | if (getDestination().isPresent()) | |||
|
49 | commandLine.add(getDestination().get()); | |||
|
50 | } | |||
|
51 | } |
@@ -0,0 +1,91 | |||||
|
1 | package org.implab.gradle.containers.tasks; | |||
|
2 | ||||
|
3 | import java.util.ArrayList; | |||
|
4 | import java.util.List; | |||
|
5 | import java.util.Optional; | |||
|
6 | ||||
|
7 | import org.gradle.api.file.DirectoryProperty; | |||
|
8 | import org.gradle.api.file.RegularFile; | |||
|
9 | import org.gradle.api.provider.Property; | |||
|
10 | import org.gradle.api.provider.Provider; | |||
|
11 | import org.gradle.api.tasks.Input; | |||
|
12 | import org.gradle.api.tasks.Internal; | |||
|
13 | import org.gradle.api.tasks.OutputFile; | |||
|
14 | import org.gradle.api.tasks.TaskExecutionException; | |||
|
15 | import org.implab.gradle.Utils; | |||
|
16 | import org.implab.gradle.containers.ImageTag; | |||
|
17 | ||||
|
18 | public abstract class SaveImage extends CliTask { | |||
|
19 | ||||
|
20 | @Input | |||
|
21 | public abstract Property<ImageTag> getImage(); | |||
|
22 | ||||
|
23 | @OutputFile | |||
|
24 | public Provider<RegularFile> getArchiveFile() { | |||
|
25 | return getDestinationDirectory().file(getArchiveFileName()); | |||
|
26 | } | |||
|
27 | ||||
|
28 | @Internal | |||
|
29 | public abstract DirectoryProperty getDestinationDirectory(); | |||
|
30 | ||||
|
31 | @Internal | |||
|
32 | public abstract Property<String> getArchiveFileName(); | |||
|
33 | ||||
|
34 | @Internal | |||
|
35 | public abstract Property<String> getArchiveBaseName(); | |||
|
36 | ||||
|
37 | @Internal | |||
|
38 | public abstract Property<String> getArchiveVersion(); | |||
|
39 | ||||
|
40 | @Internal | |||
|
41 | public abstract Property<String> getArchiveClassifier(); | |||
|
42 | ||||
|
43 | @Internal | |||
|
44 | public abstract Property<String> getArchiveExtension(); | |||
|
45 | ||||
|
46 | public SaveImage() { | |||
|
47 | getArchiveFileName().convention(getProject().provider(this::conventionalArchiveFileName)); | |||
|
48 | getArchiveBaseName().convention(getProject().provider(this::conventionalArchiveBaseName)); | |||
|
49 | getArchiveVersion().convention(getProject().provider(() -> getProject().getVersion()).map(x -> x.toString())); | |||
|
50 | getDestinationDirectory().convention(getProject().getLayout().getBuildDirectory()); | |||
|
51 | getArchiveExtension().convention("tar"); | |||
|
52 | } | |||
|
53 | ||||
|
54 | private String conventionalArchiveBaseName() { | |||
|
55 | ArrayList<String> parts = new ArrayList<>(); | |||
|
56 | Optional.of(getProject().getGroup()).map(x -> x.toString()).ifPresent(parts::add); | |||
|
57 | parts.add(getProject().getName()); | |||
|
58 | return String.join("-", parts); | |||
|
59 | } | |||
|
60 | ||||
|
61 | private String conventionalArchiveFileName() { | |||
|
62 | ArrayList<String> parts = new ArrayList<>(); | |||
|
63 | ||||
|
64 | if (getArchiveBaseName().isPresent()) | |||
|
65 | parts.add(getArchiveBaseName().get()); | |||
|
66 | ||||
|
67 | if (getArchiveVersion().isPresent()) | |||
|
68 | parts.add(getArchiveVersion().get()); | |||
|
69 | ||||
|
70 | if (getArchiveClassifier().isPresent()) | |||
|
71 | parts.add(getArchiveClassifier().get()); | |||
|
72 | ||||
|
73 | if (parts.size() == 0) | |||
|
74 | throw new TaskExecutionException(this, new Exception("The archiveFileName ism't specified")); | |||
|
75 | ||||
|
76 | return String.join("-", parts) + "." + getArchiveExtension().get(); | |||
|
77 | } | |||
|
78 | ||||
|
79 | @Override | |||
|
80 | protected void preparingCommand(List<String> commandLine) { | |||
|
81 | super.preparingCommand(commandLine); | |||
|
82 | ||||
|
83 | commandLine.add("save"); | |||
|
84 | commandLine.add(getImage().get().toString()); | |||
|
85 | } | |||
|
86 | ||||
|
87 | @Override | |||
|
88 | protected void processStarted(Process p) { | |||
|
89 | Utils.redirectIO(p.getInputStream(), getArchiveFile().get().getAsFile()); | |||
|
90 | } | |||
|
91 | } |
1 | NO CONTENT: new file 100644, binary diff hidden |
|
NO CONTENT: new file 100644, binary diff hidden |
@@ -0,0 +1,5 | |||||
|
1 | distributionBase=GRADLE_USER_HOME | |||
|
2 | distributionPath=wrapper/dists | |||
|
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip | |||
|
4 | zipStoreBase=GRADLE_USER_HOME | |||
|
5 | zipStorePath=wrapper/dists |
@@ -0,0 +1,183 | |||||
|
1 | #!/usr/bin/env sh | |||
|
2 | ||||
|
3 | # | |||
|
4 | # Copyright 2015 the original author or authors. | |||
|
5 | # | |||
|
6 | # Licensed under the Apache License, Version 2.0 (the "License"); | |||
|
7 | # you may not use this file except in compliance with the License. | |||
|
8 | # You may obtain a copy of the License at | |||
|
9 | # | |||
|
10 | # https://www.apache.org/licenses/LICENSE-2.0 | |||
|
11 | # | |||
|
12 | # Unless required by applicable law or agreed to in writing, software | |||
|
13 | # distributed under the License is distributed on an "AS IS" BASIS, | |||
|
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
|
15 | # See the License for the specific language governing permissions and | |||
|
16 | # limitations under the License. | |||
|
17 | # | |||
|
18 | ||||
|
19 | ############################################################################## | |||
|
20 | ## | |||
|
21 | ## Gradle start up script for UN*X | |||
|
22 | ## | |||
|
23 | ############################################################################## | |||
|
24 | ||||
|
25 | # Attempt to set APP_HOME | |||
|
26 | # Resolve links: $0 may be a link | |||
|
27 | PRG="$0" | |||
|
28 | # Need this for relative symlinks. | |||
|
29 | while [ -h "$PRG" ] ; do | |||
|
30 | ls=`ls -ld "$PRG"` | |||
|
31 | link=`expr "$ls" : '.*-> \(.*\)$'` | |||
|
32 | if expr "$link" : '/.*' > /dev/null; then | |||
|
33 | PRG="$link" | |||
|
34 | else | |||
|
35 | PRG=`dirname "$PRG"`"/$link" | |||
|
36 | fi | |||
|
37 | done | |||
|
38 | SAVED="`pwd`" | |||
|
39 | cd "`dirname \"$PRG\"`/" >/dev/null | |||
|
40 | APP_HOME="`pwd -P`" | |||
|
41 | cd "$SAVED" >/dev/null | |||
|
42 | ||||
|
43 | APP_NAME="Gradle" | |||
|
44 | APP_BASE_NAME=`basename "$0"` | |||
|
45 | ||||
|
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | |||
|
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' | |||
|
48 | ||||
|
49 | # Use the maximum available, or set MAX_FD != -1 to use that value. | |||
|
50 | MAX_FD="maximum" | |||
|
51 | ||||
|
52 | warn () { | |||
|
53 | echo "$*" | |||
|
54 | } | |||
|
55 | ||||
|
56 | die () { | |||
|
57 | echo | |||
|
58 | echo "$*" | |||
|
59 | echo | |||
|
60 | exit 1 | |||
|
61 | } | |||
|
62 | ||||
|
63 | # OS specific support (must be 'true' or 'false'). | |||
|
64 | cygwin=false | |||
|
65 | msys=false | |||
|
66 | darwin=false | |||
|
67 | nonstop=false | |||
|
68 | case "`uname`" in | |||
|
69 | CYGWIN* ) | |||
|
70 | cygwin=true | |||
|
71 | ;; | |||
|
72 | Darwin* ) | |||
|
73 | darwin=true | |||
|
74 | ;; | |||
|
75 | MINGW* ) | |||
|
76 | msys=true | |||
|
77 | ;; | |||
|
78 | NONSTOP* ) | |||
|
79 | nonstop=true | |||
|
80 | ;; | |||
|
81 | esac | |||
|
82 | ||||
|
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar | |||
|
84 | ||||
|
85 | # Determine the Java command to use to start the JVM. | |||
|
86 | if [ -n "$JAVA_HOME" ] ; then | |||
|
87 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then | |||
|
88 | # IBM's JDK on AIX uses strange locations for the executables | |||
|
89 | JAVACMD="$JAVA_HOME/jre/sh/java" | |||
|
90 | else | |||
|
91 | JAVACMD="$JAVA_HOME/bin/java" | |||
|
92 | fi | |||
|
93 | if [ ! -x "$JAVACMD" ] ; then | |||
|
94 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME | |||
|
95 | ||||
|
96 | Please set the JAVA_HOME variable in your environment to match the | |||
|
97 | location of your Java installation." | |||
|
98 | fi | |||
|
99 | else | |||
|
100 | JAVACMD="java" | |||
|
101 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | |||
|
102 | ||||
|
103 | Please set the JAVA_HOME variable in your environment to match the | |||
|
104 | location of your Java installation." | |||
|
105 | fi | |||
|
106 | ||||
|
107 | # Increase the maximum file descriptors if we can. | |||
|
108 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then | |||
|
109 | MAX_FD_LIMIT=`ulimit -H -n` | |||
|
110 | if [ $? -eq 0 ] ; then | |||
|
111 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then | |||
|
112 | MAX_FD="$MAX_FD_LIMIT" | |||
|
113 | fi | |||
|
114 | ulimit -n $MAX_FD | |||
|
115 | if [ $? -ne 0 ] ; then | |||
|
116 | warn "Could not set maximum file descriptor limit: $MAX_FD" | |||
|
117 | fi | |||
|
118 | else | |||
|
119 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" | |||
|
120 | fi | |||
|
121 | fi | |||
|
122 | ||||
|
123 | # For Darwin, add options to specify how the application appears in the dock | |||
|
124 | if $darwin; then | |||
|
125 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" | |||
|
126 | fi | |||
|
127 | ||||
|
128 | # For Cygwin or MSYS, switch paths to Windows format before running java | |||
|
129 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then | |||
|
130 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` | |||
|
131 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` | |||
|
132 | JAVACMD=`cygpath --unix "$JAVACMD"` | |||
|
133 | ||||
|
134 | # We build the pattern for arguments to be converted via cygpath | |||
|
135 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` | |||
|
136 | SEP="" | |||
|
137 | for dir in $ROOTDIRSRAW ; do | |||
|
138 | ROOTDIRS="$ROOTDIRS$SEP$dir" | |||
|
139 | SEP="|" | |||
|
140 | done | |||
|
141 | OURCYGPATTERN="(^($ROOTDIRS))" | |||
|
142 | # Add a user-defined pattern to the cygpath arguments | |||
|
143 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then | |||
|
144 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" | |||
|
145 | fi | |||
|
146 | # Now convert the arguments - kludge to limit ourselves to /bin/sh | |||
|
147 | i=0 | |||
|
148 | for arg in "$@" ; do | |||
|
149 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` | |||
|
150 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option | |||
|
151 | ||||
|
152 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition | |||
|
153 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` | |||
|
154 | else | |||
|
155 | eval `echo args$i`="\"$arg\"" | |||
|
156 | fi | |||
|
157 | i=`expr $i + 1` | |||
|
158 | done | |||
|
159 | case $i in | |||
|
160 | 0) set -- ;; | |||
|
161 | 1) set -- "$args0" ;; | |||
|
162 | 2) set -- "$args0" "$args1" ;; | |||
|
163 | 3) set -- "$args0" "$args1" "$args2" ;; | |||
|
164 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; | |||
|
165 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; | |||
|
166 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; | |||
|
167 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; | |||
|
168 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; | |||
|
169 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; | |||
|
170 | esac | |||
|
171 | fi | |||
|
172 | ||||
|
173 | # Escape application args | |||
|
174 | save () { | |||
|
175 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done | |||
|
176 | echo " " | |||
|
177 | } | |||
|
178 | APP_ARGS=`save "$@"` | |||
|
179 | ||||
|
180 | # Collect all arguments for the java command, following the shell quoting and substitution rules | |||
|
181 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" | |||
|
182 | ||||
|
183 | exec "$JAVACMD" "$@" |
@@ -0,0 +1,100 | |||||
|
1 | @rem | |||
|
2 | @rem Copyright 2015 the original author or authors. | |||
|
3 | @rem | |||
|
4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); | |||
|
5 | @rem you may not use this file except in compliance with the License. | |||
|
6 | @rem You may obtain a copy of the License at | |||
|
7 | @rem | |||
|
8 | @rem https://www.apache.org/licenses/LICENSE-2.0 | |||
|
9 | @rem | |||
|
10 | @rem Unless required by applicable law or agreed to in writing, software | |||
|
11 | @rem distributed under the License is distributed on an "AS IS" BASIS, | |||
|
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
|
13 | @rem See the License for the specific language governing permissions and | |||
|
14 | @rem limitations under the License. | |||
|
15 | @rem | |||
|
16 | ||||
|
17 | @if "%DEBUG%" == "" @echo off | |||
|
18 | @rem ########################################################################## | |||
|
19 | @rem | |||
|
20 | @rem Gradle startup script for Windows | |||
|
21 | @rem | |||
|
22 | @rem ########################################################################## | |||
|
23 | ||||
|
24 | @rem Set local scope for the variables with windows NT shell | |||
|
25 | if "%OS%"=="Windows_NT" setlocal | |||
|
26 | ||||
|
27 | set DIRNAME=%~dp0 | |||
|
28 | if "%DIRNAME%" == "" set DIRNAME=. | |||
|
29 | set APP_BASE_NAME=%~n0 | |||
|
30 | set APP_HOME=%DIRNAME% | |||
|
31 | ||||
|
32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | |||
|
33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" | |||
|
34 | ||||
|
35 | @rem Find java.exe | |||
|
36 | if defined JAVA_HOME goto findJavaFromJavaHome | |||
|
37 | ||||
|
38 | set JAVA_EXE=java.exe | |||
|
39 | %JAVA_EXE% -version >NUL 2>&1 | |||
|
40 | if "%ERRORLEVEL%" == "0" goto init | |||
|
41 | ||||
|
42 | echo. | |||
|
43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | |||
|
44 | echo. | |||
|
45 | echo Please set the JAVA_HOME variable in your environment to match the | |||
|
46 | echo location of your Java installation. | |||
|
47 | ||||
|
48 | goto fail | |||
|
49 | ||||
|
50 | :findJavaFromJavaHome | |||
|
51 | set JAVA_HOME=%JAVA_HOME:"=% | |||
|
52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe | |||
|
53 | ||||
|
54 | if exist "%JAVA_EXE%" goto init | |||
|
55 | ||||
|
56 | echo. | |||
|
57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% | |||
|
58 | echo. | |||
|
59 | echo Please set the JAVA_HOME variable in your environment to match the | |||
|
60 | echo location of your Java installation. | |||
|
61 | ||||
|
62 | goto fail | |||
|
63 | ||||
|
64 | :init | |||
|
65 | @rem Get command-line arguments, handling Windows variants | |||
|
66 | ||||
|
67 | if not "%OS%" == "Windows_NT" goto win9xME_args | |||
|
68 | ||||
|
69 | :win9xME_args | |||
|
70 | @rem Slurp the command line arguments. | |||
|
71 | set CMD_LINE_ARGS= | |||
|
72 | set _SKIP=2 | |||
|
73 | ||||
|
74 | :win9xME_args_slurp | |||
|
75 | if "x%~1" == "x" goto execute | |||
|
76 | ||||
|
77 | set CMD_LINE_ARGS=%* | |||
|
78 | ||||
|
79 | :execute | |||
|
80 | @rem Setup the command line | |||
|
81 | ||||
|
82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar | |||
|
83 | ||||
|
84 | @rem Execute Gradle | |||
|
85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% | |||
|
86 | ||||
|
87 | :end | |||
|
88 | @rem End local scope for the variables with windows NT shell | |||
|
89 | if "%ERRORLEVEL%"=="0" goto mainEnd | |||
|
90 | ||||
|
91 | :fail | |||
|
92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of | |||
|
93 | rem the _cmd.exe /c_ return code! | |||
|
94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 | |||
|
95 | exit /b 1 | |||
|
96 | ||||
|
97 | :mainEnd | |||
|
98 | if "%OS%"=="Windows_NT" endlocal | |||
|
99 | ||||
|
100 | :omega |
@@ -0,0 +1,13 | |||||
|
1 | /* | |||
|
2 | * This settings file was generated by the Gradle 'init' task. | |||
|
3 | * | |||
|
4 | * The settings file is used to specify which projects to include in your build. | |||
|
5 | * In a single project build this file can be empty or even removed. | |||
|
6 | * | |||
|
7 | * Detailed information about configuring a multi-project build in Gradle can be found | |||
|
8 | * in the user guide at https://docs.gradle.org/3.5/userguide/multi_project_builds.html | |||
|
9 | */ | |||
|
10 | ||||
|
11 | rootProject.name = 'plugins' | |||
|
12 | ||||
|
13 | include 'container' |
General Comments 0
You need to be logged in to leave comments.
Login now