« Return to Thread: removing the settings.gradle file

Re: removing the settings.gradle file

by Adam Murdoch-2 :: Rate this Message:

Reply to Author | View in Thread



Steve Appling wrote:

>
>
> Adam Murdoch wrote:
>>
>> * Defining the heirarchy
>>
>> It would be useful, I think, for any project to be able to define its
>> own subprojects. This allows for better build encapsulation, and
>> would allow small builds to be more easily composed into multiple
>> larger builds. Perhaps something like this in the build file:
>>
>> projects {
>>   subProject {
>>      buildFile = 'sub-project.gradle'
>>   }
>>   anotherSubProjectUsingDefaults
>>   aSubProjectConfiguredUsingAMap(projectDir: 'sub', buildFile:
>> 'sub.gradle')
>> }
>>
>> This could be nested to allow a project tree to be specified:
>>
>> projects {
>>    subProject {
>>        anotherProject { ... }
>>    }
>> }
>>
>> I think we should do away with the processing stage which figures out
>> which projects are included in the build, and simply allow them to be
>> added at any point during the evaluation stage. That is, projects are
>> just regular domain objects, not anything special. I think this
>> consistency important. In addition, this would mean you can use
>> plugins or classes in buildSrc to define or influence the project
>> hierarchy without us doing anything special to support it. The same
>> would be true of any future capability we add to let you compose the
>> build logic. To me, this approach seems more flexible and more likely
>> to handle use-cases we haven't anticipated, than would special-casing
>> assembly of the project hierarchy.
>>
>> There are some down-sides, but I think we can come up with simple
>> solutions to those (or already have, in the Task model).
>>
>
> One of the reasons that we have our own fork of Gradle currently is
> that we needed to be able to programmatically construct the set of
> projects used in a build.  We would like to to accomplish the same
> goals with this, but it looks like you may be planning to use AST
> transformations or another compile time technique to implement your
> scheme.  If so, please provide an API oriented alternative.
>

The general approach we've taken so far is to sit the DSL on top of a
public API, and I'm pretty sure we'll do the same here (though, often
the public API doesn't get any real coverage in the user guide). To be
more specific:

There are 3 events in a project's life that we're interested in here: 1)
project declaration, where the project is added to the build, 2) build
script compilation, where the class-path is assembled, and 3) project
evaluation, where the build script proper is executed. The approach
which I'm suggesting is really to simply allow a build script to
register an event handler closure for any of these events, just like it
can for afterEvaluate { } or taskGraph.whenReady {}.

So, project { } is simply an event handler for the project declared
event and buildclasspath { } is an event handler for the assemble
classpath (or before-compile) event.

We're going to need some AST magic to extract whichever of these event
handlers need to execute before the script has been compiled. The less
of these, the better, I think. There will not be any AST magic within
the closures themselves. They will just contain statements executed
against a Project (or maybe a ProjectDescriptor/Settings combo thing).

What this means, is that you'll be able to drive the API directly, or
indirectly using your own DSL classes, in these closures. Also, I
imagine this will all sit on top of a ProjectContainer interface,
returned by Build.getProjects() and Project.getSubprojects(). This
container, like TaskContainer, ConfigurationContainer, etc, will allow
you to programatically declare and configure projects.

> A common situation may be a single root project with a large number of
> child projects where all you want to specify in the root is the
> location of all the children's gradle files.  In this case, all of the
> project configuration may be done in the individual subproject gradle
> files.  A simplified syntax for this case might be:
>
> projects  {
>    include 'sub/sub.gradle', 'sub2/gradle/sub2.gradle'
> }
>

I agree we want to optimise for this case. This is how I want to be able
to compose my own builds :)

