Skip to content

Commit

Permalink
refactor(cli): rewrite rustup-init with clap_derive
Browse files Browse the repository at this point in the history
  • Loading branch information
rami3l committed Jan 19, 2024
1 parent 9955b9f commit 1d30214
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 144 deletions.
19 changes: 19 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ test = ["dep:walkdir"]
anyhow.workspace = true
cfg-if = "1.0"
chrono = { version = "0.4", default-features = false, features = ["std"] }
clap = { version = "4", features = ["wrap_help"] }
clap = { version = "4", features = ["derive", "wrap_help"] }
clap_complete = "4"
derivative.workspace = true
download = { path = "download", default-features = false }
Expand Down
12 changes: 6 additions & 6 deletions rustup-init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,16 @@ Options:
-q, --quiet
Disable progress output
-y
Disable confirmation prompt.
--default-host <default-host>
Disable confirmation prompt
--default-host <DEFAULT_HOST>
Choose a default host triple
--default-toolchain <default-toolchain>
--default-toolchain <DEFAULT_TOOLCHAIN>
Choose a default toolchain to install. Use 'none' to not install any toolchains at all
--profile <profile>
--profile <PROFILE>
[default: default] [possible values: minimal, default, complete]
-c, --component <components>...
-c, --components <COMPONENTS>...
Component name to also install
-t, --target <targets>...
-t, --targets <TARGETS>...
Target name to also install
--no-update-default-toolchain
Don't update any existing default toolchain after install
Expand Down
217 changes: 93 additions & 124 deletions src/cli/setup_mode.rs
Original file line number Diff line number Diff line change
@@ -1,158 +1,127 @@
use anyhow::Result;
use clap::{builder::PossibleValuesParser, value_parser, Arg, ArgAction, Command};
use clap::{builder::PossibleValuesParser, Parser};

use crate::{
cli::{
common,
self_update::{self, InstallOpts},
},
currentprocess::{argsource::ArgSource, filesource::StdoutSource},
currentprocess::filesource::StdoutSource,
dist::dist::Profile,
process,
toolchain::names::MaybeOfficialToolchainName,
utils::utils,
};

/// The installer for rustup
#[derive(Debug, Parser)]
#[command(
name = "rustup-init",
bin_name = "rustup-init[EXE]",
version = common::version(),
before_help = format!("rustup-init {}", common::version()),
)]
struct RustupInit {
/// Enable verbose output
#[arg(short, long)]
verbose: bool,

/// Disable progress output
#[arg(short, long)]
quiet: bool,

/// Disable confirmation prompt
#[arg(short = 'y')]
no_prompt: bool,

/// Choose a default host triple
#[arg(long)]
default_host: Option<String>,

/// Choose a default toolchain to install. Use 'none' to not install any toolchains at all
#[arg(long)]
default_toolchain: Option<MaybeOfficialToolchainName>,

#[arg(
long,
value_parser = PossibleValuesParser::new(Profile::names()),
default_value = Profile::default_name(),
)]
profile: String,

/// Component name to also install
#[arg(short, long, value_delimiter = ',', num_args = 1..)]
components: Vec<String>,

/// Target name to also install
#[arg(short, long, value_delimiter = ',', num_args = 1..)]
targets: Vec<String>,

/// Don't update any existing default toolchain after install
#[arg(long)]
no_update_default_toolchain: bool,

/// Don't configure the PATH environment variable
#[arg(long)]
no_modify_path: bool,

/// Secret command used during self-update. Not for users
#[arg(long, hide = true)]
self_replace: bool,

/// Internal testament dump used during CI. Not for users
#[arg(long, hide = true)]
dump_testament: bool,
}

