On Sun, Aug 2, 2009 at 1:21 AM, Adam Murdoch <[email protected]> wrote:
>
>
> John Murph wrote:
>
>> If an external tool (such as an IDE or CI server) wishes to integrate with
>> Gradle, they will need some way to add listeners and perhaps customize other
>> aspects of Gradle. The approach that Ant uses for this is to pass a command
>> line option (-listener <classname>) followed by a fully qualified class
>> name. Ant then uses reflection to instantiate this class and registers it
>> as a build listener. This approach is simple, but very limited. I wish to
>> propose a more complicated, but also more powerful, approach for Gradle.
>>
>> I think Gradle should provide a new command line option (--init-script
>> <path-to-script>). Prior to even finding/loading the settings.gradle file,
>> this script (if specified) would be executed.
>>
>
> Should we default the init script to something under ~/.gradle, maybe
> ~/.gradle/init.gradle or similar?
>
I had thought you might want such a thing. While I'm not a fan of these
"find a script and run it" ideas, I do understand the motivation. My intent
was for tools to use, in which case they will want to specify a script to
run (say, to point to a script that ships as part of the tool). I wonder if
it might not be good to allow both. Basically, run a well known init script
(~/.gradle/init.gradle seems best to me), then also run each script
specified on the command line (the tool might add a --init-script option,
but the user might also specify one... both should be run). Because the
scripts should not depend on each other (nor even know about each other)
this does not seem problematic to me. What do you think?
>
>
> The script would allow tools to run Gradle and point it to a custom init
>> script that allows for customized behavior. This script would be run with a
>> "delegate" (similar to how the Project class is a delegate for the build
>> script) that provides some access to Gradle as well as support for a
>> convenience DSL.
>>
>>
> I'd be tempted to delegate to the Build class. Then, an init script
> configures a Build instance just like a build script configures a Project
> instance. The Build interface would probably need some tweaks for this to
> work. I like that in both cases, the script simply configures a domain
> object.
>
The problem is that Build knows a lot about the setup of the project. This
is good in some ways, but I wanted the init script to run before any other
scripts (even before the settings is evaluated). At that point, some of the
Build methods would not be well defined. Also, this would require
restructuring Gradle some since the build object would need to be
instantiated much earlier. With all of that said, I do agree that making
the script "simply configure a domain object" is a good goal.
>
>
> This class (InitScript.groovy?) would provide access to the
>> startParameters (including allowing them to be modified), and support a
>> simple DSL for instantiating classes using a custom class loader.
>>
>
> For this, I would use exactly the exact same mechanism(s) we use in the
> build script to do this. That is, provide the equivalent of the buildscript
> {} closure, something like:
>
> initscript {
> repositories { mavenCentral() }
> classpath name: 'some-dependency'
> }
>
> I would also make Repository and Configuration containers available, so
> that the script can do whatever custom dependency management and
> classloading it wants.
>
Yes, I was thinking syntactically along those lines as well. Are you
suggesting that the init script would have a "two part" compilation stage,
where it is compiled into two classes, one is run to change the class path,
and then the other is run with that modified classpath? That seems
excessive to me. Much simpler (to me) seems to be the ability to defined
configuration-like things, and then have a method that creates classes using
them. Like this:
configurations { buildListenerConfig }
dependencies { buildListenerConfig 'some-dependency' }
buildListener = buildListenerConfig.create('my.custom.BuildListener')
addListener(buildListener)
>
> This latter would make it easy to register a custom build listener, which
>> is the main intended use. However, as other uses arise, more functionality
>> could be exposed. For instance, the script might wish to examine the
>> environment to determine that it is running in a CI server, and
>> enable/disable specific tasks. To do this, I would assume the script would
>> set system properties that would then be examined in the build scripts when
>> the tasks are defined.
>>
>
> Another option is if the script can register code to execute at various
> times during the lifecycle of the build:
>
> afterProjectsConfigured {
> def isCI = ...
> if ( isCI ) {
> allprojects {
> build.dependsOn uploadArchives
> }
> }
> }
>
> We would allow the init script to receive pretty much any of the events on
> BuildListener in the same way.
I like this much better than my "hack system properties" idea. A rich set
of such event handlers would be awesome.
>
>
> I would like to hear of any real use cases of which you currently are
>> aware.
>>
>
> Some other potential uses for an init script:
>
> - Information about the user, such as repository/app server/database
> authentication information.
> - Personal customisations, such as custom task aliases, logging
> configuration, additional plugins to apply.
> - Information about the environment, such as where JDKs are installed,
> dependency cache configuration, overrides to repository configuration.
1) and 3) seem to call out for a "per-machine" init script like you
suggested above. 2) seems like a 'per-project' script, which might be
better handled via settings.gradle or some such. I would suggest that
settings.gradle and this init idea could collapse into one, but I think the
timing is different. The init script needs to happen first. Then the
settings needs to be found, the buildSrc module built, and settings.gradle
executed (as per my other patch). This is because init wanted to register
listeners that care about the lifecycle of Gradle. On the other handle,
settings.gradle wants to have access to the buildSrc module's classes (we
want it to, anyway). This means it needs to happen during the lifecycle of
Gradle.
>
>
> It would be nice to have a slightly more "complete" implementation
>> initially, but I expect new uses to appear over time. The main problem is
>> that because this script would execute so early in the life of the
>> execution, many objects will not be created yet (such as the tasks in my
>> earlier example).
>>
>
> We can deal with this by registering code to execute later in the build.
> For example, we do this in the build script when you add an action to a
> task.
>
> Some of these cases can be handled more easily than others.
>>
>> Does anyone have any problems or concerns with this proposal?
>>
>
> I think its a good idea. I think there's heaps of potential uses for an
> init script.
>
>
> Adam
>
>
> ---------------------------------------------------------------------
> To unsubscribe from this list, please visit:
>
> http://xircles.codehaus.org/manage_email
>
>
>
--
John Murph
Automated Logic Research Team