Skip to content

Commit 403a228

Browse files
reddevillgdengbo11
authored andcommitted
refactor: unify fallback logic for binary module pulls
Extract the fallback mechanism for pulling binary modules info reusable helper functions. When pulling a binary module fails with "No such branch", the code now falls back to the runtime ref. Signed-off-by: reddevillg <reddevillg@gmail.com>
1 parent d8fe450 commit 403a228

3 files changed

Lines changed: 111 additions & 67 deletions

File tree

libs/linglong/src/linglong/repo/ostree_repo.cpp

Lines changed: 83 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
13301361
utils::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;

libs/linglong/src/linglong/repo/ostree_repo.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,10 @@ class OSTreeRepo : public QObject
263263

264264
protected:
265265
OSTreeRepo(std::filesystem::path path, api::types::v1::RepoConfigV2 cfg) noexcept;
266+
static std::vector<std::string> buildPullRefCandidates(const package::Reference &ref,
267+
const std::string &module) noexcept;
268+
static bool shouldFallbackToRuntimeBranch(const std::string &module,
269+
const GError *gErr) noexcept;
266270

267271
utils::error::Result<void> init(bool create) noexcept;
268272
utils::error::Result<void> initCache(bool create) noexcept;

libs/linglong/tests/ll-tests/src/linglong/repo/ostree_repo_test.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,18 @@ class OSTreeRepoMock : public repo::OSTreeRepo
421421
(override, const));
422422
};
423423

424+
class OSTreeRepoAccessor : public repo::OSTreeRepo
425+
{
426+
public:
427+
using repo::OSTreeRepo::buildPullRefCandidates;
428+
429+
OSTreeRepoAccessor()
430+
: repo::OSTreeRepo(
431+
"", api::types::v1::RepoConfigV2{ .defaultRepo = "", .repos = {}, .version = 2 })
432+
{
433+
}
434+
};
435+
424436
class MockClientAPIWrapper : public ClientAPIWrapper
425437
{
426438
public:
@@ -466,6 +478,18 @@ TEST(OSTreeRepoTest, searchRemote_Search)
466478
EXPECT_EQ((*result)[0].version, "1.0.0");
467479
}
468480

481+
TEST(OSTreeRepoTest, BuildPullRefCandidatesFallbackToRuntimeForBinary)
482+
{
483+
auto ref = package::Reference::parse("stable:org.deepin.demo/1.0.0/x86_64");
484+
ASSERT_TRUE(ref.has_value()) << ref.error().message();
485+
486+
auto candidates = OSTreeRepoAccessor::buildPullRefCandidates(*ref, "binary");
487+
488+
ASSERT_EQ(candidates.size(), 2);
489+
EXPECT_EQ(candidates[0], "stable/org.deepin.demo/1.0.0/x86_64/binary");
490+
EXPECT_EQ(candidates[1], "stable/org.deepin.demo/1.0.0/x86_64/runtime");
491+
}
492+
469493
TEST(OSTreeRepoTest, searchRemote_MatchVersion)
470494
{
471495
TempDir tempDir;

0 commit comments

Comments
 (0)