#!/usr/bin/env bash # Instalador de Kapiz 1.0.4 para macOS y Linux. # # curl -fsSL https://www.kapiz.dev/install.sh | bash # # Descarga la app de https://www.kapiz.dev, comprueba su huella SHA-256 y la instala. # Lo que baja curl no queda marcado como «descargado de internet», así que # macOS no muestra el aviso de desarrollador no identificado. # # KAPIZ_INSTALL_DIR cambia dónde se instala (por defecto /Applications en macOS # y ~/.local/bin en Linux) y KAPIZ_INSTALL_NAME, en Linux, con qué nombre. # # La propia app lo lanza al pulsar "Actualizar ahora", con KAPIZ_FILE (el # instalador que ella ya bajó y comprobó), KAPIZ_WAIT_PID (su proceso: espera a # que se cierre antes de tocarla) y KAPIZ_RELAUNCH (la vuelve a abrir al terminar). set -euo pipefail VERSION='1.0.4' URL_MAC='https://www.kapiz.dev/downloads/kapiz-1.0.4-universal.dmg' URL_LINUX='https://www.kapiz.dev/downloads/kapiz-1.0.4-x86_64.AppImage' tmp="$(mktemp -d)" mnt="" cleanup() { if [ -n "$mnt" ]; then hdiutil detach -quiet "$mnt" 2>/dev/null || true; fi rm -rf "$tmp" } trap cleanup EXIT fail() { printf '\n✘ %s\n' "$1" >&2; exit 1; } say() { printf '%s\n' "$1"; } sha256() { if command -v shasum >/dev/null 2>&1; then shasum -a 256 "$1" | cut -d' ' -f1 else sha256sum "$1" | cut -d' ' -f1; fi } # Descarga $1 en $2 y la compara con la huella publicada al lado ($1.sha256). download() { # Desde "Actualizar ahora" la app ya lo bajó y comprobó su huella. if [ -n "${KAPIZ_FILE:-}" ] && [ -f "$KAPIZ_FILE" ]; then mv "$KAPIZ_FILE" "$2"; return 0; fi curl -fSL --progress-bar "$1" -o "$2" || fail "No se pudo descargar $1" curl -fsSL "$1.sha256" -o "$2.sha256" || fail "No se pudo descargar la huella de $1" [ "$(cut -d' ' -f1 < "$2.sha256")" = "$(sha256 "$2")" ] \ || fail "La huella no coincide: el archivo llegó dañado o alterado. No se instaló nada." } # Actualización desde la app: no se toca nada hasta que se haya cerrado. $1 es un # patrón de sus procesos para esperar también a los hijos (el puente), que # tardan un instante más en irse. wait_app() { [ -n "${KAPIZ_WAIT_PID:-}" ] || return 0 for _ in $(seq 1 60); do kill -0 "$KAPIZ_WAIT_PID" 2>/dev/null || break; sleep 1; done if kill -0 "$KAPIZ_WAIT_PID" 2>/dev/null; then fail "Kapiz no terminó de cerrarse; no se actualizó."; fi if [ -n "${1:-}" ]; then for _ in $(seq 1 30); do pgrep -f "$1" >/dev/null 2>&1 || return 0; sleep 1; done fi } [ -n "$VERSION" ] || fail "Todavía no hay una versión de Kapiz publicada." case "$(uname -s)" in Darwin) [ -n "$URL_MAC" ] || fail "Todavía no hay versión para macOS." say "Descargando Kapiz $VERSION para macOS…" download "$URL_MAC" "$tmp/kapiz.dmg" mnt="$tmp/mnt" mkdir "$mnt" hdiutil attach -nobrowse -readonly -quiet -mountpoint "$mnt" "$tmp/kapiz.dmg" \ || fail "No se pudo abrir el instalador (.dmg)." app="$(find "$mnt" -maxdepth 1 -name '*.app' -print -quit)" [ -n "$app" ] || fail "El instalador no trae la app." name="$(basename "$app")" # La carpeta pedida se crea si no existe; sin pedir ninguna, /Applications, # y si no se puede escribir ahí (cuenta sin permisos), la del usuario. if [ -n "${KAPIZ_INSTALL_DIR:-}" ]; then dest="$KAPIZ_INSTALL_DIR" elif [ -w /Applications ]; then dest=/Applications else dest="$HOME/Applications"; fi mkdir -p "$dest" wait_app "$dest/$name/Contents/MacOS/" # Sustituirla con la app abierta deja procesos a medio actualizar. if pgrep -f "$dest/$name/Contents/MacOS/" >/dev/null 2>&1; then fail "Kapiz está abierto. Ciérralo y vuelve a ejecutar el comando." fi rm -rf "${dest:?}/$name" ditto "$app" "$dest/$name" xattr -dr com.apple.quarantine "$dest/$name" 2>/dev/null || true say "" say "✔ Kapiz $VERSION instalado en $dest/$name" say " Ábrelo desde Aplicaciones o con: open \"$dest/$name\"" if [ -n "${KAPIZ_RELAUNCH:-}" ]; then open "$dest/$name"; fi ;; Linux) [ -n "$URL_LINUX" ] || fail "Todavía no hay versión para Linux." [ "$(uname -m)" = "x86_64" ] || fail "Por ahora Kapiz solo está para Linux x86_64." say "Descargando Kapiz $VERSION para Linux…" download "$URL_LINUX" "$tmp/kapiz.AppImage" # kapiz-testing-0.2.8-x86_64.AppImage → kapiz-testing: testing y producción no se pisan. file="$(basename "$URL_LINUX")" cmd="${KAPIZ_INSTALL_NAME:-${file%%-[0-9]*}}" dest="${KAPIZ_INSTALL_DIR:-$HOME/.local/bin}" mkdir -p "$dest" # Un AppImage se puede sustituir con la app abierta, pero al actualizar desde # ella se espera igual: así se vuelve a abrir una sola vez. wait_app "" install -m 755 "$tmp/kapiz.AppImage" "$dest/$cmd" # Entrada en el menú de aplicaciones del escritorio. apps="${XDG_DATA_HOME:-$HOME/.local/share}/applications" mkdir -p "$apps" printf '[Desktop Entry]\nType=Application\nName=%s\nExec=%s\nTerminal=false\nCategories=Office;Finance;\n' \ "$([ "$cmd" = kapiz ] && echo Kapiz || echo 'Kapiz Testing')" "$dest/$cmd" > "$apps/$cmd.desktop" say "" say "✔ Kapiz $VERSION instalado en $dest/$cmd" case ":$PATH:" in *":$dest:"*) say " Ábrelo desde el menú de aplicaciones o con: $cmd" ;; *) say " Ábrelo desde el menú de aplicaciones o con: $dest/$cmd" ;; esac say " Si no abre, instala libfuse2 (AppImage lo necesita): sudo apt install libfuse2" if [ -n "${KAPIZ_RELAUNCH:-}" ]; then (nohup "$dest/$cmd" >/dev/null 2>&1 &); fi ;; *) fail "Este comando es para macOS y Linux. En Windows usa: irm https://www.kapiz.dev/install.ps1 | iex" ;; esac