Skip to content

Commit a5cc31c

Browse files
committed
fix(index): refresh missing xim package metadata
1 parent 69f8226 commit a5cc31c

4 files changed

Lines changed: 104 additions & 2 deletions

File tree

.agents/docs/2026-05-31-index-refresh-cache-labels-plan.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,28 @@ fresh while `xim-pkgindex/pkgs` is missing or stale. Toolchains are resolved
148148
from xlings' official `xim-pkgindex`, so mcpp must track that index separately
149149
from the default modular-library `mcpplibs` index.
150150

151+
### 7. Fresh official index marker does not imply the target package exists
152+
153+
The third PR checkpoint still failed in the same Linux musl step. The package
154+
lookup error remained:
155+
156+
```text
157+
[error] package 'xim:musl-gcc@15.1.0' not found
158+
```
159+
160+
That means a restored CI cache can still satisfy the coarse check
161+
`xim-pkgindex/pkgs + .mcpp-index-updated` while missing the package file added
162+
later:
163+
164+
```text
165+
xim-pkgindex/pkgs/m/musl-gcc.lua
166+
```
167+
168+
For `xim:` auto-installs, the freshness guard must therefore check the target
169+
package's index file, not just the official index directory. If the package
170+
file is absent, mcpp should silently run `xlings update` before calling either
171+
the NDJSON interface install path or the direct CLI fallback.
172+
151173
## Implementation Plan
152174

153175
- [x] Add focused regression coverage for default-index refresh quietness.
@@ -163,6 +185,8 @@ from the default modular-library `mcpplibs` index.
163185
diagnostics.
164186
- [x] Track official `xim-pkgindex` freshness independently and refresh it
165187
before auto-installing `xim:` toolchain packages.
188+
- [x] Require the target package file to exist before treating an official
189+
`xim:` index as fresh.
166190
- [x] Validate with the local xlings checkout using the new mcpp binary.
167191
- [x] Push a draft PR and use it as the multi-commit checkpoint.
168192

@@ -233,3 +257,19 @@ from the default modular-library `mcpplibs` index.
233257
passed.
234258
- `/tmp/mcpp-fresh-codex clean && /tmp/mcpp-fresh-codex build --target
235259
x86_64-linux-musl` passed and resolved `gcc@15.1.0-musl`.
260+
- The next CI run still failed at the same musl step, proving the remaining
261+
stale-cache shape is target-package-level, not just official-index-level.
262+
- Added `is_official_package_index_fresh()` /
263+
`ensure_official_package_index_fresh()` and wired `xim:` auto-installs to
264+
check the concrete package file (for example `pkgs/m/musl-gcc.lua`).
265+
- Added two more unit tests for a fresh official index marker with a missing
266+
target package file.
267+
- Local verification after this package-file fix:
268+
- `mcpp test -- --gtest_filter=XlingsIndexFreshness.*` passed with 8
269+
matching `test_xlings` cases.
270+
- `mcpp build --no-cache` passed.
271+
- e2e `49_bmi_cache_nested_custom_index.sh`,
272+
`52_local_path_namespaced_index.sh`, and `53_namespaced_cache_label.sh`
273+
passed.
274+
- `/tmp/mcpp-fresh-codex clean && /tmp/mcpp-fresh-codex build --target
275+
x86_64-linux-musl` passed and resolved `gcc@15.1.0-musl`.

