diff --git a/build.gradle b/build.gradle --- a/build.gradle +++ b/build.gradle @@ -0,0 +1,7 @@ +subprojects { p -> + plugins.withId('java') { + p.base { + archivesBaseName = "$rootProject.name-$p.name"; + } + } +} \ No newline at end of file diff --git a/container/build.gradle b/container/build.gradle --- a/container/build.gradle +++ b/container/build.gradle @@ -1,6 +1,8 @@ plugins { id "java-gradle-plugin" - id "com.gradle.plugin-publish" version "0.16.0" + id "com.gradle.plugin-publish" version "1.2.1" + // Maven Publish Plugin applied by com.gradle.plugin-publish > 1.0 + id "ivy-publish" } @@ -9,19 +11,30 @@ repositories { } gradlePlugin { + website = 'https://code.implab.org/implab/gradle-container-plugin' + vcsUrl = 'https://code.implab.org/implab/gradle-container-plugin' plugins { containerPlugin { id = 'org.implab.gradle-container' displayName = "Container building plugin" description = 'Build and publish container images with docker or podman. Simple wrapper around cli.' implementationClass = 'org.implab.gradle.containers.ContainerPlugin' + tags.set(['containers', 'image', 'docker', 'podman']) } } } -pluginBundle { - website = 'https://code.implab.org/implab/gradle-container-plugin' - vcsUrl = 'https://code.implab.org/implab/gradle-container-plugin' + +task printVersion { + doLast { + println "${->jar.archiveFileName.get()}" + } +} - tags = ['containers', 'image', 'docker', 'podman'] +publishing { + repositories { + ivy { + url "${System.properties["user.home"]}/ivy-repo" + } + } } diff --git a/container/gradle.properties b/container/gradle.properties --- a/container/gradle.properties +++ b/container/gradle.properties @@ -1,2 +1,2 @@ group=org.implab.gradle -version=1.1.1 \ No newline at end of file +version=1.1.2 \ No newline at end of file diff --git a/container/src/main/java/org/implab/gradle/Utils.java b/container/src/main/java/org/implab/gradle/Utils.java deleted file mode 100644 --- a/container/src/main/java/org/implab/gradle/Utils.java +++ /dev/null @@ -1,89 +0,0 @@ -package org.implab.gradle; - -import java.io.ByteArrayOutputStream; -import java.io.Closeable; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Scanner; - -import org.gradle.api.Action; -import groovy.json.JsonGenerator; -import groovy.json.JsonOutput; -import groovy.json.JsonGenerator.Converter; -import groovy.lang.Closure; - -public final class Utils { - public static void redirectIO(final InputStream src, final Action consumer) { - new Thread(() -> { - try (Scanner sc = new Scanner(src)) { - while (sc.hasNextLine()) { - consumer.execute(sc.nextLine()); - } - } - }).start(); - } - - public static void redirectIO(final InputStream src, final File file) { - new Thread(() -> { - try (OutputStream out = new FileOutputStream(file)) { - src.transferTo(out); - } catch(Exception e) { - // silence! - } - }).start(); - } - - public static String readAll(final InputStream src) throws IOException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - src.transferTo(out); - return out.toString(); - } - - public static String readAll(final InputStream src, String charset) throws IOException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - src.transferTo(out); - return out.toString(charset); - } - - public static JsonGenerator createDefaultJsonGenerator() { - return new JsonGenerator.Options() - .excludeNulls() - .addConverter(new Converter() { - public boolean handles(Class type) { - return (File.class == type); - } - public Object convert(Object value, String key) { - return ((File)value).getPath(); - } - }) - .build(); - } - - public static void closeSilent(Closeable handle) { - try { - handle.close(); - } catch(Exception e) { - // silence! - } - } - - public static String toJsonPretty(Object value) { - return JsonOutput.prettyPrint(createDefaultJsonGenerator().toJson(value)); - } - - public static boolean isNullOrEmptyString(String value) { - return (value == null || value.length() == 0); - } - - public static Action wrapClosure(Closure closure) { - return x -> { - closure.setDelegate(x); - closure.setResolveStrategy(Closure.DELEGATE_FIRST); - closure.call(x); - }; - } - -} diff --git a/container/src/main/java/org/implab/gradle/containers/ContainerPlugin.java b/container/src/main/java/org/implab/gradle/containers/ContainerPlugin.java --- a/container/src/main/java/org/implab/gradle/containers/ContainerPlugin.java +++ b/container/src/main/java/org/implab/gradle/containers/ContainerPlugin.java @@ -11,6 +11,7 @@ import org.gradle.api.tasks.Delete; import org.gradle.api.tasks.TaskProvider; import org.implab.gradle.containers.tasks.BuildImage; import org.implab.gradle.containers.tasks.PushImage; +import org.implab.gradle.containers.tasks.RunImage; import org.implab.gradle.containers.tasks.SaveImage; import org.implab.gradle.containers.tasks.TagImage; @@ -24,6 +25,12 @@ public class ContainerPlugin implements private ContainerExtension containerExtension; + void exportClasses(Project project, Class... classes) { + ExtraPropertiesExtension extras = project.getExtensions().getExtraProperties(); + for (var clazz : classes) + extras.set(clazz.getSimpleName(), clazz); + } + public void apply(Project project) { ObjectFactory factory = project.getObjects(); ProjectLayout layout = project.getLayout(); @@ -37,11 +44,9 @@ public class ContainerPlugin implements project.getExtensions().add(CONTAINER_EXTENSION_NAME, containerExtension); - ExtraPropertiesExtension extras = project.getExtensions().getExtraProperties(); - extras.set(BuildImage.class.getSimpleName(), BuildImage.class); - extras.set(PushImage.class.getSimpleName(), PushImage.class); - extras.set(SaveImage.class.getSimpleName(), SaveImage.class); - extras.set(TagImage.class.getSimpleName(), TagImage.class); + exportClasses( + project, + BuildImage.class, PushImage.class, SaveImage.class, TagImage.class, RunImage.class); project.getConfigurations().create(Dependency.DEFAULT_CONFIGURATION, c -> { c.setCanBeConsumed(true); @@ -88,8 +93,9 @@ public class ContainerPlugin implements t.getImage().set(buildImageTask.flatMap(b -> b.getImageName())); }); - project.getArtifacts().add(Dependency.DEFAULT_CONFIGURATION, buildImageTask.flatMap(x -> x.getImageIdFile()), t -> { - t.builtBy(buildImageTask); - }); + project.getArtifacts().add(Dependency.DEFAULT_CONFIGURATION, buildImageTask.flatMap(x -> x.getImageIdFile()), + t -> { + t.builtBy(buildImageTask); + }); } } diff --git a/container/src/main/java/org/implab/gradle/containers/ExecuteMixin.java b/container/src/main/java/org/implab/gradle/containers/ExecuteMixin.java new file mode 100644 --- /dev/null +++ b/container/src/main/java/org/implab/gradle/containers/ExecuteMixin.java @@ -0,0 +1,57 @@ +package org.implab.gradle.containers; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import org.gradle.api.logging.Logger; + +public interface ExecuteMixin { + + Logger getLogger(); + + Optional getWorkingDir(); + + default void Execute() throws Exception { + final Logger log = getLogger(); + + List command = new ArrayList<>(); + + preparingCommand(command); + + ProcessBuilder builder = new ProcessBuilder(command); + getWorkingDir().ifPresent(workingDir -> builder.directory(workingDir)); + + log.info("Starting: {}", builder.command()); + + Process p = builder.start(); + + processStarted(p); + + if (log.isErrorEnabled()) { + Utils.redirectIO(p.getErrorStream(), log::error); + } + + int code = p.waitFor(); + if (code != 0) + throw new Exception("Process exited with the error: " + code); + } + + void preparingCommand(List command); + + + /** + * Invoked after the process is started, can be used to handle the process + * output. + * + * Default implementation redirects output to the logger as INFO messages. + * + * @param p The current process. + */ + + default void processStarted(Process p) { + final Logger log = getLogger(); + Utils.redirectIO(p.getInputStream(), log::info); + } +} diff --git a/container/src/main/java/org/implab/gradle/containers/PropertiesMixin.java b/container/src/main/java/org/implab/gradle/containers/PropertiesMixin.java new file mode 100644 --- /dev/null +++ b/container/src/main/java/org/implab/gradle/containers/PropertiesMixin.java @@ -0,0 +1,45 @@ +package org.implab.gradle.containers; + +import java.util.concurrent.Callable; + +import javax.inject.Inject; + +import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.model.ObjectFactory; +import org.gradle.api.provider.ListProperty; +import org.gradle.api.provider.Property; +import org.gradle.api.provider.Provider; +import org.gradle.api.provider.ProviderFactory; + +public interface PropertiesMixin { + @Inject + ObjectFactory getObjectFactory(); + + @Inject + ProviderFactory getProviders(); + + default Provider provider(Callable callable) { + return getProviders().provider(callable); + } + + default Property property(Class clazz) { + return getObjectFactory().property(clazz); + } + + default ListProperty listProperty(Class clazz) { + return getObjectFactory().listProperty(clazz); + } + + default RegularFileProperty fileProperty() { + return getObjectFactory().fileProperty(); + } + + default DirectoryProperty directoryProperty() { + return getObjectFactory().directoryProperty(); + } + + + + +} diff --git a/container/src/main/java/org/implab/gradle/containers/Utils.java b/container/src/main/java/org/implab/gradle/containers/Utils.java new file mode 100644 --- /dev/null +++ b/container/src/main/java/org/implab/gradle/containers/Utils.java @@ -0,0 +1,91 @@ +package org.implab.gradle.containers; + +import java.io.ByteArrayOutputStream; +import java.io.Closeable; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Scanner; + +import org.gradle.api.Action; + +import groovy.json.JsonGenerator; +import groovy.json.JsonOutput; +import groovy.json.JsonGenerator.Converter; +import groovy.lang.Closure; + +public final class Utils { + public static void redirectIO(final InputStream src, final Action consumer) { + new Thread(() -> { + try (Scanner sc = new Scanner(src)) { + while (sc.hasNextLine()) { + consumer.execute(sc.nextLine()); + } + } + }).start(); + } + + public static void redirectIO(final InputStream src, final File file) { + new Thread(() -> { + try (OutputStream out = new FileOutputStream(file)) { + src.transferTo(out); + } catch (Exception e) { + // silence! + } + }).start(); + } + + public static void closeSilent(Closeable handle) { + try { + handle.close(); + } catch (Exception e) { + // silence! + } + } + + public static String readAll(final InputStream src) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + src.transferTo(out); + return out.toString(); + } + + public static String readAll(final InputStream src, String charset) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + src.transferTo(out); + return out.toString(charset); + } + + public static JsonGenerator createDefaultJsonGenerator() { + return new JsonGenerator.Options() + .excludeNulls() + .addConverter(new Converter() { + public boolean handles(Class type) { + return (File.class == type); + } + + public Object convert(Object value, String key) { + return ((File) value).getPath(); + } + }) + .build(); + } + + public static String toJsonPretty(Object value) { + return JsonOutput.prettyPrint(createDefaultJsonGenerator().toJson(value)); + } + + public static boolean isNullOrEmptyString(String value) { + return (value == null || value.length() == 0); + } + + public static Action wrapClosure(Closure closure) { + return x -> { + closure.setDelegate(x); + closure.setResolveStrategy(Closure.DELEGATE_FIRST); + closure.call(x); + }; + } + +} \ No newline at end of file diff --git a/container/src/main/java/org/implab/gradle/containers/tasks/BuildImage.java b/container/src/main/java/org/implab/gradle/containers/tasks/BuildImage.java --- a/container/src/main/java/org/implab/gradle/containers/tasks/BuildImage.java +++ b/container/src/main/java/org/implab/gradle/containers/tasks/BuildImage.java @@ -1,43 +1,96 @@ package org.implab.gradle.containers.tasks; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Optional; +import org.gradle.api.Action; import org.gradle.api.file.DirectoryProperty; import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.provider.ListProperty; +import org.gradle.api.provider.MapProperty; import org.gradle.api.provider.Property; +import org.gradle.api.provider.Provider; import org.gradle.api.tasks.Input; import org.gradle.api.tasks.InputDirectory; import org.gradle.api.tasks.OutputFile; import org.gradle.api.tasks.SkipWhenEmpty; -import org.implab.gradle.Utils; import org.implab.gradle.containers.ImageName; +import org.implab.gradle.containers.Utils; -public abstract class BuildImage extends CliTask { +import groovy.lang.Closure; + +public abstract class BuildImage extends DockerCliTask { + + public final String BUILD_COMMAND = "build"; + @InputDirectory @SkipWhenEmpty public abstract DirectoryProperty getContextDirectory(); @Input + public abstract MapProperty getBuildArgs(); + + @Input + public abstract ListProperty getExtraCommandArgs(); + + @Input + public abstract Property getBuildTarget(); + + @Input public abstract Property getImageName(); @OutputFile public abstract RegularFileProperty getImageIdFile(); - public BuildImage() { + public void buildArgs(Action> spec) { + getBuildArgs().putAll(provider(() -> { + Map args = new HashMap<>(); + spec.execute(args); + return args; + })); + } - setWorkingDir(getContextDirectory().getAsFile()); + public void buildArgs(Closure> spec) { + buildArgs(Utils.wrapClosure(spec)); + } + + @Override + protected Optional getSubCommand() { + return Optional.of(BUILD_COMMAND); } @Override - protected void preparingCommand(List commandLine) { - super.preparingCommand(commandLine); + protected Collection getSubCommandArguments() { + List args = new ArrayList<>(); + + args.addAll(List.of( + "-t", getImageName().get().toString(), + "--iidfile", getImageIdFile().getAsFile().get().toString())); + + if (imageBuildArgs.isPresent()) { + imageBuildArgs.get().forEach((k, v) -> { + args.add("--build-arg"); + args.add(String.format("%s=%s", k, v)); + }); + } - commandLine.addAll(List.of("build", ".", "-q", "-t")); - commandLine.add(getImageName().get().toString()); - } + // add --target if specified for multi-stage build + if (getBuildTarget().isPresent()) { + args.add("--target"); + args.add(getBuildTarget().get()); + } - @Override - protected void processStarted(Process p) { - Utils.redirectIO(p.getInputStream(), getImageIdFile().get().getAsFile()); + // add extra parameters + getExtraCommandArgs().getOrElse(Collections.emptyList()) + .forEach(args::add); + + args.add(getContextDirectory().getAsFile().get().toString()); + + return args; } } diff --git a/container/src/main/java/org/implab/gradle/containers/tasks/CliTask.java b/container/src/main/java/org/implab/gradle/containers/tasks/DockerCliTask.java rename from container/src/main/java/org/implab/gradle/containers/tasks/CliTask.java rename to container/src/main/java/org/implab/gradle/containers/tasks/DockerCliTask.java --- a/container/src/main/java/org/implab/gradle/containers/tasks/CliTask.java +++ b/container/src/main/java/org/implab/gradle/containers/tasks/DockerCliTask.java @@ -1,30 +1,43 @@ package org.implab.gradle.containers.tasks; import java.io.File; -import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.List; +import java.util.Optional; import org.gradle.api.DefaultTask; -import org.gradle.api.logging.Logger; +import org.gradle.api.file.DirectoryProperty; import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; import org.gradle.api.tasks.Input; import org.gradle.api.tasks.Internal; import org.gradle.api.tasks.TaskAction; -import org.implab.gradle.Utils; import org.implab.gradle.containers.ContainerExtension; +import org.implab.gradle.containers.ExecuteMixin; +import org.implab.gradle.containers.PropertiesMixin; -public abstract class CliTask extends DefaultTask { +public abstract class DockerCliTask extends DefaultTask implements PropertiesMixin, ExecuteMixin { private final Property cliCmd; - private final Property workingDir; + private final DirectoryProperty workingDir; + + public DockerCliTask() { + cliCmd = property(String.class) + .convention(getContainerExtension().getCliCmd()); + + workingDir = directoryProperty(); + } - public CliTask() { - cliCmd = getProject().getObjects().property(String.class); - cliCmd.convention(getContainerExtension().getCliCmd()); + @Internal + protected Optional getSubCommand() { + return Optional.empty(); + } - workingDir = getProject().getObjects().property(File.class); + @Internal + protected Collection getSubCommandArguments() { + return Collections.emptyList(); } @Input @@ -43,51 +56,26 @@ public abstract class CliTask extends De @TaskAction public void Run() throws Exception { - final Logger log = getLogger(); - - List args = new ArrayList<>(); - preparingCommand(args); - - ProcessBuilder builder = new ProcessBuilder(args); - if (workingDir.isPresent()) - builder.directory(workingDir.get()); - - log.info("Starting: {}", builder.command()); - - Process p = builder.start(); - - processStarted(p); - - if (log.isErrorEnabled()) { - Utils.redirectIO(p.getErrorStream(), log::error); - } - - int code = p.waitFor(); - if (code != 0) - throw new Exception("Process exited with the error: " + code); + Execute(); } - protected void preparingCommand(List commandLine) { + public void preparingCommand(List commandLine) { commandLine.add(cliCmd.get()); + getSubCommand().ifPresent(commandLine::add); + getSubCommandArguments().forEach(commandLine::add); + } + + @Override + @Internal + public Optional getWorkingDir() { + return Optional.ofNullable(workingDir.get().getAsFile()); } protected void setWorkingDir(Provider workingDir) { - this.workingDir.set(workingDir); + this.workingDir.fileProvider(workingDir); } protected void setWorkingDir(File workingDir) { this.workingDir.set(workingDir); } - - - /** Invoked after the process is started, can be used to handle the process output. - * - * Default implemetation redirects output to the logger as INFO messages. - * - * @param p The current process. - */ - protected void processStarted(Process p) { - final Logger log = getLogger(); - Utils.redirectIO(p.getInputStream(), log::info); - } } diff --git a/container/src/main/java/org/implab/gradle/containers/tasks/MountSpec.java b/container/src/main/java/org/implab/gradle/containers/tasks/MountSpec.java new file mode 100644 --- /dev/null +++ b/container/src/main/java/org/implab/gradle/containers/tasks/MountSpec.java @@ -0,0 +1,10 @@ +package org.implab.gradle.containers.tasks; + +public class MountSpec { + + String destination; + + String source; + + boolean readOnly; +} diff --git a/container/src/main/java/org/implab/gradle/containers/tasks/PushImage.java b/container/src/main/java/org/implab/gradle/containers/tasks/PushImage.java --- a/container/src/main/java/org/implab/gradle/containers/tasks/PushImage.java +++ b/container/src/main/java/org/implab/gradle/containers/tasks/PushImage.java @@ -1,5 +1,7 @@ package org.implab.gradle.containers.tasks; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.concurrent.Callable; @@ -9,7 +11,9 @@ import org.gradle.api.tasks.Input; import org.gradle.api.tasks.Optional; import org.implab.gradle.containers.ImageName; -public abstract class PushImage extends CliTask { +public abstract class PushImage extends DockerCliTask { + + public final String PUSH_COMMAND = "push"; @Input public abstract Property getImageName(); @@ -28,11 +32,17 @@ public abstract class PushImage extends } @Override - protected void preparingCommand(List commandLine) { - super.preparingCommand(commandLine); + protected java.util.Optional getSubCommand() { + return java.util.Optional.of(PUSH_COMMAND); + } - commandLine.add("push"); - commandLine.addAll(getOptions().get()); - commandLine.add(getImageName().get().toString()); + @Override + protected Collection getSubCommandArguments() { + List args = new ArrayList<>(); + + args.addAll(getOptions().get()); + args.add(getImageName().get().toString()); + + return args; } } diff --git a/container/src/main/java/org/implab/gradle/containers/tasks/RunImage.java b/container/src/main/java/org/implab/gradle/containers/tasks/RunImage.java new file mode 100644 --- /dev/null +++ b/container/src/main/java/org/implab/gradle/containers/tasks/RunImage.java @@ -0,0 +1,54 @@ +package org.implab.gradle.containers.tasks; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.gradle.api.Action; +import org.gradle.api.provider.ListProperty; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.Optional; +import org.implab.gradle.containers.ImageName; + +public abstract class RunImage extends DockerCliTask { + + public final String RUN_COMMAND = "run"; + + @Input + @Optional + public abstract ListProperty getOptions(); + + @Input + public abstract Property getImageName(); + + @Input + @Optional + public abstract ListProperty getCommandLine(); + + @Override + protected java.util.Optional getSubCommand() { + return java.util.Optional.of(RUN_COMMAND); + } + + @Override + protected Collection getSubCommandArguments() { + List args = new ArrayList(); + + args.addAll(getOptions().get()); + args.add(getImageName().get().toString()); + args.addAll(getCommandLine().get()); + + return args; + } + + public void volume(Action configure) { + getOptions().add("-v"); + getOptions().add(provider(() -> { + var volumeSpec = getObjectFactory().newInstance(VolumeSpec.class); + configure.execute(volumeSpec); + return volumeSpec.resolveSpec(); + })); + } + +} diff --git a/container/src/main/java/org/implab/gradle/containers/tasks/SaveImage.java b/container/src/main/java/org/implab/gradle/containers/tasks/SaveImage.java --- a/container/src/main/java/org/implab/gradle/containers/tasks/SaveImage.java +++ b/container/src/main/java/org/implab/gradle/containers/tasks/SaveImage.java @@ -1,6 +1,7 @@ package org.implab.gradle.containers.tasks; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Optional; @@ -12,10 +13,10 @@ import org.gradle.api.tasks.Input; import org.gradle.api.tasks.Internal; import org.gradle.api.tasks.OutputFile; import org.gradle.api.tasks.TaskExecutionException; -import org.implab.gradle.Utils; import org.implab.gradle.containers.ImageName; -public abstract class SaveImage extends CliTask { +public abstract class SaveImage extends DockerCliTask { + public final String SAVE_COMMAND = "save"; @Input public abstract Property getImage(); @@ -44,9 +45,9 @@ public abstract class SaveImage extends public abstract Property getArchiveExtension(); public SaveImage() { - getArchiveFileName().convention(getProject().provider(this::conventionalArchiveFileName)); - getArchiveBaseName().convention(getProject().provider(this::conventionalArchiveBaseName)); - getArchiveVersion().convention(getProject().provider(() -> getProject().getVersion()).map(x -> x.toString())); + getArchiveFileName().convention(provider(this::conventionalArchiveFileName)); + getArchiveBaseName().convention(provider(this::conventionalArchiveBaseName)); + getArchiveVersion().convention(provider(() -> getProject().getVersion()).map(x -> x.toString())); getDestinationDirectory().convention(getProject().getLayout().getBuildDirectory()); getArchiveExtension().convention("tar"); } @@ -77,15 +78,15 @@ public abstract class SaveImage extends } @Override - protected void preparingCommand(List commandLine) { - super.preparingCommand(commandLine); - - commandLine.add("save"); - commandLine.add(getImage().get().toString()); + protected Optional getSubCommand() { + return Optional.of(SAVE_COMMAND); } @Override - protected void processStarted(Process p) { - Utils.redirectIO(p.getInputStream(), getArchiveFile().get().getAsFile()); + protected Collection getSubCommandArguments() { + return List.of( + getImage().get().toString(), + getArchiveFile().get().getAsFile().toString() + ); } } diff --git a/container/src/main/java/org/implab/gradle/containers/tasks/TagImage.java b/container/src/main/java/org/implab/gradle/containers/tasks/TagImage.java --- a/container/src/main/java/org/implab/gradle/containers/tasks/TagImage.java +++ b/container/src/main/java/org/implab/gradle/containers/tasks/TagImage.java @@ -1,5 +1,7 @@ package org.implab.gradle.containers.tasks; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.concurrent.Callable; @@ -9,7 +11,8 @@ import org.gradle.api.tasks.Input; import org.gradle.api.tasks.Optional; import org.implab.gradle.containers.ImageName; -public abstract class TagImage extends CliTask { +public abstract class TagImage extends DockerCliTask { + public final String TAG_COMMAND = "tag"; @Input public abstract Property getSrcImage(); @@ -31,12 +34,18 @@ public abstract class TagImage extends C } @Override - protected void preparingCommand(List commandLine) { - super.preparingCommand(commandLine); + protected java.util.Optional getSubCommand() { + return java.util.Optional.of(TAG_COMMAND); + } - commandLine.add("tag"); - commandLine.addAll(getOptions().get()); - commandLine.add(getSrcImage().get().toString()); - commandLine.add(getDestImage().get().toString()); + @Override + protected Collection getSubCommandArguments() { + List args = new ArrayList<>(); + + args.addAll(getOptions().get()); + args.add(getSrcImage().get().toString()); + args.add(getDestImage().get().toString()); + + return args; } } diff --git a/container/src/main/java/org/implab/gradle/containers/tasks/VolumeSpec.java b/container/src/main/java/org/implab/gradle/containers/tasks/VolumeSpec.java new file mode 100644 --- /dev/null +++ b/container/src/main/java/org/implab/gradle/containers/tasks/VolumeSpec.java @@ -0,0 +1,34 @@ +package org.implab.gradle.containers.tasks; + +import java.util.ArrayList; + +import org.gradle.api.provider.ListProperty; +import org.gradle.api.provider.Property; + +public abstract class VolumeSpec { + + public abstract Property getSource(); + + public abstract Property getTarget(); + + public abstract ListProperty getOptions(); + + public void ro() { + getOptions().add("ro"); + } + + public String resolveSpec() { + var parts = new ArrayList(); + + if (getSource().isPresent()) + parts.add(getSource().get()); + + parts.add(getTarget().get()); + + if (getOptions().isPresent()) + parts.add(String.join(",", getOptions().get())); + + return String.join(":", parts); + } + +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index cc4fdc293d0e50b0ad9b65c16e7ddd1db2f6025b..7f93135c49b765f8051ef9d0a6055ff8e46073d8 GIT binary patch literal 63721 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 z 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,78 +17,111 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -97,87 +130,120 @@ Please set the JAVA_HOME variable in you location of your Java installation." fi else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" fi fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=`expr $i + 1` - done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,10 +25,14 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @@ -37,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJa set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -51,7 +55,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -61,38 +65,26 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/settings.gradle b/settings.gradle --- a/settings.gradle +++ b/settings.gradle @@ -8,6 +8,6 @@ * in the user guide at https://docs.gradle.org/3.5/userguide/multi_project_builds.html */ -rootProject.name = 'plugins' +rootProject.name = 'implab-gradle' include 'container'