fix: mod updates not being symlinked to a clusters mods folder after update
This commit is contained in:
parent
db764e63f9
commit
6ceba7480f
4 changed files with 44 additions and 16 deletions
|
|
@ -749,13 +749,19 @@ pub async fn remove_artifact_from_cluster(
|
|||
artifact_dao::unlink_cluster_artifact(&ctx.db, cluster_id, hash).await?;
|
||||
|
||||
// Best-effort folder cleanup failure here is not an error
|
||||
if let (Some(content_type), Some(link)) = (target, link) {
|
||||
try_unlink_materialized(&cluster, content_type, &link.cluster_file_name).await;
|
||||
}
|
||||
let deferred = match (target, link) {
|
||||
(Some(content_type), Some(link)) => {
|
||||
try_unlink_materialized(&cluster, content_type, &link.cluster_file_name).await
|
||||
== LiveSync::Deferred
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
|
||||
// The package actually lives in the cache
|
||||
// `evict_if_unused` drops it only once no other cluster still needs it
|
||||
if let Err(err) = evict_if_unused(hash, ctx).await {
|
||||
if !deferred
|
||||
&& let Err(err) = evict_if_unused(hash, ctx).await
|
||||
{
|
||||
tracing::warn!(hash, error = %err, "failed to evict unused artifact from the cache");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -109,20 +109,38 @@ async fn materialized_root(
|
|||
.map(|dir| (dir, manifest::MANIFEST_NAME))
|
||||
}
|
||||
|
||||
async fn session_owns(cluster: &ClusterRow) -> bool {
|
||||
let Ok(game_dir) = paths::cluster_game_dir(&cluster.folder_name) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
manifest::load(&game_dir, manifest::MANIFEST_NAME)
|
||||
.await
|
||||
.is_some_and(|session| session.cluster_id == cluster.id)
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(cluster), fields(cluster_id = cluster.id))]
|
||||
pub async fn try_unlink_materialized(
|
||||
cluster: &ClusterRow,
|
||||
content_type: ContentType,
|
||||
file_name: &str,
|
||||
) -> bool {
|
||||
) -> LiveSync {
|
||||
if !content_type.reloads_in_game() && session_owns(cluster).await {
|
||||
tracing::debug!(
|
||||
file = file_name,
|
||||
"file will be moved at next launch due to an active session"
|
||||
);
|
||||
return LiveSync::Deferred;
|
||||
}
|
||||
|
||||
let Some((root, manifest_name)) = materialized_root(cluster, content_type).await else {
|
||||
return false;
|
||||
return LiveSync::Deferred;
|
||||
};
|
||||
|
||||
let _guard = manifest::lock().await;
|
||||
|
||||
let Some(mut loaded) = manifest::load(&root, manifest_name).await else {
|
||||
return false;
|
||||
return LiveSync::Skipped;
|
||||
};
|
||||
|
||||
let relative = manifest::entry_path(content_type.folder_name(), file_name);
|
||||
|
|
@ -133,7 +151,7 @@ pub async fn try_unlink_materialized(
|
|||
};
|
||||
|
||||
if !ours {
|
||||
return false;
|
||||
return LiveSync::Skipped;
|
||||
}
|
||||
|
||||
let path = root.join(&relative);
|
||||
|
|
@ -143,13 +161,13 @@ pub async fn try_unlink_materialized(
|
|||
error = %err,
|
||||
"could not drop package from the game folder now; it goes at the next launch"
|
||||
);
|
||||
return false;
|
||||
return LiveSync::Deferred;
|
||||
}
|
||||
|
||||
loaded.entries.retain(|entry| entry.path != relative);
|
||||
manifest::save(&root, manifest_name, &loaded).await;
|
||||
|
||||
true
|
||||
LiveSync::Applied
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(cluster, artifact), fields(cluster_id = cluster.id, hash = %artifact.hash))]
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ use oneclient_events::GroupedProgressChild;
|
|||
use crate::ctx::ContentCtx;
|
||||
use crate::error::{ContentError, ContentResult};
|
||||
use crate::packages::dependencies::pick_version;
|
||||
use crate::packages::store::{PackageStore, evict_if_unused, try_unlink_materialized};
|
||||
use crate::packages::store::{LiveSync, PackageStore, evict_if_unused, try_unlink_materialized};
|
||||
use crate::packages::types::LinkedArtifactInfo;
|
||||
|
||||
/// Matches the bundle installer's fan-out
|
||||
|
|
@ -459,8 +459,11 @@ async fn unlink_superseded(cluster_id: i64, hash: &str, ctx: &ContentCtx) -> Con
|
|||
|
||||
artifact_dao::unlink_cluster_artifact(&ctx.db, cluster_id, hash).await?;
|
||||
|
||||
if let (Some(content_type), Some(link)) = (content_type, link) {
|
||||
try_unlink_materialized(&cluster, content_type, &link.cluster_file_name).await;
|
||||
if let (Some(content_type), Some(link)) = (content_type, link)
|
||||
&& try_unlink_materialized(&cluster, content_type, &link.cluster_file_name).await
|
||||
== LiveSync::Deferred
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Err(err) = evict_if_unused(hash, ctx).await {
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ pub async fn materialize_content(
|
|||
unwind_cluster_mods(cluster, &cluster_dir).await;
|
||||
}
|
||||
|
||||
adopt_into_global(&cluster_dir, &global_root).await;
|
||||
adopt_into_global(game_dir, &global_root).await;
|
||||
ensure_global_links(game_dir, &global_root).await;
|
||||
|
||||
|
|
@ -268,13 +269,13 @@ fn without_global_entries(mut manifest: MaterializedManifest) -> MaterializedMan
|
|||
}
|
||||
|
||||
// moves a cluster's own pack folders into the shared one before [`ensure_global_links`] replaces them with links
|
||||
async fn adopt_into_global(game_dir: &Path, global_root: &Path) {
|
||||
if game_dir == global_root {
|
||||
async fn adopt_into_global(own_root: &Path, global_root: &Path) {
|
||||
if own_root == global_root {
|
||||
return;
|
||||
}
|
||||
|
||||
for content_type in GLOBAL_TYPES {
|
||||
let own = game_dir.join(content_type.folder_name());
|
||||
let own = own_root.join(content_type.folder_name());
|
||||
let shared = global_root.join(content_type.folder_name());
|
||||
|
||||
match polyio::symlink_metadata(&own).await {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue