@@ -24,6 +24,8 @@ import mcpp.pm.index_spec;
2424import mcpp.xlings;
2525import mcpp.platform;
2626import mcpp.log;
27+ import mcpp.fallback.xlings_binary;
28+ import mcpp.fallback.config_migration;
2729
2830export namespace mcpp ::config {
2931
@@ -265,55 +267,7 @@ bool write_default_xlings_json(const std::filesystem::path& path,
265267 return std::filesystem::exists (path);
266268}
267269
268- bool replace_all (std::string& text, std::string_view from, std::string_view to) {
269- bool changed = false ;
270- for (std::size_t pos = 0 ;
271- (pos = text.find (from, pos)) != std::string::npos;) {
272- text.replace (pos, from.size (), to);
273- pos += to.size ();
274- changed = true ;
275- }
276- return changed;
277- }
278-
279- bool write_text_if_changed (const std::filesystem::path& path,
280- const std::string& original,
281- const std::string& updated) {
282- if (updated == original) return false ;
283- write_file (path, updated);
284- return true ;
285- }
286-
287- bool migrate_legacy_config_toml_index_names (const std::filesystem::path& path) {
288- std::ifstream is (path);
289- if (!is) return false ;
290- std::stringstream ss;
291- ss << is.rdbuf ();
292- auto original = ss.str ();
293- auto updated = original;
294-
295- replace_all (updated, " default = \" mcpp-index\" " , " default = \" mcpplibs\" " );
296- replace_all (updated, " [index.repos.\" mcpp-index\" ]" , " [index.repos.\" mcpplibs\" ]" );
297-
298- return write_text_if_changed (path, original, updated);
299- }
300-
301- bool migrate_legacy_xlings_json_index_names (const std::filesystem::path& path) {
302- std::ifstream is (path);
303- if (!is) return false ;
304- std::stringstream ss;
305- ss << is.rdbuf ();
306- auto original = ss.str ();
307- auto updated = original;
308-
309- // Older mcpp sandboxes seeded the package index under the repository
310- // name. Keep the URL and all xlings state intact; only rename the index
311- // key so xlings config/list output matches mcpp's default namespace.
312- replace_all (updated, " \" name\" : \" mcpp-index\" " , " \" name\" : \" mcpplibs\" " );
313- replace_all (updated, " \" name\" :\" mcpp-index\" " , " \" name\" :\" mcpplibs\" " );
314-
315- return write_text_if_changed (path, original, updated);
316- }
270+ // Migration helpers delegated to mcpp.fallback.config_migration.
317271
318272void canonicalize_legacy_index_names (GlobalConfig& cfg) {
319273 if (cfg.defaultIndex == " mcpp-index" )
@@ -334,65 +288,7 @@ void canonicalize_legacy_index_names(GlobalConfig& cfg) {
334288 cfg.indexRepos = std::move (normalized);
335289}
336290
337- // Try to acquire xlings binary. Returns the path if successful.
338- std::expected<std::filesystem::path, std::string>
339- acquire_xlings_binary (const std::filesystem::path& destBin, bool quiet)
340- {
341- if (std::filesystem::exists (destBin)) return destBin;
342-
343- std::error_code ec;
344- std::filesystem::create_directories (destBin.parent_path (), ec);
345-
346- // 1. Explicit override
347- if (auto * e = std::getenv (" MCPP_VENDORED_XLINGS" ); e && *e) {
348- std::filesystem::path src{e};
349- if (std::filesystem::exists (src)) {
350- std::filesystem::copy_file (src, destBin,
351- std::filesystem::copy_options::overwrite_existing, ec);
352- if (!ec) {
353- std::filesystem::permissions (destBin,
354- std::filesystem::perms::owner_exec
355- | std::filesystem::perms::group_exec
356- | std::filesystem::perms::others_exec,
357- std::filesystem::perm_options::add, ec);
358- if (!quiet) print_status (" Bundled" ,
359- std::format (" xlings v{} (from MCPP_VENDORED_XLINGS)" , kXlingsPinnedVersion ));
360- return destBin;
361- }
362- }
363- }
364-
365- // 2. Copy from system (`which xlings`)
366- auto xlings_name = std::string (" xlings" ) + std::string (mcpp::platform::exe_suffix);
367- auto sysXlings = mcpp::platform::fs::which (xlings_name);
368- if (sysXlings) {
369- std::string p = sysXlings->string ();
370- if (!p.empty () && std::filesystem::exists (p)) {
371- std::filesystem::copy_file (p, destBin,
372- std::filesystem::copy_options::overwrite_existing, ec);
373- if (!ec) {
374- std::filesystem::permissions (destBin,
375- std::filesystem::perms::owner_exec
376- | std::filesystem::perms::group_exec
377- | std::filesystem::perms::others_exec,
378- std::filesystem::perm_options::add, ec);
379- if (!quiet) print_status (" Bundled" ,
380- std::format (" xlings (copied from system: {})" , p));
381- return destBin;
382- }
383- }
384- }
385-
386- // 3. Download from GitHub Release (placeholder — real impl uses curl)
387- // We delegate to curl/wget in the bash bootstrap; for in-process robustness
388- // we just instruct the user.
389- return std::unexpected (std::format (
390- " xlings binary not found. Either:\n "
391- " - install via: curl -fsSL https://raw.githubusercontent.com/d2learn/xlings/refs/heads/main/tools/other/quick_install.sh | bash\n "
392- " - export MCPP_VENDORED_XLINGS=/abs/path/to/xlings\n "
393- " - set [xlings].binary = \" system\" in {}" ,
394- (destBin.parent_path ().parent_path () / " config.toml" ).string ()));
395- }
291+ // Xlings binary acquisition delegated to mcpp.fallback.xlings_binary.
396292
397293// Run `xlings self init` against the sandbox to create the standard
398294// directory layout (subos/default/{bin,lib,usr,generations}, data/, config/,
@@ -471,7 +367,7 @@ std::expected<GlobalConfig, ConfigError> load_or_init(
471367 // 3. Seed config.toml if missing
472368 bool fresh_config = !std::filesystem::exists (cfg.configFile );
473369 if (fresh_config) write_default_config_toml (cfg.configFile );
474- else migrate_legacy_config_toml_index_names (cfg.configFile );
370+ else mcpp::fallback::migrate_config_toml_index_names (cfg.configFile );
475371
476372 // 4. Load config.toml
477373 auto doc = t::parse_file (cfg.configFile );
@@ -556,12 +452,12 @@ std::expected<GlobalConfig, ConfigError> load_or_init(
556452 if (!std::filesystem::exists (xjson)) {
557453 write_default_xlings_json (xjson, cfg.indexRepos );
558454 } else {
559- migrate_legacy_xlings_json_index_names (xjson);
455+ mcpp::fallback::migrate_xlings_json_index_names (xjson);
560456 }
561457
562458 // 6. Acquire xlings binary if needed
563459 if (cfg.xlingsBinaryMode == " bundled" ) {
564- auto xbin = acquire_xlings_binary (cfg.xlingsBinary , quiet);
460+ auto xbin = mcpp::fallback:: acquire_xlings_binary (cfg.xlingsBinary , quiet);
565461 if (!xbin) return std::unexpected (ConfigError{xbin.error ()});
566462 } else if (cfg.xlingsBinaryMode == " system" ) {
567463 auto sysPath = mcpp::platform::fs::which (
0 commit comments