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