Skip to content

Commit

Permalink
Support installation with additional components and targets
Browse files Browse the repository at this point in the history
Add support for "-c" and "-t" to `rustup toolchain install`
and to `rustup-init` itself.

Signed-off-by: Daniel Silverstone <[email protected]>
  • Loading branch information
kinnison committed Sep 27, 2019
1 parent f959736 commit bdcf194
Show file tree
Hide file tree
Showing 10 changed files with 187 additions and 9 deletions.
2 changes: 2 additions & 0 deletions rustup-init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ OPTIONS:
--default-toolchain <default-toolchain> Choose a default toolchain to install
--default-toolchain none Do not install any toolchains
--profile [minimal|default|complete] Choose a profile
-c, --component <components>... Component name to also install
-t, --target <targets>... Target name to also install
EOF
}

Expand Down
26 changes: 25 additions & 1 deletion src/cli/rustup_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,22 @@ pub fn cli() -> App<'static, 'static> {
.help("Don't perform self update when running the `rustup toolchain install` command")
.long("no-self-update")
.takes_value(false)
)
.arg(
Arg::with_name("components")
.help("Add specific components on installation")
.long("component")
.short("c")
.takes_value(true)
.multiple(true)
)
.arg(
Arg::with_name("targets")
.help("Add specific targets on installation")
.long("target")
.short("t")
.takes_value(true)
.multiple(true)
),
)
.subcommand(
Expand Down Expand Up @@ -741,7 +757,15 @@ fn update(cfg: &Cfg, m: &ArgMatches<'_>) -> Result<()> {
let toolchain = cfg.get_toolchain(name, false)?;

let status = if !toolchain.is_custom() {
Some(toolchain.install_from_dist(m.is_present("force"))?)
let components: Vec<_> = m
.values_of("components")
.map(|v| v.collect())
.unwrap_or_else(Vec::new);
let targets: Vec<_> = m
.values_of("targets")
.map(|v| v.collect())
.unwrap_or_else(Vec::new);
Some(toolchain.install_from_dist(m.is_present("force"), &components, &targets)?)
} else if !toolchain.exists() {
return Err(ErrorKind::InvalidToolchainName(toolchain.name().to_string()).into());
} else {
Expand Down
10 changes: 8 additions & 2 deletions src/cli/self_update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,13 @@ use std::fs;
use std::path::{Component, Path, PathBuf};
use std::process::{self, Command};

pub struct InstallOpts {
pub struct InstallOpts<'a> {
pub default_host_triple: String,
pub default_toolchain: String,
pub profile: String,
pub no_modify_path: bool,
pub components: &'a [&'a str],
pub targets: &'a [&'a str],
}

#[cfg(feature = "no-self-update")]
Expand Down Expand Up @@ -283,6 +285,8 @@ pub fn install(no_prompt: bool, verbose: bool, quiet: bool, mut opts: InstallOpt
&opts.default_toolchain,
&opts.profile,
&opts.default_host_triple,
opts.components,
opts.targets,
verbose,
quiet,
)?;
Expand Down Expand Up @@ -737,6 +741,8 @@ fn maybe_install_rust(
toolchain_str: &str,
profile_str: &str,
default_host_triple: &str,
components: &[&str],
targets: &[&str],
verbose: bool,
quiet: bool,
) -> Result<()> {
Expand All @@ -754,7 +760,7 @@ fn maybe_install_rust(
// Set host triple first as it will affect resolution of toolchain_str
cfg.set_default_host_triple(default_host_triple)?;
let toolchain = cfg.get_toolchain(toolchain_str, false)?;
let status = toolchain.install_from_dist(false)?;
let status = toolchain.install_from_dist(false, components, targets)?;
cfg.set_default(toolchain_str)?;
println!();
common::show_channel_update(&cfg, toolchain_str, Ok(status))?;
Expand Down
28 changes: 28 additions & 0 deletions src/cli/setup_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,22 @@ pub fn main() -> Result<()> {
.possible_values(Profile::names())
.default_value(Profile::default_name()),
)
.arg(
Arg::with_name("components")
.help("Component name to also install")
.long("component")
.short("c")
.takes_value(true)
.multiple(true),
)
.arg(
Arg::with_name("targets")
.help("Target name to also install")
.long("target")
.short("target")
.takes_value(true)
.multiple(true),
)
.arg(
Arg::with_name("no-modify-path")
.long("no-modify-path")
Expand All @@ -81,11 +97,23 @@ pub fn main() -> Result<()> {
.expect("Unreachable: Clap should supply a default");
let no_modify_path = matches.is_present("no-modify-path");

let components: Vec<_> = matches
.values_of("components")
.map(|v| v.collect())
.unwrap_or_else(Vec::new);

let targets: Vec<_> = matches
.values_of("targets")
.map(|v| v.collect())
.unwrap_or_else(Vec::new);

let opts = InstallOpts {
default_host_triple: default_host,
default_toolchain: default_toolchain.to_owned(),
profile: profile.to_owned(),
no_modify_path,
components: &components,
targets: &targets,
};

self_update::install(no_prompt, verbose, quiet, opts)?;
Expand Down
6 changes: 3 additions & 3 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ impl Cfg {
ErrorKind::OverrideToolchainNotInstalled(name.to_string())
})
} else {
toolchain.install_from_dist(false)?;
toolchain.install_from_dist(false, &[], &[])?;
Ok(Some((toolchain, reason)))
}
}
Expand Down Expand Up @@ -413,7 +413,7 @@ impl Cfg {
// Update toolchains and collect the results
let channels = channels.map(|(n, t)| {
let t = t.and_then(|t| {
let t = t.install_from_dist(force_update);
let t = t.install_from_dist(force_update, &[], &[]);
if let Err(ref e) = t {
(self.notify_handler)(Notification::NonFatalError(e));
}
Expand Down Expand Up @@ -465,7 +465,7 @@ impl Cfg {
) -> Result<Command> {
let toolchain = self.get_toolchain(toolchain, false)?;
if install_if_missing && !toolchain.exists() {
toolchain.install_from_dist(false)?;
toolchain.install_from_dist(false, &[], &[])?;
}

if let Some(cmd) = self.maybe_do_cargo_fallback(&toolchain, binary)? {
Expand Down
45 changes: 43 additions & 2 deletions src/dist/dist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,8 @@ pub fn update_from_dist<'a>(
prefix: &InstallPrefix,
force_update: bool,
old_date: Option<&str>,
components: &[&str],
targets: &[&str],
) -> Result<Option<String>> {
let fresh_install = !prefix.path().exists();
let hash_exists = update_hash.map(Path::exists).unwrap_or(false);
Expand All @@ -584,6 +586,8 @@ pub fn update_from_dist<'a>(
prefix,
force_update,
old_date,
components,
targets,
);

// Don't leave behind an empty / broken installation directory
Expand All @@ -603,6 +607,8 @@ fn update_from_dist_<'a>(
prefix: &InstallPrefix,
force_update: bool,
old_date: Option<&str>,
components: &[&str],
targets: &[&str],
) -> Result<Option<String>> {
let mut toolchain = toolchain.clone();
let mut fetched = String::new();
Expand Down Expand Up @@ -633,6 +639,8 @@ fn update_from_dist_<'a>(
profile,
prefix,
force_update,
components,
targets,
&mut fetched,
) {
Ok(v) => break Ok(v),
Expand Down Expand Up @@ -701,14 +709,24 @@ fn try_update_from_dist_<'a>(
profile: Option<Profile>,
prefix: &InstallPrefix,
force_update: bool,
components: &[&str],
targets: &[&str],
fetched: &mut String,
) -> Result<Option<String>> {
let toolchain_str = toolchain.to_string();
let manifestation = Manifestation::open(prefix.clone(), toolchain.target.clone())?;

// TODO: Add a notification about which manifest version is going to be used
(download.notify_handler)(Notification::DownloadingManifest(&toolchain_str));
match dl_v2_manifest(download, update_hash, toolchain) {
match dl_v2_manifest(
download,
if components.is_empty() && targets.is_empty() {
update_hash
} else {
None
},
toolchain,
) {
Ok(Some((m, hash))) => {
(download.notify_handler)(Notification::DownloadedManifest(
&m.date,
Expand All @@ -720,11 +738,34 @@ fn try_update_from_dist_<'a>(
None => Vec::new(),
};

let changes = Changes {
let mut changes = Changes {
explicit_add_components: profile_components,
remove_components: Vec::new(),
};

for component in components {
let mut component = crate::dist::manifest::Component::new(
component.to_string(),
Some(toolchain.target.clone()),
false,
);
if let Some(renamed) = m.rename_component(&component) {
component = renamed;
}
changes.explicit_add_components.push(component);
}

for target in targets {
let triple = TargetTriple::new(target);
changes
.explicit_add_components
.push(crate::dist::manifest::Component::new(
"rust-std".to_string(),
Some(triple),
false,
));
}

*fetched = m.date.clone();

return match manifestation.update(
Expand Down
8 changes: 8 additions & 0 deletions src/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ pub enum InstallMethod<'a> {
bool,
// currently installed date
Option<&'a str>,
// Extra components to install from dist
&'a [&'a str],
// Extra targets to install from dist
&'a [&'a str],
),
}

Expand Down Expand Up @@ -64,6 +68,8 @@ impl<'a> InstallMethod<'a> {
force_update,
exists,
old_date,
components,
targets,
) => {
let prefix = &InstallPrefix::from(path.to_owned());
let maybe_new_hash = dist::update_from_dist(
Expand All @@ -74,6 +80,8 @@ impl<'a> InstallMethod<'a> {
prefix,
force_update,
old_date,
components,
targets,
)?;

if let Some(hash) = maybe_new_hash {
Expand Down
11 changes: 10 additions & 1 deletion src/toolchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,12 @@ impl<'a> Toolchain<'a> {
}
}

pub fn install_from_dist(&self, force_update: bool) -> Result<UpdateStatus> {
pub fn install_from_dist(
&self,
force_update: bool,
components: &[&str],
targets: &[&str],
) -> Result<UpdateStatus> {
let update_hash = self.update_hash()?;
let old_date = self.get_manifest().ok().and_then(|m| m.map(|m| m.date));
self.install(InstallMethod::Dist(
Expand All @@ -173,6 +178,8 @@ impl<'a> Toolchain<'a> {
force_update,
self.exists(),
old_date.as_ref().map(|s| &**s),
components,
targets,
))
}

Expand All @@ -186,6 +193,8 @@ impl<'a> Toolchain<'a> {
false,
false,
None,
&[],
&[],
))
}
pub fn is_custom(&self) -> bool {
Expand Down
29 changes: 29 additions & 0 deletions tests/cli-self-upd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1258,3 +1258,32 @@ fn update_installs_clippy_cargo_and() {
assert!(cargo_clippy_path.exists());
});
}

#[test]
fn install_with_components_and_targets() {
setup(&|config| {
expect_ok(
config,
&[
"rustup-init",
"--default-toolchain",
"nightly",
"-y",
"-c",
"rls",
"-t",
clitools::CROSS_ARCH1,
],
);
expect_stdout_ok(
config,
&["rustup", "target", "list"],
&format!("{} (installed)", clitools::CROSS_ARCH1),
);
expect_stdout_ok(
config,
&["rustup", "component", "list"],
&format!("rls-{} (installed)", this_host_triple()),
);
})
}
31 changes: 31 additions & 0 deletions tests/cli-v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1109,3 +1109,34 @@ fn target_list_ignores_unavailable_targets() {
expect_not_stdout_ok(config, target_list, clitools::CROSS_ARCH1);
})
}

#[test]
fn install_with_component_and_target() {
setup(&|config| {
expect_ok(config, &["rustup", "default", "nightly"]);
expect_ok(
config,
&[
"rustup",
"toolchain",
"install",
"nightly",
"-c",
"rls",
"-t",
clitools::CROSS_ARCH1,
"--no-self-update",
],
);
expect_stdout_ok(
config,
&["rustup", "component", "list"],
&format!("rls-{} (installed)", this_host_triple()),
);
expect_stdout_ok(
config,
&["rustup", "target", "list"],
&format!("{} (installed)", clitools::CROSS_ARCH1),
);
})
}

0 comments on commit bdcf194

Please sign in to comment.