Skip to content

Commit 5e1c9c2

Browse files
committed
fix: xlings on Windows must cd to XLINGS_HOME (self-contained sandbox)
Root cause: xlings resolves its home from the working directory or binary location. On Linux, build_command_prefix does `cd <home> &&` before invoking xlings. On Windows this was missing — xlings installed packages to its default location instead of mcpp's sandbox. Fix: add `cd /d "<home>" &&` to all Windows xlings invocations (build_command_prefix, install_with_progress, ensure_init). Also removed the fallback that copied from ~/.xlings/ — mcpp must be self-contained, not depend on system xlings.
1 parent 77f4b3e commit 5e1c9c2

2 files changed

Lines changed: 14 additions & 32 deletions

File tree

src/pm/package_fetcher.cppm

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -605,28 +605,6 @@ Fetcher::resolve_xpkg_path(std::string_view target,
605605
};
606606

607607
auto resolve = [&]() -> std::expected<XpkgPayload, CallError> {
608-
// xlings may install the package into its global home rather than
609-
// the mcpp sandbox. If the expected path is missing, copy from the
610-
// global xlings data directory.
611-
if (!std::filesystem::exists(verdir)) {
612-
auto xhome = std::getenv("HOME");
613-
#if defined(_WIN32)
614-
if (!xhome) xhome = std::getenv("USERPROFILE");
615-
#endif
616-
if (xhome) {
617-
auto globalDir = std::filesystem::path(xhome)
618-
/ ".xlings" / "data" / "xpkgs"
619-
/ verdir.parent_path().filename()
620-
/ verdir.filename();
621-
std::error_code ec;
622-
if (std::filesystem::exists(globalDir, ec)) {
623-
std::filesystem::create_directories(verdir.parent_path(), ec);
624-
std::filesystem::copy(globalDir, verdir,
625-
std::filesystem::copy_options::recursive
626-
| std::filesystem::copy_options::overwrite_existing, ec);
627-
}
628-
}
629-
}
630608
if (!std::filesystem::exists(verdir)) {
631609
return std::unexpected(CallError{
632610
std::format("xpkg payload missing: {}", verdir.string())});

src/xlings.cppm

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -428,19 +428,18 @@ std::filesystem::path sandbox_init_marker(const Env& env) {
428428
std::string build_command_prefix(const Env& env) {
429429
auto xvmBin = paths::sandbox_bin(env).string();
430430
#if defined(_WIN32)
431-
// Windows: set environment variables via the process environment
432-
// (cmd.exe `set` in compound &&-chains is unreliable) then invoke
433-
// xlings directly. _putenv_s is inherited by popen/system child.
431+
// Windows: set environment variables via _putenv_s (inherited by
432+
// child processes) AND cd to the sandbox home (xlings may use cwd
433+
// to resolve its home). Return a "cd /d <home> && <binary>" prefix.
434434
_putenv_s("XLINGS_HOME", env.home.string().c_str());
435435
_putenv_s("XLINGS_PROJECT_DIR",
436436
env.projectDir.empty() ? "" : env.projectDir.string().c_str());
437-
// Prepend sandbox bin to PATH
438437
{
439438
std::string newPath = xvmBin + ";" + (std::getenv("PATH") ? std::getenv("PATH") : "");
440439
_putenv_s("PATH", newPath.c_str());
441440
}
442-
// Return raw path — no quoting to avoid cmd.exe double-quote parsing issues
443-
return env.binary.string();
441+
return std::format("cd /d \"{}\" && \"{}\"",
442+
env.home.string(), env.binary.string());
444443
#else
445444
if (env.projectDir.empty()) {
446445
// Global mode: unset XLINGS_PROJECT_DIR (existing behavior).
@@ -664,11 +663,15 @@ int install_with_progress(const Env& env, std::string_view target,
664663
R"({{"targets":["{}"],"yes":true}})", target);
665664

666665
#if defined(_WIN32)
666+
// Ensure xlings sees XLINGS_HOME + runs from the sandbox dir.
667+
// Both _putenv_s (inherited by child) and cd /d (working dir) are
668+
// needed — xlings may resolve its home from either.
667669
_putenv_s("XLINGS_HOME", env.home.string().c_str());
668670
_putenv_s("XLINGS_PROJECT_DIR", "");
669-
// Use raw path (no quoting) to avoid cmd.exe double-quote parsing issues.
670-
// Wrap only the JSON arg in single-escaped quotes for the C runtime.
671-
auto cmd = std::format("{} interface install_packages --args {} 2>nul",
671+
std::error_code ec_mkdir;
672+
std::filesystem::create_directories(env.home, ec_mkdir);
673+
auto cmd = std::format("cd /d \"{}\" && \"{}\" interface install_packages --args {} 2>nul",
674+
env.home.string(),
672675
env.binary.string(),
673676
shq(argsJson));
674677
#else
@@ -802,7 +805,8 @@ void ensure_init(const Env& env, bool quiet) {
802805
#if defined(_WIN32)
803806
_putenv_s("XLINGS_HOME", env.home.string().c_str());
804807
_putenv_s("XLINGS_PROJECT_DIR", "");
805-
auto cmd = env.binary.string() + " self init";
808+
auto cmd = std::format("cd /d \"{}\" && \"{}\" self init",
809+
env.home.string(), env.binary.string());
806810
#else
807811
auto cmd = std::format(
808812
"cd {} && env -u XLINGS_PROJECT_DIR XLINGS_HOME={} {} self init >/dev/null 2>&1",

0 commit comments

Comments
 (0)