|
1 | 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 |
@@ -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