Skip to content

Commit bdcf194

Browse files
committed
Support installation with additional components and targets
Add support for "-c" and "-t" to `rustup toolchain install` and to `rustup-init` itself. Signed-off-by: Daniel Silverstone <[email protected]>
1 parent f959736 commit bdcf194

10 files changed

+187
-9
lines changed

rustup-init.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ OPTIONS:
3131
--default-toolchain <default-toolchain> Choose a default toolchain to install
3232
--default-toolchain none Do not install any toolchains
3333
--profile [minimal|default|complete] Choose a profile
34+
-c, --component <components>... Component name to also install
35+
-t, --target <targets>... Target name to also install
3436
EOF
3537
}
3638

src/cli/rustup_mode.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,22 @@ pub fn cli() -> App<'static, 'static> {
256256
.help("Don't perform self update when running the `rustup toolchain install` command")
257257
.long("no-self-update")
258258
.takes_value(false)
259+
)
260+
.arg(
261+
Arg::with_name("components")
262+
.help("Add specific components on installation")
263+
.long("component")
264+
.short("c")
265+
.takes_value(true)
266+
.multiple(true)
267+
)
268+
.arg(
269+
Arg::with_name("targets")
270+
.help("Add specific targets on installation")
271+
.long("target")
272+
.short("t")
273+
.takes_value(true)
274+
.multiple(true)
259275
),
260276
)
261277
.subcommand(
@@ -741,7 +757,15 @@ fn update(cfg: &Cfg, m: &ArgMatches<'_>) -> Result<()> {
741757
let toolchain = cfg.get_toolchain(name, false)?;
742758

743759
let status = if !toolchain.is_custom() {
744-
Some(toolchain.install_from_dist(m.is_present("force"))?)
760+
let components: Vec<_> = m
761+
.values_of("components")
762+
.map(|v| v.collect())
763+
.unwrap_or_else(Vec::new);
764+
let targets: Vec<_> = m
765+
.values_of("targets")
766+
.map(|v| v.collect())
767+
.unwrap_or_else(Vec::new);
768+
Some(toolchain.install_from_dist(m.is_present("force"), &components, &targets)?)
745769
} else if !toolchain.exists() {
746770
return Err(ErrorKind::InvalidToolchainName(toolchain.name().to_string()).into());
747771
} else {

src/cli/self_update.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,13 @@ use std::fs;
4545
use std::path::{Component, Path, PathBuf};
4646
use std::process::{self, Command};
4747

48-
pub struct InstallOpts {
48+
pub struct InstallOpts<'a> {
4949
pub default_host_triple: String,
5050
pub default_toolchain: String,
5151
pub profile: String,
5252
pub no_modify_path: bool,
53+
pub components: &'a [&'a str],
54+
pub targets: &'a [&'a str],
5355
}
5456

5557
#[cfg(feature = "no-self-update")]
@@ -283,6 +285,8 @@ pub fn install(no_prompt: bool, verbose: bool, quiet: bool, mut opts: InstallOpt
283285
&opts.default_toolchain,
284286
&opts.profile,
285287
&opts.default_host_triple,
288+
opts.components,
289+
opts.targets,
286290
verbose,
287291
quiet,
288292
)?;
@@ -737,6 +741,8 @@ fn maybe_install_rust(
737741
toolchain_str: &str,
738742
profile_str: &str,
739743
default_host_triple: &str,
744+
components: &[&str],
745+
targets: &[&str],
740746
verbose: bool,
741747
quiet: bool,
742748
) -> Result<()> {
@@ -754,7 +760,7 @@ fn maybe_install_rust(
754760
// Set host triple first as it will affect resolution of toolchain_str
755761
cfg.set_default_host_triple(default_host_triple)?;
756762
let toolchain = cfg.get_toolchain(toolchain_str, false)?;
757-
let status = toolchain.install_from_dist(false)?;
763+
let status = toolchain.install_from_dist(false, components, targets)?;
758764
cfg.set_default(toolchain_str)?;
759765
println!();
760766
common::show_channel_update(&cfg, toolchain_str, Ok(status))?;

src/cli/setup_mode.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,22 @@ pub fn main() -> Result<()> {
6161
.possible_values(Profile::names())
6262
.default_value(Profile::default_name()),
6363
)
64+
.arg(
65+
Arg::with_name("components")
66+
.help("Component name to also install")
67+
.long("component")
68+
.short("c")
69+
.takes_value(true)
70+
.multiple(true),
71+
)
72+
.arg(
73+
Arg::with_name("targets")
74+
.help("Target name to also install")
75+
.long("target")
76+
.short("target")
77+
.takes_value(true)
78+
.multiple(true),
79+
)
6480
.arg(
6581
Arg::with_name("no-modify-path")
6682
.long("no-modify-path")
@@ -81,11 +97,23 @@ pub fn main() -> Result<()> {
8197
.expect("Unreachable: Clap should supply a default");
8298
let no_modify_path = matches.is_present("no-modify-path");
8399

100+
let components: Vec<_> = matches
101+
.values_of("components")
102+
.map(|v| v.collect())
103+
.unwrap_or_else(Vec::new);
104+
105+
let targets: Vec<_> = matches
106+
.values_of("targets")
107+
.map(|v| v.collect())
108+
.unwrap_or_else(Vec::new);
109+
84110
let opts = InstallOpts {
85111
default_host_triple: default_host,
86112
default_toolchain: default_toolchain.to_owned(),
87113
profile: profile.to_owned(),
88114
no_modify_path,
115+
components: &components,
116+
targets: &targets,
89117
};
90118

91119
self_update::install(no_prompt, verbose, quiet, opts)?;

src/config.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ impl Cfg {
304304
ErrorKind::OverrideToolchainNotInstalled(name.to_string())
305305
})
306306
} else {
307-
toolchain.install_from_dist(false)?;
307+
toolchain.install_from_dist(false, &[], &[])?;
308308
Ok(Some((toolchain, reason)))
309309
}
310310
}
@@ -413,7 +413,7 @@ impl Cfg {
413413
// Update toolchains and collect the results
414414
let channels = channels.map(|(n, t)| {
415415
let t = t.and_then(|t| {
416-
let t = t.install_from_dist(force_update);
416+
let t = t.install_from_dist(force_update, &[], &[]);
417417
if let Err(ref e) = t {
418418
(self.notify_handler)(Notification::NonFatalError(e));
419419
}
@@ -465,7 +465,7 @@ impl Cfg {
465465
) -> Result<Command> {
466466
let toolchain = self.get_toolchain(toolchain, false)?;
467467
if install_if_missing && !toolchain.exists() {
468-
toolchain.install_from_dist(false)?;
468+
toolchain.install_from_dist(false, &[], &[])?;
469469
}
470470

471471
if let Some(cmd) = self.maybe_do_cargo_fallback(&toolchain, binary)? {

src/dist/dist.rs

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,8 @@ pub fn update_from_dist<'a>(
565565
prefix: &InstallPrefix,
566566
force_update: bool,
567567
old_date: Option<&str>,
568+
components: &[&str],
569+
targets: &[&str],
568570
) -> Result<Option<String>> {
569571
let fresh_install = !prefix.path().exists();
570572
let hash_exists = update_hash.map(Path::exists).unwrap_or(false);
@@ -584,6 +586,8 @@ pub fn update_from_dist<'a>(
584586
prefix,
585587
force_update,
586588
old_date,
589+
components,
590+
targets,
587591
);
588592

589593
// Don't leave behind an empty / broken installation directory
@@ -603,6 +607,8 @@ fn update_from_dist_<'a>(
603607
prefix: &InstallPrefix,
604608
force_update: bool,
605609
old_date: Option<&str>,
610+
components: &[&str],
611+
targets: &[&str],
606612
) -> Result<Option<String>> {
607613
let mut toolchain = toolchain.clone();
608614
let mut fetched = String::new();
@@ -633,6 +639,8 @@ fn update_from_dist_<'a>(
633639
profile,
634640
prefix,
635641
force_update,
642+
components,
643+
targets,
636644
&mut fetched,
637645
) {
638646
Ok(v) => break Ok(v),
@@ -701,14 +709,24 @@ fn try_update_from_dist_<'a>(
701709
profile: Option<Profile>,
702710
prefix: &InstallPrefix,
703711
force_update: bool,
712+
components: &[&str],
713+
targets: &[&str],
704714
fetched: &mut String,
705715
) -> Result<Option<String>> {
706716
let toolchain_str = toolchain.to_string();
707717
let manifestation = Manifestation::open(prefix.clone(), toolchain.target.clone())?;
708718

709719
// TODO: Add a notification about which manifest version is going to be used
710720
(download.notify_handler)(Notification::DownloadingManifest(&toolchain_str));
711-
match dl_v2_manifest(download, update_hash, toolchain) {
721+
match dl_v2_manifest(
722+
download,
723+
if components.is_empty() && targets.is_empty() {
724+
update_hash
725+
} else {
726+
None
727+
},
728+
toolchain,
729+
) {
712730
Ok(Some((m, hash))) => {
713731
(download.notify_handler)(Notification::DownloadedManifest(
714732
&m.date,
@@ -720,11 +738,34 @@ fn try_update_from_dist_<'a>(
720738
None => Vec::new(),
721739
};
722740

723-
let changes = Changes {
741+
let mut changes = Changes {
724742
explicit_add_components: profile_components,
725743
remove_components: Vec::new(),
726744
};
727745

746+
for component in components {
747+
let mut component = crate::dist::manifest::Component::new(
748+
component.to_string(),
749+
Some(toolchain.target.clone()),
750+
false,
751+
);
752+
if let Some(renamed) = m.rename_component(&component) {
753+
component = renamed;
754+
}
755+
changes.explicit_add_components.push(component);
756+
}
757+
758+
for target in targets {
759+
let triple = TargetTriple::new(target);
760+
changes
761+
.explicit_add_components
762+
.push(crate::dist::manifest::Component::new(
763+
"rust-std".to_string(),
764+
Some(triple),
765+
false,
766+
));
767+
}
768+
728769
*fetched = m.date.clone();
729770

730771
return match manifestation.update(

src/install.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ pub enum InstallMethod<'a> {
2828
bool,
2929
// currently installed date
3030
Option<&'a str>,
31+
// Extra components to install from dist
32+
&'a [&'a str],
33+
// Extra targets to install from dist
34+
&'a [&'a str],
3135
),
3236
}
3337

@@ -64,6 +68,8 @@ impl<'a> InstallMethod<'a> {
6468
force_update,
6569
exists,
6670
old_date,
71+
components,
72+
targets,
6773
) => {
6874
let prefix = &InstallPrefix::from(path.to_owned());
6975
let maybe_new_hash = dist::update_from_dist(
@@ -74,6 +80,8 @@ impl<'a> InstallMethod<'a> {
7480
prefix,
7581
force_update,
7682
old_date,
83+
components,
84+
targets,
7785
)?;
7886

7987
if let Some(hash) = maybe_new_hash {

src/toolchain.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,12 @@ impl<'a> Toolchain<'a> {
162162
}
163163
}
164164

165-
pub fn install_from_dist(&self, force_update: bool) -> Result<UpdateStatus> {
165+
pub fn install_from_dist(
166+
&self,
167+
force_update: bool,
168+
components: &[&str],
169+
targets: &[&str],
170+
) -> Result<UpdateStatus> {
166171
let update_hash = self.update_hash()?;
167172
let old_date = self.get_manifest().ok().and_then(|m| m.map(|m| m.date));
168173
self.install(InstallMethod::Dist(
@@ -173,6 +178,8 @@ impl<'a> Toolchain<'a> {
173178
force_update,
174179
self.exists(),
175180
old_date.as_ref().map(|s| &**s),
181+
components,
182+
targets,
176183
))
177184
}
178185

@@ -186,6 +193,8 @@ impl<'a> Toolchain<'a> {
186193
false,
187194
false,
188195
None,
196+
&[],
197+
&[],
189198
))
190199
}
191200
pub fn is_custom(&self) -> bool {

tests/cli-self-upd.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1258,3 +1258,32 @@ fn update_installs_clippy_cargo_and() {
12581258
assert!(cargo_clippy_path.exists());
12591259
});
12601260
}
1261+
1262+
#[test]
1263+
fn install_with_components_and_targets() {
1264+
setup(&|config| {
1265+
expect_ok(
1266+
config,
1267+
&[
1268+
"rustup-init",
1269+
"--default-toolchain",
1270+
"nightly",
1271+
"-y",
1272+
"-c",
1273+
"rls",
1274+
"-t",
1275+
clitools::CROSS_ARCH1,
1276+
],
1277+
);
1278+
expect_stdout_ok(
1279+
config,
1280+
&["rustup", "target", "list"],
1281+
&format!("{} (installed)", clitools::CROSS_ARCH1),
1282+
);
1283+
expect_stdout_ok(
1284+
config,
1285+
&["rustup", "component", "list"],
1286+
&format!("rls-{} (installed)", this_host_triple()),
1287+
);
1288+
})
1289+
}

tests/cli-v2.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1109,3 +1109,34 @@ fn target_list_ignores_unavailable_targets() {
11091109
expect_not_stdout_ok(config, target_list, clitools::CROSS_ARCH1);
11101110
})
11111111
}
1112+
1113+
#[test]
1114+
fn install_with_component_and_target() {
1115+
setup(&|config| {
1116+
expect_ok(config, &["rustup", "default", "nightly"]);
1117+
expect_ok(
1118+
config,
1119+
&[
1120+
"rustup",
1121+
"toolchain",
1122+
"install",
1123+
"nightly",
1124+
"-c",
1125+
"rls",
1126+
"-t",
1127+
clitools::CROSS_ARCH1,
1128+
"--no-self-update",
1129+
],
1130+
);
1131+
expect_stdout_ok(
1132+
config,
1133+
&["rustup", "component", "list"],
1134+
&format!("rls-{} (installed)", this_host_triple()),
1135+
);
1136+
expect_stdout_ok(
1137+
config,
1138+
&["rustup", "target", "list"],
1139+
&format!("{} (installed)", clitools::CROSS_ARCH1),
1140+
);
1141+
})
1142+
}

0 commit comments

Comments
 (0)