Blame view
node_modules/shelljs/src/rm.js
4.15 KB
f7563de62
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 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; |