Skip to content

Commit 82c7332

Browse files
committed
Implement support for base paths
1 parent dd94e9d commit 82c7332

File tree

4 files changed

+196
-4
lines changed

4 files changed

+196
-4
lines changed

src/cargo/core/features.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,7 @@ unstable_cli_options!(
751751
next_lockfile_bump: bool = (HIDDEN),
752752
no_index_update: bool = ("Do not update the registry index even if the cache is outdated"),
753753
panic_abort_tests: bool = ("Enable support to run tests with -Cpanic=abort"),
754+
path_bases: bool = ("Allow paths that resolve relatively to a base specified in the config"),
754755
profile_rustflags: bool = ("Enable the `rustflags` option in profiles in .cargo/config.toml file"),
755756
publish_timeout: bool = ("Enable the `publish.timeout` key in .cargo/config.toml file"),
756757
rustdoc_map: bool = ("Allow passing external documentation mappings to rustdoc"),
@@ -1094,6 +1095,7 @@ impl CliUnstable {
10941095
"mtime-on-use" => self.mtime_on_use = parse_empty(k, v)?,
10951096
"no-index-update" => self.no_index_update = parse_empty(k, v)?,
10961097
"panic-abort-tests" => self.panic_abort_tests = parse_empty(k, v)?,
1098+
"path-bases" => self.path_bases = parse_empty(k, v)?,
10971099
"profile-rustflags" => self.profile_rustflags = parse_empty(k, v)?,
10981100
"trim-paths" => self.trim_paths = parse_empty(k, v)?,
10991101
"publish-timeout" => self.publish_timeout = parse_empty(k, v)?,

src/cargo/util/toml/mod.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,7 @@ impl schema::TomlManifest {
344344
let mut d = d.clone();
345345
// Path dependencies become crates.io deps.
346346
d.path.take();
347+
d.base.take();
347348
// Same with git dependencies.
348349
d.git.take();
349350
d.branch.take();
@@ -1909,7 +1910,28 @@ impl<P: ResolveToPath + Clone> schema::TomlDetailedDependency<P> {
19091910
// always end up hashing to the same value no matter where it's
19101911
// built from.
19111912
if cx.source_id.is_path() {
1912-
let path = cx.root.join(path);
1913+
let path = if let Some(base) = self.base.as_ref() {
1914+
if !cx.config.cli_unstable().path_bases {
1915+
bail!("usage of path bases requires `-Z path-bases`");
1916+
}
1917+
1918+
// Look up the relevant base in the Config and use that as the root.
1919+
if let Some(base_path) = cx
1920+
.config
1921+
.get::<Option<ConfigRelativePath>>(&format!("base_path.{base}"))?
1922+
{
1923+
let base_path = base_path.resolve_path(cx.config);
1924+
base_path.join(path)
1925+
} else {
1926+
bail!(
1927+
"dependency ({name_in_toml}) uses an undefined base path `{base}`. \
1928+
You must add an entry for `{base}` in the Cargo configuration [base_path] table."
1929+
);
1930+
}
1931+
} else {
1932+
// This is a standard path with no prefix.
1933+
cx.root.join(path)
1934+
};
19131935
let path = paths::normalize_path(&path);
19141936
SourceId::for_path(&path)?
19151937
} else {

src/cargo/util/toml/schema.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,7 @@ pub struct TomlDetailedDependency<P: Clone = String> {
557557
// `path` is relative to the file it appears in. If that's a `Cargo.toml`, it'll be relative to
558558
// that TOML file, and if it's a `.cargo/config` file, it'll be relative to that file.
559559
pub path: Option<P>,
560+
pub base: Option<String>,
560561
pub git: Option<String>,
561562
pub branch: Option<String>,
562563
pub tag: Option<String>,
@@ -596,6 +597,7 @@ impl<P: Clone> Default for TomlDetailedDependency<P> {
596597
registry: Default::default(),
597598
registry_index: Default::default(),
598599
path: Default::default(),
600+
base: Default::default(),
599601
git: Default::default(),
600602
branch: Default::default(),
601603
tag: Default::default(),

tests/testsuite/path.rs

Lines changed: 169 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@ use cargo_test_support::{sleep_ms, t};
77
use std::fs;
88

99
#[cargo_test]
10-
// I have no idea why this is failing spuriously on Windows;
11-
// for more info, see #3466.
12-
#[cfg(not(windows))]
1310
fn cargo_compile_with_nested_deps_shorthand() {
1411
let p = project()
1512
.file(
@@ -529,6 +526,175 @@ Caused by:
529526
.run();
530527
}
531528

529+
#[cargo_test]
530+
fn path_bases_not_stable() {
531+
let bar = project()
532+
.at("bar")
533+
.file("Cargo.toml", &basic_manifest("bar", "0.5.0"))
534+
.file("src/lib.rs", "")
535+
.build();
536+
537+
fs::create_dir(&paths::root().join(".cargo")).unwrap();
538+
fs::write(
539+
&paths::root().join(".cargo/config"),
540+
&format!(
541+
"[base_path]\ntest = '{}'",
542+
bar.root().parent().unwrap().display()
543+
),
544+
)
545+
.unwrap();
546+
547+
let p = project()
548+
.file(
549+
"Cargo.toml",
550+
r#"
551+
[package]
552+
553+
name = "foo"
554+
version = "0.5.0"
555+
authors = ["[email protected]"]
556+
557+
[dependencies.bar]
558+
path = 'bar'
559+
base = 'test'
560+
"#,
561+
)
562+
.file("src/lib.rs", "")
563+
.build();
564+
565+
p.cargo("build")
566+
.with_status(101)
567+
.with_stderr(
568+
"\
569+
error: failed to parse manifest at `[..]/foo/Cargo.toml`
570+
571+
Caused by:
572+
usage of path bases requires `-Z path-bases`
573+
",
574+
)
575+
.run();
576+
}
577+
578+
#[cargo_test]
579+
fn patch_with_base() {
580+
let bar = project()
581+
.at("bar")
582+
.file("Cargo.toml", &basic_manifest("bar", "0.5.0"))
583+
.file("src/lib.rs", "pub fn hello() {}")
584+
.build();
585+
Package::new("bar", "0.5.0").publish();
586+
587+
fs::create_dir(&paths::root().join(".cargo")).unwrap();
588+
fs::write(
589+
&paths::root().join(".cargo/config"),
590+
&format!(
591+
"[base_path]\ntest = '{}'",
592+
bar.root().parent().unwrap().display()
593+
),
594+
)
595+
.unwrap();
596+
597+
let p = project()
598+
.file(
599+
"Cargo.toml",
600+
r#"
601+
[package]
602+
name = "foo"
603+
version = "0.5.0"
604+
authors = ["[email protected]"]
605+
edition = "2018"
606+
607+
[dependencies.bar]
608+
bar = "0.5.0"
609+
610+
[patch.crates-io.bar]
611+
path = 'bar'
612+
base = 'test'
613+
"#,
614+
)
615+
.file("src/lib.rs", "use bar::hello as _;")
616+
.build();
617+
618+
p.cargo("build -v -Zpath-bases")
619+
.masquerade_as_nightly_cargo(&["path-bases"])
620+
.run();
621+
}
622+
623+
#[cargo_test]
624+
fn path_with_base() {
625+
let bar = project()
626+
.at("bar")
627+
.file("Cargo.toml", &basic_manifest("bar", "0.5.0"))
628+
.file("src/lib.rs", "")
629+
.build();
630+
631+
fs::create_dir(&paths::root().join(".cargo")).unwrap();
632+
fs::write(
633+
&paths::root().join(".cargo/config"),
634+
&format!(
635+
"[base_path]\ntest = '{}'",
636+
bar.root().parent().unwrap().display()
637+
),
638+
)
639+
.unwrap();
640+
641+
let p = project()
642+
.file(
643+
"Cargo.toml",
644+
r#"
645+
[package]
646+
647+
name = "foo"
648+
version = "0.5.0"
649+
authors = ["[email protected]"]
650+
651+
[dependencies.bar]
652+
path = 'bar'
653+
base = 'test'
654+
"#,
655+
)
656+
.file("src/lib.rs", "")
657+
.build();
658+
659+
p.cargo("build -v -Zpath-bases")
660+
.masquerade_as_nightly_cargo(&["path-bases"])
661+
.run();
662+
}
663+
664+
#[cargo_test]
665+
fn unknown_base() {
666+
let p = project()
667+
.file(
668+
"Cargo.toml",
669+
r#"
670+
[package]
671+
672+
name = "foo"
673+
version = "0.5.0"
674+
authors = ["[email protected]"]
675+
676+
[dependencies.bar]
677+
path = 'bar'
678+
base = 'test'
679+
"#,
680+
)
681+
.file("src/lib.rs", "")
682+
.build();
683+
684+
p.cargo("build -Zpath-bases")
685+
.masquerade_as_nightly_cargo(&["path-bases"])
686+
.with_status(101)
687+
.with_stderr(
688+
"\
689+
error: failed to parse manifest at `[..]/foo/Cargo.toml`
690+
691+
Caused by:
692+
dependency (bar) uses an undefined base path `test`. You must add an entry for `test` in the Cargo configuration [base_path] table.
693+
",
694+
)
695+
.run();
696+
}
697+
532698
#[cargo_test]
533699
fn override_relative() {
534700
let bar = project()

0 commit comments

Comments
 (0)