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