@jsenv/test 3.5.31 → 3.5.33
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/dist/jsenv_test.js +353 -252
- package/package.json +5 -5
package/dist/jsenv_test.js
CHANGED
|
@@ -4,7 +4,7 @@ import tty from "node:tty";
|
|
|
4
4
|
import stringWidth from "string-width";
|
|
5
5
|
import { pathToFileURL, fileURLToPath } from "node:url";
|
|
6
6
|
import { URL_META, filterV8Coverage } from "./js/v8_coverage.js";
|
|
7
|
-
import { readdir, chmod, stat, lstat, chmodSync, statSync, lstatSync, promises, readFile as readFile$1,
|
|
7
|
+
import { readdir, chmod, stat, lstat, chmodSync, statSync, lstatSync, promises, readFile as readFile$1, unlinkSync, openSync, closeSync, readdirSync, rmdirSync, mkdirSync, readFileSync, writeFileSync as writeFileSync$1, unlink, rmdir, existsSync } from "node:fs";
|
|
8
8
|
import { dirname } from "node:path";
|
|
9
9
|
import crypto from "node:crypto";
|
|
10
10
|
import { readGitHubWorkflowEnv, startGithubCheckRun } from "@jsenv/github-check-run";
|
|
@@ -578,17 +578,29 @@ if (
|
|
|
578
578
|
}
|
|
579
579
|
|
|
580
580
|
function envForceColor() {
|
|
581
|
-
if ('FORCE_COLOR' in env) {
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
}
|
|
581
|
+
if (!('FORCE_COLOR' in env)) {
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
585
584
|
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
585
|
+
if (env.FORCE_COLOR === 'true') {
|
|
586
|
+
return 1;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
if (env.FORCE_COLOR === 'false') {
|
|
590
|
+
return 0;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
if (env.FORCE_COLOR.length === 0) {
|
|
594
|
+
return 1;
|
|
595
|
+
}
|
|
589
596
|
|
|
590
|
-
|
|
597
|
+
const level = Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);
|
|
598
|
+
|
|
599
|
+
if (![0, 1, 2, 3].includes(level)) {
|
|
600
|
+
return;
|
|
591
601
|
}
|
|
602
|
+
|
|
603
|
+
return level;
|
|
592
604
|
}
|
|
593
605
|
|
|
594
606
|
function translateLevel(level) {
|
|
@@ -659,11 +671,11 @@ function _supportsColor(haveStream, {streamIsTTY, sniffFlags = true} = {}) {
|
|
|
659
671
|
}
|
|
660
672
|
|
|
661
673
|
if ('CI' in env) {
|
|
662
|
-
if ('GITHUB_ACTIONS'
|
|
674
|
+
if (['GITHUB_ACTIONS', 'GITEA_ACTIONS', 'CIRCLECI'].some(key => key in env)) {
|
|
663
675
|
return 3;
|
|
664
676
|
}
|
|
665
677
|
|
|
666
|
-
if (['TRAVIS', '
|
|
678
|
+
if (['TRAVIS', 'APPVEYOR', 'GITLAB_CI', 'BUILDKITE', 'DRONE'].some(sign => sign in env) || env.CI_NAME === 'codeship') {
|
|
667
679
|
return 1;
|
|
668
680
|
}
|
|
669
681
|
|
|
@@ -2120,6 +2132,42 @@ const extractDriveLetter = (resource) => {
|
|
|
2120
2132
|
return null;
|
|
2121
2133
|
};
|
|
2122
2134
|
|
|
2135
|
+
const getParentDirectoryUrl = (url) => {
|
|
2136
|
+
if (url.startsWith("file://")) {
|
|
2137
|
+
// With node.js new URL('../', 'file:///C:/').href
|
|
2138
|
+
// returns "file:///C:/" instead of "file:///"
|
|
2139
|
+
const resource = url.slice("file://".length);
|
|
2140
|
+
const slashLastIndex = resource.lastIndexOf("/");
|
|
2141
|
+
if (slashLastIndex === -1) {
|
|
2142
|
+
return url;
|
|
2143
|
+
}
|
|
2144
|
+
const lastCharIndex = resource.length - 1;
|
|
2145
|
+
if (slashLastIndex === lastCharIndex) {
|
|
2146
|
+
const slashBeforeLastIndex = resource.lastIndexOf(
|
|
2147
|
+
"/",
|
|
2148
|
+
slashLastIndex - 1,
|
|
2149
|
+
);
|
|
2150
|
+
if (slashBeforeLastIndex === -1) {
|
|
2151
|
+
return url;
|
|
2152
|
+
}
|
|
2153
|
+
return `file://${resource.slice(0, slashBeforeLastIndex + 1)}`;
|
|
2154
|
+
}
|
|
2155
|
+
return `file://${resource.slice(0, slashLastIndex + 1)}`;
|
|
2156
|
+
}
|
|
2157
|
+
return new URL(url.endsWith("/") ? "../" : "./", url).href;
|
|
2158
|
+
};
|
|
2159
|
+
|
|
2160
|
+
const findAncestorDirectoryUrl = (url, callback) => {
|
|
2161
|
+
url = String(url);
|
|
2162
|
+
while (url !== "file:///") {
|
|
2163
|
+
if (callback(url)) {
|
|
2164
|
+
return url;
|
|
2165
|
+
}
|
|
2166
|
+
url = getParentDirectoryUrl(url);
|
|
2167
|
+
}
|
|
2168
|
+
return null;
|
|
2169
|
+
};
|
|
2170
|
+
|
|
2123
2171
|
const readDirectory = async (url, { emfileMaxWait = 1000 } = {}) => {
|
|
2124
2172
|
const directoryUrl = assertAndNormalizeDirectoryUrl(url);
|
|
2125
2173
|
const directoryUrlObject = new URL(directoryUrl);
|
|
@@ -2542,7 +2590,284 @@ const readFile = async (value, { as = "buffer" } = {}) => {
|
|
|
2542
2590
|
);
|
|
2543
2591
|
};
|
|
2544
2592
|
|
|
2545
|
-
const
|
|
2593
|
+
const removeEntrySync = (
|
|
2594
|
+
source,
|
|
2595
|
+
{
|
|
2596
|
+
allowUseless = false,
|
|
2597
|
+
recursive = false,
|
|
2598
|
+
maxRetries = 3,
|
|
2599
|
+
retryDelay = 100,
|
|
2600
|
+
onlyContent = false,
|
|
2601
|
+
} = {},
|
|
2602
|
+
) => {
|
|
2603
|
+
const sourceUrl = assertAndNormalizeFileUrl(source);
|
|
2604
|
+
const sourceStats = readEntryStatSync(sourceUrl, {
|
|
2605
|
+
nullIfNotFound: true,
|
|
2606
|
+
followLink: false,
|
|
2607
|
+
});
|
|
2608
|
+
if (!sourceStats) {
|
|
2609
|
+
if (allowUseless) {
|
|
2610
|
+
return;
|
|
2611
|
+
}
|
|
2612
|
+
throw new Error(`nothing to remove at ${urlToFileSystemPath(sourceUrl)}`);
|
|
2613
|
+
}
|
|
2614
|
+
|
|
2615
|
+
// https://nodejs.org/dist/latest-v13.x/docs/api/fs.html#fs_class_fs_stats
|
|
2616
|
+
// FIFO and socket are ignored, not sure what they are exactly and what to do with them
|
|
2617
|
+
// other libraries ignore them, let's do the same.
|
|
2618
|
+
if (
|
|
2619
|
+
sourceStats.isFile() ||
|
|
2620
|
+
sourceStats.isSymbolicLink() ||
|
|
2621
|
+
sourceStats.isCharacterDevice() ||
|
|
2622
|
+
sourceStats.isBlockDevice()
|
|
2623
|
+
) {
|
|
2624
|
+
removeNonDirectory$1(
|
|
2625
|
+
sourceUrl.endsWith("/") ? sourceUrl.slice(0, -1) : sourceUrl);
|
|
2626
|
+
} else if (sourceStats.isDirectory()) {
|
|
2627
|
+
const directoryUrl = ensurePathnameTrailingSlash(sourceUrl);
|
|
2628
|
+
removeDirectorySync$1(directoryUrl, {
|
|
2629
|
+
recursive,
|
|
2630
|
+
maxRetries,
|
|
2631
|
+
retryDelay,
|
|
2632
|
+
onlyContent,
|
|
2633
|
+
});
|
|
2634
|
+
}
|
|
2635
|
+
};
|
|
2636
|
+
|
|
2637
|
+
const removeNonDirectory$1 = (sourceUrl) => {
|
|
2638
|
+
const sourcePath = urlToFileSystemPath(sourceUrl);
|
|
2639
|
+
const attempt = () => {
|
|
2640
|
+
unlinkSyncNaive(sourcePath);
|
|
2641
|
+
};
|
|
2642
|
+
attempt();
|
|
2643
|
+
};
|
|
2644
|
+
|
|
2645
|
+
const unlinkSyncNaive = (sourcePath, { handleTemporaryError = null } = {}) => {
|
|
2646
|
+
try {
|
|
2647
|
+
unlinkSync(sourcePath);
|
|
2648
|
+
} catch (error) {
|
|
2649
|
+
if (error.code === "ENOENT") {
|
|
2650
|
+
return;
|
|
2651
|
+
}
|
|
2652
|
+
if (
|
|
2653
|
+
handleTemporaryError &&
|
|
2654
|
+
(error.code === "EBUSY" ||
|
|
2655
|
+
error.code === "EMFILE" ||
|
|
2656
|
+
error.code === "ENFILE" ||
|
|
2657
|
+
error.code === "ENOENT")
|
|
2658
|
+
) {
|
|
2659
|
+
handleTemporaryError(error);
|
|
2660
|
+
return;
|
|
2661
|
+
}
|
|
2662
|
+
throw error;
|
|
2663
|
+
}
|
|
2664
|
+
};
|
|
2665
|
+
|
|
2666
|
+
const removeDirectorySync$1 = (
|
|
2667
|
+
rootDirectoryUrl,
|
|
2668
|
+
{ maxRetries, retryDelay, recursive, onlyContent },
|
|
2669
|
+
) => {
|
|
2670
|
+
const visit = (sourceUrl) => {
|
|
2671
|
+
const sourceStats = readEntryStatSync(sourceUrl, {
|
|
2672
|
+
nullIfNotFound: true,
|
|
2673
|
+
followLink: false,
|
|
2674
|
+
});
|
|
2675
|
+
|
|
2676
|
+
// file/directory not found
|
|
2677
|
+
if (sourceStats === null) {
|
|
2678
|
+
return;
|
|
2679
|
+
}
|
|
2680
|
+
|
|
2681
|
+
if (
|
|
2682
|
+
sourceStats.isFile() ||
|
|
2683
|
+
sourceStats.isCharacterDevice() ||
|
|
2684
|
+
sourceStats.isBlockDevice()
|
|
2685
|
+
) {
|
|
2686
|
+
visitFile(sourceUrl);
|
|
2687
|
+
} else if (sourceStats.isSymbolicLink()) {
|
|
2688
|
+
visitSymbolicLink(sourceUrl);
|
|
2689
|
+
} else if (sourceStats.isDirectory()) {
|
|
2690
|
+
visitDirectory(`${sourceUrl}/`);
|
|
2691
|
+
}
|
|
2692
|
+
};
|
|
2693
|
+
|
|
2694
|
+
const visitDirectory = (directoryUrl) => {
|
|
2695
|
+
const directoryPath = urlToFileSystemPath(directoryUrl);
|
|
2696
|
+
const optionsFromRecursive = recursive
|
|
2697
|
+
? {
|
|
2698
|
+
handleNotEmptyError: () => {
|
|
2699
|
+
removeDirectoryContent(directoryUrl);
|
|
2700
|
+
visitDirectory(directoryUrl);
|
|
2701
|
+
},
|
|
2702
|
+
}
|
|
2703
|
+
: {};
|
|
2704
|
+
removeDirectorySyncNaive(directoryPath, {
|
|
2705
|
+
...optionsFromRecursive,
|
|
2706
|
+
// Workaround for https://github.com/joyent/node/issues/4337
|
|
2707
|
+
...(process.platform === "win32"
|
|
2708
|
+
? {
|
|
2709
|
+
handlePermissionError: (error) => {
|
|
2710
|
+
console.error(
|
|
2711
|
+
`trying to fix windows EPERM after readir on ${directoryPath}`,
|
|
2712
|
+
);
|
|
2713
|
+
|
|
2714
|
+
let openOrCloseError;
|
|
2715
|
+
try {
|
|
2716
|
+
const fd = openSync(directoryPath);
|
|
2717
|
+
closeSync(fd);
|
|
2718
|
+
} catch (e) {
|
|
2719
|
+
openOrCloseError = e;
|
|
2720
|
+
}
|
|
2721
|
+
|
|
2722
|
+
if (openOrCloseError) {
|
|
2723
|
+
if (openOrCloseError.code === "ENOENT") {
|
|
2724
|
+
return;
|
|
2725
|
+
}
|
|
2726
|
+
console.error(
|
|
2727
|
+
`error while trying to fix windows EPERM after readir on ${directoryPath}: ${openOrCloseError.stack}`,
|
|
2728
|
+
);
|
|
2729
|
+
throw error;
|
|
2730
|
+
}
|
|
2731
|
+
removeDirectorySyncNaive(directoryPath, {
|
|
2732
|
+
...optionsFromRecursive,
|
|
2733
|
+
});
|
|
2734
|
+
},
|
|
2735
|
+
}
|
|
2736
|
+
: {}),
|
|
2737
|
+
});
|
|
2738
|
+
};
|
|
2739
|
+
|
|
2740
|
+
const removeDirectoryContent = (directoryUrl) => {
|
|
2741
|
+
const entryNames = readdirSync(new URL(directoryUrl));
|
|
2742
|
+
for (const entryName of entryNames) {
|
|
2743
|
+
const url = resolveUrl(entryName, directoryUrl);
|
|
2744
|
+
visit(url);
|
|
2745
|
+
}
|
|
2746
|
+
};
|
|
2747
|
+
|
|
2748
|
+
const visitFile = (fileUrl) => {
|
|
2749
|
+
removeNonDirectory$1(fileUrl);
|
|
2750
|
+
};
|
|
2751
|
+
|
|
2752
|
+
const visitSymbolicLink = (symbolicLinkUrl) => {
|
|
2753
|
+
removeNonDirectory$1(symbolicLinkUrl);
|
|
2754
|
+
};
|
|
2755
|
+
|
|
2756
|
+
if (onlyContent) {
|
|
2757
|
+
removeDirectoryContent(rootDirectoryUrl);
|
|
2758
|
+
} else {
|
|
2759
|
+
visitDirectory(rootDirectoryUrl);
|
|
2760
|
+
}
|
|
2761
|
+
};
|
|
2762
|
+
|
|
2763
|
+
const removeDirectorySyncNaive = (
|
|
2764
|
+
directoryPath,
|
|
2765
|
+
{ handleNotEmptyError = null, handlePermissionError = null } = {},
|
|
2766
|
+
) => {
|
|
2767
|
+
try {
|
|
2768
|
+
rmdirSync(directoryPath);
|
|
2769
|
+
} catch (error) {
|
|
2770
|
+
if (handlePermissionError && error.code === "EPERM") {
|
|
2771
|
+
handlePermissionError(error);
|
|
2772
|
+
return;
|
|
2773
|
+
}
|
|
2774
|
+
if (error.code === "ENOENT") {
|
|
2775
|
+
return;
|
|
2776
|
+
}
|
|
2777
|
+
if (
|
|
2778
|
+
handleNotEmptyError &&
|
|
2779
|
+
// linux os
|
|
2780
|
+
(error.code === "ENOTEMPTY" ||
|
|
2781
|
+
// SunOS
|
|
2782
|
+
error.code === "EEXIST")
|
|
2783
|
+
) {
|
|
2784
|
+
handleNotEmptyError(error);
|
|
2785
|
+
return;
|
|
2786
|
+
}
|
|
2787
|
+
throw error;
|
|
2788
|
+
}
|
|
2789
|
+
};
|
|
2790
|
+
|
|
2791
|
+
const removeDirectorySync = (url, options = {}) => {
|
|
2792
|
+
return removeEntrySync(url, {
|
|
2793
|
+
...options,
|
|
2794
|
+
recursive: true,
|
|
2795
|
+
});
|
|
2796
|
+
};
|
|
2797
|
+
|
|
2798
|
+
const writeDirectorySync = (
|
|
2799
|
+
destination,
|
|
2800
|
+
{ recursive = true, allowUseless = false, force } = {},
|
|
2801
|
+
) => {
|
|
2802
|
+
const destinationUrl = assertAndNormalizeDirectoryUrl(destination);
|
|
2803
|
+
const destinationPath = urlToFileSystemPath(destinationUrl);
|
|
2804
|
+
|
|
2805
|
+
let destinationStats;
|
|
2806
|
+
try {
|
|
2807
|
+
destinationStats = readEntryStatSync(destinationUrl, {
|
|
2808
|
+
nullIfNotFound: true,
|
|
2809
|
+
followLink: false,
|
|
2810
|
+
});
|
|
2811
|
+
} catch (e) {
|
|
2812
|
+
if (e.code === "ENOTDIR") {
|
|
2813
|
+
let previousNonDirUrl = destinationUrl;
|
|
2814
|
+
// we must try all parent directories as long as it fails with ENOTDIR
|
|
2815
|
+
findAncestorDirectoryUrl(destinationUrl, (ancestorUrl) => {
|
|
2816
|
+
try {
|
|
2817
|
+
statSync(new URL(ancestorUrl));
|
|
2818
|
+
return true;
|
|
2819
|
+
} catch (e) {
|
|
2820
|
+
if (e.code === "ENOTDIR") {
|
|
2821
|
+
previousNonDirUrl = ancestorUrl;
|
|
2822
|
+
return false;
|
|
2823
|
+
}
|
|
2824
|
+
throw e;
|
|
2825
|
+
}
|
|
2826
|
+
});
|
|
2827
|
+
if (force) {
|
|
2828
|
+
unlinkSync(
|
|
2829
|
+
new URL(
|
|
2830
|
+
previousNonDirUrl
|
|
2831
|
+
// remove trailing slash
|
|
2832
|
+
.slice(0, -1),
|
|
2833
|
+
),
|
|
2834
|
+
);
|
|
2835
|
+
} else {
|
|
2836
|
+
throw new Error(
|
|
2837
|
+
`cannot write directory at ${destinationPath} because there is a file at ${urlToFileSystemPath(
|
|
2838
|
+
previousNonDirUrl,
|
|
2839
|
+
)}`,
|
|
2840
|
+
);
|
|
2841
|
+
}
|
|
2842
|
+
} else {
|
|
2843
|
+
throw e;
|
|
2844
|
+
}
|
|
2845
|
+
}
|
|
2846
|
+
|
|
2847
|
+
if (destinationStats) {
|
|
2848
|
+
if (destinationStats.isDirectory()) {
|
|
2849
|
+
if (allowUseless) {
|
|
2850
|
+
return;
|
|
2851
|
+
}
|
|
2852
|
+
throw new Error(`directory already exists at ${destinationPath}`);
|
|
2853
|
+
}
|
|
2854
|
+
const destinationType = statsToType(destinationStats);
|
|
2855
|
+
throw new Error(
|
|
2856
|
+
`cannot write directory at ${destinationPath} because there is a ${destinationType}`,
|
|
2857
|
+
);
|
|
2858
|
+
}
|
|
2859
|
+
|
|
2860
|
+
try {
|
|
2861
|
+
mkdirSync(destinationPath, { recursive });
|
|
2862
|
+
} catch (error) {
|
|
2863
|
+
if (allowUseless && error.code === "EEXIST") {
|
|
2864
|
+
return;
|
|
2865
|
+
}
|
|
2866
|
+
throw error;
|
|
2867
|
+
}
|
|
2868
|
+
};
|
|
2869
|
+
|
|
2870
|
+
const writeFileSync = (destination, content = "", { force } = {}) => {
|
|
2546
2871
|
const destinationUrl = assertAndNormalizeFileUrl(destination);
|
|
2547
2872
|
const destinationUrlObject = new URL(destinationUrl);
|
|
2548
2873
|
if (content && content instanceof URL) {
|
|
@@ -2551,8 +2876,18 @@ const writeFileSync = (destination, content = "") => {
|
|
|
2551
2876
|
try {
|
|
2552
2877
|
writeFileSync$1(destinationUrlObject, content);
|
|
2553
2878
|
} catch (error) {
|
|
2554
|
-
if (error.code === "
|
|
2555
|
-
|
|
2879
|
+
if (error.code === "EISDIR") {
|
|
2880
|
+
// happens when directory existed but got deleted and now it's a file
|
|
2881
|
+
if (force) {
|
|
2882
|
+
removeDirectorySync(destinationUrlObject);
|
|
2883
|
+
writeFileSync$1(destinationUrlObject, content);
|
|
2884
|
+
} else {
|
|
2885
|
+
throw error;
|
|
2886
|
+
}
|
|
2887
|
+
}
|
|
2888
|
+
if (error.code === "ENOENT" || error.code === "ENOTDIR") {
|
|
2889
|
+
writeDirectorySync(new URL("./", destinationUrlObject), {
|
|
2890
|
+
force,
|
|
2556
2891
|
recursive: true,
|
|
2557
2892
|
});
|
|
2558
2893
|
writeFileSync$1(destinationUrlObject, content);
|
|
@@ -2600,7 +2935,7 @@ const removeEntry = async (
|
|
|
2600
2935
|
sourceStats.isCharacterDevice() ||
|
|
2601
2936
|
sourceStats.isBlockDevice()
|
|
2602
2937
|
) {
|
|
2603
|
-
await removeNonDirectory
|
|
2938
|
+
await removeNonDirectory(
|
|
2604
2939
|
sourceUrl.endsWith("/") ? sourceUrl.slice(0, -1) : sourceUrl,
|
|
2605
2940
|
{
|
|
2606
2941
|
maxRetries,
|
|
@@ -2621,7 +2956,7 @@ const removeEntry = async (
|
|
|
2621
2956
|
}
|
|
2622
2957
|
};
|
|
2623
2958
|
|
|
2624
|
-
const removeNonDirectory
|
|
2959
|
+
const removeNonDirectory = (sourceUrl, { maxRetries, retryDelay }) => {
|
|
2625
2960
|
const sourcePath = urlToFileSystemPath(sourceUrl);
|
|
2626
2961
|
|
|
2627
2962
|
let retryCount = 0;
|
|
@@ -2760,11 +3095,11 @@ const removeDirectory = async (
|
|
|
2760
3095
|
};
|
|
2761
3096
|
|
|
2762
3097
|
const visitFile = async (fileUrl) => {
|
|
2763
|
-
await removeNonDirectory
|
|
3098
|
+
await removeNonDirectory(fileUrl, { maxRetries, retryDelay });
|
|
2764
3099
|
};
|
|
2765
3100
|
|
|
2766
3101
|
const visitSymbolicLink = async (symbolicLinkUrl) => {
|
|
2767
|
-
await removeNonDirectory
|
|
3102
|
+
await removeNonDirectory(symbolicLinkUrl, { maxRetries, retryDelay });
|
|
2768
3103
|
};
|
|
2769
3104
|
|
|
2770
3105
|
try {
|
|
@@ -2809,240 +3144,6 @@ const removeDirectoryNaive = (
|
|
|
2809
3144
|
|
|
2810
3145
|
process.platform === "win32";
|
|
2811
3146
|
|
|
2812
|
-
const writeDirectorySync = (
|
|
2813
|
-
destination,
|
|
2814
|
-
{ recursive = true, allowUseless = false } = {},
|
|
2815
|
-
) => {
|
|
2816
|
-
const destinationUrl = assertAndNormalizeDirectoryUrl(destination);
|
|
2817
|
-
const destinationPath = urlToFileSystemPath(destinationUrl);
|
|
2818
|
-
|
|
2819
|
-
const destinationStats = readEntryStatSync(destinationUrl, {
|
|
2820
|
-
nullIfNotFound: true,
|
|
2821
|
-
followLink: false,
|
|
2822
|
-
});
|
|
2823
|
-
|
|
2824
|
-
if (destinationStats) {
|
|
2825
|
-
if (destinationStats.isDirectory()) {
|
|
2826
|
-
if (allowUseless) {
|
|
2827
|
-
return;
|
|
2828
|
-
}
|
|
2829
|
-
throw new Error(`directory already exists at ${destinationPath}`);
|
|
2830
|
-
}
|
|
2831
|
-
|
|
2832
|
-
const destinationType = statsToType(destinationStats);
|
|
2833
|
-
throw new Error(
|
|
2834
|
-
`cannot write directory at ${destinationPath} because there is a ${destinationType}`,
|
|
2835
|
-
);
|
|
2836
|
-
}
|
|
2837
|
-
|
|
2838
|
-
try {
|
|
2839
|
-
mkdirSync(destinationPath, { recursive });
|
|
2840
|
-
} catch (error) {
|
|
2841
|
-
if (allowUseless && error.code === "EEXIST") {
|
|
2842
|
-
return;
|
|
2843
|
-
}
|
|
2844
|
-
throw error;
|
|
2845
|
-
}
|
|
2846
|
-
};
|
|
2847
|
-
|
|
2848
|
-
const removeEntrySync = (
|
|
2849
|
-
source,
|
|
2850
|
-
{
|
|
2851
|
-
allowUseless = false,
|
|
2852
|
-
recursive = false,
|
|
2853
|
-
maxRetries = 3,
|
|
2854
|
-
retryDelay = 100,
|
|
2855
|
-
onlyContent = false,
|
|
2856
|
-
} = {},
|
|
2857
|
-
) => {
|
|
2858
|
-
const sourceUrl = assertAndNormalizeFileUrl(source);
|
|
2859
|
-
const sourceStats = readEntryStatSync(sourceUrl, {
|
|
2860
|
-
nullIfNotFound: true,
|
|
2861
|
-
followLink: false,
|
|
2862
|
-
});
|
|
2863
|
-
if (!sourceStats) {
|
|
2864
|
-
if (allowUseless) {
|
|
2865
|
-
return;
|
|
2866
|
-
}
|
|
2867
|
-
throw new Error(`nothing to remove at ${urlToFileSystemPath(sourceUrl)}`);
|
|
2868
|
-
}
|
|
2869
|
-
|
|
2870
|
-
// https://nodejs.org/dist/latest-v13.x/docs/api/fs.html#fs_class_fs_stats
|
|
2871
|
-
// FIFO and socket are ignored, not sure what they are exactly and what to do with them
|
|
2872
|
-
// other libraries ignore them, let's do the same.
|
|
2873
|
-
if (
|
|
2874
|
-
sourceStats.isFile() ||
|
|
2875
|
-
sourceStats.isSymbolicLink() ||
|
|
2876
|
-
sourceStats.isCharacterDevice() ||
|
|
2877
|
-
sourceStats.isBlockDevice()
|
|
2878
|
-
) {
|
|
2879
|
-
removeNonDirectory(
|
|
2880
|
-
sourceUrl.endsWith("/") ? sourceUrl.slice(0, -1) : sourceUrl);
|
|
2881
|
-
} else if (sourceStats.isDirectory()) {
|
|
2882
|
-
const directoryUrl = ensurePathnameTrailingSlash(sourceUrl);
|
|
2883
|
-
removeDirectorySync(directoryUrl, {
|
|
2884
|
-
recursive,
|
|
2885
|
-
maxRetries,
|
|
2886
|
-
retryDelay,
|
|
2887
|
-
onlyContent,
|
|
2888
|
-
});
|
|
2889
|
-
}
|
|
2890
|
-
};
|
|
2891
|
-
|
|
2892
|
-
const removeNonDirectory = (sourceUrl) => {
|
|
2893
|
-
const sourcePath = urlToFileSystemPath(sourceUrl);
|
|
2894
|
-
const attempt = () => {
|
|
2895
|
-
unlinkSyncNaive(sourcePath);
|
|
2896
|
-
};
|
|
2897
|
-
attempt();
|
|
2898
|
-
};
|
|
2899
|
-
|
|
2900
|
-
const unlinkSyncNaive = (sourcePath, { handleTemporaryError = null } = {}) => {
|
|
2901
|
-
try {
|
|
2902
|
-
unlinkSync(sourcePath);
|
|
2903
|
-
} catch (error) {
|
|
2904
|
-
if (error.code === "ENOENT") {
|
|
2905
|
-
return;
|
|
2906
|
-
}
|
|
2907
|
-
if (
|
|
2908
|
-
handleTemporaryError &&
|
|
2909
|
-
(error.code === "EBUSY" ||
|
|
2910
|
-
error.code === "EMFILE" ||
|
|
2911
|
-
error.code === "ENFILE" ||
|
|
2912
|
-
error.code === "ENOENT")
|
|
2913
|
-
) {
|
|
2914
|
-
handleTemporaryError(error);
|
|
2915
|
-
return;
|
|
2916
|
-
}
|
|
2917
|
-
throw error;
|
|
2918
|
-
}
|
|
2919
|
-
};
|
|
2920
|
-
|
|
2921
|
-
const removeDirectorySync = (
|
|
2922
|
-
rootDirectoryUrl,
|
|
2923
|
-
{ maxRetries, retryDelay, recursive, onlyContent },
|
|
2924
|
-
) => {
|
|
2925
|
-
const visit = (sourceUrl) => {
|
|
2926
|
-
const sourceStats = readEntryStatSync(sourceUrl, {
|
|
2927
|
-
nullIfNotFound: true,
|
|
2928
|
-
followLink: false,
|
|
2929
|
-
});
|
|
2930
|
-
|
|
2931
|
-
// file/directory not found
|
|
2932
|
-
if (sourceStats === null) {
|
|
2933
|
-
return;
|
|
2934
|
-
}
|
|
2935
|
-
|
|
2936
|
-
if (
|
|
2937
|
-
sourceStats.isFile() ||
|
|
2938
|
-
sourceStats.isCharacterDevice() ||
|
|
2939
|
-
sourceStats.isBlockDevice()
|
|
2940
|
-
) {
|
|
2941
|
-
visitFile(sourceUrl);
|
|
2942
|
-
} else if (sourceStats.isSymbolicLink()) {
|
|
2943
|
-
visitSymbolicLink(sourceUrl);
|
|
2944
|
-
} else if (sourceStats.isDirectory()) {
|
|
2945
|
-
visitDirectory(`${sourceUrl}/`);
|
|
2946
|
-
}
|
|
2947
|
-
};
|
|
2948
|
-
|
|
2949
|
-
const visitDirectory = (directoryUrl) => {
|
|
2950
|
-
const directoryPath = urlToFileSystemPath(directoryUrl);
|
|
2951
|
-
const optionsFromRecursive = recursive
|
|
2952
|
-
? {
|
|
2953
|
-
handleNotEmptyError: () => {
|
|
2954
|
-
removeDirectoryContent(directoryUrl);
|
|
2955
|
-
visitDirectory(directoryUrl);
|
|
2956
|
-
},
|
|
2957
|
-
}
|
|
2958
|
-
: {};
|
|
2959
|
-
removeDirectorySyncNaive(directoryPath, {
|
|
2960
|
-
...optionsFromRecursive,
|
|
2961
|
-
// Workaround for https://github.com/joyent/node/issues/4337
|
|
2962
|
-
...(process.platform === "win32"
|
|
2963
|
-
? {
|
|
2964
|
-
handlePermissionError: (error) => {
|
|
2965
|
-
console.error(
|
|
2966
|
-
`trying to fix windows EPERM after readir on ${directoryPath}`,
|
|
2967
|
-
);
|
|
2968
|
-
|
|
2969
|
-
let openOrCloseError;
|
|
2970
|
-
try {
|
|
2971
|
-
const fd = openSync(directoryPath);
|
|
2972
|
-
closeSync(fd);
|
|
2973
|
-
} catch (e) {
|
|
2974
|
-
openOrCloseError = e;
|
|
2975
|
-
}
|
|
2976
|
-
|
|
2977
|
-
if (openOrCloseError) {
|
|
2978
|
-
if (openOrCloseError.code === "ENOENT") {
|
|
2979
|
-
return;
|
|
2980
|
-
}
|
|
2981
|
-
console.error(
|
|
2982
|
-
`error while trying to fix windows EPERM after readir on ${directoryPath}: ${openOrCloseError.stack}`,
|
|
2983
|
-
);
|
|
2984
|
-
throw error;
|
|
2985
|
-
}
|
|
2986
|
-
removeDirectorySyncNaive(directoryPath, {
|
|
2987
|
-
...optionsFromRecursive,
|
|
2988
|
-
});
|
|
2989
|
-
},
|
|
2990
|
-
}
|
|
2991
|
-
: {}),
|
|
2992
|
-
});
|
|
2993
|
-
};
|
|
2994
|
-
|
|
2995
|
-
const removeDirectoryContent = (directoryUrl) => {
|
|
2996
|
-
const entryNames = readdirSync(new URL(directoryUrl));
|
|
2997
|
-
for (const entryName of entryNames) {
|
|
2998
|
-
const url = resolveUrl(entryName, directoryUrl);
|
|
2999
|
-
visit(url);
|
|
3000
|
-
}
|
|
3001
|
-
};
|
|
3002
|
-
|
|
3003
|
-
const visitFile = (fileUrl) => {
|
|
3004
|
-
removeNonDirectory(fileUrl);
|
|
3005
|
-
};
|
|
3006
|
-
|
|
3007
|
-
const visitSymbolicLink = (symbolicLinkUrl) => {
|
|
3008
|
-
removeNonDirectory(symbolicLinkUrl);
|
|
3009
|
-
};
|
|
3010
|
-
|
|
3011
|
-
if (onlyContent) {
|
|
3012
|
-
removeDirectoryContent(rootDirectoryUrl);
|
|
3013
|
-
} else {
|
|
3014
|
-
visitDirectory(rootDirectoryUrl);
|
|
3015
|
-
}
|
|
3016
|
-
};
|
|
3017
|
-
|
|
3018
|
-
const removeDirectorySyncNaive = (
|
|
3019
|
-
directoryPath,
|
|
3020
|
-
{ handleNotEmptyError = null, handlePermissionError = null } = {},
|
|
3021
|
-
) => {
|
|
3022
|
-
try {
|
|
3023
|
-
rmdirSync(directoryPath);
|
|
3024
|
-
} catch (error) {
|
|
3025
|
-
if (handlePermissionError && error.code === "EPERM") {
|
|
3026
|
-
handlePermissionError(error);
|
|
3027
|
-
return;
|
|
3028
|
-
}
|
|
3029
|
-
if (error.code === "ENOENT") {
|
|
3030
|
-
return;
|
|
3031
|
-
}
|
|
3032
|
-
if (
|
|
3033
|
-
handleNotEmptyError &&
|
|
3034
|
-
// linux os
|
|
3035
|
-
(error.code === "ENOTEMPTY" ||
|
|
3036
|
-
// SunOS
|
|
3037
|
-
error.code === "EEXIST")
|
|
3038
|
-
) {
|
|
3039
|
-
handleNotEmptyError(error);
|
|
3040
|
-
return;
|
|
3041
|
-
}
|
|
3042
|
-
throw error;
|
|
3043
|
-
}
|
|
3044
|
-
};
|
|
3045
|
-
|
|
3046
3147
|
process.platform === "win32";
|
|
3047
3148
|
|
|
3048
3149
|
const ensureEmptyDirectorySync = (source) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/test",
|
|
3
|
-
"version": "3.5.
|
|
3
|
+
"version": "3.5.33",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -39,12 +39,12 @@
|
|
|
39
39
|
"@jsenv/abort": "4.3.0",
|
|
40
40
|
"@jsenv/ast": "6.4.1",
|
|
41
41
|
"@jsenv/exception": "1.1.3",
|
|
42
|
-
"@jsenv/filesystem": "4.
|
|
42
|
+
"@jsenv/filesystem": "4.12.0",
|
|
43
43
|
"@jsenv/github-check-run": "0.2.5",
|
|
44
44
|
"@jsenv/node-esm-resolution": "1.0.6",
|
|
45
45
|
"@jsenv/humanize": "1.2.8",
|
|
46
|
-
"@jsenv/plugin-supervisor": "1.6.
|
|
47
|
-
"@jsenv/sourcemap": "1.2.
|
|
46
|
+
"@jsenv/plugin-supervisor": "1.6.1",
|
|
47
|
+
"@jsenv/sourcemap": "1.2.29",
|
|
48
48
|
"@jsenv/url-meta": "8.5.2",
|
|
49
49
|
"@jsenv/urls": "2.5.4",
|
|
50
50
|
"@jsenv/utils": "2.1.2",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"istanbul-reports": "3.1.7",
|
|
56
56
|
"pidtree": "0.6.0",
|
|
57
57
|
"strip-ansi": "7.1.0",
|
|
58
|
-
"supports-color": "
|
|
58
|
+
"supports-color": "10.0.0",
|
|
59
59
|
"v8-to-istanbul": "9.3.0"
|
|
60
60
|
}
|
|
61
61
|
}
|