How to get from CopySpec to FileCollection?

I I have an instance of a ‘CopySpec’, how can I get a ‘FileCollection’ or ‘FileTree’ from it.

According to the docs, ‘project.files’ does not list ‘CopySpec’ as a valid object type.

Note that I am no actually trying to perform a copy at this point, just want an iterable collection of files.

If you just want to iterate across the ‘CopySpec’ you could just use ‘eachFile()’.

If you are creating your ‘CopySpec’ as part of an ‘AbstractCopyTask’ then you could call ‘getSource()’ on the task which returns a ‘FileCollection’. Otherwise the only way I can see is to rely on internal APIs to manually resolve the ‘CopySpec’.

I suspect internal API is the only solution.

The below will work

def resourceCopySpec = project.copySpec {
  from('foo') {
    include 'bar/**'
  }
}
  FileCollection fc = (resourceCopySpec as CopySpecInternal).buildRootResolver().allSource
1 Like

Not sure exactly what your use case is but could you instead create a ‘FileTree’ and then a ‘CopySpec’ from the ‘FileTree’?

def resources = fileTree(‘foo’) {

include ‘bar/**’

}

def resourceCopySpec = copySpec {

from resources

}

That is an interesting approach, but I don’t think it will work within this context of the ‘resources’ closures in asciidoctor - https://github.com/asciidoctor/asciidoctor-gradle-plugin/blob/development/README.adoc#handling-additional-files.

It is actually implemented as https://github.com/asciidoctor/asciidoctor-gradle-plugin/blob/development/src/main/groovy/org/asciidoctor/gradle/AsciidoctorTask.groovy#L491

AFAIK with a ‘FileTree’, that once it is created, one cannot add more patterns to it via a closure as one can do for a ‘CopySpec’. I know one can use ‘plus’, but it is not quite the same thing.

My only other though would be to refactor the ‘resources()’ method to delegate to an instance of ‘AbstractCopyTask’ rather than ‘CopySpec’. Then you could just call ‘getSource()’ to return the ‘FileCollection’. A little hokey but technically removes the dependency to the internal API.

Due to the way that a single Asciidoctor task can process multiple backends to multiple output directories, having a copy task is not a good solution in this case. Auto-generating a copy task per backend just becomes too clunky.

(I know some Gradleware devs do not like ‘project.copy’, but this is one example of where it works really well).

You may have misinterpreted what I was trying to describe. My thought was simply to replace the ‘CopySpec’ instance object with a ‘Copy’ task. You would then still treat it like a ‘CopySpec’, passing it to your call to ‘project.copy()’. The advantage would be that it would implement the method ‘getSource()’ in addition to the ‘CopySpec’ interface.

You have definitely given me some food for thought and due to that I also found an alternative way of achieving this as per what the Bintray people did for their plugin:

https://github.com/bintray/gradle-bintray-plugin/blob/master/src/main/groovy/com/jfrog/bintray/gradle/RecordingCopyTask.groovy