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?

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


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