Skip to content

Commit 82756fd

Browse files
committed
Extract TOML config loading and src directory computation into separate functions
1 parent ae05591 commit 82756fd

File tree

1 file changed

+117
-89
lines changed

1 file changed

+117
-89
lines changed

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

Lines changed: 117 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -453,11 +453,21 @@ impl Config {
453453
skip_std_check_if_no_download_rustc: flags_skip_std_check_if_no_download_rustc,
454454
} = flags;
455455

456+
// First initialize the bare minimum that we need for further operation - source directory
457+
// and execution context.
456458
let mut config = Config::default_opts();
457459
let exec_ctx = ExecutionContext::new(flags_verbose, flags_cmd.fail_fast());
458460

459461
config.exec_ctx = exec_ctx;
460462

463+
if let Some(src) = compute_src_directory(flags_src, &config.exec_ctx) {
464+
config.src = src;
465+
}
466+
467+
// Now load the TOML config, as soon as possible
468+
let (mut toml, toml_path) = load_toml_config(&config.src, flags_config, &get_toml);
469+
config.config = toml_path.clone();
470+
461471
// Set flags.
462472
config.paths = std::mem::take(&mut flags_paths);
463473

@@ -501,53 +511,6 @@ impl Config {
501511

502512
// Infer the rest of the configuration.
503513

504-
if let Some(src) = flags_src {
505-
config.src = src
506-
} else {
507-
// Infer the source directory. This is non-trivial because we want to support a downloaded bootstrap binary,
508-
// running on a completely different machine from where it was compiled.
509-
let mut cmd = helpers::git(None);
510-
// NOTE: we cannot support running from outside the repository because the only other path we have available
511-
// is set at compile time, which can be wrong if bootstrap was downloaded rather than compiled locally.
512-
// We still support running outside the repository if we find we aren't in a git directory.
513-
514-
// NOTE: We get a relative path from git to work around an issue on MSYS/mingw. If we used an absolute path,
515-
// and end up using MSYS's git rather than git-for-windows, we would get a unix-y MSYS path. But as bootstrap
516-
// has already been (kinda-cross-)compiled to Windows land, we require a normal Windows path.
517-
cmd.arg("rev-parse").arg("--show-cdup");
518-
// Discard stderr because we expect this to fail when building from a tarball.
519-
let output = cmd.allow_failure().run_capture_stdout(&config);
520-
if output.is_success() {
521-
let git_root_relative = output.stdout();
522-
// We need to canonicalize this path to make sure it uses backslashes instead of forward slashes,
523-
// and to resolve any relative components.
524-
let git_root = env::current_dir()
525-
.unwrap()
526-
.join(PathBuf::from(git_root_relative.trim()))
527-
.canonicalize()
528-
.unwrap();
529-
let s = git_root.to_str().unwrap();
530-
531-
// Bootstrap is quite bad at handling /? in front of paths
532-
let git_root = match s.strip_prefix("\\\\?\\") {
533-
Some(p) => PathBuf::from(p),
534-
None => git_root,
535-
};
536-
// If this doesn't have at least `stage0`, we guessed wrong. This can happen when,
537-
// for example, the build directory is inside of another unrelated git directory.
538-
// In that case keep the original `CARGO_MANIFEST_DIR` handling.
539-
//
540-
// NOTE: this implies that downloadable bootstrap isn't supported when the build directory is outside
541-
// the source directory. We could fix that by setting a variable from all three of python, ./x, and x.ps1.
542-
if git_root.join("src").join("stage0").exists() {
543-
config.src = git_root;
544-
}
545-
} else {
546-
// We're building from a tarball, not git sources.
547-
// We don't support pre-downloaded bootstrap in this case.
548-
}
549-
}
550-
551514
if cfg!(test) {
552515
// Use the build directory of the original x.py invocation, so that we can set `initial_rustc` properly.
553516
config.out = Path::new(
@@ -560,47 +523,6 @@ impl Config {
560523

561524
config.stage0_metadata = build_helper::stage0_parser::parse_stage0_file();
562525

563-
// Locate the configuration file using the following priority (first match wins):
564-
// 1. `--config <path>` (explicit flag)
565-
// 2. `RUST_BOOTSTRAP_CONFIG` environment variable
566-
// 3. `./bootstrap.toml` (local file)
567-
// 4. `<root>/bootstrap.toml`
568-
// 5. `./config.toml` (fallback for backward compatibility)
569-
// 6. `<root>/config.toml`
570-
let toml_path = flags_config
571-
.clone()
572-
.or_else(|| env::var_os("RUST_BOOTSTRAP_CONFIG").map(PathBuf::from));
573-
let using_default_path = toml_path.is_none();
574-
let mut toml_path = toml_path.unwrap_or_else(|| PathBuf::from("bootstrap.toml"));
575-
576-
if using_default_path && !toml_path.exists() {
577-
toml_path = config.src.join(PathBuf::from("bootstrap.toml"));
578-
if !toml_path.exists() {
579-
toml_path = PathBuf::from("config.toml");
580-
if !toml_path.exists() {
581-
toml_path = config.src.join(PathBuf::from("config.toml"));
582-
}
583-
}
584-
}
585-
586-
// Give a hard error if `--config` or `RUST_BOOTSTRAP_CONFIG` are set to a missing path,
587-
// but not if `bootstrap.toml` hasn't been created.
588-
let mut toml = if !using_default_path || toml_path.exists() {
589-
config.config = Some(if cfg!(not(test)) {
590-
toml_path = toml_path.canonicalize().unwrap();
591-
toml_path.clone()
592-
} else {
593-
toml_path.clone()
594-
});
595-
get_toml(&toml_path).unwrap_or_else(|e| {
596-
eprintln!("ERROR: Failed to parse '{}': {e}", toml_path.display());
597-
exit!(2);
598-
})
599-
} else {
600-
config.config = None;
601-
TomlConfig::default()
602-
};
603-
604526
if cfg!(test) {
605527
// When configuring bootstrap for tests, make sure to set the rustc and Cargo to the
606528
// same ones used to call the tests (if custom ones are not defined in the toml). If we
@@ -622,7 +544,12 @@ impl Config {
622544
// This must be handled before applying the `profile` since `include`s should always take
623545
// precedence over `profile`s.
624546
for include_path in toml.include.clone().unwrap_or_default().iter().rev() {
625-
let include_path = toml_path.parent().unwrap().join(include_path);
547+
let include_path = toml_path
548+
.as_ref()
549+
.expect("include found in default TOML config")
550+
.parent()
551+
.unwrap()
552+
.join(include_path);
626553

627554
let included_toml = get_toml(&include_path).unwrap_or_else(|e| {
628555
eprintln!("ERROR: Failed to parse '{}': {e}", include_path.display());
@@ -2309,3 +2236,104 @@ impl AsRef<ExecutionContext> for Config {
23092236
&self.exec_ctx
23102237
}
23112238
}
2239+
2240+
fn compute_src_directory(src_dir: Option<PathBuf>, exec_ctx: &ExecutionContext) -> Option<PathBuf> {
2241+
if let Some(src) = src_dir {
2242+
return Some(src);
2243+
} else {
2244+
// Infer the source directory. This is non-trivial because we want to support a downloaded bootstrap binary,
2245+
// running on a completely different machine from where it was compiled.
2246+
let mut cmd = helpers::git(None);
2247+
// NOTE: we cannot support running from outside the repository because the only other path we have available
2248+
// is set at compile time, which can be wrong if bootstrap was downloaded rather than compiled locally.
2249+
// We still support running outside the repository if we find we aren't in a git directory.
2250+
2251+
// NOTE: We get a relative path from git to work around an issue on MSYS/mingw. If we used an absolute path,
2252+
// and end up using MSYS's git rather than git-for-windows, we would get a unix-y MSYS path. But as bootstrap
2253+
// has already been (kinda-cross-)compiled to Windows land, we require a normal Windows path.
2254+
cmd.arg("rev-parse").arg("--show-cdup");
2255+
// Discard stderr because we expect this to fail when building from a tarball.
2256+
let output = cmd.allow_failure().run_capture_stdout(exec_ctx);
2257+
if output.is_success() {
2258+
let git_root_relative = output.stdout();
2259+
// We need to canonicalize this path to make sure it uses backslashes instead of forward slashes,
2260+
// and to resolve any relative components.
2261+
let git_root = env::current_dir()
2262+
.unwrap()
2263+
.join(PathBuf::from(git_root_relative.trim()))
2264+
.canonicalize()
2265+
.unwrap();
2266+
let s = git_root.to_str().unwrap();
2267+
2268+
// Bootstrap is quite bad at handling /? in front of paths
2269+
let git_root = match s.strip_prefix("\\\\?\\") {
2270+
Some(p) => PathBuf::from(p),
2271+
None => git_root,
2272+
};
2273+
// If this doesn't have at least `stage0`, we guessed wrong. This can happen when,
2274+
// for example, the build directory is inside of another unrelated git directory.
2275+
// In that case keep the original `CARGO_MANIFEST_DIR` handling.
2276+
//
2277+
// NOTE: this implies that downloadable bootstrap isn't supported when the build directory is outside
2278+
// the source directory. We could fix that by setting a variable from all three of python, ./x, and x.ps1.
2279+
if git_root.join("src").join("stage0").exists() {
2280+
return Some(git_root);
2281+
}
2282+
} else {
2283+
// We're building from a tarball, not git sources.
2284+
// We don't support pre-downloaded bootstrap in this case.
2285+
}
2286+
};
2287+
None
2288+
}
2289+
2290+
/// Loads bootstrap TOML config and returns the config together with a path from where
2291+
/// it was loaded.
2292+
/// `src` is the source root directory, and `config_path` is an optionally provided path to the
2293+
/// config.
2294+
fn load_toml_config(
2295+
src: &Path,
2296+
config_path: Option<PathBuf>,
2297+
get_toml: &impl Fn(&Path) -> Result<TomlConfig, toml::de::Error>,
2298+
) -> (TomlConfig, Option<PathBuf>) {
2299+
// Locate the configuration file using the following priority (first match wins):
2300+
// 1. `--config <path>` (explicit flag)
2301+
// 2. `RUST_BOOTSTRAP_CONFIG` environment variable
2302+
// 3. `./bootstrap.toml` (local file)
2303+
// 4. `<root>/bootstrap.toml`
2304+
// 5. `./config.toml` (fallback for backward compatibility)
2305+
// 6. `<root>/config.toml`
2306+
let toml_path = config_path.or_else(|| env::var_os("RUST_BOOTSTRAP_CONFIG").map(PathBuf::from));
2307+
let using_default_path = toml_path.is_none();
2308+
let mut toml_path = toml_path.unwrap_or_else(|| PathBuf::from("bootstrap.toml"));
2309+
2310+
if using_default_path && !toml_path.exists() {
2311+
toml_path = src.join(PathBuf::from("bootstrap.toml"));
2312+
if !toml_path.exists() {
2313+
toml_path = PathBuf::from("config.toml");
2314+
if !toml_path.exists() {
2315+
toml_path = src.join(PathBuf::from("config.toml"));
2316+
}
2317+
}
2318+
}
2319+
2320+
// Give a hard error if `--config` or `RUST_BOOTSTRAP_CONFIG` are set to a missing path,
2321+
// but not if `bootstrap.toml` hasn't been created.
2322+
if !using_default_path || toml_path.exists() {
2323+
let path = Some(if cfg!(not(test)) {
2324+
toml_path = toml_path.canonicalize().unwrap();
2325+
toml_path.clone()
2326+
} else {
2327+
toml_path.clone()
2328+
});
2329+
(
2330+
get_toml(&toml_path).unwrap_or_else(|e| {
2331+
eprintln!("ERROR: Failed to parse '{}': {e}", toml_path.display());
2332+
exit!(2);
2333+
}),
2334+
path,
2335+
)
2336+
} else {
2337+
(TomlConfig::default(), None)
2338+
}
2339+
}

0 commit comments

Comments
 (0)