Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
"bin": {
"shjs": "./bin/shjs"
},
"dependencies": {},
"dependencies": {
"glob": "^6.0.3"
},
"devDependencies": {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to use glob without adding it as a package dependency? I know some of the original maintainers wanted to keep dependencies at a minimum (#122 (comment)).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nevermind. Just tried it and saw that I do need to install it as a dependency. We might need to ping @arturadib and get his input on this in that case.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nfischer: I think it's not that big a deal. If a user is installing us, then they have npm installed. The whole node world favors small focused modules, which mean dependencies. This means that deps are the norm. It's not out of the ordinary. (As a matter of fact, I'd like to try and split this module up into some smaller ones).

However, if @arturadib wants to chime in, that's more than welcome.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with the philosophy of using modules where they make sense. I think we probably should take advantage of the glob module, since it seems to integrate fairly seemlessly with the existing code.

"coffee-script": "^1.10.0",
"jshint": "~2.1.11"
Expand Down
37 changes: 9 additions & 28 deletions src/common.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
var os = require('os');
var fs = require('fs');
var _ls = require('./ls');
var glob = require('glob');

// Module globals
var config = {
Expand Down Expand Up @@ -106,34 +106,15 @@ exports.parseOptions = parseOptions;
// For example:
// expand(['file*.js']) = ['file1.js', 'file2.js', ...]
// (if the files 'file1.js', 'file2.js', etc, exist in the current dir)
function expand(list) {
var expanded = [];
list.forEach(function(listEl) {
// Wildcard present on directory names ?
if(listEl.search(/\*[^\/]*\//) > -1 || listEl.search(/\*\*[^\/]*\//) > -1) {
var match = listEl.match(/^([^*]+\/|)(.*)/);
var root = match[1];
var rest = match[2];
var restRegex = rest.replace(/\*\*/g, ".*").replace(/\*/g, "[^\\/]*");
restRegex = new RegExp(restRegex);

_ls('-R', root).filter(function (e) {
return restRegex.test(e);
}).forEach(function(file) {
expanded.push(file);
});
}
// Wildcard present on file names ?
else if (listEl.search(/\*/) > -1) {
_ls('', listEl).forEach(function(file) {
expanded.push(file);
});
} else {
expanded.push(listEl);
}
});
return expanded;
// It's Just a thin wrapper around glob.sync, to allow passing in an array.
function expand(list, opts) {
if (!Array.isArray(list)) list = [list];
opts = opts || {};
return list.reduce(function (files, pattern) {
return files.concat(glob.sync(pattern, opts));
}, []);
}

exports.expand = expand;

// Normalizes _unlinkSync() across platforms to match Unix behavior, i.e.
Expand Down
101 changes: 13 additions & 88 deletions src/ls.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
var path = require('path');
var fs = require('fs');
var common = require('./common');
var _cd = require('./cd');
var _pwd = require('./pwd');

//@
//@ ### ls([options,] [path, ...])
Expand Down Expand Up @@ -37,94 +33,23 @@ function _ls(options, paths) {
options.all = true;
}

if (!paths)
paths = ['.'];
else if (typeof paths === 'object')
paths = paths; // assume array
else if (typeof paths === 'string')
paths = [].slice.call(arguments, 1);
if (typeof paths === 'string') paths = [].slice.call(arguments, 1);
paths = paths || [];

var list = [];

// Conditionally pushes file to list - returns true if pushed, false otherwise
// (e.g. prevents hidden files to be included unless explicitly told so)
function pushFile(file, query) {
// hidden file?
if (path.basename(file)[0] === '.') {
// not explicitly asking for hidden files?
if (!options.all && !(path.basename(query)[0] === '.' && path.basename(query).length > 1))
return false;
}
paths = paths.map(function (path) {
path += (options.recursive ? '/**/*' : '/*');
return path.replace(/\\/g, '/');
});

if (common.platform === 'win')
file = file.replace(/\\/g, '/');
var files = common.expand(paths, { dot: options.all });

list.push(file);
return true;
// I'm not sure if we need this.
if (common.platform === 'win') {
files = files.map(function (file) {
return file.replace(/\\/g, '/');
});
}

paths.forEach(function(p) {
if (fs.existsSync(p)) {
var stats = fs.statSync(p);
// Simple file?
if (stats.isFile()) {
pushFile(p, p);
return; // continue
}

// Simple dir?
if (options.directory) {
pushFile(p, p);
return;
} else if (stats.isDirectory()) {
// Iterate over p contents
fs.readdirSync(p).forEach(function(file) {
if (!pushFile(file, p))
return;

// Recursive?
if (options.recursive) {
var oldDir = _pwd();
_cd('', p);
if (fs.statSync(file).isDirectory())
list = list.concat(_ls('-R'+(options.all?'A':''), file+'/*'));
_cd('', oldDir);
}
});
return; // continue
}
}

// p does not exist - possible wildcard present

var basename = path.basename(p);
var dirname = path.dirname(p);
// Wildcard present on an existing dir? (e.g. '/tmp/*.js')
if (basename.search(/\*/) > -1 && fs.existsSync(dirname) && fs.statSync(dirname).isDirectory) {
// Escape special regular expression chars
var regexp = basename.replace(/(\^|\$|\(|\)|<|>|\[|\]|\{|\}|\.|\+|\?)/g, '\\$1');
// Translates wildcard into regex
regexp = '^' + regexp.replace(/\*/g, '.*') + '$';
// Iterate over directory contents
fs.readdirSync(dirname).forEach(function(file) {
if (file.match(new RegExp(regexp))) {
if (!pushFile(path.normalize(dirname+'/'+file), basename))
return;

// Recursive?
if (options.recursive) {
var pp = dirname + '/' + file;
if (fs.lstatSync(pp).isDirectory())
list = list.concat(_ls('-R'+(options.all?'A':''), pp+'/*'));
} // recursive
} // if file matches
}); // forEach
return;
}

common.error('no such file or directory: ' + p, true);
});

return list;
return files;
}
module.exports = _ls;
6 changes: 6 additions & 0 deletions test/ls.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,12 @@ assert.ok(result.indexOf('resources/ls/file2') > -1);
assert.ok(result.indexOf('resources/ls/file2.js') > -1);
assert.ok(result.indexOf('resources/ls/file2') > -1);
assert.ok(result.indexOf('resources/ls/filename(with)[chars$]^that.must+be-escaped') > -1);

// globs without -A
var result = shell.ls('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);
assert.equal(result.length, 6);

shell.exit(123);