diff options
Diffstat (limited to 'node_modules/shelljs/src/rm.js')
-rw-r--r-- | node_modules/shelljs/src/rm.js | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/node_modules/shelljs/src/rm.js b/node_modules/shelljs/src/rm.js new file mode 100644 index 000000000..595368114 --- /dev/null +++ b/node_modules/shelljs/src/rm.js @@ -0,0 +1,150 @@ +var common = require('./common'); +var fs = require('fs'); + +common.register('rm', _rm, { + cmdOptions: { + 'f': 'force', + 'r': 'recursive', + 'R': 'recursive', + }, +}); + +// Recursively removes 'dir' +// Adapted from https://github.com/ryanmcgrath/wrench-js +// +// Copyright (c) 2010 Ryan McGrath +// Copyright (c) 2012 Artur Adib +// +// Licensed under the MIT License +// http://www.opensource.org/licenses/mit-license.php +function rmdirSyncRecursive(dir, force) { + var files; + + files = fs.readdirSync(dir); + + // Loop through and delete everything in the sub-tree after checking it + for (var i = 0; i < files.length; i++) { + var file = dir + '/' + files[i]; + var currFile = fs.lstatSync(file); + + if (currFile.isDirectory()) { // Recursive function back to the beginning + rmdirSyncRecursive(file, force); + } else { // Assume it's a file - perhaps a try/catch belongs here? + if (force || isWriteable(file)) { + try { + common.unlinkSync(file); + } catch (e) { + /* istanbul ignore next */ + common.error('could not remove file (code ' + e.code + '): ' + file, { + continue: true, + }); + } + } + } + } + + // Now that we know everything in the sub-tree has been deleted, we can delete the main directory. + // Huzzah for the shopkeep. + + var result; + try { + // Retry on windows, sometimes it takes a little time before all the files in the directory are gone + var start = Date.now(); + + // TODO: replace this with a finite loop + for (;;) { + try { + result = fs.rmdirSync(dir); + if (fs.existsSync(dir)) throw { code: 'EAGAIN' }; + break; + } catch (er) { + /* istanbul ignore next */ + // In addition to error codes, also check if the directory still exists and loop again if true + if (process.platform === 'win32' && (er.code === 'ENOTEMPTY' || er.code === 'EBUSY' || er.code === 'EPERM' || er.code === 'EAGAIN')) { + if (Date.now() - start > 1000) throw er; + } else if (er.code === 'ENOENT') { + // Directory did not exist, deletion was successful + break; + } else { + throw er; + } + } + } + } catch (e) { + common.error('could not remove directory (code ' + e.code + '): ' + dir, { continue: true }); + } + + return result; +} // rmdirSyncRecursive + +// Hack to determine if file has write permissions for current user +// Avoids having to check user, group, etc, but it's probably slow +function isWriteable(file) { + var writePermission = true; + try { + var __fd = fs.openSync(file, 'a'); + fs.closeSync(__fd); + } catch (e) { + writePermission = false; + } + + return writePermission; +} + +//@ +//@ ### rm([options,] file [, file ...]) +//@ ### rm([options,] file_array) +//@ Available options: +//@ +//@ + `-f`: force +//@ + `-r, -R`: recursive +//@ +//@ Examples: +//@ +//@ ```javascript +//@ rm('-rf', '/tmp/*'); +//@ rm('some_file.txt', 'another_file.txt'); +//@ rm(['some_file.txt', 'another_file.txt']); // same as above +//@ ``` +//@ +//@ Removes files. +function _rm(options, files) { + if (!files) common.error('no paths given'); + + // Convert to array + files = [].slice.call(arguments, 1); + + files.forEach(function (file) { + var stats; + try { + stats = fs.lstatSync(file); // test for existence + } catch (e) { + // Path does not exist, no force flag given + if (!options.force) { + common.error('no such file or directory: ' + file, { continue: true }); + } + return; // skip file + } + + // If here, path exists + if (stats.isFile()) { + if (options.force || isWriteable(file)) { + // -f was passed, or file is writable, so it can be removed + common.unlinkSync(file); + } else { + common.error('permission denied: ' + file, { continue: true }); + } + } else if (stats.isDirectory()) { + if (options.recursive) { + // -r was passed, so directory can be removed + rmdirSyncRecursive(file, options.force); + } else { + common.error('path is a directory', { continue: true }); + } + } else if (stats.isSymbolicLink() || stats.isFIFO()) { + common.unlinkSync(file); + } + }); // forEach(file) + return ''; +} // rm +module.exports = _rm; |