@jsenv/filesystem 4.3.1 → 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} +10 -9
- 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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/filesystem",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.4.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -33,7 +33,8 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@jsenv/urls": "2.2.1",
|
|
36
|
-
"@jsenv/url-meta": "8.
|
|
37
|
-
"@jsenv/abort": "4.2.4"
|
|
36
|
+
"@jsenv/url-meta": "8.2.0",
|
|
37
|
+
"@jsenv/abort": "4.2.4",
|
|
38
|
+
"@jsenv/utils": "2.0.1"
|
|
38
39
|
}
|
|
39
40
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { urlToFileSystemPath } from "@jsenv/urls";
|
|
2
2
|
|
|
3
|
-
import { assertAndNormalizeFileUrl } from "./file_url_validation.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { assertAndNormalizeFileUrl } from "./path_and_url/file_url_validation.js";
|
|
4
|
+
import { readEntryStat } from "./read_write/stat/read_entry_stat.js";
|
|
5
|
+
import { statsToType } from "./read_write/stat/stats_to_type.js";
|
|
6
6
|
|
|
7
7
|
export const assertDirectoryPresence = async (source) => {
|
|
8
8
|
const sourceUrl = assertAndNormalizeFileUrl(source);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { urlToFileSystemPath } from "@jsenv/urls";
|
|
2
2
|
|
|
3
|
-
import { assertAndNormalizeFileUrl } from "./file_url_validation.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { assertAndNormalizeFileUrl } from "./path_and_url/file_url_validation.js";
|
|
4
|
+
import { readEntryStat } from "./read_write/stat/read_entry_stat.js";
|
|
5
|
+
import { statsToType } from "./read_write/stat/stats_to_type.js";
|
|
6
6
|
|
|
7
7
|
export const assertFilePresence = async (source) => {
|
|
8
8
|
const sourceUrl = assertAndNormalizeFileUrl(source);
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { Abort } from "@jsenv/abort";
|
|
2
2
|
import { urlToFileSystemPath, resolveUrl } from "@jsenv/urls";
|
|
3
3
|
|
|
4
|
-
import { assertAndNormalizeDirectoryUrl } from "
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
4
|
+
import { assertAndNormalizeDirectoryUrl } from "../path_and_url/directory_url_validation.js";
|
|
5
|
+
import { urlTargetsSameFileSystemPath } from "../path_and_url/url_targets_same_file_system_path.js";
|
|
6
|
+
import { statsToType } from "../read_write/stat/stats_to_type.js";
|
|
7
|
+
import { readEntryStat } from "../read_write/stat/read_entry_stat.js";
|
|
8
|
+
import { readSymbolicLink } from "../read_write/read_symbolic_link.js";
|
|
9
|
+
import { readDirectory } from "../read_write/read_directory.js";
|
|
10
|
+
import { copyEntry } from "./copy_entry.js";
|
|
11
11
|
|
|
12
12
|
export const copyDirectoryContent = async ({
|
|
13
13
|
signal = new AbortController().signal,
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { Abort } from "@jsenv/abort";
|
|
2
|
+
import { urlToFileSystemPath, resolveUrl } from "@jsenv/urls";
|
|
3
|
+
|
|
4
|
+
import { assertAndNormalizeDirectoryUrl } from "../path_and_url/directory_url_validation.js";
|
|
5
|
+
import { urlTargetsSameFileSystemPath } from "../path_and_url/url_targets_same_file_system_path.js";
|
|
6
|
+
import { statsToType } from "../read_write/stat/stats_to_type.js";
|
|
7
|
+
import { readEntryStatSync } from "../read_write/stat/read_entry_stat_sync.js";
|
|
8
|
+
import { readSymbolicLinkSync } from "../read_write/read_symbolic_link_sync.js";
|
|
9
|
+
import { readDirectorySync } from "../read_write/read_directory_sync.js";
|
|
10
|
+
import { copyEntrySync } from "./copy_entry_sync.js";
|
|
11
|
+
|
|
12
|
+
export const copyDirectoryContentSync = ({
|
|
13
|
+
signal = new AbortController().signal,
|
|
14
|
+
from,
|
|
15
|
+
to,
|
|
16
|
+
overwrite,
|
|
17
|
+
followLink = true,
|
|
18
|
+
} = {}) => {
|
|
19
|
+
const fromUrl = assertAndNormalizeDirectoryUrl(from);
|
|
20
|
+
const fromPath = urlToFileSystemPath(fromUrl);
|
|
21
|
+
let toUrl = assertAndNormalizeDirectoryUrl(to);
|
|
22
|
+
let toPath = urlToFileSystemPath(toUrl);
|
|
23
|
+
|
|
24
|
+
const sourceStats = readEntryStatSync(fromUrl, {
|
|
25
|
+
nullIfNotFound: true,
|
|
26
|
+
followLink: false,
|
|
27
|
+
});
|
|
28
|
+
if (!sourceStats) {
|
|
29
|
+
throw new Error(`no directory to copy content from at ${fromPath}`);
|
|
30
|
+
}
|
|
31
|
+
if (!sourceStats.isDirectory()) {
|
|
32
|
+
const sourceType = statsToType(sourceStats);
|
|
33
|
+
throw new Error(
|
|
34
|
+
`found a ${sourceType} instead of a directory at ${fromPath}`,
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let destinationStats = readEntryStatSync(toUrl, {
|
|
39
|
+
nullIfNotFound: true,
|
|
40
|
+
// we force false here but in fact we will follow the destination link
|
|
41
|
+
// to know where we will actually move and detect useless move overrite etc..
|
|
42
|
+
followLink: false,
|
|
43
|
+
});
|
|
44
|
+
if (followLink && destinationStats && destinationStats.isSymbolicLink()) {
|
|
45
|
+
const linkTarget = readSymbolicLinkSync(toUrl);
|
|
46
|
+
toUrl = resolveUrl(linkTarget, toUrl);
|
|
47
|
+
toPath = urlToFileSystemPath(toUrl);
|
|
48
|
+
destinationStats = readEntryStatSync(toUrl, {
|
|
49
|
+
nullIfNotFound: true,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (destinationStats === null) {
|
|
54
|
+
throw new Error(`no directory to copy content into at ${toPath}`);
|
|
55
|
+
}
|
|
56
|
+
if (!destinationStats.isDirectory()) {
|
|
57
|
+
const destinationType = statsToType(destinationStats);
|
|
58
|
+
throw new Error(
|
|
59
|
+
`destination leads to a ${destinationType} instead of a directory at ${toPath}`,
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (urlTargetsSameFileSystemPath(fromUrl, toUrl)) {
|
|
64
|
+
throw new Error(
|
|
65
|
+
`cannot copy directory content, source and destination are the same (${fromPath})`,
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const copyOperation = Abort.startOperation();
|
|
70
|
+
copyOperation.addAbortSignal(signal);
|
|
71
|
+
try {
|
|
72
|
+
copyOperation.throwIfAborted();
|
|
73
|
+
const directoryEntries = readDirectorySync(fromUrl);
|
|
74
|
+
directoryEntries.forEach((directoryEntry) => {
|
|
75
|
+
const from = resolveUrl(directoryEntry, fromUrl);
|
|
76
|
+
const to = resolveUrl(directoryEntry, toUrl);
|
|
77
|
+
copyOperation.withSignal((signal) => {
|
|
78
|
+
copyEntrySync({
|
|
79
|
+
signal,
|
|
80
|
+
from,
|
|
81
|
+
to,
|
|
82
|
+
overwrite,
|
|
83
|
+
followLink,
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
} finally {
|
|
88
|
+
copyOperation.end();
|
|
89
|
+
}
|
|
90
|
+
};
|
|
@@ -8,19 +8,19 @@ import {
|
|
|
8
8
|
urlToFileSystemPath,
|
|
9
9
|
} from "@jsenv/urls";
|
|
10
10
|
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import { readDirectory } from "
|
|
21
|
-
import { readSymbolicLink } from "
|
|
22
|
-
import { writeSymbolicLink } from "
|
|
23
|
-
import { removeEntry } from "
|
|
11
|
+
import { assertAndNormalizeFileUrl } from "../path_and_url/file_url_validation.js";
|
|
12
|
+
import { urlTargetsSameFileSystemPath } from "../path_and_url/url_targets_same_file_system_path.js";
|
|
13
|
+
import { readEntryStat } from "../read_write/stat/read_entry_stat.js";
|
|
14
|
+
import { statsToType } from "../read_write/stat/stats_to_type.js";
|
|
15
|
+
import { binaryFlagsToPermissions } from "../read_write/stat/permissions.js";
|
|
16
|
+
import { writeEntryPermissions } from "../read_write/stat/write_entry_permissions.js";
|
|
17
|
+
import { writeEntryModificationTime } from "../read_write/stat/write_entry_modification_time.js";
|
|
18
|
+
import { writeDirectory } from "../read_write/write_directory.js";
|
|
19
|
+
import { ensureParentDirectories } from "../read_write/ensure_parent_directories.js";
|
|
20
|
+
import { readDirectory } from "../read_write/read_directory.js";
|
|
21
|
+
import { readSymbolicLink } from "../read_write/read_symbolic_link.js";
|
|
22
|
+
import { writeSymbolicLink } from "../read_write/write_symbolic_link.js";
|
|
23
|
+
import { removeEntry } from "../remove/remove_entry.js";
|
|
24
24
|
|
|
25
25
|
export const copyEntry = async ({
|
|
26
26
|
signal = new AbortController().signal,
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { copyFileSync as copyFileSyncNode } from "node:fs";
|
|
2
|
+
import { Abort } from "@jsenv/abort";
|
|
3
|
+
import {
|
|
4
|
+
resolveUrl,
|
|
5
|
+
urlToRelativeUrl,
|
|
6
|
+
ensurePathnameTrailingSlash,
|
|
7
|
+
urlIsInsideOf,
|
|
8
|
+
urlToFileSystemPath,
|
|
9
|
+
} from "@jsenv/urls";
|
|
10
|
+
|
|
11
|
+
import { assertAndNormalizeFileUrl } from "../path_and_url/file_url_validation.js";
|
|
12
|
+
import { urlTargetsSameFileSystemPath } from "../path_and_url/url_targets_same_file_system_path.js";
|
|
13
|
+
import { readEntryStatSync } from "../read_write/stat/read_entry_stat_sync.js";
|
|
14
|
+
import { statsToType } from "../read_write/stat/stats_to_type.js";
|
|
15
|
+
import { binaryFlagsToPermissions } from "../read_write/stat/permissions.js";
|
|
16
|
+
import { writeEntryPermissionsSync } from "../read_write/stat/write_entry_permissions_sync.js";
|
|
17
|
+
import { writeEntryModificationTimeSync } from "../read_write/stat/write_entry_modification_time_sync.js";
|
|
18
|
+
import { writeDirectorySync } from "../read_write/write_directory_sync.js";
|
|
19
|
+
import { ensureParentDirectoriesSync } from "../read_write/ensure_parent_directories_sync.js";
|
|
20
|
+
import { readDirectorySync } from "../read_write/read_directory_sync.js";
|
|
21
|
+
import { readSymbolicLinkSync } from "../read_write/read_symbolic_link_sync.js";
|
|
22
|
+
import { writeSymbolicLinkSync } from "../read_write/write_symbolic_link_sync.js";
|
|
23
|
+
import { removeEntrySync } from "../remove/remove_entry_sync.js";
|
|
24
|
+
|
|
25
|
+
export const copyEntrySync = ({
|
|
26
|
+
signal = new AbortController().signal,
|
|
27
|
+
from,
|
|
28
|
+
to,
|
|
29
|
+
overwrite = false,
|
|
30
|
+
preserveStat = true,
|
|
31
|
+
preserveMtime = preserveStat,
|
|
32
|
+
preservePermissions = preserveStat,
|
|
33
|
+
allowUseless = false,
|
|
34
|
+
followLink = true,
|
|
35
|
+
}) => {
|
|
36
|
+
const fromUrl = assertAndNormalizeFileUrl(from);
|
|
37
|
+
const fromPath = urlToFileSystemPath(fromUrl);
|
|
38
|
+
let toUrl = assertAndNormalizeFileUrl(to);
|
|
39
|
+
let toPath = urlToFileSystemPath(toUrl);
|
|
40
|
+
|
|
41
|
+
const sourceStats = readEntryStatSync(fromUrl, {
|
|
42
|
+
nullIfNotFound: true,
|
|
43
|
+
followLink: false,
|
|
44
|
+
});
|
|
45
|
+
if (!sourceStats) {
|
|
46
|
+
throw new Error(`nothing to copy at ${fromPath}`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
let destinationStats = readEntryStatSync(toUrl, {
|
|
50
|
+
nullIfNotFound: true,
|
|
51
|
+
// we force false here but in fact we will follow the destination link
|
|
52
|
+
// to know where we will actually move and detect useless move overrite etc..
|
|
53
|
+
followLink: false,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
if (followLink && destinationStats && destinationStats.isSymbolicLink()) {
|
|
57
|
+
const linkTarget = readSymbolicLinkSync(toUrl);
|
|
58
|
+
toUrl = resolveUrl(linkTarget, toUrl);
|
|
59
|
+
toPath = urlToFileSystemPath(toUrl);
|
|
60
|
+
destinationStats = readEntryStatSync(toUrl, {
|
|
61
|
+
nullIfNotFound: true,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (urlTargetsSameFileSystemPath(fromUrl, toUrl)) {
|
|
66
|
+
if (allowUseless) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
throw new Error(
|
|
70
|
+
`cannot copy ${fromPath} because destination and source are the same`,
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (sourceStats.isDirectory()) {
|
|
75
|
+
toUrl = ensurePathnameTrailingSlash(toUrl);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const copyOperation = Abort.startOperation();
|
|
79
|
+
copyOperation.addAbortSignal(signal);
|
|
80
|
+
|
|
81
|
+
const visit = async (url, stats) => {
|
|
82
|
+
copyOperation.throwIfAborted();
|
|
83
|
+
if (stats.isFile() || stats.isCharacterDevice() || stats.isBlockDevice()) {
|
|
84
|
+
visitFile(url, stats);
|
|
85
|
+
} else if (stats.isSymbolicLink()) {
|
|
86
|
+
visitSymbolicLink(url, stats);
|
|
87
|
+
} else if (stats.isDirectory()) {
|
|
88
|
+
visitDirectory(ensurePathnameTrailingSlash(url), stats);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const visitFile = (fileUrl, fileStats) => {
|
|
93
|
+
const fileRelativeUrl = urlToRelativeUrl(fileUrl, fromUrl);
|
|
94
|
+
const fileCopyUrl = resolveUrl(fileRelativeUrl, toUrl);
|
|
95
|
+
|
|
96
|
+
copyFileSyncNode(
|
|
97
|
+
urlToFileSystemPath(fileUrl),
|
|
98
|
+
urlToFileSystemPath(fileCopyUrl),
|
|
99
|
+
);
|
|
100
|
+
copyStatsSync(fileCopyUrl, fileStats);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const visitSymbolicLink = (symbolicLinkUrl) => {
|
|
104
|
+
const symbolicLinkRelativeUrl = urlToRelativeUrl(symbolicLinkUrl, fromUrl);
|
|
105
|
+
const symbolicLinkTarget = readSymbolicLinkSync(symbolicLinkUrl);
|
|
106
|
+
const symbolicLinkTargetUrl = resolveUrl(
|
|
107
|
+
symbolicLinkTarget,
|
|
108
|
+
symbolicLinkUrl,
|
|
109
|
+
);
|
|
110
|
+
const linkIsRelative =
|
|
111
|
+
symbolicLinkTarget.startsWith("./") ||
|
|
112
|
+
symbolicLinkTarget.startsWith("../");
|
|
113
|
+
|
|
114
|
+
let symbolicLinkCopyTarget;
|
|
115
|
+
if (symbolicLinkTargetUrl === fromUrl) {
|
|
116
|
+
symbolicLinkCopyTarget = linkIsRelative ? symbolicLinkTarget : toUrl;
|
|
117
|
+
} else if (urlIsInsideOf(symbolicLinkTargetUrl, fromUrl)) {
|
|
118
|
+
// symbolic link targets something inside the directory we want to copy
|
|
119
|
+
// reflects it inside the copied directory structure
|
|
120
|
+
const linkCopyTargetRelative = urlToRelativeUrl(
|
|
121
|
+
symbolicLinkTargetUrl,
|
|
122
|
+
fromUrl,
|
|
123
|
+
);
|
|
124
|
+
symbolicLinkCopyTarget = linkIsRelative
|
|
125
|
+
? `./${linkCopyTargetRelative}`
|
|
126
|
+
: resolveUrl(linkCopyTargetRelative, toUrl);
|
|
127
|
+
} else {
|
|
128
|
+
// symbolic link targets something outside the directory we want to copy
|
|
129
|
+
symbolicLinkCopyTarget = symbolicLinkTarget;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// we must guess ourself the type of the symlink
|
|
133
|
+
// because the destination might not exists because not yet copied
|
|
134
|
+
// https://nodejs.org/dist/latest-v13.x/docs/api/fs.html#fs_fs_symlink_target_path_type_callback
|
|
135
|
+
const targetStats = readEntryStatSync(symbolicLinkTargetUrl, {
|
|
136
|
+
nullIfNotFound: true,
|
|
137
|
+
followLink: false,
|
|
138
|
+
});
|
|
139
|
+
const linkType = targetStats && targetStats.isDirectory() ? "dir" : "file";
|
|
140
|
+
|
|
141
|
+
const symbolicLinkCopyUrl = resolveUrl(symbolicLinkRelativeUrl, toUrl);
|
|
142
|
+
writeSymbolicLinkSync({
|
|
143
|
+
from: symbolicLinkCopyUrl,
|
|
144
|
+
to: symbolicLinkCopyTarget,
|
|
145
|
+
type: linkType,
|
|
146
|
+
});
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const copyStatsSync = (toUrl, stats) => {
|
|
150
|
+
if (preservePermissions || preserveMtime) {
|
|
151
|
+
const { mode, mtimeMs } = stats;
|
|
152
|
+
if (preservePermissions) {
|
|
153
|
+
writeEntryPermissionsSync(toUrl, binaryFlagsToPermissions(mode));
|
|
154
|
+
}
|
|
155
|
+
if (preserveMtime) {
|
|
156
|
+
writeEntryModificationTimeSync(toUrl, mtimeMs);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const visitDirectory = async (directoryUrl, directoryStats) => {
|
|
162
|
+
const directoryRelativeUrl = urlToRelativeUrl(directoryUrl, fromUrl);
|
|
163
|
+
const directoryCopyUrl = resolveUrl(directoryRelativeUrl, toUrl);
|
|
164
|
+
|
|
165
|
+
writeDirectorySync(directoryCopyUrl);
|
|
166
|
+
copyDirectoryContentSync(directoryUrl);
|
|
167
|
+
copyStatsSync(directoryCopyUrl, directoryStats);
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
const copyDirectoryContentSync = async (directoryUrl) => {
|
|
171
|
+
const names = readDirectorySync(directoryUrl);
|
|
172
|
+
names.forEach((name) => {
|
|
173
|
+
const entryUrl = resolveUrl(name, directoryUrl);
|
|
174
|
+
const stats = readEntryStatSync(entryUrl, {
|
|
175
|
+
followLink: false,
|
|
176
|
+
});
|
|
177
|
+
visit(entryUrl, stats);
|
|
178
|
+
});
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
try {
|
|
182
|
+
if (destinationStats) {
|
|
183
|
+
const sourceType = statsToType(sourceStats);
|
|
184
|
+
const destinationType = statsToType(destinationStats);
|
|
185
|
+
|
|
186
|
+
if (sourceType !== destinationType) {
|
|
187
|
+
throw new Error(
|
|
188
|
+
`cannot copy ${sourceType} from ${fromPath} to ${toPath} because destination exists and is not a ${sourceType} (it's a ${destinationType})`,
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
if (!overwrite) {
|
|
192
|
+
throw new Error(
|
|
193
|
+
`cannot copy ${sourceType} from ${fromPath} to ${toPath} because destination exists and overwrite option is disabled`,
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// remove file, link, directory...
|
|
198
|
+
removeEntrySync(toUrl, {
|
|
199
|
+
signal: copyOperation.signal,
|
|
200
|
+
recursive: true,
|
|
201
|
+
allowUseless: true,
|
|
202
|
+
});
|
|
203
|
+
} else {
|
|
204
|
+
ensureParentDirectoriesSync(toUrl);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
copyOperation.throwIfAborted();
|
|
208
|
+
visit(fromUrl, sourceStats);
|
|
209
|
+
} finally {
|
|
210
|
+
copyOperation.end();
|
|
211
|
+
}
|
|
212
|
+
};
|
|
@@ -2,13 +2,14 @@ import { readdirSync, statSync } from "node:fs";
|
|
|
2
2
|
import { URL_META } from "@jsenv/url-meta";
|
|
3
3
|
import { urlToFileSystemPath, urlToRelativeUrl } from "@jsenv/urls";
|
|
4
4
|
|
|
5
|
-
import { assertAndNormalizeDirectoryUrl } from "
|
|
6
|
-
import { statsToType } from "
|
|
7
|
-
import { guardTooFastSecondCallPerFile } from "./
|
|
8
|
-
import { createWatcher } from "./
|
|
9
|
-
import { trackResources } from "./
|
|
5
|
+
import { assertAndNormalizeDirectoryUrl } from "../path_and_url/directory_url_validation.js";
|
|
6
|
+
import { statsToType } from "../read_write/stat/stats_to_type.js";
|
|
7
|
+
import { guardTooFastSecondCallPerFile } from "./guard_second_call.js";
|
|
8
|
+
import { createWatcher } from "./create_watcher.js";
|
|
9
|
+
import { trackResources } from "./track_resources.js";
|
|
10
10
|
|
|
11
|
-
const
|
|
11
|
+
const isLinux = process.platform === "linux";
|
|
12
|
+
const fsWatchSupportsRecursive = !isLinux;
|
|
12
13
|
|
|
13
14
|
export const registerDirectoryLifecycle = (
|
|
14
15
|
source,
|
|
@@ -344,10 +345,10 @@ const shouldCallUpdated = (entryInfo) => {
|
|
|
344
345
|
if (stat.atimeMs < stat.mtimeMs) {
|
|
345
346
|
return true;
|
|
346
347
|
}
|
|
347
|
-
if (stat.mtimeMs
|
|
348
|
-
return
|
|
348
|
+
if (isLinux && stat.mtimeMs <= previousInfo.stat.mtimeMs) {
|
|
349
|
+
return false;
|
|
349
350
|
}
|
|
350
|
-
return
|
|
351
|
+
return true;
|
|
351
352
|
};
|
|
352
353
|
|
|
353
354
|
const undefinedOrFunction = (value) => {
|
|
@@ -2,11 +2,11 @@ import { statSync } from "node:fs";
|
|
|
2
2
|
import { dirname, basename } from "node:path";
|
|
3
3
|
import { urlToFileSystemPath } from "@jsenv/urls";
|
|
4
4
|
|
|
5
|
-
import { assertAndNormalizeFileUrl } from "
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { createWatcher } from "./
|
|
9
|
-
import {
|
|
5
|
+
import { assertAndNormalizeFileUrl } from "../path_and_url/file_url_validation.js";
|
|
6
|
+
import { statsToType } from "../read_write/stat/stats_to_type.js";
|
|
7
|
+
import { trackResources } from "./track_resources.js";
|
|
8
|
+
import { createWatcher } from "./create_watcher.js";
|
|
9
|
+
import { guardTooFastSecondCall } from "./guard_second_call.js";
|
|
10
10
|
|
|
11
11
|
export const registerFileLifecycle = (
|
|
12
12
|
source,
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Abort } from "@jsenv/abort";
|
|
2
|
-
|
|
3
2
|
import { URL_META } from "@jsenv/url-meta";
|
|
4
3
|
import { urlToRelativeUrl } from "@jsenv/urls";
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
4
|
+
|
|
5
|
+
import { assertAndNormalizeDirectoryUrl } from "../path_and_url/directory_url_validation.js";
|
|
6
|
+
import { comparePathnames } from "../path_and_url/compare_pathnames.js";
|
|
7
|
+
import { readDirectory } from "../read_write/read_directory.js";
|
|
8
|
+
import { readEntryStat } from "../read_write/stat/read_entry_stat.js";
|
|
9
9
|
|
|
10
10
|
export const collectDirectoryMatchReport = async ({
|
|
11
11
|
signal = new AbortController().signal,
|
|
@@ -2,10 +2,10 @@ import { Abort } from "@jsenv/abort";
|
|
|
2
2
|
import { URL_META } from "@jsenv/url-meta";
|
|
3
3
|
import { urlToRelativeUrl } from "@jsenv/urls";
|
|
4
4
|
|
|
5
|
-
import { assertAndNormalizeDirectoryUrl } from "
|
|
6
|
-
import {
|
|
7
|
-
import { readEntryStat } from "
|
|
8
|
-
import {
|
|
5
|
+
import { assertAndNormalizeDirectoryUrl } from "../path_and_url/directory_url_validation.js";
|
|
6
|
+
import { comparePathnames } from "../path_and_url/compare_pathnames.js";
|
|
7
|
+
import { readEntryStat } from "../read_write/stat/read_entry_stat.js";
|
|
8
|
+
import { readDirectory } from "../read_write/read_directory.js";
|
|
9
9
|
|
|
10
10
|
export const collectFiles = async ({
|
|
11
11
|
signal = new AbortController().signal,
|
package/src/main.js
CHANGED
|
@@ -1,41 +1,84 @@
|
|
|
1
|
+
// we might wanna expose the sync versions as follows:
|
|
2
|
+
// readDirectory.sync()
|
|
3
|
+
// +1: very easy to switch between sync/async versions of a given function
|
|
4
|
+
// -1: code splitting
|
|
5
|
+
// -1: unusual
|
|
6
|
+
|
|
7
|
+
// path_and_url
|
|
1
8
|
export {
|
|
2
9
|
validateDirectoryUrl,
|
|
3
10
|
assertAndNormalizeDirectoryUrl,
|
|
4
|
-
} from "./directory_url_validation.js";
|
|
11
|
+
} from "./path_and_url/directory_url_validation.js";
|
|
5
12
|
export {
|
|
6
13
|
validateFileUrl,
|
|
7
14
|
assertAndNormalizeFileUrl,
|
|
8
|
-
} from "./file_url_validation.js";
|
|
9
|
-
export {
|
|
10
|
-
export {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
export {
|
|
14
|
-
export {
|
|
15
|
-
export {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
export {
|
|
19
|
-
export {
|
|
20
|
-
export {
|
|
21
|
-
export {
|
|
22
|
-
export {
|
|
23
|
-
export {
|
|
24
|
-
export {
|
|
25
|
-
export {
|
|
26
|
-
export {
|
|
27
|
-
|
|
28
|
-
export {
|
|
29
|
-
export {
|
|
30
|
-
export {
|
|
31
|
-
export {
|
|
32
|
-
export {
|
|
33
|
-
export {
|
|
34
|
-
export {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
export {
|
|
38
|
-
export {
|
|
39
|
-
export { writeEntryModificationTime } from "./
|
|
40
|
-
export {
|
|
41
|
-
export {
|
|
15
|
+
} from "./path_and_url/file_url_validation.js";
|
|
16
|
+
export { comparePathnames } from "./path_and_url/compare_pathnames.js";
|
|
17
|
+
export { ensureWindowsDriveLetter } from "./path_and_url/ensure_windows_drive_letter.js";
|
|
18
|
+
|
|
19
|
+
// list
|
|
20
|
+
export { collectDirectoryMatchReport } from "./list/collect_directory_match_report.js";
|
|
21
|
+
export { collectFiles } from "./list/collect_files.js";
|
|
22
|
+
export { listFilesMatching } from "./list/list_files_matching.js";
|
|
23
|
+
|
|
24
|
+
// read and write
|
|
25
|
+
export { ensureParentDirectories } from "./read_write/ensure_parent_directories.js";
|
|
26
|
+
export { readDirectory } from "./read_write/read_directory.js";
|
|
27
|
+
export { writeDirectory } from "./read_write/write_directory.js";
|
|
28
|
+
export { readFile } from "./read_write/read_file.js";
|
|
29
|
+
export { writeFile } from "./read_write/write_file.js";
|
|
30
|
+
export { readFileSync } from "./read_write/read_file_sync.js";
|
|
31
|
+
export { writeFileSync } from "./read_write/write_file_sync.js";
|
|
32
|
+
export { readSymbolicLink } from "./read_write/read_symbolic_link.js";
|
|
33
|
+
export { writeSymbolicLink } from "./read_write/write_symbolic_link.js";
|
|
34
|
+
// read and write sync
|
|
35
|
+
export { ensureParentDirectoriesSync } from "./read_write/ensure_parent_directories_sync.js";
|
|
36
|
+
export { readDirectorySync } from "./read_write/read_directory_sync.js";
|
|
37
|
+
export { getRealFileSystemUrlSync } from "./read_write/get_real_file_system_url_sync.js";
|
|
38
|
+
export { readSymbolicLinkSync } from "./read_write/read_symbolic_link_sync.js";
|
|
39
|
+
export { writeDirectorySync } from "./read_write/write_directory_sync.js";
|
|
40
|
+
export { readFileStructureSync } from "./read_write/read_file_structure_sync.js";
|
|
41
|
+
export { writeFileStructureSync } from "./read_write/write_file_structure_sync.js";
|
|
42
|
+
|
|
43
|
+
// stat
|
|
44
|
+
export { readEntryStat } from "./read_write/stat/read_entry_stat.js";
|
|
45
|
+
export { readEntryModificationTime } from "./read_write/stat/read_entry_modification_time.js";
|
|
46
|
+
export { writeEntryModificationTime } from "./read_write/stat/write_entry_modification_time.js";
|
|
47
|
+
export { readEntryPermissions } from "./read_write/stat/read_entry_permissions.js";
|
|
48
|
+
export { writeEntryPermissions } from "./read_write/stat/write_entry_permissions.js";
|
|
49
|
+
export { grantPermissionsOnEntry } from "./read_write/stat/grant_permissions_on_entry.js";
|
|
50
|
+
export { testEntryPermissions } from "./read_write/stat/test_entry_permissions.js";
|
|
51
|
+
// stat sync
|
|
52
|
+
export { readEntryStatSync } from "./read_write/stat/read_entry_stat_sync.js";
|
|
53
|
+
export { writeEntryModificationTimeSync } from "./read_write/stat/write_entry_modification_time_sync.js";
|
|
54
|
+
|
|
55
|
+
// move
|
|
56
|
+
export { moveDirectoryContent } from "./move/move_directory_content.js";
|
|
57
|
+
export { moveEntry } from "./move/move_entry.js";
|
|
58
|
+
|
|
59
|
+
// copy
|
|
60
|
+
export { copyEntry } from "./copy/copy_entry.js";
|
|
61
|
+
export { copyDirectoryContent } from "./copy/copy_directory_content.js";
|
|
62
|
+
export { copyEntrySync } from "./copy/copy_entry_sync.js";
|
|
63
|
+
export { copyDirectorySync } from "./copy/copy_directory_sync.js";
|
|
64
|
+
export { copyDirectoryContentSync } from "./copy/copy_directory_content_sync.js";
|
|
65
|
+
|
|
66
|
+
// remove
|
|
67
|
+
export { ensureEmptyDirectory } from "./remove/ensure_empty_directory.js";
|
|
68
|
+
export { ensureEmptyDirectorySync } from "./remove/ensure_empty_directory_sync.js";
|
|
69
|
+
export { clearDirectorySync } from "./remove/clear_directory_sync.js";
|
|
70
|
+
export { removeDirectory } from "./remove/remove_directory.js";
|
|
71
|
+
export { removeFile } from "./remove/remove_file.js";
|
|
72
|
+
export { removeEntry } from "./remove/remove_entry.js";
|
|
73
|
+
export { removeDirectorySync } from "./remove/remove_directory_sync.js";
|
|
74
|
+
export { removeFileSync } from "./remove/remove_file_sync.js";
|
|
75
|
+
export { removeEntrySync } from "./remove/remove_entry_sync.js";
|
|
76
|
+
|
|
77
|
+
// lifecycle
|
|
78
|
+
export { registerDirectoryLifecycle } from "./lifecycle/register_directory_lifecycle.js";
|
|
79
|
+
export { registerFileLifecycle } from "./lifecycle/register_file_lifecycle.js";
|
|
80
|
+
|
|
81
|
+
// other
|
|
82
|
+
export { assertDirectoryPresence } from "./assert_directory_presence.js";
|
|
83
|
+
export { assertFilePresence } from "./assert_file_presence.js";
|
|
84
|
+
export { bufferToEtag } from "./buffer_to_etag.js";
|