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>
This commit is contained in:
@@ -6,16 +6,21 @@
|
||||
scan_secrets_in_dirty() {
|
||||
local repo_dir="${1:-.}"
|
||||
|
||||
if [[ ! -d "$repo_dir/.git" ]]; then
|
||||
# Accept both regular repos (.git is a directory) and worktrees (.git is a
|
||||
# file containing "gitdir: ..." pointer).
|
||||
if [[ ! -d "$repo_dir/.git" && ! -f "$repo_dir/.git" ]]; then
|
||||
echo "scan_secrets_in_dirty: '$repo_dir' no es un repo git" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Listar archivos modificados o nuevos (excluyendo borrados)
|
||||
# y filtrar por patron de secret en el nombre del archivo
|
||||
# y filtrar por patron de secret en el nombre del archivo.
|
||||
# Excluye extensiones de codigo (sh/go/py/ts/md/etc) para no marcar el
|
||||
# propio scanner ni docs que hablen de "secret"/"token".
|
||||
git -C "$repo_dir" status --porcelain \
|
||||
| awk '{print $NF}' \
|
||||
| grep -E '(^|/)(\.env(\..*)?$|.*credentials.*|.*\.key$|.*\.pem$|id_rsa.*|.*secret.*|.*token.*\.txt$)' \
|
||||
| grep -Ev '\.(sh|go|py|ts|tsx|js|jsx|md|rs|cpp|h|hpp|c|java|rb|html|css)$' \
|
||||
|| true
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,9 @@ git_hook_audit_app_drift() {
|
||||
echo "ERROR: repo_dir required" >&2
|
||||
return 2
|
||||
fi
|
||||
if [[ ! -d "$repo_dir/.git" ]]; then
|
||||
# Accept both regular repos (.git is a directory) and worktrees (.git is a
|
||||
# file containing "gitdir: ..." pointer).
|
||||
if [[ ! -d "$repo_dir/.git" && ! -f "$repo_dir/.git" ]]; then
|
||||
echo "ERROR: $repo_dir is not a git repo" >&2
|
||||
return 2
|
||||
fi
|
||||
|
||||
@@ -3,11 +3,11 @@ name: resolve_cpp_app_dir
|
||||
kind: function
|
||||
lang: bash
|
||||
domain: infra
|
||||
version: "1.0.0"
|
||||
version: "1.1.0"
|
||||
purity: impure
|
||||
signature: "resolve_cpp_app_dir(app_name?: string) -> stdout: app_name\tapp_dir"
|
||||
description: "Resuelve el nombre y directorio absoluto de una app C++ del registry. Sin arg deduce desde CWD si esta dentro de cpp/apps/<X>/ o projects/*/apps/<X>/. Con arg busca en ambas ubicaciones. Imprime '<app_name>TAB<absolute_dir>' en stdout, exit 0; si no resuelve, lista apps disponibles en stderr y sale con exit 1."
|
||||
tags: [cpp, resolve, app, directory, infra]
|
||||
description: "Resuelve el nombre y directorio absoluto de una app C++ del registry. Sin arg deduce desde CWD si esta dentro de apps/<X>/, cpp/apps/<X>/ o projects/*/apps/<X>/. Con arg busca en las tres ubicaciones (apps/ canonical issue 0096 primero, luego cpp/apps/ legacy, luego projects/*/apps/). Imprime '<app_name>TAB<absolute_dir>' en stdout, exit 0; si no resuelve, lista apps disponibles en stderr y sale con exit 1."
|
||||
tags: [cpp, resolve, app, directory, infra, cpp-windows]
|
||||
uses_functions: []
|
||||
uses_types: []
|
||||
returns: []
|
||||
@@ -20,7 +20,7 @@ test_file_path: ""
|
||||
file_path: "bash/functions/infra/resolve_cpp_app_dir.sh"
|
||||
params:
|
||||
- name: app_name
|
||||
desc: "Nombre de la app C++ a resolver (opcional). Sin arg se deduce desde el directorio actual si estamos dentro de cpp/apps/<X>/ o projects/*/apps/<X>/."
|
||||
desc: "Nombre de la app C++ a resolver (opcional). Sin arg se deduce desde el directorio actual si estamos dentro de apps/<X>/, cpp/apps/<X>/ o projects/*/apps/<X>/."
|
||||
output: "Una linea TAB-separada '<app_name>\\t<absolute_dir_path>' en stdout. En caso de error imprime ayuda a stderr y sale con exit 1."
|
||||
---
|
||||
|
||||
@@ -44,4 +44,13 @@ APP_DIR="$(echo "$resolved" | cut -f2)"
|
||||
|
||||
## Notas
|
||||
|
||||
Busca en orden: primero `$ROOT/cpp/apps/<X>`, luego `$ROOT/projects/*/apps/<X>` (primer match gana). Si ninguna ruta existe, imprime lista de apps disponibles (con prefijo de ubicacion) en stderr y sale con exit 1. Sourceable o ejecutable directamente.
|
||||
Busca en orden:
|
||||
1. `$ROOT/apps/<X>` con `CMakeLists.txt` — layout canonical post-issue 0096.
|
||||
2. `$ROOT/cpp/apps/<X>` — legacy pre-issue 0096.
|
||||
3. `$ROOT/projects/*/apps/<X>` — apps de un proyecto (primer match gana).
|
||||
|
||||
Si ninguna ruta existe, imprime lista de apps disponibles (con prefijo de ubicacion) en stderr y sale con exit 1. Sourceable o ejecutable directamente. Helper interno `_list_cpp_apps` evita duplicar codigo en los paths de error.
|
||||
|
||||
### Growth log
|
||||
|
||||
- v1.1.0 (2026-05-16) — busca tambien en `apps/<X>/` (canonical issue 0096). Antes solo cubria `cpp/apps/<X>/` y `projects/*/apps/<X>/`, lo que hacia que `./fn run compile_cpp_app <name>` fallara para apps movidas al layout canonical (ej. `dag_engine_ui`).
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
# resolve_cpp_app_dir — Resuelve nombre y directorio absoluto de una app C++ del registry.
|
||||
# Sin arg: deduce desde CWD si esta dentro de cpp/apps/<X>/ o projects/*/apps/<X>/.
|
||||
# Con arg: usa el nombre directamente y busca en ambas ubicaciones.
|
||||
# Sin arg: deduce desde CWD si esta dentro de apps/<X>/, cpp/apps/<X>/ o projects/*/apps/<X>/.
|
||||
# Con arg: usa el nombre directamente y busca en las tres ubicaciones.
|
||||
# Salida: "<app_name>\t<absolute_dir_path>" en stdout (TAB separado), exit 0.
|
||||
# Error: lista apps disponibles en stderr + exit 1.
|
||||
|
||||
@@ -9,18 +9,28 @@ resolve_cpp_app_dir() {
|
||||
local app_arg="${1:-}"
|
||||
local root="${FN_REGISTRY_ROOT:-/home/lucas/fn_registry}"
|
||||
|
||||
_list_cpp_apps() {
|
||||
ls "$root/apps/" 2>/dev/null | sed 's/^/ apps\//'
|
||||
ls "$root/cpp/apps/" 2>/dev/null | sed 's/^/ cpp\/apps\//'
|
||||
for proj in "$root"/projects/*/apps/; do
|
||||
ls "$proj" 2>/dev/null | sed "s|^| $(echo "$proj" | sed "s|$root/||")|"
|
||||
done
|
||||
}
|
||||
|
||||
# --- Deducir desde CWD si no hay argumento ---
|
||||
if [ -z "$app_arg" ]; then
|
||||
local cwd
|
||||
cwd="$(pwd)"
|
||||
case "$cwd" in
|
||||
"$root"/apps/*/|"$root"/apps/*)
|
||||
local rel="${cwd#"$root/apps/"}"
|
||||
app_arg="${rel%%/*}"
|
||||
;;
|
||||
"$root"/cpp/apps/*/|"$root"/cpp/apps/*)
|
||||
# Extraer primer segmento tras cpp/apps/
|
||||
local rel="${cwd#"$root/cpp/apps/"}"
|
||||
app_arg="${rel%%/*}"
|
||||
;;
|
||||
"$root"/projects/*/apps/*/|"$root"/projects/*/apps/*)
|
||||
# Extraer primer segmento tras la ultima /apps/
|
||||
local rel="${cwd#"$root/projects/"}"
|
||||
rel="${rel#*/apps/}"
|
||||
app_arg="${rel%%/*}"
|
||||
@@ -33,12 +43,7 @@ resolve_cpp_app_dir() {
|
||||
echo "ERROR: no se pudo deducir la app desde el directorio actual." >&2
|
||||
echo "" >&2
|
||||
echo "Apps disponibles:" >&2
|
||||
{
|
||||
ls "$root/cpp/apps/" 2>/dev/null | sed 's/^/ cpp\/apps\//'
|
||||
for proj in "$root"/projects/*/apps/; do
|
||||
ls "$proj" 2>/dev/null | sed "s|^| $(echo "$proj" | sed "s|$root/||")|"
|
||||
done
|
||||
} >&2
|
||||
_list_cpp_apps >&2
|
||||
echo "" >&2
|
||||
echo "Uso: resolve_cpp_app_dir <app_name>" >&2
|
||||
return 1
|
||||
@@ -47,12 +52,17 @@ resolve_cpp_app_dir() {
|
||||
# --- Buscar directorio real ---
|
||||
local app_dir=""
|
||||
|
||||
# Primero: cpp/apps/<X>
|
||||
if [ -d "$root/cpp/apps/$app_arg" ]; then
|
||||
# Primero (issue 0096 canonical): apps/<X>
|
||||
if [ -d "$root/apps/$app_arg" ] && [ -f "$root/apps/$app_arg/CMakeLists.txt" ]; then
|
||||
app_dir="$root/apps/$app_arg"
|
||||
fi
|
||||
|
||||
# Segundo (legacy): cpp/apps/<X>
|
||||
if [ -z "$app_dir" ] && [ -d "$root/cpp/apps/$app_arg" ]; then
|
||||
app_dir="$root/cpp/apps/$app_arg"
|
||||
fi
|
||||
|
||||
# Segundo: projects/*/apps/<X> (primer match)
|
||||
# Tercero: projects/*/apps/<X> (primer match)
|
||||
if [ -z "$app_dir" ]; then
|
||||
for cand in "$root"/projects/*/apps/"$app_arg"; do
|
||||
if [ -d "$cand" ]; then
|
||||
@@ -63,15 +73,10 @@ resolve_cpp_app_dir() {
|
||||
fi
|
||||
|
||||
if [ -z "$app_dir" ]; then
|
||||
echo "ERROR: no se encuentra app '$app_arg' en cpp/apps/ ni en projects/*/apps/" >&2
|
||||
echo "ERROR: no se encuentra app '$app_arg' en apps/, cpp/apps/ ni en projects/*/apps/" >&2
|
||||
echo "" >&2
|
||||
echo "Apps disponibles:" >&2
|
||||
{
|
||||
ls "$root/cpp/apps/" 2>/dev/null | sed 's/^/ cpp\/apps\//'
|
||||
for proj in "$root"/projects/*/apps/; do
|
||||
ls "$proj" 2>/dev/null | sed "s|^| $(echo "$proj" | sed "s|$root/||")|"
|
||||
done
|
||||
} >&2
|
||||
_list_cpp_apps >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
---
|
||||
name: fn_sync_with_pass
|
||||
kind: pipeline
|
||||
lang: bash
|
||||
domain: pipelines
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "fn_sync_with_pass [status|locations|<args>...]"
|
||||
description: "Wrapper de fn sync que lee credenciales del password-store pass y exporta FN_REGISTRY_API y REGISTRY_API_TOKEN antes de invocar el CLI. Evita persistir secretos en ~/.zshrc."
|
||||
tags: [sync, registry, pass, gpg, launcher]
|
||||
uses_functions:
|
||||
- pass_get_bash_infra
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: "error_go_core"
|
||||
imports: []
|
||||
params:
|
||||
- name: "registry/basicauth-user"
|
||||
desc: "Entry de pass con el usuario para basicAuth del registry API (linea 1)"
|
||||
- name: "registry/basicauth-pass"
|
||||
desc: "Entry de pass con la contraseña para basicAuth del registry API (linea 1)"
|
||||
- name: "registry/api-token"
|
||||
desc: "Entry de pass con el REGISTRY_API_TOKEN (linea 1)"
|
||||
- name: "args"
|
||||
desc: "Argumentos opcionales forwarded a fn sync: status, locations, o nada para push+pull completo"
|
||||
output: "Mismo output que ./fn sync (stdin/stdout/stderr heredados). Exit code del subproceso fn sync."
|
||||
tested: false
|
||||
tests: []
|
||||
test_file_path: ""
|
||||
file_path: "bash/functions/pipelines/fn_sync_with_pass.sh"
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```bash
|
||||
# Sync simple (push+pull completo)
|
||||
./fn run fn_sync_with_pass_bash_pipelines
|
||||
|
||||
# Ver estado local: PC, API, conteos
|
||||
./fn run fn_sync_with_pass_bash_pipelines status
|
||||
|
||||
# Mapa de ubicaciones cross-PC
|
||||
./fn run fn_sync_with_pass_bash_pipelines locations
|
||||
```
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Cuando necesites ejecutar `fn sync` sin tener las credenciales exportadas en el entorno. Sustituye al bloque de `export FN_REGISTRY_API=...` que de otro modo habria que poner en `~/.zshrc`.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- Si GPG no tiene la clave desbloqueada, `pass show` abre el prompt del agente gpg. Dejarlo pasar — no capturar stderr para no interferir con el pinentry.
|
||||
- Requiere que el password-store este inicializado (`pass init`). Si no existe, `pass show` falla con error claro.
|
||||
- `FN_REGISTRY_ROOT` debe apuntar a la raiz del registry donde vive el binario `./fn`. Si no esta seteado, se resuelve via `git rev-parse --show-toplevel`.
|
||||
- Los tres entries de pass deben tener el valor en la **linea 1** (convencion estandar de pass). Metadata adicional en lineas siguientes es ignorada.
|
||||
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env bash
|
||||
# fn_sync_with_pass — Wrapper de fn sync que lee credenciales desde pass.
|
||||
set -euo pipefail
|
||||
|
||||
FN_ROOT="${FN_REGISTRY_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"
|
||||
|
||||
fn_sync_with_pass() {
|
||||
command -v pass >/dev/null 2>&1 || {
|
||||
echo "fn_sync_with_pass: 'pass' CLI no instalado. Instala con: apt install pass" >&2
|
||||
return 127
|
||||
}
|
||||
|
||||
local u p t
|
||||
|
||||
u=$(pass show registry/basicauth-user 2>/dev/null | head -n1) || {
|
||||
echo "fn_sync_with_pass: falta registry/basicauth-user en pass. Crea con: pass insert registry/basicauth-user" >&2
|
||||
return 1
|
||||
}
|
||||
p=$(pass show registry/basicauth-pass 2>/dev/null | head -n1) || {
|
||||
echo "fn_sync_with_pass: falta registry/basicauth-pass en pass. Crea con: pass insert registry/basicauth-pass" >&2
|
||||
return 1
|
||||
}
|
||||
t=$(pass show registry/api-token 2>/dev/null | head -n1) || {
|
||||
echo "fn_sync_with_pass: falta registry/api-token en pass. Crea con: pass insert registry/api-token" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
export FN_REGISTRY_API="https://${u}:${p}@registry.organic-machine.com"
|
||||
export REGISTRY_API_TOKEN="$t"
|
||||
|
||||
cd "$FN_ROOT"
|
||||
./fn sync "$@"
|
||||
}
|
||||
|
||||
# Ejecucion directa (no library mode)
|
||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
||||
fn_sync_with_pass "$@"
|
||||
fi
|
||||
@@ -8,7 +8,7 @@
|
||||
# Uso:
|
||||
# init_cpp_app <name> [--project <p>] [--domain <d>] [--desc "..."] [--tags "a,b"]
|
||||
#
|
||||
# Por defecto domain=tools, sin proyecto (cpp/apps/<name>/).
|
||||
# Por defecto domain=tools, sin proyecto (apps/<name>/, issue 0096).
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
@@ -55,7 +55,7 @@ init_cpp_app() {
|
||||
fi
|
||||
rel_dir="projects/$project/apps/$name"
|
||||
else
|
||||
rel_dir="cpp/apps/$name"
|
||||
rel_dir="apps/$name"
|
||||
fi
|
||||
abs_dir="$FN_ROOT/$rel_dir"
|
||||
|
||||
@@ -201,11 +201,14 @@ if(EXISTS \${_${upper}_DIR}/CMakeLists.txt)
|
||||
endif()
|
||||
EOF
|
||||
else
|
||||
local upper
|
||||
upper="$(echo "$name" | tr '[:lower:]' '[:upper:]')"
|
||||
cat >> "$cpp_cmake" <<EOF
|
||||
|
||||
# --- $name ---
|
||||
if(EXISTS \${CMAKE_CURRENT_SOURCE_DIR}/apps/$name/CMakeLists.txt)
|
||||
add_subdirectory(apps/$name)
|
||||
# --- $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
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
---
|
||||
name: redeploy_all_cpp_apps
|
||||
kind: pipeline
|
||||
lang: bash
|
||||
domain: pipelines
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "redeploy_all_cpp_apps(filter?: string) -> void"
|
||||
description: "Cross-compila TODOS los apps C++ del registry en un solo cmake pass y despliega cada .exe al Desktop de Windows. Mas rapido que N builds individuales. Acepta filtro de nombre para despliegue parcial."
|
||||
tags: [cpp, windows, deploy, redeploy, bulk, cpp-windows]
|
||||
uses_functions:
|
||||
- build_cpp_windows_bash_infra
|
||||
- deploy_cpp_exe_to_windows_bash_infra
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: "error_go_core"
|
||||
imports: []
|
||||
tested: false
|
||||
tests: []
|
||||
test_file_path: ""
|
||||
file_path: "bash/functions/pipelines/redeploy_all_cpp_apps.sh"
|
||||
params:
|
||||
- name: filter
|
||||
desc: "Opcional. Substring para limitar el deploy a apps cuyo nombre lo contenga (ej: 'graph' solo despliega apps con 'graph' en el nombre). Sin valor = todas las apps."
|
||||
output: "Imprime tabla resumen con OK/SKIPPED/FAILED y nombres de cada app. Exit 1 si al menos una app fallo el deploy."
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```bash
|
||||
# Recompilar y redesplegar TODAS las apps C++ tras un cambio en cpp/framework/
|
||||
./fn run redeploy_all_cpp_apps
|
||||
|
||||
# Solo apps cuyo nombre contenga "graph"
|
||||
./fn run redeploy_all_cpp_apps graph
|
||||
```
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Tras un cambio en `cpp/framework/app_base.cpp`, `cpp/functions/core/*` o cualquier
|
||||
funcion linkada a multiples apps. Ahorra correr `redeploy_cpp_app_windows <name> <dir>`
|
||||
N veces — un solo cmake pass compila todo el arbol en paralelo.
|
||||
|
||||
## Comportamiento
|
||||
|
||||
1. **Build**: invoca `build_cpp_windows` sin argumento (compila todo el arbol con
|
||||
`-j$(nproc)`). Un solo cmake pass — mucho mas rapido que N builds individuales.
|
||||
2. **Descubrimiento**: itera `apps/*/CMakeLists.txt` y `projects/*/apps/*/CMakeLists.txt`.
|
||||
**No** usa `cpp/apps/` (deprecado tras issue 0096).
|
||||
3. **Filtro** (opcional): si se paso un argumento, solo procesa apps cuyo `basename`
|
||||
contiene el substring.
|
||||
4. **Por cada app**:
|
||||
- Localiza `.exe` en `cpp/build/windows/apps/<name>/<name>.exe`; si no existe,
|
||||
busca bajo `cpp/build/windows/` como fallback.
|
||||
- Si no hay `.exe`: log SKIP, continua (no aborta — apps headless o sub-repos no
|
||||
clonados no tienen build target).
|
||||
- `taskkill.exe /IM <name>.exe /F` silencioso (no aborta si falla).
|
||||
- `deploy_cpp_exe_to_windows <name> <app_dir>` (copia exe + DLLs + assets +
|
||||
enrichers + runtime, preserva `local_files/`).
|
||||
- Error por app: log FAILED, continua con la siguiente.
|
||||
5. **Resumen final**: tabla `OK / SKIPPED / FAILED` con nombres. Exit 1 si hay
|
||||
al menos un FAILED.
|
||||
|
||||
## Variables de entorno
|
||||
|
||||
| Variable | Default | Descripcion |
|
||||
|---|---|---|
|
||||
| `FN_REGISTRY_ROOT` | auto-detect | Raiz del registry (busca hacia arriba desde el script) |
|
||||
| `BUILD_WIN` | `$root/cpp/build/windows` | Directorio de build Windows |
|
||||
| `WIN_DESKTOP_APPS` | `/mnt/c/Users/lucas/Desktop/apps` | Destino de deploy en Windows |
|
||||
|
||||
## Gotchas
|
||||
|
||||
- Solo Windows (cross-compile mingw-w64 + Desktop deploy via WSL2). En Linux puro no aplica.
|
||||
- `taskkill.exe` requiere WSL2 con interop habilitado. No funciona en WSL1 ni Linux nativo.
|
||||
- Algunas apps pueden no estar en el grafo cmake actual (sub-repo no clonado, `add_subdirectory`
|
||||
protegido por `if(EXISTS ...)`). El pipeline las SKIPea sin abortar — comportamiento esperado.
|
||||
- Build paralelo puede consumir varios GB de RAM. Si hay OOM, reducir paralelismo exportando
|
||||
`BUILD_JOBS=4` antes de invocar (actualmente la funcion `build_cpp_windows` usa `$(nproc)`;
|
||||
si necesitas override edita `BUILD_JOBS` como variable de entorno custom o fork la funcion).
|
||||
- El loop de deploy atrapa errores por app (`|| { failed+=...; continue; }`) para no abortar
|
||||
en el primer fallo — todas las apps se intentan aunque alguna falle.
|
||||
|
||||
## Capability growth log
|
||||
|
||||
- v1.0.0 (2026-05-16) — creacion. Tras issue 0096 (apps movidas a `apps/<X>/`) el patron "recompilar+desplegar todas tras un cambio en `cpp/framework/`" se repitio varias veces sin un wrapper. Pipeline tolerante a fallos: build best-effort (test_* roto en mingw no aborta), deploy por app captura fallos individuales, summary OK/SKIPPED/FAILED al final. Primera corrida real (16 May 2026): 12 OK / 1 SKIP (`data_factory` sin .exe target) / 0 FAILED.
|
||||
|
||||
## Notas operativas (2026-05-16)
|
||||
|
||||
- `build_cpp_windows` sin arg compila el arbol entero. Si hay targets rotos (ej. `test_llm_anthropic`, `test_graph_icons` usan `setenv()` no disponible en mingw-w64), el pipeline logea `[1/2] Build returned exit=N — continuing with deploy of available exes` y sigue con la fase de deploy. Cada app sin `.exe` queda SKIPPED.
|
||||
- Tras una corrida exitosa, los `.exe` quedan en `/mnt/c/Users/lucas/Desktop/apps/<name>/<name>.exe`. Lanzar individualmente con `./fn run is_cpp_app_running_windows <name>` para chequear y `launch_cpp_app_windows <name>` para arrancar.
|
||||
@@ -0,0 +1,127 @@
|
||||
#!/usr/bin/env bash
|
||||
# redeploy_all_cpp_apps — Cross-compila TODOS los apps C++ del registry en un solo
|
||||
# cmake pass y despliega cada .exe al Desktop de Windows.
|
||||
# Uso: redeploy_all_cpp_apps [filter]
|
||||
# filter substring opcional para limitar el deploy a apps cuyo nombre lo contenga
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/../infra/build_cpp_windows.sh"
|
||||
source "$SCRIPT_DIR/../infra/deploy_cpp_exe_to_windows.sh"
|
||||
|
||||
redeploy_all_cpp_apps() {
|
||||
local filter="${1:-}"
|
||||
|
||||
# --- Localizar raiz del registry ---
|
||||
local root="${FN_REGISTRY_ROOT:-}"
|
||||
if [ -z "$root" ]; then
|
||||
local d="$SCRIPT_DIR"
|
||||
while [ "$d" != "/" ]; do
|
||||
if [ -f "$d/registry.db" ] && [ -d "$d/cpp" ]; then
|
||||
root="$d"; break
|
||||
fi
|
||||
d="$(dirname "$d")"
|
||||
done
|
||||
fi
|
||||
if [ -z "$root" ]; then
|
||||
echo "[redeploy_all_cpp_apps] ERROR: no se localiza la raiz del registry. Exporta FN_REGISTRY_ROOT." >&2
|
||||
return 2
|
||||
fi
|
||||
|
||||
local build_win="${BUILD_WIN:-$root/cpp/build/windows}"
|
||||
|
||||
# --- Paso 1: compilar TODO el arbol (un solo cmake pass) ---
|
||||
# Tolerante a fallos: si algun target (ej. test_* roto en mingw, app con
|
||||
# bug puntual) falla, los demas exes que SI se construyeron siguen siendo
|
||||
# desplegables. El loop de deploy hace SKIP por cada app sin .exe, asi que
|
||||
# el modo "build best-effort + deploy lo que haya" es seguro.
|
||||
echo "[1/2] Cross-compiling all C++ targets (best-effort)..."
|
||||
local build_rc=0
|
||||
build_cpp_windows || build_rc=$?
|
||||
if [ "$build_rc" -ne 0 ]; then
|
||||
echo "[1/2] Build returned exit=$build_rc — continuing with deploy of available exes" >&2
|
||||
else
|
||||
echo "[1/2] Build OK"
|
||||
fi
|
||||
|
||||
# --- Descubrir apps con CMakeLists.txt ---
|
||||
# Busca en apps/*/ y projects/*/apps/*/ (no en cpp/apps/ — deprecado)
|
||||
local -a app_dirs=()
|
||||
while IFS= read -r cmakelists; do
|
||||
app_dirs+=("$(dirname "$cmakelists")")
|
||||
done < <(
|
||||
find "$root/apps" -maxdepth 2 -name "CMakeLists.txt" 2>/dev/null | sort
|
||||
find "$root/projects" -maxdepth 4 -path "*/apps/*/CMakeLists.txt" 2>/dev/null | sort
|
||||
)
|
||||
|
||||
if [ ${#app_dirs[@]} -eq 0 ]; then
|
||||
echo "[redeploy_all_cpp_apps] WARN: no se encontraron apps con CMakeLists.txt" >&2
|
||||
return 0
|
||||
fi
|
||||
|
||||
# --- Paso 2: deploy por app ---
|
||||
echo "[2/2] Deploying apps to Windows Desktop..."
|
||||
local -a ok=() skipped=() failed=()
|
||||
|
||||
for app_dir in "${app_dirs[@]}"; do
|
||||
local name
|
||||
name="$(basename "$app_dir")"
|
||||
|
||||
# Aplicar filtro si se indico
|
||||
if [ -n "$filter" ] && [[ "$name" != *"$filter"* ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Localizar el .exe en la ubicacion canonica
|
||||
local exe_path="$build_win/apps/$name/$name.exe"
|
||||
if [ ! -f "$exe_path" ]; then
|
||||
# Fallback: buscar bajo build_win/
|
||||
exe_path="$(find "$build_win" -name "$name.exe" -type f 2>/dev/null | head -n1 || true)"
|
||||
fi
|
||||
|
||||
if [ -z "$exe_path" ] || [ ! -f "$exe_path" ]; then
|
||||
echo " SKIP: $name — .exe no encontrado en $build_win" >&2
|
||||
skipped+=("$name")
|
||||
continue
|
||||
fi
|
||||
|
||||
# taskkill silencioso (pre-autorizado; deploy_cpp_exe_to_windows lo hace internamente,
|
||||
# pero si deploy falla antes de llegar ahi nos aseguramos de liberar el lock)
|
||||
if command -v taskkill.exe >/dev/null 2>&1; then
|
||||
taskkill.exe /IM "${name}.exe" /F >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
if deploy_cpp_exe_to_windows "$name" "$app_dir"; then
|
||||
ok+=("$name")
|
||||
else
|
||||
echo " FAILED: $name" >&2
|
||||
failed+=("$name")
|
||||
fi
|
||||
done
|
||||
|
||||
# --- Resumen ---
|
||||
echo ""
|
||||
echo "===== redeploy_all_cpp_apps — summary ====="
|
||||
printf " OK : %d\n" "${#ok[@]}"
|
||||
printf " SKIPPED : %d\n" "${#skipped[@]}"
|
||||
printf " FAILED : %d\n" "${#failed[@]}"
|
||||
|
||||
if [ ${#ok[@]} -gt 0 ]; then
|
||||
echo " Deployed:"
|
||||
for n in "${ok[@]}"; do printf " + %s\n" "$n"; done
|
||||
fi
|
||||
if [ ${#skipped[@]} -gt 0 ]; then
|
||||
echo " Skipped (no .exe):"
|
||||
for n in "${skipped[@]}"; do printf " - %s\n" "$n"; done
|
||||
fi
|
||||
if [ ${#failed[@]} -gt 0 ]; then
|
||||
echo " Failed:"
|
||||
for n in "${failed[@]}"; do printf " x %s\n" "$n"; done
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Ejecutar si se llama directamente (fn run lo invoca como script)
|
||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
||||
redeploy_all_cpp_apps "$@"
|
||||
fi
|
||||
Reference in New Issue
Block a user