Skip to content

Commit 5d105b1

Browse files
committed
apply nit notes
Signed-off-by: onur-ozkan <[email protected]>
1 parent ad2e4a4 commit 5d105b1

File tree

2 files changed

+66
-25
lines changed

2 files changed

+66
-25
lines changed

bootstrap.example.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
# Inherits configuration values from different configuration files (a.k.a. config extensions).
2323
# Supports absolute paths, and uses the current directory (where the bootstrap was invoked)
2424
# as the base if the given path is not absolute.
25+
#
26+
# The overriding logic follows a right-to-left order. For example, in `include = ["a.toml", "b.toml"]`,
27+
# extension `b.toml` overrides `a.toml`. Also, parent extensions always overrides the inner ones.
2528
#include = []
2629

2730
# Keeps track of major changes made to this configuration.

src/bootstrap/src/core/config/config.rs

Lines changed: 63 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,7 @@ enum ReplaceOpt {
748748
trait Merge {
749749
fn merge(
750750
&mut self,
751+
parent_config_path: Option<PathBuf>,
751752
included_extensions: &mut HashSet<PathBuf>,
752753
other: Self,
753754
replace: ReplaceOpt,
@@ -757,26 +758,31 @@ trait Merge {
757758
impl Merge for TomlConfig {
758759
fn merge(
759760
&mut self,
761+
parent_config_path: Option<PathBuf>,
760762
included_extensions: &mut HashSet<PathBuf>,
761763
TomlConfig { build, install, llvm, gcc, rust, dist, target, profile, change_id, include }: Self,
762764
replace: ReplaceOpt,
763765
) {
764766
fn do_merge<T: Merge>(x: &mut Option<T>, y: Option<T>, replace: ReplaceOpt) {
765767
if let Some(new) = y {
766768
if let Some(original) = x {
767-
original.merge(&mut Default::default(), new, replace);
769+
original.merge(None, &mut Default::default(), new, replace);
768770
} else {
769771
*x = Some(new);
770772
}
771773
}
772774
}
773775

774-
for include_path in include.clone().unwrap_or_default() {
776+
let parent_dir = parent_config_path
777+
.as_ref()
778+
.and_then(|p| p.parent().map(ToOwned::to_owned))
779+
.unwrap_or_default();
780+
781+
for include_path in include.clone().unwrap_or_default().iter().rev() {
782+
let include_path = parent_dir.join(include_path).canonicalize().unwrap();
783+
775784
let included_toml = Config::get_toml(&include_path).unwrap_or_else(|e| {
776-
eprintln!(
777-
"ERROR: Failed to parse default config profile at '{}': {e}",
778-
include_path.display()
779-
);
785+
eprintln!("ERROR: Failed to parse '{}': {e}", include_path.display());
780786
exit!(2);
781787
});
782788

@@ -786,13 +792,20 @@ impl Merge for TomlConfig {
786792
include_path.display()
787793
);
788794

789-
self.merge(included_extensions, included_toml, ReplaceOpt::Override);
795+
self.merge(
796+
Some(include_path.clone()),
797+
included_extensions,
798+
included_toml,
799+
// Ensures that parent configuration always takes precedence
800+
// over child configurations.
801+
ReplaceOpt::IgnoreDuplicate,
802+
);
790803

791804
included_extensions.remove(&include_path);
792805
}
793806

794-
self.change_id.inner.merge(&mut Default::default(), change_id.inner, replace);
795-
self.profile.merge(&mut Default::default(), profile, replace);
807+
self.change_id.inner.merge(None, &mut Default::default(), change_id.inner, replace);
808+
self.profile.merge(None, &mut Default::default(), profile, replace);
796809

797810
do_merge(&mut self.build, build, replace);
798811
do_merge(&mut self.install, install, replace);
@@ -807,7 +820,7 @@ impl Merge for TomlConfig {
807820
(Some(original_target), Some(new_target)) => {
808821
for (triple, new) in new_target {
809822
if let Some(original) = original_target.get_mut(&triple) {
810-
original.merge(&mut Default::default(), new, replace);
823+
original.merge(None, &mut Default::default(), new, replace);
811824
} else {
812825
original_target.insert(triple, new);
813826
}
@@ -828,7 +841,13 @@ macro_rules! define_config {
828841
}
829842

830843
impl Merge for $name {
831-
fn merge(&mut self, _included_extensions: &mut HashSet<PathBuf>, other: Self, replace: ReplaceOpt) {
844+
fn merge(
845+
&mut self,
846+
_parent_config_path: Option<PathBuf>,
847+
_included_extensions: &mut HashSet<PathBuf>,
848+
other: Self,
849+
replace: ReplaceOpt
850+
) {
832851
$(
833852
match replace {
834853
ReplaceOpt::IgnoreDuplicate => {
@@ -930,6 +949,7 @@ macro_rules! define_config {
930949
impl<T> Merge for Option<T> {
931950
fn merge(
932951
&mut self,
952+
_parent_config_path: Option<PathBuf>,
933953
_included_extensions: &mut HashSet<PathBuf>,
934954
other: Self,
935955
replace: ReplaceOpt,
@@ -1608,6 +1628,24 @@ impl Config {
16081628
toml.profile = Some("dist".into());
16091629
}
16101630

1631+
// Reverse the list to ensure the last added config extension remains the most dominant.
1632+
// For example, given ["a.toml", "b.toml"], "b.toml" should take precedence over "a.toml".
1633+
//
1634+
// This must be handled before applying the `profile` since `include`s should always take
1635+
// precedence over `profile`s.
1636+
for include_path in toml.include.clone().unwrap_or_default().iter().rev() {
1637+
let included_toml = get_toml(include_path).unwrap_or_else(|e| {
1638+
eprintln!("ERROR: Failed to parse '{}': {e}", include_path.display());
1639+
exit!(2);
1640+
});
1641+
toml.merge(
1642+
Some(t!(include_path.canonicalize())),
1643+
&mut Default::default(),
1644+
included_toml,
1645+
ReplaceOpt::IgnoreDuplicate,
1646+
);
1647+
}
1648+
16111649
if let Some(include) = &toml.profile {
16121650
// Allows creating alias for profile names, allowing
16131651
// profiles to be renamed while maintaining back compatibility
@@ -1629,18 +1667,12 @@ impl Config {
16291667
);
16301668
exit!(2);
16311669
});
1632-
toml.merge(&mut Default::default(), included_toml, ReplaceOpt::IgnoreDuplicate);
1633-
}
1634-
1635-
for include_path in toml.include.clone().unwrap_or_default() {
1636-
let included_toml = get_toml(&include_path).unwrap_or_else(|e| {
1637-
eprintln!(
1638-
"ERROR: Failed to parse default config profile at '{}': {e}",
1639-
include_path.display()
1640-
);
1641-
exit!(2);
1642-
});
1643-
toml.merge(&mut Default::default(), included_toml, ReplaceOpt::Override);
1670+
toml.merge(
1671+
Some(t!(include_path.canonicalize())),
1672+
&mut Default::default(),
1673+
included_toml,
1674+
ReplaceOpt::IgnoreDuplicate,
1675+
);
16441676
}
16451677

16461678
let mut override_toml = TomlConfig::default();
@@ -1651,7 +1683,12 @@ impl Config {
16511683

16521684
let mut err = match get_table(option) {
16531685
Ok(v) => {
1654-
override_toml.merge(&mut Default::default(), v, ReplaceOpt::ErrorOnDuplicate);
1686+
override_toml.merge(
1687+
None,
1688+
&mut Default::default(),
1689+
v,
1690+
ReplaceOpt::ErrorOnDuplicate,
1691+
);
16551692
continue;
16561693
}
16571694
Err(e) => e,
@@ -1663,6 +1700,7 @@ impl Config {
16631700
match get_table(&format!(r#"{key}="{value}""#)) {
16641701
Ok(v) => {
16651702
override_toml.merge(
1703+
None,
16661704
&mut Default::default(),
16671705
v,
16681706
ReplaceOpt::ErrorOnDuplicate,
@@ -1676,7 +1714,7 @@ impl Config {
16761714
eprintln!("failed to parse override `{option}`: `{err}");
16771715
exit!(2)
16781716
}
1679-
toml.merge(&mut Default::default(), override_toml, ReplaceOpt::Override);
1717+
toml.merge(None, &mut Default::default(), override_toml, ReplaceOpt::Override);
16801718

16811719
config.change_id = toml.change_id.inner;
16821720

0 commit comments

Comments
 (0)