1 | "use strict";
|
2 |
|
3 | const pathUtil = require("path");
|
4 | const fs = require("./utils/fs");
|
5 | const validate = require("./utils/validate");
|
6 | const list = require("./list");
|
7 |
|
8 | const validateInput = (methodName, path) => {
|
9 | const methodSignature = `${methodName}([path])`;
|
10 | validate.argument(methodSignature, "path", path, ["string", "undefined"]);
|
11 | };
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 | const removeSync = path => {
|
18 | try {
|
19 |
|
20 | fs.unlinkSync(path);
|
21 | } catch (err) {
|
22 | if (
|
23 | err.code === "EPERM" ||
|
24 | err.code === "EISDIR" ||
|
25 | err.code === "ENOTEMPTY"
|
26 | ) {
|
27 |
|
28 | list.sync(path).forEach(filename => {
|
29 | removeSync(pathUtil.join(path, filename));
|
30 | });
|
31 |
|
32 |
|
33 | fs.rmdirSync(path);
|
34 | } else if (err.code === "ENOENT") {
|
35 |
|
36 | } else {
|
37 |
|
38 | throw err;
|
39 | }
|
40 | }
|
41 | };
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 | const removeAsyncInternal = (path, retryCount) => {
|
48 | return new Promise((resolve, reject) => {
|
49 | const retryInAWhileOrFail = err => {
|
50 | if (retryCount === 3) {
|
51 |
|
52 | reject(err);
|
53 | } else {
|
54 |
|
55 | setTimeout(() => {
|
56 | removeAsyncInternal(path, retryCount + 1).then(resolve, reject);
|
57 | }, 100);
|
58 | }
|
59 | };
|
60 |
|
61 | const removeEverythingInsideDirectory = () => {
|
62 | return list.async(path).then(filenamesInsideDir => {
|
63 | const promises = filenamesInsideDir.map(filename => {
|
64 | return removeAsyncInternal(pathUtil.join(path, filename), 0);
|
65 | });
|
66 | return Promise.all(promises);
|
67 | });
|
68 | };
|
69 |
|
70 |
|
71 | fs.unlink(path)
|
72 | .then(resolve)
|
73 | .catch(err => {
|
74 | if (err.code === "EBUSY") {
|
75 | retryInAWhileOrFail(err);
|
76 | } else if (
|
77 | err.code === "EPERM" ||
|
78 | err.code === "EISDIR" ||
|
79 | err.code === "ENOTEMPTY"
|
80 | ) {
|
81 |
|
82 |
|
83 | removeEverythingInsideDirectory()
|
84 | .then(() => {
|
85 |
|
86 | return fs.rmdir(path);
|
87 | })
|
88 | .then(resolve)
|
89 | .catch(err2 => {
|
90 | if (
|
91 | err2.code === "EBUSY" ||
|
92 | err2.code === "EPERM" ||
|
93 | err2.code === "ENOTEMPTY"
|
94 | ) {
|
95 |
|
96 |
|
97 | retryInAWhileOrFail(err2);
|
98 | } else {
|
99 | reject(err2);
|
100 | }
|
101 | });
|
102 | } else if (err.code === "ENOENT") {
|
103 |
|
104 | resolve();
|
105 | } else {
|
106 |
|
107 | reject(err);
|
108 | }
|
109 | });
|
110 | });
|
111 | };
|
112 |
|
113 | const removeAsync = path => {
|
114 | return removeAsyncInternal(path, 0);
|
115 | };
|
116 |
|
117 |
|
118 |
|
119 |
|
120 |
|
121 | exports.validateInput = validateInput;
|
122 | exports.sync = removeSync;
|
123 | exports.async = removeAsync;
|