Remove the need for execArgs when user specifying an exec

- Also update tests to check end value, not individual parts
- Simplify tests to check actual output, rather than the pieces that make the output
- Remove redundant code: such a shame, it was cool code, but I'd rather remove it for simplicity and better support. Woot.
This commit is contained in:
Remy Sharp
2015-02-01 13:57:42 +00:00
parent 8ee71f4157
commit d796e41120
5 changed files with 45 additions and 173 deletions

View File

@@ -3,92 +3,6 @@ var path = require('path'),
utils = require('../utils');
module.exports = exec;
module.exports.parseExecutable = parseExecutable;
function parseExecutable(str) {
var length = str.length;
var i = 0;
var exec = null;
var execArgs = [];
var token = '';
var inspace = false;
var escaped = false;
var unescapeNextTime = false;
var open = false;
var c = null;
var isescape = false;
for (; i < length; i++) {
c = str[i];
if (unescapeNextTime) {
escaped = false;
}
unescapeNextTime = escaped;
if (c === '\\' && !utils.isWindows) {
isescape = true;
} else if (c === '^' && utils.isWindows) {
isescape = true;
} else {
isescape = false;
}
if (isescape) {
escaped = true;
// peek next character
if (str[i+1] === ' ') { // space we skip
inspace = true;
}
if (utils.isWindows) {
continue; // chomp the carat
}
}
if (!escaped && (c === '"' || c === "'")) {
open = !open;
// continue;
}
if (c === ' ') {
if (!open && inspace === false) {
if (exec === null) {
exec = token;
execArgs.push(str.slice(i + 1));
token = '';
break;
} else {
execArgs.push(token);
}
// reset the token now
token = '';
continue;
} else if (inspace) {
inspace = false;
}
}
token += c;
}
// deal with the left overs
if (exec === null) {
exec = token;
} else if (token) {
execArgs.push(token);
}
var result = {
exec: exec,
execArgs: execArgs,
};
return result;
}
/**
* Reads the cwd/package.json file and looks to see if it can load a script
@@ -179,16 +93,18 @@ function exec(nodemonOptions, execMap) {
if (Array.isArray(options.exec)) {
options.execArgs = options.exec;
options.exec = options.execArgs.shift();
} else if (options.exec && options.exec.indexOf(' ') !== -1) {
options = utils.merge(parseExecutable(options.exec), options);
}
if (options.exec === undefined) {
options.exec = 'node';
} else {
// allow variable substitution for {{filename}} and {{pwd}}
var substitution = replace.bind(null, { filename: script, pwd: process.cwd() });
options.exec = substitution(options.exec);
var substitution = replace.bind(null, { filename: options.script, pwd: process.cwd() });
var newExec = substitution(options.exec);
if (newExec !== options.exec && options.exec.indexOf('{{filename}}') !== -1) {
options.script = null;
}
options.exec = newExec;
var newExecArgs = options.execArgs.map(substitution);
if (newExecArgs.join('') !== options.execArgs.join('')) {

View File

@@ -4,32 +4,46 @@ var exec = require('../../lib/config/exec'),
command = require('../../lib/config/command'),
assert = require('assert');
function toCmd(options) {
var cmd = command({
script: options.script || 'app.js',
execOptions: options
});
return {
cmd: cmd,
string: cmd.executable + (cmd.args.length ? ' ' + cmd.args.join(' ') : '')
};
}
describe('nodemon exec', function () {
it('should default to node', function () {
var options = exec({ script: 'index.js' });
var cmd = toCmd(options);
assert(options.exec === 'node', 'exec is node');
assert(options.ext === 'js');
assert(cmd.string === 'node index.js', cmd.string);
});
it('should support --debug', function () {
var options = exec({ script: 'app.js', nodeArgs: [ '--debug' ]});
assert(options.exec === 'node', 'exec is node');
assert(options.execArgs.indexOf('--debug') !== -1, '--debug is in the execArgs');
var cmd = toCmd(options);
assert(cmd.string === 'node --debug app.js', cmd.string);
assert(options.ext.indexOf('js') !== -1, 'extension watched is .js');
});
it('should support --debug=XXXX', function () {
var options = exec({ script: 'app.js', nodeArgs: [ '--debug=9999' ]});
var cmd = toCmd(options);
assert(cmd.string === 'node --debug=9999 app.js', cmd.string);
assert(options.exec === 'node');
assert(options.execArgs.indexOf('--debug=9999') !== -1);
assert(options.ext.indexOf('js') !== -1);
});
it('should support multiple extensions', function () {
var options = exec({ script: 'app.js', ext: 'js, jade, hbs' });
assert(options.exec === 'node');
var cmd = toCmd(options);
assert(cmd.string === 'node app.js', cmd.string);
assert(options.ext.indexOf('jade') !== -1, 'comma separated string');
options = exec({ script: 'app.js', ext: 'js|jade|hbs' });
@@ -39,21 +53,23 @@ describe('nodemon exec', function () {
it('should replace {{filename}}', function () {
var options = exec({ script: 'app.js', exec: 'node {{filename}}.tmp --somethingElse' });
var cmd = command({ execOptions: options });
assert(cmd.executable + ' ' + cmd.args.join(' ') === 'node app.js.tmp --somethingElse', 'filename is interpolated: ' + cmd.executable + ' ' + cmd.args.join(' '));
var cmd = toCmd(options);
assert(cmd.string === 'node app.js.tmp --somethingElse', cmd.string);
});
it('should not split on spaces in {{filename}}', function () {
var options = exec({ script: 'my app.js', exec: 'node {{filename}}.tmp --somethingElse' });
var cmd = command({ execOptions: options });
var cmd = toCmd(options);
// var cmd = command({ execOptions: options });
assert(cmd.args[0] === 'my app.js.tmp --somethingElse', cmd.args[0]);
assert(cmd.string === 'node my app.js.tmp --somethingElse', cmd.string);
});
it('should support extension maps', function () {
var options = exec({ script: 'template.jade' }, { 'jade': 'jade {{filename}} --out /tmp' });
assert(options.exec === 'jade', 'exec used, should be "jade": ' + options.exec);
assert(options.execArgs[0] === 'template.jade --out /tmp', 'filename interpolated');
var cmd = toCmd(options);
assert(cmd.string === 'jade template.jade --out /tmp', cmd.string);
});
it('should support input from argv#parse', function () {
@@ -84,9 +100,9 @@ describe('nodemon exec', function () {
it('should support custom executables with arguments', function () {
var options = exec({ script: 'app.py', exec: 'python --debug'});
var cmd = toCmd(options);
assert(options.exec === 'python');
assert(options.execArgs.indexOf('--debug') !== -1);
assert(cmd.string === 'python --debug app.py', cmd.string);
assert(options.ext.indexOf('py') !== -1);
});

View File

@@ -41,6 +41,12 @@ describe('nodemon CLI parser', function () {
assert(cmd === 'node --debug ./bin/www')
});
it('should replace {{filename}}', function () {
var settings = parse(asCLI('test/fixtures/app.js --exec "node {{filename}}.tmp" --somethingElse'));
var cmd = commandToString(command(settings));
assert(cmd === 'node test/fixtures/app.js.tmp --somethingElse', cmd);
});
it('should parse the help examples #1', function () {
var settings = parse(asCLI('test/fixtures/app.js')),
cmd = commandToString(command(settings));
@@ -128,12 +134,11 @@ describe('nodemon CLI parser', function () {
var pwd = process.cwd();
process.chdir('test/fixtures/');
var settings = parse(asCLI('--exec \'"app with spaces.js" foo\''));
var options = settings.execOptions;
var cmd = commandToString(command(settings));
process.chdir(pwd);
assert(options.exec === '"app with spaces.js"', 'exec is: ' + options.exec);
assert(options.execArgs[0] === 'foo', 'execArgs is: ' + options.execArgs[0]);
assert(cmd === '"app with spaces.js" foo', cmd);
});

View File

@@ -99,7 +99,7 @@ describe('config load', function () {
// ensure global mapping works too
var options = exec({ script: 'template.jade' }, config.execMap);
assert(options.exec === 'bin/jade', 'exec used, should be "bin/jade": ' + options.exec);
assert(options.exec === 'bin/jade template.jade --out /tmp', 'exec used, should be "bin/jade": ' + options.exec);
done();

View File

@@ -1,65 +0,0 @@
'use strict';
/*global describe:true, it: true, after: true */
var parseExecutable = require('../../lib/config/exec').parseExecutable,
assert = require('assert');
describe('exec.parseExecutable', function () {
it('should parse simple commands', function () {
var cmd = 'run.js';
var result = parseExecutable(cmd);
assert(result.exec === cmd, result.exec);
});
it('should parse simple commands with space separated arguments', function () {
var cmd = 'run.js --arg1 --arg2';
var result = parseExecutable(cmd);
assert(result.exec === 'run.js', result.exec);
assert(result.execArgs.length === 1, 'args.length ' + result.execArgs.length);
assert(result.execArgs[0] === '--arg1 --arg2', result.execArgs[0]);
});
it('should leave escaped characters alone', function () {
var cmd = 'test/fixtures/some \\file'
var result = parseExecutable(cmd);
assert(result.exec === 'test/fixtures/some', 'exec: ' + result.exec);
assert(result.execArgs[0] === '\\file', 'arg: ' + result.execArgs[0]);
});
it('should maintain space separated commands', function () {
var cmd = 'test/fixtures/some\\ \\file';
var result = parseExecutable(cmd);
assert(result.exec === cmd, 'exec: ' + result.exec);
assert(result.execArgs.length === 0, 'arg: ' + JSON.stringify(result.execArgs));
});
it('should handle test/fixtures/some\\\"file', function () {
var cmd = 'test/fixtures/some\\\"file';
var result = parseExecutable(cmd);
assert(result.exec === cmd, 'exec: ' + result.exec);
assert(result.execArgs.length === 0, 'arg: ' + JSON.stringify(result.execArgs));
});
it('should handle some\\\"file\\" "and some"', function () {
var cmd = 'some\\\"file\\" "and some"';
var result = parseExecutable(cmd);
assert(result.exec === 'some\\\"file\\"', 'exec: ' + result.exec);
});
it('should handle "test/fixtures/app with spaces.js" foo', function () {
var cmd = '"test/fixtures/app with spaces.js" foo';
var result = parseExecutable(cmd);
assert(result.exec === '"test/fixtures/app with spaces.js"', 'exec: ' + result.exec);
});
// it('should handle echo -e "line1\\nline2"', function () {
// var cmd = '"echo -e \"line1\\nline2\""';
// var result = parseExecutable(cmd);
// assert(result.exec === cmd, 'exec: ' + result.exec);
// });
it('should handle simple spaces: test/fixtures/app\\ with\\ spaces.js', function () {
var cmd = 'test/fixtures/app\\ with\\ spaces.js';
var result = parseExecutable(cmd);
assert(result.exec === cmd, 'exec: ' + result.exec);
});
});