From 6dffb0838cc8c3dddb1675cd7565c10d16bc1e38 Mon Sep 17 00:00:00 2001 From: Sebastian Ullrich Date: Tue, 10 Dec 2024 14:57:45 +0100 Subject: [PATCH] feat: differentiate live and cached toolchain resolution in `dump-state` (#150) --- src/elan-cli/json_dump.rs | 30 ++++++++++++++++++++---------- src/elan/config.rs | 2 +- src/elan/toolchain.rs | 14 +++++++++----- 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/elan-cli/json_dump.rs b/src/elan-cli/json_dump.rs index f1d56f5..2a35f79 100644 --- a/src/elan-cli/json_dump.rs +++ b/src/elan-cli/json_dump.rs @@ -1,4 +1,4 @@ -use elan::{lookup_unresolved_toolchain_desc, resolve_toolchain_desc, utils::{self, fetch_latest_release_tag}, Cfg, Toolchain, UnresolvedToolchainDesc}; +use elan::{lookup_unresolved_toolchain_desc, resolve_toolchain_desc_ext, utils::{self, fetch_latest_release_tag}, Cfg, Toolchain, UnresolvedToolchainDesc}; use std::{io, path::PathBuf}; use serde_derive::Serialize; @@ -22,12 +22,20 @@ struct InstalledToolchain { path: PathBuf, } +#[derive(Serialize)] +struct ToolchainResolution { + /// On network error, will always be `Err` even if `elan` commands would fall back to the latest + /// local toolchain if any + live: Result, + /// The latest local toolchain if any independently of network availability + cached: Option, +} + #[derive(Serialize)] struct DefaultToolchain { /// Not necessarily resolved name as given to `elan default`, e.g. `stable` unresolved: UnresolvedToolchainDesc, - /// Fully resolved name; `Err` if `unresolved` needed to be resolved but there was a network error - resolved: Result, + resolved: ToolchainResolution, } #[derive(Serialize)] @@ -44,7 +52,7 @@ struct Toolchains { /// `None` if no override for current directory configured, in which case `default` if any is used active_override: Option, /// Toolchain, if any, ultimately chosen based on `default` and `active_override` - resolved_active: Option>, + resolved_active: Option, } #[derive(Serialize)] @@ -53,6 +61,12 @@ pub struct StateDump { toolchains: Toolchains, } +fn mk_toolchain_resolution(cfg: &Cfg, unresolved: &UnresolvedToolchainDesc, no_net: bool) -> ToolchainResolution { + let live = resolve_toolchain_desc_ext(cfg, unresolved, no_net, false).map(|t| t.to_string()).map_err(|e| e.to_string()); + let cached = resolve_toolchain_desc_ext(cfg, unresolved, true, true).map(|t| t.to_string()).map_err(|e| e.to_string()).ok(); + ToolchainResolution { live, cached } +} + impl StateDump { pub fn new(cfg: &Cfg, no_net: bool) -> crate::Result { let newest = fetch_latest_release_tag("leanprover/elan", no_net); @@ -76,9 +90,7 @@ impl StateDump { }).collect(), default: default.as_ref().map(|default| DefaultToolchain { unresolved: default.clone(), - resolved: resolve_toolchain_desc(cfg, &default, no_net) - .map(|t| t.to_string()) - .map_err(|e| e.to_string()), + resolved: mk_toolchain_resolution(cfg, default, no_net), }), active_override: active_override.as_ref().map(|(desc, reason)| Override { unresolved: desc.clone(), @@ -87,9 +99,7 @@ impl StateDump { resolved_active: active_override .map(|p| p.0) .or(default) - .map(|t| resolve_toolchain_desc(cfg, &t, no_net) - .map(|tc| tc.to_string()) - .map_err(|e| e.to_string())) + .map(|t| mk_toolchain_resolution(cfg, &t, no_net)) }, }) } diff --git a/src/elan/config.rs b/src/elan/config.rs index 305cad7..7ab69ac 100644 --- a/src/elan/config.rs +++ b/src/elan/config.rs @@ -235,7 +235,7 @@ impl Cfg { path: &Path, ) -> Result)>> { if let Some((toolchain, reason)) = self.find_override(path)? { - let toolchain = resolve_toolchain_desc(&self, &toolchain, false)?; + let toolchain = resolve_toolchain_desc(&self, &toolchain)?; match self.get_toolchain(&toolchain, false) { Ok(toolchain) => { if toolchain.exists() { diff --git a/src/elan/toolchain.rs b/src/elan/toolchain.rs index f8a76cd..f3054cd 100644 --- a/src/elan/toolchain.rs +++ b/src/elan/toolchain.rs @@ -92,19 +92,19 @@ fn find_latest_local_toolchain(cfg: &Cfg, channel: &str) -> Option Result { +pub fn resolve_toolchain_desc_ext(cfg: &Cfg, unresolved_tc: &UnresolvedToolchainDesc, no_net: bool, use_cache: bool) -> Result { if let ToolchainDesc::Remote { ref origin, ref release, from_channel: Some(ref channel) } = unresolved_tc.0 { if release == "lean-toolchain" { let toolchain_url = format!( "https://raw.githubusercontent.com/{}/HEAD/lean-toolchain", origin ); - return resolve_toolchain_desc(cfg, &lookup_unresolved_toolchain_desc(cfg, fetch_url(&toolchain_url)?.trim())?, no_net); + return resolve_toolchain_desc_ext(cfg, &lookup_unresolved_toolchain_desc(cfg, fetch_url(&toolchain_url)?.trim())?, no_net, use_cache); } else if release == "stable" || release == "beta" || release == "nightly" { match utils::fetch_latest_release_tag(origin, no_net) { Ok(release) => Ok(ToolchainDesc::Remote { origin: origin.clone(), release, from_channel: Some(channel.clone()) }), Err(e) => { - if let Some(tc) = find_latest_local_toolchain(cfg, &release) { + if let (true, Some(tc)) = (use_cache, find_latest_local_toolchain(cfg, &release)) { (cfg.notify_handler)(Notification::UsingExistingRelease(&tc)); Ok(tc) } else { @@ -120,8 +120,12 @@ pub fn resolve_toolchain_desc(cfg: &Cfg, unresolved_tc: &UnresolvedToolchainDesc } } +pub fn resolve_toolchain_desc(cfg: &Cfg, unresolved_tc: &UnresolvedToolchainDesc) -> Result { + resolve_toolchain_desc_ext(cfg, unresolved_tc, false, true) +} + pub fn lookup_toolchain_desc(cfg: &Cfg, name: &str) -> Result { - resolve_toolchain_desc(cfg, &lookup_unresolved_toolchain_desc(cfg, name)?, false) + resolve_toolchain_desc(cfg, &lookup_unresolved_toolchain_desc(cfg, name)?) } pub fn read_unresolved_toolchain_desc_from_file(cfg: &Cfg, toolchain_file: &Path) -> Result { @@ -135,7 +139,7 @@ pub fn read_unresolved_toolchain_desc_from_file(cfg: &Cfg, toolchain_file: &Path } pub fn read_toolchain_desc_from_file(cfg: &Cfg, toolchain_file: &Path) -> Result { - resolve_toolchain_desc(cfg, &read_unresolved_toolchain_desc_from_file(cfg, toolchain_file)?, false) + resolve_toolchain_desc(cfg, &read_unresolved_toolchain_desc_from_file(cfg, toolchain_file)?) } impl<'a> Toolchain<'a> {