feat(compile): Wails support in /compile skill
- New helper: deploy_wails_exe_to_windows_bash_infra - taskkill + cp build/bin/<app>.exe to Desktop/apps/<app>/ - cmd.exe /c start RELAUNCHES the app post-deploy (key diff vs cpp) - preserves local_files/, copies appicon.ico if present - New pipeline: compile_wails_app_bash_pipelines - resolve_cpp_app_dir (reused) + wails build -platform windows/amd64 - auto -tags goolm if app declares matrix_crypto_init - delegates deploy + relaunch to deploy_wails_exe_to_windows - /compile skill dispatches by framework: - wails.json present -> compile_wails_app (relaunches) - CMakeLists.txt present -> compile_cpp_app (no relaunch) Refs: matrix_client_pc + matrix_admin_panel (issues 0147, 0163)
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
---
|
||||
name: deploy_wails_exe_to_windows
|
||||
kind: function
|
||||
lang: bash
|
||||
domain: infra
|
||||
version: "0.1.0"
|
||||
purity: impure
|
||||
signature: "deploy_wails_exe_to_windows <app_name> <app_dir>"
|
||||
description: "Copia el .exe de una app Wails desde <app_dir>/build/bin/<app>.exe al escritorio de Windows, mata el proceso anterior (taskkill /F) y relanza la app via cmd.exe. Single-binary: no copia DLLs (Webview2 nativo en SO). Preserva local_files/ si existe."
|
||||
tags: ["wails", "windows", "deploy", "cross-compile", "mingw", "infra", "launch", "matrix-mas"]
|
||||
params:
|
||||
- name: app_name
|
||||
desc: "Nombre del binario sin extension (ej. matrix_client_pc). Debe coincidir con el nombre del .exe generado por wails build."
|
||||
- name: app_dir
|
||||
desc: "Ruta absoluta al directorio raiz de la app, donde vive build/bin/<app>.exe. Puede estar en projects/<project>/apps/<app>/ o apps/<app>/."
|
||||
output: "Imprime pasos en stderr. En stdout: ls -lh del .exe desplegado. Exit 0 si ok, exit 1 si build/bin/<app>.exe no existe o los args estan vacios."
|
||||
uses_functions: []
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: "error_go_core"
|
||||
imports: []
|
||||
tested: true
|
||||
tests:
|
||||
- "args vacios devuelven error con mensaje de uso"
|
||||
- "app_dir inexistente devuelve exit 1"
|
||||
- "build/bin exe inexistente devuelve exit 1"
|
||||
test_file_path: "bash/functions/infra/deploy_wails_exe_to_windows_test.sh"
|
||||
file_path: "bash/functions/infra/deploy_wails_exe_to_windows.sh"
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```bash
|
||||
source bash/functions/infra/deploy_wails_exe_to_windows.sh
|
||||
|
||||
# Desplegar matrix_client_pc tras wails build -platform windows/amd64
|
||||
deploy_wails_exe_to_windows matrix_client_pc \
|
||||
/home/lucas/fn_registry/projects/element_agents/apps/matrix_client_pc
|
||||
```
|
||||
|
||||
Con override de destino:
|
||||
|
||||
```bash
|
||||
WIN_DESKTOP_APPS=/mnt/c/Users/lucas/Desktop/apps \
|
||||
deploy_wails_exe_to_windows matrix_admin_panel \
|
||||
/home/lucas/fn_registry/projects/element_agents/apps/matrix_admin_panel
|
||||
```
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Tras un `wails build -platform windows/amd64` exitoso, para desplegar el binario compilado en Windows y relanzarlo en el mismo paso. Ideal en el ciclo de iteracion rapida: compilar → desplegar → ver cambios. Equivalente a `deploy_cpp_exe_to_windows_bash_infra` pero para apps Wails (single-binary sin DLLs extras).
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **taskkill /F fuerza muerte** sin permitir guardado en disco. Las apps Wails persisten estado en keyring de Windows y AppData — este kill es seguro para ellas. Si la app tuviera autosave en progreso, se perderia (aceptable en ciclos de dev).
|
||||
- **UNC paths prohibidos en cmd.exe**: `cmd.exe /c start` debe ejecutarse con `cd` previo al directorio Windows (`/mnt/c/...`). Intentar lanzar con path `\\wsl.localhost\...` falla con "UNC paths are not supported as the current directory".
|
||||
- **cmd.exe start no bloquea**: la funcion espera 3s y verifica via `tasklist.exe`. Si la app cierra sola tras el arranque (error de inicio), el warn final lo indica pero no causa exit 1. Revisar logs en `%APPDATA%\<app>\` o `%LOCALAPPDATA%\<app>\`.
|
||||
- **Single-binary Wails**: no copiar DLLs. Webview2 es nativo del SO (Windows 10+ ya lo incluye). Si una version vieja de Windows no tuviera Webview2, la app falla al arrancar — solucion: instalar Webview2 Runtime en esa maquina.
|
||||
- **Build previo es responsabilidad del caller**: esta funcion NO compila. Para matrix_client_pc usa `-tags goolm` por el crypto de Matrix: `wails build -platform windows/amd64 -tags goolm`.
|
||||
- **WIN_DESKTOP_APPS override**: variable de entorno para cambiar el destino. Util en CI o maquinas con escritorio en otra ruta.
|
||||
@@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env bash
|
||||
# deploy_wails_exe_to_windows — Copia el .exe de una app Wails compilado en
|
||||
# <app_dir>/build/bin/<app>.exe al escritorio de Windows, mata el proceso
|
||||
# anterior y relanza la app. Single-binary: no copia DLLs (Webview2 nativo SO).
|
||||
# Pre-authorized: taskkill.exe /F — idempotente, sin prompt.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
deploy_wails_exe_to_windows() {
|
||||
local app="${1:-}"
|
||||
local app_dir="${2:-}"
|
||||
|
||||
if [ -z "$app" ] || [ -z "$app_dir" ]; then
|
||||
echo "ERROR: uso: deploy_wails_exe_to_windows <app_name> <app_dir>" >&2
|
||||
echo " app_name: nombre del binario sin extension (ej. matrix_client_pc)" >&2
|
||||
echo " app_dir: ruta absoluta al directorio de la app (donde vive build/bin/)" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local win_desktop_apps="${WIN_DESKTOP_APPS:-/mnt/c/Users/lucas/Desktop/apps}"
|
||||
|
||||
# --- 1. Validar que el .exe existe ---
|
||||
local exe_src="${app_dir}/build/bin/${app}.exe"
|
||||
if [ ! -f "$exe_src" ]; then
|
||||
echo "ERROR: no se encontro $exe_src" >&2
|
||||
echo "Compila primero con: wails build -platform windows/amd64" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# --- 2. Crear directorio destino (preserva local_files/ si existe) ---
|
||||
local dest="${win_desktop_apps}/${app}"
|
||||
mkdir -p "$dest"
|
||||
echo "[deploy_wails] dest: $dest" >&2
|
||||
|
||||
# --- 3. Matar proceso si esta corriendo en Windows ---
|
||||
# Pre-authorized. Wails apps usan AppData+keyring para estado, kill /F es seguro.
|
||||
if command -v taskkill.exe >/dev/null 2>&1; then
|
||||
echo "[deploy_wails] matando ${app}.exe si corre..." >&2
|
||||
taskkill.exe /IM "${app}.exe" /F 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# --- 4. Esperar a que Windows libere el file handle ---
|
||||
sleep 1
|
||||
|
||||
# --- 5. Copiar .exe (cp -f: overwrite sin borrar el directorio) ---
|
||||
echo "[deploy_wails] copiando ${app}.exe..." >&2
|
||||
cp -f "$exe_src" "$dest/${app}.exe"
|
||||
|
||||
# --- 6. Copiar appicon.ico si existe (opcional, algunos hubs lo leen) ---
|
||||
local icon_src="${app_dir}/appicon.ico"
|
||||
if [ -f "$icon_src" ]; then
|
||||
echo "[deploy_wails] copiando appicon.ico..." >&2
|
||||
cp -f "$icon_src" "$dest/appicon.ico"
|
||||
fi
|
||||
|
||||
# --- 7. Relanzar la app desde su dir Windows ---
|
||||
# Usar cmd.exe /c start desde el dir destino (no UNC paths — falla en cmd.exe).
|
||||
echo "[deploy_wails] lanzando ${app}.exe..." >&2
|
||||
(
|
||||
cd "$dest"
|
||||
cmd.exe /c start "" "${app}.exe"
|
||||
)
|
||||
|
||||
# --- 8. Dar tiempo a que el proceso arranque ---
|
||||
sleep 3
|
||||
|
||||
# --- 9. Verificar que el proceso esta corriendo ---
|
||||
if command -v tasklist.exe >/dev/null 2>&1; then
|
||||
local tasklist_out
|
||||
tasklist_out=$(tasklist.exe /FI "IMAGENAME eq ${app}.exe" /NH 2>/dev/null || true)
|
||||
if echo "$tasklist_out" | grep -qi "^${app}.exe"; then
|
||||
local pid
|
||||
pid=$(echo "$tasklist_out" | grep -i "^${app}.exe" | awk '{print $2}' | head -n1)
|
||||
echo "[deploy_wails] ${app}.exe corriendo con PID $pid" >&2
|
||||
else
|
||||
echo "WARN: ${app}.exe no aparece en tasklist tras el lanzamiento." >&2
|
||||
echo " Puede que la app cerro con error. Revisar AppData para logs." >&2
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- 10. Resumen final en stdout ---
|
||||
ls -lh "$dest/${app}.exe"
|
||||
|
||||
echo "[deploy_wails] OK: ${app} deployado en $dest" >&2
|
||||
if [ -d "$dest/local_files" ]; then
|
||||
echo "[deploy_wails] local_files/ preservado: $(du -sh "$dest/local_files" | cut -f1)" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
if [ "${BASH_SOURCE[0]}" = "$0" ]; then
|
||||
deploy_wails_exe_to_windows "$@"
|
||||
fi
|
||||
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env bash
|
||||
# Tests para deploy_wails_exe_to_windows
|
||||
# Solo prueba validacion de argumentos y rutas — no ejecuta taskkill/cmd.exe reales.
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/deploy_wails_exe_to_windows.sh"
|
||||
|
||||
PASS=0
|
||||
FAIL=0
|
||||
|
||||
assert_eq() {
|
||||
local test_name="$1" expected="$2" got="$3"
|
||||
if [[ "$expected" == "$got" ]]; then
|
||||
echo "PASS: $test_name"
|
||||
PASS=$((PASS + 1))
|
||||
else
|
||||
echo "FAIL: $test_name — expected '$expected', got '$got'"
|
||||
FAIL=$((FAIL + 1))
|
||||
fi
|
||||
}
|
||||
|
||||
# --- Test 1: args vacios devuelven error con mensaje de uso ---
|
||||
actual_exit=0
|
||||
deploy_wails_exe_to_windows >/dev/null 2>&1 || actual_exit=$?
|
||||
assert_eq "args vacios devuelven error con mensaje de uso" "1" "$actual_exit"
|
||||
|
||||
# --- Test 2: app_dir inexistente devuelve exit 1 ---
|
||||
actual_exit=0
|
||||
deploy_wails_exe_to_windows "myapp" "/tmp/nonexistent_dir_$(date +%s)" >/dev/null 2>&1 || actual_exit=$?
|
||||
assert_eq "app_dir inexistente devuelve exit 1" "1" "$actual_exit"
|
||||
|
||||
# --- Test 3: build/bin exe inexistente devuelve exit 1 ---
|
||||
TMPDIR_APP=$(mktemp -d)
|
||||
# Crear estructura de dir de app pero SIN el exe
|
||||
mkdir -p "$TMPDIR_APP/build/bin"
|
||||
actual_exit=0
|
||||
deploy_wails_exe_to_windows "myapp" "$TMPDIR_APP" >/dev/null 2>&1 || actual_exit=$?
|
||||
rm -rf "$TMPDIR_APP"
|
||||
assert_eq "build/bin exe inexistente devuelve exit 1" "1" "$actual_exit"
|
||||
|
||||
echo "---"
|
||||
echo "Results: $PASS passed, $FAIL failed"
|
||||
[[ $FAIL -eq 0 ]] || exit 1
|
||||
@@ -0,0 +1,65 @@
|
||||
---
|
||||
name: compile_wails_app
|
||||
kind: pipeline
|
||||
lang: bash
|
||||
domain: pipelines
|
||||
version: "0.1.0"
|
||||
purity: impure
|
||||
signature: "compile_wails_app(app_name_or_empty: string) -> void"
|
||||
description: "Pipeline que resuelve la app Wails desde el nombre o CWD, la compila para Windows con wails build -platform windows/amd64 (detectando -tags goolm automaticamente si la app usa E2EE Matrix), y despliega el .exe al escritorio de Windows + relanza el proceso. Equivalente a compile_cpp_app pero para apps Wails (Go + WebView2)."
|
||||
tags: [wails, windows, compile, pipelines, launch, matrix-mas]
|
||||
uses_functions:
|
||||
- resolve_cpp_app_dir_bash_infra
|
||||
- deploy_wails_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/compile_wails_app.sh"
|
||||
params:
|
||||
- name: app_name_or_empty
|
||||
desc: "Nombre de la app Wails a compilar (opcional). Sin arg se deduce desde el directorio actual si estamos dentro de projects/*/apps/<X>/ o apps/<X>/. Lista apps disponibles si no puede deducirlo."
|
||||
output: "Compila el .exe con wails build, lo despliega al escritorio de Windows y relanza el proceso. Imprime progreso por steps a stderr y resumen final con ls -lh del .exe resultante."
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```bash
|
||||
# Desde el directorio de la app (deduce nombre automaticamente)
|
||||
cd projects/element_agents/apps/matrix_client_pc
|
||||
./fn run compile_wails_app
|
||||
|
||||
# Desde la raiz del registry, con nombre explicito
|
||||
cd /home/lucas/fn_registry
|
||||
./fn run compile_wails_app matrix_admin_panel
|
||||
|
||||
# Directo sin fn run
|
||||
bash bash/functions/pipelines/compile_wails_app.sh matrix_client_pc
|
||||
```
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Usar cuando quieras rebuild + redeploy + relanzar una app Wails con un solo comando durante iteracion activa de desarrollo. Equivale al slash command `/compile` aplicado a targets Wails. El pipeline detecta automaticamente si la app necesita `-tags goolm` (apps Matrix con E2EE).
|
||||
|
||||
## Gotchas
|
||||
|
||||
- Requiere `wails` CLI instalado en PATH y mingw-w64 configurado para cross-compile (`GOARCH=amd64 GOOS=windows` via toolchain Wails).
|
||||
- Si la app usa `-tags goolm` (E2EE Matrix), esta pipeline lo detecta automaticamente: busca `matrix_crypto_init` en `app.md` o `"build:tags": "goolm"` en `wails.json`. Si la deteccion falla, pasar la variable `TAGS` o editar el `wails.json`.
|
||||
- El relanzar despues del deploy es la diferencia clave con `compile_cpp_app`: las apps Wails son single-binary (no DLLs adicionales) y arrancan en <1s, lo que hace iteracion muy rapida.
|
||||
- Si el build falla con `no required module provides package`, ejecutar `go mod tidy` en el directorio de la app antes de volver a compilar.
|
||||
- `matrix_client_pc` tiene helpers en `internal/infra/` que son copias vendored de `functions/infra/` del registry padre. Si actualizas un helper en el registry padre, debes copiarlo manualmente a la app antes de compilar — el build de Wails no ve el modulo padre.
|
||||
- El deploy mata el proceso anterior con `taskkill.exe /F` (pre-autorizado) antes de copiar el .exe, para evitar "Permission denied" de Windows al sobreescribir un binario en uso.
|
||||
- Variable de entorno `WIN_DESKTOP_APPS` controla el destino; default `/mnt/c/Users/lucas/Desktop/apps`.
|
||||
|
||||
## Flujo
|
||||
|
||||
1. `resolve_cpp_app_dir` — deduce nombre y directorio absoluto de la app (desde CWD o arg)
|
||||
2. Verifica `wails.json` y `go.mod` en el directorio de la app
|
||||
3. Detecta si necesita `-tags goolm` (app.md referencia `matrix_crypto_init` o wails.json lo declara)
|
||||
4. `wails build -platform windows/amd64 [tags]` desde el directorio de la app
|
||||
5. `deploy_wails_exe_to_windows` — mata proceso, copia .exe, relanza y verifica PID
|
||||
6. Imprime `ls -lh` del exe final en `Desktop/apps/<APP>/`
|
||||
@@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env bash
|
||||
# Pipeline: compile_wails_app — Resuelve la app Wails desde el nombre o CWD,
|
||||
# la compila para Windows con wails build y despliega al escritorio + relanza.
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
INFRA_DIR="$SCRIPT_DIR/../infra"
|
||||
|
||||
source "$INFRA_DIR/resolve_cpp_app_dir.sh"
|
||||
source "$INFRA_DIR/deploy_wails_exe_to_windows.sh"
|
||||
|
||||
compile_wails_app() {
|
||||
local app_arg="${1:-}"
|
||||
|
||||
# --- Paso 1: Resolver nombre y directorio de la app ---
|
||||
echo "[1/3] Resolviendo app..." >&2
|
||||
local resolved
|
||||
resolved=$(resolve_cpp_app_dir "$app_arg")
|
||||
local APP APP_DIR
|
||||
APP="$(echo "$resolved" | cut -f1)"
|
||||
APP_DIR="$(echo "$resolved" | cut -f2)"
|
||||
echo " App: $APP" >&2
|
||||
echo " Dir: $APP_DIR" >&2
|
||||
|
||||
# --- Verificar que es una app Wails (no C++) ---
|
||||
if [ ! -f "$APP_DIR/wails.json" ]; then
|
||||
echo "ERROR: $APP_DIR/wails.json no encontrado." >&2
|
||||
echo "La app '$APP' no es una app Wails." >&2
|
||||
echo "Si es C++, usa compile_cpp_app en su lugar." >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$APP_DIR/go.mod" ]; then
|
||||
echo "ERROR: $APP_DIR/go.mod no encontrado." >&2
|
||||
echo "Una app Wails requiere go.mod. Ejecuta 'go mod init' en $APP_DIR." >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# --- Paso 2: Compilar para Windows con wails ---
|
||||
echo "" >&2
|
||||
echo "[2/3] Compilando '$APP' para Windows (wails + mingw)..." >&2
|
||||
|
||||
# Detectar si necesita -tags goolm:
|
||||
# 1. app.md declara matrix_crypto_init en uses_functions (E2EE habilitado)
|
||||
# 2. wails.json tiene "build:tags": "goolm" (o "buildTags": "goolm")
|
||||
local TAGS=""
|
||||
local app_md="${APP_DIR}/app.md"
|
||||
local wails_json="${APP_DIR}/wails.json"
|
||||
local needs_goolm=0
|
||||
|
||||
if [ -f "$app_md" ] && grep -q "matrix_crypto_init" "$app_md" 2>/dev/null; then
|
||||
needs_goolm=1
|
||||
echo " Detectado matrix_crypto_init en app.md -> usando -tags goolm" >&2
|
||||
fi
|
||||
|
||||
if [ "$needs_goolm" -eq 0 ] && [ -f "$wails_json" ]; then
|
||||
if grep -qE '"(build:tags|buildTags)"\s*:\s*"goolm"' "$wails_json" 2>/dev/null; then
|
||||
needs_goolm=1
|
||||
echo " Detectado goolm en wails.json -> usando -tags goolm" >&2
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$needs_goolm" -eq 1 ]; then
|
||||
TAGS="-tags goolm"
|
||||
fi
|
||||
|
||||
(
|
||||
cd "$APP_DIR"
|
||||
# shellcheck disable=SC2086
|
||||
wails build -platform windows/amd64 $TAGS
|
||||
)
|
||||
|
||||
# --- Paso 3: Desplegar al escritorio + relanzar ---
|
||||
echo "" >&2
|
||||
echo "[3/3] Desplegando '$APP' al escritorio + relanzar..." >&2
|
||||
deploy_wails_exe_to_windows "$APP" "$APP_DIR"
|
||||
|
||||
# --- Resumen final ---
|
||||
local win_desktop_apps="${WIN_DESKTOP_APPS:-/mnt/c/Users/lucas/Desktop/apps}"
|
||||
local final_exe="$win_desktop_apps/$APP/$APP.exe"
|
||||
|
||||
echo "" >&2
|
||||
if [ -f "$final_exe" ]; then
|
||||
echo "===== compile_wails_app: OK =====" >&2
|
||||
ls -lh "$final_exe" >&2
|
||||
else
|
||||
echo "WARN: no se encuentra $final_exe" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
compile_wails_app "${1:-}"
|
||||
Reference in New Issue
Block a user