Skip to content

Commit 5dd487e

Browse files
committed
feat(run): auto-resolve global packages in vix run
- auto-enable deps for single C++ files (vix run main.cpp) - load global packages from ~/.vix/global/installed.json - inject global include paths alongside local .vix/deps - preserve local priority over global packages - unify behavior between run and watch modes - extend ScriptCMake to support global packages with CMake or header-only Now global installs (vix install -g) work transparently with vix run
1 parent a720dc5 commit 5dd487e

3 files changed

Lines changed: 405 additions & 32 deletions

File tree

src/commands/run/RunFlow.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,15 @@ namespace vix::commands::RunCommand::detail
504504
o.forceScriptLike = false;
505505
}
506506

507+
// Auto-enable deps for single-file C++ scripts so that:
508+
// vix run main.cpp
509+
// also resolves local/global packages without requiring --auto-deps.
510+
if (o.singleCpp)
511+
{
512+
if (o.autoDeps != AutoDepsMode::Up)
513+
o.autoDeps = AutoDepsMode::Local;
514+
}
515+
507516
// normalize clearMode
508517
for (auto &c : o.clearMode)
509518
c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));

src/commands/run/RunScript.cpp

Lines changed: 111 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@
2929
#include <cstring>
3030
#include <iostream>
3131
#include <chrono>
32+
#include <optional>
33+
#include <unordered_set>
34+
#include <cstdlib>
35+
#include <algorithm>
36+
#include <nlohmann/json.hpp>
3237

3338
#ifndef _WIN32
3439
#include <unistd.h>
@@ -68,6 +73,39 @@ namespace vix::commands::RunCommand::detail
6873
return false;
6974
};
7075

76+
auto home_dir = []() -> std::optional<std::string>
77+
{
78+
#ifdef _WIN32
79+
const char *home = std::getenv("USERPROFILE");
80+
#else
81+
const char *home = std::getenv("HOME");
82+
#endif
83+
if (!home || std::string(home).empty())
84+
return std::nullopt;
85+
return std::string(home);
86+
};
87+
88+
auto vix_root = [&]() -> fs::path
89+
{
90+
if (const auto home = home_dir(); home)
91+
return fs::path(*home) / ".vix";
92+
return fs::path(".vix");
93+
};
94+
95+
auto global_manifest_path = [&]() -> fs::path
96+
{
97+
return vix_root() / "global" / "installed.json";
98+
};
99+
100+
auto dep_id_to_dir = [](std::string depId) -> std::string
101+
{
102+
depId.erase(std::remove(depId.begin(), depId.end(), '@'), depId.end());
103+
std::replace(depId.begin(), depId.end(), '/', '.');
104+
return depId;
105+
};
106+
107+
std::unordered_set<std::string> localPkgDirs;
108+
71109
auto scan_one = [&](const fs::path &baseDir)
72110
{
73111
const fs::path depsRoot = baseDir / ".vix" / "deps";
@@ -82,6 +120,10 @@ namespace vix::commands::RunCommand::detail
82120
if (!it->is_directory())
83121
continue;
84122

123+
const std::string pkgDir = it->path().filename().string();
124+
if (!pkgDir.empty())
125+
localPkgDirs.insert(pkgDir);
126+
85127
const fs::path inc = it->path() / "include";
86128
if (!fs::exists(inc, ec) || ec)
87129
continue;
@@ -92,14 +134,66 @@ namespace vix::commands::RunCommand::detail
92134
}
93135
};
94136

95-
// Local: scan startDir only
137+
auto scan_global = [&]()
138+
{
139+
const fs::path manifestPath = global_manifest_path();
140+
if (!fs::exists(manifestPath))
141+
return;
142+
143+
std::ifstream ifs(manifestPath);
144+
if (!ifs)
145+
return;
146+
147+
nlohmann::json root;
148+
ifs >> root;
149+
150+
if (!root.is_object() || !root.contains("packages") || !root["packages"].is_array())
151+
return;
152+
153+
for (const auto &item : root["packages"])
154+
{
155+
if (!item.is_object())
156+
continue;
157+
158+
if (!item.contains("id") || !item["id"].is_string())
159+
continue;
160+
161+
if (!item.contains("installed_path") || !item["installed_path"].is_string())
162+
continue;
163+
164+
const std::string id = item["id"].get<std::string>();
165+
const std::string pkgDir = dep_id_to_dir(id);
166+
167+
// priorité au local
168+
if (localPkgDirs.contains(pkgDir))
169+
continue;
170+
171+
std::string includeDir = "include";
172+
if (item.contains("include") && item["include"].is_string())
173+
includeDir = item["include"].get<std::string>();
174+
175+
const fs::path installedPath = fs::path(item["installed_path"].get<std::string>());
176+
const fs::path inc = installedPath / includeDir;
177+
178+
std::error_code ec;
179+
if (!fs::exists(inc, ec) || ec)
180+
continue;
181+
182+
const std::string incStr = inc.string();
183+
if (!already_has_I(incStr))
184+
opt.scriptFlags.push_back("-I" + incStr);
185+
}
186+
};
187+
188+
// Local: scan startDir only, then globals
96189
if (opt.autoDeps == AutoDepsMode::Local)
97190
{
98191
scan_one(startDir);
192+
scan_global();
99193
return;
100194
}
101195

102-
// Up: scan startDir and all parents up to filesystem root
196+
// Up: scan startDir and all parents up to filesystem root, then globals
103197
if (opt.autoDeps == AutoDepsMode::Up)
104198
{
105199
fs::path cur = startDir;
@@ -112,12 +206,13 @@ namespace vix::commands::RunCommand::detail
112206
if (parent.empty() || parent == cur)
113207
break;
114208

115-
// Stop at root ("/" or drive root)
116209
if (fs::equivalent(parent, cur, ec) && !ec)
117210
break;
118211

119212
cur = parent;
120213
}
214+
215+
scan_global();
121216
return;
122217
}
123218
}
@@ -648,13 +743,21 @@ namespace vix::commands::RunCommand::detail
648743
using namespace std;
649744
namespace fs = std::filesystem;
650745

651-
const fs::path script = opt.cppFile;
746+
Options o = opt;
747+
748+
const fs::path script = o.cppFile;
652749
if (!fs::exists(script))
653750
{
654751
error("C++ file not found: " + script.string());
655752
return 1;
656753
}
657754

755+
// auto deps (single .cpp)
756+
if (o.autoDeps != AutoDepsMode::None)
757+
{
758+
apply_auto_deps_includes_from_deps_folder(o, script.parent_path());
759+
}
760+
658761
const string exeName = script.stem().string();
659762

660763
fs::path scriptsRoot = get_scripts_root();
@@ -673,17 +776,17 @@ namespace vix::commands::RunCommand::detail
673776
exeName,
674777
script,
675778
useVixRuntime,
676-
opt.scriptFlags);
779+
o.scriptFlags);
677780
}
678781

679782
fs::path buildDir = projectDir / "build-ninja";
680783
const fs::path sigFile = projectDir / ".vix-config.sig";
681784

682785
const std::string sig = make_script_config_signature(
683786
useVixRuntime,
684-
opt.enableSanitizers,
685-
opt.enableUbsanOnly,
686-
opt.scriptFlags);
787+
o.enableSanitizers,
788+
o.enableUbsanOnly,
789+
o.scriptFlags);
687790

688791
bool needConfigure = true;
689792
{

0 commit comments

Comments
 (0)