Marketplace: cheaper update checks and single-marketplace refreshes (PR review #10)
compute_updates reads each marketplace's head once (snapshot_head, no snapshot clone) and opens each cache once, sharing trees across installs through GitTree::at. refresh_marketplaces(Some(id)) re-pins only that marketplace (mk::set_pins with only) and returns only its snapshot, which the frontend merges by id. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -568,34 +568,17 @@ async fn snapshot_blocking(
|
||||
.map_err(|e| format!("Reading the marketplace cache failed: {e}"))
|
||||
}
|
||||
|
||||
/// Make each cache's pin refs exactly the commits installs reference, so a
|
||||
/// pinned version can never be garbage-collected away. Each marketplace's
|
||||
/// pins are set under that marketplace's repo lock only (pre-flight F11, PR
|
||||
/// review #5): a concurrent fetch writes refs in the same repo.
|
||||
/// Make each cache's pin refs exactly the commits installs reference (see
|
||||
/// [`mk::set_pins`]), for every marketplace.
|
||||
pub(crate) async fn refresh_pins(state: &AppState) {
|
||||
refresh_pins_of(state, None).await;
|
||||
}
|
||||
|
||||
/// [`refresh_pins`] for every marketplace, or only `only`.
|
||||
async fn refresh_pins_of(state: &AppState, only: Option<&str>) {
|
||||
let settings = state.settings_store.get();
|
||||
let pins = mk::pins_by_marketplace(&settings, &state.projects_store.list());
|
||||
let root = state.marketplace.data_root().to_path_buf();
|
||||
for m in &settings.marketplaces {
|
||||
let lock = state.marketplace.repo_lock(&m.id);
|
||||
let _repo_guard = lock.lock().await;
|
||||
let repo = git::cache_path(&root, &m.id);
|
||||
let commits = pins.get(&m.id).cloned().unwrap_or_default();
|
||||
let id = m.id.clone();
|
||||
let _ = tokio::task::spawn_blocking(move || {
|
||||
if !repo.exists() {
|
||||
return;
|
||||
}
|
||||
if let Err(e) = git::set_pins(&repo, &commits) {
|
||||
log::warn!(
|
||||
"Could not update the pinned commits of marketplace {}: {}",
|
||||
id,
|
||||
e
|
||||
);
|
||||
}
|
||||
})
|
||||
.await;
|
||||
}
|
||||
let projects = state.projects_store.list();
|
||||
mk::set_pins(&state.marketplace, &settings, &projects, only).await;
|
||||
}
|
||||
|
||||
/// Forget a marketplace's snapshot and delete its cache, under its repo lock.
|
||||
@@ -640,21 +623,25 @@ pub async fn list_marketplace_snapshots(
|
||||
.map_err(|e| format!("Reading the marketplace caches failed: {e}"))
|
||||
}
|
||||
|
||||
/// With `marketplace_id`, refreshes (and re-pins) only that marketplace and
|
||||
/// returns only its snapshot — the frontend merges snapshots by id — or
|
||||
/// nothing if it was removed meanwhile. Without, refreshes all and returns
|
||||
/// every snapshot.
|
||||
#[tauri::command]
|
||||
pub async fn refresh_marketplaces(
|
||||
marketplace_id: Option<String>,
|
||||
state: State<'_, AppState>,
|
||||
) -> Result<Vec<MarketplaceSnapshot>, String> {
|
||||
let settings = state.settings_store.get();
|
||||
let current = || state.settings_store.get();
|
||||
if let Some(id) = &marketplace_id {
|
||||
find_marketplace(&settings, id)?;
|
||||
find_marketplace(¤t(), id)?;
|
||||
let snap = mk::refresh_marketplace(&state.marketplace, ¤t, id).await;
|
||||
refresh_pins_of(&state, Some(id)).await;
|
||||
let still_configured = find_marketplace(¤t(), id).is_ok();
|
||||
return Ok(if still_configured { vec![snap] } else { vec![] });
|
||||
}
|
||||
for m in settings
|
||||
.marketplaces
|
||||
.iter()
|
||||
.filter(|m| marketplace_id.as_deref().is_none_or(|id| id == m.id))
|
||||
{
|
||||
mk::refresh_marketplace(&state.marketplace, &|| state.settings_store.get(), &m.id).await;
|
||||
for m in current().marketplaces {
|
||||
mk::refresh_marketplace(&state.marketplace, ¤t, &m.id).await;
|
||||
}
|
||||
refresh_pins(&state).await;
|
||||
list_marketplace_snapshots(state).await
|
||||
|
||||
Reference in New Issue
Block a user