summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Sherret <dsherret@users.noreply.github.com>2022-09-27 18:02:35 -0400
committerGitHub <noreply@github.com>2022-09-27 18:02:35 -0400
commita44c83a3d66a576e93f642ec475ea505215a8d62 (patch)
tree549d3f8d563ef9685f210f37337a9ef3b52f5ec3
parentabdb6aad6e3e9aa8b6943eba1bbe297f34a825f4 (diff)
fix(npm): use ntfs junctions in node_modules folder on Windows (#16061)
-rw-r--r--Cargo.lock11
-rw-r--r--cli/Cargo.toml1
-rw-r--r--cli/npm/resolvers/local.rs35
3 files changed, 47 insertions, 0 deletions
diff --git a/Cargo.lock b/Cargo.lock
index a7bfecc65..b6bbbf31a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -848,6 +848,7 @@ dependencies = [
"indexmap",
"indicatif",
"jsonc-parser",
+ "junction",
"libc",
"log 0.4.17",
"mitata",
@@ -2494,6 +2495,16 @@ dependencies = [
]
[[package]]
+name = "junction"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be39922b087cecaba4e2d5592dedfc8bda5d4a5a1231f143337cca207950b61d"
+dependencies = [
+ "scopeguard",
+ "winapi 0.3.9",
+]
+
+[[package]]
name = "kernel32-sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/cli/Cargo.toml b/cli/Cargo.toml
index 0663c02ff..22929fd21 100644
--- a/cli/Cargo.toml
+++ b/cli/Cargo.toml
@@ -111,6 +111,7 @@ zstd = '=0.11.2'
[target.'cfg(windows)'.dependencies]
fwdansi = "=1.1.0"
+junction = "=0.2.0"
winapi = { version = "=0.3.9", features = ["knownfolders", "mswsock", "objbase", "shlobj", "tlhelp32", "winbase", "winerror", "winsock2"] }
[dev-dependencies]
diff --git a/cli/npm/resolvers/local.rs b/cli/npm/resolvers/local.rs
index 35223f1aa..fa2ad4275 100644
--- a/cli/npm/resolvers/local.rs
+++ b/cli/npm/resolvers/local.rs
@@ -323,9 +323,44 @@ fn symlink_package_dir(
// need to delete the previous symlink before creating a new one
let _ignore = fs::remove_dir_all(new_path);
+
+ #[cfg(windows)]
+ return junction_or_symlink_dir(old_path, new_path);
+ #[cfg(not(windows))]
fs_util::symlink_dir(old_path, new_path)
}
+#[cfg(windows)]
+fn junction_or_symlink_dir(
+ old_path: &Path,
+ new_path: &Path,
+) -> Result<(), AnyError> {
+ // Use junctions because they're supported on ntfs file systems without
+ // needing to elevate privileges on Windows
+ match junction::create(old_path, new_path) {
+ Ok(()) => Ok(()),
+ Err(junction_err) => {
+ if cfg!(debug) {
+ // When running the tests, junctions should be created, but if not then
+ // surface this error.
+ log::warn!("Error creating junction. {:#}", junction_err);
+ }
+
+ match fs_util::symlink_dir(old_path, new_path) {
+ Ok(()) => Ok(()),
+ Err(symlink_err) => bail!(
+ concat!(
+ "Failed creating junction and fallback symlink in node_modules folder.\n\n",
+ "{:#}\n\n{:#}",
+ ),
+ junction_err,
+ symlink_err,
+ ),
+ }
+ }
+ }
+}
+
fn join_package_name(path: &Path, package_name: &str) -> PathBuf {
let mut path = path.to_path_buf();
// ensure backslashes are used on windows