Make LoggedExec gradle task configuration cache compatible (#87621)

This changes the LoggedExec task to be configuration cache compatible. We changed the implementation
to use `ExecOperations` instead of extending `Exec` task. As double checked with the Gradle team this task
is not planned to be made configuration cache compatible out of the box anytime soon.

This is part of the effort on https://github.com/elastic/elasticsearch/issues/57918
This commit is contained in:
Rene Groeschke 2022-07-11 08:46:54 +02:00 committed by GitHub
parent f99ee51c5d
commit dbf39741a0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 381 additions and 127 deletions

View file

@ -14,8 +14,6 @@ import org.gradle.testkit.runner.TaskOutcome
class InternalBwcGitPluginFuncTest extends AbstractGitAwareGradleFuncTest {
def setup() {
// using LoggedExec is not cc compatible
configurationCacheCompatible = false
internalBuild()
buildFile << """
import org.elasticsearch.gradle.Version;

View file

@ -17,12 +17,11 @@ import spock.lang.Unroll
/*
* Test is ignored on ARM since this test case tests the ability to build certain older BWC branches that we don't support on ARM
*/
@IgnoreIf({ Architecture.current() == Architecture.AARCH64 })
class InternalDistributionBwcSetupPluginFuncTest extends AbstractGitAwareGradleFuncTest {
def setup() {
// used LoggedExec task is not configuration cache compatible and
// Cannot serialize BwcSetupExtension containing project object
configurationCacheCompatible = false
internalBuild()
buildFile << """
@ -119,4 +118,5 @@ class InternalDistributionBwcSetupPluginFuncTest extends AbstractGitAwareGradleF
result.output.contains("nested folder /distribution/bwc/minor/build/bwc/checkout-8.0/" +
"distribution/archives/darwin-tar/build/install/elasticsearch-8.0.0-SNAPSHOT")
}
}

View file

@ -12,22 +12,20 @@ import org.apache.tools.ant.taskdefs.condition.Os
import org.elasticsearch.gradle.LoggedExec
import org.elasticsearch.gradle.internal.test.AntFixture
import org.gradle.api.file.FileSystemOperations
import org.gradle.api.file.ProjectLayout
import org.gradle.api.tasks.Internal
import org.gradle.process.ExecOperations
import javax.inject.Inject
class AntFixtureStop extends LoggedExec implements FixtureStop {
abstract class AntFixtureStop extends LoggedExec implements FixtureStop {
@Internal
AntFixture fixture
@Internal
FileSystemOperations fileSystemOperations
@Inject
AntFixtureStop(FileSystemOperations fileSystemOperations) {
super(fileSystemOperations)
this.fileSystemOperations = fileSystemOperations
AntFixtureStop(ProjectLayout projectLayout, ExecOperations execOperations, FileSystemOperations fileSystemOperations) {
super(projectLayout, execOperations, fileSystemOperations)
}
void setFixture(AntFixture fixture) {
@ -40,10 +38,10 @@ class AntFixtureStop extends LoggedExec implements FixtureStop {
}
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
executable = 'Taskkill'
getExecutable().set('Taskkill')
args('/PID', pid, '/F')
} else {
executable = 'kill'
getExecutable().set('kill')
args('-9', pid)
}
doLast {

View file

@ -15,15 +15,12 @@ import org.elasticsearch.gradle.Version;
import org.gradle.api.Action;
import org.gradle.api.GradleException;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.logging.LogLevel;
import org.gradle.api.provider.Provider;
import org.gradle.api.tasks.TaskProvider;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
@ -64,26 +61,21 @@ public class BwcSetupExtension {
return project.getTasks().register(name, LoggedExec.class, loggedExec -> {
loggedExec.dependsOn("checkoutBwcBranch");
loggedExec.usesService(bwcTaskThrottleProvider);
loggedExec.setSpoolOutput(true);
loggedExec.setWorkingDir(checkoutDir.get());
loggedExec.doFirst(new Action<Task>() {
@Override
public void execute(Task t) {
// Execution time so that the checkouts are available
String compilerVersionInfoPath = minimumCompilerVersionPath(unreleasedVersionInfo.get().version());
String minimumCompilerVersion = readFromFile(new File(checkoutDir.get(), compilerVersionInfoPath));
loggedExec.environment("JAVA_HOME", getJavaHome(Integer.parseInt(minimumCompilerVersion)));
}
});
loggedExec.getWorkingDir().set(checkoutDir.get());
loggedExec.getEnvironment().put("JAVA_HOME", unreleasedVersionInfo.zip(checkoutDir, (version, checkoutDir) -> {
String minimumCompilerVersion = readFromFile(new File(checkoutDir, minimumCompilerVersionPath(version.version())));
return getJavaHome(Integer.parseInt(minimumCompilerVersion));
}));
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
loggedExec.executable("cmd");
loggedExec.getExecutable().set("cmd");
loggedExec.args("/C", "call", new File(checkoutDir.get(), "gradlew").toString());
} else {
loggedExec.executable(new File(checkoutDir.get(), "gradlew").toString());
loggedExec.getExecutable().set(new File(checkoutDir.get(), "gradlew").toString());
}
loggedExec.args("-g", project.getGradle().getGradleUserHomeDir());
loggedExec.args("-g", project.getGradle().getGradleUserHomeDir().toString());
if (project.getGradle().getStartParameter().isOffline()) {
loggedExec.args("--offline");
}
@ -93,8 +85,7 @@ public class BwcSetupExtension {
loggedExec.args("-Dorg.elasticsearch.build.cache.url=" + buildCacheUrl);
}
loggedExec.args("-Dbuild.snapshot=true");
loggedExec.args("-Dscan.tag.NESTED");
loggedExec.args("-Dbuild.snapshot=true", "-Dscan.tag.NESTED");
final LogLevel logLevel = project.getGradle().getStartParameter().getLogLevel();
List<LogLevel> nonDefaultLogLevels = Arrays.asList(LogLevel.QUIET, LogLevel.WARN, LogLevel.INFO, LogLevel.DEBUG);
if (nonDefaultLogLevels.contains(logLevel)) {
@ -110,8 +101,7 @@ public class BwcSetupExtension {
if (project.getGradle().getStartParameter().isParallelProjectExecutionEnabled()) {
loggedExec.args("--parallel");
}
loggedExec.setStandardOutput(new IndentingOutputStream(System.out, unreleasedVersionInfo.get().version()));
loggedExec.setErrorOutput(new IndentingOutputStream(System.err, unreleasedVersionInfo.get().version()));
loggedExec.getIndentingConsoleOutput().set(unreleasedVersionInfo.map(v -> v.version().toString()));
configAction.execute(loggedExec);
});
}
@ -122,32 +112,6 @@ public class BwcSetupExtension {
: "buildSrc/" + MINIMUM_COMPILER_VERSION_PATH;
}
private static class IndentingOutputStream extends OutputStream {
public final byte[] indent;
private final OutputStream delegate;
IndentingOutputStream(OutputStream delegate, Object version) {
this.delegate = delegate;
indent = (" [" + version + "] ").getBytes(StandardCharsets.UTF_8);
}
@Override
public void write(int b) throws IOException {
int[] arr = { b };
write(arr, 0, 1);
}
public void write(int[] bytes, int offset, int length) throws IOException {
for (int i = 0; i < bytes.length; i++) {
delegate.write(bytes[i]);
if (bytes[i] == '\n') {
delegate.write(indent);
}
}
}
}
private static String readFromFile(File file) {
try {
return FileUtils.readFileToString(file).trim();

View file

@ -69,29 +69,27 @@ public class InternalBwcGitPlugin implements Plugin<Project> {
TaskContainer tasks = project.getTasks();
TaskProvider<LoggedExec> createCloneTaskProvider = tasks.register("createClone", LoggedExec.class, createClone -> {
createClone.onlyIf(task -> this.gitExtension.getCheckoutDir().get().exists() == false);
createClone.setCommandLine(asList("git", "clone", buildLayout.getRootDirectory(), gitExtension.getCheckoutDir().get()));
createClone.commandLine("git", "clone", buildLayout.getRootDirectory(), gitExtension.getCheckoutDir().get());
});
ExtraPropertiesExtension extraProperties = project.getExtensions().getExtraProperties();
TaskProvider<LoggedExec> findRemoteTaskProvider = tasks.register("findRemote", LoggedExec.class, findRemote -> {
findRemote.dependsOn(createCloneTaskProvider);
// TODO Gradle should provide property based configuration here
findRemote.setWorkingDir(gitExtension.getCheckoutDir().get());
findRemote.setCommandLine(asList("git", "remote", "-v"));
ByteArrayOutputStream output = new ByteArrayOutputStream();
findRemote.setStandardOutput(output);
findRemote.doLast(t -> { extraProperties.set("remoteExists", isRemoteAvailable(remote, output)); });
findRemote.getWorkingDir().set(gitExtension.getCheckoutDir());
findRemote.commandLine("git", "remote", "-v");
findRemote.getCaptureOutput().set(true);
findRemote.doLast(t -> { extraProperties.set("remoteExists", isRemoteAvailable(remote, findRemote.getOutput())); });
});
TaskProvider<LoggedExec> addRemoteTaskProvider = tasks.register("addRemote", LoggedExec.class, addRemote -> {
addRemote.dependsOn(findRemoteTaskProvider);
addRemote.onlyIf(task -> ((boolean) extraProperties.get("remoteExists")) == false);
addRemote.setWorkingDir(gitExtension.getCheckoutDir().get());
addRemote.getWorkingDir().set(gitExtension.getCheckoutDir().get());
String remoteRepo = remote.get();
// for testing only we can override the base remote url
String remoteRepoUrl = providerFactory.systemProperty("testRemoteRepo")
.getOrElse("https://github.com/" + remoteRepo + "/elasticsearch.git");
addRemote.setCommandLine(asList("git", "remote", "add", remoteRepo, remoteRepoUrl));
addRemote.commandLine("git", "remote", "add", remoteRepo, remoteRepoUrl);
});
boolean isOffline = project.getGradle().getStartParameter().isOffline();
@ -107,8 +105,8 @@ public class InternalBwcGitPlugin implements Plugin<Project> {
});
fetchLatest.onlyIf(t -> isOffline == false && gitFetchLatest.get());
fetchLatest.dependsOn(addRemoteTaskProvider);
fetchLatest.setWorkingDir(gitExtension.getCheckoutDir().get());
fetchLatest.setCommandLine(asList("git", "fetch", "--all"));
fetchLatest.getWorkingDir().set(gitExtension.getCheckoutDir().get());
fetchLatest.commandLine("git", "fetch", "--all");
});
String projectPath = project.getPath();
@ -210,7 +208,7 @@ public class InternalBwcGitPlugin implements Plugin<Project> {
return os.toString().trim();
}
private static boolean isRemoteAvailable(Provider<String> remote, ByteArrayOutputStream output) {
return new String(output.toByteArray()).lines().anyMatch(l -> l.contains(remote.get() + "\t"));
private static boolean isRemoteAvailable(Provider<String> remote, String output) {
return output.lines().anyMatch(l -> l.contains(remote.get() + "\t"));
}
}

View file

@ -241,9 +241,9 @@ public class InternalDistributionBwcSetupPlugin implements Plugin<Project> {
return BuildParams.isCi()
&& (gitBranch == null || gitBranch.endsWith("master") == false || gitBranch.endsWith("main") == false);
});
c.args(projectPath.replace('/', ':') + ":" + assembleTaskName);
c.getArgs().add(projectPath.replace('/', ':') + ":" + assembleTaskName);
if (project.getGradle().getStartParameter().isBuildCacheEnabled()) {
c.args("--build-cache");
c.getArgs().add("--build-cache");
}
c.doLast(new Action<Task>() {
@Override

View file

@ -0,0 +1,166 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
package org.elasticsearch.gradle
import org.elasticsearch.gradle.fixtures.AbstractGradleFuncTest
import org.gradle.testkit.runner.TaskOutcome
import spock.lang.Ignore
import spock.lang.IgnoreIf
import spock.lang.Unroll
import spock.util.environment.OperatingSystem
@IgnoreIf({ os.isWindows() })
class LoggedExecFuncTest extends AbstractGradleFuncTest {
def setup() {
buildFile << """
// we need apply any custom plugin
// to add build-logic to the build classpath
plugins {
id 'elasticsearch.distribution-download'
}
"""
}
@Unroll
def "can configure spooling #spooling"() {
setup:
buildFile << """
import org.elasticsearch.gradle.LoggedExec
tasks.register('loggedExec', LoggedExec) {
commandLine 'ls', '-lh'
spoolOutput = $spooling
}
"""
when:
def result = gradleRunner("loggedExec").build()
then:
result.task(':loggedExec').outcome == TaskOutcome.SUCCESS
file("build/buffered-output/loggedExec").exists() == spooling
where:
spooling << [false, true]
}
@Unroll
def "failed tasks output logged to console when spooling #spooling"() {
setup:
buildFile << """
import org.elasticsearch.gradle.LoggedExec
tasks.register('loggedExec', LoggedExec) {
commandLine 'ls', 'wtf'
spoolOutput = $spooling
}
"""
when:
def result = gradleRunner("loggedExec").buildAndFail()
then:
result.task(':loggedExec').outcome == TaskOutcome.FAILED
file("build/buffered-output/loggedExec").exists() == spooling
assertOutputContains(result.output, """\
> Task :loggedExec FAILED
Output for ls:""".stripIndent())
assertOutputContains(result.output, "No such file or directory")
where:
spooling << [false, true]
}
def "can capture output"() {
setup:
buildFile << """
import org.elasticsearch.gradle.LoggedExec
tasks.register('loggedExec', LoggedExec) {
commandLine 'echo', 'HELLO'
getCaptureOutput().set(true)
doLast {
println 'OUTPUT ' + output
}
}
"""
when:
def result = gradleRunner("loggedExec").build()
then:
result.task(':loggedExec').outcome == TaskOutcome.SUCCESS
result.getOutput().contains("OUTPUT HELLO")
}
def "capturing output with spooling enabled is not supported"() {
setup:
buildFile << """
import org.elasticsearch.gradle.LoggedExec
tasks.register('loggedExec', LoggedExec) {
commandLine 'echo', 'HELLO'
getCaptureOutput().set(true)
spoolOutput = true
}
"""
when:
def result = gradleRunner("loggedExec").buildAndFail()
then:
result.task(':loggedExec').outcome == TaskOutcome.FAILED
assertOutputContains(result.output, '''\
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':loggedExec'.
> Capturing output is not supported when spoolOutput is true.'''.stripIndent())
}
def "can configure output indenting"() {
setup:
buildFile << """
import org.elasticsearch.gradle.LoggedExec
tasks.register('loggedExec', LoggedExec) {
getIndentingConsoleOutput().set("CUSTOM")
commandLine('echo', '''
HELLO
Darkness
my old friend''')
}
"""
when:
def result = gradleRunner("loggedExec", '-q').build()
then:
result.task(':loggedExec').outcome == TaskOutcome.SUCCESS
normalized(result.output) == '''
[CUSTOM] HELLO
[CUSTOM] Darkness
[CUSTOM] my old friend'''.stripIndent(9)
}
def "can provide standard input"() {
setup:
file('script.sh') << """
#!/bin/bash
# Read the user input
echo "Enter the user input: "
read userInput
echo "The user input is \$userInput"
"""
buildFile << """
import org.elasticsearch.gradle.LoggedExec
tasks.register('loggedExec', LoggedExec) {
getCaptureOutput().set(true)
commandLine 'bash', 'script.sh'
getStandardInput().set('FooBar')
doLast {
println output
}
}
"""
when:
def result = gradleRunner("loggedExec").build()
then:
result.task(':loggedExec').outcome == TaskOutcome.SUCCESS
result.getOutput().contains("The user input is FooBar")
}
}

View file

@ -8,12 +8,19 @@
package org.elasticsearch.gradle;
import org.gradle.api.Action;
import org.gradle.api.DefaultTask;
import org.gradle.api.GradleException;
import org.gradle.api.Task;
import org.gradle.api.file.FileSystemOperations;
import org.gradle.api.file.ProjectLayout;
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
import org.gradle.api.tasks.Exec;
import org.gradle.api.provider.ListProperty;
import org.gradle.api.provider.MapProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.TaskAction;
import org.gradle.api.tasks.WorkResult;
import org.gradle.process.BaseExecSpec;
import org.gradle.process.ExecOperations;
@ -21,13 +28,16 @@ import org.gradle.process.ExecResult;
import org.gradle.process.ExecSpec;
import org.gradle.process.JavaExecSpec;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.regex.Pattern;
@ -35,52 +45,70 @@ import java.util.regex.Pattern;
import javax.inject.Inject;
/**
* A wrapper around gradle's Exec task to capture output and log on error.
* A wrapper around gradle's exec functionality to capture output and log on error.
* This Task is configuration cache-compatible in contrast to Gradle's built-in
* Exec task implementation.
*/
@SuppressWarnings("unchecked")
public class LoggedExec extends Exec implements FileSystemOperationsAware {
public abstract class LoggedExec extends DefaultTask implements FileSystemOperationsAware {
private static final Logger LOGGER = Logging.getLogger(LoggedExec.class);
private Consumer<Logger> outputLogger;
private FileSystemOperations fileSystemOperations;
protected FileSystemOperations fileSystemOperations;
private ProjectLayout projectLayout;
private ExecOperations execOperations;
private boolean spoolOutput;
@Input
@Optional
abstract public ListProperty<Object> getArgs();
@Input
@Optional
abstract public MapProperty<String, String> getEnvironment();
@Input
abstract public Property<String> getExecutable();
@Input
@Optional
abstract public Property<String> getStandardInput();
@Input
@Optional
abstract public Property<String> getIndentingConsoleOutput();
@Input
@Optional
abstract public Property<Boolean> getCaptureOutput();
@Input
abstract public Property<File> getWorkingDir();
private String output;
@Inject
public LoggedExec(FileSystemOperations fileSystemOperations) {
public LoggedExec(ProjectLayout projectLayout, ExecOperations execOperations, FileSystemOperations fileSystemOperations) {
this.projectLayout = projectLayout;
this.execOperations = execOperations;
this.fileSystemOperations = fileSystemOperations;
if (getLogger().isInfoEnabled() == false) {
setIgnoreExitValue(true);
setSpoolOutput(false);
// We use an anonymous inner class here because Gradle cannot properly snapshot this input for the purposes of
// incremental build if we use a lambda. This ensures LoggedExec tasks that declare output can be UP-TO-DATE.
doLast(new Action<Task>() {
@Override
public void execute(Task task) {
int exitValue = LoggedExec.this.getExecutionResult().get().getExitValue();
if (exitValue != 0) {
try {
LoggedExec.this.getLogger().error("Output for " + LoggedExec.this.getExecutable() + ":");
outputLogger.accept(LoggedExec.this.getLogger());
} catch (Exception e) {
throw new GradleException("Failed to read exec output", e);
}
throw new GradleException(
String.format(
"Process '%s %s' finished with non-zero exit value %d",
LoggedExec.this.getExecutable(),
LoggedExec.this.getArgs(),
exitValue
)
);
}
}
});
}
getWorkingDir().convention(projectLayout.getProjectDirectory().getAsFile());
// For now mimic default behaviour of Gradle Exec task here
getEnvironment().putAll(System.getenv());
getCaptureOutput().convention(false);
}
public void setSpoolOutput(boolean spoolOutput) {
final OutputStream out;
@TaskAction
public void run() {
if (spoolOutput && getCaptureOutput().get()) {
throw new GradleException("Capturing output is not supported when spoolOutput is true.");
}
if (getCaptureOutput().getOrElse(false) && getIndentingConsoleOutput().isPresent()) {
throw new GradleException("Capturing output is not supported when indentingConsoleOutput is configured.");
}
Consumer<Logger> outputLogger;
OutputStream out;
if (spoolOutput) {
File spoolFile = new File(getProject().getBuildDir() + "/buffered-output/" + this.getName());
File spoolFile = new File(projectLayout.getBuildDirectory().dir("buffered-output").get().getAsFile(), this.getName());
out = new LazyFileOutputStream(spoolFile);
outputLogger = logger -> {
try {
@ -94,10 +122,59 @@ public class LoggedExec extends Exec implements FileSystemOperationsAware {
};
} else {
out = new ByteArrayOutputStream();
outputLogger = logger -> { logger.error(((ByteArrayOutputStream) out).toString(StandardCharsets.UTF_8)); };
outputLogger = getIndentingConsoleOutput().isPresent() ? logger -> {} : logger -> logger.error(byteStreamToString(out));
}
setStandardOutput(out);
setErrorOutput(out);
OutputStream finalOutputStream = getIndentingConsoleOutput().isPresent()
? new IndentingOutputStream(System.out, getIndentingConsoleOutput().get())
: out;
ExecResult execResult = execOperations.exec(execSpec -> {
execSpec.setIgnoreExitValue(true);
execSpec.setStandardOutput(finalOutputStream);
execSpec.setErrorOutput(finalOutputStream);
execSpec.setExecutable(getExecutable().get());
execSpec.setEnvironment(getEnvironment().get());
if (getArgs().isPresent()) {
execSpec.setArgs(getArgs().get());
}
if (getWorkingDir().isPresent()) {
execSpec.setWorkingDir(getWorkingDir().get());
}
if (getStandardInput().isPresent()) {
try {
execSpec.setStandardInput(new ByteArrayInputStream(getStandardInput().get().getBytes("UTF-8")));
} catch (UnsupportedEncodingException e) {
throw new GradleException("Cannot set standard input", e);
}
}
});
int exitValue = execResult.getExitValue();
if (exitValue == 0 && getCaptureOutput().get()) {
output = byteStreamToString(out);
}
if (getLogger().isInfoEnabled() == false) {
if (exitValue != 0) {
try {
getLogger().error("Output for " + getExecutable().get() + ":");
outputLogger.accept(getLogger());
} catch (Exception e) {
throw new GradleException("Failed to read exec output", e);
}
throw new GradleException(
String.format("Process '%s %s' finished with non-zero exit value %d", getExecutable().get(), getArgs().get(), exitValue)
);
}
}
}
private String byteStreamToString(OutputStream out) {
return ((ByteArrayOutputStream) out).toString(StandardCharsets.UTF_8);
}
public void setSpoolOutput(boolean spoolOutput) {
this.spoolOutput = spoolOutput;
}
public static ExecResult exec(ExecOperations execOperations, Action<ExecSpec> action) {
@ -139,4 +216,60 @@ public class LoggedExec extends Exec implements FileSystemOperationsAware {
public WorkResult delete(Object... objects) {
return fileSystemOperations.delete(d -> d.delete(objects));
}
@Internal
public String getOutput() {
if (getCaptureOutput().get() == false) {
throw new GradleException(
"Capturing output was not enabled. Use " + getName() + ".getCapturedOutput.set(true) to enable output capturing."
);
}
return output;
}
private static class IndentingOutputStream extends OutputStream {
public final byte[] indent;
private final OutputStream delegate;
IndentingOutputStream(OutputStream delegate, Object version) {
this.delegate = delegate;
indent = (" [" + version + "] ").getBytes(StandardCharsets.UTF_8);
}
@Override
public void write(int b) throws IOException {
int[] arr = { b };
write(arr, 0, 1);
}
public void write(int[] bytes, int offset, int length) throws IOException {
for (int i = 0; i < bytes.length; i++) {
delegate.write(bytes[i]);
if (bytes[i] == '\n') {
delegate.write(indent);
}
}
}
}
public void args(Object... args) {
args(List.of(args));
}
public void args(List<Object> args) {
getArgs().addAll(args);
}
public void commandLine(Object... args) {
commandLine(List.of(args));
}
public void commandLine(List<Object> args) {
if (args.isEmpty()) {
throw new IllegalArgumentException("Cannot set commandline with empty list.");
}
getExecutable().set(args.get(0).toString());
getArgs().set(args.subList(1, args.size()));
}
}

View file

@ -47,9 +47,9 @@ abstract class AbstractGradleFuncTest extends Specification {
}
def cleanup() {
if (Boolean.getBoolean('test.keep.samplebuild')) {
// if (Boolean.getBoolean('test.keep.samplebuild')) {
FileUtils.copyDirectory(testProjectDir.root, new File("build/test-debug/" + testProjectDir.root.name))
}
// }
}
File subProject(String subProjectPath) {

View file

@ -469,7 +469,7 @@ subprojects { Project subProject ->
tasks.register(exportTaskName, LoggedExec) {
inputs.file("${parent.projectDir}/build/markers/${buildTaskName}.marker")
executable 'docker'
executable = 'docker'
outputs.file(tarFile)
args "save",
"-o",

View file

@ -475,15 +475,13 @@ subprojects {
if (project.name.contains('deb')) {
checkLicenseMetadataTaskProvider.configure { LoggedExec exec ->
onlyIf dpkgExists
final ByteArrayOutputStream output = new ByteArrayOutputStream()
exec.commandLine 'dpkg-deb', '--info', "${-> buildDist.get().outputs.files.filter(debFilter).singleFile}"
exec.standardOutput = output
exec.getCaptureOutput().set(true)
doLast {
String expectedLicense
expectedLicense = "Elastic-License"
final Pattern pattern = Pattern.compile("\\s*License: (.+)")
final String info = output.toString('UTF-8')
final String[] actualLines = info.split("\n")
final String[] actualLines = getOutput().split("\n")
int count = 0
for (final String actualLine : actualLines) {
final Matcher matcher = pattern.matcher(actualLine)
@ -507,11 +505,10 @@ subprojects {
assert project.name.contains('rpm')
checkLicenseMetadataTaskProvider.configure { LoggedExec exec ->
onlyIf rpmExists
final ByteArrayOutputStream output = new ByteArrayOutputStream()
exec.commandLine 'rpm', '-qp', '--queryformat', '%{License}', "${-> buildDist.get().outputs.files.singleFile}"
exec.standardOutput = output
exec.getCaptureOutput().set(true)
doLast {
String license = output.toString('UTF-8')
String license = getOutput()
String expectedLicense
expectedLicense = "Elastic License"
if (license != expectedLicense) {

View file

@ -64,7 +64,7 @@ TaskProvider createKey = tasks.register("createKey", LoggedExec) {
}
outputs.file(keystore).withPropertyName('keystoreFile')
executable = "${BuildParams.runtimeJavaHome}/bin/keytool"
standardInput = new ByteArrayInputStream('FirstName LastName\nUnit\nOrganization\nCity\nState\nNL\nyes\n\n'.getBytes('UTF-8'))
getStandardInput().set('FirstName LastName\nUnit\nOrganization\nCity\nState\nNL\nyes\n\n')
args '-genkey',
'-alias', 'test-node',
'-keystore', keystore,