On 08/08/2013, at 11:12 PM, Sean Reilly <seanjrei...@gmail.com> wrote:

> On Thu, Aug 8, 2013 at 9:04 PM, Adam Murdoch 
> <adam.murd...@gradleware.com>wrote:
> 
>> 
>> On 09/08/2013, at 12:29 AM, Sean Reilly <seanjrei...@gmail.com> wrote:
>> 
>> Hmm...
>> 
>> I'm pretty sure we're going to need those extra features. I can see using
>> a copy task if you need filtering, but I'll need multiple from.... to...
>> blocks, as that's how you specify where in the target linux system things
>> get copied to:
>> 
>> rpm {
>> 
>>    into('/var/lib/tomcat7/webapps') {
>>        from(war.archivePath)
>>    }
>> 
>>    into('/usr/share/documentation') {
>>        from "${buildDir}/error-codes.txt"
>>        from 'src/test/resources/config/sample.properties'
>>    }
>> 
>>    into('/usr/bin') {
>>        from fileTree("${projectDir}/../scripts") { include('*.groovy') }
>>        fileMode = 0755
>>    }
>> }
>> 
>> That was an example pulled from my project.
>> 
>> Do you think I could implement CopySpec, use a copy task to copy things
>> into a temporary directory (with the absolute paths turned into relative
>> paths), and then walk that directory to build the rpm? It's a lot of
>> copying that really shouldn't be necessary, but I'm struggling to think of
>> a better way….
>> 
>> 
>> I think a better solution would be for us to work together to open up the
>> copy APIs so that people can create their own copy/archive tasks without
>> reimplementing the whole thing or using internal APIs. Are you interested
>> in helping out?
>> 
>> 
> Yes I am, time permitting. I've had an idea — let me try and punch some
> holes in it myself for a bit and then get back to you.

Make sure you check out the code on master. It's moved on quite a lot of 1.7, 
with the goal of simplification. I did a spike of work in this area quite 
recently.

