From 6e06388a7f165a1d532187cafc4346ce55385ca7 Mon Sep 17 00:00:00 2001 From: Antoine Martin Date: Thu, 1 Oct 2020 16:08:05 +0200 Subject: [PATCH 1/4] Fix suggestions for x.py setup --- src/bootstrap/setup.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs index 8a77641fbfefb..76a554d7cf6b5 100644 --- a/src/bootstrap/setup.rs +++ b/src/bootstrap/setup.rs @@ -40,9 +40,9 @@ pub fn setup(src_path: &Path, include_name: &str) { println!("`x.py` will now use the configuration at {}", include_path); let suggestions = match include_name { - "codegen" | "compiler" => &["check", "build", "test"][..], + "llvm" | "codegen" | "compiler" => &["check", "build", "test"][..], "library" => &["check", "build", "test library/std", "doc"], - "user" => &["dist", "build"], + "maintainer" | "user" => &["dist", "build"], _ => return, }; From d3d33971216f5eca3139e239c2b1f485c52270f4 Mon Sep 17 00:00:00 2001 From: Antoine Martin Date: Mon, 5 Oct 2020 17:27:42 +0200 Subject: [PATCH 2/4] Use Profile enum for x.py setup --- src/bootstrap/flags.rs | 16 ++++---- src/bootstrap/lib.rs | 4 +- src/bootstrap/setup.rs | 93 +++++++++++++++++++++++++++++------------- 3 files changed, 75 insertions(+), 38 deletions(-) diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index c1a9d4fcd23fe..2c1e361fae4c0 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -12,6 +12,7 @@ use getopts::Options; use crate::builder::Builder; use crate::config::{Config, TargetSelection}; +use crate::setup::Profile; use crate::{Build, DocTests}; /// Deserialized version of all flags for this compile. @@ -94,7 +95,7 @@ pub enum Subcommand { paths: Vec, }, Setup { - path: String, + profile: Profile, }, } @@ -533,18 +534,19 @@ Arguments: Subcommand::Run { paths } } "setup" => { - let path = if paths.len() > 1 { + let profile = if paths.len() > 1 { println!("\nat most one profile can be passed to setup\n"); usage(1, &opts, verbose, &subcommand_help) } else if let Some(path) = paths.pop() { - t!(path.into_os_string().into_string().map_err(|path| format!( - "{} is not a valid UTF8 string", - path.to_string_lossy() - ))) + let profile_string = t!(path.into_os_string().into_string().map_err( + |path| format!("{} is not a valid UTF8 string", path.to_string_lossy()) + )); + + profile_string.parse().expect("unknown profile") } else { t!(crate::setup::interactive_path()) }; - Subcommand::Setup { path } + Subcommand::Setup { profile } } _ => { usage(1, &opts, verbose, &subcommand_help); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 4cc72f5f39c97..147bcf30709f9 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -471,8 +471,8 @@ impl Build { return clean::clean(self, all); } - if let Subcommand::Setup { path: include_name } = &self.config.cmd { - return setup::setup(&self.config.src, include_name); + if let Subcommand::Setup { profile } = &self.config.cmd { + return setup::setup(&self.config.src, *profile); } { diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs index 76a554d7cf6b5..cbbb406cd167f 100644 --- a/src/bootstrap/setup.rs +++ b/src/bootstrap/setup.rs @@ -1,11 +1,56 @@ use crate::t; use std::path::{Path, PathBuf}; +use std::str::FromStr; use std::{ - env, fs, + env, fmt, fs, io::{self, Write}, }; -pub fn setup(src_path: &Path, include_name: &str) { +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum Profile { + Compiler, + Codegen, + Library, + User, +} + +impl Profile { + fn include_path(&self, src_path: &Path) -> PathBuf { + PathBuf::from(format!("{}/src/bootstrap/defaults/config.{}.toml", src_path.display(), self)) + } +} + +#[derive(Debug)] +pub struct ProfileErr { + pub name: String, +} + +impl FromStr for Profile { + type Err = ProfileErr; + + fn from_str(s: &str) -> Result { + match s { + "a" | "lib" | "library" => Ok(Profile::Library), + "b" | "compiler" => Ok(Profile::Compiler), + "c" | "llvm" | "codegen" => Ok(Profile::Codegen), + "d" | "maintainer" | "user" => Ok(Profile::User), + _ => Err(ProfileErr { name: s.to_string() }), + } + } +} + +impl fmt::Display for Profile { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Profile::Compiler => write!(f, "compiler"), + Profile::Codegen => write!(f, "codegen"), + Profile::Library => write!(f, "library"), + Profile::User => write!(f, "user"), + } + } +} + +pub fn setup(src_path: &Path, profile: Profile) { let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from); if cfg_file.as_ref().map_or(false, |f| f.exists()) { @@ -14,15 +59,10 @@ pub fn setup(src_path: &Path, include_name: &str) { "error: you asked `x.py` to setup a new config file, but one already exists at `{}`", file.display() ); + println!("help: try adding `profile = \"{}\"` at the top of {}", profile, file.display()); println!( - "help: try adding `profile = \"{}\"` at the top of {}", - include_name, - file.display() - ); - println!( - "note: this will use the configuration in {}/src/bootstrap/defaults/config.{}.toml", - src_path.display(), - include_name + "note: this will use the configuration in {}", + profile.include_path(src_path).display() ); std::process::exit(1); } @@ -31,19 +71,17 @@ pub fn setup(src_path: &Path, include_name: &str) { let settings = format!( "# Includes one of the default files in src/bootstrap/defaults\n\ profile = \"{}\"\n", - include_name + profile ); t!(fs::write(path, settings)); - let include_path = - format!("{}/src/bootstrap/defaults/config.{}.toml", src_path.display(), include_name); - println!("`x.py` will now use the configuration at {}", include_path); + let include_path = profile.include_path(src_path); + println!("`x.py` will now use the configuration at {}", include_path.display()); - let suggestions = match include_name { - "llvm" | "codegen" | "compiler" => &["check", "build", "test"][..], - "library" => &["check", "build", "test library/std", "doc"], - "maintainer" | "user" => &["dist", "build"], - _ => return, + let suggestions = match profile { + Profile::Codegen | Profile::Compiler => &["check", "build", "test"][..], + Profile::Library => &["check", "build", "test library/std", "doc"], + Profile::User => &["dist", "build"], }; println!("To get started, try one of the following commands:"); @@ -51,7 +89,7 @@ pub fn setup(src_path: &Path, include_name: &str) { println!("- `x.py {}`", cmd); } - if include_name != "user" { + if profile != Profile::User { println!( "For more suggestions, see https://rustc-dev-guide.rust-lang.org/building/suggested.html" ); @@ -59,7 +97,7 @@ pub fn setup(src_path: &Path, include_name: &str) { } // Used to get the path for `Subcommand::Setup` -pub fn interactive_path() -> io::Result { +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? @@ -72,17 +110,14 @@ d) Install Rust from source" print!("Please choose one (a/b/c/d): "); io::stdout().flush()?; io::stdin().read_line(&mut input)?; - break match input.trim().to_lowercase().as_str() { - "a" | "lib" | "library" => "library", - "b" | "compiler" => "compiler", - "c" | "llvm" => "llvm", - "d" | "user" | "maintainer" => "maintainer", - _ => { - println!("error: unrecognized option '{}'", input.trim()); + break match input.trim().to_lowercase().parse() { + Ok(profile) => profile, + Err(ProfileErr { name }) => { + println!("error: unrecognized option '{}'", name); println!("note: press Ctrl+C to exit"); continue; } }; }; - Ok(template.to_owned()) + Ok(template) } From 3afc004845b36d18009718fe8d5179adfa1ca2ea Mon Sep 17 00:00:00 2001 From: Antoine Martin Date: Mon, 5 Oct 2020 17:55:14 +0200 Subject: [PATCH 3/4] Show available profiles on error --- src/bootstrap/flags.rs | 9 ++++++++- src/bootstrap/setup.rs | 4 ++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 2c1e361fae4c0..d1f256d6dd09a 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -542,7 +542,14 @@ Arguments: |path| format!("{} is not a valid UTF8 string", path.to_string_lossy()) )); - profile_string.parse().expect("unknown profile") + profile_string.parse().unwrap_or_else(|_| { + eprintln!("error: unknown profile {}", profile_string); + eprintln!("help: the available profiles are:"); + for choice in Profile::all() { + eprintln!("- {}", choice); + } + std::process::exit(1); + }) } else { t!(crate::setup::interactive_path()) }; diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs index cbbb406cd167f..0d2945c3c3969 100644 --- a/src/bootstrap/setup.rs +++ b/src/bootstrap/setup.rs @@ -18,6 +18,10 @@ impl Profile { fn include_path(&self, src_path: &Path) -> PathBuf { PathBuf::from(format!("{}/src/bootstrap/defaults/config.{}.toml", src_path.display(), self)) } + + pub fn all() -> impl Iterator { + [Profile::Compiler, Profile::Codegen, Profile::Library, Profile::User].iter().copied() + } } #[derive(Debug)] From d67a7e6cfc86352ffdd1098d66831675736677dc Mon Sep 17 00:00:00 2001 From: Antoine Martin Date: Mon, 5 Oct 2020 18:03:54 +0200 Subject: [PATCH 4/4] Use String type for Profile parse error --- src/bootstrap/flags.rs | 4 ++-- src/bootstrap/setup.rs | 13 ++++--------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index d1f256d6dd09a..f806e40aa8bd2 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -542,8 +542,8 @@ Arguments: |path| format!("{} is not a valid UTF8 string", path.to_string_lossy()) )); - profile_string.parse().unwrap_or_else(|_| { - eprintln!("error: unknown profile {}", profile_string); + profile_string.parse().unwrap_or_else(|err| { + eprintln!("error: {}", err); eprintln!("help: the available profiles are:"); for choice in Profile::all() { eprintln!("- {}", choice); diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs index 0d2945c3c3969..fdc0892845d94 100644 --- a/src/bootstrap/setup.rs +++ b/src/bootstrap/setup.rs @@ -24,13 +24,8 @@ impl Profile { } } -#[derive(Debug)] -pub struct ProfileErr { - pub name: String, -} - impl FromStr for Profile { - type Err = ProfileErr; + type Err = String; fn from_str(s: &str) -> Result { match s { @@ -38,7 +33,7 @@ impl FromStr for Profile { "b" | "compiler" => Ok(Profile::Compiler), "c" | "llvm" | "codegen" => Ok(Profile::Codegen), "d" | "maintainer" | "user" => Ok(Profile::User), - _ => Err(ProfileErr { name: s.to_string() }), + _ => Err(format!("unknown profile: '{}'", s)), } } } @@ -116,8 +111,8 @@ d) Install Rust from source" io::stdin().read_line(&mut input)?; break match input.trim().to_lowercase().parse() { Ok(profile) => profile, - Err(ProfileErr { name }) => { - println!("error: unrecognized option '{}'", name); + Err(err) => { + println!("error: {}", err); println!("note: press Ctrl+C to exit"); continue; }