Skip to content

Commit a423415

Browse files
committed
Catch potential symlinks
1 parent ac6a87d commit a423415

File tree

2 files changed

+46
-10
lines changed

2 files changed

+46
-10
lines changed

rewatch/src/build/compile.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,9 @@ fn get_dependency_paths(
535535
.as_ref()
536536
.map(|package| package.path.clone())
537537
} else {
538-
packages::read_dependency(package_name, project_root, project_root, workspace_root).ok()
538+
packages::read_dependency(package_name, project_root, project_root, workspace_root)
539+
.map(|(p, _)| p)
540+
.ok()
539541
}
540542
.map(|canonicalized_path| {
541543
vec![

rewatch/src/build/packages.rs

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use super::build_types::*;
22
use super::namespaces;
33
use super::packages;
4+
use crate::build::packages::DependencySymLink::{NoSymlink, Symlink};
45
use crate::config;
56
use crate::helpers;
67
use crate::helpers::StrippedVerbatimPath;
@@ -39,13 +40,22 @@ impl Namespace {
3940
}
4041
}
4142

43+
#[derive(Debug, Clone)]
44+
pub enum DependencySymLink {
45+
NoSymlink,
46+
Symlink(PathBuf),
47+
}
48+
4249
#[derive(Debug, Clone)]
4350
struct Dependency {
4451
name: String,
4552
config: config::Config,
4653
path: PathBuf,
4754
is_pinned: bool,
4855
dependencies: Vec<Dependency>,
56+
// Track if the original dependency path actually a symbolic link.
57+
// We need to know this to later assert if a package is local or not.
58+
sym_link: DependencySymLink,
4959
}
5060

5161
#[derive(Debug, Clone)]
@@ -254,7 +264,7 @@ pub fn read_dependency(
254264
parent_path: &Path,
255265
project_root: &Path,
256266
workspace_root: &Option<PathBuf>,
257-
) -> Result<PathBuf, String> {
267+
) -> Result<(PathBuf, DependencySymLink), String> {
258268
let path_from_parent = PathBuf::from(helpers::package_path(parent_path, package_name));
259269
let path_from_project_root = PathBuf::from(helpers::package_path(project_root, package_name));
260270
let maybe_path_from_workspace_root = workspace_root
@@ -277,6 +287,17 @@ pub fn read_dependency(
277287
)),
278288
}?;
279289

290+
// There could be a symbolic link because the package.json has:
291+
// "dependencies": {
292+
// "my-package": "link:my-package",
293+
// }
294+
// In this case, there will be a link from node_modules/my-package to a local path.
295+
let symlink = match fs::symlink_metadata(&path).map(|m| m.file_type().is_symlink()) {
296+
Err(_) => NoSymlink,
297+
Ok(false) => NoSymlink,
298+
Ok(true) => Symlink(path.clone()),
299+
};
300+
280301
let canonical_path = match path
281302
.canonicalize()
282303
.map(StrippedVerbatimPath::to_stripped_verbatim_path)
@@ -290,7 +311,7 @@ pub fn read_dependency(
290311
)),
291312
}?;
292313

293-
Ok(canonical_path)
314+
Ok((canonical_path, symlink))
294315
}
295316

296317
/// # Make Package
@@ -331,7 +352,7 @@ fn read_dependencies(
331352
// Read all config files in parallel instead of blocking
332353
.par_iter()
333354
.map(|package_name| {
334-
let (config, canonical_path) =
355+
let (config, canonical_path, sym_link) =
335356
match read_dependency(package_name, parent_path, project_root, &workspace_root) {
336357
Err(error) => {
337358
if show_progress {
@@ -350,9 +371,9 @@ fn read_dependencies(
350371

351372
std::process::exit(2)
352373
}
353-
Ok(canonical_path) => {
374+
Ok((canonical_path, sym_link)) => {
354375
match read_config(&canonical_path) {
355-
Ok(config) => (config, canonical_path),
376+
Ok(config) => (config, canonical_path, sym_link),
356377
Err(error) => {
357378
let parent_path_str = parent_path.to_string_lossy();
358379
log::error!(
@@ -386,6 +407,7 @@ fn read_dependencies(
386407
path: canonical_path,
387408
is_pinned,
388409
dependencies,
410+
sym_link
389411
}
390412
})
391413
.collect()
@@ -416,7 +438,13 @@ pub fn read_package_name(package_dir: &Path) -> Result<String> {
416438
.ok_or_else(|| anyhow!("No name field found in package.json"))
417439
}
418440

419-
fn make_package(config: config::Config, package_path: &Path, is_pinned_dep: bool, is_root: bool) -> Package {
441+
fn make_package(
442+
config: config::Config,
443+
package_path: &Path,
444+
is_pinned_dep: bool,
445+
is_root: bool,
446+
is_local_dep: bool,
447+
) -> Package {
420448
let source_folders = match config.sources.to_owned() {
421449
Some(config::OneOrMore::Single(source)) => get_source_dirs(source, None),
422450
Some(config::OneOrMore::Multiple(sources)) => {
@@ -469,7 +497,7 @@ This inconsistency will cause issues with package resolution.\n",
469497
.expect("Could not canonicalize"),
470498
dirs: None,
471499
is_pinned_dep,
472-
is_local_dep: !package_path.components().any(|c| c.as_os_str() == "node_modules"),
500+
is_local_dep,
473501
is_root,
474502
}
475503
}
@@ -484,7 +512,7 @@ fn read_packages(
484512

485513
// Store all packages and completely deduplicate them
486514
let mut map: AHashMap<String, Package> = AHashMap::new();
487-
let root_package = make_package(root_config.to_owned(), project_root, false, true);
515+
let root_package = make_package(root_config.to_owned(), project_root, false, true, true);
488516
map.insert(root_package.name.to_string(), root_package);
489517

490518
let mut registered_dependencies_set: AHashSet<String> = AHashSet::new();
@@ -499,7 +527,13 @@ fn read_packages(
499527
));
500528
dependencies.iter().for_each(|d| {
501529
if !map.contains_key(&d.name) {
502-
let package = make_package(d.config.to_owned(), &d.path, d.is_pinned, false);
530+
let is_local_dep = match &d.sym_link {
531+
NoSymlink => !d.path.components().any(|c| c.as_os_str() == "node_modules"),
532+
Symlink(original_path) => !original_path
533+
.components()
534+
.any(|c| c.as_os_str() == "node_modules"),
535+
};
536+
let package = make_package(d.config.to_owned(), &d.path, d.is_pinned, false, is_local_dep);
503537
map.insert(d.name.to_string(), package);
504538
}
505539
});

0 commit comments

Comments
 (0)