var path = require('path'); | |
var fs = require('fs'); | |
var common = require('./common'); | |
var _cd = require('./cd'); | |
var _pwd = require('./pwd'); | |
//@ | |
//@ ### ls([options ,] path [,path ...]) | |
//@ ### ls([options ,] path_array) | |
//@ Available options: | |
//@ | |
//@ + `-R`: recursive | |
//@ + `-A`: all files (include files beginning with `.`, except for `.` and `..`) | |
//@ | |
//@ Examples: | |
//@ | |
//@ ```javascript | |
//@ ls('projs/*.js'); | |
//@ ls('-R', '/users/me', '/tmp'); | |
//@ ls('-R', ['/users/me', '/tmp']); // same as above | |
//@ ``` | |
//@ | |
//@ Returns array of files in the given path, or in current directory if no path provided. | |
function _ls(options, paths) { | |
options = common.parseOptions(options, { | |
'R': 'recursive', | |
'A': 'all', | |
'a': 'all_deprecated' | |
}); | |
if (options.all_deprecated) { | |
// We won't support the -a option as it's hard to image why it's useful | |
// (it includes '.' and '..' in addition to '.*' files) | |
// For backwards compatibility we'll dump a deprecated message and proceed as before | |
common.log('ls: Option -a is deprecated. Use -A instead'); | |
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); | |
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; | |
} | |
if (common.platform === 'win') | |
file = file.replace(/\\/g, '/'); | |
list.push(file); | |
return true; | |
} | |
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 (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; | |
} | |
module.exports = _ls; |