Skip to content

Commit 09f9797

Browse files
committed
toolchain: add methods to list and remove targets
1 parent 2f88d79 commit 09f9797

File tree

3 files changed

+150
-13
lines changed

3 files changed

+150
-13
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
55

66
## Unreleased
77

8+
### Added
9+
10+
- New enum `toolchain::ToolchainError`
11+
- New method `Toolchain::remove_target`
12+
- New method `Toolchain::installed_targets`
13+
814
## [0.4.0] - 2019-12-23
915

1016
### Added

src/toolchain.rs

Lines changed: 143 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,22 @@ use std::path::Path;
1010

1111
pub(crate) const MAIN_TOOLCHAIN_NAME: &str = "stable";
1212

13+
/// Error caused by methods in the `toolchain` moodule.
14+
#[derive(Debug, failure::Fail)]
15+
#[non_exhaustive]
16+
pub enum ToolchainError {
17+
/// The toolchain is not installed in the workspace, but the called method requires it to be
18+
/// present. Use the [`Toolchain::Install`](struct.Toolchain.html#method.install) method to
19+
/// install it inside the workspace.
20+
#[fail(display = "the toolchain is not installed")]
21+
NotInstalled,
22+
/// Not every method can be called with every kind of toolchain. If you receive this error
23+
/// please check the documentation of the method you're calling to see which toolchains can you
24+
/// use with it.
25+
#[fail(display = "unsupported operation on this toolchain")]
26+
UnsupportedOperation,
27+
}
28+
1329
/// Metadata of a dist toolchain. See [`Toolchain`](struct.Toolchain.html) to create and get it.
1430
#[derive(serde::Serialize, serde::Deserialize, PartialEq, Eq, Hash, Debug, Clone)]
1531
pub struct DistToolchain {
@@ -39,6 +55,44 @@ impl DistToolchain {
3955
}
4056
}
4157

