fix(jobs): autodetectar distro WSL + normalizar separadores UNC (issue 0026)
El usuario reportaba "no enrichers for url" en Windows. Tres bugs:
1. resolve_registry_root tenia el fallback hardcoded a "Ubuntu" pero la
distro real era "Ubuntu-22.04". Reemplazado por detect_wsl_distro()
que sondea las distros comunes (Ubuntu, Ubuntu-24.04, Ubuntu-22.04,
Ubuntu-20.04, Debian, kali-linux, Fedora, openSUSE-Tumbleweed) y se
queda con la primera cuyo UNC tenga registry.db.
2. enrichers_load construia paths con mixed separators
("\\\\wsl.localhost\\Ubuntu-22.04\\...\\enrichers/foo/manifest.yaml")
que confunden a opendir de MinGW. Ahora normaliza todo a backslashes
en Windows antes de opendir + concatena con el separador nativo.
3. El menu "Run enricher" decia simplemente "(no enrichers para tipo X)"
sin distinguir si era 0/N (no se carga ninguno) o N>0/M (existen pero
ninguno aplica). Ahora muestra "(no enrichers cargados — revisa
FN_REGISTRY_ROOT)" vs "(0/4 enrichers para tipo 'url')".
Si el usuario tiene una distro con nombre raro, sigue pudiendo setear
FN_REGISTRY_ROOT explicitamente.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+20
-5
@@ -108,19 +108,34 @@ int enrichers_load(const char* enrichers_dir) {
|
||||
g_enrichers.clear();
|
||||
if (!enrichers_dir || !*enrichers_dir) return -1;
|
||||
|
||||
DIR* d = opendir(enrichers_dir);
|
||||
if (!d) return -1;
|
||||
// En Windows los UNC paths esperan backslashes consistentes; mixed
|
||||
// separators (`\\wsl$\<distro>\foo/bar`) confunden a opendir de MinGW.
|
||||
std::string dir = enrichers_dir;
|
||||
#ifdef _WIN32
|
||||
for (char& c : dir) if (c == '/') c = '\\';
|
||||
#endif
|
||||
|
||||
DIR* d = opendir(dir.c_str());
|
||||
if (!d) {
|
||||
std::fprintf(stderr, "[enrichers] opendir failed: %s\n", dir.c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct dirent* ent;
|
||||
while ((ent = readdir(d)) != nullptr) {
|
||||
if (ent->d_name[0] == '.') continue;
|
||||
|
||||
std::string sub = std::string(enrichers_dir) + "/" + ent->d_name;
|
||||
#ifdef _WIN32
|
||||
const char sep = '\\';
|
||||
#else
|
||||
const char sep = '/';
|
||||
#endif
|
||||
std::string sub = dir + sep + ent->d_name;
|
||||
struct stat st{};
|
||||
if (stat(sub.c_str(), &st) != 0 || !S_ISDIR(st.st_mode)) continue;
|
||||
|
||||
std::string manifest = sub + "/manifest.yaml";
|
||||
std::string runpy = sub + "/run.py";
|
||||
std::string manifest = sub + sep + "manifest.yaml";
|
||||
std::string runpy = sub + sep + "run.py";
|
||||
if (stat(manifest.c_str(), &st) != 0) continue;
|
||||
if (stat(runpy.c_str(), &st) != 0) continue;
|
||||
|
||||
|
||||
@@ -252,14 +252,35 @@ static bool load_input(bool first_load = true);
|
||||
// Registry path resolution (issue 0026)
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifdef _WIN32
|
||||
// Detecta la distro WSL "default" buscando que UNC `\\wsl.localhost\<name>\`
|
||||
// existe y contiene `home/lucas/fn_registry/registry.db`. Devuelve "" si no
|
||||
// encuentra ninguna. Probamos las distros comunes — el usuario sobrescribe
|
||||
// con FN_REGISTRY_ROOT si tiene una con nombre raro.
|
||||
static std::string detect_wsl_distro() {
|
||||
const char* candidates[] = {
|
||||
"Ubuntu", "Ubuntu-24.04", "Ubuntu-22.04", "Ubuntu-20.04",
|
||||
"Debian", "kali-linux", "Fedora", "openSUSE-Tumbleweed",
|
||||
nullptr
|
||||
};
|
||||
for (int i = 0; candidates[i]; ++i) {
|
||||
std::string probe = std::string("\\\\wsl.localhost\\") + candidates[i] +
|
||||
"\\home\\lucas\\fn_registry\\registry.db";
|
||||
FILE* f = std::fopen(probe.c_str(), "rb");
|
||||
if (f) { std::fclose(f); return candidates[i]; }
|
||||
}
|
||||
return "";
|
||||
}
|
||||
#endif
|
||||
|
||||
// Devuelve el path absoluto al root de fn_registry. Estrategia:
|
||||
// 1) FN_REGISTRY_ROOT env var (acepta path Linux o UNC Windows
|
||||
// `\\\\wsl.localhost\\Ubuntu\\home\\...`).
|
||||
// `\\\\wsl.localhost\\<distro>\\home\\...`).
|
||||
// 2) Sube desde getcwd() buscando un dir con `registry.db`.
|
||||
// 3) En Windows, fallback al UNC default `\\\\wsl.localhost\\Ubuntu\\home\\
|
||||
// lucas\\fn_registry` (la build se distribuye al desktop fuera del
|
||||
// arbol del registry, asi que getcwd nunca lo encuentra).
|
||||
// 4) "" si no se encuentra.
|
||||
// 3) En Windows, sondear UNCs de las distros comunes hasta encontrar
|
||||
// una con `registry.db`. La build se distribuye al desktop fuera del
|
||||
// arbol del registry, asi que getcwd nunca lo encuentra.
|
||||
// 4) "" si no se encuentra (los enrichers quedan desactivados).
|
||||
static std::string resolve_registry_root() {
|
||||
if (const char* env = std::getenv("FN_REGISTRY_ROOT")) {
|
||||
if (env && *env) return env;
|
||||
@@ -268,7 +289,6 @@ static std::string resolve_registry_root() {
|
||||
if (getcwd(cwd, sizeof(cwd)) != nullptr) {
|
||||
std::string p = cwd;
|
||||
#ifdef _WIN32
|
||||
// Normalizar separadores para comparar.
|
||||
for (char& c : p) if (c == '\\') c = '/';
|
||||
#endif
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
@@ -281,9 +301,15 @@ static std::string resolve_registry_root() {
|
||||
}
|
||||
}
|
||||
#ifdef _WIN32
|
||||
// Fallback Windows: el UNC apunta al WSL del usuario. Ajustar el nombre
|
||||
// de la distro si no es "Ubuntu". La build Linux/WSL nunca llega aqui.
|
||||
return "\\\\wsl.localhost\\Ubuntu\\home\\lucas\\fn_registry";
|
||||
std::string distro = detect_wsl_distro();
|
||||
if (!distro.empty()) {
|
||||
return std::string("\\\\wsl.localhost\\") + distro +
|
||||
"\\home\\lucas\\fn_registry";
|
||||
}
|
||||
std::fprintf(stderr,
|
||||
"[graph_explorer] no se detecta la distro WSL — "
|
||||
"setea FN_REGISTRY_ROOT con el UNC del registry.\n");
|
||||
return "";
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
@@ -676,18 +702,23 @@ static void render_context_menu() {
|
||||
// issue 0026 — listamos enrichers cuyo applies_to incluye este type.
|
||||
const char* type_name = (n.type_id < (uint16_t)g_graph.type_count)
|
||||
? g_graph.types[n.type_id].name : "";
|
||||
auto specs = ge::enrichers_for_type(type_name);
|
||||
const auto& all = ge::enrichers_all();
|
||||
auto specs = ge::enrichers_for_type(type_name);
|
||||
if (!sql_id) {
|
||||
ImGui::TextDisabled("(node has no entity id)");
|
||||
} else if (all.empty()) {
|
||||
ImGui::TextDisabled("(no enrichers cargados)");
|
||||
ImGui::TextDisabled("revisa FN_REGISTRY_ROOT");
|
||||
} else if (specs.empty()) {
|
||||
ImGui::TextDisabled("(no enrichers para tipo '%s')", type_name);
|
||||
ImGui::TextDisabled("(0/%d enrichers para tipo '%s')",
|
||||
(int)all.size(), type_name);
|
||||
} else {
|
||||
for (const auto& s : specs) {
|
||||
if (ImGui::MenuItem(s.name.c_str())) {
|
||||
char job_id[64];
|
||||
bool ok = ge::jobs_submit(s.id.c_str(), sql_id, lbl,
|
||||
"{}", job_id, sizeof(job_id));
|
||||
if (ok) g_app.panel_jobs = true; // abrir panel auto
|
||||
if (ok) g_app.panel_jobs = true;
|
||||
}
|
||||
if (!s.description.empty() && ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("%s", s.description.c_str());
|
||||
|
||||
Reference in New Issue
Block a user