Hi,

We want to extend the tooling API to expose the Intellij IDEA model, similar to 
the way we expose the Eclipse model. This will allow tools that want to know 
about the IDEA model for a build to integrate with Gradle (the obvious, and 
probably only, candidate being IDEA itself).

At the moment, we expose several models through the tooling API. You can 
separate these models into 2 groups: the Gradle model, and the Eclipse model. 
The Gradle model provides the Gradle view of the build. The Eclipse model 
provides the Gradle model mapped onto the Eclipse view of the world. This 
Eclipse model is exactly the same one we use to generate the .classpath and 
.project files when you run 'gradle eclipse'.

I think we didn't quite get the relationship between the Gradle and Eclipse 
models right with the first cut of the tooling API. Rather than just add in the 
IDEA model the same way, I think we should clean this up.

The Gradle model is represented using various subtypes of Project (for this 
discussion, I'm referring to org.gradle.tooling.model.*, not org.gradle.api.*):

* Project provides some basic identifying information about a project.
* BuildableProject extends Project and provides information about the tasks of 
the project.
* HierarchicalProject extends Project and provides information about the 
project hierarchy.

The Eclipse model is also represented using various subtypes of Project:

* EclipseHierarchicalProject extends HierarchicalProject and provides some 
basic information about an Eclipse project.
* EclipseProject extends EclipseHierarchicalProject and BuildableProject and 
provides the full details of an Eclipse project.

What this basically means is that an Eclipse project is-a Gradle project. Which 
isn't correct. Often there is a one-to-one relationship between the two, but 
not always. We want our Eclipse mapping to handle the case where there are 
multiple Eclipse projects per Gradle project (eg to separate out, say, 
integration tests, or any other source set). We probably also want our Eclipse 
mapping to handle the case where there are multiple Gradle projects mapped onto 
a single Eclipse project. So this means, in general, we want a 
many-to-many-relationship between Gradle project and Eclipse project.

For the time being, we probably don't need to expose this relationship in the 
tooling API model, but we should separate the concepts of Eclipse project and 
Gradle project.

Another consideration is that what the tooling API calls a 'project', IDEA 
calls a 'module'. The tooling API does not yet have a concept that matches an 
IDEA 'project'. So, if we here to add the IDEA model the same way as the 
Eclipse model, we'd add something called an IdeaModule which extends Project, 
and something called an IdeaProject which does not.

I think there are a few separate concepts here, which we might make explicit as 
interfaces:
* An identifiable thing. Not sure what to call this thing, but it's what 
Project currently represents. Let's call it a 'model element' for now. It has 
an identity, description and some root directory.
* A source element. Has source directories, external dependencies, 
inter-element dependencies, and other configuration.
* A buildable element. Has tasks, which can be executed.
* A composite element. A container of other elements.

We can mix these together to model the various things we need:

* Gradle project = source element, buildable element, composite element.
* Gradle build = composite element.
* Eclipse project = source element, buildable element.
* Eclipse workspace = composite element.
* IDEA module = source element, buildable element.
* IDEA project = composite element.

So, a plan might be:

Rename Project to ModelElement:
* Extract all the methods of Project onto a new super-interface called 
ModelElement. Deprecate Project.
* Extract all the methods of BuildableProject onto a new super-interface called 
BuildableModelElement. Deprecate BuildableProject.
* Extract all the methods of HierarchicalProject onto a new super-interface 
called CompositeModelElement. Deprecate HierarchicalProject.
* Change ProjectConnection.getModel() and model() to work with <T extends 
ModelElement>, instead of <T extends Project>.

Then, add:
* GradleProject extends ModelElement, BuildableModelElement, 
CompositeModelElement.
* IdeaProject extends ModelElement, CompositeModelElement.
* IdeaModule extends ModelElement, BuildableModelElement.

At some point, we might also add a SourceModelElement interface.

A variation of the above would be to deprecate BuildableProject and 
HierarchicalProject and duplicate their methods onto GradleProject, IdeaProject 
and IdeaModule, instead of adding BuildableModelElement and 
CompositeModelElement (ie don't try to model the abstract concepts).


--
Adam Murdoch
Gradle Co-founder
http://www.gradle.org
VP of Engineering, Gradleware Inc. - Gradle Training, Support, Consulting
http://www.gradleware.com

Reply via email to