>>
>> * Project Descriptor
>>
>> It makes sense that a build script should be able to define the name
>> of the project, something like:
>>
>> project {
>>    name = 'myProject'
>>    // maybe some other properties as well
>> }
>>
>> Given that the name is fundamental to the identity of the project,
>> this closure would have to be executed as soon as the project is
>> included in the build (regardless of how that might happen). We would
>> need to do some magic to extract just this closure. I think it should
>> be possible.
>>
>> It's a closure so that 1) we can find it easily, 2) you can use
>> statements to configure the descriptor, and 3) so we can add more
>> properties or methods to the descriptor later.
>>
>> Some issues:
>>
>> - There is the potential for 2 different names to be specified for
>> the project: one in the ancestor project, and one in the project
>> itself. Not sure how to resolve this.
>>
>> - Which properties should be available for configuring in the
>> descriptor? For example, do we let you specify the project or build
>> dirs? Let you apply plugins? Define
>> tasks/configurations/repositories? Set arbitrary project properties?
>> Are you simply configuring a Project object, where the name property
>> is mutable while the closure executes?
>>
>> - Which properties can only be specified in the descriptor? Certainly
>> the name is one. If we let you specify the project or build dirs,
>> should we make them immutable after the descriptor has been configured?
>>
>> - What about the ancestor parent which includes the project? What can
>> it configure?
>>
> Names:
> In our Gradle fork, some of the changes we made were to allow us to
> debug .gradle files in IDEA.  We found it necessary to have distinct
> names for the gradle files in each project, so for the project
> "reportengine", the gradle file would just be "reportengine.gradle".  
> This is also much nicer to deal with in an IDE's editor where you
> often just see the file name on a editor's tab, not the full path.  It
> was confusing to see 6 different "build.gradle" files.  Is there a
> problem with just using the base name of the .gradle file as the
> project name?

I don't think so. I want to use the build file name as the default
project name.

>  Is there a reason to ever change this?
>

Not sure. There will be :)

Until we find out what that reason is, perhaps we don't need a way for a
build file to specify the project name, other than by naming the build
file appropriately. Which removes (for now) the need to the build file
to register a 'project declared' event handler.

> Other configured properties:
> Currently we need to store the gradle files in a subdirectory of the
> project directory to avoid some problems with the location of IDEA's
> source directories.  Please allow both the project and build dirs to
> be configured.
>

Definitely. The question is where and how should it be configured?

>>
>> * Build Script Classpath
>>
>> Again, it makes sense that each project can specify its own
>> classpath. Perhaps, something like:
>>
>> buildclasspath {
>>    repositories { .... }     dependencies {
>>        build name: 'somelib', version: '..'
>>        build group: '..' ...
>>    }
>> }
>>
>> That is, a mini project which allows you specify repositories and
>> dependencies (but maybe not configurations). Like the project
>> descriptor, this closure would be executed as a special step before
>> compiling the build script proper.
>>
>> Some issues:
>>
>> - Do we configure the project descriptor before the build classpath?
>> Or the other way around? That is, can you use the project name in the
>> buildclasspath { } closure, or can you use the classpath in the
>> project { } closure?
>>
>
> We would like to be able to use classes from the buildclasspath inside
> the project closure.  It would be nice to be able to share some of
> this from the root project.  It will be verbose to redefine things
> like the company repo in every build file.  Currently we inject the
> company repo from the root project for the configuration phase so it
> is only specified in one place.  Syntactically it might be nice to
> nest the "buildclasspath" section inside of the root projects
> "projects" section, but this may conflict with my goal of using the
> buildclasspath in the evaluation of this section.
>

If "projects" closure evaluation is not a special event in the life of a
project, ie it is part of the regular build script evaluation, then
everything in the build class-path will be available to the "projects"
closure.

Also, you'll be able to inject configuration into sub projects,
something like:

projects {
    ... declare some projects

    subprojects {
        projectDir = file("projects/$name")
        buildclasspath {
             ... inject the classpath config
        }
    }
}

or

projects {
    whenProjectAdded {
        buildclasspath {
             ... inject the classpath config
        }
    }
    ... declare some projects
}

An alternative to this configuration injection, would be for a project
classloader to extend their parent's classloader. This might be a simple
starting point for now, as I think the classloader graph will need to be
re-done for whatever modularisation solution we come up with in 0.8.

> Thanks for taking the time to think all this through.  This is an
> important step to help gradle scale up to large projects.
>

And thank you for the feedback.


Adam



---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


 « Return to Thread: removing the settings.gradle file