Venkatesh Nannan
Venkatesh Nannan

Reputation: 1677

How to copy to multiple destinations with Gradle copy task?

I am trying to copy one file to multiple destinations through a Gradle task. I found the following in other websites but I get an ERROR while running this task.

def filesToCopy = copySpec{
    from 'somefile.jar'
    rename {String fileName -> 'anotherfile.jar'}
}

task copyFile(type:Copy) {
    with filesToCopy  {
      into 'dest1/'
    }
    with filesToCopy  {
      into 'dest2/'
    }
}

ERROR

No signature of method: org.gradle.api.internal.file.copy.CopySpecImpl.call() is applicable for argument types

Is there a way to copy to multiple destinations in one Gradle task?

Upvotes: 62

Views: 48364

Answers (7)

Maxim Dorofeev
Maxim Dorofeev

Reputation: 21

For seekers. You can use it. Example:

fun getModulesUsingSubmodule(submoduleName: String): List<String> {
    val result = mutableListOf<String>()
    rootProject.allprojects.forEach { project ->
        project.configurations.forEach { configuration ->
            if (configuration.dependencies.any { dependency -> dependency.name == submoduleName }) {
                result.add(project.name)
            }
        }
    }
    return result
}

tasks.register("copyLiquibaseResourcesToModule") {    
    dependsOn(tasks.processResources)
    val buildSrcDir = layout.buildDirectory.dir("resources/main/liquibase")
    val srcAbsolutePath = buildSrcDir.get().asFile.absolutePath
    val rootProjectName = rootProject.name
    val resourcesPath = "/resources/main/db"

    doFirst {
        val modulesUsingDatabase = getModulesUsingSubmodule(project.name)
        println("Copy resources from '$srcAbsolutePath'")
        modulesUsingDatabase.forEach { moduleName ->

            val targetAbsolutePath: String = if (rootProjectName == moduleName) {
                "${rootProject.buildDir}${resourcesPath}"
            } else {
                "${rootProject.project(":$moduleName").buildDir}${resourcesPath}"
            }

            println("To module '$moduleName' catalog: $targetAbsolutePath")

            copy {
                from(srcAbsolutePath)
                into(targetAbsolutePath)
            }
        }
    }

    doLast {
        println("Clean resources: '$srcAbsolutePath'!")
        delete(buildSrcDir)
    }
}

Upvotes: 0

bdetweiler
bdetweiler

Reputation: 1574

I needed to do this in a particular order to rewrite a particular string on a set of files.

task copyAtoB(dependsOn: [existingTask]) {
    doLast {
        copy {
            from("folder/a") {
                include "*.java"
            }
            // Have to use a new path for modified files
            into("folder/b")
            filter {
                String line ->
                    line.replaceAll("changeme", "to this")
            }
        }
    }
}

task overwriteFilesInAfromB(dependsOn: [copyAtoB]) {
    doLast {
        copy {
            from("folder/b") {
                include "*.java"
            }
            into("folder/a")
        }
    }
}

// Finally, delete the files in folder B
task deleteB(type: Delete, dependsOn: overwriteFilesInAfromB) {
    delete("folder/b")
}

nextTask.dependsOn(deleteB)

Upvotes: 0

Rene Groeschke
Rene Groeschke

Reputation: 28663

no there isn't a way to do that atm. I would create seperate gradle tasks for each target directory

def filesToCopy = copySpec{
    from 'somefile.jar'
    rename {String fileName -> 'anotherfile.jar'}
}

task copyFileDest1(type:Copy) {
    with filesToCopy
    into 'dest1/'
}

task filesToCopyDest2(type:Copy)  {
    with filesToCopy
    into 'dest2/'
}

Upvotes: 14

Alen Vrečko
Alen Vrečko

Reputation: 886

Here is a general snippet without copySpec for Gradle 4.1. As pointed out the trick is to use a base into and use relative into inside the closures (e.g. from closure).

task multiIntoCopy(type: Copy){
    into(projectDir) // copy into relative to this

    from("foo"){
        into("copied/foo") // will be projectDir/copied/foo
        // just standard copy stuff
        rename("a.txt", "x.txt")
    }

    from("bar"){
        into("copied/aswell/bar") //  projectDir/copied/copied/aswell/bar
    }

    from("baz") // baz folder content will get copied into projectDir

    //from("/bar"){ // this will mess things up, be very careful with the paths
    //    into("copied/aswell/bar")
    //}
}

Upvotes: 26

Chriki
Chriki

Reputation: 16408

With a Common Destination Base Path

If your destination paths share a common path prefix (dest_base), then you can use something like this:

def filesToCopy = copySpec {
    from 'somefile.jar'
    rename { String fileName -> 'anotherfile.jar' }
}

task copyFile(type: Copy) {
    into 'dest_base'
    into('dest1') {
      with filesToCopy
    }
    into('dest2') {
      with filesToCopy
    }
}

Compared to other answers which use the copy method, this approach also retains Gradle’s UP-TO-DATE checks.

The above snippet would result in output like this:

dest_base/
├── dest1
│   └── anotherfile.jar
└── dest2
    └── anotherfile.jar

Upvotes: 24

bhdrk
bhdrk

Reputation: 3495

an alternative way

task myCustomTask << {

    copy {
        from 'sourcePath/folderA'
        into 'targetPath/folderA'
    }

    copy {
        from 'sourcePath/folderB'
        into 'targetPath/folderB'
    }

    copy {
        from 'sourcePath/fileA.java','sourcePath/fileB.java'
        into 'targetPath/folderC'
    }
}

Upvotes: 47

ajoberstar
ajoberstar

Reputation: 2585

If you really want them in one task, you do something like this:

def filesToCopy = copySpec {
  from 'someFile.jar'
  rename { 'anotherfile.jar' }
}

task copyFiles << {
  ['dest1', 'dest2'].each { dest ->
    copy {
      with filesToCopy
      into dest
    }
  }
}

Upvotes: 46

Related Questions