Skip to content

Commit c39598a

Browse files
authored
Rollup merge of #76631 - jyn514:x.py-setup, r=Mark-Simulacrum
Add `x.py setup` Closes #76503. - Suggest `x.py setup` if config.toml doesn't exist yet - Prompt for a profile if not given on the command line - Print the configuration that will be used - Print helpful starting commands after setup - Link to the dev-guide after finishing
2 parents 1e62382 + 9baa601 commit c39598a

File tree

8 files changed

+152
-8
lines changed

8 files changed

+152
-8
lines changed

src/bootstrap/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
66

77
## [Non-breaking changes since the last major version]
88

9+
- Add `x.py setup` [#76631](https://github.com/rust-lang/rust/pull/76631)
910
- Add a changelog for x.py [#76626](https://github.com/rust-lang/rust/pull/76626)
1011
- Optionally, download LLVM from CI on Linux and NixOS
1112
+ [#76439](https://github.com/rust-lang/rust/pull/76349)

src/bootstrap/bin/main.rs

+16-3
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,34 @@
77
88
use std::env;
99

10-
use bootstrap::{Build, Config};
10+
use bootstrap::{Build, Config, Subcommand};
1111

1212
fn main() {
1313
let args = env::args().skip(1).collect::<Vec<_>>();
1414
let config = Config::parse(&args);
1515

1616
let changelog_suggestion = check_version(&config);
17-
if let Some(suggestion) = &changelog_suggestion {
17+
18+
// NOTE: Since `./configure` generates a `config.toml`, distro maintainers will see the
19+
// changelog warning, not the `x.py setup` message.
20+
let suggest_setup = !config.config.exists() && !matches!(config.cmd, Subcommand::Setup { .. });
21+
if suggest_setup {
22+
println!("warning: you have not made a `config.toml`");
23+
println!("help: consider running `x.py setup` or copying `config.toml.example`");
24+
} else if let Some(suggestion) = &changelog_suggestion {
1825
println!("{}", suggestion);
1926
}
2027

2128
Build::new(config).build();
2229

23-
if let Some(suggestion) = changelog_suggestion {
30+
if suggest_setup {
31+
println!("warning: you have not made a `config.toml`");
32+
println!("help: consider running `x.py setup` or copying `config.toml.example`");
33+
} else if let Some(suggestion) = &changelog_suggestion {
2434
println!("{}", suggestion);
35+
}
36+
37+
if suggest_setup || changelog_suggestion.is_some() {
2538
println!("note: this message was printed twice to make it more likely to be seen");
2639
}
2740
}

src/bootstrap/builder.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,9 @@ impl<'a> Builder<'a> {
549549
Subcommand::Dist { ref paths } => (Kind::Dist, &paths[..]),
550550
Subcommand::Install { ref paths } => (Kind::Install, &paths[..]),
551551
Subcommand::Run { ref paths } => (Kind::Run, &paths[..]),
552-
Subcommand::Format { .. } | Subcommand::Clean { .. } => panic!(),
552+
Subcommand::Format { .. } | Subcommand::Clean { .. } | Subcommand::Setup { .. } => {
553+
panic!()
554+
}
553555
};
554556

555557
Self::new_internal(build, kind, paths.to_owned())

src/bootstrap/config.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ pub struct Config {
7373
pub keep_stage: Vec<u32>,
7474
pub keep_stage_std: Vec<u32>,
7575
pub src: PathBuf,
76+
// defaults to `config.toml`
77+
pub config: PathBuf,
7678
pub jobs: Option<u32>,
7779
pub cmd: Subcommand,
7880
pub incremental: bool,
@@ -513,6 +515,7 @@ impl Config {
513515
config.rust_codegen_backends = vec![INTERNER.intern_str("llvm")];
514516
config.deny_warnings = true;
515517
config.missing_tools = false;
518+
config.config = PathBuf::from("config.toml");
516519

517520
// set by bootstrap.py
518521
config.build = TargetSelection::from_user(&env!("BUILD_TRIPLE"));
@@ -558,7 +561,7 @@ impl Config {
558561
let get_toml = |file: PathBuf| {
559562
use std::process;
560563

561-
let contents = t!(fs::read_to_string(&file), "configuration file did not exist");
564+
let contents = t!(fs::read_to_string(&file), "`include` config not found");
562565
match toml::from_str(&contents) {
563566
Ok(table) => table,
564567
Err(err) => {
@@ -644,6 +647,7 @@ impl Config {
644647
| Subcommand::Clippy { .. }
645648
| Subcommand::Fix { .. }
646649
| Subcommand::Run { .. }
650+
| Subcommand::Setup { .. }
647651
| Subcommand::Format { .. } => flags.stage.unwrap_or(0),
648652
};
649653

@@ -668,6 +672,7 @@ impl Config {
668672
| Subcommand::Clippy { .. }
669673
| Subcommand::Fix { .. }
670674
| Subcommand::Run { .. }
675+
| Subcommand::Setup { .. }
671676
| Subcommand::Format { .. } => {}
672677
}
673678
}

src/bootstrap/flags.rs

+31-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use std::env;
77
use std::path::PathBuf;
88
use std::process;
99

10+
use build_helper::t;
1011
use getopts::Options;
1112

1213
use crate::builder::Builder;
@@ -89,6 +90,9 @@ pub enum Subcommand {
8990
Run {
9091
paths: Vec<PathBuf>,
9192
},
93+
Setup {
94+
path: String,
95+
},
9296
}
9397

9498
impl Default for Subcommand {
@@ -199,6 +203,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`",
199203
|| (s == "install")
200204
|| (s == "run")
201205
|| (s == "r")
206+
|| (s == "setup")
202207
});
203208
let subcommand = match subcommand {
204209
Some(s) => s,
@@ -453,10 +458,21 @@ Arguments:
453458
At least a tool needs to be called.",
454459
);
455460
}
461+
"setup" => {
462+
subcommand_help.push_str(
463+
"\n
464+
Arguments:
465+
This subcommand accepts a 'profile' to use for builds. For example:
466+
467+
./x.py setup library
468+
469+
The profile is optional and you will be prompted interactively if it is not given.",
470+
);
471+
}
456472
_ => {}
457473
};
458474
// Get any optional paths which occur after the subcommand
459-
let paths = matches.free[1..].iter().map(|p| p.into()).collect::<Vec<PathBuf>>();
475+
let mut paths = matches.free[1..].iter().map(|p| p.into()).collect::<Vec<PathBuf>>();
460476

461477
let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from);
462478
let verbose = matches.opt_present("verbose");
@@ -508,6 +524,20 @@ Arguments:
508524
}
509525
Subcommand::Run { paths }
510526
}
527+
"setup" => {
528+
let path = if paths.len() > 1 {
529+
println!("\nat most one profile can be passed to setup\n");
530+
usage(1, &opts, verbose, &subcommand_help)
531+
} else if let Some(path) = paths.pop() {
532+
t!(path.into_os_string().into_string().map_err(|path| format!(
533+
"{} is not a valid UTF8 string",
534+
path.to_string_lossy()
535+
)))
536+
} else {
537+
t!(crate::setup::interactive_path())
538+
};
539+
Subcommand::Setup { path }
540+
}
511541
_ => {
512542
usage(1, &opts, verbose, &subcommand_help);
513543
}

src/bootstrap/lib.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ mod metadata;
141141
mod native;
142142
mod run;
143143
mod sanity;
144+
mod setup;
144145
mod test;
145146
mod tool;
146147
mod toolstate;
@@ -165,7 +166,7 @@ mod job {
165166

166167
use crate::cache::{Interned, INTERNER};
167168
pub use crate::config::Config;
168-
use crate::flags::Subcommand;
169+
pub use crate::flags::Subcommand;
169170

170171
const LLVM_TOOLS: &[&str] = &[
171172
"llvm-nm", // used to inspect binaries; it shows symbol names, their sizes and visibility
@@ -470,6 +471,10 @@ impl Build {
470471
return clean::clean(self, all);
471472
}
472473

474+
if let Subcommand::Setup { path: include_name } = &self.config.cmd {
475+
return setup::setup(&self.config.src, include_name);
476+
}
477+
473478
{
474479
let builder = builder::Builder::new(&self);
475480
if let Some(path) = builder.paths.get(0) {

src/bootstrap/run.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ impl Step for ExpandYamlAnchors {
1010

1111
/// Runs the `expand-yaml_anchors` tool.
1212
///
13-
/// This tool in `src/tools` read the CI configuration files written in YAML and expands the
13+
/// This tool in `src/tools` reads the CI configuration files written in YAML and expands the
1414
/// anchors in them, since GitHub Actions doesn't support them.
1515
fn run(self, builder: &Builder<'_>) {
1616
builder.info("Expanding YAML anchors in the GitHub Actions configuration");

src/bootstrap/setup.rs

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
use crate::t;
2+
use std::path::{Path, PathBuf};
3+
use std::{
4+
env, fs,
5+
io::{self, Write},
6+
};
7+
8+
pub fn setup(src_path: &Path, include_name: &str) {
9+
let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from);
10+
11+
if cfg_file.as_ref().map_or(false, |f| f.exists()) {
12+
let file = cfg_file.unwrap();
13+
println!(
14+
"error: you asked `x.py` to setup a new config file, but one already exists at `{}`",
15+
file.display()
16+
);
17+
println!(
18+
"help: try adding `profile = \"{}\"` at the top of {}",
19+
include_name,
20+
file.display()
21+
);
22+
println!(
23+
"note: this will use the configuration in {}/src/bootstrap/defaults/config.toml.{}",
24+
src_path.display(),
25+
include_name
26+
);
27+
std::process::exit(1);
28+
}
29+
30+
let path = cfg_file.unwrap_or_else(|| src_path.join("config.toml"));
31+
let settings = format!(
32+
"# Includes one of the default files in src/bootstrap/defaults\n\
33+
profile = \"{}\"\n",
34+
include_name
35+
);
36+
t!(fs::write(path, settings));
37+
38+
let include_path =
39+
format!("{}/src/bootstrap/defaults/config.toml.{}", src_path.display(), include_name);
40+
println!("`x.py` will now use the configuration at {}", include_path);
41+
42+
let suggestions = match include_name {
43+
"codegen" | "compiler" => &["check", "build", "test"][..],
44+
"library" => &["check", "build", "test library/std", "doc"],
45+
"user" => &["dist", "build"],
46+
_ => return,
47+
};
48+
49+
println!("To get started, try one of the following commands:");
50+
for cmd in suggestions {
51+
println!("- `x.py {}`", cmd);
52+
}
53+
54+
if include_name != "user" {
55+
println!(
56+
"For more suggestions, see https://rustc-dev-guide.rust-lang.org/building/suggested.html"
57+
);
58+
}
59+
}
60+
61+
// Used to get the path for `Subcommand::Setup`
62+
pub fn interactive_path() -> io::Result<String> {
63+
let mut input = String::new();
64+
println!(
65+
"Welcome to the Rust project! What do you want to do with x.py?
66+
a) Contribute to the standard library
67+
b) Contribute to the compiler
68+
c) Contribute to the compiler, and also modify LLVM or codegen
69+
d) Install Rust from source"
70+
);
71+
let template = loop {
72+
print!("Please choose one (a/b/c/d): ");
73+
io::stdout().flush()?;
74+
io::stdin().read_line(&mut input)?;
75+
break match input.trim().to_lowercase().as_str() {
76+
"a" | "lib" | "library" => "library",
77+
"b" | "compiler" => "compiler",
78+
"c" | "llvm" => "llvm",
79+
"d" | "user" | "maintainer" => "maintainer",
80+
_ => {
81+
println!("error: unrecognized option '{}'", input.trim());
82+
println!("note: press Ctrl+C to exit");
83+
continue;
84+
}
85+
};
86+
};
87+
Ok(template.to_owned())
88+
}

0 commit comments

Comments
 (0)