Skip to content

Commit fc4a05b

Browse files
authored
fix: implement index auto-refresh (searchTtlSeconds) (#31)
Three improvements to the package index update mechanism: 1. Implement searchTtlSeconds auto-refresh: new ensure_index_fresh() checks if local index data exists and is within the configured TTL (default 3600s). Runs `xlings update` automatically when stale. 2. mcpp build auto-triggers index update: before dependency resolution, checks if the project has version-source deps and the index is missing/stale. Prevents silent failure on fresh installs. 3. Fix misleading "Updating registry index" in mcpp search: replaced with actual auto-refresh via ensure_index_fresh() — only prints when an update actually happens. Also refactored cmd_index_update to use xlings::update_index instead of manual popen.
1 parent f9b22e0 commit fc4a05b

2 files changed

Lines changed: 79 additions & 9 deletions

File tree

src/cli.cppm

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1191,6 +1191,22 @@ prepare_build(bool print_fingerprint,
11911191
// and ODR-respecting symbols, so the same `(ns, name)` resolved to
11921192
// two different exact versions is an error — mcpp prints both
11931193
// requesting parents and asks the user to align them.
1194+
1195+
// Auto-refresh the package index if the project has version-source
1196+
// dependencies and the local index is missing or stale.
1197+
if (!m->dependencies.empty()) {
1198+
bool hasVersionDeps = false;
1199+
for (auto& [_, spec] : m->dependencies) {
1200+
if (!spec.isPath() && !spec.isGit()) { hasVersionDeps = true; break; }
1201+
}
1202+
if (hasVersionDeps) {
1203+
auto cfg2 = get_cfg();
1204+
if (cfg2) {
1205+
auto xlEnv = mcpp::config::make_xlings_env(**cfg2);
1206+
mcpp::xlings::ensure_index_fresh(xlEnv, (*cfg2)->searchTtlSeconds);
1207+
}
1208+
}
1209+
}
11941210
std::vector<mcpp::modgraph::PackageRoot> packages;
11951211
packages.push_back({*root, *m});
11961212

@@ -2311,7 +2327,8 @@ int cmd_search(const mcpplibs::cmdline::ParsedArgs& parsed) {
23112327
auto cfg = mcpp::config::load_or_init(/*quiet=*/false, make_bootstrap_progress_callback());
23122328
if (!cfg) { mcpp::ui::error(cfg.error().message); return 4; }
23132329

2314-
mcpp::ui::info("Updating", std::format("registry index `{}`", cfg->defaultIndex));
2330+
auto xlEnv = mcpp::config::make_xlings_env(*cfg);
2331+
mcpp::xlings::ensure_index_fresh(xlEnv, cfg->searchTtlSeconds);
23152332

23162333
mcpp::fetcher::Fetcher f(*cfg);
23172334
auto hits = f.search(keyword);
@@ -2390,14 +2407,7 @@ int cmd_index_update(const mcpplibs::cmdline::ParsedArgs& /*parsed*/) {
23902407
if (!cfg) { mcpp::ui::error(cfg.error().message); return 4; }
23912408
mcpp::ui::status("Updating", "all index repos");
23922409
auto xlEnv = mcpp::config::make_xlings_env(*cfg);
2393-
std::string cmd = mcpp::xlings::build_command_prefix(xlEnv) + " update 2>&1";
2394-
std::array<char, 4096> buf{};
2395-
std::FILE* fp = ::popen(cmd.c_str(), "r");
2396-
if (!fp) { mcpp::ui::error("failed to spawn index updater"); return 1; }
2397-
while (std::fgets(buf.data(), buf.size(), fp)) {
2398-
std::fputs(buf.data(), stdout);
2399-
}
2400-
int rc = ::pclose(fp);
2410+
int rc = mcpp::xlings::update_index(xlEnv);
24012411
if (rc != 0) { mcpp::ui::error("index update failed"); return 1; }
24022412
mcpp::ui::status("Updated", "index refresh complete");
24032413
return 0;

src/xlings.cppm

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,21 @@ void ensure_patchelf(const Env& env, bool quiet,
202202
void ensure_ninja(const Env& env, bool quiet,
203203
const BootstrapProgressCallback& cb);
204204

205+
// ─── Index freshness ────────────────────────────────────────────────
206+
207+
// Check whether local index data exists and is fresh (within ttlSeconds).
208+
// Returns true if index is present and fresh, false otherwise.
209+
bool is_index_fresh(const Env& env, std::int64_t ttlSeconds);
210+
211+
// Run `xlings update` to refresh all index repos. Streams output to stdout.
212+
// Returns the xlings exit code.
213+
int update_index(const Env& env, bool quiet = false);
214+
215+
// Ensure the local index is present and fresh. Runs `xlings update` if
216+
// the index is missing or older than ttlSeconds. Idempotent and quiet
217+
// when no update is needed.
218+
void ensure_index_fresh(const Env& env, std::int64_t ttlSeconds, bool quiet = false);
219+
205220
// ─── run_capture utility ────────────────────────────────────────────
206221

207222
std::expected<std::string, std::string> run_capture(const std::string& cmd);
@@ -745,4 +760,49 @@ void ensure_ninja(const Env& env, bool quiet,
745760
}
746761
}
747762

763+
// ─── Index freshness ────────────────────────────────────────────────
764+
765+
bool is_index_fresh(const Env& env, std::int64_t ttlSeconds) {
766+
auto data = paths::index_data(env);
767+
if (!std::filesystem::exists(data)) return false;
768+
769+
// Look for any directory under data/ that has a pkgs/ subdirectory —
770+
// that's a cloned index repo.
771+
std::error_code ec;
772+
bool hasIndex = false;
773+
std::filesystem::file_time_type newest{};
774+
for (auto& entry : std::filesystem::directory_iterator(data, ec)) {
775+
if (!entry.is_directory()) continue;
776+
auto pkgsDir = entry.path() / "pkgs";
777+
if (!std::filesystem::exists(pkgsDir)) continue;
778+
hasIndex = true;
779+
auto t = std::filesystem::last_write_time(pkgsDir, ec);
780+
if (!ec && t > newest) newest = t;
781+
}
782+
if (!hasIndex) return false;
783+
784+
// Check TTL
785+
auto now = std::filesystem::file_time_type::clock::now();
786+
auto age = std::chrono::duration_cast<std::chrono::seconds>(now - newest);
787+
return age.count() < ttlSeconds;
788+
}
789+
790+
int update_index(const Env& env, bool quiet) {
791+
std::string cmd = build_command_prefix(env) + " update 2>&1";
792+
std::array<char, 4096> buf{};
793+
std::FILE* fp = ::popen(cmd.c_str(), "r");
794+
if (!fp) return -1;
795+
while (std::fgets(buf.data(), buf.size(), fp)) {
796+
if (!quiet) std::fputs(buf.data(), stdout);
797+
}
798+
return ::pclose(fp);
799+
}
800+
801+
void ensure_index_fresh(const Env& env, std::int64_t ttlSeconds, bool quiet) {
802+
if (is_index_fresh(env, ttlSeconds)) return;
803+
if (!quiet)
804+
print_status("Updating", "package index (auto-refresh)");
805+
update_index(env, quiet);
806+
}
807+
748808
} // namespace mcpp::xlings

0 commit comments

Comments
 (0)