> 
>> 
>> Cheers,
>> 
>> Sean
>> 
>> P.S. I've got to say that I'm a bit disappointed to find out how hard it
>> would be to write my own implementation of Zip without extending the
>> non-public api. There go my dreams of writing Bz2Task. ;-)
>> 
>> 
>> Depends what you want to do exactly. For example, it wouldn't make sense
>> to use the copy infrastructure to implement a task that takes a file and
>> bzips it. You'd just have a task with an input file and an output file.
>> 
>> 
>> 
> That was a joke. I was thinking "produces a .tar.bz2 archive" — momentarily
> forgetting about the Tar task of course. ;-)
> 
> While that comment was entirely intended as a joke, I think that we could
> consider the goal of "open up the copy APIs so that people can create their
> own copy/archive tasks without reimplementing the whole thing or using
> internal APIs" largely complete once the Zip, Copy, and Tar tasks could be
> external plugins.
> 
> 
>> 
>> P.P.S. Thanks so much for all of your help.
>> 
>> 
>> 
>> On Thu, Aug 8, 2013 at 3:14 PM, Luke Daley <luke.da...@gradleware.com>wrote:
>> 
>>> 
>>> On 08/08/2013, at 3:07 PM, Sean Reilly <seanjrei...@gmail.com> wrote:
>>> 
>>>> 
>>>> 
>>>> 
>>>> On Thu, Aug 8, 2013 at 2:29 PM, Luke Daley <luke.da...@gradleware.com>
>>> wrote:
>>>> 
>>>> On 08/08/2013, at 2:01 PM, Sean Reilly <seanjrei...@gmail.com> wrote:
>>>> 
>>>>> Luke,
>>>>> 
>>>>> Thanks for the info. Comments inline:
>>>>> 
>>>>> 
>>>>>>> I'm fine with that if that's really the case, but if so, is it
>>> possible
>>>>>> for Gradle to emit (suitably grave) warnings if a plugin author uses
>>> the
>>>>>> internal api at all? I don't want to use gradle plugins that
>>> drastically
>>>>>> fail when I upgrade to a new version of gradle.
>>>>>> There would be a pretty severe cost on doing this at runtime. It's
>>>>>> something we can look into though. It's not an easy problem to solve.
>>>>> 
>>>>> 
>>>>> Fair enough. Off of the top of my head the only thing that would work
>>> would
>>>>> be some sort of classloader hierarchy for plugins, so that they would
>>> fail
>>>>> period if they tried to access internal packages. I'm sure that this
>>> would
>>>>> get really complicated really quickly, and it would probably just
>>> result in
>>>>> a poor implementation of OSGi. Blech.
>>>> 
>>>> There are long term plans to make a stronger boundary between the
>>> public/internal space.
>>>> 
>>>> However, there is no plan to enforce runtime separation. I personally
>>> (other devs may feel different) don't want to go down this route. 3rd party
>>> code should be allowed to use internal API if they wish, but they take on
>>> the responsibility that comes with that (i.e. no guarantee of any kind of
>>> cross version compatibility).
>>>> 
>>>> I agree with you there.
>>>> 
>>>> 
>>>>> One option I just thought of is a compile-time tool (e.g., a template
>>>>> gradle project that could be used by plugin authors, etc) that warns
>>> when
>>>>> internal classes are used at plugin build time. I don't have time to
>>> build
>>>>> one, and I'm not suggesting that you do either — just registering it
>>> in
>>>>> case someone else brings this up later...
>>>> 
>>>> I like this better, and it's more realistic.
>>>> 
>>>> We need a similar kind of reporting function for use of deprecated API.
>>>> 
>>>> Cool.
>>>> 
>>>> 
>>>>> Internal APIs can change at any time without notice.
>>>>>> Internal classes are under an 'internal' package name space.
>>>>> 
>>>>> 
>>>>> That's fair, but IMO it's only fair if the public, backwards
>>> compatible
>>>>> apis don't depend on (or import) the private ones.
>>>> 
>>>> You're right, more below.
>>>> 
>>>>> I've taken a closer look, and it seems to me that in order to extend
>>>>> AbstractCopyTask (which doesn't look internal, as it's not in any
>>> internal
>>>>> package, right?), you are *required* to implement the getCopyAction()
>>>>> method and return an instance of
>>>>> org.gradle.api.internal.file.copy.CopyActionImpl, which is in the
>>> internal
>>>>> package. So it looks to me like the internal api is 'infecting' the
>>>>> org.gradle.api.tasks namespace.
>>>>> 
>>>> 
>>>>> Is AbstractCopyTask in the wrong package (i.e., should it really be an
>>>>> internal class?),
>>>> 
>>>> It is, but we can't move it because that breaks binary compatibility.
>>>> 
>>>> We have a historical leak with the copy task stuff that will be awkward
>>> until Gradle 2.0. We are in a bit of a mixed state here.
>>>> 
>>>> 
>>>> So we need to maintain the infection of the backwards compatible stuff
>>> with a non-backwards compatible class, to preserve backwards compatibility?
>>> Ouch. This is why I write web services instead of binary APIs. ;-)
>>>> 
>>>> Fair enough. In this case I have a couple of suggestions:
>>>> 
>>>> 1. Deprecate AbstractCopyTask.
>>>> 2. Add a big fat warning to the javadoc/groovydoc so that innocent
>>> plugin writers (as well as not-so-innocent ones like me) know not to use
>>> it. Preferably with a suggested alternative.
>>>> 
>>>>> or is there some other suggested way of writing an
>>>>> archive task other than subclassing
>>> AbstractArchiveTask/AbstractCopyTask?
>>>> 
>>>> Effectively to use composition over inheritance. Subclassing tasks is
>>> problematic, but not always avoidable currently in Gradle.
>>>> 
>>>> After a quick look at the RPM plugin, I can see why the author used
>>> subclassing as it's the most obvious solution to implement. I'm in no way
>>> assigning any blame there.
>>>> 
>>>> However, many other parts of the plugin are using other parts of
>>> uncontentious internal api and will need to change. It's going to have to
>>> be rewritten.
>>>> 
>>>> I imagine so, and since I'm working on a project that uses it, I guess
>>> I'll give it a try and see what happens.
>>>> 
>>>> Any quick advice on the best way to write an archive task that archives
>>> things completely differently? Implement CopySpec? Is there something I can
>>> wrap to do most of the heavy lifting?
>>> 
>>> The only way I can think of to do this and avoid public API is to extend
>>> SourceTask.
>>> 
>>> In your impl, you'd walk the FileTree returned by getSource() and do what
>>> you need with it. In this case, using the RPM builder library that the RPM
>>> plugin is using.
>>> 
>>> This won't be as feature rich copy wise as using a copy task. However, if
>>> someone requires the kind of features that Copy provides in order to
>>> construct the content they can use a dependent task…
>>> 
>>> task rpmContent(type: Copy) {
>>>        from "somewhere"
>>>        into "destination"
>>> }
>>> 
>>> task rpm(type: Rpm) {
>>>        source rpmContent
>>>        // configure rpm options
>>> }
>>> 
>>>> 
>>>> 
>>>>> 
>>>>> Cheers,
>>>>> 
>>>>> Sean
>>>>> 
>>>>> 
>>>>> 
>>>>> On Thu, Aug 8, 2013 at 12:57 PM, Luke Daley <
>>> luke.da...@gradleware.com>wrote:
>>>>> 
>>>>>> 
>>>>>> On 08/08/2013, at 12:13 PM, Sean Reilly <seanjrei...@gmail.com>
>>> wrote:
>>>>>> 
>>>>>>> So it's the plugin author's problem, and that's it?
>>>>>> 
>>>>>> Internal APIs can change at any time without notice.
>>>>>> 
>>>>>> Internal classes are under an 'internal' package name space.
>>>>>> 
>>>>>>> I'm fine with that if that's really the case, but if so, is it
>>> possible
>>>>>> for Gradle to emit (suitably grave) warnings if a plugin author uses
>>> the
>>>>>> internal api at all? I don't want to use gradle plugins that
>>> drastically
>>>>>> fail when I upgrade to a new version of gradle.
>>>>>> 
>>>>>> There would be a pretty severe cost on doing this at runtime. It's
>>>>>> something we can look into though. It's not an easy problem to solve.
>>>>>> 
>>>>>>> And if that's not the case, and using the internal API is sometimes
>>> ok,
>>>>>> is it possible to write a plugin that works with gradle 1.6 and 1.7
>>> without
>>>>>> using resorting to reflection?
>>>>>> 
>>>>>> It depends on exactly how the API is being used. There's no simple
>>> answer
>>>>>> to this question.
>>>>>> 
>>>>>>> 
>>>>>>> Cheers,
>>>>>>> 
>>>>>>> Sean
>>>>>>> 
>>>>>>> 
>>>>>>> On Thu, Aug 8, 2013 at 12:08 PM, Luke Daley <
>>> luke.da...@gradleware.com>
>>>>>> wrote:
>>>>>>> Hi Sean,
>>>>>>> 
>>>>>>> The RPM plugin is using internal API, which changed in this release.
>>>>>>> 
>>>>>>> The RPM plugin will need to be updated.
>>>>>>> 
>>>>>>> On 08/08/2013, at 11:52 AM, Sean Reilly <seanjrei...@gmail.com>
>>> wrote:
>>>>>>> 
>>>>>>>> Hi All,
>>>>>>>> 
>>>>>>>> I'm attempting to upgrade from gradle 1.6 to gradle 1.7, and I
>>> think
>>>>>> I've encountered a potential backwards compatibility issue.
>>>>>>>> 
>>>>>>>> I'm using the RPM plugin as follows:
>>>>>>>> 
>>>>>>>> buildscript {
>>>>>>>>   repositories {
>>>>>>>>       mavenCentral()
>>>>>>>>   }
>>>>>>>>   dependencies {
>>>>>>>>       classpath 'com.trigonic:gradle-rpm-plugin:1.3'
>>>>>>>>   }
>>>>>>>> }
>>>>>>>> 
>>>>>>>> apply plugin: 'war'
>>>>>>>> apply plugin: 'rpm'
>>>>>>>> 
>>>>>>>> task rpm(type: Rpm, dependsOn: war) {
>>>>>>>>   packageName = "blah-${project.name}"
>>>>>>>>   version = "1.0.1"
>>>>>>>>   release = revision
>>>>>>>>   arch = NOARCH
>>>>>>>>   os = LINUX
>>>>>>>>  //more configuration, etc
>>>>>>>> }
>>>>>>>> 
>>>>>>>> Under gradle 1.6, this works fine, but if I run the same script
>>> with
>>>>>> gradle 1.7, the build fails.
>>>>>>>> 
>>>>>>>> 
>>>>>>>> I've included the stack trace below. At first glance it looks like
>>> a
>>>>>> method has been removed from a gradle api class.
>>>>>>>> 
>>>>>>>> Cheers,
>>>>>>>> 
>>>>>>>> Sean
>>>>>>>> 
>>>>>>>> 
>>>>>>>> FAILURE: Build failed with an exception.
>>>>>>>> 
>>>>>>>> * Where:
>>>>>>>> Script '/Users/sreilly/Projects/XXX/build.gradle' line: XXX
>>>>>>>> 
>>>>>>>> * What went wrong:
>>>>>>>> A problem occurred evaluating script.
>>>>>>>>> Could not create task of type 'Rpm'.
>>>>>>>> 
>>>>>>>> * Try:
>>>>>>>> Run with --info or --debug option to get more log output.
>>>>>>>> 
>>>>>>>> * Exception is:
>>>>>>>> org.gradle.api.GradleScriptException: A problem occurred evaluating
>>>>>> script.
>>>>>>>>     at
>>>>>> 
>>> org.gradle.groovy.scripts.internal.DefaultScriptRunnerFactory$ScriptRunnerImpl.run(DefaultScriptRunnerFactory.java:54)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.configuration.DefaultScriptPluginFactory$ScriptPluginImpl.apply(DefaultScriptPluginFactory.java:131)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.api.internal.plugins.DefaultObjectConfigurationAction.applyScript(DefaultObjectConfigurationAction.java:82)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.api.internal.plugins.DefaultObjectConfigurationAction.access$000(DefaultObjectConfigurationAction.java:32)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.api.internal.plugins.DefaultObjectConfigurationAction$1.run(DefaultObjectConfigurationAction.java:54)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.api.internal.plugins.DefaultObjectConfigurationAction.execute(DefaultObjectConfigurationAction.java:114)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.api.internal.project.AbstractPluginAware.apply(AbstractPluginAware.java:39)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.api.internal.BeanDynamicObject$MetaClassAdapter.invokeMethod(BeanDynamicObject.java:248)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.api.internal.BeanDynamicObject.invokeMethod(BeanDynamicObject.java:136)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.api.internal.CompositeDynamicObject.invokeMethod(CompositeDynamicObject.java:147)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.api.internal.project.DefaultProject_Decorated.invokeMethod(Unknown
>>>>>> Source)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.api.internal.project.ProjectScript.apply(ProjectScript.groovy:34)
>>>>>>>>     at org.gradle.api.Script$apply.callCurrent(Unknown Source)
>>>>>>>>     at
>>>>>> 
>>> build_3ouab9f94ai0o2vmdevnmfcojb.run(/Users/sreilly/Projects/TelefonicaInsightServices/smartsteps/rest/build.gradle:4)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.groovy.scripts.internal.DefaultScriptRunnerFactory$ScriptRunnerImpl.run(DefaultScriptRunnerFactory.java:52)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.configuration.DefaultScriptPluginFactory$ScriptPluginImpl.apply(DefaultScriptPluginFactory.java:131)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.configuration.project.BuildScriptProcessor.execute(BuildScriptProcessor.java:38)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.configuration.project.BuildScriptProcessor.execute(BuildScriptProcessor.java:25)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.configuration.project.ConfigureActionsProjectEvaluator.evaluate(ConfigureActionsProjectEvaluator.java:34)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.configuration.project.LifecycleProjectEvaluator.evaluate(LifecycleProjectEvaluator.java:55)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.api.internal.project.AbstractProject.evaluate(AbstractProject.java:469)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.api.internal.project.AbstractProject.evaluate(AbstractProject.java:77)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.configuration.DefaultBuildConfigurer.configure(DefaultBuildConfigurer.java:31)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:142)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:113)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:81)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.launcher.exec.InProcessBuildActionExecuter$DefaultBuildController.run(InProcessBuildActionExecuter.java:64)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.launcher.cli.ExecuteBuildAction.run(ExecuteBuildAction.java:33)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.launcher.cli.ExecuteBuildAction.run(ExecuteBuildAction.java:24)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:35)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:26)
>>>>>>>>     at
>>>>>> org.gradle.launcher.cli.RunBuildAction.run(RunBuildAction.java:50)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.api.internal.Actions$RunnableActionAdapter.execute(Actions.java:171)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:201)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:174)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:170)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:139)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:33)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:22)
>>>>>>>>     at org.gradle.launcher.Main.doAction(Main.java:48)
>>>>>>>>     at
>>>>>> org.gradle.launcher.bootstrap.EntryPoint.run(EntryPoint.java:45)
>>>>>>>>     at org.gradle.launcher.Main.main(Main.java:39)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.launcher.bootstrap.ProcessBootstrap.runNoExit(ProcessBootstrap.java:50)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.launcher.bootstrap.ProcessBootstrap.run(ProcessBootstrap.java:32)
>>>>>>>>     at org.gradle.launcher.GradleMain.main(GradleMain.java:26)
>>>>>>>> Caused by: org.gradle.api.tasks.TaskInstantiationException: Could
>>> not
>>>>>> create task of type 'Rpm'.
>>>>>>>>     at
>>>>>> 
>>> org.gradle.api.internal.project.taskfactory.TaskFactory$1.call(TaskFactory.java:115)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.api.internal.project.taskfactory.TaskFactory$1.call(TaskFactory.java:110)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.api.internal.AbstractTask.injectIntoNewInstance(AbstractTask.java:145)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.api.internal.project.taskfactory.TaskFactory.createTaskObject(TaskFactory.java:110)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.api.internal.project.taskfactory.TaskFactory.createTask(TaskFactory.java:70)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory.createTask(AnnotationProcessingTaskFactory.java:100)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.api.internal.project.taskfactory.DependencyAutoWireTaskFactory.createTask(DependencyAutoWireTaskFactory.java:39)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.api.internal.tasks.DefaultTaskContainer.create(DefaultTaskContainer.java:55)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.api.internal.project.AbstractProject.task(AbstractProject.java:912)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.api.internal.BeanDynamicObject$MetaClassAdapter.invokeMethod(BeanDynamicObject.java:248)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.api.internal.BeanDynamicObject.invokeMethod(BeanDynamicObject.java:136)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.api.internal.CompositeDynamicObject.invokeMethod(CompositeDynamicObject.java:147)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.groovy.scripts.BasicScript.methodMissing(BasicScript.java:83)
>>>>>>>>     at
>>>>>> 
>>> rpm_support_4gv6ia50cgflj085708i87sqoi.run(/Users/sreilly/Projects/TelefonicaInsightServices/smartsteps/rpm-support.gradle:3)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.groovy.scripts.internal.DefaultScriptRunnerFactory$ScriptRunnerImpl.run(DefaultScriptRunnerFactory.java:52)
>>>>>>>>     ... 44 more
>>>>>>>> Caused by: java.lang.NoSuchMethodError:
>>>>>> 
>>> org.gradle.api.internal.file.copy.CopyActionImpl.<init>(Lorg/gradle/api/internal/file/FileResolver;Lorg/gradle/api/internal/file/copy/CopySpecVisitor;)V
>>>>>>>>     at
>>>>>> 
>>> com.trigonic.gradle.plugins.rpm.Rpm$RpmCopyAction.<init>(Rpm.groovy:154)
>>>>>>>>     at com.trigonic.gradle.plugins.rpm.Rpm.<init>(Rpm.groovy:62)
>>>>>>>>     at
>>> com.trigonic.gradle.plugins.rpm.Rpm_Decorated.<init>(Unknown
>>>>>> Source)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.api.internal.DependencyInjectingInstantiator.newInstance(DependencyInjectingInstantiator.java:62)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.api.internal.ClassGeneratorBackedInstantiator.newInstance(ClassGeneratorBackedInstantiator.java:36)
>>>>>>>>     at
>>>>>> 
>>> org.gradle.api.internal.project.taskfactory.TaskFactory$1.call(TaskFactory.java:113)
>>>>>>>>     ... 58 more
>>>>>>>> 
>>>>>>>> 
>>>>>>>> BUILD FAILED
>>>>>>>> 
>>>>>>> 
>>>>>>> --
>>>>>>> Luke Daley
>>>>>>> Principal Engineer, Gradleware
>>>>>>> http://gradleware.com
>>>>>>> 
>>>>>>> 
>>>>>>> 
>>> ---------------------------------------------------------------------
>>>>>>> To unsubscribe from this list, please visit:
>>>>>>> 
>>>>>>>   http://xircles.codehaus.org/manage_email
>>>>>>> 
>>>>>>> 
>>>>>>> 
>>>>>> 
>>>>>> --
>>>>>> Luke Daley
>>>>>> Principal Engineer, Gradleware
>>>>>> http://gradleware.com
>>>>>> 
>>>>>> 
>>>>>> ---------------------------------------------------------------------
>>>>>> To unsubscribe from this list, please visit:
>>>>>> 
>>>>>>   http://xircles.codehaus.org/manage_email
>>>>>> 
>>>>>> 
>>>>>> 
>>>> 
>>>> --
>>>> Luke Daley
>>>> Principal Engineer, Gradleware
>>>> http://gradleware.com
>>>> 
>>>> 
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe from this list, please visit:
>>>> 
>>>>    http://xircles.codehaus.org/manage_email
>>>> 
>>>> 
>>>> 
>>> 
>>> --
>>> Luke Daley
>>> Principal Engineer, Gradleware
>>> http://gradleware.com
>>> 
>>> 
>>> ---------------------------------------------------------------------
>>> To unsubscribe from this list, please visit:
>>> 
>>>    http://xircles.codehaus.org/manage_email
>>> 
>>> 
>>> 
>> 
>> 
>> --
>> Adam Murdoch
>> Gradle Co-founder
>> http://www.gradle.org
>> VP of Engineering, Gradleware Inc. - Gradle Training, Support, Consulting
>> http://www.gradleware.com
>> 
>> 
>> 
>> 

-- 
Luke Daley
Principal Engineer, Gradleware 
http://gradleware.com


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

    http://xircles.codehaus.org/manage_email


Reply via email to