Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

grunt-sync

Package Overview
Dependencies
Maintainers
1
Versions
25
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

grunt-sync - npm Package Compare versions

Comparing version 0.2.3 to 0.2.4

4

complexity.json

@@ -7,6 +7,6 @@ {

"cyclomatic": 3,
"halstead": 8,
"halstead": 10,
"maintainability": 90
}
}
}
}
/*global module:false*/
module.exports = function(grunt) {
require('time-grunt')(grunt);
module.exports = function (grunt) {
require('time-grunt')(grunt);
// Project configuration.
grunt.initConfig({
// Project configuration.
grunt.initConfig({
files: ['Gruntfile.js', 'tasks/**/*.js', 'test/*.js'],
files: ['Gruntfile.js', 'tasks/**/*.js', 'test/*.js'],
watch: {
all: {
files: '<%= files %>'
}
},
watch: {
all: {
files: '<%= files %>'
}
},
simplemocha: {
all: {
src: 'test/*.js'
}
},
simplemocha: {
all: {
src: 'test/*.js'
}
},
jshint: {
all: '<%= files %>'
},
jshint: {
all: '<%= files %>'
},
sync: grunt.file.readJSON('sync.json'),
sync: grunt.file.readJSON('sync.json'),
complexity: grunt.file.readJSON('complexity.json')
});
grunt.loadNpmTasks('grunt-simple-mocha');
grunt.loadNpmTasks('grunt-complexity');
grunt.loadNpmTasks('grunt-contrib-jshint');
complexity: grunt.file.readJSON('complexity.json')
});
grunt.loadNpmTasks('grunt-simple-mocha');
grunt.loadNpmTasks('grunt-complexity');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.registerTask('default', ['jshint', 'simplemocha', 'complexity']);
grunt.registerTask('default', ['jshint', 'simplemocha', 'complexity']);
// Used for testing only, you shouldn't add this to your code:
grunt.loadTasks('tasks');
// Used for testing only, you shouldn't add this to your code:
grunt.loadTasks('tasks');
};
};
{
"name": "grunt-sync",
"description": "Task to synchronize two directories. Similar to grunt-copy but updates only files that have been changed.",
"version": "0.2.3",
"version": "0.2.4",
"homepage": "https://github.com/tomusdrw/grunt-sync.git",

@@ -30,2 +30,3 @@ "author": {

"scripts": {
"lint": "semistandard",
"test": "mocha"

@@ -45,2 +46,3 @@ },

"mocha": "~1.8.1",
"semistandard": "^6.1.2",
"time-grunt": "^0.4.0"

@@ -47,0 +49,0 @@ },

@@ -16,23 +16,23 @@ # Grunt-sync

```javascript
grunt.initConfig({
grunt.initConfig({
sync: {
main: {
files: [{
cwd: 'src',
src: [
'**', /* Include everything */
'!**/*.txt' /* but exclude txt files */
],
dest: 'bin',
}],
pretend: true, // Don't do any IO. Before you run the task with `updateAndDelete` PLEASE MAKE SURE it doesn't remove too much.
verbose: true // Display log messages when copying files
}
}
sync: {
main: {
files: [{
cwd: 'src',
src: [
'**', /* Include everything */
'!**/*.txt' /* but exclude txt files */
],
dest: 'bin',
}],
pretend: true, // Don't do any IO. Before you run the task with `updateAndDelete` PLEASE MAKE SURE it doesn't remove too much.
verbose: true // Display log messages when copying files
}
}
});
});
grunt.loadNpmTasks('grunt-sync');
grunt.registerTask('default', 'sync');
grunt.loadNpmTasks('grunt-sync');
grunt.registerTask('default', 'sync');
```

@@ -48,6 +48,7 @@

],
verbose: true,
pretend: true, // Don't do any disk operations - just write log
ignoreInDest: "**/*.js", // Never remove js files from destination
updateAndDelete: true // Remove all files from dest that are not found in src
verbose: true, // Default: false
pretend: true, // Don't do any disk operations - just write log. Default: false
failOnError: true, // Fail the task when copying is not possible. Default: false
ignoreInDest: "**/*.js", // Never remove js files from destination. Default: none
updateAndDelete: true // Remove all files from dest that are not found in src. Default: false

@@ -63,3 +64,16 @@ }

