From 880567c7788facfa72cd4e395aa5871e1cbbec07 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Mon, 4 Nov 2024 17:30:57 -0600 Subject: [PATCH] fix: respect lockfile on `mise install` --- .mise.lock | 17 +++++++++++++ .mise.toml | 2 +- e2e/lockfile/test_lockfile_install | 14 ++++++++++ src/cli/exec.rs | 2 +- src/cli/install.rs | 9 +++++-- src/cli/shell.rs | 2 +- src/cli/uninstall.rs | 5 +++- src/cli/upgrade.rs | 7 +++-- src/cli/use.rs | 2 +- src/cli/where.rs | 2 +- src/config/config_file/mod.rs | 2 +- src/toolset/mod.rs | 10 ++++---- src/toolset/tool_request.rs | 5 ++-- src/toolset/tool_version.rs | 41 ++++++++++++++++++++++-------- src/toolset/tool_version_list.rs | 16 +++++++++--- 15 files changed, 103 insertions(+), 33 deletions(-) create mode 100644 .mise.lock create mode 100644 e2e/lockfile/test_lockfile_install diff --git a/.mise.lock b/.mise.lock new file mode 100644 index 0000000000..aede0f7aa2 --- /dev/null +++ b/.mise.lock @@ -0,0 +1,17 @@ +[tools] +actionlint = "1.7.4" +cargo-binstall = "1.10.10" +"cargo:cargo-edit" = "0.13.0" +"cargo:cargo-insta" = "1.41.1" +"cargo:cargo-show" = "0.6.0" +"cargo:git-cliff" = "2.6.1" +"cargo:usage-cli" = "1.1.1" +direnv = "latest" +jq = "1.7.1" +"npm:markdownlint-cli" = "0.42.0" +"npm:prettier" = "3.3.3" +"pipx:toml-sort" = "0.23.1" +python = "3.13.0" +ripgrep = "14.1.1" +shellcheck = "0.10.0" +shfmt = "3.10.0" diff --git a/.mise.toml b/.mise.toml index 7e245a6cc9..d618a13df9 100644 --- a/.mise.toml +++ b/.mise.toml @@ -25,7 +25,7 @@ direnv = "latest" actionlint = "latest" ripgrep = "latest" "pipx:toml-sort" = "latest" -usage = "1" +"cargo:usage-cli" = "1" #python = { version = "latest", virtualenv = "{{env.HOME}}/.cache/venv" } #ruby = "3.1" diff --git a/e2e/lockfile/test_lockfile_install b/e2e/lockfile/test_lockfile_install new file mode 100644 index 0000000000..98e9a8de67 --- /dev/null +++ b/e2e/lockfile/test_lockfile_install @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +export MISE_LOCKFILE=1 +export MISE_EXPERIMENTAL=1 + +mise use tiny@1 +cat <.mise.lock +[tools] +tiny = "1.0.0" +EOF +rm -rf "$MISE_DATA_DIR/installs/tiny" +mise install +assert "mise ls tiny --json --current | jq -r '.[0].requested_version'" "1" +assert "mise ls tiny --json --current | jq -r '.[0].version'" "1.0.0" diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 1ac4d4b7ec..1d83625cad 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -62,7 +62,7 @@ impl Exec { force: false, jobs: self.jobs, raw: self.raw, - latest_versions: false, + resolve_options: Default::default(), }; ts.install_arg_versions(&config, &opts)?; ts.notify_if_versions_missing(); diff --git a/src/cli/install.rs b/src/cli/install.rs index efc2f3c1d6..58aa94c0e3 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -1,7 +1,9 @@ use crate::cli::args::{BackendArg, ToolArg}; use crate::config::Config; use crate::lockfile; -use crate::toolset::{InstallOptions, ToolRequest, ToolSource, ToolVersion, Toolset}; +use crate::toolset::{ + InstallOptions, ResolveOptions, ToolRequest, ToolSource, ToolVersion, Toolset, +}; use crate::ui::multi_progress_report::MultiProgressReport; use eyre::{Result, WrapErr}; use itertools::Itertools; @@ -75,7 +77,10 @@ impl Install { force: self.force, jobs: self.jobs, raw: self.raw, - latest_versions: true, + resolve_options: ResolveOptions { + use_locked_version: true, + latest_versions: true, + }, } } diff --git a/src/cli/shell.rs b/src/cli/shell.rs index f9c7e3cc23..642eee946b 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -48,7 +48,7 @@ impl Shell { force: false, jobs: self.jobs, raw: self.raw, - latest_versions: false, + resolve_options: Default::default(), }; ts.install_arg_versions(&config, &opts)?; ts.notify_if_versions_missing(); diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index 2463db4cfb..93959df26e 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -112,7 +112,10 @@ impl Uninstall { }) .collect::>>()?; if let Some(tvr) = &a.tvr { - tvs.push((tool.clone(), tvr.resolve(tool.as_ref(), false)?)); + tvs.push(( + tool.clone(), + tvr.resolve(tool.as_ref(), &Default::default())?, + )); } if tvs.is_empty() { warn!("no versions found for {}", style(&tool).blue().for_stderr()); diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index 2f62f175d0..810124cbb2 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -1,7 +1,7 @@ use crate::cli::args::ToolArg; use crate::config::{config_file, Config}; use crate::file::display_path; -use crate::toolset::{InstallOptions, OutdatedInfo, ToolVersion, ToolsetBuilder}; +use crate::toolset::{InstallOptions, OutdatedInfo, ResolveOptions, ToolVersion, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; use crate::ui::progress_report::SingleReport; use crate::{lockfile, runtime_symlinks, shims, ui}; @@ -141,7 +141,10 @@ impl Upgrade { force: false, jobs: self.jobs, raw: self.raw, - latest_versions: true, + resolve_options: ResolveOptions { + use_locked_version: false, + latest_versions: true, + }, }; let new_versions = outdated.iter().map(|o| o.tool_request.clone()).collect(); let versions = ts.install_versions(config, new_versions, &mpr, &opts)?; diff --git a/src/cli/use.rs b/src/cli/use.rs index 62bb0bdb54..c0e2f6b98f 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -105,7 +105,7 @@ impl Use { force: self.force, jobs: self.jobs, raw: self.raw, - latest_versions: false, + resolve_options: Default::default(), }, )?; diff --git a/src/cli/where.rs b/src/cli/where.rs index 224edc1699..a20f59d90c 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -46,7 +46,7 @@ impl Where { let ba = tvr.backend(); let backend = backend::get(ba); - let tv = tvr.resolve(backend.as_ref(), false)?; + let tv = tvr.resolve(backend.as_ref(), &Default::default())?; if backend.is_version_installed(&tv, true) { miseprintln!("{}", tv.install_path().to_string_lossy()); diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index ecd1b31db5..2d3231d5a4 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -120,7 +120,7 @@ impl dyn ConfigFile { .map(|tvr| { if pin { let plugin = backend::get(&fa); - let tv = tvr.resolve(plugin.as_ref(), false)?; + let tv = tvr.resolve(plugin.as_ref(), &Default::default())?; Ok(tv.version) } else { Ok(tvr.version()) diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 5f87a3eccc..7397954e8c 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -27,7 +27,7 @@ use tabled::Tabled; pub use tool_request::ToolRequest; pub use tool_request_set::{ToolRequestSet, ToolRequestSetBuilder}; pub use tool_source::ToolSource; -pub use tool_version::ToolVersion; +pub use tool_version::{ResolveOptions, ToolVersion}; pub use tool_version_list::ToolVersionList; use versions::{Version, Versioning}; use xx::regex; @@ -58,7 +58,7 @@ pub struct InstallOptions { pub force: bool, pub jobs: Option, pub raw: bool, - pub latest_versions: bool, + pub resolve_options: ResolveOptions, } impl InstallOptions { @@ -118,7 +118,7 @@ impl Toolset { .iter_mut() .collect::>() .par_iter_mut() - .map(|(_, v)| v.resolve(false)) + .map(|(_, v)| v.resolve(&Default::default())) .filter(|r| r.is_err()) .map(|r| r.unwrap_err()) .collect::>(); @@ -225,7 +225,7 @@ impl Toolset { sleep(Duration::from_millis(100)); } } - let tv = tr.resolve(t.as_ref(), opts.latest_versions)?; + let tv = tr.resolve(t.as_ref(), &opts.resolve_options)?; let ctx = InstallContext { ts, pr: mpr.add(&tv.style()), @@ -284,7 +284,7 @@ impl Toolset { Some((p, tv)) => Ok((p.clone(), tv.clone())), None => { let tv = ToolRequest::new(p.fa().clone(), &v, ToolSource::Unknown)? - .resolve(p.as_ref(), false) + .resolve(p.as_ref(), &Default::default()) .unwrap(); Ok((p.clone(), tv)) } diff --git a/src/toolset/tool_request.rs b/src/toolset/tool_request.rs index fa46c7227a..5f8514f02c 100644 --- a/src/toolset/tool_request.rs +++ b/src/toolset/tool_request.rs @@ -8,6 +8,7 @@ use xx::file; use crate::backend::Backend; use crate::cli::args::BackendArg; use crate::runtime_symlinks::is_runtime_symlink; +use crate::toolset::tool_version::ResolveOptions; use crate::toolset::{ToolSource, ToolVersion, ToolVersionOptions}; use crate::{backend, lockfile}; @@ -225,8 +226,8 @@ impl ToolRequest { Ok(None) } - pub fn resolve(&self, plugin: &dyn Backend, latest_versions: bool) -> Result { - ToolVersion::resolve(plugin, self.clone(), latest_versions) + pub fn resolve(&self, plugin: &dyn Backend, opts: &ResolveOptions) -> Result { + ToolVersion::resolve(plugin, self.clone(), opts) } } diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index fb8a2f9400..ce6916b02a 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -37,9 +37,9 @@ impl ToolVersion { pub fn resolve( backend: &dyn Backend, request: ToolRequest, - latest_versions: bool, + opts: &ResolveOptions, ) -> Result { - if !latest_versions { + if opts.use_locked_version { if let Some(v) = request.lockfile_resolve()? { let tv = Self::new(backend, request.clone(), v); return Ok(tv); @@ -53,12 +53,12 @@ impl ToolVersion { } let tv = match request.clone() { ToolRequest::Version { version: v, .. } => { - Self::resolve_version(backend, request, latest_versions, &v)? + Self::resolve_version(backend, request, &v, opts)? } ToolRequest::Prefix { prefix, .. } => Self::resolve_prefix(backend, request, &prefix)?, ToolRequest::Sub { sub, orig_version, .. - } => Self::resolve_sub(backend, request, latest_versions, &sub, &orig_version)?, + } => Self::resolve_sub(backend, request, &sub, &orig_version, opts)?, _ => { let version = request.version(); Self::new(backend, request, version) @@ -101,7 +101,11 @@ impl ToolVersion { self.backend.downloads_path.join(self.tv_pathname()) } pub fn latest_version(&self, tool: &dyn Backend) -> Result { - let tv = self.request.resolve(tool, true)?; + let opts = ResolveOptions { + latest_versions: true, + use_locked_version: false, + }; + let tv = self.request.resolve(tool, &opts)?; // map cargo backend specific prefixes to ref let version = match tv.request.version().split_once(':') { Some((_ref_type @ ("tag" | "branch" | "rev"), r)) => { @@ -132,8 +136,8 @@ impl ToolVersion { fn resolve_version( backend: &dyn Backend, request: ToolRequest, - latest_versions: bool, v: &str, + opts: &ResolveOptions, ) -> Result { let config = Config::get(); let v = config.resolve_alias(backend, v)?; @@ -155,7 +159,7 @@ impl ToolVersion { } Some((part, v)) if part.starts_with("sub-") => { let sub = part.split_once('-').unwrap().1; - return Self::resolve_sub(backend, request, latest_versions, sub, v); + return Self::resolve_sub(backend, request, sub, v, opts); } _ => (), } @@ -169,7 +173,7 @@ impl ToolVersion { } if v == "latest" { - if !latest_versions { + if !opts.latest_versions { if let Some(v) = backend.latest_installed_version(None)? { return build(v); } @@ -178,7 +182,7 @@ impl ToolVersion { return build(v); } } - if !latest_versions { + if !opts.latest_versions { let matches = backend.list_installed_versions_matching(&v)?; if matches.contains(&v) { return build(v); @@ -198,16 +202,16 @@ impl ToolVersion { fn resolve_sub( tool: &dyn Backend, request: ToolRequest, - latest_versions: bool, sub: &str, v: &str, + opts: &ResolveOptions, ) -> Result { let v = match v { "latest" => tool.latest_version(None)?.unwrap(), _ => Config::get().resolve_alias(tool, v)?, }; let v = tool_request::version_sub(&v, sub); - Self::resolve_version(tool, request, latest_versions, &v) + Self::resolve_version(tool, request, &v, opts) } fn resolve_prefix(tool: &dyn Backend, request: ToolRequest, prefix: &str) -> Result { @@ -281,3 +285,18 @@ impl Hash for ToolVersion { self.version.hash(state); } } + +#[derive(Debug, Clone)] +pub struct ResolveOptions { + pub latest_versions: bool, + pub use_locked_version: bool, +} + +impl Default for ResolveOptions { + fn default() -> Self { + Self { + latest_versions: false, + use_locked_version: true, + } + } +} diff --git a/src/toolset/tool_version_list.rs b/src/toolset/tool_version_list.rs index 5bff2fcced..cfa69c5aff 100644 --- a/src/toolset/tool_version_list.rs +++ b/src/toolset/tool_version_list.rs @@ -2,6 +2,7 @@ use crate::backend; use crate::cli::args::BackendArg; use crate::errors::Error; use crate::toolset::tool_request::ToolRequest; +use crate::toolset::tool_version::ResolveOptions; use crate::toolset::{ToolSource, ToolVersion}; /// represents several versions of a tool for a particular plugin @@ -22,11 +23,11 @@ impl ToolVersionList { source, } } - pub fn resolve(&mut self, latest_versions: bool) -> eyre::Result<()> { + pub fn resolve(&mut self, opts: &ResolveOptions) -> eyre::Result<()> { self.versions.clear(); let plugin = backend::get(&self.backend); for tvr in &mut self.requests { - match tvr.resolve(plugin.as_ref(), latest_versions) { + match tvr.resolve(plugin.as_ref(), opts) { Ok(v) => self.versions.push(v), Err(err) => { return Err(Error::FailedToResolveVersion { @@ -58,7 +59,11 @@ mod tests { let mut tvl = ToolVersionList::new(fa.clone(), ToolSource::Argument); tvl.requests .push(ToolRequest::new(fa, "latest", ToolSource::Argument).unwrap()); - tvl.resolve(true).unwrap(); + tvl.resolve(&ResolveOptions { + latest_versions: true, + use_locked_version: false, + }) + .unwrap(); assert_eq!(tvl.versions.len(), 1); } @@ -72,7 +77,10 @@ mod tests { let mut tvl = ToolVersionList::new(fa.clone(), ToolSource::Argument); tvl.requests .push(ToolRequest::new(fa, "latest", ToolSource::Argument).unwrap()); - let _ = tvl.resolve(true); + let _ = tvl.resolve(&ResolveOptions { + latest_versions: true, + use_locked_version: false, + }); assert_eq!(tvl.versions.len(), 0); } }