Comparing version 0.7.8 to 0.8.0
{ | ||
"name": "shelljs", | ||
"version": "0.7.8", | ||
"version": "0.8.0", | ||
"description": "Portable Unix shell commands for Node.js", | ||
@@ -37,4 +37,4 @@ "keywords": [ | ||
"posttest": "npm run lint", | ||
"test": "nyc --reporter=text --reporter=lcov ava --serial test/*.js", | ||
"test-no-coverage": "ava --serial test/*.js", | ||
"test": "nyc --reporter=text --reporter=lcov ava test/*.js", | ||
"test-no-coverage": "ava test/*.js", | ||
"gendocs": "node scripts/generate-docs", | ||
@@ -57,4 +57,9 @@ "lint": "eslint .", | ||
}, | ||
"ava": { | ||
"serial": true, | ||
"powerAssert": false | ||
}, | ||
"devDependencies": { | ||
"ava": "^0.16.0", | ||
"ava": "^0.21.0", | ||
"chalk": "^1.1.3", | ||
"codecov": "^1.0.1", | ||
@@ -65,3 +70,3 @@ "coffee-script": "^1.10.0", | ||
"eslint-plugin-import": "^1.11.1", | ||
"nyc": "^10.0.0", | ||
"nyc": "^11.3.0", | ||
"shelljs-changelog": "^0.2.0", | ||
@@ -74,5 +79,4 @@ "shelljs-release": "^0.2.0", | ||
"engines": { | ||
"node": ">=0.11.0", | ||
"iojs": "*" | ||
"node": ">=4" | ||
} | ||
} |
@@ -16,7 +16,6 @@ # ShellJS - Unix shell commands for Node.js | ||
ShellJS is proudly tested on every node release since `v0.11`! | ||
ShellJS is proudly tested on every node release since `v4`! | ||
The project is [unit-tested](http://travis-ci.org/shelljs/shelljs) and battle-tested in projects like: | ||
+ [PDF.js](http://github.com/mozilla/pdf.js) - Firefox's next-gen PDF reader | ||
+ [Firebug](http://getfirebug.com/) - Firefox's infamous debugger | ||
@@ -53,2 +52,8 @@ + [JSHint](http://jshint.com) & [ESLint](http://eslint.org/) - popular JavaScript linters | ||
## Plugin API | ||
ShellJS now supports third-party plugins! You can learn more about using plugins | ||
and writing your own ShellJS commands in [the | ||
wiki](https://github.com/shelljs/shelljs/wiki/Using-ShellJS-Plugins). | ||
## A quick note about the docs | ||
@@ -100,2 +105,12 @@ | ||
## Exclude options | ||
If you need to pass a parameter that looks like an option, you can do so like: | ||
```js | ||
shell.grep('--', '-v', 'path/to/file'); // Search for "-v", no grep options | ||
shell.cp('-R', '-dir', 'outdir'); // If already using an option, you're done | ||
``` | ||
## Global vs. Local | ||
@@ -128,5 +143,8 @@ | ||
### cat(file [, file ...]) | ||
### cat(file_array) | ||
### cat([options,] file [, file ...]) | ||
### cat([options,] file_array) | ||
Available options: | ||
+ `-n`: number all output lines | ||
Examples: | ||
@@ -206,2 +224,3 @@ | ||
+ `-n`: Suppresses the normal change of directory when adding directories to the stack, so that only the stack is manipulated. | ||
+ `-q`: Supresses output to the console. | ||
@@ -229,2 +248,3 @@ Arguments: | ||
+ `-n`: Suppresses the normal change of directory when removing directories from the stack, so that only the stack is manipulated. | ||
+ `-q`: Supresses output to the console. | ||
@@ -253,2 +273,3 @@ Arguments: | ||
+ `-c`: Clears the directory stack by deleting all of the elements. | ||
+ `-q`: Supresses output to the console. | ||
@@ -269,2 +290,3 @@ Arguments: | ||
+ `-e`: interpret backslash escapes (default) | ||
+ `-n`: remove trailing newline from output | ||
@@ -276,2 +298,3 @@ Examples: | ||
var str = echo('hello world'); | ||
echo('-n', 'no newline at end'); | ||
``` | ||
@@ -284,7 +307,9 @@ | ||
### exec(command [, options] [, callback]) | ||
Available options (all `false` by default): | ||
Available options: | ||
+ `async`: Asynchronous execution. If a callback is provided, it will be set to | ||
`true`, regardless of the passed value. | ||
+ `silent`: Do not echo program output to console. | ||
`true`, regardless of the passed value (default: `false`). | ||
+ `silent`: Do not echo program output to console (default: `false`). | ||
+ `encoding`: Character encoding to use. Affects the returned stdout and stderr values, and | ||
what is written to stdout and stderr when not in silent mode (default: `'utf8'`). | ||
+ and any option available to Node.js's | ||
@@ -291,0 +316,0 @@ [child_process.exec()](https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback) |
@@ -6,8 +6,14 @@ var common = require('./common'); | ||
canReceivePipe: true, | ||
cmdOptions: { | ||
'n': 'number', | ||
}, | ||
}); | ||
//@ | ||
//@ ### cat(file [, file ...]) | ||
//@ ### cat(file_array) | ||
//@ ### cat([options,] file [, file ...]) | ||
//@ ### cat([options,] file_array) | ||
//@ Available options: | ||
//@ | ||
//@ + `-n`: number all output lines | ||
//@ | ||
//@ Examples: | ||
@@ -34,3 +40,3 @@ //@ | ||
common.error('no such file or directory: ' + file); | ||
} else if (fs.statSync(file).isDirectory()) { | ||
} else if (common.statFollowLinks(file).isDirectory()) { | ||
common.error(file + ': Is a directory'); | ||
@@ -42,4 +48,31 @@ } | ||
if (options.number) { | ||
cat = addNumbers(cat); | ||
} | ||
return cat; | ||
} | ||
module.exports = _cat; | ||
function addNumbers(cat) { | ||
var lines = cat.split('\n'); | ||
var lastLine = lines.pop(); | ||
lines = lines.map(function (line, i) { | ||
return numberedLine(i + 1, line); | ||
}); | ||
if (lastLine.length) { | ||
lastLine = numberedLine(lines.length + 1, lastLine); | ||
} | ||
lines.push(lastLine); | ||
return lines.join('\n'); | ||
} | ||
function numberedLine(n, line) { | ||
// GNU cat use six pad start number + tab. See http://lingrok.org/xref/coreutils/src/cat.c#57 | ||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart | ||
var number = (' ' + n).slice(-6) + '\t'; | ||
return number + line; | ||
} |
@@ -1,2 +0,2 @@ | ||
var fs = require('fs'); | ||
var os = require('os'); | ||
var common = require('./common'); | ||
@@ -11,3 +11,3 @@ | ||
function _cd(options, dir) { | ||
if (!dir) dir = common.getUserHome(); | ||
if (!dir) dir = os.homedir(); | ||
@@ -30,3 +30,3 @@ if (dir === '-') { | ||
try { | ||
fs.statSync(dir); // if this succeeds, it must be some sort of file | ||
common.statFollowLinks(dir); // if this succeeds, it must be some sort of file | ||
err = 'not a directory: ' + dir; | ||
@@ -33,0 +33,0 @@ } catch (e2) { |
@@ -88,3 +88,3 @@ var common = require('./common'); | ||
filePattern.forEach(function addFile(expandedFile) { | ||
var stat = fs.lstatSync(expandedFile); | ||
var stat = common.statNoFollowLinks(expandedFile); | ||
@@ -112,7 +112,7 @@ if (!stat.isSymbolicLink()) { | ||
// When recursing, don't follow symlinks. | ||
if (options.recursive && fs.lstatSync(file).isSymbolicLink()) { | ||
if (options.recursive && common.statNoFollowLinks(file).isSymbolicLink()) { | ||
return; | ||
} | ||
var stat = fs.statSync(file); | ||
var stat = common.statFollowLinks(file); | ||
var isDir = stat.isDirectory(); | ||
@@ -180,3 +180,3 @@ var perms = stat.mode; | ||
// permissions, setuid and setgid can never be cleared. | ||
if (fs.statSync(file).isDirectory()) { | ||
if (common.statFollowLinks(file).isDirectory()) { | ||
newPerms |= (PERMS.SETUID + PERMS.SETGID) & perms; | ||
@@ -210,3 +210,3 @@ } | ||
// form, but not cleared. | ||
if (fs.statSync(file).isDirectory()) { | ||
if (common.statFollowLinks(file).isDirectory()) { | ||
newPerms |= (PERMS.SETUID + PERMS.SETGID) & perms; | ||
@@ -213,0 +213,0 @@ } |
@@ -12,19 +12,4 @@ // Ignore warning about 'new String()' | ||
// objectAssign(target_obj, source_obj1 [, source_obj2 ...]) | ||
// "Ponyfill" for Object.assign | ||
// objectAssign({A:1}, {b:2}, {c:3}) returns {A:1, b:2, c:3} | ||
var objectAssign = typeof Object.assign === 'function' ? | ||
Object.assign : | ||
function objectAssign(target) { | ||
var sources = [].slice.call(arguments, 1); | ||
sources.forEach(function (source) { | ||
Object.keys(source).forEach(function (key) { | ||
target[key] = source[key]; | ||
}); | ||
}); | ||
exports.extend = Object.assign; | ||
return target; | ||
}; | ||
exports.extend = objectAssign; | ||
// Check if we're running under electron | ||
@@ -47,3 +32,3 @@ var isElectron = Boolean(process.versions.electron); | ||
reset: function () { | ||
objectAssign(this, DEFAULT_CONFIG); | ||
Object.assign(this, DEFAULT_CONFIG); | ||
if (!isElectron) { | ||
@@ -72,5 +57,2 @@ this.execPath = process.execPath; | ||
// This is populated by calls to commonl.wrap() | ||
var pipeMethods = []; | ||
// Reliably test if something is any sort of javascript object | ||
@@ -122,3 +104,3 @@ function isObject(a) { | ||
} | ||
options = objectAssign({}, DEFAULT_OPTIONS, options); | ||
options = Object.assign({}, DEFAULT_OPTIONS, options); | ||
@@ -177,15 +159,2 @@ if (!state.errorCode) state.errorCode = options.code; | ||
// Return the home directory in a platform-agnostic way, with consideration for | ||
// older versions of node | ||
function getUserHome() { | ||
var result; | ||
if (os.homedir) { | ||
result = os.homedir(); // node 3+ | ||
} else { | ||
result = process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME']; | ||
} | ||
return result; | ||
} | ||
exports.getUserHome = getUserHome; | ||
// Returns {'alice': true, 'bob': false} when passed a string and dictionary as follows: | ||
@@ -195,2 +164,4 @@ // parseOptions('-a', {'a':'alice', 'b':'bob'}); | ||
// parseOptions({'-r': 'string-value'}, {'r':'reference', 'b':'bob'}); | ||
// Throws an error when passed a string that does not start with '-': | ||
// parseOptions('a', {'a':'alice'}); // throws | ||
function parseOptions(opt, map, errorOptions) { | ||
@@ -206,2 +177,7 @@ // Validate input | ||
if (opt === '--') { | ||
// This means there are no options. | ||
return {}; | ||
} | ||
// All options are false by default | ||
@@ -220,3 +196,3 @@ var options = {}; | ||
if (opt[0] !== '-') { | ||
error("Options string must start with a '-'", errorOptions || {}); | ||
throw new Error("Options string must start with a '-'"); | ||
} | ||
@@ -314,2 +290,14 @@ | ||
// wrappers around common.statFollowLinks and common.statNoFollowLinks that clarify intent | ||
// and improve readability | ||
function statFollowLinks() { | ||
return fs.statSync.apply(fs, arguments); | ||
} | ||
exports.statFollowLinks = statFollowLinks; | ||
function statNoFollowLinks() { | ||
return fs.lstatSync.apply(fs, arguments); | ||
} | ||
exports.statNoFollowLinks = statNoFollowLinks; | ||
// e.g. 'shelljs_a5f185d0443ca...' | ||
@@ -336,5 +324,2 @@ function randomFileName() { | ||
options = options || {}; | ||
if (options.canReceivePipe) { | ||
pipeMethods.push(cmd); | ||
} | ||
return function () { | ||
@@ -389,3 +374,3 @@ var retValue = null; | ||
// Expand the '~' if appropriate | ||
var homeDir = getUserHome(); | ||
var homeDir = os.homedir(); | ||
args = args.map(function (arg) { | ||
@@ -424,5 +409,4 @@ if (typeof arg === 'string' && arg.slice(0, 2) === '~/' || arg === '~') { | ||
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug... | ||
console.error('ShellJS: internal error'); | ||
console.error(e.stack || e); | ||
process.exit(1); | ||
e.name = 'ShellJSInternalError'; | ||
throw e; | ||
} | ||
@@ -453,18 +437,32 @@ if (config.fatal) throw e; | ||
canReceivePipe: false, | ||
cmdOptions: false, | ||
cmdOptions: null, | ||
globStart: 1, | ||
pipeOnly: false, | ||
wrapOutput: true, | ||
unix: true, | ||
wrapOutput: true, | ||
overWrite: false, | ||
}; | ||
// This is populated during plugin registration | ||
var pipeMethods = []; | ||
// Register a new ShellJS command | ||
function _register(name, implementation, wrapOptions) { | ||
wrapOptions = wrapOptions || {}; | ||
// Validate options | ||
Object.keys(wrapOptions).forEach(function (option) { | ||
if (!DEFAULT_WRAP_OPTIONS.hasOwnProperty(option)) { | ||
throw new Error("Unknown option '" + option + "'"); | ||
} | ||
if (typeof wrapOptions[option] !== typeof DEFAULT_WRAP_OPTIONS[option]) { | ||
throw new TypeError("Unsupported type '" + typeof wrapOptions[option] + | ||
"' for option '" + option + "'"); | ||
} | ||
}); | ||
// If an option isn't specified, use the default | ||
wrapOptions = objectAssign({}, DEFAULT_WRAP_OPTIONS, wrapOptions); | ||
wrapOptions = Object.assign({}, DEFAULT_WRAP_OPTIONS, wrapOptions); | ||
if (shell[name] && !wrapOptions.overWrite) { | ||
throw new Error('unable to overwrite `' + name + '` command'); | ||
if (shell[name]) { | ||
throw new Error('Command `' + name + '` already exists'); | ||
} | ||
@@ -478,3 +476,7 @@ | ||
} | ||
if (wrapOptions.canReceivePipe) { | ||
pipeMethods.push(name); | ||
} | ||
} | ||
exports.register = _register; |
@@ -30,3 +30,3 @@ var fs = require('fs'); | ||
try { | ||
if (options.update && fs.statSync(srcFile).mtime < fs.statSync(destFile).mtime) { | ||
if (options.update && common.statFollowLinks(srcFile).mtime < fs.statSync(destFile).mtime) { | ||
return; | ||
@@ -38,5 +38,5 @@ } | ||
if (fs.lstatSync(srcFile).isSymbolicLink() && !options.followsymlink) { | ||
if (common.statNoFollowLinks(srcFile).isSymbolicLink() && !options.followsymlink) { | ||
try { | ||
fs.lstatSync(destFile); | ||
common.statNoFollowLinks(destFile); | ||
common.unlinkSync(destFile); // re-link it | ||
@@ -80,3 +80,3 @@ } catch (e) { | ||
fs.chmodSync(destFile, fs.statSync(srcFile).mode); | ||
fs.chmodSync(destFile, common.statFollowLinks(srcFile).mode); | ||
} | ||
@@ -105,3 +105,3 @@ } | ||
try { | ||
var checkDir = fs.statSync(sourceDir); | ||
var checkDir = common.statFollowLinks(sourceDir); | ||
fs.mkdirSync(destDir, checkDir.mode); | ||
@@ -118,3 +118,3 @@ } catch (e) { | ||
var destFile = destDir + '/' + files[i]; | ||
var srcFileStat = fs.lstatSync(srcFile); | ||
var srcFileStat = common.statNoFollowLinks(srcFile); | ||
@@ -137,3 +137,3 @@ var symlinkFull; | ||
try { | ||
fs.lstatSync(destFile); | ||
common.statNoFollowLinks(destFile); | ||
common.unlinkSync(destFile); // re-link it | ||
@@ -145,3 +145,3 @@ } catch (e) { | ||
} else if (srcFileStat.isSymbolicLink() && opts.followsymlink) { | ||
srcFileStat = fs.statSync(srcFile); | ||
srcFileStat = common.statFollowLinks(srcFile); | ||
if (srcFileStat.isDirectory()) { | ||
@@ -172,3 +172,3 @@ cpdirSyncRecursive(srcFile, destFile, currentDepth, opts); | ||
function cpcheckcycle(sourceDir, srcFile) { | ||
var srcFileStat = fs.lstatSync(srcFile); | ||
var srcFileStat = common.statNoFollowLinks(srcFile); | ||
if (srcFileStat.isSymbolicLink()) { | ||
@@ -181,3 +181,3 @@ // Do cycle check. For example: | ||
// $ cp -RL 1 copy | ||
var cyclecheck = fs.statSync(srcFile); | ||
var cyclecheck = common.statFollowLinks(srcFile); | ||
if (cyclecheck.isDirectory()) { | ||
@@ -235,3 +235,3 @@ var sourcerealpath = fs.realpathSync(sourceDir); | ||
var destExists = fs.existsSync(dest); | ||
var destStat = destExists && fs.statSync(dest); | ||
var destStat = destExists && common.statFollowLinks(dest); | ||
@@ -254,3 +254,3 @@ // Dest is not existing dir, but multiple sources given | ||
} | ||
var srcStat = fs.statSync(src); | ||
var srcStat = common.statFollowLinks(src); | ||
if (!options.noFollowsymlink && srcStat.isDirectory()) { | ||
@@ -268,3 +268,3 @@ if (!options.recursive) { | ||
try { | ||
fs.statSync(path.dirname(dest)); | ||
common.statFollowLinks(path.dirname(dest)); | ||
cpdirSyncRecursive(src, newDest, 0, { no_force: options.no_force, followsymlink: options.followsymlink }); | ||
@@ -271,0 +271,0 @@ } catch (e) { |
@@ -43,2 +43,3 @@ var common = require('./common'); | ||
//@ + `-n`: Suppresses the normal change of directory when adding directories to the stack, so that only the stack is manipulated. | ||
//@ + `-q`: Supresses output to the console. | ||
//@ | ||
@@ -68,2 +69,3 @@ //@ Arguments: | ||
'n': 'no-cd', | ||
'q': 'quiet', | ||
}); | ||
@@ -100,3 +102,3 @@ | ||
_dirStack = dirs; | ||
return _dirs(''); | ||
return _dirs(options.quiet ? '-q' : ''); | ||
} | ||
@@ -111,2 +113,3 @@ exports.pushd = _pushd; | ||
//@ + `-n`: Suppresses the normal change of directory when removing directories from the stack, so that only the stack is manipulated. | ||
//@ + `-q`: Supresses output to the console. | ||
//@ | ||
@@ -137,2 +140,3 @@ //@ Arguments: | ||
'n': 'no-cd', | ||
'q': 'quiet', | ||
}); | ||
@@ -154,3 +158,3 @@ | ||
return _dirs(''); | ||
return _dirs(options.quiet ? '-q' : ''); | ||
} | ||
@@ -165,2 +169,3 @@ exports.popd = _popd; | ||
//@ + `-c`: Clears the directory stack by deleting all of the elements. | ||
//@ + `-q`: Supresses output to the console. | ||
//@ | ||
@@ -183,2 +188,3 @@ //@ Arguments: | ||
'c': 'clear', | ||
'q': 'quiet', | ||
}); | ||
@@ -200,7 +206,11 @@ | ||
common.log(stack[index]); | ||
if (!options.quiet) { | ||
common.log(stack[index]); | ||
} | ||
return stack[index]; | ||
} | ||
common.log(stack.join(' ')); | ||
if (!options.quiet) { | ||
common.log(stack.join(' ')); | ||
} | ||
@@ -207,0 +217,0 @@ return stack; |
@@ -0,1 +1,3 @@ | ||
var format = require('util').format; | ||
var common = require('./common'); | ||
@@ -12,2 +14,3 @@ | ||
//@ + `-e`: interpret backslash escapes (default) | ||
//@ + `-n`: remove trailing newline from output | ||
//@ | ||
@@ -19,2 +22,3 @@ //@ Examples: | ||
//@ var str = echo('hello world'); | ||
//@ echo('-n', 'no newline at end'); | ||
//@ ``` | ||
@@ -24,14 +28,38 @@ //@ | ||
//@ like `.to()`. | ||
function _echo(opts, messages) { | ||
function _echo(opts) { | ||
// allow strings starting with '-', see issue #20 | ||
messages = [].slice.call(arguments, opts ? 0 : 1); | ||
var messages = [].slice.call(arguments, opts ? 0 : 1); | ||
var options = {}; | ||
if (messages[0] === '-e') { | ||
// ignore -e | ||
messages.shift(); | ||
// If the first argument starts with '-', parse it as options string. | ||
// If parseOptions throws, it wasn't an options string. | ||
try { | ||
options = common.parseOptions(messages[0], { | ||
'e': 'escapes', | ||
'n': 'no_newline', | ||
}, { | ||
silent: true, | ||
}); | ||
// Allow null to be echoed | ||
if (messages[0]) { | ||
messages.shift(); | ||
} | ||
} catch (_) { | ||
// Clear out error if an error occurred | ||
common.state.error = null; | ||
} | ||
console.log.apply(console, messages); | ||
return messages.join(' '); | ||
var output = format.apply(null, messages); | ||
// Add newline if -n is not passed. | ||
if (!options.no_newline) { | ||
output += '\n'; | ||
} | ||
process.stdout.write(output); | ||
return output; | ||
} | ||
module.exports = _echo; |
199
src/exec.js
@@ -16,7 +16,4 @@ var common = require('./common'); | ||
// Hack to run child_process.exec() synchronously (sync avoids callback hell) | ||
// Uses a custom wait loop that checks for a flag file, created when the child process is done. | ||
// (Can't do a wait loop that checks for internal Node variables/messages as | ||
// Node is single-threaded; callbacks and other internal state changes are done in the | ||
// event loop). | ||
// We use this function to run exec synchronously while also providing realtime | ||
// output. | ||
function execSync(cmd, opts, pipe) { | ||
@@ -28,7 +25,4 @@ if (!common.config.execPath) { | ||
var tempDir = _tempDir(); | ||
var stderrFile = path.resolve(tempDir + '/' + common.randomFileName()); | ||
var stdoutFile = path.resolve(tempDir + '/' + common.randomFileName()); | ||
var stderrFile = path.resolve(tempDir + '/' + common.randomFileName()); | ||
var codeFile = path.resolve(tempDir + '/' + common.randomFileName()); | ||
var scriptFile = path.resolve(tempDir + '/' + common.randomFileName()); | ||
var sleepFile = path.resolve(tempDir + '/' + common.randomFileName()); | ||
@@ -40,140 +34,59 @@ opts = common.extend({ | ||
maxBuffer: DEFAULT_MAXBUFFER_SIZE, | ||
encoding: 'utf8', | ||
}, opts); | ||
var previousStdoutContent = ''; | ||
var previousStderrContent = ''; | ||
// Echoes stdout and stderr changes from running process, if not silent | ||
function updateStream(streamFile) { | ||
if (opts.silent || !fs.existsSync(streamFile)) { | ||
return; | ||
} | ||
var previousStreamContent; | ||
var procStream; | ||
if (streamFile === stdoutFile) { | ||
previousStreamContent = previousStdoutContent; | ||
procStream = process.stdout; | ||
} else { // assume stderr | ||
previousStreamContent = previousStderrContent; | ||
procStream = process.stderr; | ||
} | ||
var streamContent = fs.readFileSync(streamFile, 'utf8'); | ||
// No changes since last time? | ||
if (streamContent.length <= previousStreamContent.length) { | ||
return; | ||
} | ||
procStream.write(streamContent.substr(previousStreamContent.length)); | ||
previousStreamContent = streamContent; | ||
} | ||
if (fs.existsSync(scriptFile)) common.unlinkSync(scriptFile); | ||
if (fs.existsSync(stderrFile)) common.unlinkSync(stderrFile); | ||
if (fs.existsSync(stdoutFile)) common.unlinkSync(stdoutFile); | ||
if (fs.existsSync(stderrFile)) common.unlinkSync(stderrFile); | ||
if (fs.existsSync(codeFile)) common.unlinkSync(codeFile); | ||
var execCommand = JSON.stringify(common.config.execPath) + ' ' + JSON.stringify(scriptFile); | ||
var script; | ||
opts.cwd = path.resolve(opts.cwd); | ||
var optString = JSON.stringify(opts); | ||
if (typeof child.execSync === 'function') { | ||
script = [ | ||
"var child = require('child_process')", | ||
" , fs = require('fs');", | ||
'var childProcess = child.exec(' + JSON.stringify(cmd) + ', ' + optString + ', function(err) {', | ||
' var fname = ' + JSON.stringify(codeFile) + ';', | ||
' if (!err) {', | ||
' fs.writeFileSync(fname, "0");', | ||
' } else if (err.code === undefined) {', | ||
' fs.writeFileSync(fname, "1");', | ||
' } else {', | ||
' fs.writeFileSync(fname, err.code.toString());', | ||
' }', | ||
'});', | ||
'var stdoutStream = fs.createWriteStream(' + JSON.stringify(stdoutFile) + ');', | ||
'var stderrStream = fs.createWriteStream(' + JSON.stringify(stderrFile) + ');', | ||
'childProcess.stdout.pipe(stdoutStream, {end: false});', | ||
'childProcess.stderr.pipe(stderrStream, {end: false});', | ||
'childProcess.stdout.pipe(process.stdout);', | ||
'childProcess.stderr.pipe(process.stderr);', | ||
].join('\n') + | ||
(pipe ? '\nchildProcess.stdin.end(' + JSON.stringify(pipe) + ');\n' : '\n') + | ||
[ | ||
'var stdoutEnded = false, stderrEnded = false;', | ||
'function tryClosingStdout(){ if(stdoutEnded){ stdoutStream.end(); } }', | ||
'function tryClosingStderr(){ if(stderrEnded){ stderrStream.end(); } }', | ||
"childProcess.stdout.on('end', function(){ stdoutEnded = true; tryClosingStdout(); });", | ||
"childProcess.stderr.on('end', function(){ stderrEnded = true; tryClosingStderr(); });", | ||
].join('\n'); | ||
var paramsToSerialize = { | ||
command: cmd, | ||
execOptions: opts, | ||
pipe: pipe, | ||
stdoutFile: stdoutFile, | ||
stderrFile: stderrFile, | ||
}; | ||
fs.writeFileSync(scriptFile, script); | ||
var execArgs = [ | ||
path.join(__dirname, 'exec-child.js'), | ||
JSON.stringify(paramsToSerialize), | ||
]; | ||
if (opts.silent) { | ||
opts.stdio = 'ignore'; | ||
} else { | ||
opts.stdio = [0, 1, 2]; | ||
} | ||
// Welcome to the future | ||
try { | ||
child.execSync(execCommand, opts); | ||
} catch (e) { | ||
// Clean up immediately if we have an exception | ||
try { common.unlinkSync(scriptFile); } catch (e2) {} | ||
try { common.unlinkSync(stdoutFile); } catch (e2) {} | ||
try { common.unlinkSync(stderrFile); } catch (e2) {} | ||
try { common.unlinkSync(codeFile); } catch (e2) {} | ||
throw e; | ||
} | ||
/* istanbul ignore else */ | ||
if (opts.silent) { | ||
opts.stdio = 'ignore'; | ||
} else { | ||
cmd += ' > ' + stdoutFile + ' 2> ' + stderrFile; // works on both win/unix | ||
opts.stdio = [0, 1, 2]; | ||
} | ||
script = [ | ||
"var child = require('child_process')", | ||
" , fs = require('fs');", | ||
'var childProcess = child.exec(' + JSON.stringify(cmd) + ', ' + optString + ', function(err) {', | ||
' var fname = ' + JSON.stringify(codeFile) + ';', | ||
' if (!err) {', | ||
' fs.writeFileSync(fname, "0");', | ||
' } else if (err.code === undefined) {', | ||
' fs.writeFileSync(fname, "1");', | ||
' } else {', | ||
' fs.writeFileSync(fname, err.code.toString());', | ||
' }', | ||
'});', | ||
].join('\n') + | ||
(pipe ? '\nchildProcess.stdin.end(' + JSON.stringify(pipe) + ');\n' : '\n'); | ||
var code = 0; | ||
fs.writeFileSync(scriptFile, script); | ||
// Welcome to the future | ||
try { | ||
// Bad things if we pass in a `shell` option to child_process.execFileSync, | ||
// so we need to explicitly remove it here. | ||
delete opts.shell; | ||
child.exec(execCommand, opts); | ||
// The wait loop | ||
// sleepFile is used as a dummy I/O op to mitigate unnecessary CPU usage | ||
// (tried many I/O sync ops, writeFileSync() seems to be only one that is effective in reducing | ||
// CPU usage, though apparently not so much on Windows) | ||
while (!fs.existsSync(codeFile)) { updateStream(stdoutFile); fs.writeFileSync(sleepFile, 'a'); } | ||
while (!fs.existsSync(stdoutFile)) { updateStream(stdoutFile); fs.writeFileSync(sleepFile, 'a'); } | ||
while (!fs.existsSync(stderrFile)) { updateStream(stderrFile); fs.writeFileSync(sleepFile, 'a'); } | ||
try { common.unlinkSync(sleepFile); } catch (e) {} | ||
child.execFileSync(common.config.execPath, execArgs, opts); | ||
} catch (e) { | ||
// Commands with non-zero exit code raise an exception. | ||
code = e.status; | ||
} | ||
// At this point codeFile exists, but it's not necessarily flushed yet. | ||
// Keep reading it until it is. | ||
var code = parseInt('', 10); | ||
while (isNaN(code)) { | ||
code = parseInt(fs.readFileSync(codeFile, 'utf8'), 10); | ||
// fs.readFileSync uses buffer encoding by default, so call | ||
// it without the encoding option if the encoding is 'buffer' | ||
var stdout; | ||
var stderr; | ||
if (opts.encoding === 'buffer') { | ||
stdout = fs.readFileSync(stdoutFile); | ||
stderr = fs.readFileSync(stderrFile); | ||
} else { | ||
stdout = fs.readFileSync(stdoutFile, opts.encoding); | ||
stderr = fs.readFileSync(stderrFile, opts.encoding); | ||
} | ||
var stdout = fs.readFileSync(stdoutFile, 'utf8'); | ||
var stderr = fs.readFileSync(stderrFile, 'utf8'); | ||
// No biggie if we can't erase the files now -- they're in a temp dir anyway | ||
try { common.unlinkSync(scriptFile); } catch (e) {} | ||
try { common.unlinkSync(stderrFile); } catch (e) {} | ||
try { common.unlinkSync(stdoutFile); } catch (e) {} | ||
try { common.unlinkSync(stderrFile); } catch (e) {} | ||
try { common.unlinkSync(codeFile); } catch (e) {} | ||
@@ -189,5 +102,2 @@ if (code !== 0) { | ||
function execAsync(cmd, opts, pipe, callback) { | ||
var stdout = ''; | ||
var stderr = ''; | ||
opts = common.extend({ | ||
@@ -198,5 +108,6 @@ silent: common.config.silent, | ||
maxBuffer: DEFAULT_MAXBUFFER_SIZE, | ||
encoding: 'utf8', | ||
}, opts); | ||
var c = child.exec(cmd, opts, function (err) { | ||
var c = child.exec(cmd, opts, function (err, stdout, stderr) { | ||
if (callback) { | ||
@@ -207,2 +118,3 @@ if (!err) { | ||
// See issue #536 | ||
/* istanbul ignore next */ | ||
callback(1, stdout, stderr); | ||
@@ -217,12 +129,7 @@ } else { | ||
c.stdout.on('data', function (data) { | ||
stdout += data; | ||
if (!opts.silent) process.stdout.write(data); | ||
}); | ||
if (!opts.silent) { | ||
c.stdout.pipe(process.stdout); | ||
c.stderr.pipe(process.stderr); | ||
} | ||
c.stderr.on('data', function (data) { | ||
stderr += data; | ||
if (!opts.silent) process.stderr.write(data); | ||
}); | ||
return c; | ||
@@ -233,7 +140,9 @@ } | ||
//@ ### exec(command [, options] [, callback]) | ||
//@ Available options (all `false` by default): | ||
//@ Available options: | ||
//@ | ||
//@ + `async`: Asynchronous execution. If a callback is provided, it will be set to | ||
//@ `true`, regardless of the passed value. | ||
//@ + `silent`: Do not echo program output to console. | ||
//@ `true`, regardless of the passed value (default: `false`). | ||
//@ + `silent`: Do not echo program output to console (default: `false`). | ||
//@ + `encoding`: Character encoding to use. Affects the returned stdout and stderr values, and | ||
//@ what is written to stdout and stderr when not in silent mode (default: `'utf8'`). | ||
//@ + and any option available to Node.js's | ||
@@ -240,0 +149,0 @@ //@ [child_process.exec()](https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback) |
@@ -1,2 +0,1 @@ | ||
var fs = require('fs'); | ||
var path = require('path'); | ||
@@ -45,3 +44,3 @@ var common = require('./common'); | ||
try { | ||
stat = fs.statSync(file); | ||
stat = common.statFollowLinks(file); | ||
} catch (e) { | ||
@@ -48,0 +47,0 @@ common.error('no such file or directory: ' + file); |
@@ -50,3 +50,2 @@ var common = require('./common'); | ||
var contents = file === '-' ? pipe : fs.readFileSync(file, 'utf8'); | ||
var lines = contents.split(/\r*\n/); | ||
if (options.nameOnly) { | ||
@@ -57,2 +56,3 @@ if (contents.match(regex)) { | ||
} else { | ||
var lines = contents.split('\n'); | ||
lines.forEach(function (line) { | ||
@@ -59,0 +59,0 @@ var matched = line.match(regex); |
@@ -11,3 +11,3 @@ var common = require('./common'); | ||
// This reads n or more lines, or the entire file, whichever is less. | ||
// Reads |numLines| lines or the entire file, whichever is less. | ||
function readSomeLines(file, numLines) { | ||
@@ -18,10 +18,4 @@ var buf = common.buffer(); | ||
var pos = 0; | ||
var fdr = null; | ||
try { | ||
fdr = fs.openSync(file, 'r'); | ||
} catch (e) { | ||
common.error('cannot read file: ' + file); | ||
} | ||
var fdr = fs.openSync(file, 'r'); | ||
var numLinesRead = 0; | ||
@@ -40,2 +34,3 @@ var ret = ''; | ||
} | ||
//@ | ||
@@ -82,3 +77,3 @@ //@ ### head([{'-n': \<num\>},] file [, file ...]) | ||
return; | ||
} else if (fs.statSync(file).isDirectory()) { | ||
} else if (common.statFollowLinks(file).isDirectory()) { | ||
common.error("error reading '" + file + "': Is a directory", { | ||
@@ -85,0 +80,0 @@ continue: true, |
@@ -51,3 +51,3 @@ var fs = require('fs'); | ||
common.error('Source file does not exist', { continue: true }); | ||
} else if (isWindows && fs.statSync(resolvedSourcePath).isDirectory()) { | ||
} else if (isWindows && common.statFollowLinks(resolvedSourcePath).isDirectory()) { | ||
linkType = 'junction'; | ||
@@ -54,0 +54,0 @@ } |
@@ -65,3 +65,3 @@ var path = require('path'); | ||
if (options.long) { | ||
stat = stat || (options.link ? fs.statSync(abs) : fs.lstatSync(abs)); | ||
stat = stat || (options.link ? common.statFollowLinks(abs) : common.statNoFollowLinks(abs)); | ||
list.push(addLsAttributes(relName, stat)); | ||
@@ -78,3 +78,12 @@ } else { | ||
try { | ||
stat = options.link ? fs.statSync(p) : fs.lstatSync(p); | ||
stat = options.link ? common.statFollowLinks(p) : common.statNoFollowLinks(p); | ||
// follow links to directories by default | ||
if (stat.isSymbolicLink()) { | ||
try { | ||
var _stat = common.statFollowLinks(p); | ||
if (_stat.isDirectory()) { | ||
stat = _stat; | ||
} | ||
} catch (_) {} // bad symlink, treat it like a file | ||
} | ||
} catch (e) { | ||
@@ -81,0 +90,0 @@ common.error('no such file or directory: ' + p, 2, { continue: true }); |
@@ -60,3 +60,3 @@ var common = require('./common'); | ||
try { | ||
var stat = fs.lstatSync(dir); | ||
var stat = common.statNoFollowLinks(dir); | ||
if (!options.fullpath) { | ||
@@ -63,0 +63,0 @@ common.error('path already exists: ' + dir, { continue: true }); |
@@ -54,3 +54,3 @@ var fs = require('fs'); | ||
var exists = fs.existsSync(dest); | ||
var stats = exists && fs.statSync(dest); | ||
var stats = exists && common.statFollowLinks(dest); | ||
@@ -78,3 +78,3 @@ // Dest is not existing dir, but multiple sources given | ||
var thisDest = dest; | ||
if (fs.existsSync(dest) && fs.statSync(dest).isDirectory()) { | ||
if (fs.existsSync(dest) && common.statFollowLinks(dest).isDirectory()) { | ||
thisDest = path.normalize(dest + '/' + path.basename(src)); | ||
@@ -81,0 +81,0 @@ } |
@@ -28,3 +28,3 @@ var common = require('./common'); | ||
var file = dir + '/' + files[i]; | ||
var currFile = fs.lstatSync(file); | ||
var currFile = common.statNoFollowLinks(file); | ||
@@ -120,3 +120,3 @@ if (currFile.isDirectory()) { // Recursive function back to the beginning | ||
try { | ||
stats = fs.statSync(file); | ||
stats = common.statFollowLinks(file); | ||
} catch (e) { | ||
@@ -180,3 +180,3 @@ // symlink is broken, so remove the symlink itself | ||
: file; | ||
lstats = fs.lstatSync(filepath); // test for existence | ||
lstats = common.statNoFollowLinks(filepath); // test for existence | ||
} catch (e) { | ||
@@ -183,0 +183,0 @@ // Path does not exist, no force flag given |
@@ -72,3 +72,3 @@ var common = require('./common'); | ||
var contents = file === '-' ? pipe : fs.readFileSync(file, 'utf8'); | ||
var lines = contents.split(/\r*\n/); | ||
var lines = contents.split('\n'); | ||
var result = lines.map(function (line) { | ||
@@ -75,0 +75,0 @@ return line.replace(regex, replacement); |
@@ -70,13 +70,12 @@ var common = require('./common'); | ||
var lines = []; | ||
files.forEach(function (file) { | ||
var lines = files.reduce(function (accum, file) { | ||
if (file !== '-') { | ||
if (!fs.existsSync(file)) { | ||
common.error('no such file or directory: ' + file, { continue: true }); | ||
return; | ||
} else if (fs.statSync(file).isDirectory()) { | ||
return accum; | ||
} else if (common.statFollowLinks(file).isDirectory()) { | ||
common.error('read failed: ' + file + ': Is a directory', { | ||
continue: true, | ||
}); | ||
return; | ||
return accum; | ||
} | ||
@@ -86,7 +85,6 @@ } | ||
var contents = file === '-' ? pipe : fs.readFileSync(file, 'utf8'); | ||
lines = lines.concat(contents.trimRight().split(/\r*\n/)); | ||
}); | ||
return accum.concat(contents.trimRight().split('\n')); | ||
}, []); | ||
var sorted; | ||
sorted = lines.sort(options.numerical ? numericalCmp : unixCmp); | ||
var sorted = lines.sort(options.numerical ? numericalCmp : unixCmp); | ||
@@ -93,0 +91,0 @@ if (options.reverse) { |
@@ -53,3 +53,3 @@ var common = require('./common'); | ||
return; | ||
} else if (fs.statSync(file).isDirectory()) { | ||
} else if (common.statFollowLinks(file).isDirectory()) { | ||
common.error("error reading '" + file + "': Is a directory", { | ||
@@ -56,0 +56,0 @@ continue: true, |
@@ -14,3 +14,3 @@ var common = require('./common'); | ||
if (!fs.statSync(dir).isDirectory()) return false; | ||
if (!common.statFollowLinks(dir).isDirectory()) return false; | ||
@@ -44,4 +44,3 @@ var testFile = dir + '/' + common.randomFileName(); | ||
state.tempDir = writeableDir(os.tmpdir && os.tmpdir()) || // node 0.10+ | ||
writeableDir(os.tmpDir && os.tmpDir()) || // node 0.8+ | ||
state.tempDir = writeableDir(os.tmpdir()) || | ||
writeableDir(process.env.TMPDIR) || | ||
@@ -48,0 +47,0 @@ writeableDir(process.env.TEMP) || |
@@ -55,3 +55,3 @@ var common = require('./common'); | ||
try { | ||
return fs.lstatSync(path).isSymbolicLink(); | ||
return common.statNoFollowLinks(path).isSymbolicLink(); | ||
} catch (e) { | ||
@@ -66,3 +66,3 @@ return false; | ||
var stats = fs.statSync(path); | ||
var stats = common.statFollowLinks(path); | ||
@@ -69,0 +69,0 @@ if (options.block) return stats.isBlockDevice(); |
@@ -106,3 +106,3 @@ var common = require('./common'); | ||
try { | ||
return fs.statSync(filePath); | ||
return common.statFollowLinks(filePath); | ||
} catch (e) { | ||
@@ -109,0 +109,0 @@ return null; |
@@ -48,7 +48,7 @@ var common = require('./common'); | ||
common.error(input + ': No such file or directory'); | ||
} else if (fs.statSync(input).isDirectory()) { | ||
} else if (common.statFollowLinks(input).isDirectory()) { | ||
common.error("error reading '" + input + "'"); | ||
} | ||
} | ||
if (output && fs.existsSync(output) && fs.statSync(output).isDirectory()) { | ||
if (output && fs.existsSync(output) && common.statFollowLinks(output).isDirectory()) { | ||
common.error(output + ': Is a directory'); | ||
@@ -59,3 +59,3 @@ } | ||
trimRight(). | ||
split(/\r*\n/); | ||
split('\n'); | ||
@@ -62,0 +62,0 @@ var compare = function (a, b) { |
@@ -22,3 +22,3 @@ var common = require('./common'); | ||
function checkPath(pathName) { | ||
return fs.existsSync(pathName) && !fs.statSync(pathName).isDirectory(); | ||
return fs.existsSync(pathName) && !common.statFollowLinks(pathName).isDirectory(); | ||
} | ||
@@ -25,0 +25,0 @@ |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
200526
42
3147
813
39
12
2