## How it works?
In the first phase the plugin compares modification times of files in `src` and `dest`. It only copies files with newer modification time. Second phase deletes files that exists in `dest` but have not been found in `src`.
Details:
1. [1st phase] Read modification time of all files in `src`.
1. [1] Overwrite destination if modification time is newer or destination is directory not file.
1. [2nd phase] Read all files in `dest` and calculate difference between files in destination and source files.
1. [2] Delete all files (and directories) that have been found in `dest` but are not found `src` excluding ignored files.
## Changelog
* 0.2.4 - `failOnError` option
* 0.2.3 - Fixed issue with files defined as array when using `updateAndDelete`.
* 0.2.2 - Fixed issue with `updateAndDelete` when source patterns matches only files.

@@ -66,0 +80,0 @@ * 0.2.1 - Fixed grunt Compact Format.

@@ -1,189 +0,23 @@

var fs = require('promised-io/fs'),
promise = require('promised-io/promise'),
path = require('path'),
glob = require('glob'),
util = require('util'),
_ = require('lodash');
var fs = require('promised-io/fs');
var promise = require('promised-io/promise');
var path = require('path');
var glob = require('glob');
var util = require('util');
var _ = require('lodash');
module.exports = function(grunt) {
module.exports = function (grunt) {
var tryCopy = function(src, dest) {
try {
grunt.file.copy(src, dest);
} catch (e) {
grunt.log.warn('Cannot copy to ' + dest.red);
}
};
grunt.registerMultiTask('sync', 'Synchronize content of two directories.', function () {
var done = this.async();
var logger = grunt[this.data.verbose ? 'log' : 'verbose'];
var updateOnly = !this.data.updateAndDelete;
var justPretend = !!this.data.pretend;
var failOnError = !!this.data.failOnError;
var ignoredPatterns = this.data.ignoreInDest;
var expandedPaths = {};
var tryMkdir = function(dest) {
try {
grunt.file.mkdir(dest);
} catch (e) {
grunt.log.warn('Cannot create directory ' + dest.red);
}
};
var overwriteDest = function(src, dest) {
try {
grunt.file['delete'](dest);
grunt.file.copy(src, dest);
} catch (e) {
grunt.log.warn('Cannot overwrite ' + dest.red);
}
};
var processPair = function(justPretend, logger, src, dest) {
var doOrPretend = function(operation) {
if (justPretend) {
return;
}
operation();
};
var overwriteOrUpdate = function(isSrcDirectory, typeDiffers, srcStat, destStat) {
// If types differ we have to overwrite destination.
if (typeDiffers) {
logger.writeln('Overwriting ' + dest.cyan + ' because type differs.');
doOrPretend(function() {
overwriteDest(src, dest);
});
return;
}
// we can now compare modification dates of files
if (isSrcDirectory || srcStat.mtime.getTime() <= destStat.mtime.getTime()) {
return;
}
logger.writeln('Updating file ' + dest.cyan);
doOrPretend(function() {
// and just update destination
tryCopy(src, dest);
});
};
//stat destination file
return promise.all([fs.stat(src), fs.stat(dest)]).then(function(result) {
var srcStat = result[0],
destStat = result[1];
var isSrcDirectory = srcStat.isDirectory();
var typeDiffers = isSrcDirectory !== destStat.isDirectory();
overwriteOrUpdate(isSrcDirectory, typeDiffers, srcStat, destStat);
}, function() {
// we got an error which means that destination file does not exist
// so make a copy
if (grunt.file.isDir(src)) {
logger.writeln('Creating ' + dest.cyan);
doOrPretend(function() {
tryMkdir(dest);
});
} else {
logger.writeln('Copying ' + src.cyan + ' -> ' + dest.cyan);
doOrPretend(function() {
tryCopy(src, dest);
});
}
});
};
var removePaths = function(justPretend, logger, paths) {
return promise.all(paths.map(function(file) {
return fs.stat(file).then(function(stat) {
return {
file: file,
isDirectory: stat.isDirectory()
};
});
})).then(function(stats) {
var paths = splitFilesAndDirs(stats);
// First we need to process files
return promise.all(paths.files.map(function(filePath) {
logger.writeln('Unlinking ' + filePath.cyan + ' because it was removed from src.');
if (justPretend) {
return;
}
return fs.unlink(filePath);
})).then(function() {
// Then process directories in ascending order
var sortedDirs = paths.dirs.sort(function(a, b) {
return b.length - a.length;
});
return promise.all(sortedDirs.map(function(dir) {
logger.writeln('Removing dir ' + dir.cyan + ' because not longer in src.');
if (justPretend) {
return;
}
return fs.rmdir(dir);
}));
});
});
};
var splitFilesAndDirs = function(stats) {
return stats.reduce(function(memo, stat) {
if (stat.isDirectory) {
memo.dirs.push(stat.file);
} else {
memo.files.push(stat.file);
}
return memo;
}, {
files: [],
dirs: []
});
};
var fastArrayDiff = function(from, diff) {
diff.map(function(v) {
from[from.indexOf(v)] = undefined;
});
return from.filter(function(v) {
return v;
});
};
var convertPathsToSystemSpecific = function(paths) {
return paths.map(function(filePath) {
return path.join.apply(path, filePath.split('/'));
});
};
var addDirectoriesPaths = function(arr, dest) {
var f = dest.split(path.sep);
var i, p;
p = f[0];
for (i = 1; i < f.length - 1; ++i) {
p += path.sep + f[i];
if (arr.indexOf(p) === -1) {
arr.push(p);
}
}
};
grunt.registerMultiTask('sync', 'Synchronize content of two directories.', function() {
var done = this.async(),
logger = grunt[this.data.verbose ? 'log' : 'verbose'],
updateOnly = !this.data.updateAndDelete,
justPretend = !!this.data.pretend,
ignoredPatterns = this.data.ignoreInDest,
expandedPaths = {};
var getExpandedPaths = function(origDest) {
var getExpandedPaths = function (origDest) {
if (!expandedPaths[origDest]) {
// Always include destination as processed.
expandedPaths[origDest] = [origDest.replace(new RegExp("\\" + path.sep + "$"), '')];
expandedPaths[origDest] = [origDest.replace(new RegExp('\\' + path.sep + '$'), '')];
return expandedPaths[origDest];

@@ -194,3 +28,3 @@ }

promise.all(this.files.map(function(fileDef) {
promise.all(this.files.map(function (fileDef) {
var isCompactForm = this.data.src && this.data.dest;

@@ -203,3 +37,3 @@ var cwd = fileDef.cwd ? fileDef.cwd : '.';

return promise.all(fileDef.src.map(function(src) {
return promise.all(fileDef.src.map(function (src) {
var dest;

@@ -219,6 +53,6 @@ // when using expanded mapping dest is the destination file

// Process pair
return processPair(justPretend, logger, path.join(cwd, src), dest);
return processPair(justPretend, failOnError, logger, path.join(cwd, src), dest);
}));
}, this)).then(function() {
}, this)).then(function () {
if (updateOnly) {

@@ -228,7 +62,7 @@ return;

var getDestPaths = function(dest, pattern) {
var getDestPaths = function (dest, pattern) {
var defer = new promise.Deferred();
glob(path.join(dest, pattern), {
dot: true
}, function(err, result) {
}, function (err, result) {
if (err) {

@@ -243,3 +77,3 @@ defer.reject(err);

var getIgnoredPaths = function(dest, ignore) {
var getIgnoredPaths = function (dest, ignore) {
var defer = new promise.Deferred();

@@ -255,10 +89,10 @@ if (!ignore) {

promise.all(ignore.map(function(pattern) {
promise.all(ignore.map(function (pattern) {
return getDestPaths(dest, pattern);
})).then(function(results) {
var flat = results.reduce(function(memo, a) {
})).then(function (results) {
var flat = results.reduce(function (memo, a) {
return memo.concat(a);
}, []);
defer.resolve(flat);
}, function(err) {
}, function (err) {
defer.reject(err);

@@ -271,3 +105,3 @@ });

// Second pass
return promise.all(Object.keys(expandedPaths).map(function(dest) {
return promise.all(Object.keys(expandedPaths).map(function (dest) {
var processedDestinations = convertPathsToSystemSpecific(expandedPaths[dest]);

@@ -282,4 +116,4 @@

return promise.all([destPaths, ignoredPaths, processedDestinations]);
})).then(function(result) {
var files = result.map(function(destAndIgnored) {
})).then(function (result) {
var files = result.map(function (destAndIgnored) {
var paths = convertPathsToSystemSpecific(destAndIgnored[0]);

@@ -289,8 +123,8 @@ var ignoredPaths = convertPathsToSystemSpecific(destAndIgnored[1]);

return [paths, ignoredPaths, destAndIgnored[2]];
}).reduce(function(memo, destAndIgnored) {
return memo.map(function(val, key) {
}).reduce(function (memo, destAndIgnored) {
return memo.map(function (val, key) {
return val.concat(destAndIgnored[key]);
});
}, [[], [], []]);
// TODO Find some faster way to ensure uniqueness here

@@ -305,3 +139,3 @@ var paths = _.uniq(files[0]);

toRemove = fastArrayDiff(toRemove, ignoredPaths);
return removePaths(justPretend, logger, toRemove);

@@ -311,2 +145,176 @@ });

});
function processPair (justPretend, failOnError, logger, src, dest) {
// stat destination file
return promise.all([fs.stat(src), fs.stat(dest)]).then(function (result) {
var srcStat = result[0];
var destStat = result[1];
var isSrcDirectory = srcStat.isDirectory();
var typeDiffers = isSrcDirectory !== destStat.isDirectory();
overwriteOrUpdate(isSrcDirectory, typeDiffers, srcStat, destStat);
}, function () {
// we got an error which means that destination file does not exist
// so make a copy
if (grunt.file.isDir(src)) {
logger.writeln('Creating ' + dest.cyan);
doOrPretend(function () {
tryMkdir(dest);
});
} else {
logger.writeln('Copying ' + src.cyan + ' -> ' + dest.cyan);
doOrPretend(function () {
tryCopy(src, dest);
});
}
});
function doOrPretend (operation) {
if (justPretend) {
return;
}
operation();
}
function warnOrFail (msg) {
if (failOnError) {
grunt.fail.warn(msg);
return;
}
grunt.log.warn(msg);
}
function tryCopy (src, dest) {
try {
grunt.file.copy(src, dest);
} catch (e) {
warnOrFail('Cannot copy to ' + dest.red);
}
}
function tryMkdir (dest) {
try {
grunt.file.mkdir(dest);
} catch (e) {
warnOrFail('Cannot create directory ' + dest.red);
}
}
function overwriteDest (src, dest) {
try {
grunt.file['delete'](dest);
grunt.file.copy(src, dest);
} catch (e) {
warnOrFail('Cannot overwrite ' + dest.red);
}
}
function overwriteOrUpdate (isSrcDirectory, typeDiffers, srcStat, destStat) {
// If types differ we have to overwrite destination.
if (typeDiffers) {
logger.writeln('Overwriting ' + dest.cyan + ' because type differs.');
doOrPretend(function () {
overwriteDest(src, dest);
});
return;
}
// we can now compare modification dates of files
if (isSrcDirectory || srcStat.mtime.getTime() <= destStat.mtime.getTime()) {
return;
}
logger.writeln('Updating file ' + dest.cyan);
doOrPretend(function () {
// and just update destination
tryCopy(src, dest);
});
}
}
function removePaths (justPretend, logger, paths) {
return promise.all(paths.map(function (file) {
return fs.stat(file).then(function (stat) {
return {
file: file,
isDirectory: stat.isDirectory()
};
});
})).then(function (stats) {
var paths = splitFilesAndDirs(stats);
// First we need to process files
return promise.all(paths.files.map(function (filePath) {
logger.writeln('Unlinking ' + filePath.cyan + ' because it was removed from src.');
if (justPretend) {
return;
}
return fs.unlink(filePath);
})).then(function () {
// Then process directories in ascending order
var sortedDirs = paths.dirs.sort(function (a, b) {
return b.length - a.length;
});
return promise.all(sortedDirs.map(function (dir) {
logger.writeln('Removing dir ' + dir.cyan + ' because not longer in src.');
if (justPretend) {
return;
}
return fs.rmdir(dir);
}));
});
});
}
function splitFilesAndDirs (stats) {
return stats.reduce(function (memo, stat) {
if (stat.isDirectory) {
memo.dirs.push(stat.file);
} else {
memo.files.push(stat.file);
}
return memo;
}, {
files: [],
dirs: []
});
}
function fastArrayDiff (from, diff) {
diff.map(function (v) {
from[from.indexOf(v)] = undefined;
});
return from.filter(function (v) {
return v;
});
}
function convertPathsToSystemSpecific (paths) {
return paths.map(function (filePath) {
return path.join.apply(path, filePath.split('/'));
});
}
function addDirectoriesPaths (arr, dest) {
var f = dest.split(path.sep);
var i, p;
p = f[0];
for (i = 1; i < f.length - 1; ++i) {
p += path.sep + f[i];
if (arr.indexOf(p) === -1) {
arr.push(p);
}
}
}
};
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc