Skip to content

Commit ba4df9f

Browse files
committed
Implemented templating support for build.build-dir
1 parent d0a3ec7 commit ba4df9f

File tree

5 files changed

+70
-24
lines changed

5 files changed

+70
-24
lines changed

src/cargo/core/workspace.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,6 @@ impl<'gctx> Workspace<'gctx> {
213213
pub fn new(manifest_path: &Path, gctx: &'gctx GlobalContext) -> CargoResult<Workspace<'gctx>> {
214214
let mut ws = Workspace::new_default(manifest_path.to_path_buf(), gctx);
215215
ws.target_dir = gctx.target_dir()?;
216-
ws.build_dir = gctx.build_dir()?;
217216

218217
if manifest_path.is_relative() {
219218
bail!(
@@ -224,6 +223,12 @@ impl<'gctx> Workspace<'gctx> {
224223
ws.root_manifest = ws.find_root(manifest_path)?;
225224
}
226225

226+
ws.build_dir = gctx.build_dir(
227+
ws.root_manifest
228+
.as_ref()
229+
.unwrap_or(&manifest_path.to_path_buf()),
230+
)?;
231+
227232
ws.custom_metadata = ws
228233
.load_workspace_config()?
229234
.and_then(|cfg| cfg.custom_metadata);

src/cargo/util/context/mod.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -652,13 +652,36 @@ impl GlobalContext {
652652
/// Falls back to the target directory if not specified.
653653
///
654654
/// Callers should prefer [`Workspace::build_dir`] instead.
655-
pub fn build_dir(&self) -> CargoResult<Option<Filesystem>> {
655+
pub fn build_dir(&self, workspace_manifest_path: &PathBuf) -> CargoResult<Option<Filesystem>> {
656656
if !self.cli_unstable().build_dir {
657657
return self.target_dir();
658658
}
659659
if let Some(val) = &self.build_config()?.build_dir {
660-
let path = val.resolve_path(self);
661-
660+
let replacements = vec![
661+
(
662+
"{workspace-root}",
663+
workspace_manifest_path
664+
.parent()
665+
.unwrap()
666+
.to_str()
667+
.context("workspace root was not valid utf-8")?
668+
.to_string(),
669+
),
670+
(
671+
"{cargo-cache-home}",
672+
self.home()
673+
.as_path_unlocked()
674+
.to_str()
675+
.context("cargo home was not valid utf-8")?
676+
.to_string(),
677+
),
678+
("{workspace-manifest-path-hash}", {
679+
let hash = crate::util::hex::short_hash(&workspace_manifest_path);
680+
format!("{}{}{}", &hash[0..2], std::path::MAIN_SEPARATOR, &hash[2..])
681+
}),
682+
];
683+
684+
let path = val.resolve_templated_path(self, replacements);
662685
// Check if the target directory is set to an empty string in the config.toml file.
663686
if val.raw_value().is_empty() {
664687
bail!(

src/cargo/util/context/path.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,25 @@ impl ConfigRelativePath {
3232
self.0.definition.root(gctx).join(&self.0.val)
3333
}
3434

35+
/// Same as [`Self::resolve_path`] but will make string replacements
36+
/// before resolving the path.
37+
///
38+
/// `replacements` should be an an [`IntoIterator`] of tuples with the "from" and "to" for the
39+
/// string replacement
40+
pub fn resolve_templated_path(
41+
&self,
42+
gctx: &GlobalContext,
43+
replacements: impl IntoIterator<Item = (impl AsRef<str>, impl AsRef<str>)>,
44+
) -> PathBuf {
45+
let mut value = self.0.val.clone();
46+
47+
for (from, to) in replacements {
48+
value = value.replace(from.as_ref(), to.as_ref());
49+
}
50+
51+
self.0.definition.root(gctx).join(&value)
52+
}
53+
3554
/// Resolves this configuration-relative path to either an absolute path or
3655
/// something appropriate to execute from `PATH`.
3756
///

src/doc/src/reference/unstable.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,13 @@ build-dir = "out"
260260

261261
The path to where internal files used as part of the build are placed.
262262

263+
This option supports path templating.
264+
265+
Avaiable template variables:
266+
* `{workspace-root}` resolves to root of the current workspace.
267+
* `{cargo-cache-home}` resolves to `CARGO_HOME`
268+
* `{workspace-manifest-path-hash}` resolves to a hash of the manifest path
269+
263270

264271
## root-dir
265272
* Original Issue: [#9887](https://github.com/rust-lang/cargo/issues/9887)

tests/testsuite/build_dir.rs

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -493,20 +493,15 @@ fn future_incompat_should_output_to_build_dir() {
493493

494494
#[cargo_test]
495495
fn template_workspace_root() {
496-
let p = project();
497-
let root = p.root();
498-
let p = p
496+
let p = project()
499497
.file("src/main.rs", r#"fn main() { println!("Hello, World!") }"#)
500498
.file(
501499
".cargo/config.toml",
502-
&format!(
503-
r#"
504-
[build]
505-
build-dir = "{}/build-dir"
506-
target-dir = "target-dir"
507-
"#,
508-
root.display()
509-
),
500+
r#"
501+
[build]
502+
build-dir = "{workspace-root}/build-dir"
503+
target-dir = "target-dir"
504+
"#,
510505
)
511506
.build();
512507

@@ -528,14 +523,11 @@ fn template_cargo_cache_home() {
528523
.file("src/main.rs", r#"fn main() { println!("Hello, World!") }"#)
529524
.file(
530525
".cargo/config.toml",
531-
&format!(
532-
r#"
533-
[build]
534-
build-dir = "{}/build-dir"
535-
target-dir = "target-dir"
536-
"#,
537-
paths::home().join(".cargo").display()
538-
),
526+
r#"
527+
[build]
528+
build-dir = "{cargo-cache-home}/build-dir"
529+
target-dir = "target-dir"
530+
"#,
539531
)
540532
.build();
541533

@@ -569,7 +561,7 @@ fn template_workspace_manfiest_path_hash() {
569561
".cargo/config.toml",
570562
r#"
571563
[build]
572-
build-dir = "foo/a7/0a942ddb7da6b4/build-dir"
564+
build-dir = "foo/{workspace-manifest-path-hash}/build-dir"
573565
target-dir = "target-dir"
574566
"#,
575567
)

0 commit comments

Comments
 (0)