Extending Copy task to support parallel execution

Ultimately, there should be a core gradle task which can copy in parallel. Until this time, it’s possibly easier to write a limited ParallelCopy task from scratch rather extending the Copy task.

Eg:

class ParallelCopy extends DefaultTask {
   private final WorkerExecutor workerExecutor

   @Inject
   ParallelCopy(WorkerExecutor workerExecutor) { this.workerExecutor = workerExecutor; }

   @InputFiles
   private List<FileCollection> froms = []

   @OutputDirectory
   private File into

   public void from(Object from) {
      this.froms << project.files(from)
   }
   public void into(Object into) {
      this.into = project.file(into)
   }
   @TaskAction
   public void parallelCopy() {
      for (FileCollection fc : froms) {
         if (fc instanceof FileTree) {
            ((FileTree) fc).visit { FileVisitDetails fvd ->
               if (!fvd.directory) {
                  File destination = new File(into, fvd.path)
                  submitWorker(fvd.file, destination)
               }
            }
         } else {
            for (File file : fc.files) {
               File destination = new File(into, file.name)
               submitWorker(file, destination)
            }
         }
      }
   }
   private void submitWorker(File source, File destination) {
            workerExecutor.submit(ParallelCopyWorker.class, new Action<WorkerConfiguration>() { 
                @Override
                public void execute(WorkerConfiguration config) {
                    config.setIsolationMode(IsolationMode.NONE); 
                    config.params(source, destination); 
                }
            });
   }

   public static class ParalellCopyWorker implements Runnable {
      private final File source;
      private final File destination;
      @Inject
      public ParalellCopyWorker(File source, File destination) {
         this.source = source;
         this.destination = destination;
      }
      public void run() {
         destination.parentFile.mkdirs()
         destination.bytes = source.bytes // TODO use buffer/stream instead
      }
   }
} 

Usage

task copy1(type:ParallelCopy) {
   from fileTree('somePath').matching { 
      include '**/*.txt'
   }
   from 'another/path'
   into 'some/destination'
}
1 Like