From 0f09c8470369127fab807cb89dfa58a3537598f8 Mon Sep 17 00:00:00 2001 From: Jaroslav Moravec Date: Wed, 2 Mar 2016 10:41:46 +0100 Subject: [PATCH 1/4] Not password prompt when options.agent is set --- tasks/scp.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/scp.js b/tasks/scp.js index 2460fb3..26d4dcb 100644 --- a/tasks/scp.js +++ b/tasks/scp.js @@ -93,7 +93,7 @@ module.exports = function(grunt) { }); } - if (options.password || options.privateKey) { + if (options.password || options.privateKey || options.agent) { execUploads(); } else { inquirer.prompt([{ From aa39253fbf3ee8a775421dedb291952652a46a91 Mon Sep 17 00:00:00 2001 From: Jaroslav Moravec Date: Wed, 2 Mar 2016 13:08:36 +0100 Subject: [PATCH 2/4] Log transfers only in --verbose mode. --- package.json | 7 ++++--- tasks/scp.js | 18 +++++++++++------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index d0e88c4..55c38e6 100644 --- a/package.json +++ b/package.json @@ -29,8 +29,9 @@ }, "dependencies": { "async": "~0.2.6", - "scp2": "~0.1.4", - "inquirer": "~0.3.5" + "chalk": "^1.1.1", + "inquirer": "~0.3.5", + "scp2": "~0.1.4" }, "devDependencies": { "grunt-contrib-jshint": "^0.9.2", @@ -44,4 +45,4 @@ "keywords": [ "gruntplugin" ] -} \ No newline at end of file +} diff --git a/tasks/scp.js b/tasks/scp.js index 26d4dcb..1acddaa 100644 --- a/tasks/scp.js +++ b/tasks/scp.js @@ -12,6 +12,7 @@ var path = require('path'); var async = require('async'); var Client = require('scp2').Client; var inquirer = require('inquirer'); +var chalk = require('chalk'); module.exports = function(grunt) { @@ -25,22 +26,24 @@ module.exports = function(grunt) { var filename, destfile; var client = new Client(options); var files = this.files; + var uploadedFiles = 0; client.on('connect', function() { - grunt.log.writeln('ssh connect ' + options.host); + grunt.verbose.writeln('ssh connect ' + options.host); }); client.on('keyboard-interactive', function(name, instructions, instructionsLang, prompts, finish) { finish([options.password]); }); client.on('close', function() { - grunt.log.writeln('ssh close ' + options.host); + grunt.verbose.writeln('ssh close ' + options.host); + grunt.log.writeln("\nUploaded " + chalk.cyan(uploadedFiles) + " " + (uploadedFiles > 1 ? "files" : "file") ); done(); }); client.on('mkdir', function(dir) { - grunt.log.writeln('mkdir ' + dir); + grunt.verbose.writeln('mkdir ' + dir); }); client.on('write', function(o) { - grunt.log.writeln('write ' + o.destination); + grunt.verbose.writeln('write ' + o.destination).or.write('.'); if (options.log) { options.log(o); } @@ -49,12 +52,13 @@ module.exports = function(grunt) { up = up + 1; if (up < total) { if ((Math.floor(up / 550)) === (up / 550)) { - grunt.log.writeln('transfer ' + Math.floor(up / total * 100) + '% data'); + grunt.verbose.writeln('transfer ' + Math.floor(up / total * 100) + '% data'); } else if (up === 1) { - grunt.log.writeln('transfer 1% data'); + grunt.verbose.writeln('transfer 1% data'); } } else { - grunt.log.writeln('transfer ' + Math.floor(up / total * 100) + '% data'); + grunt.verbose.writeln('transfer ' + Math.floor(up / total * 100) + '% data'); + uploadedFiles++; } }); client.on('error', function(err) { From ead7e9fe0b9e14f878305f51baeed87d189246fc Mon Sep 17 00:00:00 2001 From: Jaroslav Moravec Date: Wed, 2 Mar 2016 14:04:08 +0100 Subject: [PATCH 3/4] Basic support for uploading only newer files --- .gitignore | 1 + tasks/scp.js | 50 +++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 3023049..f216162 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,6 @@ node_modules npm-debug.log *.iml .idea +.cache test/tmp \ No newline at end of file diff --git a/tasks/scp.js b/tasks/scp.js index 1acddaa..1a1346b 100644 --- a/tasks/scp.js +++ b/tasks/scp.js @@ -13,6 +13,7 @@ var async = require('async'); var Client = require('scp2').Client; var inquirer = require('inquirer'); var chalk = require('chalk'); +var fs = require('fs'); module.exports = function(grunt) { @@ -27,6 +28,12 @@ module.exports = function(grunt) { var client = new Client(options); var files = this.files; var uploadedFiles = 0; + var skippedFiles = 0; + + var cacheDir = path.join(__dirname, '..', '.cache'); + var cacheFile = path.join(cacheDir, this.nameArgs.replace(/:/g, '.') + '.json'); + var cache = initCache(); + client.on('connect', function() { grunt.verbose.writeln('ssh connect ' + options.host); @@ -36,7 +43,6 @@ module.exports = function(grunt) { }); client.on('close', function() { grunt.verbose.writeln('ssh close ' + options.host); - grunt.log.writeln("\nUploaded " + chalk.cyan(uploadedFiles) + " " + (uploadedFiles > 1 ? "files" : "file") ); done(); }); client.on('mkdir', function(dir) { @@ -71,13 +77,45 @@ module.exports = function(grunt) { return false; }); + function initCache () { + if (!options.newer) { + return false; + } + if (!grunt.file.exists(cacheDir)) { + fs.mkdir(cacheDir); + } + return grunt.file.exists(cacheFile) ? grunt.file.readJSON(cacheFile) : {}; + } + function shouldUpload (filepath) { + if (!options.newer) { + return true; + } + stats = fs.statSync(filepath); + if (cache.hasOwnProperty(filepath) && cache[filepath] === stats.ctime.toJSON()) { + return false; + } + cache[filepath] = stats.ctime; + return true; + } + function storeCache () { + if (!options.newer) { + return; + } + grunt.file.write(cacheFile, JSON.stringify(cache)); + } + function execUploads() { + initCache(); async.eachSeries(files, function(fileObj, cb) { upload(fileObj, cb); }, function(err) { if (err) { grunt.log.error('Error ' + err); } + grunt.log.writeln((uploadedFiles > 0 ? "\n" : "") + + "Uploaded " + chalk.cyan(uploadedFiles) + " " + (uploadedFiles !== 1 ? "files" : "file") + + " skipped " + chalk.cyan(skippedFiles) + " " + (skippedFiles !== 1 ? "files" : "file")); + storeCache(); client.close(); }); } @@ -90,8 +128,14 @@ module.exports = function(grunt) { } else { filename = path.relative(fileObj.orig.cwd, filepath); } - destfile = path.join(fileObj.dest, filename); - client.upload(filepath, destfile, cb); + if (shouldUpload(filepath)) { + destfile = path.join(fileObj.dest, filename); + client.upload(filepath, destfile, cb); + } else { + grunt.verbose.writeln(filepath + "...skipped"); + skippedFiles++; + cb.call(null); + } }, function(err) { cb(err); }); From 4a259fa225b979775ed4315e4853c8db359e82d4 Mon Sep 17 00:00:00 2001 From: Jaroslav Moravec Date: Wed, 2 Mar 2016 15:38:31 +0100 Subject: [PATCH 4/4] Cache changed to object and is controled by additional task arguments. --- README.md | 29 ++++++++++++++++++++ tasks/scp.js | 77 ++++++++++++++++++++++++++++++---------------------- 2 files changed, 73 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 6dfd40e..f16876a 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,35 @@ Type: `Function` Read more: https://github.com/mscdex/ssh2#connection-methods +### Task arguments + +You can control uploading only newer files to server and clean cache of uploaded files. +This additional arguments can be added only to task with specified target. + +#### :newer +Uploads only file which has been changed after previous upload. + +#### :clean +Cleans cache of uploaded files. Uploads all specified files. + +#### Examples + +on command line +``` +grunt scp:your_target:newer +grunt scp:your_target:clean +``` + +in gruntfile +```js +grunt.task.run('scp:your_target:newer'); +``` + +WARNING! Next example fails because there is no specified target. +``` +grunt scp:newer +``` + ## Changelog **2013-11-14** `0.1.6` diff --git a/tasks/scp.js b/tasks/scp.js index 1a1346b..78d8daf 100644 --- a/tasks/scp.js +++ b/tasks/scp.js @@ -23,6 +23,9 @@ module.exports = function(grunt) { tryKeyboard: true }); + var ARG_NEWER = 'newer'; + var ARG_CLEAN = 'clean'; + var done = this.async(); var filename, destfile; var client = new Client(options); @@ -30,10 +33,46 @@ module.exports = function(grunt) { var uploadedFiles = 0; var skippedFiles = 0; - var cacheDir = path.join(__dirname, '..', '.cache'); - var cacheFile = path.join(cacheDir, this.nameArgs.replace(/:/g, '.') + '.json'); - var cache = initCache(); + var cache = new (function (name, args) { + + var newer = args.indexOf(ARG_NEWER) !== -1; + var clean = args.indexOf(ARG_CLEAN) !== -1; + + this.dir = path.join(__dirname, '..', '.cache'); + this.file = path.join(this.dir, (name || 'scp') + '.json'); + this.data = {}; + + this.isUpToDate = function (filepath) { + stats = fs.statSync(filepath); + if (!clean && newer && (this.data.hasOwnProperty(filepath) && this.data[filepath] === stats.ctime.toJSON())) { + return true; + } + this.data[filepath] = stats.ctime; + return false; + }; + + this.store = function () { + if (!clean) { + grunt.file.write(this.file, JSON.stringify(this.data)); + } + }; + + this.clean = function () { + if (grunt.file.exists(this.file)) { + grunt.file.delete(this.file); + } + }; + + /** CONSTRUCTOR **/ + if (clean) { + this.clean(); + } + if (!grunt.file.exists(this.dir)) { + fs.mkdir(this.dir); + } + this.data = grunt.file.exists(this.file) ? grunt.file.readJSON(this.file) : {}; + })(this.target, this.args); client.on('connect', function() { grunt.verbose.writeln('ssh connect ' + options.host); @@ -77,35 +116,7 @@ module.exports = function(grunt) { return false; }); - function initCache () { - if (!options.newer) { - return false; - } - if (!grunt.file.exists(cacheDir)) { - fs.mkdir(cacheDir); - } - return grunt.file.exists(cacheFile) ? grunt.file.readJSON(cacheFile) : {}; - } - function shouldUpload (filepath) { - if (!options.newer) { - return true; - } - stats = fs.statSync(filepath); - if (cache.hasOwnProperty(filepath) && cache[filepath] === stats.ctime.toJSON()) { - return false; - } - cache[filepath] = stats.ctime; - return true; - } - function storeCache () { - if (!options.newer) { - return; - } - grunt.file.write(cacheFile, JSON.stringify(cache)); - } - function execUploads() { - initCache(); async.eachSeries(files, function(fileObj, cb) { upload(fileObj, cb); }, function(err) { @@ -115,7 +126,7 @@ module.exports = function(grunt) { grunt.log.writeln((uploadedFiles > 0 ? "\n" : "") + "Uploaded " + chalk.cyan(uploadedFiles) + " " + (uploadedFiles !== 1 ? "files" : "file") + " skipped " + chalk.cyan(skippedFiles) + " " + (skippedFiles !== 1 ? "files" : "file")); - storeCache(); + cache.store(); client.close(); }); } @@ -128,7 +139,7 @@ module.exports = function(grunt) { } else { filename = path.relative(fileObj.orig.cwd, filepath); } - if (shouldUpload(filepath)) { + if (!cache.isUpToDate(filepath)) { destfile = path.join(fileObj.dest, filename); client.upload(filepath, destfile, cb); } else {