mirror of
https://github.com/shelljs/shelljs.git
synced 2026-01-18 16:03:37 +00:00
feat(glob): glob support for (almost) all commands
This commit is contained in:
parent
90569dcdac
commit
3a7eb3f2ad
36
shell.js
36
shell.js
@ -15,7 +15,7 @@ var common = require('./src/common');
|
||||
|
||||
//@include ./src/cd
|
||||
var _cd = require('./src/cd');
|
||||
exports.cd = common.wrap('cd', _cd);
|
||||
exports.cd = common.wrap('cd', _cd, {idx: 1});
|
||||
|
||||
//@include ./src/pwd
|
||||
var _pwd = require('./src/pwd');
|
||||
@ -23,27 +23,27 @@ exports.pwd = common.wrap('pwd', _pwd);
|
||||
|
||||
//@include ./src/ls
|
||||
var _ls = require('./src/ls');
|
||||
exports.ls = common.wrap('ls', _ls);
|
||||
exports.ls = common.wrap('ls', _ls, {idx: 1});
|
||||
|
||||
//@include ./src/find
|
||||
var _find = require('./src/find');
|
||||
exports.find = common.wrap('find', _find);
|
||||
exports.find = common.wrap('find', _find, {idx: 1});
|
||||
|
||||
//@include ./src/cp
|
||||
var _cp = require('./src/cp');
|
||||
exports.cp = common.wrap('cp', _cp);
|
||||
exports.cp = common.wrap('cp', _cp, {idx: 1});
|
||||
|
||||
//@include ./src/rm
|
||||
var _rm = require('./src/rm');
|
||||
exports.rm = common.wrap('rm', _rm);
|
||||
exports.rm = common.wrap('rm', _rm, {idx: 1});
|
||||
|
||||
//@include ./src/mv
|
||||
var _mv = require('./src/mv');
|
||||
exports.mv = common.wrap('mv', _mv);
|
||||
exports.mv = common.wrap('mv', _mv, {idx: 1});
|
||||
|
||||
//@include ./src/mkdir
|
||||
var _mkdir = require('./src/mkdir');
|
||||
exports.mkdir = common.wrap('mkdir', _mkdir);
|
||||
exports.mkdir = common.wrap('mkdir', _mkdir, {idx: 1});
|
||||
|
||||
//@include ./src/test
|
||||
var _test = require('./src/test');
|
||||
@ -51,23 +51,23 @@ exports.test = common.wrap('test', _test);
|
||||
|
||||
//@include ./src/cat
|
||||
var _cat = require('./src/cat');
|
||||
exports.cat = common.wrap('cat', _cat);
|
||||
exports.cat = common.wrap('cat', _cat, {idx: 1});
|
||||
|
||||
//@include ./src/to
|
||||
var _to = require('./src/to');
|
||||
String.prototype.to = common.wrap('to', _to);
|
||||
String.prototype.to = common.wrap('to', _to, {idx: 1});
|
||||
|
||||
//@include ./src/toEnd
|
||||
var _toEnd = require('./src/toEnd');
|
||||
String.prototype.toEnd = common.wrap('toEnd', _toEnd);
|
||||
String.prototype.toEnd = common.wrap('toEnd', _toEnd, {idx: 1});
|
||||
|
||||
//@include ./src/sed
|
||||
var _sed = require('./src/sed');
|
||||
exports.sed = common.wrap('sed', _sed);
|
||||
exports.sed = common.wrap('sed', _sed, {idx: 3});
|
||||
|
||||
//@include ./src/grep
|
||||
var _grep = require('./src/grep');
|
||||
exports.grep = common.wrap('grep', _grep);
|
||||
exports.grep = common.wrap('grep', _grep, {idx: 2});
|
||||
|
||||
//@include ./src/which
|
||||
var _which = require('./src/which');
|
||||
@ -79,15 +79,15 @@ exports.echo = _echo; // don't common.wrap() as it could parse '-options'
|
||||
|
||||
//@include ./src/dirs
|
||||
var _dirs = require('./src/dirs').dirs;
|
||||
exports.dirs = common.wrap("dirs", _dirs);
|
||||
exports.dirs = common.wrap("dirs", _dirs, {idx: 1});
|
||||
var _pushd = require('./src/dirs').pushd;
|
||||
exports.pushd = common.wrap('pushd', _pushd);
|
||||
exports.pushd = common.wrap('pushd', _pushd, {idx: 1});
|
||||
var _popd = require('./src/dirs').popd;
|
||||
exports.popd = common.wrap("popd", _popd);
|
||||
exports.popd = common.wrap("popd", _popd, {idx: 1});
|
||||
|
||||
//@include ./src/ln
|
||||
var _ln = require('./src/ln');
|
||||
exports.ln = common.wrap('ln', _ln);
|
||||
exports.ln = common.wrap('ln', _ln, {idx: 1});
|
||||
|
||||
//@
|
||||
//@ ### exit(code)
|
||||
@ -105,11 +105,11 @@ exports.exec = common.wrap('exec', _exec, {notUnix:true});
|
||||
|
||||
//@include ./src/chmod
|
||||
var _chmod = require('./src/chmod');
|
||||
exports.chmod = common.wrap('chmod', _chmod);
|
||||
exports.chmod = common.wrap('chmod', _chmod, {idx: 1});
|
||||
|
||||
//@include ./src/touch
|
||||
var _touch = require('./src/touch');
|
||||
exports.touch = common.wrap('touch', _touch);
|
||||
exports.touch = common.wrap('touch', _touch, {idx: 1});
|
||||
|
||||
//@include ./src/set
|
||||
var _set = require('./src/set');
|
||||
|
||||
@ -26,8 +26,6 @@ function _cat(options, files) {
|
||||
files = [].slice.call(arguments, 1);
|
||||
// if it's array leave it as it is
|
||||
|
||||
files = common.expand(files);
|
||||
|
||||
files.forEach(function(file) {
|
||||
if (!fs.existsSync(file))
|
||||
common.error('no such file or directory: ' + file);
|
||||
|
||||
13
src/chmod.js
13
src/chmod.js
@ -62,9 +62,7 @@ function _chmod(options, mode, filePattern) {
|
||||
// Special case where the specified file permissions started with - to subtract perms, which
|
||||
// get picked up by the option parser as command flags.
|
||||
// If we are down by one argument and options starts with -, shift everything over.
|
||||
filePattern = mode;
|
||||
mode = options;
|
||||
options = '';
|
||||
[].unshift.call(arguments, '');
|
||||
}
|
||||
else {
|
||||
common.error('You must specify a file.');
|
||||
@ -77,15 +75,14 @@ function _chmod(options, mode, filePattern) {
|
||||
'v': 'verbose'
|
||||
});
|
||||
|
||||
if (typeof filePattern === 'string') {
|
||||
filePattern = [ filePattern ];
|
||||
}
|
||||
filePattern = [].slice.call(arguments, 2);
|
||||
|
||||
var files;
|
||||
|
||||
// TODO: replace this with a call to common.expand()
|
||||
if (options.recursive) {
|
||||
files = [];
|
||||
common.expand(filePattern).forEach(function addFile(expandedFile) {
|
||||
filePattern.forEach(function addFile(expandedFile) {
|
||||
var stat = fs.lstatSync(expandedFile);
|
||||
|
||||
if (!stat.isSymbolicLink()) {
|
||||
@ -100,7 +97,7 @@ function _chmod(options, mode, filePattern) {
|
||||
});
|
||||
}
|
||||
else {
|
||||
files = common.expand(filePattern);
|
||||
files = filePattern;
|
||||
}
|
||||
|
||||
files.forEach(function innerChmod(file) {
|
||||
|
||||
@ -127,10 +127,17 @@ exports.parseOptions = parseOptions;
|
||||
// expand(['file*.js']) = ['file1.js', 'file2.js', ...]
|
||||
// (if the files 'file1.js', 'file2.js', etc, exist in the current dir)
|
||||
function expand(list) {
|
||||
if (!Array.isArray(list)) {
|
||||
throw new TypeError('must be an array');
|
||||
}
|
||||
var expanded = [];
|
||||
list.forEach(function(listEl) {
|
||||
// Don't expand non-strings
|
||||
if (typeof listEl !== 'string') {
|
||||
expanded.push(listEl);
|
||||
}
|
||||
// Wildcard present on directory names ?
|
||||
if(listEl.search(/\*[^\/]*\//) > -1 || listEl.search(/\*\*[^\/]*\//) > -1) {
|
||||
else if(listEl.search(/\*[^\/]*\//) > -1 || listEl.search(/\*\*[^\/]*\//) > -1) {
|
||||
var match = listEl.match(/^([^*]+\/|)(.*)/);
|
||||
var root = match[1];
|
||||
var rest = match[2];
|
||||
@ -145,9 +152,14 @@ function expand(list) {
|
||||
}
|
||||
// Wildcard present on file names ?
|
||||
else if (listEl.search(/\*/) > -1) {
|
||||
_ls('', listEl).forEach(function(file) {
|
||||
expanded.push(file);
|
||||
});
|
||||
var matches = _ls('', listEl);
|
||||
if (matches.length === 0) {
|
||||
expanded.push(listEl); // Interpret this as a literal string
|
||||
} else {
|
||||
matches.forEach(function(file) {
|
||||
expanded.push(file);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
expanded.push(listEl);
|
||||
}
|
||||
@ -229,6 +241,15 @@ function wrap(cmd, fn, options) {
|
||||
} else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') {
|
||||
args.unshift(''); // only add dummy option if '-option' not already present
|
||||
}
|
||||
|
||||
args = args.reduce(function(accum, cur) {
|
||||
if (Array.isArray(cur)) {
|
||||
return accum.concat(cur);
|
||||
} else {
|
||||
accum.push(cur);
|
||||
return accum;
|
||||
}
|
||||
}, []);
|
||||
// Expand the '~' if appropriate
|
||||
var homeDir = getUserHome();
|
||||
args = args.map(function(arg) {
|
||||
@ -237,6 +258,8 @@ function wrap(cmd, fn, options) {
|
||||
else
|
||||
return arg;
|
||||
});
|
||||
if (options && typeof options.idx === 'number')
|
||||
args = args.slice(0, options.idx).concat(expand(args.slice(options.idx)));
|
||||
retValue = fn.apply(this, args);
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
@ -33,14 +33,10 @@ function _mv(options, sources, dest) {
|
||||
dest = arguments[arguments.length - 1];
|
||||
} else if (typeof sources === 'string') {
|
||||
sources = [sources];
|
||||
} else if ('length' in sources) {
|
||||
sources = sources; // no-op for array
|
||||
} else {
|
||||
common.error('invalid arguments');
|
||||
}
|
||||
|
||||
sources = common.expand(sources);
|
||||
|
||||
var exists = fs.existsSync(dest),
|
||||
stats = exists && fs.statSync(dest);
|
||||
|
||||
|
||||
@ -114,11 +114,8 @@ function _rm(options, files) {
|
||||
if (!files)
|
||||
common.error('no paths given');
|
||||
|
||||
if (typeof files === 'string')
|
||||
files = [].slice.call(arguments, 1);
|
||||
// if it's array leave it as it is
|
||||
|
||||
files = common.expand(files);
|
||||
// Convert to array
|
||||
files = [].slice.call(arguments, 1);
|
||||
|
||||
files.forEach(function(file) {
|
||||
if (!fs.existsSync(file)) {
|
||||
|
||||
@ -40,8 +40,6 @@ function _sed(options, regex, replacement, files) {
|
||||
files = [].slice.call(arguments, 3);
|
||||
// if it's array leave it as it is
|
||||
|
||||
files = common.expand(files);
|
||||
|
||||
var sed = [];
|
||||
files.forEach(function(file) {
|
||||
if (!fs.existsSync(file)) {
|
||||
|
||||
14
test/ln.js
14
test/ln.js
@ -71,6 +71,20 @@ assert.equal(
|
||||
'new content 1'
|
||||
);
|
||||
|
||||
// With glob
|
||||
shell.rm('tmp/linkfile1');
|
||||
shell.ln('tmp/fi*1', 'tmp/linkfile1');
|
||||
assert(fs.existsSync('tmp/linkfile1'));
|
||||
assert.equal(
|
||||
fs.readFileSync('tmp/file1').toString(),
|
||||
fs.readFileSync('tmp/linkfile1').toString()
|
||||
);
|
||||
fs.writeFileSync('tmp/file1', 'new content 1');
|
||||
assert.equal(
|
||||
fs.readFileSync('tmp/linkfile1').toString(),
|
||||
'new content 1'
|
||||
);
|
||||
|
||||
skipOnWinForEPERM(shell.ln.bind(shell, '-s', 'file2', 'tmp/linkfile2'), function () {
|
||||
assert(fs.existsSync('tmp/linkfile2'));
|
||||
assert.equal(
|
||||
|
||||
42
test/ls.js
42
test/ls.js
@ -81,6 +81,13 @@ assert.equal(result.indexOf('.hidden_dir') > -1, true);
|
||||
assert.equal(result.length, 8);
|
||||
shell.cd('../..');
|
||||
|
||||
// wildcard, very simple
|
||||
var result = shell.ls('resources/cat/*');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result.indexOf('resources/cat/file1') > -1, true);
|
||||
assert.equal(result.indexOf('resources/cat/file2') > -1, true);
|
||||
assert.equal(result.length, 2);
|
||||
|
||||
// wildcard, simple
|
||||
var result = shell.ls('resources/ls/*');
|
||||
assert.equal(shell.error(), null);
|
||||
@ -89,11 +96,24 @@ assert.equal(result.indexOf('resources/ls/file2') > -1, true);
|
||||
assert.equal(result.indexOf('resources/ls/file1.js') > -1, true);
|
||||
assert.equal(result.indexOf('resources/ls/file2.js') > -1, true);
|
||||
assert.equal(result.indexOf('resources/ls/filename(with)[chars$]^that.must+be-escaped') > -1, true);
|
||||
assert.equal(result.indexOf('resources/ls/a_dir') > -1, true);
|
||||
assert.ok(result.indexOf('resources/ls/a_dir') === -1); // this shouldn't be there
|
||||
assert.ok(result.indexOf('nada') > -1);
|
||||
assert.ok(result.indexOf('b_dir') > -1);
|
||||
assert.equal(result.length, 7);
|
||||
|
||||
// wildcard, simple, with -d
|
||||
var result = shell.ls('-d', 'resources/ls/*');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result.indexOf('resources/ls/file1') > -1, true);
|
||||
assert.equal(result.indexOf('resources/ls/file2') > -1, true);
|
||||
assert.equal(result.indexOf('resources/ls/file1.js') > -1, true);
|
||||
assert.equal(result.indexOf('resources/ls/file2.js') > -1, true);
|
||||
assert.equal(result.indexOf('resources/ls/filename(with)[chars$]^that.must+be-escaped') > -1, true);
|
||||
assert.ok(result.indexOf('resources/ls/a_dir') > -1);
|
||||
assert.equal(result.length, 6);
|
||||
|
||||
// wildcard, hidden only
|
||||
var result = shell.ls('resources/ls/.*');
|
||||
var result = shell.ls('-d', 'resources/ls/.*');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result.indexOf('resources/ls/.hidden_file') > -1, true);
|
||||
assert.equal(result.indexOf('resources/ls/.hidden_dir') > -1, true);
|
||||
@ -116,6 +136,12 @@ assert.equal(result.length, 2);
|
||||
assert.equal(result.indexOf('resources/ls/file1.js') > -1, true);
|
||||
assert.equal(result.indexOf('resources/ls/file2.js') > -1, true);
|
||||
|
||||
// one file that exists, one that doesn't
|
||||
var result = shell.ls('resources/ls/file1.js', 'resources/ls/thisdoesntexist');
|
||||
assert.ok(shell.error());
|
||||
assert.equal(result.length, 1);
|
||||
assert.equal(result.indexOf('resources/ls/file1.js') > -1, true);
|
||||
|
||||
// wildcard, should not do partial matches
|
||||
var result = shell.ls('resources/ls/*.j'); // shouldn't get .js
|
||||
assert.equal(shell.error(), null);
|
||||
@ -144,7 +170,7 @@ assert.equal(shell.error(), null);
|
||||
assert.equal(result.length, 4);
|
||||
assert.equal(result.indexOf('resources/ls/file1.js') > -1, true);
|
||||
assert.equal(result.indexOf('resources/ls/file2.js') > -1, true);
|
||||
assert.equal(result.indexOf('resources/ls/a_dir/b_dir') > -1, true);
|
||||
assert.equal(result.indexOf('z') > -1, true);
|
||||
assert.equal(result.indexOf('resources/ls/a_dir/nada') > -1, true);
|
||||
|
||||
// wildcard for both paths, array
|
||||
@ -153,7 +179,7 @@ assert.equal(shell.error(), null);
|
||||
assert.equal(result.length, 4);
|
||||
assert.equal(result.indexOf('resources/ls/file1.js') > -1, true);
|
||||
assert.equal(result.indexOf('resources/ls/file2.js') > -1, true);
|
||||
assert.equal(result.indexOf('resources/ls/a_dir/b_dir') > -1, true);
|
||||
assert.equal(result.indexOf('z') > -1, true);
|
||||
assert.equal(result.indexOf('resources/ls/a_dir/nada') > -1, true);
|
||||
|
||||
// recursive, no path
|
||||
@ -184,11 +210,11 @@ assert.equal(result.indexOf('a_dir/.hidden_dir/nada') > -1, true);
|
||||
assert.equal(result.length, 14);
|
||||
|
||||
// recursive, wildcard
|
||||
var result = shell.ls('-R', 'resources/ls/*');
|
||||
var result = shell.ls('-R', 'resources/ls');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result.indexOf('resources/ls/a_dir') > -1, true);
|
||||
assert.equal(result.indexOf('resources/ls/a_dir/b_dir') > -1, true);
|
||||
assert.equal(result.indexOf('resources/ls/a_dir/b_dir/z') > -1, true);
|
||||
assert.equal(result.indexOf('a_dir') > -1, true);
|
||||
assert.equal(result.indexOf('a_dir/b_dir') > -1, true);
|
||||
assert.equal(result.indexOf('a_dir/b_dir/z') > -1, true);
|
||||
assert.equal(result.length, 9);
|
||||
|
||||
// directory option, single arg
|
||||
|
||||
@ -69,4 +69,13 @@ assert.equal(fs.existsSync('tmp/yyya'), true);
|
||||
assert.equal(fs.existsSync('tmp/yyyb'), true);
|
||||
assert.equal(fs.existsSync('tmp/yyyc'), true);
|
||||
|
||||
// globbed dir
|
||||
shell.mkdir('-p', 'tmp/mydir');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(fs.existsSync('tmp/mydir'), true);
|
||||
shell.mkdir('-p', 'tmp/m*ir');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(fs.existsSync('tmp/mydir'), true);
|
||||
assert.equal(fs.existsSync('tmp/m*ir'), false); // doesn't create literal name
|
||||
|
||||
shell.exit(123);
|
||||
|
||||
10
test/sed.js
10
test/sed.js
@ -101,4 +101,14 @@ assert.equal(result, 'hello1\nhello2');
|
||||
assert.equal(shell.cat('tmp/file1'), 'hello1');
|
||||
assert.equal(shell.cat('tmp/file2'), 'hello2');
|
||||
|
||||
// glob file names, with in-place-replacement
|
||||
shell.cp('resources/file*.txt', 'tmp/');
|
||||
assert.equal(shell.cat('tmp/file1.txt'), 'test1\n');
|
||||
assert.equal(shell.cat('tmp/file2.txt'), 'test2\n');
|
||||
var result = shell.sed('-i', 'test', 'hello', 'tmp/file*.txt');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result, 'hello1\n\nhello2\n'); // TODO: fix sed's behavior
|
||||
assert.equal(shell.cat('tmp/file1.txt'), 'hello1\n');
|
||||
assert.equal(shell.cat('tmp/file2.txt'), 'hello2\n');
|
||||
|
||||
shell.exit(123);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
var shell = require('..');
|
||||
var common = require('./common');
|
||||
var common = require('../src/common');
|
||||
|
||||
var assert = require('assert');
|
||||
|
||||
|
||||
@ -31,4 +31,10 @@ result = shell.cat('tmp/to2');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result, 'hello world');
|
||||
|
||||
// With a glob
|
||||
'goodbye'.to('tmp/t*1');
|
||||
var result = shell.cat('tmp/to1');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result, 'goodbye');
|
||||
|
||||
shell.exit(123);
|
||||
|
||||
@ -33,4 +33,11 @@ result = shell.cat('tmp/toEnd2');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result, 'world'); //Check that the result is what we expect
|
||||
|
||||
// With a glob
|
||||
'good'.to('tmp/toE*1');
|
||||
'bye'.toEnd('tmp/toE*1');
|
||||
var result = shell.cat('tmp/toEnd1');
|
||||
assert.equal(shell.error(), null);
|
||||
assert.equal(result, 'goodbye');
|
||||
|
||||
shell.exit(123);
|
||||
|
||||
@ -30,6 +30,15 @@ var testFile = tmpFile(true);
|
||||
shell.touch('-c', testFile);
|
||||
assert.ok(!fs.existsSync(testFile));
|
||||
|
||||
// handles globs correctly
|
||||
shell.touch('tmp/file.txt');
|
||||
shell.touch('tmp/file.js');
|
||||
shell.touch('tmp/file*');
|
||||
var files = shell.ls('tmp/file*');
|
||||
assert.ok(files.indexOf('tmp/file.txt') > -1);
|
||||
assert.ok(files.indexOf('tmp/file.js') > -1);
|
||||
assert.equal(files.length, 2);
|
||||
|
||||
// errors if reference file is not found
|
||||
var testFile = tmpFile();
|
||||
var refFile = tmpFile(true);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user