On 23/07/2013, at 3:50 PM, Alex Ruiz <alr...@google.com> wrote:

> Another alternative that Xav and I were talking about later today is that, 
> instead of having the single-pass multi-model resolution, we can just have a 
> AndroidStudioModel.
> 
> The ToolModelBuilder for this model will do exactly what Studio is doing now: 
> gets the IdeaProject and iterates through its children (IdeaModel), 
> retrieving and AndroidModel if applicable.
> 
> The benefits for this alternative would be:
> 
> 1. We don't have to deal with multiple model hierarchies (e.g. GradleModel, 
> IdeaProject which have a parent-child structure, and AndroidProject that does 
> not know about this relationship)
> 2. We wouldn't have to wait for Gradle 1.8 to do a single-pass multi-model 
> resolution. We can use still use 1.6
> 
> I looked at the code and it looks like we can get the 
> ToolModelBuilderRegistry (to get the IdeaProject and AndroidProject models) 
> at any point as long we have a Project:
> 
> project.getServices().get(ToolingModelBuilderRegistry.class)
> 
> At the beginning Xav and I talked about having an IDE-agnostic model, but now 
> it seems that having one (AndroidStudioModel) is not a bad idea :-)
> 
> If we decide that this is the way to go for now (we can revisit the idea of 
> having the single-pass multi-model resolution in Gradle later on), the only 
> change that we'll need is adding the method 'File getRootDir' to 
> GradleProject (last item in my original e-mail.) This change seems pretty 
> small and straightforward. Do you think it can be included in Gradle 1.7?

Possibly. What would you use it for?


> 
> Regards,
> -Alex
> 
> 
> On Mon, Jul 22, 2013 at 5:14 PM, 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()?
>  
> 
> 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
> 
> Is there a reason to return something different than GradleProject when 
> querying the non actual hierarchy? The data from that interface is still 
> relevant I think.
> 
> 
> 
>> 
>> org.gradle.tooling.model.GradleProject:
>> Add method ‘List<Object> getModels()’ to GradleProject. This change will 
>> allows us to retrieve the models available from a project.
> 
> What would be the behaviour when a requested model is not available? It would 
> be missing from the list?
> 
> I think the GradleProject would be present but its model list would be empty.
> 
> --
> Adam Murdoch
> Gradle Co-founder
> http://www.gradle.org
> VP of Engineering, Gradleware Inc. - Gradle Training, Support, Consulting
> http://www.gradleware.com
> 
> 
> 
> 
> 


--
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