Skip to content

Commit 897f38e

Browse files
committed
Implement support for base paths
1 parent 479b7c4 commit 897f38e

File tree

9 files changed

+455
-25
lines changed

9 files changed

+455
-25
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ cargo-platform = { path = "crates/cargo-platform", version = "0.1.5" }
3333
cargo-test-macro = { version = "0.3.0", path = "crates/cargo-test-macro" }
3434
cargo-test-support = { version = "0.4.0", path = "crates/cargo-test-support" }
3535
cargo-util = { version = "0.2.14", path = "crates/cargo-util" }
36-
cargo-util-schemas = { version = "0.5.0", path = "crates/cargo-util-schemas" }
36+
cargo-util-schemas = { version = "0.6.0", path = "crates/cargo-util-schemas" }
3737
cargo_metadata = "0.18.1"
3838
clap = "4.5.11"
3939
color-print = "0.3.6"

crates/cargo-util-schemas/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "cargo-util-schemas"
3-
version = "0.5.1"
3+
version = "0.6.0"
44
rust-version = "1.80" # MSRV:1
55
edition.workspace = true
66
license.workspace = true

crates/cargo-util-schemas/src/manifest/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,7 @@ pub struct TomlDetailedDependency<P: Clone = String> {
767767
// `path` is relative to the file it appears in. If that's a `Cargo.toml`, it'll be relative to
768768
// that TOML file, and if it's a `.cargo/config` file, it'll be relative to that file.
769769
pub path: Option<P>,
770+
pub base: Option<String>,
770771
pub git: Option<String>,
771772
pub branch: Option<String>,
772773
pub tag: Option<String>,
@@ -806,6 +807,7 @@ impl<P: Clone> Default for TomlDetailedDependency<P> {
806807
registry: Default::default(),
807808
registry_index: Default::default(),
808809
path: Default::default(),
810+
base: Default::default(),
809811
git: Default::default(),
810812
branch: Default::default(),
811813
tag: Default::default(),

src/cargo/core/features.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,7 @@ unstable_cli_options!(
776776
no_index_update: bool = ("Do not update the registry index even if the cache is outdated"),
777777
package_workspace: bool = ("Handle intra-workspace dependencies when packaging"),
778778
panic_abort_tests: bool = ("Enable support to run tests with -Cpanic=abort"),
779+
path_bases: bool = ("Allow paths that resolve relatively to a base specified in the config"),
779780
profile_rustflags: bool = ("Enable the `rustflags` option in profiles in .cargo/config.toml file"),
780781
public_dependency: bool = ("Respect a dependency's `public` field in Cargo.toml to control public/private dependencies"),
781782
publish_timeout: bool = ("Enable the `publish.timeout` key in .cargo/config.toml file"),
@@ -1280,6 +1281,7 @@ impl CliUnstable {
12801281
"package-workspace" => self.package_workspace= parse_empty(k, v)?,
12811282
"panic-abort-tests" => self.panic_abort_tests = parse_empty(k, v)?,
12821283
"public-dependency" => self.public_dependency = parse_empty(k, v)?,
1284+
"path-bases" => self.path_bases = parse_empty(k, v)?,
12831285
"profile-rustflags" => self.profile_rustflags = parse_empty(k, v)?,
12841286
"trim-paths" => self.trim_paths = parse_empty(k, v)?,
12851287
"publish-timeout" => self.publish_timeout = parse_empty(k, v)?,

src/cargo/sources/path.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -910,6 +910,11 @@ fn nested_paths(manifest: &Manifest) -> Vec<PathBuf> {
910910
let Some(path) = dep.path.as_ref() else {
911911
continue;
912912
};
913+
if dep.base.is_some() {
914+
// Skip dependencies with base paths, if they are part of the directory tree then
915+
// the outer walk will find them.
916+
continue;
917+
}
913918
nested_paths.push(PathBuf::from(path.as_str()));
914919
}
915920
}

src/cargo/util/toml/mod.rs

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -901,13 +901,17 @@ impl InheritableFields {
901901
};
902902
let mut dep = dep.clone();
903903
if let manifest::TomlDependency::Detailed(detailed) = &mut dep {
904-
if let Some(rel_path) = &detailed.path {
905-
detailed.path = Some(resolve_relative_path(
906-
name,
907-
self.ws_root(),
908-
package_root,
909-
rel_path,
910-
)?);
904+
if detailed.base.is_none() {
905+
// If this is a path dependency without a base, then update the path to be relative
906+
// to the workspace root instead.
907+
if let Some(rel_path) = &detailed.path {
908+
detailed.path = Some(resolve_relative_path(
909+
name,
910+
self.ws_root(),
911+
package_root,
912+
rel_path,
913+
)?);
914+
}
911915
}
912916
}
913917
Ok(dep)
@@ -2129,7 +2133,40 @@ fn to_dependency_source_id<P: ResolveToPath + Clone>(
21292133
// always end up hashing to the same value no matter where it's
21302134
// built from.
21312135
if manifest_ctx.source_id.is_path() {
2132-
let path = manifest_ctx.root.join(path);
2136+
let path = if let Some(base) = orig.base.as_ref() {
2137+
if !manifest_ctx.gctx.cli_unstable().path_bases {
2138+
bail!("usage of path bases requires `-Z path-bases`");
2139+
}
2140+
2141+
// Look up the relevant base in the Config and use that as the root.
2142+
if let Some(path_bases) = manifest_ctx
2143+
.gctx
2144+
.get::<Option<ConfigRelativePath>>(&format!("path-bases.{base}"))?
2145+
{
2146+
let path_base = path_bases.resolve_path(manifest_ctx.gctx);
2147+
path_base.join(path)
2148+
} else {
2149+
// Otherwise, check the build-in bases.
2150+
match base.as_str() {
2151+
"workspace" => {
2152+
if let Some(workspace_root) = find_workspace_root(manifest_ctx.root, manifest_ctx.gctx)? {
2153+
workspace_root.parent().unwrap().join(path)
2154+
} else {
2155+
bail!(
2156+
"dependency ({name_in_toml}) is using the `workspace` built-in path base outside of a workspace."
2157+
)
2158+
}
2159+
},
2160+
_ => bail!(
2161+
"dependency ({name_in_toml}) uses an undefined path base `{base}`. \
2162+
You must add an entry for `{base}` in the Cargo configuration [path-bases] table."
2163+
)
2164+
}
2165+
}
2166+
} else {
2167+
// This is a standard path with no prefix.
2168+
manifest_ctx.root.join(path)
2169+
};
21332170
let path = paths::normalize_path(&path);
21342171
SourceId::for_path(&path)
21352172
} else {
@@ -2855,6 +2892,7 @@ fn prepare_toml_for_publish(
28552892
let mut d = d.clone();
28562893
// Path dependencies become crates.io deps.
28572894
d.path.take();
2895+
d.base.take();
28582896
// Same with git dependencies.
28592897
d.git.take();
28602898
d.branch.take();

tests/testsuite/cargo/z_help/stdout.term.svg

Lines changed: 16 additions & 14 deletions
Loading

0 commit comments

Comments
 (0)