javascriptgruntjsgrunt-contrib-copy

Grunt-Contrib-Copy, how to copy contents of a directory keeping the same folder structure without overwriting existing files/folders in dest folder?


Source Structure ``` folder

|----Sub-Folder-1
|    |-a.js
|    |-b.js
|----Sub-Folder-2
|    |-c.js
|-d.js
|-e.js
```

Destination structure before running copy task ``` folder

|----Sub-Folder-1
|    |-a.js
|-e.js
```

I need the destination folder to be exactly the same as src folder but I don't want to overwrite the existing files, like a.js and e.js in the above example already exist so they should not be touched, other files/folders should be created, so I want to recursively check inside 'folder' if a file exists or not and copy it if it doesn't exist. I have been using following filter for not overwriting single files filter: function (filepath) { return !(grunt.file.exists('dest')); } but 'folder consists several subdirectories and files so it is not feasible to write for every file. Please help in writing custom grunt task which can do this .


Solution

  • This can be achieved by adding custom logic inside the filter function of the grunt-contrib-copy target to carry out the following:

    1. Utilize the nodejs path module to help ascertain what the resultant path will be.
    2. Determine whether a file already exists at its destination path by utilizing grunt.file.exists.

    The following gists demonstrates how to achieve your requirement cross-platform:

    Gruntfile.js

    module.exports = function (grunt) {
    
      'use strict';
    
      var path = require('path'); // Load additional built-in node module. 
    
      grunt.loadNpmTasks('grunt-contrib-copy');
    
      grunt.initConfig({
        copy: {
          non_existing: {
            expand: true,
            cwd: 'src/', //       <-- Define as necessary.
            src: [ '**/*.js' ],
            dest: 'dist/', //     <-- Define as necessary.
    
            // Copy file only when it does not exist.
            filter: function (filePath) {
    
              // For cross-platform. When run on Windows any forward slash(s)
              // defined in the `cwd` config path are replaced with backslash(s).
              var srcDir = path.normalize(grunt.config('copy.non_existing.cwd'));
    
              // Combine the `dest` config path value with the
              // `filepath` value excluding the cwd` config path part.
              var destPath = path.join(
                grunt.config('copy.non_existing.dest'),
                filePath.replace(srcDir, '')
              );
    
              // Returns false when the file exists.
              return !(grunt.file.exists(destPath));
            }
          }
        }
      });
    
      grunt.registerTask('default', [ 'copy:non_existing' ]);
    };