From 2bbc0fd72f4c2e59095fe38424ee5f8169055e22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emil=20Gardstr=C3=B6m?= Date: Sat, 25 Mar 2023 13:13:42 +0100 Subject: [PATCH] ensure sysroot is correct --- src/bin/commands/containers.rs | 11 +++-- src/lib.rs | 17 +++++-- src/rustc.rs | 62 +++++++++++++++++-------- src/rustup.rs | 83 ++++++++++++++++++++++++++++++---- 4 files changed, 136 insertions(+), 37 deletions(-) diff --git a/src/bin/commands/containers.rs b/src/bin/commands/containers.rs index 0043280d6..e8b32dcc4 100644 --- a/src/bin/commands/containers.rs +++ b/src/bin/commands/containers.rs @@ -1,10 +1,10 @@ use std::io; use clap::{Args, Subcommand}; -use cross::docker::ImagePlatform; use cross::rustc::{QualifiedToolchain, Toolchain}; use cross::shell::{MessageInfo, Stream}; use cross::{docker, CommandExt, TargetTriple}; +use cross::{docker::ImagePlatform, rustup::ToolchainMode}; #[derive(Args, Debug)] pub struct ListVolumes { @@ -392,7 +392,8 @@ pub fn create_persistent_volume( channel: Option<&Toolchain>, msg_info: &mut MessageInfo, ) -> cross::Result<()> { - let mut toolchain = toolchain_or_target(&toolchain, msg_info)?; + let installed_toolchains = cross::rustup::installed_toolchains(msg_info)?; + let mut toolchain = toolchain_or_target(&toolchain, &installed_toolchains, msg_info)?; if let Some(channel) = channel { toolchain.channel = channel.channel.clone(); }; @@ -460,7 +461,8 @@ pub fn remove_persistent_volume( channel: Option<&Toolchain>, msg_info: &mut MessageInfo, ) -> cross::Result<()> { - let mut toolchain = toolchain_or_target(&toolchain, msg_info)?; + let installed_toolchains = cross::rustup::installed_toolchains(msg_info)?; + let mut toolchain = toolchain_or_target(&toolchain, &installed_toolchains, msg_info)?; if let Some(channel) = channel { toolchain.channel = channel.channel.clone(); }; @@ -557,10 +559,11 @@ pub fn remove_all_containers( fn toolchain_or_target( s: &str, + installed_toolchains: &[(String, ToolchainMode, std::path::PathBuf)], msg_info: &mut MessageInfo, ) -> Result { let config = cross::config::Config::new(None); - let mut toolchain = QualifiedToolchain::default(&config, msg_info)?; + let mut toolchain = QualifiedToolchain::default(&config, installed_toolchains, msg_info)?; let target_list = cross::rustc::target_list(msg_info)?; if target_list.contains(s) { toolchain.replace_host(&ImagePlatform::from_target(s.into())?); diff --git a/src/lib.rs b/src/lib.rs index 798177f42..2f4b8f591 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,6 +55,7 @@ use color_eyre::{Help, SectionExt}; use config::Config; use rustc::{QualifiedToolchain, Toolchain}; use rustc_version::Channel; +use rustup::ToolchainMode; use serde::{Deserialize, Serialize, Serializer}; pub use self::cargo::{cargo_command, cargo_metadata_with_args, CargoMetadata, Subcommand}; @@ -525,10 +526,11 @@ pub fn run( uses_zig, uses_build_std, zig_version, - toolchain, + mut toolchain, is_remote, engine, image, + installed_toolchains, } = match setup(&host_version_meta, &metadata, &args, target_list, msg_info)? { Some(setup) => setup, _ => { @@ -547,6 +549,11 @@ pub fn run( "toolchain `{toolchain}` may not run on image `{image}`" ))?; } + + let available_targets = + rustup::setup_rustup(&toolchain, &installed_toolchains, msg_info)?; + toolchain.ensure_sysroot(installed_toolchains, msg_info)?; + let mut is_nightly = toolchain.channel.contains("nightly"); let mut rustc_version = None; if let Some((version, channel, commit)) = toolchain.rustc_version()? { @@ -563,8 +570,6 @@ pub fn run( rustc_version = Some(version); } - let available_targets = rustup::setup_rustup(&toolchain, msg_info)?; - rustup::setup_components( &target, uses_xargo, @@ -739,7 +744,9 @@ pub fn setup( return Ok(None); } }; - let default_toolchain = QualifiedToolchain::default(&config, msg_info)?; + let installed_toolchains = rustup::installed_toolchains(msg_info)?; + + let default_toolchain = QualifiedToolchain::default(&config, &installed_toolchains, msg_info)?; let mut toolchain = if let Some(channel) = &args.channel { let picked_toolchain: Toolchain = channel.parse()?; @@ -774,6 +781,7 @@ To override the toolchain mounted in the image, set `target.{target}.image.toolc is_remote, engine, image, + installed_toolchains, })) } @@ -789,6 +797,7 @@ pub struct CrossSetup { pub is_remote: bool, pub engine: docker::Engine, pub image: docker::Image, + pub installed_toolchains: Vec<(String, ToolchainMode, PathBuf)>, } #[derive(PartialEq, Eq, Debug)] diff --git a/src/rustc.rs b/src/rustc.rs index ef50475d2..05fe31c6a 100644 --- a/src/rustc.rs +++ b/src/rustc.rs @@ -4,11 +4,11 @@ use std::process::Command; use rustc_version::{Version, VersionMeta}; use serde::Deserialize; -use crate::docker::ImagePlatform; use crate::errors::*; use crate::extensions::{env_program, CommandExt}; use crate::shell::MessageInfo; use crate::TargetTriple; +use crate::{docker::ImagePlatform, rustup::ToolchainMode}; #[derive(Debug)] pub struct TargetList { @@ -196,19 +196,30 @@ impl QualifiedToolchain { } /// Grab the current default toolchain - pub fn default(config: &crate::config::Config, msg_info: &mut MessageInfo) -> Result { - let sysroot = sysroot(msg_info)?; - - let default_toolchain_name = sysroot - .file_name() - .ok_or_else(|| eyre::eyre!("couldn't get name of active toolchain"))? - .to_str() - .ok_or_else(|| eyre::eyre!("toolchain was not utf-8"))?; + pub fn default( + config: &crate::config::Config, + installed_toolchains: &[(String, ToolchainMode, PathBuf)], + msg_info: &mut MessageInfo, + ) -> Result { + let (toolchain_name, sysroot) = if let Some((toolchain_name, _, sysroot)) = + installed_toolchains + .iter() + .find(|(_, mode, _)| mode.is_overriden()) + { + (toolchain_name, sysroot) + } else if let Some((toolchain_name, _, sysroot)) = installed_toolchains + .iter() + .find(|(_, mode, _)| mode.is_defaulted()) + { + (toolchain_name, sysroot) + } else { + eyre::bail!("no default toolchain found"); + }; if !config.custom_toolchain() { - QualifiedToolchain::parse(sysroot.clone(), default_toolchain_name, config, msg_info) + QualifiedToolchain::parse(sysroot.clone(), toolchain_name, config, msg_info) } else { - QualifiedToolchain::custom(default_toolchain_name, &sysroot, config, msg_info) + QualifiedToolchain::custom(toolchain_name, sysroot, config, msg_info) } } @@ -232,6 +243,26 @@ impl QualifiedToolchain { pub fn set_sysroot(&mut self, convert: impl Fn(&Path) -> PathBuf) { self.sysroot = convert(&self.sysroot); } + + pub fn ensure_sysroot( + &mut self, + installed_toolchains: Vec<(String, ToolchainMode, std::path::PathBuf)>, + msg_info: &mut MessageInfo, + ) -> Result<()> { + self.sysroot = if let Some((_, _, sysroot)) = installed_toolchains + .iter() + .find(|(name, _, _)| &self.full == name) + { + sysroot.clone() + } else { + let (_, _, sysroot) = crate::rustup::installed_toolchains(msg_info)? + .into_iter() + .find(|(name, _, _)| &self.full == name) + .ok_or_else(|| eyre::eyre!("toolchain not found"))?; + sysroot + }; + Ok(()) + } } impl std::fmt::Display for QualifiedToolchain { @@ -364,15 +395,6 @@ pub fn target_list(msg_info: &mut MessageInfo) -> Result { }) } -pub fn sysroot(msg_info: &mut MessageInfo) -> Result { - let stdout = rustc_command() - .args(["--print", "sysroot"]) - .run_and_get_stdout(msg_info)? - .trim() - .to_owned(); - Ok(PathBuf::from(stdout)) -} - pub fn version_meta() -> Result { rustc_version::version_meta().wrap_err("couldn't fetch the `rustc` version") } diff --git a/src/rustup.rs b/src/rustup.rs index 90b8b4f97..05516ee10 100644 --- a/src/rustup.rs +++ b/src/rustup.rs @@ -30,12 +30,13 @@ impl AvailableTargets { pub fn setup_rustup( toolchain: &QualifiedToolchain, + installed_toolchains: &[(String, ToolchainMode, PathBuf)], msg_info: &mut MessageInfo, ) -> Result { if !toolchain.is_custom - && !installed_toolchains(msg_info)? - .into_iter() - .any(|t| t == toolchain.to_string()) + && !installed_toolchains + .iter() + .any(|(t, _, _)| t == &toolchain.to_string()) { install_toolchain(toolchain, msg_info)?; } @@ -83,18 +84,82 @@ pub fn active_toolchain(msg_info: &mut MessageInfo) -> Result { .to_owned()) } -pub fn installed_toolchains(msg_info: &mut MessageInfo) -> Result> { +#[derive(Debug)] +pub enum ToolchainMode { + Override, + Default, + DefaultOverride, + None, + Other, +} + +impl ToolchainMode { + /// Returns `true` if the toolchain mode is [`Override`] or [`DefaultOverride`]. + /// + /// [`Override`]: ToolchainMode::Override + /// [`DefaultOverride`]: ToolchainMode::DefaultOverride + #[must_use] + pub fn is_overriden(&self) -> bool { + matches!(self, Self::Override | Self::DefaultOverride) + } + + /// Returns `true` if the toolchain mode is [`None`]. + /// + /// [`None`]: ToolchainMode::None + #[must_use] + pub fn is_none(&self) -> bool { + matches!(self, Self::None) + } + + /// Returns `true` if the toolchain mode is [`Default`] or [`DefaultOverride`]. + /// + /// [`Default`]: ToolchainMode::Default + /// [`DefaultOverride`]: ToolchainMode::DefaultOverride + #[must_use] + pub fn is_defaulted(&self) -> bool { + matches!(self, Self::Default) + } +} + +pub fn installed_toolchains( + msg_info: &mut MessageInfo, +) -> Result> { let out = rustup_command(msg_info, true) - .args(["toolchain", "list"]) + .args(["toolchain", "list", "-v"]) .run_and_get_stdout(msg_info)?; Ok(out .lines() .map(|l| { - l.replace(" (default)", "") - .replace(" (override)", "") - .trim() - .to_owned() + let mut mode = ToolchainMode::None; + let mut l = if l.contains(" (override)") { + mode = ToolchainMode::Override; + l.replace(" (override)", "") + } else { + l.to_owned() + }; + if l.contains(" (default)") { + if mode.is_overriden() { + mode = ToolchainMode::DefaultOverride; + } else { + mode = ToolchainMode::Default; + } + l = l.replace(" (default)", ""); + } + + (l, mode) + }) + .map(|(l, mode)| { + let mut i = l.split_whitespace(); + ( + i.next() + .map(|s| s.to_owned()) + .expect("rustup output should be consistent"), + mode, + i.next() + .map(PathBuf::from) + .expect("rustup output should be consistent"), + ) }) .collect()) }