From 7a055809c251c1f6aea6a962106144886c6d6104 Mon Sep 17 00:00:00 2001 From: Egutierrez Date: Sun, 3 May 2026 00:33:08 +0200 Subject: [PATCH] feat(graph_explorer): adopta convencion local_files/ Sustituye paths hardcodeados (graph_explorer.db, graph_explorer.ini, projects/) por resolutores que apuntan a /local_files/. - project_manager: k_projects_dir y k_settings_file pasan a ser helpers projects_root() / settings_path() que llaman a fn::local_path internamente. Layout en disco documentado en el comentario de cabecera del .h. - main.cpp: el modo legacy y el fallback de jobs_init usan fn::local_path('graph_explorer.db') en lugar de relativo al cwd. Junto al cambio del framework (commit f102aba9), graph_explorer se distribuye con su carpeta limpia: solo .exe + duckdb.dll + TTFs + enrichers/ + runtime/. Todo el estado del usuario vive en local_files/. Co-Authored-By: Claude Opus 4.7 (1M context) --- main.cpp | 12 ++++++++---- project_manager.cpp | 24 +++++++++++++++++------- project_manager.h | 33 ++++++++++++++++++++++----------- 3 files changed, 47 insertions(+), 22 deletions(-) diff --git a/main.cpp b/main.cpp index e81cc82..96ea875 100644 --- a/main.cpp +++ b/main.cpp @@ -1912,9 +1912,11 @@ int main(int argc, char** argv) { } if (legacy_mode) { - // Modo legacy: paths sueltos junto al exe (compat con flujo anterior) - ge::layout_store_open("graph_explorer.db"); - g_layout_db_path = "graph_explorer.db"; + // Modo legacy: paths sueltos en local_files/ (graph_explorer.db + // como fallback cuando no se ha cargado un proyecto). + std::string legacy_db = fn::local_path("graph_explorer.db"); + ge::layout_store_open(legacy_db.c_str()); + g_layout_db_path = legacy_db; if (!g_input_path.empty()) { load_input(); } @@ -1969,8 +1971,10 @@ int main(int argc, char** argv) { std::string enrichers_dir = app_dir + "/enrichers"; // graph_explorer.db es el mismo SQLite usado por layout_store. + // Default a /graph_explorer.db si no hay proyecto. + std::string fallback_db = fn::local_path("graph_explorer.db"); const char* app_db = g_layout_db_path.empty() - ? "graph_explorer.db" : g_layout_db_path.c_str(); + ? fallback_db.c_str() : g_layout_db_path.c_str(); // Layout storage — guardado/cargado de layouts ImGui en // graph_explorer.db. El menu Layouts del menubar consume estos cb. diff --git a/project_manager.cpp b/project_manager.cpp index 51d4024..f7322e5 100644 --- a/project_manager.cpp +++ b/project_manager.cpp @@ -1,5 +1,7 @@ #include "project_manager.h" +#include "../../../../cpp/framework/app_base.h" + #include #include @@ -20,6 +22,14 @@ namespace fs = std::filesystem; namespace ge { +// Helpers de paths — resuelven contra /local_files/. +const char* projects_root() { + return fn::local_path(k_projects_subdir); +} +const char* settings_path() { + return fn::local_path(k_settings_basename); +} + // ---------------------------------------------------------------------------- // DDL embebido (operations.db schema) // ---------------------------------------------------------------------------- @@ -217,7 +227,7 @@ bool project_validate_slug(const char* name, std::string* error_msg) { ProjectPaths project_paths(const char* slug) { ProjectPaths p; if (!slug || !*slug) return p; - fs::path root = fs::path(k_projects_dir) / slug; + fs::path root = fs::path(projects_root()) / slug; p.root_dir = root.string(); p.operations_db = (root / "operations.db").string(); p.types_yaml = (root / "types.yaml").string(); @@ -231,7 +241,7 @@ ProjectPaths project_paths(const char* slug) { bool projects_root_ensure() { std::error_code ec; - fs::create_directories(k_projects_dir, ec); + fs::create_directories(projects_root(), ec); return !ec; } @@ -239,8 +249,8 @@ bool project_list(std::vector* out) { if (!out) return false; out->clear(); std::error_code ec; - if (!fs::exists(k_projects_dir, ec)) return true; - for (auto& e : fs::directory_iterator(k_projects_dir, ec)) { + if (!fs::exists(projects_root(), ec)) return true; + for (auto& e : fs::directory_iterator(projects_root(), ec)) { if (ec) break; if (!e.is_directory()) continue; std::string slug = e.path().filename().string(); @@ -346,7 +356,7 @@ bool project_create(const char* slug, std::string* error_msg) { bool projects_migrate_legacy_layout() { std::error_code ec; - if (fs::exists(k_projects_dir, ec)) return true; // ya migrado o creado + if (fs::exists(projects_root(), ec)) return true; // ya migrado o creado bool has_operations = fs::exists("operations.db", ec); bool has_layout = fs::exists("graph_explorer.db", ec); @@ -423,7 +433,7 @@ static std::vector split_csv(const std::string& s) { bool project_settings_load(ProjectSettings* out) { if (!out) return false; *out = {}; - std::ifstream in(k_settings_file); + std::ifstream in(settings_path()); if (!in) return true; // no es error: archivo aun no existe std::string line; while (std::getline(in, line)) { @@ -440,7 +450,7 @@ bool project_settings_load(ProjectSettings* out) { } bool project_settings_save(const ProjectSettings& s) { - std::ofstream out(k_settings_file); + std::ofstream out(settings_path()); if (!out) return false; out << "# graph_explorer.ini — autogenerado, editable\n"; out << "last_active = " << s.last_active << "\n"; diff --git a/project_manager.h b/project_manager.h index 4e1330a..738d9b7 100644 --- a/project_manager.h +++ b/project_manager.h @@ -7,23 +7,34 @@ // contiene sus propios `operations.db`, `types.yaml` y `graph_explorer.db` // (layouts). El usuario crea proyectos, los nombra y conmuta entre ellos. // -// Layout en disco: +// Layout en disco (issue: convencion local_files): // // / -// graph_explorer.ini # last_active + recent (gestionado aqui) -// projects/ -// default/ -// operations.db # bootstrap con DDL completo -// types.yaml # copia editable; semilla = ./examples/types.yaml o embed -// graph_explorer.db # layouts del proyecto -// caso_X/ -// ... +// graph_explorer.exe +// enrichers/, runtime/, *.ttf, ... (read-only, distribuibles) +// local_files/ (escribibles, per-PC) +// imgui.ini, app_settings.ini (gestionados por fn_framework) +// graph_explorer.ini # last_active + recent +// projects/ +// default/ +// operations.db +// types.yaml +// graph_explorer.db # layouts del proyecto +// caso_X/ +// ... namespace ge { -constexpr const char* k_projects_dir = "projects"; +// Helpers que resuelven a /local_files/... via fn::local_path. +// Las constantes solo guardan el basename relativo a local_files/. +constexpr const char* k_projects_subdir = "projects"; constexpr const char* k_default_project = "default"; -constexpr const char* k_settings_file = "graph_explorer.ini"; +constexpr const char* k_settings_basename = "graph_explorer.ini"; + +// Devuelven paths absolutos resueltos contra local_files/ (creando la +// carpeta si no existe). Sustituyen el uso directo de los constexpr. +const char* projects_root(); // /local_files/projects +const char* settings_path(); // /local_files/graph_explorer.ini struct ProjectPaths { std::string root_dir; // /projects//