Skip to content

Commit 0ddf51f

Browse files
committed
fix(update): 避免重复提示同版本更新
1 parent 7954d02 commit 0ddf51f

4 files changed

Lines changed: 90 additions & 6 deletions

File tree

src/cortex-cli/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ fn check_cortex_home_writable() -> Result<()> {
110110
async fn check_for_updates_background() {
111111
// Use cortex_update crate for update checking
112112
// This runs asynchronously and doesn't block the main command
113-
if let Ok(manager) = cortex_update::UpdateManager::new()
113+
if let Ok(mut manager) = cortex_update::UpdateManager::new()
114114
&& let Ok(Some(update_info)) = manager.check_update().await
115115
{
116116
eprintln!(

src/cortex-tui/src/runner/app_runner/runner.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,7 @@ impl AppRunner {
557557
// 2. Background update check task - check for new versions without blocking startup
558558
let update_check_task = tokio::spawn(async move {
559559
match UpdateManager::new() {
560-
Ok(manager) => match manager.check_update().await {
560+
Ok(mut manager) => match manager.check_update().await {
561561
Ok(info) => info,
562562
Err(e) => {
563563
tracing::debug!("Update check failed: {}", e);

src/cortex-update/src/config.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,4 +145,65 @@ impl UpdateConfig {
145145
pub fn is_version_skipped(&self, version: &str) -> bool {
146146
self.skip_version.as_deref() == Some(version)
147147
}
148+
149+
/// Check if this version has already been surfaced to the user.
150+
pub fn is_version_notified(&self, version: &str) -> bool {
151+
self.last_notified_version.as_deref() == Some(version)
152+
}
153+
154+
/// Persist the latest version that has already been surfaced to the user.
155+
pub fn mark_version_notified(&mut self, version: &str) -> Result<(), std::io::Error> {
156+
if self.is_version_notified(version) {
157+
return Ok(());
158+
}
159+
160+
self.last_notified_version = Some(version.to_string());
161+
self.save()
162+
}
163+
}
164+
165+
#[cfg(test)]
166+
mod tests {
167+
use super::*;
168+
use std::ffi::OsString;
169+
use std::sync::Mutex;
170+
171+
static HOME_LOCK: Mutex<()> = Mutex::new(());
172+
173+
struct HomeGuard(Option<OsString>);
174+
175+
impl Drop for HomeGuard {
176+
fn drop(&mut self) {
177+
if let Some(original) = self.0.take() {
178+
unsafe { std::env::set_var("HOME", original) };
179+
} else {
180+
unsafe { std::env::remove_var("HOME") };
181+
}
182+
}
183+
}
184+
185+
#[test]
186+
fn test_is_version_notified() {
187+
let config = UpdateConfig {
188+
last_notified_version: Some("0.9.0".to_string()),
189+
..UpdateConfig::default()
190+
};
191+
192+
assert!(config.is_version_notified("0.9.0"));
193+
assert!(!config.is_version_notified("0.9.1"));
194+
}
195+
196+
#[test]
197+
fn test_mark_version_notified_persists() {
198+
let _lock = HOME_LOCK.lock().unwrap();
199+
let _guard = HomeGuard(std::env::var_os("HOME"));
200+
let temp_home = tempfile::tempdir().unwrap();
201+
unsafe { std::env::set_var("HOME", temp_home.path()) };
202+
203+
let mut config = UpdateConfig::default();
204+
config.mark_version_notified("1.2.3").unwrap();
205+
206+
let loaded = UpdateConfig::load();
207+
assert_eq!(loaded.last_notified_version.as_deref(), Some("1.2.3"));
208+
}
148209
}

src/cortex-update/src/manager.rs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,21 +84,34 @@ impl UpdateManager {
8484
}
8585

8686
/// Check if an update is available (uses cache if valid).
87-
pub async fn check_update(&self) -> UpdateResult<Option<UpdateInfo>> {
87+
pub async fn check_update(&mut self) -> UpdateResult<Option<UpdateInfo>> {
8888
// Try to use cache first
8989
if let Some(cache) = VersionCache::load() {
9090
if cache.is_valid(&self.config)
9191
&& cache.has_update()
9292
&& !self.config.is_version_skipped(&cache.latest.version)
93+
&& !self.config.is_version_notified(&cache.latest.version)
9394
{
94-
return Ok(Some(self.build_update_info(&cache.latest)?));
95+
let info = self.build_update_info(&cache.latest)?;
96+
self.record_notification(&info.latest_version);
97+
return Ok(Some(info));
9598
} else if cache.is_valid(&self.config) {
9699
return Ok(None);
97100
}
98101
}
99102

100103
// Cache invalid or missing, check server
101-
self.check_update_forced().await
104+
let info = self.check_update_forced().await?;
105+
if let Some(info) = info {
106+
if self.config.is_version_notified(&info.latest_version) {
107+
return Ok(None);
108+
}
109+
110+
self.record_notification(&info.latest_version);
111+
Ok(Some(info))
112+
} else {
113+
Ok(None)
114+
}
102115
}
103116

104117
/// Force check for updates (bypass cache).
@@ -188,7 +201,7 @@ impl UpdateManager {
188201
F: FnMut(DownloadProgress),
189202
{
190203
// Check for update
191-
let info = match self.check_update().await? {
204+
let info = match self.check_update_forced().await? {
192205
Some(info) => info,
193206
None => return Ok(UpdateOutcome::AlreadyLatest),
194207
};
@@ -220,6 +233,16 @@ impl UpdateManager {
220233
})?;
221234
Ok(())
222235
}
236+
237+
fn record_notification(&mut self, version: &str) {
238+
if let Err(e) = self.config.mark_version_notified(version) {
239+
tracing::warn!(
240+
"Failed to persist last_notified_version for {}: {}",
241+
version,
242+
e
243+
);
244+
}
245+
}
223246
}
224247

225248
#[cfg(test)]

0 commit comments

Comments
 (0)