@@ -1162,36 +1162,49 @@ OSTreeRepo::fetchRefMetaData(const package::ReferenceWithRepo &refRepo,
11621162 const std::string &module ,
11631163 bool fetchPackageInfo) noexcept
11641164{
1165- auto refString = ostreeSpecFromReferenceV2 (refRepo.reference , std::nullopt , module );
11661165 auto repoName = refRepo.repo .alias .value_or (refRepo.repo .name );
1167- LINGLONG_TRACE (fmt::format (" fetch info.json from {}:{}" , repoName, refString));
11681166
11691167 g_autoptr (GError) gErr = nullptr ;
1168+ auto refCandidates = buildPullRefCandidates (refRepo.reference , module );
1169+ auto refString = refCandidates.front ();
1170+ LINGLONG_TRACE (fmt::format (" fetch info.json from {}:{}" , repoName, refString));
11701171
1171- GVariantBuilder builder = this ->initOStreePullOptions (refString);
1172- if (fetchPackageInfo) {
1173- std::vector<const char *> subdirs{ " /info.json" , nullptr };
1174- g_variant_builder_add (&builder,
1175- " {s@v}" ,
1176- " subdirs" ,
1177- g_variant_new_variant (g_variant_new_strv (subdirs.data (), -1 )));
1178- } else {
1179- g_variant_builder_add (
1180- &builder,
1181- " {s@v}" ,
1182- " flags" ,
1183- g_variant_new_variant (g_variant_new_int32 (OSTREE_REPO_PULL_FLAGS_COMMIT_ONLY )));
1184- }
1185-
1186- g_autoptr (GVariant) pull_options = g_variant_ref_sink (g_variant_builder_end (&builder));
1187- auto status = ostree_repo_pull_with_options (this ->ostreeRepo .get (),
1188- repoName.c_str (),
1189- pull_options,
1190- nullptr ,
1191- nullptr ,
1192- &gErr );
1193- if (status == FALSE ) {
1194- return LINGLONG_ERR (fmt::format (" ostree_repo_pull_with_options {}" , ptr_view (gErr )));
1172+ for (size_t idx = 0 ; idx < refCandidates.size (); ++idx) {
1173+ refString = refCandidates[idx];
1174+
1175+ GVariantBuilder builder = this ->initOStreePullOptions (refString);
1176+ if (fetchPackageInfo) {
1177+ std::vector<const char *> subdirs{ " /info.json" , nullptr };
1178+ g_variant_builder_add (&builder,
1179+ " {s@v}" ,
1180+ " subdirs" ,
1181+ g_variant_new_variant (g_variant_new_strv (subdirs.data (), -1 )));
1182+ } else {
1183+ g_variant_builder_add (
1184+ &builder,
1185+ " {s@v}" ,
1186+ " flags" ,
1187+ g_variant_new_variant (g_variant_new_int32 (OSTREE_REPO_PULL_FLAGS_COMMIT_ONLY )));
1188+ }
1189+
1190+ g_autoptr (GVariant) pull_options = g_variant_ref_sink (g_variant_builder_end (&builder));
1191+ auto status = ostree_repo_pull_with_options (this ->ostreeRepo .get (),
1192+ repoName.c_str (),
1193+ pull_options,
1194+ nullptr ,
1195+ nullptr ,
1196+ &gErr );
1197+ if (status != FALSE ) {
1198+ break ;
1199+ }
1200+
1201+ if (idx + 1 == refCandidates.size () || !shouldFallbackToRuntimeBranch (module , gErr )) {
1202+ return LINGLONG_ERR (fmt::format (" ostree_repo_pull_with_options {}" , ptr_view (gErr )));
1203+ }
1204+
1205+ LogW (" ostree_repo_pull_with_options failed with [{}]: {}" , gErr ->code , gErr ->message );
1206+ LogW (" fallback to module runtime, fetch {}" , refCandidates[idx + 1 ]);
1207+ g_clear_error (&gErr );
11951208 }
11961209 g_clear_error (&gErr );
11971210
@@ -1327,12 +1340,31 @@ GVariantBuilder OSTreeRepo::initOStreePullOptions(const std::string &ref) noexce
13271340 return builder;
13281341}
13291342
1343+ std::vector<std::string> OSTreeRepo::buildPullRefCandidates (const package::Reference &ref,
1344+ const std::string &module ) noexcept
1345+ {
1346+ std::vector<std::string> candidates;
1347+ candidates.emplace_back (ostreeSpecFromReferenceV2 (ref, std::nullopt , module ));
1348+ if (module == " binary" ) {
1349+ candidates.emplace_back (ostreeSpecFromReference (ref, std::nullopt , module ));
1350+ }
1351+ return candidates;
1352+ }
1353+
1354+ bool OSTreeRepo::shouldFallbackToRuntimeBranch (const std::string &module ,
1355+ const GError *gErr ) noexcept
1356+ {
1357+ return module == " binary" && gErr != nullptr && gErr ->message != nullptr
1358+ && strstr (gErr ->message , " No such branch" ) != nullptr ;
1359+ }
1360+
13301361utils::error::Result<void > OSTreeRepo::pull (service::Task &taskContext,
13311362 const package::ReferenceWithRepo &refRepo,
13321363 const std::string &module ) noexcept
13331364{
1334- auto refString = ostreeSpecFromReferenceV2 (refRepo.reference , std::nullopt , module );
13351365 auto repoName = refRepo.repo .alias .value_or (refRepo.repo .name );
1366+ auto refCandidates = buildPullRefCandidates (refRepo.reference , module );
1367+ auto refString = refCandidates.front ();
13361368 LINGLONG_TRACE (fmt::format (" pull {} from {}" , refString, repoName));
13371369
13381370 auto *cancellable = taskContext.cancellable ();
@@ -1346,51 +1378,35 @@ utils::error::Result<void> OSTreeRepo::pull(service::Task &taskContext,
13461378
13471379 g_autoptr (GError) gErr = nullptr ;
13481380
1349- auto builder = this ->initOStreePullOptions (refString);
1350- g_autoptr (GVariant) pull_options = g_variant_ref_sink (g_variant_builder_end (&builder));
1351- // 这里不能使用g_main_context_push_thread_default,因为会阻塞Qt的事件循环
1352-
1353- auto status = ostree_repo_pull_with_options (this ->ostreeRepo .get (),
1354- repoName.c_str (),
1355- pull_options,
1356- progress,
1357- cancellable,
1358- &gErr );
1359- ostree_async_progress_finish (progress);
1360- auto shouldFallback = false ;
1361- if (status == FALSE ) {
1362- // gErr->code is 0, so we compare string here.
1363- if (!strstr (gErr ->message , " No such branch" )) {
1364- return LINGLONG_ERR (fmt::format (" ostree_repo_pull_with_options {}" , ptr_view (gErr )));
1365- }
1366- LogW (" ostree_repo_pull_with_options failed with [{}]: {}" , gErr ->code , gErr ->message );
1367- shouldFallback = true ;
1368- }
1369- // Note: this fallback is only for binary to runtime
1370- if (shouldFallback && (module == " binary" || module == " runtime" )) {
1371- g_autoptr (OstreeAsyncProgress) progress =
1372- ostree_async_progress_new_and_connect (progress_changed, (void *)&data);
1373- Q_ASSERT (progress != nullptr );
1374- // fallback to old ref
1375- refString = ostreeSpecFromReference (refRepo.reference , std::nullopt , module );
1376- LogW (" fallback to module runtime, pull {}" , refString);
1377-
1378- g_clear_error (&gErr );
1379-
1380- GVariantBuilder builder = this ->initOStreePullOptions (refString);
1381+ for (size_t idx = 0 ; idx < refCandidates.size (); ++idx) {
1382+ refString = refCandidates[idx];
13811383
1384+ auto builder = this ->initOStreePullOptions (refString);
13821385 g_autoptr (GVariant) pull_options = g_variant_ref_sink (g_variant_builder_end (&builder));
1383-
1384- status = ostree_repo_pull_with_options (this ->ostreeRepo .get (),
1385- repoName.c_str (),
1386- pull_options,
1387- progress,
1388- cancellable,
1389- &gErr );
1386+ // 这里不能使用g_main_context_push_thread_default,因为会阻塞Qt的事件循环
1387+
1388+ auto status = ostree_repo_pull_with_options (this ->ostreeRepo .get (),
1389+ repoName.c_str (),
1390+ pull_options,
1391+ progress,
1392+ cancellable,
1393+ &gErr );
13901394 ostree_async_progress_finish (progress);
1391- if (status == FALSE ) {
1395+ if (status != FALSE ) {
1396+ break ;
1397+ }
1398+
1399+ if (idx + 1 == refCandidates.size () || !shouldFallbackToRuntimeBranch (module , gErr )) {
13921400 return LINGLONG_ERR (fmt::format (" ostree_repo_pull_with_options {}" , ptr_view (gErr )));
13931401 }
1402+
1403+ LogW (" ostree_repo_pull_with_options failed with [{}]: {}" , gErr ->code , gErr ->message );
1404+ LogW (" fallback to module runtime, pull {}" , refCandidates[idx + 1 ]);
1405+ g_clear_error (&gErr );
1406+
1407+ g_clear_object (&progress);
1408+ progress = ostree_async_progress_new_and_connect (progress_changed, (void *)&data);
1409+ Q_ASSERT (progress != nullptr );
13941410 }
13951411
13961412 g_autofree char *commit = nullptr ;
0 commit comments