Copy subdirectory of fileTree into dest vs top level folder


i have a fileTree. suppose it’s:

      ... (files) ...

i then have a copy closure:

  copy {
    into myDest

on run, what i get is /path/to/myDest/lib/file1.jar.

what i desire is /path/to/myDest/file1.jar. note, no lib is in that path.

it’s not clear to me how to achieve this simple task. thanks!

There’s probably an easier way, but the only way I know is to iterate through all files in the file tree, and add only normal files (no sub-directories):

copy {
    fileTree('lib').each { file ->
        if (file.isFile())
            from file

hey @jvff, thanks. Unfortunately, the code you presented flattens the folder structure. What i’m looking to do instead is move a subdir from within a fileTree to a target.

Ok, that should be easier :slight_smile:

I think you can convert it from a FileTree into a path, then add it with the desired sub-path.

copy {
    from myFileTree.asPath + '/lib'
    into myDest

If you need to obtain the directories in the first level of the file tree, you can transform it into a file and list its contents, adding all directories:

copy {
    myFileTree.singleFile().listFiles().each { entry ->
        if (entry.isDirectory())
            from entry
    into myDest

I’m not sure if the myFile.singleFile() call works. If it doesn’t, you can try file(myFileTree.asPath).

Hope this helps :slight_smile:

from(myFileTree.files) should have the desired effect. It will ‘flatten’ the tree to a set of files

1 Like

There are two opinionated solutions I can see:

The more simplistic solution where one just include the lib part in the from.

copy {
  from "${myLibTree}/lib", {
    include '**'
  into myDest

A more generic solution which will handle deeper paths:

copy {
  from myLIbTree
  into myDest
  eachFile { fcd ->
    def relPath = fcd.relativePath
    if(relPath.lastName == 'lib' && fcd.isDirectory()) {
    } else if(relPath.parent.lastName == 'lib') {
        def segments = relPath.segments
        fcd.relativePath = new RelativePath( !fcd.isDirectory() ,(segments.take(segments.size()-2) + segments[-1]) as String[]  )

The only problem with the second solution is that it leaves a dangling empty lib folder in the destination. It is something I have traditionally solved by adding a doLast { delete '/path/to/lib' } action to the task.

hey @Lance_Java, thank you, however flattened is not desired. ref

awesome! i’ll try the top solution! thx

Hi, sorry, this is an old thread, but it appears in the top result of search machines.

The solution below worked for me:

task copyDirAndFiles(type: Copy) {
  def tree = fileTree('lib') {
    include '**/*'
  from tree
  into 'myDest'

Can this approach be broadened to allow for arbitrary sub-directories to be copied (allowing selective flattening of the structure)?


copy {
    from "myLibTree/*/"
    into "myDest"

I’ve tried a handful of approaches, but haven’t been able to get anything to work.