Rollup merge of #76631 - jyn514:x.py-setup, r=Mark-Simulacrum
Add `x.py setup` Closes #76503. - Suggest `x.py setup` if config.toml doesn't exist yet - Prompt for a profile if not given on the command line - Print the configuration that will be used - Print helpful starting commands after setup - Link to the dev-guide after finishing
This commit is contained in:
commit
c39598aeea
@ -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)
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -549,7 +549,9 @@ impl<'a> Builder<'a> {
|
||||
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())
|
||||
|
@ -73,6 +73,8 @@ pub struct Config {
|
||||
pub keep_stage: Vec<u32>,
|
||||
pub keep_stage_std: Vec<u32>,
|
||||
pub src: PathBuf,
|
||||
// defaults to `config.toml`
|
||||
pub config: PathBuf,
|
||||
pub jobs: Option<u32>,
|
||||
pub cmd: Subcommand,
|
||||
pub incremental: bool,
|
||||
@ -513,6 +515,7 @@ impl 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"));
|
||||
@ -558,7 +561,7 @@ impl 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) => {
|
||||
@ -644,6 +647,7 @@ impl Config {
|
||||
| Subcommand::Clippy { .. }
|
||||
| Subcommand::Fix { .. }
|
||||
| Subcommand::Run { .. }
|
||||
| Subcommand::Setup { .. }
|
||||
| Subcommand::Format { .. } => flags.stage.unwrap_or(0),
|
||||
};
|
||||
|
||||
@ -668,6 +672,7 @@ impl Config {
|
||||
| Subcommand::Clippy { .. }
|
||||
| Subcommand::Fix { .. }
|
||||
| Subcommand::Run { .. }
|
||||
| Subcommand::Setup { .. }
|
||||
| Subcommand::Format { .. } => {}
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ use std::env;
|
||||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
|
||||
use build_helper::t;
|
||||
use getopts::Options;
|
||||
|
||||
use crate::builder::Builder;
|
||||
@ -89,6 +90,9 @@ pub enum Subcommand {
|
||||
Run {
|
||||
paths: Vec<PathBuf>,
|
||||
},
|
||||
Setup {
|
||||
path: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl Default for Subcommand {
|
||||
@ -199,6 +203,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`",
|
||||
|| (s == "install")
|
||||
|| (s == "run")
|
||||
|| (s == "r")
|
||||
|| (s == "setup")
|
||||
});
|
||||
let subcommand = match subcommand {
|
||||
Some(s) => s,
|
||||
@ -453,10 +458,21 @@ Arguments:
|
||||
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");
|
||||
@ -508,6 +524,20 @@ Arguments:
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
@ -141,6 +141,7 @@ mod metadata;
|
||||
mod native;
|
||||
mod run;
|
||||
mod sanity;
|
||||
mod setup;
|
||||
mod test;
|
||||
mod tool;
|
||||
mod toolstate;
|
||||
@ -165,7 +166,7 @@ mod job {
|
||||
|
||||
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 @@ 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);
|
||||
}
|
||||
|
||||
{
|
||||
let builder = builder::Builder::new(&self);
|
||||
if let Some(path) = builder.paths.get(0) {
|
||||
|
@ -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");
|
||||
|
88
src/bootstrap/setup.rs
Normal file
88
src/bootstrap/setup.rs
Normal file
@ -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())
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user