From af8d20ea3fc5a1d8ad3eda60047a67c570ebd74e Mon Sep 17 00:00:00 2001 From: Kostas Lekkas Date: Tue, 19 Jul 2016 19:10:26 +0300 Subject: [PATCH 01/12] resin sync/ssh: only accept uuid as destination Also change --port option alias to '-p' from '-t' --- lib/actions/ssh.coffee | 12 +++++------- lib/actions/sync.coffee | 38 ++++++++++++++++++++++++++------------ 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/lib/actions/ssh.coffee b/lib/actions/ssh.coffee index 6a46e659..f02fcb9e 100644 --- a/lib/actions/ssh.coffee +++ b/lib/actions/ssh.coffee @@ -36,7 +36,7 @@ getSubShellCommand = (command) -> } 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`. @@ -44,8 +44,6 @@ module.exports = Use this command to get a shell into the running application container of your device. - The `destination` argument can be either a device uuid or an application name. - Examples: $ resin ssh MyApp @@ -59,7 +57,7 @@ module.exports = signature: 'port' parameter: 'port' description: 'ssh gateway port' - alias: 't' + alias: 'p' , signature: 'verbose' boolean: true @@ -78,11 +76,11 @@ module.exports = verbose = if options.verbose then '-vvv' else '' - resin.models.device.has(params.destination).then (isValidUUID) -> + resin.models.device.has(params.uuid).then (isValidUUID) -> if isValidUUID - return params.destination + return params.uuid - return patterns.inferOrSelectDevice(params.destination) + return patterns.inferOrSelectDevice() .then (uuid) -> console.info("Connecting with: #{uuid}") resin.models.device.get(uuid) diff --git a/lib/actions/sync.coffee b/lib/actions/sync.coffee index a6912c8f..9ab871c4 100644 --- a/lib/actions/sync.coffee +++ b/lib/actions/sync.coffee @@ -15,15 +15,13 @@ limitations under the License. ### module.exports = - signature: 'sync [destination]' + signature: 'sync [uuid]' description: '(beta) sync your changes with a device' help: ''' WARNING: If you're running Windows, this command only supports `cmd.exe`. Use this command to sync your local changes to a certain device on the fly. - The `destination` argument can be either a device uuid or an application name. - You can save all the options mentioned below in a `resin-sync.yml` file, by using the same option names as keys. For example: @@ -82,18 +80,34 @@ module.exports = ] action: (params, options, done) -> resin = require('resin-sdk') + Promise = require('bluebird') resinSync = require('resin-sync') patterns = require('../utils/patterns') + { loadConfig } = require('../utils/helpers') - # TODO: Add comma separated options to Capitano - if options.ignore? - options.ignore = options.ignore.split(',') + Promise.try -> + try + fs.accessSync(path.join(process.cwd(), '.resin-sync.yml')) + catch + if not options.source? + throw new Error('No --source option passed and no \'.resin-sync.yml\' file found in current directory.') - resin.models.device.has(params.destination).then (isValidUUID) -> - if isValidUUID - return params.destination + options.source ?= process.cwd() - return patterns.inferOrSelectDevice(params.destination) - .then (uuid) -> - resinSync.sync(uuid, options) + # TODO: Add comma separated options to Capitano + if options.ignore? + options.ignore = options.ignore.split(',') + + Promise.resolve(params.uuid ? loadConfig(options.source).uuid) + .then (uuid) -> + if not uuid? + return patterns.inferOrSelectDevice() + + resin.models.device.has(uuid) + .then (hasDevice) -> + if not hasDevice + throw new Error("Device not found: #{uuid}") + return uuid + .then (uuid) -> + resinSync.sync(uuid, options) .nodeify(done) From 81d8974213e07f41951f7b26bc0a962d1260eee9 Mon Sep 17 00:00:00 2001 From: Kostas Lekkas Date: Thu, 21 Jul 2016 14:32:57 +0300 Subject: [PATCH 02/12] resin-sync: update to resin-sync@3.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 17bfb05f..52a4a060 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "resin-pine": "^1.3.0", "resin-sdk": "^5.3.5", "resin-settings-client": "^3.5.0", - "resin-sync": "^2.0.2", + "resin-sync": "^3.0.0", "resin-vcs": "^2.0.0", "rimraf": "^2.4.3", "rindle": "^1.0.0", From fdb8bf6967867091456073f0644df786e9986b0f Mon Sep 17 00:00:00 2001 From: Kostas Lekkas Date: Mon, 18 Jul 2016 19:07:07 +0300 Subject: [PATCH 03/12] resin sync: add --destination option and require --source if .resin-sync.yml is missing Closes #359 --- lib/actions/sync.coffee | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/lib/actions/sync.coffee b/lib/actions/sync.coffee index 9ab871c4..66a5f40a 100644 --- a/lib/actions/sync.coffee +++ b/lib/actions/sync.coffee @@ -16,17 +16,21 @@ limitations under the License. module.exports = signature: 'sync [uuid]' - description: '(beta) sync your changes with a device' + description: '(beta) sync your changes to a device' help: ''' WARNING: If you're running Windows, this command only supports `cmd.exe`. Use this command to sync your local changes to a certain device on the fly. - You can save all the options mentioned below in a `resin-sync.yml` file, - by using the same option names as keys. For example: + After every 'resin sync' the updated settings will be saved in + '/.resin-sync.yml' and will be used in later invocations. You can + also change any option by editing '.resin-sync.yml' directly. - $ cat $PWD/resin-sync.yml - source: src/ + Here is an example '.resin-sync.yml' : + + $ cat $PWD/.resin-sync.yml + uuid: 7cf02a6 + destination: '/usr/src/app' before: 'echo Hello' ignore: - .git @@ -36,21 +40,29 @@ module.exports = Notice that explicitly passed command options override the ones set in the configuration file. + Also, if '.gitignore' is found in the source directory then all explicitly listed files will be + excluded from the syncing process. + Examples: - $ resin sync MyApp - $ resin sync 7cf02a6 - $ resin sync 7cf02a6 --port 8080 - $ resin sync 7cf02a6 --ignore foo,bar - $ resin sync 7cf02a6 -v + $ resin sync 7cf02a6 --source '.' --destination '/usr/src/app' + $ resin sync 7cf02a6 -s '/home/user/myResinProject' -d '/usr/src/app' --before 'echo Hello' + $ resin sync --ignore 'lib/' + $ resin sync --verbose false + $ 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' @@ -79,6 +91,8 @@ module.exports = , ] action: (params, options, done) -> + fs = require('fs') + path = require('path') resin = require('resin-sdk') Promise = require('bluebird') resinSync = require('resin-sync') From 10a0924cd71600bc9ac481df32a797359891ea18 Mon Sep 17 00:00:00 2001 From: Kostas Lekkas Date: Thu, 21 Jul 2016 19:31:47 +0300 Subject: [PATCH 04/12] resin sync: load uuid from .resin-sync.yml if possible --- lib/actions/sync.coffee | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/lib/actions/sync.coffee b/lib/actions/sync.coffee index 66a5f40a..4b7c0b6a 100644 --- a/lib/actions/sync.coffee +++ b/lib/actions/sync.coffee @@ -14,6 +14,32 @@ See the License for the specific language governing permissions and limitations under the License. ### +# Loads '.resin-sync.yml' configuration from 'source' directory. +# Returns the configuration object on success +# +# TODO: Use 'config.load()' method from `resin sync` when resin sync gets +# integrated into resin CLI +loadConfig = (source) -> + 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 error + # return empty object if '.resin-sync.yml' is missing + if error.code is 'ENOENT' + return {} + throw error + + if not _.isPlainObject(result) + throw new Error("Invalid configuration file: #{configPath}") + + return result + module.exports = signature: 'sync [uuid]' description: '(beta) sync your changes to a device' @@ -97,7 +123,6 @@ module.exports = Promise = require('bluebird') resinSync = require('resin-sync') patterns = require('../utils/patterns') - { loadConfig } = require('../utils/helpers') Promise.try -> try From 97c768edcd4d9240982b4f6d40adcb18f80cef0b Mon Sep 17 00:00:00 2001 From: Kostas Lekkas Date: Wed, 20 Jul 2016 16:53:41 +0300 Subject: [PATCH 05/12] resin sync: add --skip-gitignore option. Improve help section wording --- lib/actions/sync.coffee | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/lib/actions/sync.coffee b/lib/actions/sync.coffee index 4b7c0b6a..4a546a82 100644 --- a/lib/actions/sync.coffee +++ b/lib/actions/sync.coffee @@ -61,13 +61,12 @@ module.exports = ignore: - .git - node_modules/ - progress: true - verbose: false - Notice that explicitly passed command options override the ones set in the configuration file. + Command line options have precedence over the ones saved in '.resin-sync.yml'. - Also, if '.gitignore' is found in the source directory then all explicitly listed files will be - excluded from the syncing process. + If '.gitignore' is found in the source directory then all explicitly listed files will be + excluded from the syncing process. You can choose to change this default behavior with the + '--skip-gitignore' option. Examples: @@ -94,21 +93,25 @@ module.exports = 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: 'port' parameter: 'port' description: 'ssh port' alias: 't' + , + signature: 'progress' + boolean: true + description: 'show progress' + alias: 'p' , signature: 'verbose' boolean: true From 42d0b52df7ea8f965a90ec5587cb56d47e554c43 Mon Sep 17 00:00:00 2001 From: Kostas Lekkas Date: Wed, 20 Jul 2016 17:24:42 +0300 Subject: [PATCH 06/12] resin ssh: disable ControlMaster ssh option This change was necessary because our ssh gateway does not support ControlMaster mode. Closes #366 --- lib/actions/ssh.coffee | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/actions/ssh.coffee b/lib/actions/ssh.coffee index f02fcb9e..e3f9f358 100644 --- a/lib/actions/ssh.coffee +++ b/lib/actions/ssh.coffee @@ -94,7 +94,11 @@ module.exports = .then ({ username, uuid, containerId }) -> throw new Error('Did not find running application container') if not containerId? Promise.try -> - command = "ssh #{verbose} -t -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \ + 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) From 6b00bbc73a1a05a652d4a56121fab1ea7d175644 Mon Sep 17 00:00:00 2001 From: Kostas Lekkas Date: Tue, 26 Jul 2016 18:01:32 +0300 Subject: [PATCH 07/12] resin sync: add --after option --- lib/actions/sync.coffee | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/actions/sync.coffee b/lib/actions/sync.coffee index 4a546a82..4f75e885 100644 --- a/lib/actions/sync.coffee +++ b/lib/actions/sync.coffee @@ -58,6 +58,7 @@ module.exports = uuid: 7cf02a6 destination: '/usr/src/app' before: 'echo Hello' + after: 'echo Done' ignore: - .git - node_modules/ @@ -71,7 +72,7 @@ module.exports = Examples: $ resin sync 7cf02a6 --source '.' --destination '/usr/src/app' - $ resin sync 7cf02a6 -s '/home/user/myResinProject' -d '/usr/src/app' --before 'echo Hello' + $ resin sync 7cf02a6 -s '/home/user/myResinProject' -d '/usr/src/app' --before 'echo Hello' --after 'echo Done' $ resin sync --ignore 'lib/' $ resin sync --verbose false $ resin sync @@ -102,6 +103,11 @@ module.exports = parameter: 'command' description: 'execute a command before syncing' alias: 'b' + , + signature: 'after' + parameter: 'command' + description: 'execute a command after syncing' + alias: 'a' , signature: 'port' parameter: 'port' From 7bd8a683b21e50b508c39b6deb124e6d39436fff Mon Sep 17 00:00:00 2001 From: Kostas Lekkas Date: Thu, 28 Jul 2016 15:41:34 +0300 Subject: [PATCH 08/12] resin sync: remove quotes from --source/--destination help as it implies they're required Closes #372 --- lib/actions/sync.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/actions/sync.coffee b/lib/actions/sync.coffee index 4f75e885..d467f100 100644 --- a/lib/actions/sync.coffee +++ b/lib/actions/sync.coffee @@ -71,9 +71,9 @@ module.exports = Examples: - $ resin sync 7cf02a6 --source '.' --destination '/usr/src/app' - $ resin sync 7cf02a6 -s '/home/user/myResinProject' -d '/usr/src/app' --before 'echo Hello' --after 'echo Done' - $ resin sync --ignore 'lib/' + $ resin sync 7cf02a6 --source . --destination /usr/src/app + $ resin sync 7cf02a6 -s /home/user/myResinProject -d /usr/src/app --before 'echo Hello' --after 'echo Done' + $ resin sync --ignore lib/ $ resin sync --verbose false $ resin sync ''' From e0a2217b9491c52cac12958c9cee7d7c11e7e7fb Mon Sep 17 00:00:00 2001 From: Kostas Lekkas Date: Thu, 28 Jul 2016 15:50:32 +0300 Subject: [PATCH 09/12] resin sync/ssh: always display selection dialog, even for a single online device Closes #373 --- lib/utils/patterns.coffee | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/utils/patterns.coffee b/lib/utils/patterns.coffee index 254598ec..26770639 100644 --- a/lib/utils/patterns.coffee +++ b/lib/utils/patterns.coffee @@ -161,9 +161,6 @@ exports.inferOrSelectDevice = (applicationName) -> if _.isEmpty(devices) throw new Error('You don\'t have any devices') - if devices.length is 1 - return _.first(devices).uuid - return form.ask message: 'Select a device' type: 'list' From 16a1741374d5c01b7cb1a6a2734a8ad8db938bbe Mon Sep 17 00:00:00 2001 From: Kostas Lekkas Date: Fri, 29 Jul 2016 12:12:56 +0300 Subject: [PATCH 10/12] resin sync: always display device selection dialog when uuid is not passed as an argument Closes #375 --- lib/actions/sync.coffee | 5 +++-- lib/utils/patterns.coffee | 16 +++++++--------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/lib/actions/sync.coffee b/lib/actions/sync.coffee index d467f100..63cf165a 100644 --- a/lib/actions/sync.coffee +++ b/lib/actions/sync.coffee @@ -146,10 +146,11 @@ module.exports = if options.ignore? options.ignore = options.ignore.split(',') - Promise.resolve(params.uuid ? loadConfig(options.source).uuid) + Promise.resolve(params.uuid) .then (uuid) -> if not uuid? - return patterns.inferOrSelectDevice() + savedUuid = loadConfig(options.source).uuid + return patterns.inferOrSelectDevice(savedUuid) resin.models.device.has(uuid) .then (hasDevice) -> diff --git a/lib/utils/patterns.coffee b/lib/utils/patterns.coffee index 26770639..c1ab8a4c 100644 --- a/lib/utils/patterns.coffee +++ b/lib/utils/patterns.coffee @@ -150,21 +150,19 @@ exports.awaitDevice = (uuid) -> console.info("Waiting for #{deviceName} to connect to resin...") poll().return(uuid) -exports.inferOrSelectDevice = (applicationName) -> - Promise.try -> - if applicationName? - return resin.models.device.getAllByApplication(applicationName) - return resin.models.device.getAll() +exports.inferOrSelectDevice = (preferredUuid) -> + resin.models.device.getAll() .filter (device) -> device.is_online - .then (devices) -> - if _.isEmpty(devices) - throw new Error('You don\'t have any devices') + .then (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, (device) -> + default: if preferredUuid in _.map(onlineDevices, 'uuid') then preferredUuid else onlineDevices[0].uuid + choices: _.map onlineDevices, (device) -> return { name: "#{device.name or 'Untitled'} (#{device.uuid.slice(0, 7)})" value: device.uuid From b4edb7ed7ff7cd547852c7dee4aa83c031521892 Mon Sep 17 00:00:00 2001 From: Kostas Lekkas Date: Tue, 19 Jul 2016 19:12:36 +0300 Subject: [PATCH 11/12] 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 From 7fecb53cdfe3a3107ff32f1476cd70d1c3d78a6c Mon Sep 17 00:00:00 2001 From: Kostas Lekkas Date: Thu, 21 Jul 2016 19:35:44 +0300 Subject: [PATCH 12/12] resin sync/ssh: update docs --- doc/cli.markdown | 60 +++++++++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/doc/cli.markdown b/doc/cli.markdown index 10056a1b..c5dfd98b 100644 --- a/doc/cli.markdown +++ b/doc/cli.markdown @@ -69,11 +69,11 @@ Now you have access to all the commands referenced below. - Sync - - [sync [source]](#sync-source-) + - [sync [uuid]](#sync-uuid-) - SSH - - [ssh <uuid>](#ssh-60-uuid-62-) + - [ssh [uuid]](#ssh-uuid-) - Notes @@ -582,65 +582,82 @@ continuously stream output # Sync -## sync [source] +## sync [uuid] WARNING: If you're running Windows, this command only supports `cmd.exe`. Use this command to sync your local changes to a certain device on the fly. -The `source` argument can be either a device uuid or an application name. +After every 'resin sync' the updated settings will be saved in +'/.resin-sync.yml' and will be used in later invocations. You can +also change any option by editing '.resin-sync.yml' directly. -You can save all the options mentioned below in a `resin-sync.yml` file, -by using the same option names as keys. For example: +Here is an example '.resin-sync.yml' : - $ cat $PWD/resin-sync.yml - source: src/ + $ cat $PWD/.resin-sync.yml + uuid: 7cf02a6 + destination: '/usr/src/app' before: 'echo Hello' + after: 'echo Done' ignore: - .git - node_modules/ - progress: true - verbose: false -Notice that explicitly passed command options override the ones set in the configuration file. +Command line options have precedence over the ones saved in '.resin-sync.yml'. + +If '.gitignore' is found in the source directory then all explicitly listed files will be +excluded from the syncing process. You can choose to change this default behavior with the +'--skip-gitignore' option. Examples: - $ resin sync MyApp - $ resin sync 7cf02a6 - $ resin sync 7cf02a6 --port 8080 - $ resin sync 7cf02a6 --ignore foo,bar - $ resin sync 7cf02a6 -v + $ resin sync 7cf02a6 --source . --destination /usr/src/app + $ resin sync 7cf02a6 -s /home/user/myResinProject -d /usr/src/app --before 'echo Hello' --after 'echo Done' + $ resin sync --ignore lib/ + $ resin sync --verbose false + $ resin sync ### Options #### --source, -s <path> -custom source path +local directory path to synchronize to device + +#### --destination, -d <path> + +destination path on device #### --ignore, -i <paths> comma delimited paths to ignore when syncing +#### --skip-gitignore + +do not parse excluded/included files from .gitignore + #### --before, -b <command> execute a command before syncing -#### --progress, -p +#### --after, -a <command> -show progress +execute a command after syncing #### --port, -t <port> ssh port +#### --progress, -p + +show progress + #### --verbose, -v increase verbosity # SSH -## ssh <uuid> +## ssh [uuid] WARNING: If you're running Windows, this command only supports `cmd.exe`. @@ -649,13 +666,14 @@ your device. Examples: + $ resin ssh MyApp $ resin ssh 7cf02a6 $ resin ssh 7cf02a6 --port 8080 $ resin ssh 7cf02a6 -v ### Options -#### --port, -t <port> +#### --port, -p <port> ssh gateway port