From 2c6f1d40523b4a7c5c8b210323c8a41ec047436e Mon Sep 17 00:00:00 2001 From: Rick Waldron Date: Wed, 20 Jul 2016 15:50:10 -0400 Subject: [PATCH] run/push: support "subargs" for forwarding to remote process. Fixes gh-732 Uses the "subarg" syntax: t2 run index.js [foo bar baz -a 1 -b 2 --named --key=value] Will result in process.argv on the deployed program: [ '/usr/bin/node', '/tmp/remote-script/index.js', 'foo', 'bar', 'baz', '-a', '1', '-b', '2', '--named', '--key=value' ] Signed-off-by: Rick Waldron --- bin/tessel-2.js | 37 +++++++++++++++++++++++++++++ lib/tessel/commands.js | 6 ++--- lib/tessel/deploy.js | 4 +++- lib/tessel/deployment/javascript.js | 4 ++-- lib/tessel/deployment/python.js | 4 ++-- lib/tessel/deployment/rust.js | 4 ++-- test/unit/deploy.js | 12 +++++++--- test/unit/deployment/javascript.js | 30 ++++++++++++++++++++--- 8 files changed, 85 insertions(+), 16 deletions(-) diff --git a/bin/tessel-2.js b/bin/tessel-2.js index 8543c9e3..fe15c329 100755 --- a/bin/tessel-2.js +++ b/bin/tessel-2.js @@ -186,6 +186,10 @@ makeCommand('run') // Overridden in tarBundle if options.full is `true` options.slim = true; + if (parser.subargs) { + options.subargs = parser.subargs; + } + callControllerWith('deploy', options); }) .option('entryPoint', { @@ -241,6 +245,7 @@ makeCommand('push') options.push = true; // Overridden in tarBundle if options.full is `true` options.slim = true; + options.subargs = parser.subargs || []; callControllerWith('deploy', options); }) @@ -516,6 +521,38 @@ makeCommand('root') module.exports = function(args) { + var sIndexOfSA = -1; + var eIndexOfSA = -1; + + // Check to see if there are any subargs... + for (var i = 0; i < args.length; i++) { + var arg = args[i]; + + if (arg.startsWith('[') && sIndexOfSA === -1) { + // Remove the leading '[', replace existing + args[i] = arg.slice(1, arg.length); + sIndexOfSA = i; + } + + if (arg.endsWith(']') && sIndexOfSA !== -1) { + // Remove the trailing ']' + args[i] = arg.slice(0, arg.length - 1); + eIndexOfSA = i; + } + } + + // If there are, remove them from the `args` + // that get passed to parser.parse(). + // + // If these are not removed, they will be + // treated like they are part of the t2-cli args + // themselves, which is undesirable. + if (sIndexOfSA !== -1 && eIndexOfSA !== -1) { + // Splice the subargs from the args that will be passed to nomnom, + // store on parser so we can get to them later. + parser.subargs = args.splice(sIndexOfSA, eIndexOfSA); + } + // Clear the spec from one call to the next. This is // only necessary for testing the CLI (each call must be "fresh") parser.specs = {}; diff --git a/lib/tessel/commands.js b/lib/tessel/commands.js index 71674845..50705f61 100644 --- a/lib/tessel/commands.js +++ b/lib/tessel/commands.js @@ -18,15 +18,15 @@ module.exports.app = { * */ module.exports.js = { - execute: (filepath, relpath) => ['node', filepath + relpath], + execute: (filepath, relpath, args) => ['node', filepath + relpath].concat(args), }; module.exports.rs = { - execute: (filepath, relpath) => [filepath + relpath], + execute: (filepath, relpath, args) => [filepath + relpath].concat(args), }; module.exports.py = { - execute: (filepath, relpath) => ['python', filepath + relpath], + execute: (filepath, relpath, args) => ['python', filepath + relpath].concat(args), }; module.exports.readFile = function(filepath) { diff --git a/lib/tessel/deploy.js b/lib/tessel/deploy.js index 08bc6910..7976a3c4 100644 --- a/lib/tessel/deploy.js +++ b/lib/tessel/deploy.js @@ -124,6 +124,7 @@ Tessel.prototype.deploy = function(opts) { // Resolve the application's language/runtime opts.lang = deployment.resolveLanguage(opts.lang || opts.entryPoint); + opts.subargs = opts.subargs || []; return new Promise((resolve, reject) => { // Stop running an existing applications @@ -373,7 +374,7 @@ exportables.run = function(tessel, options) { return preRun.then(() => { tessel.connection.exec( - commands[lang.meta.extname].execute(Tessel.REMOTE_RUN_PATH, options.resolvedEntryPoint), { + commands[lang.meta.extname].execute(Tessel.REMOTE_RUN_PATH, options.resolvedEntryPoint, options.subargs), { pty: true }, (error, remoteProcess) => { if (error) { @@ -438,6 +439,7 @@ exportables.createShellScript = function(tessel, opts) { }); }); }); + remoteProcess.stdin.end(new Buffer(opts.lang.meta.shell(opts).trim())); }); }); diff --git a/lib/tessel/deployment/javascript.js b/lib/tessel/deployment/javascript.js index b4c9abb9..0b6a05e8 100644 --- a/lib/tessel/deployment/javascript.js +++ b/lib/tessel/deployment/javascript.js @@ -53,10 +53,10 @@ var exportables = { program }; }, - shell: (opts) => { + shell: (options) => { return tags.stripIndent ` #!/bin/sh - exec node /app/remote-script/${opts.resolvedEntryPoint} + exec node /app/remote-script/${options.resolvedEntryPoint} ${options.subargs.join(' ')} `; }, }, diff --git a/lib/tessel/deployment/python.js b/lib/tessel/deployment/python.js index 89a2c96a..11515a98 100644 --- a/lib/tessel/deployment/python.js +++ b/lib/tessel/deployment/python.js @@ -33,10 +33,10 @@ var exportables = { program }; }, - shell: (opts) => { + shell: (options) => { return tags.stripIndent ` #!/bin/sh - exec python /app/remote-script/${opts.resolvedEntryPoint} + exec python /app/remote-script/${options.resolvedEntryPoint} ${options.subargs.join(' ')} `; }, }, diff --git a/lib/tessel/deployment/rust.js b/lib/tessel/deployment/rust.js index 52e7f095..35e064b2 100644 --- a/lib/tessel/deployment/rust.js +++ b/lib/tessel/deployment/rust.js @@ -37,10 +37,10 @@ var exportables = { program }; }, - shell: (opts) => { + shell: (options) => { return tags.stripIndent ` #!/bin/sh - exec /app/remote-script/${opts.resolvedEntryPoint} + exec /app/remote-script/${options.resolvedEntryPoint} ${options.subargs.join(' ')} `; }, }, diff --git a/test/unit/deploy.js b/test/unit/deploy.js index be9a6545..e1a31d16 100644 --- a/test/unit/deploy.js +++ b/test/unit/deploy.js @@ -284,7 +284,8 @@ exports['Tessel.prototype.deploy'] = { test.expect(12); deployTestCode(this.tessel, { push: true, - single: false + single: false, + subargs: [], }, (error) => { if (error) { test.ok(false, `deployTestCode failed: ${error.toString()}`); @@ -538,8 +539,10 @@ exports['deploy.run'] = { deploy.run(this.tessel, { entryPoint: entryPoint, lang: deployment.js, + subargs: ['--key=value'], }).then(() => { - test.deepEqual(this.exec.lastCall.args[0], [deployment.js.meta.binary, Tessel.REMOTE_RUN_PATH + entryPoint]); + test.deepEqual( + this.exec.lastCall.args[0], [deployment.js.meta.binary, Tessel.REMOTE_RUN_PATH + entryPoint, '--key=value']); test.done(); }); }, @@ -572,6 +575,7 @@ exports['deploy.run'] = { deploy.run(this.tessel, { entryPoint: entryPoint, lang: deployment.rs, + subargs: [], }).then(() => { test.done(); }); @@ -591,6 +595,7 @@ exports['deploy.run'] = { deploy.run(this.tessel, { resolvedEntryPoint: 'foo', lang: deployment.js, + subargs: [], }).then(() => { test.equal(this.postRun.callCount, 1); test.done(); @@ -640,7 +645,8 @@ exports['deploy.createShellScript'] = { var opts = { lang: deployment.js, - resolvedEntryPoint: 'foo' + resolvedEntryPoint: 'foo', + subargs: ['--key=value'], }; deploy.createShellScript(this.tessel, opts).then(() => { diff --git a/test/unit/deployment/javascript.js b/test/unit/deployment/javascript.js index 51890581..b541d992 100644 --- a/test/unit/deployment/javascript.js +++ b/test/unit/deployment/javascript.js @@ -96,11 +96,12 @@ exports['Deployment: JavaScript'] = { var shellScript = tags.stripIndent ` #!/bin/sh - exec node /app/remote-script/index.js + exec node /app/remote-script/index.js --key=value `; var opts = { lang: deployment.js, resolvedEntryPoint: 'index.js', + subargs: ['--key=value'], }; this.end.restore(); this.end = sandbox.stub(this.tessel._rps.stdin, 'end', (buffer) => { @@ -120,11 +121,12 @@ exports['Deployment: JavaScript'] = { var shellScript = tags.stripIndent ` #!/bin/sh - exec node /app/remote-script/index.js + exec node /app/remote-script/index.js --key=value `; var opts = { lang: deployment.js, resolvedEntryPoint: 'index.js', + subargs: ['--key=value'], }; this.end.restore(); this.end = sandbox.stub(this.tessel._rps.stdin, 'end', (buffer) => { @@ -2552,7 +2554,29 @@ exports['deploy.createShellScript'] = { var opts = { lang: deployment.js, - resolvedEntryPoint: 'foo' + resolvedEntryPoint: 'foo', + subargs: [], + }; + + deploy.createShellScript(this.tessel, opts).then(() => { + test.deepEqual(this.exec.firstCall.args[0], ['dd', 'of=/app/start']); + test.deepEqual(this.exec.lastCall.args[0], ['chmod', '+x', '/app/start']); + test.done(); + }); + }, + + remoteShellScriptPathIsNotPathNormalizedWithSubargs: function(test) { + test.expect(2); + + this.exec = sandbox.stub(this.tessel.connection, 'exec', (command, callback) => { + callback(null, this.tessel._rps); + this.tessel._rps.emit('close'); + }); + + var opts = { + lang: deployment.js, + resolvedEntryPoint: 'foo', + subargs: ['--key=value'], }; deploy.createShellScript(this.tessel, opts).then(() => {