Add `x.py setup`
- 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
This commit is contained in:
parent
cbc5e4d4d5
commit
9baa601afd
|
@ -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]
|
## [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)
|
- Add a changelog for x.py [#76626](https://github.com/rust-lang/rust/pull/76626)
|
||||||
- Optionally, download LLVM from CI on Linux and NixOS
|
- Optionally, download LLVM from CI on Linux and NixOS
|
||||||
+ [#76439](https://github.com/rust-lang/rust/pull/76349)
|
+ [#76439](https://github.com/rust-lang/rust/pull/76349)
|
||||||
|
|
|
@ -7,21 +7,34 @@
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
use bootstrap::{Build, Config};
|
use bootstrap::{Build, Config, Subcommand};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args = env::args().skip(1).collect::<Vec<_>>();
|
let args = env::args().skip(1).collect::<Vec<_>>();
|
||||||
let config = Config::parse(&args);
|
let config = Config::parse(&args);
|
||||||
|
|
||||||
let changelog_suggestion = check_version(&config);
|
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);
|
println!("{}", suggestion);
|
||||||
}
|
}
|
||||||
|
|
||||||
Build::new(config).build();
|
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);
|
println!("{}", suggestion);
|
||||||
|
}
|
||||||
|
|
||||||
|
if suggest_setup || changelog_suggestion.is_some() {
|
||||||
println!("note: this message was printed twice to make it more likely to be seen");
|
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::Dist { ref paths } => (Kind::Dist, &paths[..]),
|
||||||
Subcommand::Install { ref paths } => (Kind::Install, &paths[..]),
|
Subcommand::Install { ref paths } => (Kind::Install, &paths[..]),
|
||||||
Subcommand::Run { ref paths } => (Kind::Run, &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())
|
Self::new_internal(build, kind, paths.to_owned())
|
||||||
|
|
|
@ -72,6 +72,8 @@ pub struct Config {
|
||||||
pub stage: u32,
|
pub stage: u32,
|
||||||
pub keep_stage: Vec<u32>,
|
pub keep_stage: Vec<u32>,
|
||||||
pub src: PathBuf,
|
pub src: PathBuf,
|
||||||
|
// defaults to `config.toml`
|
||||||
|
pub config: PathBuf,
|
||||||
pub jobs: Option<u32>,
|
pub jobs: Option<u32>,
|
||||||
pub cmd: Subcommand,
|
pub cmd: Subcommand,
|
||||||
pub incremental: bool,
|
pub incremental: bool,
|
||||||
|
@ -512,6 +514,7 @@ impl Config {
|
||||||
config.rust_codegen_backends = vec![INTERNER.intern_str("llvm")];
|
config.rust_codegen_backends = vec![INTERNER.intern_str("llvm")];
|
||||||
config.deny_warnings = true;
|
config.deny_warnings = true;
|
||||||
config.missing_tools = false;
|
config.missing_tools = false;
|
||||||
|
config.config = PathBuf::from("config.toml");
|
||||||
|
|
||||||
// set by bootstrap.py
|
// set by bootstrap.py
|
||||||
config.build = TargetSelection::from_user(&env!("BUILD_TRIPLE"));
|
config.build = TargetSelection::from_user(&env!("BUILD_TRIPLE"));
|
||||||
|
@ -556,7 +559,7 @@ impl Config {
|
||||||
let get_toml = |file: PathBuf| {
|
let get_toml = |file: PathBuf| {
|
||||||
use std::process;
|
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) {
|
match toml::from_str(&contents) {
|
||||||
Ok(table) => table,
|
Ok(table) => table,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
@ -642,6 +645,7 @@ impl Config {
|
||||||
| Subcommand::Clippy { .. }
|
| Subcommand::Clippy { .. }
|
||||||
| Subcommand::Fix { .. }
|
| Subcommand::Fix { .. }
|
||||||
| Subcommand::Run { .. }
|
| Subcommand::Run { .. }
|
||||||
|
| Subcommand::Setup { .. }
|
||||||
| Subcommand::Format { .. } => flags.stage.unwrap_or(0),
|
| Subcommand::Format { .. } => flags.stage.unwrap_or(0),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -666,6 +670,7 @@ impl Config {
|
||||||
| Subcommand::Clippy { .. }
|
| Subcommand::Clippy { .. }
|
||||||
| Subcommand::Fix { .. }
|
| Subcommand::Fix { .. }
|
||||||
| Subcommand::Run { .. }
|
| Subcommand::Run { .. }
|
||||||
|
| Subcommand::Setup { .. }
|
||||||
| Subcommand::Format { .. } => {}
|
| Subcommand::Format { .. } => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ use std::env;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process;
|
use std::process;
|
||||||
|
|
||||||
|
use build_helper::t;
|
||||||
use getopts::Options;
|
use getopts::Options;
|
||||||
|
|
||||||
use crate::builder::Builder;
|
use crate::builder::Builder;
|
||||||
|
@ -88,6 +89,9 @@ pub enum Subcommand {
|
||||||
Run {
|
Run {
|
||||||
paths: Vec<PathBuf>,
|
paths: Vec<PathBuf>,
|
||||||
},
|
},
|
||||||
|
Setup {
|
||||||
|
path: String,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Subcommand {
|
impl Default for Subcommand {
|
||||||
|
@ -191,6 +195,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`",
|
||||||
|| (s == "install")
|
|| (s == "install")
|
||||||
|| (s == "run")
|
|| (s == "run")
|
||||||
|| (s == "r")
|
|| (s == "r")
|
||||||
|
|| (s == "setup")
|
||||||
});
|
});
|
||||||
let subcommand = match subcommand {
|
let subcommand = match subcommand {
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
|
@ -445,10 +450,21 @@ Arguments:
|
||||||
At least a tool needs to be called.",
|
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
|
// 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 cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from);
|
||||||
let verbose = matches.opt_present("verbose");
|
let verbose = matches.opt_present("verbose");
|
||||||
|
@ -500,6 +516,20 @@ Arguments:
|
||||||
}
|
}
|
||||||
Subcommand::Run { paths }
|
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);
|
usage(1, &opts, verbose, &subcommand_help);
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,6 +141,7 @@ mod metadata;
|
||||||
mod native;
|
mod native;
|
||||||
mod run;
|
mod run;
|
||||||
mod sanity;
|
mod sanity;
|
||||||
|
mod setup;
|
||||||
mod test;
|
mod test;
|
||||||
mod tool;
|
mod tool;
|
||||||
mod toolstate;
|
mod toolstate;
|
||||||
|
@ -165,7 +166,7 @@ mod job {
|
||||||
|
|
||||||
use crate::cache::{Interned, INTERNER};
|
use crate::cache::{Interned, INTERNER};
|
||||||
pub use crate::config::Config;
|
pub use crate::config::Config;
|
||||||
use crate::flags::Subcommand;
|
pub use crate::flags::Subcommand;
|
||||||
|
|
||||||
const LLVM_TOOLS: &[&str] = &[
|
const LLVM_TOOLS: &[&str] = &[
|
||||||
"llvm-nm", // used to inspect binaries; it shows symbol names, their sizes and visibility
|
"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);
|
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);
|
let builder = builder::Builder::new(&self);
|
||||||
if let Some(path) = builder.paths.get(0) {
|
if let Some(path) = builder.paths.get(0) {
|
||||||
|
|
|
@ -10,7 +10,7 @@ impl Step for ExpandYamlAnchors {
|
||||||
|
|
||||||
/// Runs the `expand-yaml_anchors` tool.
|
/// 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.
|
/// anchors in them, since GitHub Actions doesn't support them.
|
||||||
fn run(self, builder: &Builder<'_>) {
|
fn run(self, builder: &Builder<'_>) {
|
||||||
builder.info("Expanding YAML anchors in the GitHub Actions configuration");
|
builder.info("Expanding YAML anchors in the GitHub Actions configuration");
|
||||||
|
|
|
@ -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…
Reference in New Issue