diff --git a/lib/runner.js b/lib/runner.js index ff9443b..0ee8865 100644 --- a/lib/runner.js +++ b/lib/runner.js @@ -318,6 +318,9 @@ Runner.prototype.capture_stdin = function(stdin) { if (key === '\u0003') self.interrupted(); + console.log('key', key, self.verbose); + if (key == 'v') self.verbose = !self.verbose; + // write the key to stdout all normal like // process.stdout.write(key); }); diff --git a/lib/sftp.js b/lib/sftp.js new file mode 100644 index 0000000..3995e7d --- /dev/null +++ b/lib/sftp.js @@ -0,0 +1,101 @@ +var connect = require('./connect'), + output = require('./output'); + +function startSFTP(stage, cb) { + + var host = stage.env.primary_host; + if (!host) throw new Error('No primary host set!'); + + var role = find_role_of_host(host); + if (!role) throw new Error('Unable to find host in host list!'); + + var warned_at, + replaced; // real command sent, so we can filter it from the output + + // traverses list of roles and returns the first one where + // the primary host name exists in list of role's hosts + function find_role_of_host() { + for (var name in stage.roles) { + var role = stage.roles[name]; + if (role.host == host || role.hosts.indexOf(host) != -1) + return role; + } + } + + function write(out) { + process.stdout.write(out); + } + + function close(conn) { + output.warn('Closing connection.'); + conn.end(); + + process.stdin.setRawMode(false); + process.stdin.pause(); + } + + function interrupted(conn) { + // if warned less than 3 secs ago, it's bye bye + if (warned_at && ((new Date() - warned_at) < 3000)) + return close(conn); + + output.notice('\n^C quickly if you want to end the session.'); + warned_at = new Date(); + } + + connect.one(host, role, function(err, conn) { + if (err) throw err; + + conn.sftp(function(err, sftp) { + if (err) throw err; + + console.log('SFTP connection established.'); + cb(sftp, onFinished); + + function onFinished() { + close(conn); + } + + process.stdin.on('data', function(key) { + if (key == '\u0004') // Ctrl-D + return close(conn); + + if (key == '\u0003') // Ctrl-C + interrupted(conn); + + // close(conn); + }) + + // without this, we would only get streams once enter is pressed + process.stdin.setRawMode(true); + }) + }) +} + +var transferOpts = { + concurrency: 64, + chunkSize: 32768, + step: function(total_transferred, chunk, total) { + console.log('Got chunk, total transferred: ' + total_transferred); + } +} + +exports.get = function(stage, remote, local) { + output.notice('Getting remote file ' + remote) + startSFTP(stage, function(sftp, done) { + sftp.fastGet(remote, local, transferOpts, function(err) { + output.notice(err ? err.message : 'File successfully received.'); + done(); + }); + }) +} + +exports.put = function(stage, local, remote) { + output.notice('Putting local file ' + local) + startSFTP(stage, function(sftp, done) { + sftp.fastPut(local, remote, transferOpts, function(err) { + output.notice(err ? err.message : 'File successfully sent.'); + done(); + }); + }) +} \ No newline at end of file diff --git a/lib/tasks/copy.js b/lib/tasks/copy.js new file mode 100644 index 0000000..c1d21dd --- /dev/null +++ b/lib/tasks/copy.js @@ -0,0 +1,19 @@ +var fs = require('fs'), + sftp = require('../sftp'); + +function resolveRemotePath(env, path) { + return path[0] == '/' ? path : env.current_path + '/' + path; +} + +exports.description = 'Copy a file to remote server or vice-versa.'; + +exports.run = function(stage, args) { + if (!args[0]) + return console.log('File required, either local or remote.') + + if (fs.existsSync(args[0])) { // local to remote + sftp.put(stage, args[0], resolveRemotePath(stage.env, args[1] || args[0])) + } else { + sftp.get(stage, resolveRemotePath(stage.env, args[0]), args[1] || args[0]) + } +}