Skip to content

Commit

Permalink
Check for [workspace] when finding workspace root
Browse files Browse the repository at this point in the history
Before, the top-most `Cargo.toml` file was used. Now we use the
nearest `Cargo.toml` file which contain a line saying `[workspace]`.

This should avoid false positives when Cargo workspaces are nested
inside each other: in this case, the inner package will have an empty
`[workspace]` table.
  • Loading branch information
mgeisler committed Apr 6, 2022
1 parent ec83506 commit 2d8af43
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 9 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,6 @@ members = ["xtask"]
[dependencies]
once_cell = "1"
dissimilar = "1"

[dev-dependencies]
tempfile = "3"
23 changes: 14 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -644,17 +644,22 @@ fn to_abs_ws_path(path: &Path) -> PathBuf {
static WORKSPACE_ROOT: OnceCell<PathBuf> = 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)
.ancestors()
.filter(|it| it.join("Cargo.toml").exists())
.last()
.unwrap()
.to_path_buf();

Ok(workspace_root)
let workspace_root = Path::new(&manifest_dir).ancestors().find(|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
}
});

// 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())
Expand Down
36 changes: 36 additions & 0 deletions tests/nested-workspaces.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Because this test modifies CARGO_MANIFEST_DIR, it has to be run as
// an integration test. This way we can isolate the modification to
// just one process.

use std::env;
use std::fs;
use std::path::Path;

use expect_test::ExpectFile;

#[test]
fn test_nested_workspaces() -> Result<(), std::io::Error> {
let tmpdir = tempfile::tempdir()?;
let outer_toml = tmpdir.path().join("Cargo.toml");
let nested = tmpdir.path().join("nested");
let nested_src = nested.join("src");
let inner_toml = nested.join("Cargo.toml");

fs::write(&outer_toml, r#"[package]\nname = "foo""#)?;

fs::create_dir(&nested)?;
fs::create_dir(&nested_src)?;
fs::write(&inner_toml, r#"[package]\nname = "bar"\n[workspace]\n"#)?;

// Fabricate a ExpectFile as if had been created with expect_file!
// inside the nested project.
env::set_var("CARGO_MANIFEST_DIR", nested.as_os_str());
let expect_file = ExpectFile { path: Path::new("bar.txt").to_owned(), position: "src/lib.rs" };
// Populate nested/src/bar.txt.
env::set_var("UPDATE_EXPECT", "1");
expect_file.assert_eq("Expected content");

assert_eq!(fs::read_to_string(nested_src.join("bar.txt"))?, "Expected content");

Ok(())
}

0 comments on commit 2d8af43

Please sign in to comment.