Add additional options to x setup

This commit is contained in:
clubby789 2023-02-09 14:01:07 +00:00
parent c40919b7a7
commit ee5404c69e
3 changed files with 114 additions and 21 deletions

View File

@ -793,7 +793,7 @@ impl<'a> Builder<'a> {
run::CollectLicenseMetadata, run::CollectLicenseMetadata,
run::GenerateCopyright, run::GenerateCopyright,
), ),
Kind::Setup => describe!(setup::Profile), Kind::Setup => describe!(setup::Profile, setup::Hook, setup::Link, setup::Vscode),
Kind::Clean => describe!(clean::CleanAll, clean::Rustc, clean::Std), Kind::Clean => describe!(clean::CleanAll, clean::Rustc, clean::Std),
// special-cased in Build::build() // special-cased in Build::build()
Kind::Format => vec![], Kind::Format => vec![],

View File

@ -542,7 +542,8 @@ Arguments:
Kind::Setup => { Kind::Setup => {
subcommand_help.push_str(&format!( subcommand_help.push_str(&format!(
"\n "\n
x.py setup creates a `config.toml` which changes the defaults for x.py itself. x.py setup creates a `config.toml` which changes the defaults for x.py itself,
as well as setting up a git pre-push hook, VS code config and toolchain link.
Arguments: Arguments:
This subcommand accepts a 'profile' to use for builds. For example: This subcommand accepts a 'profile' to use for builds. For example:
@ -552,7 +553,13 @@ Arguments:
The profile is optional and you will be prompted interactively if it is not given. The profile is optional and you will be prompted interactively if it is not given.
The following profiles are available: The following profiles are available:
{}", {}
To only set up the git hook, VS code or toolchain link, you may use
./x.py setup hook
./x.py setup vscode
./x.py setup link
",
Profile::all_for_help(" ").trim_end() Profile::all_for_help(" ").trim_end()
)); ));
} }
@ -625,7 +632,7 @@ Arguments:
} }
Kind::Setup => { Kind::Setup => {
let profile = if paths.len() > 1 { let profile = if paths.len() > 1 {
eprintln!("\nerror: At most one profile can be passed to setup\n"); eprintln!("\nerror: At most one option can be passed to setup\n");
usage(1, &opts, verbose, &subcommand_help) usage(1, &opts, verbose, &subcommand_help)
} else if let Some(path) = paths.pop() { } else if let Some(path) = paths.pop() {
let profile_string = t!(path.into_os_string().into_string().map_err( let profile_string = t!(path.into_os_string().into_string().map_err(

View File

@ -21,6 +21,7 @@ pub enum Profile {
Library, Library,
Tools, Tools,
User, User,
None,
} }
/// A list of historical hashes of `src/etc/vscode_settings.json`. /// A list of historical hashes of `src/etc/vscode_settings.json`.
@ -40,7 +41,7 @@ impl Profile {
pub fn all() -> impl Iterator<Item = Self> { pub fn all() -> impl Iterator<Item = Self> {
use Profile::*; use Profile::*;
// N.B. these are ordered by how they are displayed, not alphabetically // N.B. these are ordered by how they are displayed, not alphabetically
[Library, Compiler, Codegen, Tools, User].iter().copied() [Library, Compiler, Codegen, Tools, User, None].iter().copied()
} }
pub fn purpose(&self) -> String { pub fn purpose(&self) -> String {
@ -51,6 +52,7 @@ impl Profile {
Codegen => "Contribute to the compiler, and also modify LLVM or codegen", Codegen => "Contribute to the compiler, and also modify LLVM or codegen",
Tools => "Contribute to tools which depend on the compiler, but do not modify it directly (e.g. rustdoc, clippy, miri)", Tools => "Contribute to tools which depend on the compiler, but do not modify it directly (e.g. rustdoc, clippy, miri)",
User => "Install Rust from source", User => "Install Rust from source",
None => "Do not modify `config.toml`"
} }
.to_string() .to_string()
} }
@ -70,6 +72,7 @@ impl Profile {
Profile::Library => "library", Profile::Library => "library",
Profile::Tools => "tools", Profile::Tools => "tools",
Profile::User => "user", Profile::User => "user",
Profile::None => "none",
} }
} }
} }
@ -86,6 +89,7 @@ impl FromStr for Profile {
"tools" | "tool" | "rustdoc" | "clippy" | "miri" | "rustfmt" | "rls" => { "tools" | "tool" | "rustdoc" | "clippy" | "miri" | "rustfmt" | "rls" => {
Ok(Profile::Tools) Ok(Profile::Tools)
} }
"none" => Ok(Profile::None),
_ => Err(format!("unknown profile: '{}'", s)), _ => Err(format!("unknown profile: '{}'", s)),
} }
} }
@ -143,17 +147,8 @@ impl Step for Profile {
} }
pub fn setup(config: &Config, profile: Profile) { pub fn setup(config: &Config, profile: Profile) {
let stage_path = let suggestions: &[&str] = match profile {
["build", config.build.rustc_target_arg(), "stage1"].join(&MAIN_SEPARATOR.to_string()); Profile::Codegen | Profile::Compiler | Profile::None => &["check", "build", "test"],
if !rustup_installed() && profile != Profile::User {
eprintln!("`rustup` is not installed; cannot link `stage1` toolchain");
} else if stage_dir_exists(&stage_path[..]) && !config.dry_run() {
attempt_toolchain_link(&stage_path[..]);
}
let suggestions = match profile {
Profile::Codegen | Profile::Compiler => &["check", "build", "test"][..],
Profile::Tools => &[ Profile::Tools => &[
"check", "check",
"build", "build",
@ -166,11 +161,6 @@ pub fn setup(config: &Config, profile: Profile) {
Profile::User => &["dist", "build"], Profile::User => &["dist", "build"],
}; };
if !config.dry_run() {
t!(install_git_hook_maybe(&config));
t!(create_vscode_settings_maybe(&config));
}
println!(); println!();
println!("To get started, try one of the following commands:"); println!("To get started, try one of the following commands:");
@ -189,6 +179,9 @@ pub fn setup(config: &Config, profile: Profile) {
} }
fn setup_config_toml(path: &PathBuf, profile: Profile, config: &Config) { fn setup_config_toml(path: &PathBuf, profile: Profile, config: &Config) {
if profile == Profile::None {
return;
}
if path.exists() { if path.exists() {
eprintln!(); eprintln!();
eprintln!( eprintln!(
@ -216,6 +209,41 @@ fn setup_config_toml(path: &PathBuf, profile: Profile, config: &Config) {
println!("`x.py` will now use the configuration at {}", include_path.display()); println!("`x.py` will now use the configuration at {}", include_path.display());
} }
/// Creates a toolchain link for stage1 using `rustup`
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct Link;
impl Step for Link {
type Output = ();
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.alias("link")
}
fn make_run(run: RunConfig<'_>) {
if run.builder.config.dry_run() {
return;
}
if let [cmd] = &run.paths[..] {
if cmd.assert_single_path().path.as_path().as_os_str() == "link" {
run.builder.ensure(Link);
}
}
}
fn run(self, builder: &Builder<'_>) -> Self::Output {
let config = &builder.config;
if config.dry_run() {
return;
}
let stage_path =
["build", config.build.rustc_target_arg(), "stage1"].join(&MAIN_SEPARATOR.to_string());
if !rustup_installed() {
eprintln!("`rustup` is not installed; cannot link `stage1` toolchain");
} else if stage_dir_exists(&stage_path[..]) && !config.dry_run() {
attempt_toolchain_link(&stage_path[..]);
}
}
}
fn rustup_installed() -> bool { fn rustup_installed() -> bool {
Command::new("rustup") Command::new("rustup")
.arg("--version") .arg("--version")
@ -393,6 +421,35 @@ fn prompt_user(prompt: &str) -> io::Result<Option<PromptResult>> {
} }
} }
/// Installs `src/etc/pre-push.sh` as a Git hook
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct Hook;
impl Step for Hook {
type Output = ();
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.alias("hook")
}
fn make_run(run: RunConfig<'_>) {
if run.builder.config.dry_run() {
return;
}
if let [cmd] = &run.paths[..] {
if cmd.assert_single_path().path.as_path().as_os_str() == "hook" {
run.builder.ensure(Hook);
}
}
}
fn run(self, builder: &Builder<'_>) -> Self::Output {
let config = &builder.config;
if config.dry_run() {
return;
}
t!(install_git_hook_maybe(&config));
}
}
// install a git hook to automatically run tidy, if they want // install a git hook to automatically run tidy, if they want
fn install_git_hook_maybe(config: &Config) -> io::Result<()> { fn install_git_hook_maybe(config: &Config) -> io::Result<()> {
let git = t!(config.git().args(&["rev-parse", "--git-common-dir"]).output().map(|output| { let git = t!(config.git().args(&["rev-parse", "--git-common-dir"]).output().map(|output| {
@ -431,6 +488,35 @@ undesirable, simply delete the `pre-push` file from .git/hooks."
Ok(()) Ok(())
} }
/// Sets up or displays `src/etc/vscode_settings.json`
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct Vscode;
impl Step for Vscode {
type Output = ();
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.alias("vscode")
}
fn make_run(run: RunConfig<'_>) {
if run.builder.config.dry_run() {
return;
}
if let [cmd] = &run.paths[..] {
if cmd.assert_single_path().path.as_path().as_os_str() == "vscode" {
run.builder.ensure(Vscode);
}
}
}
fn run(self, builder: &Builder<'_>) -> Self::Output {
let config = &builder.config;
if config.dry_run() {
return;
}
t!(create_vscode_settings_maybe(&config));
}
}
/// Create a `.vscode/settings.json` file for rustc development, or just print it /// Create a `.vscode/settings.json` file for rustc development, or just print it
fn create_vscode_settings_maybe(config: &Config) -> io::Result<()> { fn create_vscode_settings_maybe(config: &Config) -> io::Result<()> {
let (current_hash, historical_hashes) = SETTINGS_HASHES.split_last().unwrap(); let (current_hash, historical_hashes) = SETTINGS_HASHES.split_last().unwrap();