about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/bootstrap/flags.rs23
-rw-r--r--src/bootstrap/lib.rs4
-rw-r--r--src/bootstrap/setup.rs92
3 files changed, 81 insertions, 38 deletions
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index c1a9d4fcd23..f806e40aa8b 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<PathBuf>,
     },
     Setup {
-        path: String,
+        profile: Profile,
     },
 }
 
@@ -533,18 +534,26 @@ 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().unwrap_or_else(|err| {
+                        eprintln!("error: {}", err);
+                        eprintln!("help: the available profiles are:");
+                        for choice in Profile::all() {
+                            eprintln!("- {}", choice);
+                        }
+                        std::process::exit(1);
+                    })
                 } 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 4cc72f5f39c..147bcf30709 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 24ec43373cc..dcfb9fd6734 100644
--- a/src/bootstrap/setup.rs
+++ b/src/bootstrap/setup.rs
@@ -1,11 +1,55 @@
 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))
+    }
+
+    pub fn all() -> impl Iterator<Item = Self> {
+        [Profile::Compiler, Profile::Codegen, Profile::Library, Profile::User].iter().copied()
+    }
+}
+
+impl FromStr for Profile {
+    type Err = String;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        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(format!("unknown profile: '{}'", s)),
+        }
+    }
+}
+
+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 +58,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 +70,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 {
-        "codegen" | "compiler" => &["check", "build", "test"][..],
-        "library" => &["check", "build", "test library/std", "doc"],
-        "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!();
@@ -57,7 +94,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"
         );
@@ -65,7 +102,7 @@ pub fn setup(src_path: &Path, include_name: &str) {
 }
 
 // Used to get the path for `Subcommand::Setup`
-pub fn interactive_path() -> io::Result<String> {
+pub fn interactive_path() -> io::Result<Profile> {
     let mut input = String::new();
     println!(
         "Welcome to the Rust project! What do you want to do with x.py?
@@ -78,19 +115,16 @@ 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(err) => {
+                println!("error: {}", err);
                 println!("note: press Ctrl+C to exit");
                 continue;
             }
         };
     };
-    Ok(template.to_owned())
+    Ok(template)
 }
 
 // install a git hook to automatically run tidy --bless, if they want