copy tree with gradle and change structure?

2019-03-18 12:26发布

问题:

Can gradle alter the structure of the tree while copying?

original

  • mod/a/src
  • mod/b/src

desired

  • dest/mod-a/source
  • dest/mod-b/source
  • dest/mod-c/source

I'm not sure where I should create a closure and override the copy tree logic

I'd like to do the gradle equivalent of ant's globmapper functionality

<property name="from.dir" location=".."/>      
<property name="to.dir" location="dbutil"/>
<copy>
    <fileset dir="${from.dir}" ... />
    <globmapper from="${from.dir}/*/db" to="${to.dir}"/> 
</copy>

Thanks

Peter

回答1:

When changing file name, rename seems a good approach. When changing path you can override eachFile and modify the destination path.

This works pretty well.

    copy {
    from("${sourceDir}") {
        include 'modules/**/**'
    }
    into(destDir)
    eachFile {details ->

        // Top Level Modules
        def targetPath = rawPathToModulesPath(details.path)
        details.path = targetPath
    }
}
....
def rawPathToModulesPath(def path) {
// Standard case modules/name/src -> module-name/src
def modified=path.replaceAll('modules/([^/]+)/.*src/(java/)?(.*)', {"module-${it[1]}/src/${it[3]}"})
return modified
}


回答2:

The following works, but is there a more gradle-ish way to do this?

    ant.copy(todir: destDir) {
      fileset( dir: "${srcDir}/module", includes: '**/src/**')
      regexpmapper(from: '^(.*)/src/(.*)$', to: /module-\1\/src\/\2/)
    }


回答3:

Please see sample below. Gradle 4.3 does not have rename/move methods, so we can do renaming on the fly.

What was happened:

  1. Load file tree into the memory. I used zip file from dependencies in my example
  2. Filter items, which are in the target folder
  3. All result items will have the same prefix: if we filter files from directory "A/B/C/", then all files will be like "A/B/C/file.txt" or "A/B/C/D/file.txt". E.g. all of them will start with the same words
  4. In the last statement eachFile we will change final name by cutting the directory prefix (e.g. we will cut "A/B/C").
  5. Important: use type of task "Copy", which has optimizations for incremental compilation. Gradle will not do file copy if all of items below are true:
    • Input is the same (for my case - all dependencies of scope "nativeDependenciesScope") with previous build
    • Your function returned the same items with the previous build
    • Destination folder has the same file hashes, with the previous build
task copyNativeDependencies(type: Copy) {
    includeEmptyDirs = false
    def subfolderToUse = "win32Subfolder"

    def nativePack = configurations.nativeDependenciesScope.singleFile // result - single dependency file

    def nativeFiles = zipTree(nativePack).matching { include subfolderToUse + "/*" } // result - filtered file tree

    from nativeFiles
    into 'build/native_libs'
    eachFile {
        print(it.path)

        // we filtered this folder above, e.g. all files will start from the same folder name
        it.path = it.path.replaceFirst("$subfolderToUse/", "")
    }
}

// and don't forget to link this task for something mandatory
test.dependsOn(copyNativeDependencies)
run.dependsOn(copyNativeDependencies)