# HG changeset patch # User cin # Date 2024-06-16 18:42:56 # Node ID 77543ddacb8db657d897e88889df2f22a640605d # Parent d3d34ee14dfe865991f6ba9c081347a40ba6000b Added LazyValue, ExternalTask diff --git a/common/build.gradle b/common/build.gradle --- a/common/build.gradle +++ b/common/build.gradle @@ -12,6 +12,7 @@ java { } dependencies { + compileOnly "org.eclipse.jdt:org.eclipse.jdt.annotation:2.3.0" api gradleApi() } diff --git a/common/src/main/java/org/implab/gradle/common/tasks/ExecuteTask.java b/common/src/main/java/org/implab/gradle/common/tasks/ExecuteTask.java new file mode 100644 --- /dev/null +++ b/common/src/main/java/org/implab/gradle/common/tasks/ExecuteTask.java @@ -0,0 +1,52 @@ +package org.implab.gradle.common.tasks; + +import org.gradle.api.DefaultTask; +import org.gradle.api.provider.ListProperty; +import org.gradle.api.tasks.Internal; +import org.implab.gradle.common.dsl.RedirectFromSpec; +import org.implab.gradle.common.dsl.RedirectToSpec; + +public abstract class ExecuteTask extends DefaultTask { + + private final RedirectToSpec redirectStderr = new RedirectToSpec(); + + private final RedirectToSpec redirectStdout = new RedirectToSpec(); + + private final RedirectFromSpec redirectStdin = new RedirectFromSpec(); + + @Internal + public abstract ListProperty getCommandLine(); + + + /** + * STDIN redirection, if not specified, no input will be passed to the command + */ + @Internal + public RedirectFromSpec getStdin() { + return redirectStdin; + } + + /** + * STDOUT redirection, if not specified, redirected to logger::info + */ + @Internal + public RedirectToSpec getStdout() { + return redirectStdout; + } + + /** + * STDERR redirection, if not specified, redirected to logger::error + */ + @Internal + public RedirectToSpec getStderr() { + return redirectStderr; + } + + + /** Appends specified parameters to the command line */ + void commandLine(String... args) { + getCommandLine().addAll(args); + } + + +} diff --git a/common/src/main/java/org/implab/gradle/common/tasks/ExternalTask.java b/common/src/main/java/org/implab/gradle/common/tasks/ExternalTask.java new file mode 100644 --- /dev/null +++ b/common/src/main/java/org/implab/gradle/common/tasks/ExternalTask.java @@ -0,0 +1,104 @@ +package org.implab.gradle.common.tasks; + +import java.io.IOException; +import java.util.Optional; +import java.util.concurrent.ExecutionException; + +import org.gradle.api.DefaultTask; +import org.implab.gradle.common.dsl.ProcessSpec; +import org.implab.gradle.common.exec.Executor; +import org.implab.gradle.common.exec.RedirectFrom; +import org.implab.gradle.common.exec.RedirectTo; + +public abstract class ExternalTask extends DefaultTask { + + /** + * A default redirection to the build log when loglevel is set to INFO, + * otherwise returns an empty redirection. + */ + protected Optional loggerInfoRedirect() { + return getLogger().isInfoEnabled() + ? Optional.of(RedirectTo.consumer(getLogger()::info)) + : Optional.empty(); + } + + /** + * A default redirection to the build log when loglevel is set to ERROR, + * otherwise returns an empty redirection. Note that ERROR level is set + * by default for a build runs. + */ + protected Optional loggerErrorRedirect() { + return getLogger().isErrorEnabled() + ? Optional.of(RedirectTo.consumer(getLogger()::error)) + : Optional.empty(); + } + + /** + * Stdout redirection for {@link #exec(ProcessSpec)}, default implementation + * will forward stdout to the build log through {@link #loggerErrorRedirect()} + */ + protected Optional stdoutRedirection() { + return loggerInfoRedirect(); + } + + /** + * Stderr redirection for {@link #exec(ProcessSpec)}, default implementation + * will forward stderr to build log through {@link #loggerErrorRedirect()}. + */ + protected Optional stderrRedirection() { + return loggerErrorRedirect(); + } + + /** + * Stdin redirection for {@link #exec(ProcessSpec)}, empty by default. + */ + protected Optional stdinRedirection() { + return Optional.empty(); + } + + /** + * Executes the specified process specification + * + * @param spec + * @throws InterruptedException + * @throws ExecutionException + * @throws IOException + */ + protected void exec(ProcessSpec spec) throws InterruptedException, ExecutionException, IOException { + var executor = exec(); + + stdoutRedirection().ifPresent(executor::stdout); + stderrRedirection().ifPresent(executor::stderr); + stdinRedirection().ifPresent(executor::stdin); + + getLogger().info("Staring: {}", spec.command()); + + spec.accept(executor); + + // runs the command and checks the error code + var code = executor.start().get(); + + // check success code + if (code != 0) + throw new IOException("The process exited with error code " + code); + } + + protected boolean checkRetCode(ProcessSpec proc, int code) + throws InterruptedException, ExecutionException, IOException { + + var executor = exec(); + + if (getLogger().isInfoEnabled()) { + loggerInfoRedirect().ifPresent(executor::stdout); + loggerInfoRedirect().ifPresent(executor::stderr); + } + + getLogger().info("Starting: {}", proc.command()); + + proc.accept(executor); + + return executor.start().get() == code; + } + + protected abstract Executor exec(); +} diff --git a/common/src/main/java/org/implab/gradle/common/utils/LazyValue.java b/common/src/main/java/org/implab/gradle/common/utils/LazyValue.java new file mode 100644 --- /dev/null +++ b/common/src/main/java/org/implab/gradle/common/utils/LazyValue.java @@ -0,0 +1,29 @@ +package org.implab.gradle.common.utils; + +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; + +public class LazyValue implements Supplier { + private final AtomicReference reference = new AtomicReference<>(); + + private final Supplier innerSupplier; + + public LazyValue(Supplier supplier) { + this.innerSupplier = supplier; + } + + @Override + public T get() { + var t = reference.get(); + if (t != null) + return t; + return updateValue(); + } + + private T updateValue() { + var v = innerSupplier.get(); + var t = reference.compareAndExchange(null, v); + return t != null ? t : v; + } + +} diff --git a/settings.gradle b/settings.gradle --- a/settings.gradle +++ b/settings.gradle @@ -8,6 +8,16 @@ * in the user guide at https://docs.gradle.org/3.5/userguide/multi_project_builds.html */ +dependencyResolutionManagement { + repositories { + mavenCentral() + mavenLocal() + ivy { + url "${System.properties["user.home"]}/ivy-repo" + } + } +} + rootProject.name = 'gradle-common' include 'common'