Files
fn_registry/bash/functions/pipelines/init_cpp_app.sh
T
egutierrez a03675113a chore: auto-commit (286 archivos)
- .claude/agents/fn-orquestador/SKILL.md
- .claude/commands/fn_claude.md
- .claude/rules/INDEX.md
- .claude/rules/cpp_apps.md
- .claude/rules/ids_naming.md
- CHANGELOG.md
- apps/dag_engine/README.md
- apps/dag_engine/api.go
- apps/dag_engine/dags_migrated/example.yaml
- apps/dag_engine/dags_migrated/example_lineage_tracking.yaml
- ...

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 16:33:22 +02:00

241 lines
7.1 KiB
Bash
Executable File

#!/usr/bin/env bash
# init_cpp_app — Scaffolder estandar de apps C++ del registry.
#
# Genera la estructura canonica (main.cpp, CMakeLists.txt, app.md), registra
# la app en cpp/CMakeLists.txt, inicializa git + repo Gitea dataforge/<name>,
# y ejecuta fn index. La plantilla cumple cpp/PATTERNS.md y .claude/rules/cpp_apps.md.
#
# Uso:
# init_cpp_app <name> [--project <p>] [--domain <d>] [--desc "..."] [--tags "a,b"]
#
# Por defecto domain=tools, sin proyecto (apps/<name>/, issue 0096).
set -euo pipefail
# Carga helpers del registry
FN_ROOT="${FN_REGISTRY_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"
# shellcheck source=/dev/null
source "$FN_ROOT/bash/functions/infra/ensure_repo_synced.sh"
init_cpp_app() {
local name=""
local project=""
local domain="tools"
local desc=""
local tags=""
while [[ $# -gt 0 ]]; do
case "$1" in
--project) project="$2"; shift 2 ;;
--domain) domain="$2"; shift 2 ;;
--desc) desc="$2"; shift 2 ;;
--tags) tags="$2"; shift 2 ;;
-*) echo "init_cpp_app: flag desconocido: $1" >&2; return 2 ;;
*) if [[ -z "$name" ]]; then name="$1"; else
echo "init_cpp_app: argumento extra: $1" >&2; return 2
fi
shift ;;
esac
done
if [[ -z "$name" ]]; then
echo "init_cpp_app: se requiere <name>" >&2
echo "Uso: init_cpp_app <name> [--project <p>] [--domain <d>] [--desc \"...\"] [--tags \"a,b\"]" >&2
return 2
fi
[[ -z "$desc" ]] && desc="App C++ del registry"
# Resolver dir destino
local rel_dir abs_dir
if [[ -n "$project" ]]; then
if [[ ! -f "$FN_ROOT/projects/$project/project.md" ]]; then
echo "init_cpp_app: proyecto '$project' no existe (falta projects/$project/project.md)" >&2
return 1
fi
rel_dir="projects/$project/apps/$name"
else
rel_dir="apps/$name"
fi
abs_dir="$FN_ROOT/$rel_dir"
if [[ -e "$abs_dir" ]]; then
echo "init_cpp_app: $rel_dir ya existe" >&2
return 1
fi
mkdir -p "$abs_dir"
# ---------- main.cpp ----------
cat > "$abs_dir/main.cpp" <<EOF
#include <imgui.h>
#include "app_base.h"
#include "core/panel_menu.h"
#include "core/icons_tabler.h"
#include "core/logger.h"
// #include "viz/data_table.h" // uncomment to enable data_table::render() panel
// Toggles de paneles (visibles desde el menu View del menubar canonico)
static bool g_show_main = true;
static void draw_main() {
if (!ImGui::Begin(TI_HOME " Main", &g_show_main)) {
ImGui::End();
return;
}
ImGui::TextUnformatted("Hello from $name");
ImGui::End();
}
static void render() {
// El framework dibuja menubar (View/Layouts/Settings/About) y un
// DockSpaceOverViewport central (auto_dockspace=true por defecto).
// Aqui solo se dibujan los paneles propios de la app.
if (g_show_main) draw_main();
// === Data panel (uncomment to enable) ===
// static data_table::State data_state;
// static std::vector<data_table::TableInput> data_tables; // populate from your source
// data_table::render("main_data", data_tables, data_state);
}
int main(int /*argc*/, char** /*argv*/) {
static fn_ui::PanelToggle panels[] = {
{ "Main", nullptr, &g_show_main },
};
fn::AppConfig cfg;
cfg.title = "$name — $desc";
cfg.about = { "$name", "0.1.0", "$desc" };
cfg.log = { "$name.log", 1 };
cfg.panels = panels;
cfg.panel_count = sizeof(panels) / sizeof(panels[0]);
return fn::run_app(cfg, render);
}
EOF
# ---------- CMakeLists.txt ----------
cat > "$abs_dir/CMakeLists.txt" <<EOF
add_imgui_app($name
main.cpp
)
target_include_directories($name PRIVATE \${CMAKE_CURRENT_SOURCE_DIR})
# fn_table_viz: provides data_table::render(), viz_render, TQL engine, Lua, LLM.
# Guard keeps the app compilable in builds where vendor/lua is absent.
if(TARGET fn_table_viz)
target_link_libraries($name PRIVATE fn_table_viz)
endif()
if(WIN32)
set_target_properties($name PROPERTIES WIN32_EXECUTABLE TRUE)
endif()
EOF
# ---------- app.md ----------
local repo_url="https://gitea.organic-machine.com/dataforge/$name"
local tags_yaml="[imgui]"
if [[ -n "$tags" ]]; then
# Convierte "a,b,c" -> "[a, b, c]"
tags_yaml="[$(echo "$tags" | sed 's/,/, /g'), imgui]"
fi
cat > "$abs_dir/app.md" <<EOF
---
name: $name
lang: cpp
domain: $domain
description: "$desc"
tags: $tags_yaml
uses_functions:
# Uncomment when using data_table::render() — provided via fn_table_viz:
# - data_table_cpp_viz
# - viz_render_cpp_viz
# - compute_stage_cpp_core
# - compute_pipeline_cpp_core
# - compute_column_stats_cpp_core
# - auto_detect_type_cpp_core
# - tql_emit_cpp_core
# - tql_apply_cpp_core
# - lua_engine_cpp_core
# - join_tables_cpp_core
# - tql_to_sql_cpp_core
# - llm_anthropic_cpp_core
uses_types: []
framework: "imgui"
entry_point: "main.cpp"
dir_path: "$rel_dir"
repo_url: "$repo_url"
---
# $name
$desc
## Build
\`\`\`bash
cd cpp && cmake --build build --target $name -j
\`\`\`
## Run
\`\`\`bash
./cpp/build/$name
\`\`\`
EOF
# ---------- Registrar en cpp/CMakeLists.txt ----------
local cpp_cmake="$FN_ROOT/cpp/CMakeLists.txt"
if ! grep -q "# --- $name ---" "$cpp_cmake"; then
if [[ -n "$project" ]]; then
local upper
upper="$(echo "$name" | tr '[:lower:]' '[:upper:]')"
cat >> "$cpp_cmake" <<EOF
# --- $name (lives in projects/$project/apps/) ---
set(_${upper}_DIR \${CMAKE_SOURCE_DIR}/../projects/$project/apps/$name)
if(EXISTS \${_${upper}_DIR}/CMakeLists.txt)
add_subdirectory(\${_${upper}_DIR} \${CMAKE_BINARY_DIR}/apps/$name)
endif()
EOF
else
local upper
upper="$(echo "$name" | tr '[:lower:]' '[:upper:]')"
cat >> "$cpp_cmake" <<EOF
# --- $name (lives in apps/, issue 0096) ---
set(_${upper}_DIR \${CMAKE_SOURCE_DIR}/../apps/$name)
if(EXISTS \${_${upper}_DIR}/CMakeLists.txt)
add_subdirectory(\${_${upper}_DIR} \${CMAKE_BINARY_DIR}/apps/$name)
endif()
EOF
fi
fi
# ---------- Git + Gitea ----------
if [[ -n "${GITEA_URL:-}" && -n "${GITEA_TOKEN:-}" ]]; then
ensure_repo_synced "$abs_dir" "dataforge" "$name" "master" "feat: scaffold $name via init_cpp_app" || \
echo "init_cpp_app: warning — ensure_repo_synced fallo, repo no creado" >&2
else
echo "init_cpp_app: GITEA_URL/GITEA_TOKEN no seteados, omitiendo creacion de repo Gitea" >&2
(cd "$abs_dir" && git init -b master >/dev/null 2>&1 || git init >/dev/null 2>&1)
fi
# ---------- fn index ----------
if [[ -x "$FN_ROOT/fn" ]]; then
(cd "$FN_ROOT" && ./fn index >/dev/null 2>&1) || \
echo "init_cpp_app: warning — fn index fallo" >&2
fi
echo "init_cpp_app: $rel_dir creada"
echo " - Build: cd $FN_ROOT/cpp && cmake --build build --target $name -j"
echo " - app.md: $rel_dir/app.md (rellena uses_functions cuando uses funciones del registry)"
}
# Permitir invocacion directa via 'fn run init_cpp_app ...'
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
init_cpp_app "$@"
fi