src/pm/package_fetcher.cppm

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -694,8 +694,8 @@ Fetcher::resolve_xpkg_path(std::string_view target,
694694
if (autoInstall) {
695695
if (parsed.indexName == "xim") {
696696
mcpp::xlings::Env xlEnv{ cfg_.xlingsBinary, cfg_.xlingsHome() };
697-
mcpp::xlings::ensure_official_index_fresh(
698-
xlEnv, cfg_.searchTtlSeconds, /*quiet=*/true);
697+
mcpp::xlings::ensure_official_package_index_fresh(
698+
xlEnv, parsed.packageName, cfg_.searchTtlSeconds, /*quiet=*/true);
699699
}
700700

701701
std::vector<std::string> targets {

src/xlings.cppm

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,13 @@ bool is_index_fresh(const Env& env, std::int64_t ttlSeconds);
246246
// toolchains live in xim-pkgindex, while modular libraries live in mcpplibs.
247247
bool is_official_index_fresh(const Env& env, std::int64_t ttlSeconds);
248248

249+
// Check whether a specific package file exists in xlings' official xim index
250+
// and the index is fresh. This catches restored CI caches that have an index
251+
// directory and marker but predate a package added later.
252+
bool is_official_package_index_fresh(const Env& env,
253+
std::string_view packageName,
254+
std::int64_t ttlSeconds);
255+
249256
// Run `xlings update` to refresh all index repos. Streams output to stdout.
250257
// Returns the xlings exit code.
251258
int update_index(const Env& env, bool quiet = false);
@@ -258,6 +265,12 @@ void ensure_index_fresh(const Env& env, std::int64_t ttlSeconds, bool quiet = fa
258265
// Ensure xlings' official xim index is present and fresh.
259266
void ensure_official_index_fresh(const Env& env, std::int64_t ttlSeconds, bool quiet = false);
260267

268+
// Ensure a specific package file exists in xlings' official xim index.
269+
void ensure_official_package_index_fresh(const Env& env,
270+
std::string_view packageName,
271+
std::int64_t ttlSeconds,
272+
bool quiet = false);
273+
261274
// ─── run_capture utility ────────────────────────────────────────────
262275

263276
std::expected<std::string, std::string> run_capture(const std::string& cmd);
@@ -298,6 +311,12 @@ std::filesystem::path index_refresh_marker(const std::filesystem::path& indexDir
298311
return indexDir / ".mcpp-index-updated";
299312
}
300313

314+
std::filesystem::path official_package_file(const Env& env, std::string_view packageName) {
315+
if (packageName.empty()) return {};
316+
std::string name(packageName);
317+
return official_index_dir(env) / "pkgs" / std::string(1, name[0]) / (name + ".lua");
318+
}
319+
301320
void mark_index_refreshed(const std::filesystem::path& indexDir) {
302321
if (!std::filesystem::exists(index_pkgs_dir(indexDir))) return;
303322
std::error_code ec;
@@ -1016,6 +1035,14 @@ bool is_official_index_fresh(const Env& env, std::int64_t ttlSeconds) {
10161035
return is_index_dir_fresh(official_index_dir(env), ttlSeconds);
10171036
}
10181037

1038+
bool is_official_package_index_fresh(const Env& env,
1039+
std::string_view packageName,
1040+
std::int64_t ttlSeconds) {
1041+
if (!is_official_index_fresh(env, ttlSeconds)) return false;
1042+
auto pkg = official_package_file(env, packageName);
1043+
return !pkg.empty() && std::filesystem::exists(pkg);
1044+
}
1045+
10191046
int update_index(const Env& env, bool quiet) {
10201047
std::string cmd = build_command_prefix(env) + " update 2>&1";
10211048
int rc = mcpp::platform::process::run_streaming(cmd,
@@ -1040,4 +1067,14 @@ void ensure_official_index_fresh(const Env& env, std::int64_t ttlSeconds, bool q
10401067
update_index(env, /*quiet=*/true);
10411068
}
10421069

1070+
void ensure_official_package_index_fresh(const Env& env,
1071+
std::string_view packageName,
1072+
std::int64_t ttlSeconds,
1073+
bool quiet) {
1074+
if (is_official_package_index_fresh(env, packageName, ttlSeconds)) return;
1075+
if (!quiet)
1076+
print_status("Updating", "package index (auto-refresh)");
1077+
update_index(env, /*quiet=*/true);
1078+
}
1079+
10431080
} // namespace mcpp::xlings

tests/unit/test_xlings.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,28 @@ TEST(XlingsIndexFreshness, AcceptsFreshOfficialXimIndex) {
8686

8787
std::filesystem::remove_all(home);
8888
}
89+
90+
TEST(XlingsIndexFreshness, RequiresOfficialPackageFileEvenWhenOfficialIndexIsFresh) {
91+
auto home = make_tempdir("mcpp-xlings-index-freshness");
92+
std::filesystem::create_directories(home / "data" / "xim-pkgindex" / "pkgs");
93+
std::ofstream(home / "data" / "xim-pkgindex" / ".mcpp-index-updated") << "ok\n";
94+
95+
mcpp::xlings::Env env{.home = home};
96+
97+
EXPECT_FALSE(mcpp::xlings::is_official_package_index_fresh(env, "musl-gcc", 3600));
98+
99+
std::filesystem::remove_all(home);
100+
}
101+
102+
TEST(XlingsIndexFreshness, AcceptsFreshOfficialPackageFile) {
103+
auto home = make_tempdir("mcpp-xlings-index-freshness");
104+
std::filesystem::create_directories(home / "data" / "xim-pkgindex" / "pkgs" / "m");
105+
std::ofstream(home / "data" / "xim-pkgindex" / ".mcpp-index-updated") << "ok\n";
106+
std::ofstream(home / "data" / "xim-pkgindex" / "pkgs" / "m" / "musl-gcc.lua") << "package = {}\n";
107+
108+
mcpp::xlings::Env env{.home = home};
109+
110+
EXPECT_TRUE(mcpp::xlings::is_official_package_index_fresh(env, "musl-gcc", 3600));
111+
112+
std::filesystem::remove_all(home);
113+
}

0 commit comments

Comments
 (0)