Skip to content

Commit 436f3d8

Browse files
authored
feat(cli): load Cargo configuration to check default build target (#4990)
1 parent fa44c44 commit 436f3d8

File tree

3 files changed

+143
-3
lines changed

3 files changed

+143
-3
lines changed

.changes/cargo-config-target.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"cli.rs": patch
3+
"cli.js": patch
4+
---
5+
6+
Check if the default build target is set in the Cargo configuration.

tooling/cli/src/interface/rust.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,10 @@ use crate::helpers::{
3535
config::{reload as reload_config, wix_settings, Config},
3636
};
3737

38+
mod cargo_config;
3839
mod desktop;
3940
mod manifest;
41+
use cargo_config::Config as CargoConfig;
4042
use manifest::{rewrite_manifest, Manifest};
4143

4244
#[derive(Debug, Clone)]
@@ -427,6 +429,7 @@ pub struct RustAppSettings {
427429
cargo_settings: CargoSettings,
428430
cargo_package_settings: CargoPackageSettings,
429431
package_settings: PackageSettings,
432+
cargo_config: CargoConfig,
430433
}
431434

432435
impl AppSettings for RustAppSettings {
@@ -614,11 +617,14 @@ impl RustAppSettings {
614617
default_run: cargo_package_settings.default_run.clone(),
615618
};
616619

620+
let cargo_config = CargoConfig::load(&tauri_dir())?;
621+
617622
Ok(Self {
618623
manifest,
619624
cargo_settings,
620625
cargo_package_settings,
621626
package_settings,
627+
cargo_config,
622628
})
623629
}
624630

@@ -627,7 +633,12 @@ impl RustAppSettings {
627633
}
628634

629635
pub fn out_dir(&self, target: Option<String>, debug: bool) -> crate::Result<PathBuf> {
630-
get_target_dir(target, !debug)
636+
get_target_dir(
637+
target
638+
.as_deref()
639+
.or_else(|| self.cargo_config.build().target()),
640+
!debug,
641+
)
631642
}
632643
}
633644

@@ -655,12 +666,12 @@ fn get_cargo_metadata() -> crate::Result<CargoMetadata> {
655666

656667
/// This function determines the 'target' directory and suffixes it with 'release' or 'debug'
657668
/// to determine where the compiled binary will be located.
658-
fn get_target_dir(target: Option<String>, is_release: bool) -> crate::Result<PathBuf> {
669+
fn get_target_dir(target: Option<&str>, is_release: bool) -> crate::Result<PathBuf> {
659670
let mut path = get_cargo_metadata()
660671
.with_context(|| "failed to get cargo metadata")?
661672
.target_directory;
662673

663-
if let Some(ref triple) = target {
674+
if let Some(triple) = target {
664675
path.push(triple);
665676
}
666677

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
use anyhow::{Context, Result};
2+
use serde::Deserialize;
3+
use std::{
4+
fs,
5+
path::{Path, PathBuf},
6+
};
7+
8+
struct PathAncestors<'a> {
9+
current: Option<&'a Path>,
10+
}
11+
12+
impl<'a> PathAncestors<'a> {
13+
fn new(path: &'a Path) -> PathAncestors<'a> {
14+
PathAncestors {
15+
current: Some(path),
16+
}
17+
}
18+
}
19+
20+
impl<'a> Iterator for PathAncestors<'a> {
21+
type Item = &'a Path;
22+
23+
fn next(&mut self) -> Option<&'a Path> {
24+
if let Some(path) = self.current {
25+
self.current = path.parent();
26+
27+
Some(path)
28+
} else {
29+
None
30+
}
31+
}
32+
}
33+
34+
#[derive(Default, Deserialize)]
35+
pub struct BuildConfig {
36+
target: Option<String>,
37+
}
38+
39+
#[derive(Deserialize)]
40+
pub struct ConfigSchema {
41+
build: Option<BuildConfig>,
42+
}
43+
44+
#[derive(Default)]
45+
pub struct Config {
46+
build: BuildConfig,
47+
}
48+
49+
impl Config {
50+
pub fn load(path: &Path) -> Result<Self> {
51+
let mut config = Self::default();
52+
53+
for current in PathAncestors::new(path) {
54+
if let Some(path) = get_file_path(&current.join(".cargo"), "config", true)? {
55+
let contents = fs::read_to_string(&path)
56+
.with_context(|| format!("failed to read configuration file `{}`", path.display()))?;
57+
let toml: ConfigSchema = toml::from_str(&contents)
58+
.with_context(|| format!("could not parse TOML configuration in `{}`", path.display()))?;
59+
60+
if let Some(target) = toml.build.and_then(|b| b.target) {
61+
config.build.target = Some(target);
62+
break;
63+
}
64+
}
65+
}
66+
67+
Ok(config)
68+
}
69+
70+
pub fn build(&self) -> &BuildConfig {
71+
&self.build
72+
}
73+
}
74+
75+
impl BuildConfig {
76+
pub fn target(&self) -> Option<&str> {
77+
self.target.as_deref()
78+
}
79+
}
80+
81+
/// The purpose of this function is to aid in the transition to using
82+
/// .toml extensions on Cargo's config files, which were historically not used.
83+
/// Both 'config.toml' and 'credentials.toml' should be valid with or without extension.
84+
/// When both exist, we want to prefer the one without an extension for
85+
/// backwards compatibility, but warn the user appropriately.
86+
fn get_file_path(
87+
dir: &Path,
88+
filename_without_extension: &str,
89+
warn: bool,
90+
) -> Result<Option<PathBuf>> {
91+
let possible = dir.join(filename_without_extension);
92+
let possible_with_extension = dir.join(format!("{}.toml", filename_without_extension));
93+
94+
if possible.exists() {
95+
if warn && possible_with_extension.exists() {
96+
// We don't want to print a warning if the version
97+
// without the extension is just a symlink to the version
98+
// WITH an extension, which people may want to do to
99+
// support multiple Cargo versions at once and not
100+
// get a warning.
101+
let skip_warning = if let Ok(target_path) = fs::read_link(&possible) {
102+
target_path == possible_with_extension
103+
} else {
104+
false
105+
};
106+
107+
if !skip_warning {
108+
log::warn!(
109+
"Both `{}` and `{}` exist. Using `{}`",
110+
possible.display(),
111+
possible_with_extension.display(),
112+
possible.display()
113+
);
114+
}
115+
}
116+
117+
Ok(Some(possible))
118+
} else if possible_with_extension.exists() {
119+
Ok(Some(possible_with_extension))
120+
} else {
121+
Ok(None)
122+
}
123+
}

0 commit comments

Comments
 (0)