TrigonicSolutions / gradle-rpm-plugin

Gradle plugin for constructing RPM packages.
Apache License 2.0
38 stars 19 forks source link

Support filter() expression #30

Closed soid closed 10 years ago

soid commented 11 years ago

I tried to use filter() expression do to some replacement in files that are going to rpm, but it didn't work. The code looked like that:

rpm {
    from('scripts') {
        into '/usr/local/myproduct/bin'
        filter({ line ->
            return line//line.replaceAll('{{BASE}}', '/usr/local/myproduct')
        })
    }
    ...

It threw an exception (caught using --stacktrace option):

Caused by: java.lang.UnsupportedOperationException
    at org.gradle.api.internal.file.copy.MappingCopySpecVisitor$FileVisitDetailsImpl.getFile(MappingCopySpecVisitor.java:85)
    at com.trigonic.gradle.plugins.rpm.RpmCopySpecVisitor.visitFile(RpmCopySpecVisitor.groovy:81)
    at org.gradle.api.internal.file.copy.NormalizingCopySpecVisitor.visitFile(NormalizingCopySpecVisitor.java:70)
    at org.gradle.api.internal.file.copy.MappingCopySpecVisitor.visitFile(MappingCopySpecVisitor.java:57)
    at org.gradle.api.internal.file.AbstractFileTree$FilteredFileTree$1.visitFile(AbstractFileTree.java:145)
    at org.gradle.api.internal.file.collections.SingletonFileTree.visit(SingletonFileTree.java:40)
    at org.gradle.api.internal.file.collections.FileTreeAdapter.visit(FileTreeAdapter.java:96)
    at org.gradle.api.internal.file.AbstractFileTree$FilteredFileTree.visit(AbstractFileTree.java:136)
    at org.gradle.api.internal.file.CompositeFileTree.visit(CompositeFileTree.java:54)
    at org.gradle.api.internal.file.copy.CopyActionImpl.execute(CopyActionImpl.java:64)
    at org.gradle.api.tasks.AbstractCopyTask.copy(AbstractCopyTask.java:42)
    at org.gradle.api.internal.BeanDynamicObject$MetaClassAdapter.invokeMethod(BeanDynamicObject.java:196)
    at org.gradle.api.internal.BeanDynamicObject.invokeMethod(BeanDynamicObject.java:102)
    at org.gradle.api.internal.CompositeDynamicObject.invokeMethod(CompositeDynamicObject.java:99)
    at com.trigonic.gradle.plugins.rpm.Rpm_Decorated.invokeMethod(Unknown Source)
    at org.gradle.util.ReflectionUtil.invoke(ReflectionUtil.groovy:23)
    at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$4.execute(AnnotationProcessingTaskFactory.java:150)
    at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$4.execute(AnnotationProcessingTaskFactory.java:145)
    at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:472)
    at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:461)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:60)
    ... 57 more

It would be nice to support this standard in copy task function.

kapuraghav commented 11 years ago

I would like to have this working as well.!!!

quidryan commented 11 years ago

I wrote this test, which throws the UnsupportedOperationException.


    @Test
    void filter_expression() {
        Project project = ProjectBuilder.builder().build()
        project.version = '1.0.0'
        File appleFile = new File(project.buildDir, 'src/apple')
        Files.createParentDirs(appleFile)
        appleFile.text = 'apple'

        project.apply plugin: 'rpm'

        def rpmTask = project.task([type: Rpm], 'buildRpm', {
            from(appleFile.getParentFile()) {
                into '/usr/local/myproduct/bin'
                filter({ line ->
                    return line //line.replaceAll('{{BASE}}', '/usr/local/myproduct')
                })
            }
        })
        rpmTask.execute()
    }

I'll see that MappingCopySpecVisitor explicitly does not allow filter (https://github.com/gradle/gradle/blob/master/subprojects/core/src/main/groovy/org/gradle/api/internal/file/copy/MappingCopySpecVisitor.java#L83). Now the question is how and why MappingCopySpecVisitor got involved.

quidryan commented 11 years ago

Ah, when calling builder.addFile, we're passing in a java.io.File object. But Gradle is telling us that there is no file, since it does the filtering on the fly. We can open the "file" and get an InputStream but there is no concrete File object to point to. We'll have to write the contents of the filter to a tmp directory, since redline doesn't take InputStreams. What is annoying is that it's primarily used by CpioHeader to determine the modification time and the length. I think writing to a temp file is a the best solution, if filterChain.hasFilters(). It possible we can extend File URL, and then re-implement openConnection. We extend File, because FileInputStream requires a real file on the Filesystem.

AlanKrueger commented 11 years ago

Sounds like you have a good start on a fix and a pull request. =)

quidryan commented 11 years ago

:-) I do, but I've got to finish my debian support first, since we need it internally here first. My codebase is also different enough right now that just fixing this one bug on master would be a little hard for me. But I can get back to this later.

quidryan commented 11 years ago

I have a fix for #30, but it's at the end of a long pull request that I'm putting together. I just have the docs left to write.