Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement API access to the Tooling API #726

Closed
donat opened this issue Jul 23, 2018 · 1 comment
Closed

Implement API access to the Tooling API #726

donat opened this issue Jul 23, 2018 · 1 comment
Assignees
Labels
Milestone

Comments

@donat
Copy link
Contributor

donat commented Jul 23, 2018

Overview

The Buildship downstream dependencies need to directly interact with the Gradle build. They want to extract arbitrary information from the build, query available tasks and run them. The Tooling API offers the necessary services to do that. Buildship already relies on this TAPI functionality, but there’s no convenient way to do the same for the dependencies.

Design

The ProjectConnection Tooling API interface contains all the methods to query models and execute build invocations. Buildship should expose a method on GradleBuild with a ProjectConnection instance. Buildship should take care of the connection initialization and cleanup.

Classes

GradleBuild should have a new ``withConnection()` method that provides a reference to the project connection.

interface GradleBuild {
    ...
    <T> T withConnection(Function<ProjectConnection, ? extends T> action, IProgressMonitor monitor)
}

The project connection should be a proxy so that all long-running operations (ModelBuilder, BuildLauncher, and TestLauncher) created by it are already pre-configured with correct inputs, outputs, progress loggers, etc.

Use cases

Querying available tasks

IProject project = ...
GradleWorkspace workspace = GradleCore.workspace();
GradleBuild build = workspace.getBuild(project);
List<String> tasks = build.withConnection(connection -> {
    GradleProject model = connection.getModel(GradleProject.class);
    return model.getTasks().stream().map(Task::getPath).collect(Collectors.toList());
});

Launching tasks

build.withConnection(conn -> conn.newBuild().forTasks("init").run());

Launching tests

build.withConnection(conn -> conn.newTestLauncher().withJvmTestClasses("org.example.MyTest").run());

Custom model loading

// from https://github.com/bmuschko/tooling-api-custom-model
String initScriptLoc = "/path/to/init.gradle";
build.withConnection(connection -> {
     connection.addArguments("--init-script", initScriptLoc);
     CustomModel model = connection.getModel(CustomModel);
     return model.hasPlugin(EclipsePlugin.class)
});

Test coverage

  • Integration tests for use-cases
    • When clients query models then the operation succeeds.
    • When clients query tasks then the operation succeeds.
    • When clients query custom models then the operation succeeds.
  • Configuration
    • Buildship settings are configured on all long-running operation created in withConnnection().
    • When the withConnection() method returns then the project connection is automatically closed.
  • Concurrency and scheduling rules

Additional notes

  • Switching to a different Gradle distribution can be done by creating a new GradleBuild object with a new Gradle version and calling withConnection(). Without calling synchronize() it won’t have any effect to the workspace.
  • The LongRunningOperation interface only supports setting arguments and jvm arguments, there’s no way to read or append the existing list. This means Buildship can’t preconfigure the operation and let the client manipulate the list. This makes the custom model injection impossible via an init script impossible. We have to introduce those methods to implement this story. Also, we should consider deprecating the withArguments and withJvmArguments as they have an identical implementation to setArguments and setJvmArguments.
  • We should add explicit documentation how a custom model can be queried via this API. As part of that, we should document how can a client load an init script location from a plugin jar.
@donat
Copy link
Contributor Author

donat commented Aug 17, 2018

Required story in Gradle: gradle/gradle#6404
Update: done; we only need to update the Tooling API dependency to get this feature.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant