Skip to content

Commit 59707c5

Browse files
authored
Rollup merge of #77400 - alarsyo:xpy-setup-suggestions, r=jyn514
Fix suggestions for x.py setup #76631 introduced a new `setup` command to x.py By default the command prompts for a profile to use: ``` Welcome to the Rust project! What do you want to do with x.py? a) Contribute to the standard library b) Contribute to the compiler c) Contribute to the compiler, and also modify LLVM or codegen d) Install Rust from source ``` and then displays command suggestions, depending on which profile was chosen. However [the mapping between chosen profile](https://github.com/rust-lang/rust/blob/9cba260df0f1c67ea3690035cd5611a7465a1560/src/bootstrap/setup.rs#L75-L85) and [suggestion](https://github.com/rust-lang/rust/blob/9cba260df0f1c67ea3690035cd5611a7465a1560/src/bootstrap/setup.rs#L42-L47) isn't exact, leading to suggestions not being shown if the user presses `c` or `d`. (because "c" is translated to "llvm" and "d" to "maintainer", but suggestions trigger for "codegen" and "user" respectively) A more thorough refactor would stop using "strings-as-type" to make sure this kind of error doesn't happen, but it may be overkill for that kind of "script" program? Tagging the setup command author: @jyn514
2 parents 5ae45ea + d67a7e6 commit 59707c5

File tree

3 files changed

+81
-38
lines changed

3 files changed

+81
-38
lines changed

src/bootstrap/flags.rs

+16-7
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use getopts::Options;
1212

1313
use crate::builder::Builder;
1414
use crate::config::{Config, TargetSelection};
15+
use crate::setup::Profile;
1516
use crate::{Build, DocTests};
1617

1718
/// Deserialized version of all flags for this compile.
@@ -94,7 +95,7 @@ pub enum Subcommand {
9495
paths: Vec<PathBuf>,
9596
},
9697
Setup {
97-
path: String,
98+
profile: Profile,
9899
},
99100
}
100101

