From b4edb7ed7ff7cd547852c7dee4aa83c031521892 Mon Sep 17 00:00:00 2001 From: Kostas Lekkas Date: Tue, 19 Jul 2016 19:12:36 +0300 Subject: [PATCH] resin sync/ssh: generate JS --- build/actions/ssh.js | 14 +++--- build/actions/sync.js | 100 ++++++++++++++++++++++++++++++++-------- build/utils/patterns.js | 24 ++++------ 3 files changed, 98 insertions(+), 40 deletions(-) diff --git a/build/actions/ssh.js b/build/actions/ssh.js index 2a53b296..ffa26ca0 100644 --- a/build/actions/ssh.js +++ b/build/actions/ssh.js @@ -35,9 +35,9 @@ limitations under the License. }; module.exports = { - signature: 'ssh [destination]', + signature: 'ssh [uuid]', description: '(beta) get a shell into the running app container of a device', - help: 'WARNING: If you\'re running Windows, this command only supports `cmd.exe`.\n\nUse this command to get a shell into the running application container of\nyour device.\n\nThe `destination` argument can be either a device uuid or an application name.\n\nExamples:\n\n $ resin ssh MyApp\n $ resin ssh 7cf02a6\n $ resin ssh 7cf02a6 --port 8080\n $ resin ssh 7cf02a6 -v', + help: 'WARNING: If you\'re running Windows, this command only supports `cmd.exe`.\n\nUse this command to get a shell into the running application container of\nyour device.\n\nExamples:\n\n $ resin ssh MyApp\n $ resin ssh 7cf02a6\n $ resin ssh 7cf02a6 --port 8080\n $ resin ssh 7cf02a6 -v', permission: 'user', primary: true, options: [ @@ -45,7 +45,7 @@ limitations under the License. signature: 'port', parameter: 'port', description: 'ssh gateway port', - alias: 't' + alias: 'p' }, { signature: 'verbose', boolean: true, @@ -64,11 +64,11 @@ limitations under the License. options.port = 22; } verbose = options.verbose ? '-vvv' : ''; - return resin.models.device.has(params.destination).then(function(isValidUUID) { + return resin.models.device.has(params.uuid).then(function(isValidUUID) { if (isValidUUID) { - return params.destination; + return params.uuid; } - return patterns.inferOrSelectDevice(params.destination); + return patterns.inferOrSelectDevice(); }).then(function(uuid) { console.info("Connecting with: " + uuid); return resin.models.device.get(uuid); @@ -88,7 +88,7 @@ limitations under the License. } return Promise["try"](function() { var command, spawn, subShellCommand; - command = "ssh " + verbose + " -t -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p " + options.port + " " + username + "@ssh." + (settings.get('proxyUrl')) + " enter " + uuid + " " + containerId; + command = "ssh " + verbose + " -t -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ControlMaster=no -p " + options.port + " " + username + "@ssh." + (settings.get('proxyUrl')) + " enter " + uuid + " " + containerId; subShellCommand = getSubShellCommand(command); return spawn = child_process.spawn(subShellCommand.program, subShellCommand.args, { stdio: 'inherit' diff --git a/build/actions/sync.js b/build/actions/sync.js index 2d8b8263..ff84ee6a 100644 --- a/build/actions/sync.js +++ b/build/actions/sync.js @@ -16,38 +16,79 @@ limitations under the License. */ (function() { + var loadConfig; + + loadConfig = function(source) { + var _, config, configPath, error, error1, fs, jsYaml, path, result; + fs = require('fs'); + path = require('path'); + _ = require('lodash'); + jsYaml = require('js-yaml'); + configPath = path.join(source, '.resin-sync.yml'); + try { + config = fs.readFileSync(configPath, { + encoding: 'utf8' + }); + result = jsYaml.safeLoad(config); + } catch (error1) { + error = error1; + if (error.code === 'ENOENT') { + return {}; + } + throw error; + } + if (!_.isPlainObject(result)) { + throw new Error("Invalid configuration file: " + configPath); + } + return result; + }; + module.exports = { - signature: 'sync [destination]', - description: '(beta) sync your changes with a device', - help: 'WARNING: If you\'re running Windows, this command only supports `cmd.exe`.\n\nUse this command to sync your local changes to a certain device on the fly.\n\nThe `destination` argument can be either a device uuid or an application name.\n\nYou can save all the options mentioned below in a `resin-sync.yml` file,\nby using the same option names as keys. For example:\n\n $ cat $PWD/resin-sync.yml\n source: src/\n before: \'echo Hello\'\n ignore:\n - .git\n - node_modules/\n progress: true\n verbose: false\n\nNotice that explicitly passed command options override the ones set in the configuration file.\n\nExamples:\n\n $ resin sync MyApp\n $ resin sync 7cf02a6\n $ resin sync 7cf02a6 --port 8080\n $ resin sync 7cf02a6 --ignore foo,bar\n $ resin sync 7cf02a6 -v', + signature: 'sync [uuid]', + description: '(beta) sync your changes to a device', + help: 'WARNING: If you\'re running Windows, this command only supports `cmd.exe`.\n\nUse this command to sync your local changes to a certain device on the fly.\n\nAfter every \'resin sync\' the updated settings will be saved in\n\'/.resin-sync.yml\' and will be used in later invocations. You can\nalso change any option by editing \'.resin-sync.yml\' directly.\n\nHere is an example \'.resin-sync.yml\' :\n\n $ cat $PWD/.resin-sync.yml\n uuid: 7cf02a6\n destination: \'/usr/src/app\'\n before: \'echo Hello\'\n after: \'echo Done\'\n ignore:\n - .git\n - node_modules/\n\nCommand line options have precedence over the ones saved in \'.resin-sync.yml\'.\n\nIf \'.gitignore\' is found in the source directory then all explicitly listed files will be\nexcluded from the syncing process. You can choose to change this default behavior with the\n\'--skip-gitignore\' option.\n\nExamples:\n\n $ resin sync 7cf02a6 --source . --destination /usr/src/app\n $ resin sync 7cf02a6 -s /home/user/myResinProject -d /usr/src/app --before \'echo Hello\' --after \'echo Done\'\n $ resin sync --ignore lib/\n $ resin sync --verbose false\n $ resin sync', permission: 'user', primary: true, options: [ { signature: 'source', parameter: 'path', - description: 'custom source path', + description: 'local directory path to synchronize to device', alias: 's' + }, { + signature: 'destination', + parameter: 'path', + description: 'destination path on device', + alias: 'd' }, { signature: 'ignore', parameter: 'paths', description: 'comma delimited paths to ignore when syncing', alias: 'i' + }, { + signature: 'skip-gitignore', + boolean: true, + description: 'do not parse excluded/included files from .gitignore' }, { signature: 'before', parameter: 'command', description: 'execute a command before syncing', alias: 'b' }, { - signature: 'progress', - boolean: true, - description: 'show progress', - alias: 'p' + signature: 'after', + parameter: 'command', + description: 'execute a command after syncing', + alias: 'a' }, { signature: 'port', parameter: 'port', description: 'ssh port', alias: 't' + }, { + signature: 'progress', + boolean: true, + description: 'show progress', + alias: 'p' }, { signature: 'verbose', boolean: true, @@ -56,20 +97,43 @@ limitations under the License. } ], action: function(params, options, done) { - var patterns, resin, resinSync; + var Promise, fs, path, patterns, resin, resinSync; + fs = require('fs'); + path = require('path'); resin = require('resin-sdk'); + Promise = require('bluebird'); resinSync = require('resin-sync'); patterns = require('../utils/patterns'); - if (options.ignore != null) { - options.ignore = options.ignore.split(','); - } - return resin.models.device.has(params.destination).then(function(isValidUUID) { - if (isValidUUID) { - return params.destination; + return Promise["try"](function() { + var error1; + try { + fs.accessSync(path.join(process.cwd(), '.resin-sync.yml')); + } catch (error1) { + if (options.source == null) { + throw new Error('No --source option passed and no \'.resin-sync.yml\' file found in current directory.'); + } } - return patterns.inferOrSelectDevice(params.destination); - }).then(function(uuid) { - return resinSync.sync(uuid, options); + if (options.source == null) { + options.source = process.cwd(); + } + if (options.ignore != null) { + options.ignore = options.ignore.split(','); + } + return Promise.resolve(params.uuid).then(function(uuid) { + var savedUuid; + if (uuid == null) { + savedUuid = loadConfig(options.source).uuid; + return patterns.inferOrSelectDevice(savedUuid); + } + return resin.models.device.has(uuid).then(function(hasDevice) { + if (!hasDevice) { + throw new Error("Device not found: " + uuid); + } + return uuid; + }); + }).then(function(uuid) { + return resinSync.sync(uuid, options); + }); }).nodeify(done); } }; diff --git a/build/utils/patterns.js b/build/utils/patterns.js index 33b60be6..0fb977f7 100644 --- a/build/utils/patterns.js +++ b/build/utils/patterns.js @@ -16,7 +16,8 @@ limitations under the License. */ (function() { - var Promise, _, chalk, form, messages, resin, validation, visuals; + var Promise, _, chalk, form, messages, resin, validation, visuals, + indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; _ = require('lodash'); @@ -191,25 +192,18 @@ limitations under the License. }); }; - exports.inferOrSelectDevice = function(applicationName) { - return Promise["try"](function() { - if (applicationName != null) { - return resin.models.device.getAllByApplication(applicationName); - } - return resin.models.device.getAll(); - }).filter(function(device) { + exports.inferOrSelectDevice = function(preferredUuid) { + return resin.models.device.getAll().filter(function(device) { return device.is_online; - }).then(function(devices) { - if (_.isEmpty(devices)) { - throw new Error('You don\'t have any devices'); - } - if (devices.length === 1) { - return _.first(devices).uuid; + }).then(function(onlineDevices) { + if (_.isEmpty(onlineDevices)) { + throw new Error('You don\'t have any devices online'); } return form.ask({ message: 'Select a device', type: 'list', - choices: _.map(devices, function(device) { + "default": indexOf.call(_.map(onlineDevices, 'uuid'), preferredUuid) >= 0 ? preferredUuid : onlineDevices[0].uuid, + choices: _.map(onlineDevices, function(device) { return { name: (device.name || 'Untitled') + " (" + (device.uuid.slice(0, 7)) + ")", value: device.uuid