Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 0 additions & 37 deletions mise.toml

This file was deleted.

6 changes: 4 additions & 2 deletions src/cli/outdated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::collections::HashSet;

use crate::cli::args::ToolArg;
use crate::config::Config;
use crate::toolset::ToolsetBuilder;
use crate::toolset::{ResolveOptions, ToolsetBuilder};
use crate::toolset::outdated_info::OutdatedInfo;
use crate::ui::table;
use eyre::Result;
Expand Down Expand Up @@ -54,7 +54,9 @@ impl Outdated {
.collect::<HashSet<_>>();
ts.versions
.retain(|_, tvl| tool_set.is_empty() || tool_set.contains(&tvl.backend));
let outdated = ts.list_outdated_versions(&config, self.bump).await;
let outdated = ts
.list_outdated_versions(&config, self.bump, &ResolveOptions::default())
.await;
self.display(outdated).await?;
Ok(())
}
Expand Down
7 changes: 6 additions & 1 deletion src/cli/upgrade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,12 @@ impl Upgrade {
.with_args(&self.tool)
.build(&config)
.await?;
let mut outdated = ts.list_outdated_versions(&config, self.bump).await;
let opts = ResolveOptions {
use_locked_version: false,
latest_versions: true,
before_date: self.get_before_date()?,
};
let mut outdated = ts.list_outdated_versions(&config, self.bump, &opts).await;
if self.interactive && !outdated.is_empty() {
outdated = self.get_interactive_tool_set(&outdated)?;
} else if !self.tool.is_empty() {
Expand Down
5 changes: 3 additions & 2 deletions src/plugins/core/rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::http::HTTP;
use crate::install_context::InstallContext;
use crate::toolset::ToolSource::IdiomaticVersionFile;
use crate::toolset::outdated_info::OutdatedInfo;
use crate::toolset::{ToolVersion, Toolset};
use crate::toolset::{ResolveOptions, ToolVersion, Toolset};
use crate::ui::progress_report::SingleReport;
use crate::{dirs, env, file, github, plugins};
use async_trait::async_trait;
Expand Down Expand Up @@ -196,7 +196,8 @@ impl Backend for RustPlugin {
) -> Result<Option<OutdatedInfo>> {
let v_re = regex!(r#"Update available : (.*) -> (.*)"#);
if regex!(r"(\d+)\.(\d+)\.(\d+)").is_match(&tv.version) {
let oi = OutdatedInfo::resolve(config, tv.clone(), bump).await?;
let oi = OutdatedInfo::resolve(config, tv.clone(), bump, &ResolveOptions::default())
.await?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Rust plugin ignores before_date causing duplicate entries

The Rust plugin's outdated_info method calls OutdatedInfo::resolve with ResolveOptions::default(), ignoring the before_date filter. In list_outdated_versions, both t.outdated_info() and OutdatedInfo::resolve() results are added to the outdated list. For Rust with semver versions, this creates duplicate entries - one ignoring before_date and one respecting it - leading to incorrect output when users specify --before.

Additional Locations (1)

Fix in Cursor Fix in Web

Ok(oi)
} else {
let ts = config.get_toolset().await?;
Expand Down
48 changes: 26 additions & 22 deletions src/toolset/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -633,37 +633,41 @@ impl Toolset {
&self,
config: &Arc<Config>,
bump: bool,
opts: &ResolveOptions,
) -> Vec<OutdatedInfo> {
let versions = self
.list_current_versions()
.into_iter()
// Respect per-tool os constraints set via options.os
.filter(|(_, tv)| tv.request.is_os_supported())
.map(|(t, tv)| (config.clone(), t, tv, bump))
.map(|(t, tv)| (config.clone(), t, tv, bump, opts.clone()))
.collect::<Vec<_>>();
let outdated = parallel::parallel(versions, |(config, t, tv, bump)| async move {
let mut outdated = vec![];
match t.outdated_info(&config, &tv, bump).await {
Ok(Some(oi)) => outdated.push(oi),
Ok(None) => {}
Err(e) => {
warn!("Error getting outdated info for {tv}: {e:#}");
let outdated = parallel::parallel(
versions,
|(config, t, tv, bump, opts)| async move {
let mut outdated = vec![];
match t.outdated_info(&config, &tv, bump).await {
Ok(Some(oi)) => outdated.push(oi),
Ok(None) => {}
Err(e) => {
warn!("Error getting outdated info for {tv}: {e:#}");
}
}
}
if t.symlink_path(&tv).is_some() {
trace!("skipping symlinked version {tv}");
// do not consider symlinked versions to be outdated
return Ok(outdated);
}
match OutdatedInfo::resolve(&config, tv.clone(), bump).await {
Ok(Some(oi)) => outdated.push(oi),
Ok(None) => {}
Err(e) => {
warn!("Error creating OutdatedInfo for {tv}: {e:#}");
if t.symlink_path(&tv).is_some() {
trace!("skipping symlinked version {tv}");
// do not consider symlinked versions to be outdated
return Ok(outdated);
}
}
Ok(outdated)
})
match OutdatedInfo::resolve(&config, tv.clone(), bump, &opts).await {
Ok(Some(oi)) => outdated.push(oi),
Ok(None) => {}
Err(e) => {
warn!("Error creating OutdatedInfo for {tv}: {e:#}");
}
}
Ok(outdated)
},
)
.await
.unwrap_or_else(|e| {
warn!("Error in parallel outdated version check: {e:#}");
Expand Down
17 changes: 13 additions & 4 deletions src/toolset/outdated_info.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::semver::{chunkify_version, split_version_prefix};
use crate::toolset;
use crate::toolset::{ToolRequest, ToolSource, ToolVersion};
use crate::toolset::{ResolveOptions, ToolRequest, ToolSource, ToolVersion};
use crate::{Result, config::Config};
use serde_derive::Serialize;
use std::{
Expand Down Expand Up @@ -53,15 +53,24 @@ impl OutdatedInfo {
config: &Arc<Config>,
tv: ToolVersion,
bump: bool,
opts: &ResolveOptions,
) -> eyre::Result<Option<Self>> {
let t = tv.backend()?;
// prefix is something like "temurin-" or "corretto-"
let (prefix, _) = split_version_prefix(&tv.request.version());
let latest_result = if bump {
t.latest_version(config, Some(prefix.clone()).filter(|s| !s.is_empty()))
.await
// Note: Backend's latest_version_with_opts takes individual parameters,
// not a ResolveOptions struct like ToolVersion's method
t.latest_version_with_opts(
config,
Some(prefix.clone()).filter(|s| !s.is_empty()),
opts.before_date,
)
.await
} else {
tv.latest_version(config).await.map(Option::from)
tv.latest_version_with_opts(config, opts)
.await
.map(Option::from)
};
let latest = match latest_result {
Ok(Some(latest)) => latest,
Expand Down
13 changes: 12 additions & 1 deletion src/toolset/tool_version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,21 @@ impl ToolVersion {
self.request.ba().downloads_path.join(self.tv_pathname())
}
pub async fn latest_version(&self, config: &Arc<Config>) -> Result<String> {
self.latest_version_with_opts(config, &ResolveOptions::default())
.await
}

pub async fn latest_version_with_opts(
&self,
config: &Arc<Config>,
base_opts: &ResolveOptions,
) -> Result<String> {
// Note: We always use latest_versions=true and use_locked_version=false for latest version lookup,
// but we preserve before_date from base_opts to respect date-based filtering
let opts = ResolveOptions {
latest_versions: true,
use_locked_version: false,
..Default::default()
before_date: base_opts.before_date,
};
let tv = self.request.resolve(config, &opts).await?;
// map cargo backend specific prefixes to ref
Expand Down
Loading