Fix version-tag matching and bundle filtering
This commit is contained in:
parent
09509b1b3d
commit
41ce177483
3 changed files with 87 additions and 4 deletions
|
|
@ -7,10 +7,12 @@ use std::collections::{HashMap, HashSet};
|
||||||
use oneclient_common::domain::{ContentType, ProviderId};
|
use oneclient_common::domain::{ContentType, ProviderId};
|
||||||
use oneclient_db::dao::applied_migration as migration_dao;
|
use oneclient_db::dao::applied_migration as migration_dao;
|
||||||
use oneclient_db::dao::artifact as artifact_dao;
|
use oneclient_db::dao::artifact as artifact_dao;
|
||||||
|
use oneclient_db::dao::bundle as bundle_catalog_dao;
|
||||||
use oneclient_db::dao::cluster_bundle as bundle_dao;
|
use oneclient_db::dao::cluster_bundle as bundle_dao;
|
||||||
|
|
||||||
use crate::ctx::ContentCtx;
|
use crate::ctx::ContentCtx;
|
||||||
use crate::error::ContentResult;
|
use crate::error::ContentResult;
|
||||||
|
use crate::packages::dependencies::base_game_version;
|
||||||
use crate::packages::store::PackageStore;
|
use crate::packages::store::PackageStore;
|
||||||
use crate::packages::types::LinkedArtifactInfo;
|
use crate::packages::types::LinkedArtifactInfo;
|
||||||
|
|
||||||
|
|
@ -96,6 +98,7 @@ fn group_duplicates(
|
||||||
pub async fn disable_foreign_game_versions(
|
pub async fn disable_foreign_game_versions(
|
||||||
cluster_id: i64,
|
cluster_id: i64,
|
||||||
mc_version: &str,
|
mc_version: &str,
|
||||||
|
mc_loader: i64,
|
||||||
ctx: &ContentCtx,
|
ctx: &ContentCtx,
|
||||||
) -> ContentResult<Vec<String>> {
|
) -> ContentResult<Vec<String>> {
|
||||||
if mc_version.is_empty() {
|
if mc_version.is_empty() {
|
||||||
|
|
@ -105,9 +108,21 @@ pub async fn disable_foreign_game_versions(
|
||||||
let linked = PackageStore::list_linked_artifacts(cluster_id, ctx).await?;
|
let linked = PackageStore::list_linked_artifacts(cluster_id, ctx).await?;
|
||||||
|
|
||||||
// bundle installs skip the compatibility check so launch must trust them too
|
// bundle installs skip the compatibility check so launch must trust them too
|
||||||
|
let live_bundles: HashSet<String> =
|
||||||
|
bundle_catalog_dao::list_visible_for_version_loader(&ctx.db, mc_version, mc_loader)
|
||||||
|
.await?
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|row| row.name)
|
||||||
|
.collect();
|
||||||
|
|
||||||
let from_bundle: HashSet<String> = bundle_dao::list_bundle_tracked(&ctx.db, cluster_id)
|
let from_bundle: HashSet<String> = bundle_dao::list_bundle_tracked(&ctx.db, cluster_id)
|
||||||
.await?
|
.await?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
.filter(|row| {
|
||||||
|
row.bundle_name
|
||||||
|
.as_deref()
|
||||||
|
.is_some_and(|name| live_bundles.contains(name))
|
||||||
|
})
|
||||||
.map(|row| row.hash)
|
.map(|row| row.hash)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
|
@ -175,11 +190,13 @@ fn built_for_another_game_version(stated: &[String], mc_version: &str) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn covers_game_version(stated: &[String], mc_version: &str) -> bool {
|
fn covers_game_version(stated: &[String], mc_version: &str) -> bool {
|
||||||
|
let wanted = base_game_version(mc_version);
|
||||||
stated.is_empty()
|
stated.is_empty()
|
||||||
|| stated.iter().any(|version| {
|
|| stated.iter().any(|version| {
|
||||||
version == mc_version
|
let built_for = base_game_version(version);
|
||||||
|| mc_version
|
built_for == wanted
|
||||||
.strip_prefix(version.as_str())
|
|| wanted
|
||||||
|
.strip_prefix(built_for)
|
||||||
.is_some_and(|rest| rest.starts_with('.'))
|
.is_some_and(|rest| rest.starts_with('.'))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -295,6 +312,34 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_pre_release_tag_is_the_same_game_version() {
|
||||||
|
let foreign = |rows: &[&str], mc_version: &str| {
|
||||||
|
built_for_another_game_version(
|
||||||
|
&rows.iter().map(|r| (*r).to_string()).collect::<Vec<_>>(),
|
||||||
|
mc_version,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
!foreign(&["[\"26.3-rc-1\"]"], "26.3"),
|
||||||
|
"a jar built against the release candidate runs on the release"
|
||||||
|
);
|
||||||
|
assert!(!foreign(&["[\"26.3-snapshot-7\",\"26.3-pre-2\"]"], "26.3"));
|
||||||
|
assert!(
|
||||||
|
!foreign(&["[\"26.3\"]"], "26.3-snapshot-10"),
|
||||||
|
"and a snapshot cluster keeps the release build"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
!foreign(&["[\"26.3-rc-1\"]"], "26.3.1"),
|
||||||
|
"the component prefix still applies once the tag is off"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
foreign(&["[\"26.2-rc-1\"]"], "26.3"),
|
||||||
|
"stripping the tag must not blur two game versions together"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn only_projects_with_several_copies_are_reconciled() {
|
fn only_projects_with_several_copies_are_reconciled() {
|
||||||
let groups = group_duplicates(&[
|
let groups = group_duplicates(&[
|
||||||
|
|
|
||||||
|
|
@ -193,9 +193,18 @@ fn choose_version(
|
||||||
.cloned()
|
.cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub(crate) fn base_game_version(version: &str) -> &str {
|
||||||
|
version
|
||||||
|
.split_once('-')
|
||||||
|
.filter(|(base, _)| base.contains('.'))
|
||||||
|
.map_or(version, |(base, _)| base)
|
||||||
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn supports_game_version(game_versions: &[String], mc_version: &str) -> bool {
|
pub(crate) fn supports_game_version(game_versions: &[String], mc_version: &str) -> bool {
|
||||||
game_versions.is_empty() || game_versions.iter().any(|v| v == mc_version)
|
let wanted = base_game_version(mc_version);
|
||||||
|
game_versions.is_empty() || game_versions.iter().any(|v| base_game_version(v) == wanted)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fits_cluster(version: &VersionSummary, cluster: &ClusterRow, loader: GameLoader) -> bool {
|
fn fits_cluster(version: &VersionSummary, cluster: &ClusterRow, loader: GameLoader) -> bool {
|
||||||
|
|
@ -230,6 +239,34 @@ mod tests {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_version_is_offered_only_for_the_game_version_it_names() {
|
||||||
|
let offered = |stated: &[&str], mc_version: &str| {
|
||||||
|
supports_game_version(
|
||||||
|
&stated.iter().map(|v| (*v).to_string()).collect::<Vec<_>>(),
|
||||||
|
mc_version,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(offered(&[], "26.3"), "an undescribed version is offered");
|
||||||
|
assert!(offered(&["26.3"], "26.3"));
|
||||||
|
assert!(
|
||||||
|
offered(&["26.3-rc-1"], "26.3"),
|
||||||
|
"a pre-release tag names the same game version"
|
||||||
|
);
|
||||||
|
assert!(offered(&["26.3"], "26.3-snapshot-10"));
|
||||||
|
assert!(
|
||||||
|
!offered(&["26.1"], "26.1.2"),
|
||||||
|
"strict where the launch-time check is lenient: #830 stopped 26.1 \
|
||||||
|
builds being offered to a 26.1.2 cluster"
|
||||||
|
);
|
||||||
|
assert!(!offered(&["1.21.11"], "26.1.2"));
|
||||||
|
assert!(
|
||||||
|
!offered(&["rd-132211"], "rd-160052"),
|
||||||
|
"pre-classic names the build after the dash, so there is no tag to strip"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn summary(
|
fn summary(
|
||||||
version_id: &str,
|
version_id: &str,
|
||||||
release_type: ReleaseType,
|
release_type: ReleaseType,
|
||||||
|
|
|
||||||
|
|
@ -139,6 +139,7 @@ pub async fn materialize_content(
|
||||||
match oneclient_content::packages::disable_foreign_game_versions(
|
match oneclient_content::packages::disable_foreign_game_versions(
|
||||||
cluster.id,
|
cluster.id,
|
||||||
&cluster.mc_version,
|
&cluster.mc_version,
|
||||||
|
cluster.mc_loader as i64,
|
||||||
&services.content(),
|
&services.content(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue