Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright 2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.gradle.process;

import org.gradle.api.Action;

/**
* Process execution operations.
*
* @since 6.0
*/
public interface ExecOperations {

/**
* Executes the specified external process.
* The given action is used to configure an {@link ExecSpec}, which is then used to run an external process.
*
* @param action Action to configure the ExecSpec
* @return {@link ExecResult} that can be used to check if the execution worked
*/
ExecResult exec(Action<? super ExecSpec> action);

/**
* Executes the specified external <code>java</code> process.
* The given action is used to configure an {@link JavaExecSpec}, which is then used to run an external <code>java</code> process.
*
* @param action Action to configure the JavaExecSpec
* @return {@link ExecResult} that can be used to check if the execution worked
*/
ExecResult javaexec(Action<? super JavaExecSpec> action);
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@
import org.gradle.normalization.internal.DefaultRuntimeClasspathNormalization;
import org.gradle.normalization.internal.InputNormalizationHandlerInternal;
import org.gradle.normalization.internal.RuntimeClasspathNormalizationInternal;
import org.gradle.process.ExecOperations;
import org.gradle.process.internal.DefaultExecOperations;
import org.gradle.process.internal.ExecFactory;
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry;
import org.gradle.tooling.provider.model.internal.DefaultToolingModelBuilderRegistry;
Expand Down Expand Up @@ -204,6 +206,10 @@ protected ExecFactory decorateExecFactory(ExecFactory execFactory, FileResolver
return execFactory.forContext(fileResolver, fileCollectionFactory, instantiatorFactory.decorateLenient(), objectFactory);
}

protected ExecOperations createExecOperations(ExecFactory execFactory) {
return new DefaultExecOperations(execFactory);
}

protected TemporaryFileProvider createTemporaryFileProvider() {
return new DefaultTemporaryFileProvider(new Factory<File>() {
@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright 2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.gradle.process.internal;

import org.gradle.api.Action;
import org.gradle.api.internal.ProcessOperations;
import org.gradle.process.ExecOperations;
import org.gradle.process.ExecResult;
import org.gradle.process.ExecSpec;
import org.gradle.process.JavaExecSpec;


public class DefaultExecOperations implements ExecOperations {

private final ProcessOperations processOperations;

public DefaultExecOperations(ProcessOperations processOperations) {
this.processOperations = processOperations;
}

@Override
public ExecResult exec(Action<? super ExecSpec> action) {
return processOperations.exec(action);
}

@Override
public ExecResult javaexec(Action<? super JavaExecSpec> action) {
return processOperations.javaexec(action);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,24 @@
"changes": [
"Method has been removed"
]
},
{
"type": "org.gradle.process.ExecOperations",
"member": "Class org.gradle.process.ExecOperations",
"acceptation": "New public API",
"changes": []
},
{
"type": "org.gradle.process.ExecOperations",
"member": "Method org.gradle.process.ExecOperations.exec(org.gradle.api.Action)",
"acceptation": "New public API",
"changes": []
},
{
"type": "org.gradle.process.ExecOperations",
"member": "Method org.gradle.process.ExecOperations.javaexec(org.gradle.api.Action)",
"acceptation": "New public API",
"changes": []
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import org.gradle.initialization.DefaultSettings
import org.gradle.initialization.LoadProjectsBuildOperationType
import org.gradle.integtests.fixtures.BuildOperationsFixture
import org.gradle.invocation.DefaultGradle
import org.gradle.process.ExecOperations
import org.gradle.test.fixtures.server.http.BlockingHttpServer
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
import org.gradle.workers.WorkerExecutor
Expand Down Expand Up @@ -478,6 +479,7 @@ class InstantExecutionIntegrationTest extends AbstractInstantExecutionIntegratio
ToolingModelBuilderRegistry.name | "project.services.get(${ToolingModelBuilderRegistry.name})" | "toString()"
WorkerExecutor.name | "project.services.get(${WorkerExecutor.name})" | "noIsolation()"
FileSystemOperations.name | "project.services.get(${FileSystemOperations.name})" | "toString()"
ExecOperations.name | "project.services.get(${ExecOperations.name})" | "toString()"
}

@Unroll
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ import org.gradle.internal.serialize.BaseSerializerFactory.SHORT_SERIALIZER
import org.gradle.internal.serialize.BaseSerializerFactory.STRING_SERIALIZER
import org.gradle.internal.serialize.SetSerializer
import org.gradle.internal.snapshot.ValueSnapshotter
import org.gradle.process.ExecOperations
import org.gradle.process.internal.ExecActionFactory
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
import org.gradle.workers.WorkerExecutor
Expand Down Expand Up @@ -174,6 +175,7 @@ class Codecs(
bind(ownerService<FileOperations>())
bind(ownerService<BuildOperationExecutor>())
bind(ownerService<ToolingModelBuilderRegistry>())
bind(ownerService<ExecOperations>())
bind(ownerService<ExecActionFactory>())
bind(ownerService<BuildOperationListenerManager>())
bind(ownerService<BuildRequestMetaData>())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,22 @@ import org.gradle.integtests.fixtures.AbstractIntegrationSpec
import org.gradle.integtests.fixtures.TestResources
import org.junit.Rule
import spock.lang.Issue
import spock.lang.Unroll

class ExecIntegrationTest extends AbstractIntegrationSpec {
@Rule
public final TestResources testResources = new TestResources(testDirectoryProvider)

def 'can execute java'() {
@Unroll
def 'can execute java with #task'() {
given:
buildFile << '''
buildFile << """
import javax.inject.Inject

apply plugin: 'java'

task javaexecTask(type: JavaExec) {
ext.testFile = file("$buildDir/$name")
ext.testFile = file("${'$'}buildDir/${'$'}name")
classpath(sourceSets.main.output.classesDirs)
main = 'org.gradle.TestMain'
args projectDir, testFile
Expand All @@ -42,8 +46,9 @@ class ExecIntegrationTest extends AbstractIntegrationSpec {
assert delegate instanceof ExtensionAware
}

task javaexecByMethod() {
ext.testFile = file("$buildDir/$name")
task javaexecProjectMethod() {
ext.testFile = file("${'$'}buildDir/${'$'}name")
dependsOn(sourceSets.main.output)
doFirst {
javaexec {
assert !(delegate instanceof ExtensionAware)
Expand All @@ -56,23 +61,40 @@ class ExecIntegrationTest extends AbstractIntegrationSpec {
assert testFile.exists()
}
}
'''.stripIndent()

${
injectedTaskActionTask('javaexecInjectedTaskAction', '''
File testFile = project.file("${project.buildDir}/$name")
execOperations.javaexec {
assert !(it instanceof ExtensionAware)
it.classpath(project.sourceSets['main'].output.classesDirs)
it.main 'org.gradle.TestMain'
it.args project.projectDir, testFile
}
assert testFile.exists()
''')
}
""".stripIndent()

expect:
succeeds 'javaexecTask', 'javaexecByMethod'
succeeds task

where:
task << ['javaexecTask', 'javaexecProjectMethod', 'javaexecInjectedTaskAction']
}

def 'can execute commands'() {
@Unroll
def 'can execute commands with #task'() {
given:
buildFile << '''
buildFile << """
import org.gradle.internal.jvm.Jvm
import javax.inject.Inject

apply plugin: 'java'

task execTask(type: Exec) {
dependsOn sourceSets.main.runtimeClasspath
ext.testFile = file("$buildDir/$name")
ext.testFile = file("${'$'}buildDir/${'$'}name")
executable = Jvm.current().getJavaExecutable()
args '-cp', sourceSets.main.runtimeClasspath.asPath, 'org.gradle.TestMain', projectDir, testFile
doLast {
Expand All @@ -81,9 +103,9 @@ class ExecIntegrationTest extends AbstractIntegrationSpec {
assert delegate instanceof ExtensionAware
}

task execByMethod {
task execProjectMethod {
dependsOn sourceSets.main.runtimeClasspath
ext.testFile = file("$buildDir/$name")
ext.testFile = file("${'$'}buildDir/${'$'}name")
doFirst {
exec {
executable Jvm.current().getJavaExecutable()
Expand All @@ -95,10 +117,46 @@ class ExecIntegrationTest extends AbstractIntegrationSpec {
assert testFile.exists()
}
}
'''.stripIndent()

${
injectedTaskActionTask('execInjectedTaskAction', '''
File testFile = project.file("${project.buildDir}/$name")
execOperations.exec {
assert !(it instanceof ExtensionAware)
it.executable Jvm.current().getJavaExecutable()
it.args '-cp', project.sourceSets['main'].runtimeClasspath.asPath, 'org.gradle.TestMain', project.projectDir, testFile
}
assert testFile.exists()
''')
}
""".stripIndent()

expect:
succeeds 'execTask', 'execByMethod'
succeeds task

where:
task << ['execTask', 'execProjectMethod', 'execInjectedTaskAction']
}

private static String injectedTaskActionTask(String taskName, String taskActionBody) {
return """
class InjectedServiceTask extends DefaultTask {

final ExecOperations execOperations

@Inject
InjectedServiceTask(ExecOperations execOperations) { this.execOperations = execOperations }

@TaskAction
void myAction() {
$taskActionBody
}
}

task $taskName(type: InjectedServiceTask) {
dependsOn(sourceSets.main.runtimeClasspath)
}
"""
}

@Issue("GRADLE-3528")
Expand Down