rimraf-windows.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. "use strict";
  2. // This is the same as rimrafPosix, with the following changes:
  3. //
  4. // 1. EBUSY, ENFILE, EMFILE trigger retries and/or exponential backoff
  5. // 2. All non-directories are removed first and then all directories are
  6. // removed in a second sweep.
  7. // 3. If we hit ENOTEMPTY in the second sweep, fall back to move-remove on
  8. // the that folder.
  9. //
  10. // Note: "move then remove" is 2-10 times slower, and just as unreliable.
  11. Object.defineProperty(exports, "__esModule", { value: true });
  12. exports.rimrafWindowsSync = exports.rimrafWindows = void 0;
  13. const path_1 = require("path");
  14. const fix_eperm_js_1 = require("./fix-eperm.js");
  15. const fs_js_1 = require("./fs.js");
  16. const ignore_enoent_js_1 = require("./ignore-enoent.js");
  17. const readdir_or_error_js_1 = require("./readdir-or-error.js");
  18. const retry_busy_js_1 = require("./retry-busy.js");
  19. const rimraf_move_remove_js_1 = require("./rimraf-move-remove.js");
  20. const { unlink, rmdir, lstat } = fs_js_1.promises;
  21. const rimrafWindowsFile = (0, retry_busy_js_1.retryBusy)((0, fix_eperm_js_1.fixEPERM)(unlink));
  22. const rimrafWindowsFileSync = (0, retry_busy_js_1.retryBusySync)((0, fix_eperm_js_1.fixEPERMSync)(fs_js_1.unlinkSync));
  23. const rimrafWindowsDirRetry = (0, retry_busy_js_1.retryBusy)((0, fix_eperm_js_1.fixEPERM)(rmdir));
  24. const rimrafWindowsDirRetrySync = (0, retry_busy_js_1.retryBusySync)((0, fix_eperm_js_1.fixEPERMSync)(fs_js_1.rmdirSync));
  25. const rimrafWindowsDirMoveRemoveFallback = async (path, opt) => {
  26. /* c8 ignore start */
  27. if (opt?.signal?.aborted) {
  28. throw opt.signal.reason;
  29. }
  30. /* c8 ignore stop */
  31. // already filtered, remove from options so we don't call unnecessarily
  32. const { filter, ...options } = opt;
  33. try {
  34. return await rimrafWindowsDirRetry(path, options);
  35. }
  36. catch (er) {
  37. if (er?.code === 'ENOTEMPTY') {
  38. return await (0, rimraf_move_remove_js_1.rimrafMoveRemove)(path, options);
  39. }
  40. throw er;
  41. }
  42. };
  43. const rimrafWindowsDirMoveRemoveFallbackSync = (path, opt) => {
  44. if (opt?.signal?.aborted) {
  45. throw opt.signal.reason;
  46. }
  47. // already filtered, remove from options so we don't call unnecessarily
  48. const { filter, ...options } = opt;
  49. try {
  50. return rimrafWindowsDirRetrySync(path, options);
  51. }
  52. catch (er) {
  53. const fer = er;
  54. if (fer?.code === 'ENOTEMPTY') {
  55. return (0, rimraf_move_remove_js_1.rimrafMoveRemoveSync)(path, options);
  56. }
  57. throw er;
  58. }
  59. };
  60. const START = Symbol('start');
  61. const CHILD = Symbol('child');
  62. const FINISH = Symbol('finish');
  63. const rimrafWindows = async (path, opt) => {
  64. if (opt?.signal?.aborted) {
  65. throw opt.signal.reason;
  66. }
  67. try {
  68. return await rimrafWindowsDir(path, opt, await lstat(path), START);
  69. }
  70. catch (er) {
  71. if (er?.code === 'ENOENT')
  72. return true;
  73. throw er;
  74. }
  75. };
  76. exports.rimrafWindows = rimrafWindows;
  77. const rimrafWindowsSync = (path, opt) => {
  78. if (opt?.signal?.aborted) {
  79. throw opt.signal.reason;
  80. }
  81. try {
  82. return rimrafWindowsDirSync(path, opt, (0, fs_js_1.lstatSync)(path), START);
  83. }
  84. catch (er) {
  85. if (er?.code === 'ENOENT')
  86. return true;
  87. throw er;
  88. }
  89. };
  90. exports.rimrafWindowsSync = rimrafWindowsSync;
  91. const rimrafWindowsDir = async (path, opt, ent, state = START) => {
  92. if (opt?.signal?.aborted) {
  93. throw opt.signal.reason;
  94. }
  95. const entries = ent.isDirectory() ? await (0, readdir_or_error_js_1.readdirOrError)(path) : null;
  96. if (!Array.isArray(entries)) {
  97. // this can only happen if lstat/readdir lied, or if the dir was
  98. // swapped out with a file at just the right moment.
  99. /* c8 ignore start */
  100. if (entries) {
  101. if (entries.code === 'ENOENT') {
  102. return true;
  103. }
  104. if (entries.code !== 'ENOTDIR') {
  105. throw entries;
  106. }
  107. }
  108. /* c8 ignore stop */
  109. if (opt.filter && !(await opt.filter(path, ent))) {
  110. return false;
  111. }
  112. // is a file
  113. await (0, ignore_enoent_js_1.ignoreENOENT)(rimrafWindowsFile(path, opt));
  114. return true;
  115. }
  116. const s = state === START ? CHILD : state;
  117. const removedAll = (await Promise.all(entries.map(ent => rimrafWindowsDir((0, path_1.resolve)(path, ent.name), opt, ent, s)))).reduce((a, b) => a && b, true);
  118. if (state === START) {
  119. return rimrafWindowsDir(path, opt, ent, FINISH);
  120. }
  121. else if (state === FINISH) {
  122. if (opt.preserveRoot === false && path === (0, path_1.parse)(path).root) {
  123. return false;
  124. }
  125. if (!removedAll) {
  126. return false;
  127. }
  128. if (opt.filter && !(await opt.filter(path, ent))) {
  129. return false;
  130. }
  131. await (0, ignore_enoent_js_1.ignoreENOENT)(rimrafWindowsDirMoveRemoveFallback(path, opt));
  132. }
  133. return true;
  134. };
  135. const rimrafWindowsDirSync = (path, opt, ent, state = START) => {
  136. const entries = ent.isDirectory() ? (0, readdir_or_error_js_1.readdirOrErrorSync)(path) : null;
  137. if (!Array.isArray(entries)) {
  138. // this can only happen if lstat/readdir lied, or if the dir was
  139. // swapped out with a file at just the right moment.
  140. /* c8 ignore start */
  141. if (entries) {
  142. if (entries.code === 'ENOENT') {
  143. return true;
  144. }
  145. if (entries.code !== 'ENOTDIR') {
  146. throw entries;
  147. }
  148. }
  149. /* c8 ignore stop */
  150. if (opt.filter && !opt.filter(path, ent)) {
  151. return false;
  152. }
  153. // is a file
  154. (0, ignore_enoent_js_1.ignoreENOENTSync)(() => rimrafWindowsFileSync(path, opt));
  155. return true;
  156. }
  157. let removedAll = true;
  158. for (const ent of entries) {
  159. const s = state === START ? CHILD : state;
  160. const p = (0, path_1.resolve)(path, ent.name);
  161. removedAll = rimrafWindowsDirSync(p, opt, ent, s) && removedAll;
  162. }
  163. if (state === START) {
  164. return rimrafWindowsDirSync(path, opt, ent, FINISH);
  165. }
  166. else if (state === FINISH) {
  167. if (opt.preserveRoot === false && path === (0, path_1.parse)(path).root) {
  168. return false;
  169. }
  170. if (!removedAll) {
  171. return false;
  172. }
  173. if (opt.filter && !opt.filter(path, ent)) {
  174. return false;
  175. }
  176. (0, ignore_enoent_js_1.ignoreENOENTSync)(() => {
  177. rimrafWindowsDirMoveRemoveFallbackSync(path, opt);
  178. });
  179. }
  180. return true;
  181. };
  182. //# sourceMappingURL=rimraf-windows.js.map