58+
#[derive(Copy, Clone)]
59+
enum RustupAction {
60+
Add,
61+
Remove,
62+
}
63+
64+
impl std::fmt::Display for RustupAction {
65+
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
66+
write!(
67+
f,
68+
"{}",
69+
match self {
70+
Self::Add => "add",
71+
Self::Remove => "remove",
72+
}
73+
)
74+
}
75+
}
76+
77+
#[derive(Copy, Clone)]
78+
enum RustupThing {
79+
Target,
80+
Component,
81+
}
82+
83+
impl std::fmt::Display for RustupThing {
84+
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
85+
write!(
86+
f,
87+
"{}",
88+
match self {
89+
Self::Target => "target",
90+
Self::Component => "component",
91+
}
92+
)
93+
}
94+
}
95+
4296
/// Metadata of a CI toolchain. See [`Toolchain`](struct.Toolchain.html) to create and get it.
4397
#[derive(serde::Serialize, serde::Deserialize, PartialEq, Eq, Hash, Debug, Clone)]
4498
pub struct CiToolchain {
@@ -182,41 +236,118 @@ impl Toolchain {
182236

183237
/// Download and install a component for the toolchain.
184238
pub fn add_component(&self, workspace: &Workspace, name: &str) -> Result<(), Error> {
185-
self.add_rustup_thing(workspace, "component", name)
239+
self.change_rustup_thing(workspace, RustupAction::Add, RustupThing::Component, name)
186240
}
187241

188242
/// Download and install a target for the toolchain.
243+
///
244+
/// If the toolchain is not installed in the workspace an error will be returned. This is only
245+
/// supported for dist toolchains.
189246
pub fn add_target(&self, workspace: &Workspace, name: &str) -> Result<(), Error> {
190-
self.add_rustup_thing(workspace, "target", name)
247+
self.change_rustup_thing(workspace, RustupAction::Add, RustupThing::Target, name)
191248
}
192249

193-
fn add_rustup_thing(
250+
/// Remove a target already installed for the toolchain.
251+
///
252+
/// If the toolchain is not installed in the workspace or the target is missing an error will
253+
/// be returned. This is only supported for dist toolchains.
254+
pub fn remove_target(&self, workspace: &Workspace, name: &str) -> Result<(), Error> {
255+
self.change_rustup_thing(workspace, RustupAction::Remove, RustupThing::Target, name)
256+
}
257+
258+
/// Return a list of installed targets for this toolchain.
259+
///
260+
/// If the toolchain is not installed an empty list is returned.
261+
pub fn installed_targets(&self, workspace: &Workspace) -> Result<Vec<String>, Error> {
262+
self.list_rustup_things(workspace, RustupThing::Target)
263+
}
264+
265+
fn change_rustup_thing(
194266
&self,
195267
workspace: &Workspace,
196-
thing: &str,
268+
action: RustupAction,
269+
thing: RustupThing,
197270
name: &str,
198271
) -> Result<(), Error> {
272+
let (log_action, log_action_ing) = match action {
273+
RustupAction::Add => ("add", "adding"),
274+
RustupAction::Remove => ("remove", "removing"),
275+
};
276+
277+
let thing = thing.to_string();
278+
let action = action.to_string();
279+
199280
if let ToolchainInner::CI { .. } = self.inner {
200-
bail!("installing {} on CI toolchains is not supported yet", thing);
281+
bail!(
282+
"{} {} on CI toolchains is not supported yet",
283+
log_action_ing,
284+
thing
285+
);
201286
}
202287
let toolchain_name = self.rustup_name();
203288
info!(
204-
"installing {} {} for toolchain {}",
205-
thing, name, toolchain_name
289+
"{} {} {} for toolchain {}",
290+
log_action_ing, thing, name, toolchain_name
206291
);
207292

208293
Command::new(workspace, &RUSTUP)
209-
.args(&[thing, "add", "--toolchain", &toolchain_name, name])
294+
.args(&[
295+
thing.as_str(),
296+
action.as_str(),
297+
"--toolchain",
298+
&toolchain_name,
299+
name,
300+
])
210301
.run()
211302
.with_context(|_| {
212303
format!(
213-
"unable to install {} {} for toolchain {} via rustup",
214-
thing, name, toolchain_name,
304+
"unable to {} {} {} for toolchain {} via rustup",
305+
log_action, thing, name, toolchain_name,
215306
)
216307
})?;
217308
Ok(())
218309
}
219310

311+
fn list_rustup_things(
312+
&self,
313+
workspace: &Workspace,
314+
thing: RustupThing,
315+
) -> Result<Vec<String>, Error> {
316+
let thing = thing.to_string();
317+
let name = if let Some(dist) = self.as_dist() {
318+
dist.name()
319+
} else {
320+
return Err(ToolchainError::UnsupportedOperation.into());
321+
};
322+
323+
let mut not_installed = false;
324+
let result = Command::new(workspace, &RUSTUP)
325+
.args(&[thing.as_str(), "list", "--installed", "--toolchain", name])
326+
.log_output(false)
327+
.process_lines(&mut |line| {
328+
if line.starts_with("error: toolchain ") && line.ends_with(" is not installed") {
329+
not_installed = true;
330+
}
331+
})
332+
.run_capture();
333+
334+
match result {
335+
Ok(out) => Ok(out
336+
.stdout_lines()
337+
.iter()
338+
.filter(|line| !line.is_empty())
339+
.cloned()
340+
.collect()),
341+
Err(_) if not_installed => Err(ToolchainError::NotInstalled.into()),
342+
Err(err) => Err(err
343+
.context(format!(
344+
"failed to read the list of installed {}s for {} with rustup",
345+
thing, name
346+
))
347+
.into()),
348+
}
349+
}
350+
220351
/// Remove the toolchain from the rustwide workspace, freeing up disk space.
221352
pub fn uninstall(&self, workspace: &Workspace) -> Result<(), Error> {
222353
let name = self.rustup_name();
@@ -305,7 +436,7 @@ impl Runnable for RustupProxy<'_> {
305436
}
306437
}
307438

308-
pub(crate) fn list_installed(rustup_home: &Path) -> Result<Vec<Toolchain>, Error> {
439+
pub(crate) fn list_installed_toolchains(rustup_home: &Path) -> Result<Vec<Toolchain>, Error> {
309440
let update_hashes = rustup_home.join("update-hashes");
310441

311442
let mut result = Vec::new();
@@ -395,7 +526,7 @@ mod tests {
395526
.join(format!("{}-alt", CI_SHA)),
396527
)?;
397528

398-
let res = super::list_installed(rustup_home.path())?;
529+
let res = super::list_installed_toolchains(rustup_home.path())?;
399530
assert_eq!(4, res.len());
400531
assert!(res.contains(&Toolchain::dist(DIST_NAME)));
401532
assert!(res.contains(&Toolchain::dist(LINK_NAME)));

src/workspace.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ impl Workspace {
241241
/// # }
242242
/// ```
243243
pub fn installed_toolchains(&self) -> Result<Vec<Toolchain>, Error> {
244-
crate::toolchain::list_installed(&self.rustup_home())
244+
crate::toolchain::list_installed_toolchains(&self.rustup_home())
245245
}
246246

247247
pub(crate) fn http_client(&self) -> &reqwest::Client {

0 commit comments

Comments
 (0)