On 23/07/2013, at 10:14 AM, Xavier Ducrohet <x...@google.com> wrote:
> > > > On Mon, Jul 22, 2013 at 4:34 PM, Adam Murdoch <adam.murd...@gradleware.com> > wrote: > > On 23/07/2013, at 5:53 AM, Alex Ruiz <alr...@google.com> wrote: > >> x >> Greetings everyone, >> >> We have, in Android Studio, a use case for retrieving multiple types of >> model, in single pass, from a Gradle project using the Tooling API. The >> following section explains the problem and the proposed solution. We >> discussed this issue and the potential solution with Adam during Gradle >> Summit back in June. Please let us know your thoughts. We plan to contribute >> this change to Gradle. > > That'd be great. > >> >> Thanks, >> -Alex >> >> Problem >> >> Currently, importing a Gradle-based Android project takes a considerable >> amount of time. The reason is that we have to make multiple calls to the >> Gradle Tooling API. For a project with N Android sub-projects, we have to >> make N+1 calls to Gradle. The reason is that an Android project may have a >> mix of Android sub-projects and plain Java ones and we cannot get all the >> Gradle models for such structure in one shot. >> >> What we are doing now is asking for the IdeaProject at the top-level >> project, then we iterate through the models of the returned IdeaProject >> asking for the corresponding AndroidProject, if it doesn’t have it, we >> assume is a Java project. >> >> Solution >> >> We are proposing is single-pass project import: a way to return all the >> models we need, from the Tooling API, in one invocation: >> >> ModelBuilder<GradleProject> builder = >> connection.models(IdeaProject.class, AndroidProject.class); >> GradleProject project = builder.get(); >> // ‘models’ will have instances of IdeaProject and AndroidProject. >> List<Object> models = project.getModels(); >> for (GradleProject child : project.getChildren) { >> // Each child will have its own models. >> models = child.getModels(); >> } > > This is a good plan. There are a couple of things I would tweak - more on > this below. > >> >> Changes to Gradle Tooling API >> >> org.gradle.tooling.ProjectConnection: >> Add method ‘ModelBuilder<GradleProject> models(Class<?>...modelTypes)’. This >> change will allow us to query multiple models type as shown above. > > `GradleProject` currently bundles together a few things about a project - its > place in the hierarchy, some identifying info, and the tasks of the project. > This would mean that for every model query, we'd need to create and configure > the tasks of each project. And this is something we'd like to avoid where > possible. I think it would be better if the API did not imply anything about > the tasks, and instead the tool can ask for them explicitly. > > One solution would be to split up GradleProject into an interface that > defines the structure and some basic information about each project, and into > a separate model (or perhaps models) that provide additional, specific > information about the project. You can then ask for this extra information as > you would for any model of the project. > > So the tasks would be part of another Model that is queried and returned as > part of GradleProject#getModels()? Yes. The idea is that pretty much anything except for some basic identifying information about a project lives on other models that you get via `getModels()` or perhaps some conveniences we add. The upside is that the client is more explicit about exactly what they need to know about a set of projects, which means we can do as little work as possible to calculate this. It would also avoid the need for special model types that define certain subsets of the model. For example, at the moment there's a HierarchicalEclipseProject model that contains a subset of the EclipseProject model. This is just (from a client's point of view) some arbitrary subset. It happens to be the exact subset that the STS plugin uses to import a build. Some for the BasicIdeaProject. Busting the models up into smaller chunks would mean that these types would go away. We might keep some subsets as a convenience, but they'd be a bit more coherent than the ones we have now. > > > Another potential issue here is that there isn't necessarily a 1-1 > relationship between a Gradle project and an IDE project. There are many ways > you might map a set of Gradle projects to a set of IDE projects. It just so > happens that our IDE plugins current map each Gradle project to its own IDE > project. But you might, for example, want to map the integration tests of > each Gradle project to a separate `IntTest` IDE project. We want to allow the > build some flexibility over how each Gradle project is mapped to the IDE, so > we don't really want to bake a 1-1 mapping into the tooling API. > > There are really several parallel hierarchies here - the set of Gradle > projects, the set of IDEA modules + IDEA project, and the set of Eclipse > projects. There is a relationship between a given Gradle project and IDEA > module, and a given Gradle project and Eclipse project. > > > It seems like the issue with Integration test is always going to be a Gradle > project becoming 2+ projects in the IDE and it's very specific to the > plugin(s) that are applied in a project(*). > > This means that the API of connection.models(IdeProject.class, > AndroidProject.class) is probably still the right one. It just may mean that > some GradleProject are present twice. > When you want to get the true Gradle project hierarchy, you can still do > connection.getModel(GradleProject.class). > > When calling models(), it's up to the Java plugin to return more than one > project for a given Gradle project. > > (*) I say plugins plural here because there could be a combination of plugin > that changes the returned model maybe? > > So I think there are 3 steps: > > 1. Split GradleModel in 2+ models. The current one, minus the task, plus the > model lists. And a new one for the tasks. > 2. Add the Connection.models() feature to the tooling API to get the model in > a single pass, and possible more than one model per project (e.g. the tasks + > the IDEA model for a Java project). > 3. Change the ToolingModelBuilder class to allow returning more than one > GradleProject object from a single project I think so. Not entirely sure about #3 yet. -- Adam Murdoch Gradle Co-founder http://www.gradle.org VP of Engineering, Gradleware Inc. - Gradle Training, Support, Consulting http://www.gradleware.com