Skip to content

Commit

Permalink
Implement support for base paths
Browse files Browse the repository at this point in the history
  • Loading branch information
dpaoliello committed Jan 3, 2024
1 parent f9946d1 commit a0d901e
Show file tree
Hide file tree
Showing 4 changed files with 264 additions and 8 deletions.
2 changes: 2 additions & 0 deletions crates/cargo-util-schemas/src/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,7 @@ pub struct TomlDetailedDependency<P: Clone = String> {
// `path` is relative to the file it appears in. If that's a `Cargo.toml`, it'll be relative to
// that TOML file, and if it's a `.cargo/config` file, it'll be relative to that file.
pub path: Option<P>,
pub base: Option<String>,
pub git: Option<String>,
pub branch: Option<String>,
pub tag: Option<String>,
Expand Down Expand Up @@ -624,6 +625,7 @@ impl<P: Clone> Default for TomlDetailedDependency<P> {
registry: Default::default(),
registry_index: Default::default(),
path: Default::default(),
base: Default::default(),
git: Default::default(),
branch: Default::default(),
tag: Default::default(),
Expand Down
2 changes: 2 additions & 0 deletions src/cargo/core/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,7 @@ unstable_cli_options!(
next_lockfile_bump: bool = (HIDDEN),
no_index_update: bool = ("Do not update the registry index even if the cache is outdated"),
panic_abort_tests: bool = ("Enable support to run tests with -Cpanic=abort"),
path_bases: bool = ("Allow paths that resolve relatively to a base specified in the config"),
profile_rustflags: bool = ("Enable the `rustflags` option in profiles in .cargo/config.toml file"),
publish_timeout: bool = ("Enable the `publish.timeout` key in .cargo/config.toml file"),
rustdoc_map: bool = ("Allow passing external documentation mappings to rustdoc"),
Expand Down Expand Up @@ -1094,6 +1095,7 @@ impl CliUnstable {
"mtime-on-use" => self.mtime_on_use = parse_empty(k, v)?,
"no-index-update" => self.no_index_update = parse_empty(k, v)?,
"panic-abort-tests" => self.panic_abort_tests = parse_empty(k, v)?,
"path-bases" => self.path_bases = parse_empty(k, v)?,
"profile-rustflags" => self.profile_rustflags = parse_empty(k, v)?,
"trim-paths" => self.trim_paths = parse_empty(k, v)?,
"publish-timeout" => self.publish_timeout = parse_empty(k, v)?,
Expand Down
42 changes: 34 additions & 8 deletions src/cargo/util/toml/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ pub fn prepare_for_publish(
let mut d = d.clone();
// Path dependencies become crates.io deps.
d.path.take();
d.base.take();
// Same with git dependencies.
d.git.take();
d.branch.take();
Expand Down Expand Up @@ -1504,13 +1505,17 @@ impl InheritableFields {
};
let mut dep = dep.clone();
if let manifest::TomlDependency::Detailed(detailed) = &mut dep {
if let Some(rel_path) = &detailed.path {
detailed.path = Some(resolve_relative_path(
name,
self.ws_root(),
package_root,
rel_path,
)?);
if detailed.base.is_none() {
// If this is a path dependency without a base, then update the path to be relative
// to the workspace root instead.
if let Some(rel_path) = &detailed.path {
detailed.path = Some(resolve_relative_path(
name,
self.ws_root(),
package_root,
rel_path,
)?);
}
}
}
Ok(dep)
Expand Down Expand Up @@ -1877,7 +1882,28 @@ fn detailed_dep_to_dependency<P: ResolveToPath + Clone>(
// always end up hashing to the same value no matter where it's
// built from.
if cx.source_id.is_path() {
let path = cx.root.join(path);
let path = if let Some(base) = orig.base.as_ref() {
if !cx.config.cli_unstable().path_bases {
bail!("usage of path bases requires `-Z path-bases`");
}

// Look up the relevant base in the Config and use that as the root.
if let Some(base_path) = cx
.config
.get::<Option<ConfigRelativePath>>(&format!("base_path.{base}"))?
{
let base_path = base_path.resolve_path(cx.config);
base_path.join(path)
} else {
bail!(
"dependency ({name_in_toml}) uses an undefined base path `{base}`. \
You must add an entry for `{base}` in the Cargo configuration [base_path] table."
);
}
} else {
// This is a standard path with no prefix.
cx.root.join(path)
};
let path = paths::normalize_path(&path);
SourceId::for_path(&path)?
} else {
Expand Down
226 changes: 226 additions & 0 deletions tests/testsuite/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,232 @@ Caused by:
.run();
}

#[cargo_test]
fn path_bases_not_stable() {
let bar = project()
.at("bar")
.file("Cargo.toml", &basic_manifest("bar", "0.5.0"))
.file("src/lib.rs", "")
.build();

fs::create_dir(&paths::root().join(".cargo")).unwrap();
fs::write(
&paths::root().join(".cargo/config"),
&format!(
"[base_path]\ntest = '{}'",
bar.root().parent().unwrap().display()
),
)
.unwrap();

let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.5.0"
authors = ["[email protected]"]
[dependencies.bar]
path = 'bar'
base = 'test'
"#,
)
.file("src/lib.rs", "")
.build();

p.cargo("build")
.with_status(101)
.with_stderr(
"\
error: failed to parse manifest at `[..]/foo/Cargo.toml`
Caused by:
usage of path bases requires `-Z path-bases`
",
)
.run();
}

#[cargo_test]
fn patch_with_base() {
let bar = project()
.at("bar")
.file("Cargo.toml", &basic_manifest("bar", "0.5.0"))
.file("src/lib.rs", "pub fn hello() {}")
.build();
Package::new("bar", "0.5.0").publish();

fs::create_dir(&paths::root().join(".cargo")).unwrap();
fs::write(
&paths::root().join(".cargo/config"),
&format!(
"[base_path]\ntest = '{}'",
bar.root().parent().unwrap().display()
),
)
.unwrap();

let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.5.0"
authors = ["[email protected]"]
edition = "2018"
[dependencies.bar]
bar = "0.5.0"
[patch.crates-io.bar]
path = 'bar'
base = 'test'
"#,
)
.file("src/lib.rs", "use bar::hello as _;")
.build();

p.cargo("build -v -Zpath-bases")
.masquerade_as_nightly_cargo(&["path-bases"])
.run();
}

#[cargo_test]
fn path_with_base() {
let bar = project()
.at("bar")
.file("Cargo.toml", &basic_manifest("bar", "0.5.0"))
.file("src/lib.rs", "")
.build();

fs::create_dir(&paths::root().join(".cargo")).unwrap();
fs::write(
&paths::root().join(".cargo/config"),
&format!(
"[base_path]\ntest = '{}'",
bar.root().parent().unwrap().display()
),
)
.unwrap();

let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.5.0"
authors = ["[email protected]"]
[dependencies.bar]
path = 'bar'
base = 'test'
"#,
)
.file("src/lib.rs", "")
.build();

p.cargo("build -v -Zpath-bases")
.masquerade_as_nightly_cargo(&["path-bases"])
.run();
}

#[cargo_test]
fn workspace_with_base() {
let bar = project()
.at("dep_with_base")
.file("Cargo.toml", &basic_manifest("dep_with_base", "0.5.0"))
.file("src/lib.rs", "")
.build();

fs::create_dir(&paths::root().join(".cargo")).unwrap();
fs::write(
&paths::root().join(".cargo/config"),
&format!(
"[base_path]\ntest = '{}'",
bar.root().parent().unwrap().display()
),
)
.unwrap();

let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "parent"
version = "0.1.0"
authors = []
[workspace]
members = ["child"]
[workspace.dependencies.dep_with_base]
path = 'dep_with_base'
base = 'test'
"#,
)
.file("src/main.rs", "fn main() {}")
.file(
"child/Cargo.toml",
r#"
[package]
name = "child"
version = "0.1.0"
authors = []
workspace = ".."
[dependencies.dep_with_base]
workspace = true
"#,
)
.file("child/src/main.rs", "fn main() {}");
let p = p.build();

p.cargo("build -v -Zpath-bases")
.masquerade_as_nightly_cargo(&["path-bases"])
.run();
}

#[cargo_test]
fn unknown_base() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.5.0"
authors = ["[email protected]"]
[dependencies.bar]
path = 'bar'
base = 'test'
"#,
)
.file("src/lib.rs", "")
.build();

p.cargo("build -Zpath-bases")
.masquerade_as_nightly_cargo(&["path-bases"])
.with_status(101)
.with_stderr(
"\
error: failed to parse manifest at `[..]/foo/Cargo.toml`
Caused by:
dependency (bar) uses an undefined base path `test`. You must add an entry for `test` in the Cargo configuration [base_path] table.
",
)
.run();
}

#[cargo_test]
fn override_relative() {
let bar = project()
Expand Down

0 comments on commit a0d901e

Please sign in to comment.