#[cfg_attr(feature = "otel", tracing::instrument)]
pub fn main() -> Result<utils::ExitCode> {
use clap::error::ErrorKind;

let args: Vec<_> = process().args().collect();
let arg1 = args.get(1).map(|a| &**a);
let RustupInit {
verbose,
quiet,
no_prompt,
default_host,
default_toolchain,
profile,
components,
targets,
no_update_default_toolchain,
no_modify_path,
self_replace,
dump_testament,
} = match RustupInit::try_parse() {
Ok(args) => args,
Err(e) if [ErrorKind::DisplayHelp, ErrorKind::DisplayVersion].contains(&e.kind()) => {
write!(process().stdout().lock(), "{e}")?;
return Ok(utils::ExitCode(0));
}
Err(e) => return Err(e.into()),
};

// Secret command used during self-update. Not for users.
if arg1 == Some("--self-replace") {
if self_replace {
return self_update::self_replace();
}

// Internal testament dump used during CI. Not for users.
if arg1 == Some("--dump-testament") {
if dump_testament {
common::dump_testament()?;
return Ok(utils::ExitCode(0));
}

// NOTICE: If you change anything here, please make the same changes in rustup-init.sh
let cli = Command::new("rustup-init")
.version(common::version())
.before_help(format!("rustup-init {}", common::version()))
.about("The installer for rustup")
.arg(
Arg::new("verbose")
.short('v')
.long("verbose")
.help("Enable verbose output")
.action(ArgAction::SetTrue),
)
.arg(
Arg::new("quiet")
.conflicts_with("verbose")
.short('q')
.long("quiet")
.help("Disable progress output")
.action(ArgAction::SetTrue),
)
.arg(
Arg::new("no-prompt")
.short('y')
.help("Disable confirmation prompt.")
.action(ArgAction::SetTrue),
)
.arg(
Arg::new("default-host")
.long("default-host")
.num_args(1)
.help("Choose a default host triple"),
)
.arg(
Arg::new("default-toolchain")
.long("default-toolchain")
.num_args(1)
.help("Choose a default toolchain to install. Use 'none' to not install any toolchains at all")
.value_parser(value_parser!(MaybeOfficialToolchainName))
)
.arg(
Arg::new("profile")
.long("profile")
.value_parser(PossibleValuesParser::new(Profile::names()))
.default_value(Profile::default_name()),
)
.arg(
Arg::new("components")
.help("Component name to also install")
.long("component")
.short('c')
.num_args(1..)
.use_value_delimiter(true)
.action(ArgAction::Append),
)
.arg(
Arg::new("targets")
.help("Target name to also install")
.long("target")
.short('t')
.num_args(1..)
.use_value_delimiter(true)
.action(ArgAction::Append),
)
.arg(
Arg::new("no-update-default-toolchain")
.long("no-update-default-toolchain")
.help("Don't update any existing default toolchain after install")
.action(ArgAction::SetTrue),
)
.arg(
Arg::new("no-modify-path")
.long("no-modify-path")
.help("Don't configure the PATH environment variable")
.action(ArgAction::SetTrue),
);

let matches = match cli.try_get_matches_from(process().args_os()) {
Ok(matches) => matches,
Err(e) if [ErrorKind::DisplayHelp, ErrorKind::DisplayVersion].contains(&e.kind()) => {
write!(process().stdout().lock(), "{e}")?;
return Ok(utils::ExitCode(0));
}
Err(e) => return Err(e.into()),
};
let no_prompt = matches.get_flag("no-prompt");
let verbose = matches.get_flag("verbose");
let quiet = matches.get_flag("quiet");
let default_host = matches
.get_one::<String>("default-host")
.map(ToOwned::to_owned);
let default_toolchain = matches
.get_one::<MaybeOfficialToolchainName>("default-toolchain")
.map(ToOwned::to_owned);
let profile = matches
.get_one::<String>("profile")
.expect("Unreachable: Clap should supply a default");
let no_modify_path = matches.get_flag("no-modify-path");
let no_update_toolchain = matches.get_flag("no-update-default-toolchain");

let components: Vec<_> = matches
.get_many::<String>("components")
.map(|v| v.map(|s| &**s).collect())
.unwrap_or_else(Vec::new);

let targets: Vec<_> = matches
.get_many::<String>("targets")
.map(|v| v.map(|s| &**s).collect())
.unwrap_or_else(Vec::new);
if &profile == "complete" {
warn!("{}", common::WARN_COMPLETE_PROFILE);
}

let opts = InstallOpts {
default_host_triple: default_host,
default_toolchain,
profile: profile.to_owned(),
profile,
no_modify_path,
no_update_toolchain,
components: &components,
targets: &targets,
no_update_toolchain: no_update_default_toolchain,
components: &components.iter().map(|s| &**s).collect::<Vec<_>>(),
targets: &targets.iter().map(|s| &**s).collect::<Vec<_>>(),
};

if profile == "complete" {
warn!("{}", common::WARN_COMPLETE_PROFILE);
}

self_update::install(no_prompt, verbose, quiet, opts)
}
2 changes: 1 addition & 1 deletion src/toolchain/names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ pub(crate) fn maybe_resolvable_toolchainame_parser(

/// ResolvableToolchainName + none, for overriding default-has-a-value
/// situations in the CLI with an official toolchain name or none
#[derive(Clone)]
#[derive(Debug, Clone)]
pub(crate) enum MaybeOfficialToolchainName {
None,
Some(PartialToolchainDesc),
Expand Down
12 changes: 6 additions & 6 deletions tests/suite/cli-ui/rustup-init/rustup-init_help_flag_stdout.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ Options:
-q, --quiet
Disable progress output
-y
Disable confirmation prompt.
--default-host <default-host>
Disable confirmation prompt
--default-host <DEFAULT_HOST>
Choose a default host triple
--default-toolchain <default-toolchain>
--default-toolchain <DEFAULT_TOOLCHAIN>
Choose a default toolchain to install. Use 'none' to not install any toolchains at all
--profile <profile>
--profile <PROFILE>
[default: default] [possible values: minimal, default, complete]
-c, --component <components>...
-c, --components <COMPONENTS>...
Component name to also install
-t, --target <targets>...
-t, --targets <TARGETS>...
Target name to also install
--no-update-default-toolchain
Don't update any existing default toolchain after install
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ Options:
-q, --quiet
Disable progress output
-y
Disable confirmation prompt.
--default-host <default-host>
Disable confirmation prompt
--default-host <DEFAULT_HOST>
Choose a default host triple
--default-toolchain <default-toolchain>
--default-toolchain <DEFAULT_TOOLCHAIN>
Choose a default toolchain to install. Use 'none' to not install any toolchains at all
--profile <profile>
--profile <PROFILE>
[default: default] [possible values: minimal, default, complete]
-c, --component <components>...
-c, --components <COMPONENTS>...
Component name to also install
-t, --target <targets>...
-t, --targets <TARGETS>...
Target name to also install
--no-update-default-toolchain
Don't update any existing default toolchain after install
Expand Down

0 comments on commit 1d30214

Please sign in to comment.