On 29/07/2013, at 4:25 PM, Alex Ruiz <[email protected]> wrote:

> Thanks, Adam. I've been looking into (and debugging) how the current API for 
> retrieving models work, to have a better understanding on how the API and 
> implementation of this new action would look like.
> 
> Attila: This approach may also benefit your work on Netbeans. Please take a 
> look.
> 
> This is what I have in mind, based on what I have done this weekend:
> 
> - The action interface can be simple, and so far this is what I think about 
> its API:
> 
>   public interface ConsumerAction<T> extends Serializable {
>     T execute(Project project);
>   }
> 
>    where Project is a org.gradle.api.Project. My understanding is that by 
> having a Project we can do everything we need  (through Project#getService()).

The action should accept something other than `org.gradle.api.Project`, for a 
few reasons:

1. `org.gradle.api.Project` is not version-independent. The entry point for the 
action should be a function of the client's tooling API version, not target 
Gradle version.
2. Some actions don't need a configured project. For example, an action may 
just be interested in the project hierarchy or the build environment. Or it may 
not be interested in the tasks of a project, or the dependencies of a project, 
or whatever. Instead, we need an interface that implies no configuration is 
done, except for that which is explicitly requested by the action.
3. It's not going to work well with decoupled project mode (e.g. parallel 
execution, configure on demand). This will become the default at some point. 
The plan there is that there will be no way to navigate from one project to 
another. Instead, we need an interface which provides access to the whole 
build, but in a way that allows things like parallel configuration and 
configuration on demand.
4. There's no opportunity to cache models. We'd have to cache the whole project 
model, which is unlikely to be possible any time soon.

So, instead, I'd introduce a new 'invocation' API. The contract would be that 
we start with an empty model and execute the action. The action can then use 
the invocation API to access the things it needs and these would be populated 
on demand.

There's probably 2 basic things the API would need to do:

1. Give me the set of all the projects in the build. This would return 
something like `GradleProject` minus the tasks. It implies that the settings 
script has been executed.
2. For a given project, give me the model of type M.

Possibly the API might also allow tasks to be scheduled and executed as well, 
but that can happen later.

> 
> - The tooling API can have this method in ProjectConnection:
> 
>   <T> ConsumerActionExecutor<T> execute(ConsumerAction<T> action); 
> 
>   where ConsumerActionExecutor is:
> 
>   public interface ConsumerActionExecutor<T> extends LongRunningOperation {
>     T get();
>   }
> 
>   This API sort of follows the pattern of ProjectConnection#model(Class).

This is good.

> 
> From here, I'm looking on how to implement what goes in between 
> ProjectConnection#execute(ConsumerAction) and ConsumerActionExecutor#get().

There are some pretty deep changes here. I have some time to help out at the 
moment if you'd like me to pick up some (or most) of this.

Here a potential implementation plan:

1. Add the APIs and a dummy implementation that runs the action in the tooling 
API client and returns the result.
2. Pass the action across the cross-version layer into the provider. Move the 
dummy implementation into the provider.
3. Serialize the action across to the daemon and the result back. Move the 
dummy implementation into the daemon. Now we've got a round trip into the real 
process.
4. Add an initial implementation of the invocation API, which simply configures 
all projects before doing anything.
5. Handle the case where the result references one of the models returned by 
the invocation API.

At this point, you've got a solution to your problem, as you can now do a 
single pass over the model and collect up the bits you need and send them back 
to the client. Later steps can make this better:

1. Don't configure a project until one of its models is requested.
2. Don't configure the project hierarchy until it is requested.
3. Don't configure the tasks of a project until they are requested

And generally making the invocation API richer.


> 
> WDYT?
> 
> -Alex
> 
> 
> On Sun, Jul 28, 2013 at 7:01 PM, Adam Murdoch <[email protected]> 
> wrote:
> 
> On 26/07/2013, at 8:24 AM, kelemen <[email protected]> wrote:
> 
>> Hi Alex,
>> 
>> I'm the developer of the NetBeans integration of Gradle and pleased to hear
>> that you want to work on this part of the Tooling API.
>> 
>> May I be selfish enough to ask you to consider my needs as well? :) I have
>> already reported two RFE for improving the model loading:
>> 
>> 1.
>> http://forums.gradle.org/gradle/topics/tooling_api_fetch_multiple_models_in_a_single_method_call
>> 2.
>> http://forums.gradle.org/gradle/topics/tooling_api_let_us_know_if_multiple_projects_got_evaluated
>> 
>> I will summarize those two RFEs:
>> 
>> 1. Allow loading multiple models in a single call (similar as you have
>> recommended) but also allow to define "fall-back models". That is return
>> another model if the one requested is not available. There is no use for
>> this currently but could make things easier if a model is to be made
>> obsolete (replaced by other models).
>> 
>> 2. Evaluating a Gradle project will likely cause other Gradle projects to be
>> evaluated as well. So, instead of leting evaluated projects go to waste. Let
>> the client code request what other projects got evaluated and allow
>> retrieving models from those projects as well. This is advantageous if you
>> do not wish to load all the projects of a multi-project build and should
>> work well with the configuration on deman feature of Gradle (when/if it will
>> be implemented for model loading as well).
>> 
>> Although these things are not vital (although advantageous) for simple J2SE
>> projects. These changes would improve performance considerably when
>> NBAndroid plugin is installed as well. Currently, installing NBAndroid will
>> slow down the loading of each project by magnitudes, simply because I have
>> to determine for each subproject if it has an AndroidProject as well.
> 
> I think the approach I've proposed in another email should help solve these 
> problems. The idea is that you provide the tooling API with an action which 
> can be executed in the Gradle process to build whatever results you need, 
> based on whatever logic you have. The action will run against some API 
> through which you can ask things like: which projects are available, which 
> models are available for a given project, and give me this model from this 
> project.
> 
> 
> --
> 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