diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index c10188875fbc4..22cfd0c56431d 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -125,6 +125,7 @@ Subcommands: dist Build distribution artifacts install Install distribution artifacts run, r Run tools contained in this repository + setup Create a config.toml (making it easier to use `x.py` itself) To learn more about a subcommand, run `./x.py -h`", ); @@ -472,15 +473,21 @@ Arguments: ); } "setup" => { - subcommand_help.push_str( + subcommand_help.push_str(&format!( "\n +x.py setup creates a `config.toml` which changes the defaults for x.py itself. + Arguments: This subcommand accepts a 'profile' to use for builds. For example: ./x.py setup library - The profile is optional and you will be prompted interactively if it is not given.", - ); + The profile is optional and you will be prompted interactively if it is not given. + The following profiles are available: + +{}", + Profile::all_for_help(" ").trim_end() + )); } _ => {} }; @@ -551,9 +558,7 @@ Arguments: profile_string.parse().unwrap_or_else(|err| { eprintln!("error: {}", err); eprintln!("help: the available profiles are:"); - for choice in Profile::all() { - eprintln!("- {}", choice); - } + eprint!("{}", Profile::all_for_help("- ")); std::process::exit(1); }) } else { diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs index 2a9507cfc4c18..a281061ace15b 100644 --- a/src/bootstrap/setup.rs +++ b/src/bootstrap/setup.rs @@ -1,4 +1,5 @@ use crate::{t, VERSION}; +use std::fmt::Write as _; use std::path::{Path, PathBuf}; use std::str::FromStr; use std::{ @@ -20,7 +21,28 @@ impl Profile { } pub fn all() -> impl Iterator { - [Profile::Compiler, Profile::Codegen, Profile::Library, Profile::User].iter().copied() + use Profile::*; + // N.B. these are ordered by how they are displayed, not alphabetically + [Library, Compiler, Codegen, User].iter().copied() + } + + pub fn purpose(&self) -> String { + use Profile::*; + match self { + Library => "Contribute to the standard library", + Compiler => "Contribute to the compiler or rustdoc", + Codegen => "Contribute to the compiler, and also modify LLVM or codegen", + User => "Install Rust from source", + } + .to_string() + } + + pub fn all_for_help(indent: &str) -> String { + let mut out = String::new(); + for choice in Profile::all() { + writeln!(&mut out, "{}{}: {}", indent, choice, choice.purpose()).unwrap(); + } + out } } @@ -29,10 +51,10 @@ impl FromStr for Profile { fn from_str(s: &str) -> Result { match s { - "a" | "lib" | "library" => Ok(Profile::Library), - "b" | "compiler" | "rustdoc" => Ok(Profile::Compiler), - "c" | "llvm" | "codegen" => Ok(Profile::Codegen), - "d" | "maintainer" | "user" => Ok(Profile::User), + "lib" | "library" => Ok(Profile::Library), + "compiler" | "rustdoc" => Ok(Profile::Compiler), + "llvm" | "codegen" => Ok(Profile::Codegen), + "maintainer" | "user" => Ok(Profile::User), _ => Err(format!("unknown profile: '{}'", s)), } } @@ -104,19 +126,37 @@ pub fn setup(src_path: &Path, profile: Profile) { // Used to get the path for `Subcommand::Setup` pub fn interactive_path() -> io::Result { - let mut input = String::new(); - println!( - "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 or rustdoc -c) Contribute to the compiler, and also modify LLVM or codegen -d) Install Rust from source" - ); + fn abbrev_all() -> impl Iterator { + ('a'..).map(|c| c.to_string()).zip(Profile::all()) + } + + fn parse_with_abbrev(input: &str) -> Result { + let input = input.trim().to_lowercase(); + for (letter, profile) in abbrev_all() { + if input == letter { + return Ok(profile); + } + } + input.parse() + } + + println!("Welcome to the Rust project! What do you want to do with x.py?"); + for (letter, profile) in abbrev_all() { + println!("{}) {}: {}", letter, profile, profile.purpose()); + } let template = loop { - print!("Please choose one (a/b/c/d): "); + print!( + "Please choose one ({}): ", + abbrev_all().map(|(l, _)| l).collect::>().join("/") + ); io::stdout().flush()?; + let mut input = String::new(); io::stdin().read_line(&mut input)?; - break match input.trim().to_lowercase().parse() { + if input == "" { + eprintln!("EOF on stdin, when expecting answer to question. Giving up."); + std::process::exit(1); + } + break match parse_with_abbrev(&input) { Ok(profile) => profile, Err(err) => { println!("error: {}", err);