diff --git a/Cargo.toml b/Cargo.toml index 2c852c9..a4ed83b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,3 +17,6 @@ members = ["xtask"] [dependencies] once_cell = "1" dissimilar = "1" + +[dev-dependencies] +tempfile = "3" diff --git a/src/lib.rs b/src/lib.rs index 1e93a3b..69d5c1e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -644,17 +644,23 @@ fn to_abs_ws_path(path: &Path) -> PathBuf { static WORKSPACE_ROOT: OnceCell = OnceCell::new(); WORKSPACE_ROOT .get_or_try_init(|| { - let my_manifest = env::var("CARGO_MANIFEST_DIR")?; + let manifest_dir = env::var("CARGO_MANIFEST_DIR")?; // Heuristic, see https://github.com/rust-lang/cargo/issues/3946 - let workspace_root = Path::new(&my_manifest) + let workspace_root = Path::new(&manifest_dir) .ancestors() - .filter(|it| it.join("Cargo.toml").exists()) - .last() - .unwrap() - .to_path_buf(); - - Ok(workspace_root) + .filter(|it| match fs::read_to_string(it.join("Cargo.toml")) { + Ok(cargo_toml) => cargo_toml.lines().any(|line| line.trim() == "[workspace]"), + Err(_) => false, // no Cargo.toml + }) + .next(); + + // Check if we found a workspace or if we should use + // manifest_dir. + match workspace_root { + Some(workspace_root) => Ok(workspace_root.to_path_buf()), + None => Ok(PathBuf::from(manifest_dir)), + } }) .unwrap_or_else(|_: env::VarError| { panic!("No CARGO_MANIFEST_DIR env var and the path is relative: {}", path.display()) @@ -867,4 +873,27 @@ line1 "#\"#\"#", ]; } + + #[test] + fn test_nested_workspaces1() -> Result<(), std::io::Error> { + let dir = tempfile::tempdir()?; + + let outer = dir.path().join("Cargo.toml"); + let nested = dir.path().join("nested"); + let inner = nested.join("Cargo.toml"); + + std::fs::write(outer, r#"[package]\nname = "foo""#)?; + + std::fs::create_dir(&nested)?; + std::fs::write(&inner, r#"[package]\nname = "bar"\n[workspace]\n"#)?; + + let old_manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); + env::set_var("CARGO_MANIFEST_DIR", nested.as_os_str()); + let nested_bar = to_abs_ws_path(&Path::new("bar.txt")); + env::set_var("CARGO_MANIFEST_DIR", old_manifest_dir); + + assert_eq!(nested_bar, nested.join("bar.txt")); + + Ok(()) + } }