@jsenv/filesystem 4.3.2 → 4.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -3
- package/src/{assertDirectoryPresence.js → assert_directory_presence.js} +3 -3
- package/src/{assertFilePresence.js → assert_file_presence.js} +3 -3
- package/src/{copyDirectoryContent.js → copy/copy_directory_content.js} +7 -7
- package/src/copy/copy_directory_content_sync.js +90 -0
- package/src/copy/copy_directory_sync.js +9 -0
- package/src/{copyEntry.js → copy/copy_entry.js} +13 -13
- package/src/copy/copy_entry_sync.js +212 -0
- package/src/{registerDirectoryLifecycle.js → lifecycle/register_directory_lifecycle.js} +5 -5
- package/src/{registerFileLifecycle.js → lifecycle/register_file_lifecycle.js} +5 -5
- package/src/{collectDirectoryMatchReport.js → list/collect_directory_match_report.js} +5 -5
- package/src/{collectFiles.js → list/collect_files.js} +4 -4
- package/src/{listFilesMatching.js → list/list_files_matching.js} +1 -1
- package/src/main.js +78 -35
- package/src/{moveDirectoryContent.js → move/move_directory_content.js} +7 -7
- package/src/{moveEntry.js → move/move_entry.js} +8 -8
- package/src/{ensureParentDirectories.js → read_write/ensure_parent_directories.js} +3 -3
- package/src/read_write/ensure_parent_directories_sync.js +16 -0
- package/src/{readDirectory.js → read_write/read_directory.js} +2 -1
- package/src/read_write/read_directory_sync.js +10 -0
- package/src/{readFile.js → read_write/read_file.js} +1 -1
- package/src/read_write/read_file_structure_sync.js +57 -0
- package/src/{readFileSync.js → read_write/read_file_sync.js} +1 -1
- package/src/{readSymbolicLink.js → read_write/read_symbolic_link.js} +1 -1
- package/src/read_write/read_symbolic_link_sync.js +17 -0
- package/src/{grantPermissionsOnEntry.js → read_write/stat/grant_permissions_on_entry.js} +3 -3
- package/src/{internal → read_write/stat}/read_entry_info.js +1 -1
- package/src/{readEntryModificationTime.js → read_write/stat/read_entry_modification_time.js} +1 -1
- package/src/{readEntryPermissions.js → read_write/stat/read_entry_permissions.js} +2 -2
- package/src/{readEntryStat.js → read_write/stat/read_entry_stat.js} +2 -2
- package/src/read_write/stat/read_entry_stat_sync.js +92 -0
- package/src/{testEntryPermissions.js → read_write/stat/test_entry_permissions.js} +1 -1
- package/src/{writeEntryModificationTime.js → read_write/stat/write_entry_modification_time.js} +1 -1
- package/src/read_write/stat/write_entry_modification_time_sync.js +14 -0
- package/src/{writeEntryPermissions.js → read_write/stat/write_entry_permissions.js} +2 -2
- package/src/read_write/stat/write_entry_permissions_sync.js +77 -0
- package/src/{writeDirectory.js → read_write/write_directory.js} +3 -3
- package/src/read_write/write_directory_sync.js +42 -0
- package/src/{writeFile.js → read_write/write_file.js} +2 -2
- package/src/read_write/write_file_structure_sync.js +13 -0
- package/src/{writeFileSync.js → read_write/write_file_sync.js} +1 -1
- package/src/{writeSymbolicLink.js → read_write/write_symbolic_link.js} +5 -5
- package/src/read_write/write_symbolic_link_sync.js +115 -0
- package/src/remove/clear_directory_sync.js +68 -0
- package/src/{ensureEmptyDirectory.js → remove/ensure_empty_directory.js} +9 -7
- package/src/remove/ensure_empty_directory_sync.js +34 -0
- package/src/remove/remove_directory.js +8 -0
- package/src/remove/remove_directory_sync.js +8 -0
- package/src/{removeEntry.js → remove/remove_entry.js} +3 -3
- package/src/remove/remove_entry_sync.js +240 -0
- package/src/remove/remove_file.js +5 -0
- package/src/remove/remove_file_sync.js +5 -0
- package/src/internal/getCommandArgument.js +0 -27
- /package/src/{bufferToEtag.js → buffer_to_etag.js} +0 -0
- /package/src/{internal/createWatcher.js → lifecycle/create_watcher.js} +0 -0
- /package/src/{internal → lifecycle}/guard_second_call.js +0 -0
- /package/src/{internal → lifecycle}/track_resources.js +0 -0
- /package/src/{comparePathnames.js → path_and_url/compare_pathnames.js} +0 -0
- /package/src/{directory_url_validation.js → path_and_url/directory_url_validation.js} +0 -0
- /package/src/{ensureWindowsDriveLetter.js → path_and_url/ensure_windows_drive_letter.js} +0 -0
- /package/src/{fileSystemRootUrl.js → path_and_url/file_system_root_url.js} +0 -0
- /package/src/{file_url_validation.js → path_and_url/file_url_validation.js} +0 -0
- /package/src/{internal/urlTargetsSameFileSystemPath.js → path_and_url/url_targets_same_file_system_path.js} +0 -0
- /package/src/{getRealFileSystemUrlSync.js → read_write/get_real_file_system_url_sync.js} +0 -0
- /package/src/{internal → read_write/stat}/permissions.js +0 -0
- /package/src/{internal/statsToType.js → read_write/stat/stats_to_type.js} +0 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { symlinkSync } from "node:fs";
|
|
2
|
+
import {
|
|
3
|
+
fileSystemPathToUrl,
|
|
4
|
+
urlToFileSystemPath,
|
|
5
|
+
resolveUrl,
|
|
6
|
+
isFileSystemPath,
|
|
7
|
+
} from "@jsenv/urls";
|
|
8
|
+
|
|
9
|
+
import { assertAndNormalizeFileUrl } from "../path_and_url/file_url_validation.js";
|
|
10
|
+
import { removeEntrySync } from "../remove/remove_entry_sync.js";
|
|
11
|
+
import { readEntryStatSync } from "./stat/read_entry_stat_sync.js";
|
|
12
|
+
import { readSymbolicLinkSync } from "./read_symbolic_link_sync.js";
|
|
13
|
+
import { ensureParentDirectoriesSync } from "./ensure_parent_directories_sync.js";
|
|
14
|
+
|
|
15
|
+
const isWindows = process.platform === "win32";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Writes a symbolic link pointing from a filesystem node to an other
|
|
19
|
+
* @param {string} from Where symlink is written
|
|
20
|
+
* @param {string} to The symlink target
|
|
21
|
+
* @param {"file" | "dir"} [type] Symlink type if you know it before hand
|
|
22
|
+
* @param {boolean} [allowUseless=false] Prevent error when symlink already exists with the same target
|
|
23
|
+
* @param {boolean} [allowOverwrite=false] Will replace any existing symlink
|
|
24
|
+
*/
|
|
25
|
+
export const writeSymbolicLinkSync = ({
|
|
26
|
+
from,
|
|
27
|
+
to,
|
|
28
|
+
type,
|
|
29
|
+
allowUseless = false,
|
|
30
|
+
allowOverwrite = false,
|
|
31
|
+
}) => {
|
|
32
|
+
const fromUrl = assertAndNormalizeFileUrl(from);
|
|
33
|
+
const toInfo = getToInfo(to, fromUrl);
|
|
34
|
+
// Node.js doc at https://nodejs.org/api/fs.html#fssymlinktarget-path-type-callback
|
|
35
|
+
// states the following:
|
|
36
|
+
// "If the type argument is not set, Node.js will autodetect
|
|
37
|
+
// target type and use 'file' or 'dir'"
|
|
38
|
+
// In practice, if code don't specify "type" on windows, you later get EPERM errors
|
|
39
|
+
// when doing operation on the symlink such as "fs.stat"
|
|
40
|
+
if (isWindows && typeof type === "undefined") {
|
|
41
|
+
const toStats = readEntryStatSync(toInfo.url, {
|
|
42
|
+
nullIfNotFound: true,
|
|
43
|
+
});
|
|
44
|
+
type = toStats && toStats.isDirectory() ? "dir" : "file";
|
|
45
|
+
}
|
|
46
|
+
const symbolicLinkPath = urlToFileSystemPath(fromUrl);
|
|
47
|
+
try {
|
|
48
|
+
symlinkSync(toInfo.value, symbolicLinkPath, type);
|
|
49
|
+
} catch (error) {
|
|
50
|
+
if (error.code === "ENOENT") {
|
|
51
|
+
ensureParentDirectoriesSync(fromUrl);
|
|
52
|
+
symlinkSync(toInfo.value, symbolicLinkPath, type);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (error.code === "EEXIST") {
|
|
56
|
+
if (allowUseless) {
|
|
57
|
+
const existingSymbolicLinkUrl = readSymbolicLinkSync(fromUrl);
|
|
58
|
+
if (existingSymbolicLinkUrl === toInfo.url) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (allowOverwrite) {
|
|
63
|
+
removeEntrySync(fromUrl);
|
|
64
|
+
symlinkSync(toInfo.value, symbolicLinkPath, type);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const getToInfo = (to, fromUrl) => {
|
|
73
|
+
if (typeof to === "string") {
|
|
74
|
+
// absolute filesystem path
|
|
75
|
+
if (isFileSystemPath(to)) {
|
|
76
|
+
const url = fileSystemPathToUrl(to);
|
|
77
|
+
const value = to;
|
|
78
|
+
return {
|
|
79
|
+
url,
|
|
80
|
+
value,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// relative url
|
|
85
|
+
if (to.startsWith("./") || to.startsWith("../")) {
|
|
86
|
+
const url = resolveUrl(to, fromUrl);
|
|
87
|
+
const value = to;
|
|
88
|
+
return {
|
|
89
|
+
url,
|
|
90
|
+
value,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// absolute url
|
|
95
|
+
const url = resolveUrl(to, fromUrl);
|
|
96
|
+
const value = urlToFileSystemPath(url);
|
|
97
|
+
return {
|
|
98
|
+
url,
|
|
99
|
+
value,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (to instanceof URL) {
|
|
104
|
+
const url = String(to);
|
|
105
|
+
const value = urlToFileSystemPath(url);
|
|
106
|
+
return {
|
|
107
|
+
url,
|
|
108
|
+
value,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
throw new TypeError(
|
|
113
|
+
`symbolic link to must be a string or an url, received ${to}`,
|
|
114
|
+
);
|
|
115
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { readdirSync, statSync } from "node:fs";
|
|
2
|
+
import { URL_META } from "@jsenv/url-meta";
|
|
3
|
+
|
|
4
|
+
import { removeEntrySync } from "./remove_entry_sync.js";
|
|
5
|
+
|
|
6
|
+
export const clearDirectorySync = (initialDirectoryUrl, pattern = "**/*") => {
|
|
7
|
+
const associations = URL_META.resolveAssociations(
|
|
8
|
+
{
|
|
9
|
+
clear: {
|
|
10
|
+
[pattern]: true,
|
|
11
|
+
"**/.*": false,
|
|
12
|
+
"**/.*/": false,
|
|
13
|
+
"**/node_modules/": false,
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
initialDirectoryUrl,
|
|
17
|
+
);
|
|
18
|
+
const visitDirectory = (directoryUrl) => {
|
|
19
|
+
const entryNames = readdirSync(new URL(directoryUrl));
|
|
20
|
+
for (const entryName of entryNames) {
|
|
21
|
+
const entryUrl = new URL(entryName, directoryUrl);
|
|
22
|
+
let entryStat;
|
|
23
|
+
try {
|
|
24
|
+
entryStat = statSync(entryUrl);
|
|
25
|
+
} catch (e) {
|
|
26
|
+
if (e && e.code === "ENOENT") {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
throw e;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (entryStat.isDirectory()) {
|
|
33
|
+
const subDirectoryUrl = new URL(`${entryName}/`, directoryUrl);
|
|
34
|
+
const meta = URL_META.applyAssociations({
|
|
35
|
+
url: subDirectoryUrl,
|
|
36
|
+
associations,
|
|
37
|
+
});
|
|
38
|
+
if (meta.clear) {
|
|
39
|
+
removeEntrySync(subDirectoryUrl, {
|
|
40
|
+
recursive: true,
|
|
41
|
+
allowUseless: true,
|
|
42
|
+
});
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (
|
|
46
|
+
!URL_META.urlChildMayMatch({
|
|
47
|
+
url: subDirectoryUrl,
|
|
48
|
+
associations,
|
|
49
|
+
predicate: ({ clear }) => clear,
|
|
50
|
+
})
|
|
51
|
+
) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
visitDirectory(subDirectoryUrl);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const meta = URL_META.applyAssociations({
|
|
58
|
+
url: entryUrl,
|
|
59
|
+
associations,
|
|
60
|
+
});
|
|
61
|
+
if (meta.clear) {
|
|
62
|
+
removeEntrySync(entryUrl, { allowUseless: true });
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
visitDirectory(initialDirectoryUrl);
|
|
68
|
+
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { urlToFileSystemPath } from "@jsenv/urls";
|
|
2
2
|
|
|
3
|
-
import { assertAndNormalizeFileUrl } from "
|
|
4
|
-
import { statsToType } from "
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { removeEntry } from "./
|
|
3
|
+
import { assertAndNormalizeFileUrl } from "../path_and_url/file_url_validation.js";
|
|
4
|
+
import { statsToType } from "../read_write/stat/stats_to_type.js";
|
|
5
|
+
import { readEntryStat } from "../read_write/stat/read_entry_stat.js";
|
|
6
|
+
import { writeDirectory } from "../read_write/write_directory.js";
|
|
7
|
+
import { removeEntry } from "./remove_entry.js";
|
|
8
8
|
|
|
9
9
|
export const ensureEmptyDirectory = async (source) => {
|
|
10
10
|
const stats = await readEntryStat(source, {
|
|
@@ -13,15 +13,17 @@ export const ensureEmptyDirectory = async (source) => {
|
|
|
13
13
|
});
|
|
14
14
|
if (stats === null) {
|
|
15
15
|
// if there is nothing, create a directory
|
|
16
|
-
|
|
16
|
+
await writeDirectory(source, { allowUseless: true });
|
|
17
|
+
return;
|
|
17
18
|
}
|
|
18
19
|
if (stats.isDirectory()) {
|
|
19
20
|
// if there is a directory remove its content and done
|
|
20
|
-
|
|
21
|
+
await removeEntry(source, {
|
|
21
22
|
allowUseless: true,
|
|
22
23
|
recursive: true,
|
|
23
24
|
onlyContent: true,
|
|
24
25
|
});
|
|
26
|
+
return;
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
const sourceType = statsToType(stats);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { urlToFileSystemPath } from "@jsenv/urls";
|
|
2
|
+
|
|
3
|
+
import { assertAndNormalizeFileUrl } from "../path_and_url/file_url_validation.js";
|
|
4
|
+
import { readEntryStatSync } from "../read_write/stat/read_entry_stat_sync.js";
|
|
5
|
+
import { statsToType } from "../read_write/stat/stats_to_type.js";
|
|
6
|
+
import { writeDirectorySync } from "../read_write/write_directory_sync.js";
|
|
7
|
+
import { removeEntrySync } from "./remove_entry_sync.js";
|
|
8
|
+
|
|
9
|
+
export const ensureEmptyDirectorySync = (source) => {
|
|
10
|
+
const stat = readEntryStatSync(source, {
|
|
11
|
+
nullIfNotFound: true,
|
|
12
|
+
followLink: false,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
if (stat === null) {
|
|
16
|
+
// if there is nothing, create a directory
|
|
17
|
+
writeDirectorySync(source, { allowUseless: true });
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
if (stat.isDirectory()) {
|
|
21
|
+
removeEntrySync(source, {
|
|
22
|
+
recursive: true,
|
|
23
|
+
onlyContent: true,
|
|
24
|
+
allowUseless: true,
|
|
25
|
+
});
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const sourceType = statsToType(stat);
|
|
30
|
+
const sourcePath = urlToFileSystemPath(assertAndNormalizeFileUrl(source));
|
|
31
|
+
throw new Error(
|
|
32
|
+
`ensureEmptyDirectorySync expect directory at ${sourcePath}, found ${sourceType} instead`,
|
|
33
|
+
);
|
|
34
|
+
};
|
|
@@ -6,9 +6,9 @@ import {
|
|
|
6
6
|
resolveUrl,
|
|
7
7
|
} from "@jsenv/urls";
|
|
8
8
|
|
|
9
|
-
import { assertAndNormalizeFileUrl } from "
|
|
10
|
-
import { readEntryStat } from "
|
|
11
|
-
import { readDirectory } from "
|
|
9
|
+
import { assertAndNormalizeFileUrl } from "../path_and_url/file_url_validation.js";
|
|
10
|
+
import { readEntryStat } from "../read_write/stat/read_entry_stat.js";
|
|
11
|
+
import { readDirectory } from "../read_write/read_directory.js";
|
|
12
12
|
|
|
13
13
|
export const removeEntry = async (
|
|
14
14
|
source,
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import {
|
|
2
|
+
unlinkSync,
|
|
3
|
+
rmdirSync,
|
|
4
|
+
readdirSync,
|
|
5
|
+
openSync,
|
|
6
|
+
closeSync,
|
|
7
|
+
} from "node:fs";
|
|
8
|
+
import { Abort } from "@jsenv/abort";
|
|
9
|
+
import {
|
|
10
|
+
ensurePathnameTrailingSlash,
|
|
11
|
+
urlToFileSystemPath,
|
|
12
|
+
resolveUrl,
|
|
13
|
+
} from "@jsenv/urls";
|
|
14
|
+
|
|
15
|
+
import { assertAndNormalizeFileUrl } from "../path_and_url/file_url_validation.js";
|
|
16
|
+
import { readEntryStatSync } from "../read_write/stat/read_entry_stat_sync.js";
|
|
17
|
+
|
|
18
|
+
export const removeEntrySync = (
|
|
19
|
+
source,
|
|
20
|
+
{
|
|
21
|
+
signal = new AbortController().signal,
|
|
22
|
+
allowUseless = false,
|
|
23
|
+
recursive = false,
|
|
24
|
+
maxRetries = 3,
|
|
25
|
+
retryDelay = 100,
|
|
26
|
+
onlyContent = false,
|
|
27
|
+
} = {},
|
|
28
|
+
) => {
|
|
29
|
+
const sourceUrl = assertAndNormalizeFileUrl(source);
|
|
30
|
+
|
|
31
|
+
const removeOperation = Abort.startOperation();
|
|
32
|
+
removeOperation.addAbortSignal(signal);
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
removeOperation.throwIfAborted();
|
|
36
|
+
const sourceStats = readEntryStatSync(sourceUrl, {
|
|
37
|
+
nullIfNotFound: true,
|
|
38
|
+
followLink: false,
|
|
39
|
+
});
|
|
40
|
+
if (!sourceStats) {
|
|
41
|
+
if (allowUseless) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
throw new Error(`nothing to remove at ${urlToFileSystemPath(sourceUrl)}`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// https://nodejs.org/dist/latest-v13.x/docs/api/fs.html#fs_class_fs_stats
|
|
48
|
+
// FIFO and socket are ignored, not sure what they are exactly and what to do with them
|
|
49
|
+
// other libraries ignore them, let's do the same.
|
|
50
|
+
if (
|
|
51
|
+
sourceStats.isFile() ||
|
|
52
|
+
sourceStats.isSymbolicLink() ||
|
|
53
|
+
sourceStats.isCharacterDevice() ||
|
|
54
|
+
sourceStats.isBlockDevice()
|
|
55
|
+
) {
|
|
56
|
+
removeNonDirectory(
|
|
57
|
+
sourceUrl.endsWith("/") ? sourceUrl.slice(0, -1) : sourceUrl,
|
|
58
|
+
{
|
|
59
|
+
maxRetries,
|
|
60
|
+
retryDelay,
|
|
61
|
+
},
|
|
62
|
+
);
|
|
63
|
+
} else if (sourceStats.isDirectory()) {
|
|
64
|
+
const directoryUrl = ensurePathnameTrailingSlash(sourceUrl);
|
|
65
|
+
removeDirectorySync(directoryUrl, {
|
|
66
|
+
signal: removeOperation.signal,
|
|
67
|
+
recursive,
|
|
68
|
+
maxRetries,
|
|
69
|
+
retryDelay,
|
|
70
|
+
onlyContent,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
} finally {
|
|
74
|
+
removeOperation.end();
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const removeNonDirectory = (sourceUrl) => {
|
|
79
|
+
const sourcePath = urlToFileSystemPath(sourceUrl);
|
|
80
|
+
const attempt = () => {
|
|
81
|
+
unlinkSyncNaive(sourcePath);
|
|
82
|
+
};
|
|
83
|
+
attempt();
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const unlinkSyncNaive = (sourcePath, { handleTemporaryError = null } = {}) => {
|
|
87
|
+
try {
|
|
88
|
+
unlinkSync(sourcePath);
|
|
89
|
+
} catch (error) {
|
|
90
|
+
if (error.code === "ENOENT") {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (
|
|
94
|
+
handleTemporaryError &&
|
|
95
|
+
(error.code === "EBUSY" ||
|
|
96
|
+
error.code === "EMFILE" ||
|
|
97
|
+
error.code === "ENFILE" ||
|
|
98
|
+
error.code === "ENOENT")
|
|
99
|
+
) {
|
|
100
|
+
handleTemporaryError(error);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const removeDirectorySync = (
|
|
108
|
+
rootDirectoryUrl,
|
|
109
|
+
{ signal, maxRetries, retryDelay, recursive, onlyContent },
|
|
110
|
+
) => {
|
|
111
|
+
const removeDirectoryOperation = Abort.startOperation();
|
|
112
|
+
removeDirectoryOperation.addAbortSignal(signal);
|
|
113
|
+
|
|
114
|
+
const visit = (sourceUrl) => {
|
|
115
|
+
removeDirectoryOperation.throwIfAborted();
|
|
116
|
+
const sourceStats = readEntryStatSync(sourceUrl, {
|
|
117
|
+
nullIfNotFound: true,
|
|
118
|
+
followLink: false,
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// file/directory not found
|
|
122
|
+
if (sourceStats === null) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (
|
|
127
|
+
sourceStats.isFile() ||
|
|
128
|
+
sourceStats.isCharacterDevice() ||
|
|
129
|
+
sourceStats.isBlockDevice()
|
|
130
|
+
) {
|
|
131
|
+
visitFile(sourceUrl);
|
|
132
|
+
} else if (sourceStats.isSymbolicLink()) {
|
|
133
|
+
visitSymbolicLink(sourceUrl);
|
|
134
|
+
} else if (sourceStats.isDirectory()) {
|
|
135
|
+
visitDirectory(`${sourceUrl}/`);
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const visitDirectory = (directoryUrl) => {
|
|
140
|
+
const directoryPath = urlToFileSystemPath(directoryUrl);
|
|
141
|
+
const optionsFromRecursive = recursive
|
|
142
|
+
? {
|
|
143
|
+
handleNotEmptyError: () => {
|
|
144
|
+
removeDirectoryContent(directoryUrl);
|
|
145
|
+
visitDirectory(directoryUrl);
|
|
146
|
+
},
|
|
147
|
+
}
|
|
148
|
+
: {};
|
|
149
|
+
removeDirectoryOperation.throwIfAborted();
|
|
150
|
+
removeDirectorySyncNaive(directoryPath, {
|
|
151
|
+
...optionsFromRecursive,
|
|
152
|
+
// Workaround for https://github.com/joyent/node/issues/4337
|
|
153
|
+
...(process.platform === "win32"
|
|
154
|
+
? {
|
|
155
|
+
handlePermissionError: (error) => {
|
|
156
|
+
console.error(
|
|
157
|
+
`trying to fix windows EPERM after readir on ${directoryPath}`,
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
let openOrCloseError;
|
|
161
|
+
try {
|
|
162
|
+
const fd = openSync(directoryPath);
|
|
163
|
+
closeSync(fd);
|
|
164
|
+
} catch (e) {
|
|
165
|
+
openOrCloseError = e;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (openOrCloseError) {
|
|
169
|
+
if (openOrCloseError.code === "ENOENT") {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
console.error(
|
|
173
|
+
`error while trying to fix windows EPERM after readir on ${directoryPath}: ${openOrCloseError.stack}`,
|
|
174
|
+
);
|
|
175
|
+
throw error;
|
|
176
|
+
}
|
|
177
|
+
removeDirectorySyncNaive(directoryPath, {
|
|
178
|
+
...optionsFromRecursive,
|
|
179
|
+
});
|
|
180
|
+
},
|
|
181
|
+
}
|
|
182
|
+
: {}),
|
|
183
|
+
});
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
const removeDirectoryContent = (directoryUrl) => {
|
|
187
|
+
removeDirectoryOperation.throwIfAborted();
|
|
188
|
+
const entryNames = readdirSync(new URL(directoryUrl));
|
|
189
|
+
for (const entryName of entryNames) {
|
|
190
|
+
const url = resolveUrl(entryName, directoryUrl);
|
|
191
|
+
visit(url);
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const visitFile = (fileUrl) => {
|
|
196
|
+
removeNonDirectory(fileUrl, { maxRetries, retryDelay });
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const visitSymbolicLink = (symbolicLinkUrl) => {
|
|
200
|
+
removeNonDirectory(symbolicLinkUrl, { maxRetries, retryDelay });
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
try {
|
|
204
|
+
if (onlyContent) {
|
|
205
|
+
removeDirectoryContent(rootDirectoryUrl);
|
|
206
|
+
} else {
|
|
207
|
+
visitDirectory(rootDirectoryUrl);
|
|
208
|
+
}
|
|
209
|
+
} finally {
|
|
210
|
+
removeDirectoryOperation.end();
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
const removeDirectorySyncNaive = (
|
|
215
|
+
directoryPath,
|
|
216
|
+
{ handleNotEmptyError = null, handlePermissionError = null } = {},
|
|
217
|
+
) => {
|
|
218
|
+
try {
|
|
219
|
+
rmdirSync(directoryPath);
|
|
220
|
+
} catch (error) {
|
|
221
|
+
if (handlePermissionError && error.code === "EPERM") {
|
|
222
|
+
handlePermissionError(error);
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
if (error.code === "ENOENT") {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
if (
|
|
229
|
+
handleNotEmptyError &&
|
|
230
|
+
// linux os
|
|
231
|
+
(error.code === "ENOTEMPTY" ||
|
|
232
|
+
// SunOS
|
|
233
|
+
error.code === "EEXIST")
|
|
234
|
+
) {
|
|
235
|
+
handleNotEmptyError(error);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
throw error;
|
|
239
|
+
}
|
|
240
|
+
};
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
export const getCommandArgument = (argv, name) => {
|
|
2
|
-
let i = 0;
|
|
3
|
-
|
|
4
|
-
while (i < argv.length) {
|
|
5
|
-
const arg = argv[i];
|
|
6
|
-
|
|
7
|
-
if (arg === name) {
|
|
8
|
-
return {
|
|
9
|
-
name,
|
|
10
|
-
index: i,
|
|
11
|
-
value: "",
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
if (arg.startsWith(`${name}=`)) {
|
|
16
|
-
return {
|
|
17
|
-
name,
|
|
18
|
-
index: i,
|
|
19
|
-
value: arg.slice(`${name}=`.length),
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
i++;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return null;
|
|
27
|
-
};
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|