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.

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

Reply via email to