@@ -533,18 +534,26 @@ Arguments:
533534
Subcommand::Run { paths }
534535
}
535536
"setup" => {
536-
let path = if paths.len() > 1 {
537+
let profile = if paths.len() > 1 {
537538
println!("\nat most one profile can be passed to setup\n");
538539
usage(1, &opts, verbose, &subcommand_help)
539540
} else if let Some(path) = paths.pop() {
540-
t!(path.into_os_string().into_string().map_err(|path| format!(
541-
"{} is not a valid UTF8 string",
542-
path.to_string_lossy()
543-
)))
541+
let profile_string = t!(path.into_os_string().into_string().map_err(
542+
|path| format!("{} is not a valid UTF8 string", path.to_string_lossy())
543+
));
544+
545+
profile_string.parse().unwrap_or_else(|err| {
546+
eprintln!("error: {}", err);
547+
eprintln!("help: the available profiles are:");
548+
for choice in Profile::all() {
549+
eprintln!("- {}", choice);
550+
}
551+
std::process::exit(1);
552+
})
544553
} else {
545554
t!(crate::setup::interactive_path())
546555
};
547-
Subcommand::Setup { path }
556+
Subcommand::Setup { profile }
548557
}
549558
_ => {
550559
usage(1, &opts, verbose, &subcommand_help);

src/bootstrap/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -471,8 +471,8 @@ impl Build {
471471
return clean::clean(self, all);
472472
}
473473

474-
if let Subcommand::Setup { path: include_name } = &self.config.cmd {
475-
return setup::setup(&self.config.src, include_name);
474+
if let Subcommand::Setup { profile } = &self.config.cmd {
475+
return setup::setup(&self.config.src, *profile);
476476
}
477477

478478
{

src/bootstrap/setup.rs

+63-29
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,55 @@
11
use crate::t;
22
use std::path::{Path, PathBuf};
3+
use std::str::FromStr;
34
use std::{
4-
env, fs,
5+
env, fmt, fs,
56
io::{self, Write},
67
};
78

8-
pub fn setup(src_path: &Path, include_name: &str) {
9+
#[derive(Clone, Copy, Eq, PartialEq)]
10+
pub enum Profile {
11+
Compiler,
12+
Codegen,
13+
Library,
14+
User,
15+
}
16+
17+
impl Profile {
18+
fn include_path(&self, src_path: &Path) -> PathBuf {
19+
PathBuf::from(format!("{}/src/bootstrap/defaults/config.{}.toml", src_path.display(), self))
20+
}
21+
22+
pub fn all() -> impl Iterator<Item = Self> {
23+
[Profile::Compiler, Profile::Codegen, Profile::Library, Profile::User].iter().copied()
24+
}
25+
}
26+
27+
impl FromStr for Profile {
28+
type Err = String;
29+
30+
fn from_str(s: &str) -> Result<Self, Self::Err> {
31+
match s {
32+
"a" | "lib" | "library" => Ok(Profile::Library),
33+
"b" | "compiler" => Ok(Profile::Compiler),
34+
"c" | "llvm" | "codegen" => Ok(Profile::Codegen),
35+
"d" | "maintainer" | "user" => Ok(Profile::User),
36+
_ => Err(format!("unknown profile: '{}'", s)),
37+
}
38+
}
39+
}
40+
41+
impl fmt::Display for Profile {
42+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43+
match self {
44+
Profile::Compiler => write!(f, "compiler"),
45+
Profile::Codegen => write!(f, "codegen"),
46+
Profile::Library => write!(f, "library"),
47+
Profile::User => write!(f, "user"),
48+
}
49+
}
50+
}
51+
52+
pub fn setup(src_path: &Path, profile: Profile) {
953
let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from);
1054

1155
if cfg_file.as_ref().map_or(false, |f| f.exists()) {
@@ -14,15 +58,10 @@ pub fn setup(src_path: &Path, include_name: &str) {
1458
"error: you asked `x.py` to setup a new config file, but one already exists at `{}`",
1559
file.display()
1660
);
61+
println!("help: try adding `profile = \"{}\"` at the top of {}", profile, file.display());
1762
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
63+
"note: this will use the configuration in {}",
64+
profile.include_path(src_path).display()
2665
);
2766
std::process::exit(1);
2867
}
@@ -31,19 +70,17 @@ pub fn setup(src_path: &Path, include_name: &str) {
3170
let settings = format!(
3271
"# Includes one of the default files in src/bootstrap/defaults\n\
3372
profile = \"{}\"\n",
34-
include_name
73+
profile
3574
);
3675
t!(fs::write(path, settings));
3776

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);
77+
let include_path = profile.include_path(src_path);
78+
println!("`x.py` will now use the configuration at {}", include_path.display());
4179

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,
80+
let suggestions = match profile {
81+
Profile::Codegen | Profile::Compiler => &["check", "build", "test"][..],
82+
Profile::Library => &["check", "build", "test library/std", "doc"],
83+
Profile::User => &["dist", "build"],
4784
};
4885

4986
println!();
@@ -57,15 +94,15 @@ pub fn setup(src_path: &Path, include_name: &str) {
5794
println!("- `x.py {}`", cmd);
5895
}
5996

60-
if include_name != "user" {
97+
if profile != Profile::User {
6198
println!(
6299
"For more suggestions, see https://rustc-dev-guide.rust-lang.org/building/suggested.html"
63100
);
64101
}
65102
}
66103

67104
// Used to get the path for `Subcommand::Setup`
68-
pub fn interactive_path() -> io::Result<String> {
105+
pub fn interactive_path() -> io::Result<Profile> {
69106
let mut input = String::new();
70107
println!(
71108
"Welcome to the Rust project! What do you want to do with x.py?
@@ -78,19 +115,16 @@ d) Install Rust from source"
78115
print!("Please choose one (a/b/c/d): ");
79116
io::stdout().flush()?;
80117
io::stdin().read_line(&mut input)?;
81-
break match input.trim().to_lowercase().as_str() {
82-
"a" | "lib" | "library" => "library",
83-
"b" | "compiler" => "compiler",
84-
"c" | "llvm" => "llvm",
85-
"d" | "user" | "maintainer" => "maintainer",
86-
_ => {
87-
println!("error: unrecognized option '{}'", input.trim());
118+
break match input.trim().to_lowercase().parse() {
119+
Ok(profile) => profile,
120+
Err(err) => {
121+
println!("error: {}", err);
88122
println!("note: press Ctrl+C to exit");
89123
continue;
90124
}
91125
};
92126
};
93-
Ok(template.to_owned())
127+
Ok(template)
94128
}
95129

96130
// install a git hook to automatically run tidy --bless, if they want

0 commit comments

Comments
 (0)