]> git.lizzy.rs Git - rust.git/commitdiff
Add `x.py setup`
authorJoshua Nelson <jyn514@gmail.com>
Sat, 12 Sep 2020 06:32:43 +0000 (02:32 -0400)
committerJoshua Nelson <jyn514@gmail.com>
Thu, 24 Sep 2020 14:32:45 +0000 (10:32 -0400)
- Suggest `x.py setup` if config.toml doesn't exist yet (twice, once
before and once after the build)
- Prompt for a profile if not given on the command line
- Print the configuration file that will be used
- Print helpful starting commands after setup
- Link to the dev-guide after finishing
- Note that distro maintainers will see the changelog warning

src/bootstrap/CHANGELOG.md
src/bootstrap/bin/main.rs
src/bootstrap/builder.rs
src/bootstrap/config.rs
src/bootstrap/flags.rs
src/bootstrap/lib.rs
src/bootstrap/run.rs
src/bootstrap/setup.rs [new file with mode: 0644]

index 5fcaafab959e9edf484255b150547afd96611647..aa398f25020f1fdd56e25fd0c78272518e7bce81 100644 (file)
@@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 
 ## [Non-breaking changes since the last major version]
 
+- Add `x.py setup` [#76631](https://github.com/rust-lang/rust/pull/76631)
 - Add a changelog for x.py [#76626](https://github.com/rust-lang/rust/pull/76626)
 - Optionally, download LLVM from CI on Linux and NixOS
   + [#76439](https://github.com/rust-lang/rust/pull/76349)
index f7512aa9fcebdd3648a9ed648aa3267a9dab6537..669dd7a33de187ae664270f98bc368e89c4e8f7c 100644 (file)
@@ -7,21 +7,34 @@
 
 use std::env;
 
-use bootstrap::{Build, Config};
+use bootstrap::{Build, Config, Subcommand};
 
 fn main() {
     let args = env::args().skip(1).collect::<Vec<_>>();
     let config = Config::parse(&args);
 
     let changelog_suggestion = check_version(&config);
-    if let Some(suggestion) = &changelog_suggestion {
+
+    // NOTE: Since `./configure` generates a `config.toml`, distro maintainers will see the
+    // changelog warning, not the `x.py setup` message.
+    let suggest_setup = !config.config.exists() && !matches!(config.cmd, Subcommand::Setup { .. });
+    if suggest_setup {
+        println!("warning: you have not made a `config.toml`");
+        println!("help: consider running `x.py setup` or copying `config.toml.example`");
+    } else if let Some(suggestion) = &changelog_suggestion {
         println!("{}", suggestion);
     }
 
     Build::new(config).build();
 
-    if let Some(suggestion) = changelog_suggestion {
+    if suggest_setup {
+        println!("warning: you have not made a `config.toml`");
+        println!("help: consider running `x.py setup` or copying `config.toml.example`");
+    } else if let Some(suggestion) = &changelog_suggestion {
         println!("{}", suggestion);
+    }
+
+    if suggest_setup || changelog_suggestion.is_some() {
         println!("note: this message was printed twice to make it more likely to be seen");
     }
 }
index d2537d65e67f50fe6dcf32977689b69d52511764..4aaaeb8a93bda903e799b25317cc762b0677a001 100644 (file)
@@ -549,7 +549,9 @@ pub fn new(build: &Build) -> Builder<'_> {
             Subcommand::Dist { ref paths } => (Kind::Dist, &paths[..]),
             Subcommand::Install { ref paths } => (Kind::Install, &paths[..]),
             Subcommand::Run { ref paths } => (Kind::Run, &paths[..]),
-            Subcommand::Format { .. } | Subcommand::Clean { .. } => panic!(),
+            Subcommand::Format { .. } | Subcommand::Clean { .. } | Subcommand::Setup { .. } => {
+                panic!()
+            }
         };
 
         Self::new_internal(build, kind, paths.to_owned())
index c74501979f0ecde4614756707dbeb018f6ef06e1..46a9d989652e93af5405d6728df9d1baafd8b0a0 100644 (file)
@@ -72,6 +72,8 @@ pub struct Config {
     pub stage: u32,
     pub keep_stage: Vec<u32>,
     pub src: PathBuf,
+    // defaults to `config.toml`
+    pub config: PathBuf,
     pub jobs: Option<u32>,
     pub cmd: Subcommand,
     pub incremental: bool,
@@ -512,6 +514,7 @@ pub fn default_opts() -> Config {
         config.rust_codegen_backends = vec![INTERNER.intern_str("llvm")];
         config.deny_warnings = true;
         config.missing_tools = false;
+        config.config = PathBuf::from("config.toml");
 
         // set by bootstrap.py
         config.build = TargetSelection::from_user(&env!("BUILD_TRIPLE"));
@@ -556,7 +559,7 @@ pub fn parse(args: &[String]) -> Config {
         let get_toml = |file: PathBuf| {
             use std::process;
 
-            let contents = t!(fs::read_to_string(&file), "configuration file did not exist");
+            let contents = t!(fs::read_to_string(&file), "`include` config not found");
             match toml::from_str(&contents) {
                 Ok(table) => table,
                 Err(err) => {
@@ -642,6 +645,7 @@ pub fn parse(args: &[String]) -> Config {
             | Subcommand::Clippy { .. }
             | Subcommand::Fix { .. }
             | Subcommand::Run { .. }
+            | Subcommand::Setup { .. }
             | Subcommand::Format { .. } => flags.stage.unwrap_or(0),
         };
 
@@ -666,6 +670,7 @@ pub fn parse(args: &[String]) -> Config {
                 | Subcommand::Clippy { .. }
                 | Subcommand::Fix { .. }
                 | Subcommand::Run { .. }
+                | Subcommand::Setup { .. }
                 | Subcommand::Format { .. } => {}
             }
         }
index 842c84a3e5cd6dcd82220e36c49133be5da00db2..643edeb8321bae12aab17f6b7e65e12b8e5b6ee7 100644 (file)
@@ -7,6 +7,7 @@
 use std::path::PathBuf;
 use std::process;
 
+use build_helper::t;
 use getopts::Options;
 
 use crate::builder::Builder;
@@ -88,6 +89,9 @@ pub enum Subcommand {
     Run {
         paths: Vec<PathBuf>,
     },
+    Setup {
+        path: String,
+    },
 }
 
 impl Default for Subcommand {
@@ -191,6 +195,7 @@ pub fn parse(args: &[String]) -> Flags {
                 || (s == "install")
                 || (s == "run")
                 || (s == "r")
+                || (s == "setup")
         });
         let subcommand = match subcommand {
             Some(s) => s,
@@ -445,10 +450,21 @@ pub fn parse(args: &[String]) -> Flags {
     At least a tool needs to be called.",
                 );
             }
+            "setup" => {
+                subcommand_help.push_str(
+                    "\n
+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.",
+                );
+            }
             _ => {}
         };
         // Get any optional paths which occur after the subcommand
-        let paths = matches.free[1..].iter().map(|p| p.into()).collect::<Vec<PathBuf>>();
+        let mut paths = matches.free[1..].iter().map(|p| p.into()).collect::<Vec<PathBuf>>();
 
         let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from);
         let verbose = matches.opt_present("verbose");
@@ -500,6 +516,20 @@ pub fn parse(args: &[String]) -> Flags {
                 }
                 Subcommand::Run { paths }
             }
+            "setup" => {
+                let path = 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()
+                    )))
+                } else {
+                    t!(crate::setup::interactive_path())
+                };
+                Subcommand::Setup { path }
+            }
             _ => {
                 usage(1, &opts, verbose, &subcommand_help);
             }
index 3f7aeae0ed4951f79c598960341b0ffc65bb4e48..4cc72f5f39c979755994039162804cf76071c107 100644 (file)
 mod native;
 mod run;
 mod sanity;
+mod setup;
 mod test;
 mod tool;
 mod toolstate;
@@ -165,7 +166,7 @@ pub unsafe fn setup(_build: &mut crate::Build) {}
 
 use crate::cache::{Interned, INTERNER};
 pub use crate::config::Config;
-use crate::flags::Subcommand;
+pub use crate::flags::Subcommand;
 
 const LLVM_TOOLS: &[&str] = &[
     "llvm-nm", // used to inspect binaries; it shows symbol names, their sizes and visibility
@@ -470,6 +471,10 @@ pub fn build(&mut self) {
             return clean::clean(self, all);
         }
 
+        if let Subcommand::Setup { path: include_name } = &self.config.cmd {
+            return setup::setup(&self.config.src, include_name);
+        }
+
         {
             let builder = builder::Builder::new(&self);
             if let Some(path) = builder.paths.get(0) {
index 900534714277cb83ef2296b9f2ba82c8f9992e8d..ba593cadbad817a490e14675f33864d40fca5aa7 100644 (file)
@@ -10,7 +10,7 @@ impl Step for ExpandYamlAnchors {
 
     /// Runs the `expand-yaml_anchors` tool.
     ///
-    /// This tool in `src/tools` read the CI configuration files written in YAML and expands the
+    /// This tool in `src/tools` reads the CI configuration files written in YAML and expands the
     /// anchors in them, since GitHub Actions doesn't support them.
     fn run(self, builder: &Builder<'_>) {
         builder.info("Expanding YAML anchors in the GitHub Actions configuration");
diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs
new file mode 100644 (file)
index 0000000..9d3a889
--- /dev/null
@@ -0,0 +1,88 @@
+use crate::t;
+use std::path::{Path, PathBuf};
+use std::{
+    env, fs,
+    io::{self, Write},
+};
+
+pub fn setup(src_path: &Path, include_name: &str) {
+    let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from);
+
+    if cfg_file.as_ref().map_or(false, |f| f.exists()) {
+        let file = cfg_file.unwrap();
+        println!(
+            "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 {}",
+            include_name,
+            file.display()
+        );
+        println!(
+            "note: this will use the configuration in {}/src/bootstrap/defaults/config.toml.{}",
+            src_path.display(),
+            include_name
+        );
+        std::process::exit(1);
+    }
+
+    let path = cfg_file.unwrap_or_else(|| src_path.join("config.toml"));
+    let settings = format!(
+        "# Includes one of the default files in src/bootstrap/defaults\n\
+    profile = \"{}\"\n",
+        include_name
+    );
+    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 suggestions = match include_name {
+        "codegen" | "compiler" => &["check", "build", "test"][..],
+        "library" => &["check", "build", "test library/std", "doc"],
+        "user" => &["dist", "build"],
+        _ => return,
+    };
+
+    println!("To get started, try one of the following commands:");
+    for cmd in suggestions {
+        println!("- `x.py {}`", cmd);
+    }
+
+    if include_name != "user" {
+        println!(
+            "For more suggestions, see https://rustc-dev-guide.rust-lang.org/building/suggested.html"
+        );
+    }
+}
+
+// Used to get the path for `Subcommand::Setup`
+pub fn interactive_path() -> io::Result<String> {
+    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
+c) Contribute to the compiler, and also modify LLVM or codegen
+d) Install Rust from source"
+    );
+    let template = loop {
+        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());
+                println!("note: press Ctrl+C to exit");
+                continue;
+            }
+        };
+    };
+    Ok(template.to_owned())
+}