Skip to content

Commit c9419ef

Browse files
committed
Decouple install toolchain handling, add error types for it
1 parent c9f3000 commit c9419ef

File tree

5 files changed

+245
-85
lines changed

5 files changed

+245
-85
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,4 @@ crates/shader-crate-template/manifest.json
2727
crates/shader-crate-template/rust_gpu_shader_crate_template.spv
2828

2929
.idea
30+
.vscode

crates/cargo-gpu-cache/src/install_toolchain.rs

Lines changed: 22 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -2,98 +2,41 @@
22
33
use anyhow::Context as _;
44
use crossterm::tty::IsTty as _;
5+
use rustc_codegen_spirv_cache::toolchain::{
6+
ensure_toolchain_installation, REQUIRED_TOOLCHAIN_COMPONENTS,
7+
};
58

6-
/// Use `rustup` to install the toolchain and components, if not already installed.
7-
///
8-
/// Pretty much runs:
9-
///
10-
/// * rustup toolchain add nightly-2024-04-24
11-
/// * rustup component add --toolchain nightly-2024-04-24 rust-src rustc-dev llvm-tools
9+
use crate::user_output;
10+
11+
/// Uses `rustup` to install the toolchain and all the [required components](REQUIRED_TOOLCHAIN_COMPONENTS),
12+
/// if not already installed, while additionally asking for the user consent.
1213
pub fn ensure_toolchain_and_components_exist(
1314
channel: &str,
1415
skip_toolchain_install_consent: bool,
1516
) -> anyhow::Result<()> {
16-
// Check for the required toolchain
17-
let output_toolchain_list = std::process::Command::new("rustup")
18-
.args(["toolchain", "list"])
19-
.output()
20-
.context("running rustup command")?;
21-
anyhow::ensure!(
22-
output_toolchain_list.status.success(),
23-
"could not list installed toolchains"
24-
);
25-
let string_toolchain_list = String::from_utf8_lossy(&output_toolchain_list.stdout);
26-
if string_toolchain_list
27-
.split_whitespace()
28-
.any(|toolchain| toolchain.starts_with(channel))
29-
{
30-
log::debug!("toolchain {channel} is already installed");
31-
} else {
17+
let on_toolchain_install = || {
3218
let message = format!("Rust {channel} with `rustup`");
3319
get_consent_for_toolchain_install(
3420
format!("Install {message}").as_ref(),
3521
skip_toolchain_install_consent,
3622
)?;
37-
crate::user_output!("Installing {message}\n")?;
38-
39-
let output_toolchain_add = std::process::Command::new("rustup")
40-
.args(["toolchain", "add"])
41-
.arg(channel)
42-
.stdout(std::process::Stdio::inherit())
43-
.stderr(std::process::Stdio::inherit())
44-
.output()
45-
.context("adding toolchain")?;
46-
anyhow::ensure!(
47-
output_toolchain_add.status.success(),
48-
"could not install required toolchain"
23+
log::debug!("installing toolchain {channel}");
24+
user_output!("Installing {message}\n")?;
25+
Ok(())
26+
};
27+
let on_components_install = || {
28+
let message = format!(
29+
"components {REQUIRED_TOOLCHAIN_COMPONENTS:?} for toolchain {channel} with `rustup`"
4930
);
50-
}
51-
52-
// Check for the required components
53-
let output_component_list = std::process::Command::new("rustup")
54-
.args(["component", "list", "--toolchain"])
55-
.arg(channel)
56-
.output()
57-
.context("getting toolchain list")?;
58-
anyhow::ensure!(
59-
output_component_list.status.success(),
60-
"could not list installed components"
61-
);
62-
let string_component_list = String::from_utf8_lossy(&output_component_list.stdout);
63-
let required_components = ["rust-src", "rustc-dev", "llvm-tools"];
64-
let installed_components = string_component_list.lines().collect::<Vec<_>>();
65-
let all_components_installed = required_components.iter().all(|component| {
66-
installed_components.iter().any(|installed_component| {
67-
let is_component = installed_component.starts_with(component);
68-
let is_installed = installed_component.ends_with("(installed)");
69-
is_component && is_installed
70-
})
71-
});
72-
if all_components_installed {
73-
log::debug!("all required components are installed");
74-
} else {
75-
let message = "toolchain components [rust-src, rustc-dev, llvm-tools] with `rustup`";
7631
get_consent_for_toolchain_install(
7732
format!("Install {message}").as_ref(),
7833
skip_toolchain_install_consent,
7934
)?;
80-
crate::user_output!("Installing {message}\n")?;
81-
82-
let output_component_add = std::process::Command::new("rustup")
83-
.args(["component", "add", "--toolchain"])
84-
.arg(channel)
85-
.args(["rust-src", "rustc-dev", "llvm-tools"])
86-
.stdout(std::process::Stdio::inherit())
87-
.stderr(std::process::Stdio::inherit())
88-
.output()
89-
.context("adding rustup component")?;
90-
anyhow::ensure!(
91-
output_component_add.status.success(),
92-
"could not install required components"
93-
);
94-
}
95-
96-
Ok(())
35+
log::debug!("installing required components of toolchain {channel}");
36+
user_output!("Installing {message}\n")?;
37+
Ok(())
38+
};
39+
ensure_toolchain_installation(channel, on_toolchain_install, on_components_install)
9740
}
9841

9942
/// Prompt user if they want to install a new Rust toolchain.
@@ -106,13 +49,13 @@ fn get_consent_for_toolchain_install(
10649
}
10750

10851
if !std::io::stdout().is_tty() {
109-
log::error!("Attempted to ask for consent when there's no TTY");
52+
log::error!("attempted to ask for consent when there's no TTY");
11053
anyhow::bail!("no TTY detected, so can't ask for consent to install Rust toolchain")
11154
}
11255

11356
log::debug!("asking for consent to install the required toolchain");
11457
crossterm::terminal::enable_raw_mode().context("enabling raw mode")?;
115-
crate::user_output!("{prompt} [y/n]: ")?;
58+
user_output!("{prompt} [y/n]: ")?;
11659
let mut input = crossterm::event::read().context("reading crossterm event")?;
11760

11861
if let crossterm::event::Event::Key(crossterm::event::KeyEvent {

crates/rustc_codegen_spirv-cache/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,4 @@ pub mod cache;
2424
pub mod metadata;
2525
pub mod spirv_source;
2626
pub mod target_specs;
27+
pub mod toolchain;

crates/rustc_codegen_spirv-cache/src/spirv_source.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ pub fn rust_gpu_toolchain_channel(
264264
let path = rustc_codegen_spirv
265265
.manifest_path
266266
.parent()
267-
.ok_or(RustGpuToolchainChannelError::PackageAtRoot)?;
267+
.ok_or(RustGpuToolchainChannelError::ManifestAtRoot)?;
268268
let build_script = path.join("build.rs");
269269

270270
log::debug!("Parsing `build.rs` at {build_script:?} for the used toolchain");
@@ -308,7 +308,7 @@ pub fn rust_gpu_toolchain_channel(
308308

309309
let range = start..end;
310310
let Some(channel) = channel_line.get(range.clone()) else {
311-
let err = RustGpuToolchainChannelError::InvalidRange {
311+
let err = RustGpuToolchainChannelError::InvalidChannelSlice {
312312
range,
313313
channel_line: channel_line.to_owned(),
314314
build_script,
@@ -322,10 +322,10 @@ pub fn rust_gpu_toolchain_channel(
322322
#[derive(Debug, thiserror::Error)]
323323
#[non_exhaustive]
324324
pub enum RustGpuToolchainChannelError {
325-
/// Package is located at the root of the file system
325+
/// Manifest of the package is located at the root of the file system
326326
/// and cannot have a parent.
327-
#[error("package located at root")]
328-
PackageAtRoot,
327+
#[error("package manifest was located at root")]
328+
ManifestAtRoot,
329329
/// Build script file is not valid or does not exist.
330330
#[error("invalid build script {build_script}: {source}")]
331331
InvalidBuildScript {
@@ -356,7 +356,7 @@ pub enum RustGpuToolchainChannelError {
356356
},
357357
/// The range to slice the channel line is not valid.
358358
#[error("cannot slice line \"{channel_line}\" of {build_script:?} by range {range:?}")]
359-
InvalidRange {
359+
InvalidChannelSlice {
360360
/// The invalid range.
361361
range: Range<usize>,
362362
/// The line containing the channel information.

0 commit comments

Comments
 (0)