Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 

Repository files navigation

up

Actualiza el software de tu máquina desde la consola. Un paso por gestor de paquetes.

$ up

==> dnf
  $ sudo dnf5 check-upgrade --refresh
  $ sudo dnf5 upgrade -y
  ...

==> flatpak_sys
  $ sudo flatpak update --system -y --noninteractive
  Nothing to do.

== resumen ==
  dnf            ok
  flatpak_sys    nada que hacer
  flatpak_user   nada que hacer
  npm_global     FALLO (rc=1)

El paso que falla no cancela los demás, y lo ves en una línea en vez de en 2000.

365 líneas de bash. Cero dependencias. Cero configuración. Linux (dnf · apt · pacman · zypper · apk) y macOS. Bash 3.2+.


Qué es

Un envoltorio honesto sobre los gestores que ya tienes instalados. No inventa nada: los lanza con los argumentos correctos, traduce sus códigos de salida, y te dice al final qué funcionó y qué no.

Qué NO es

  • No es un gestor de paquetes. No instala, no busca, no desinstala.
  • No actualiza firmware por su cuenta (ver Firmware).
  • No hace saltos de versión de la distro (dnf system-upgrade, do-release-upgrade, macOS mayor). Eso se hace a mano, mirando la pantalla.
  • No se auto-actualiza. Una herramienta que se rompe a sí misma a mitad de ejecución te deja sin actualizador.
  • No tiene fichero de configuración. Si necesitas una web para explicar tu config, la config está mal.
  • No soporta Windows nativo. Con WSL es Linux y funciona.

Instalación

git clone https://github.com/blasdecrespo/up.git
ln -s "$PWD/up/up" ~/.local/bin/up

Requisitos: bash 3.2 o superior. Nada más. Si tienes GNU timeout (cualquier Linux, o brew install coreutils en macOS) se usa; si no, avisa y sigue sin él.


Uso

up                    # todos los pasos por defecto que existan en esta máquina
up -n                 # dry-run: imprime los comandos exactos, no ejecuta, no pide contraseña
up -l                 # lista los pasos y cuáles existen aquí
up dnf flatpak_user   # solo esos pasos
up firmware           # paso opt-in
up -t 600             # timeout por comando, en segundos (por defecto 1800)
up -h                 # ayuda

Pasos

Paso Binario Root Defecto Comando
dnf dnf5 check-upgrade --refresh, y si hay algo, upgrade -y
apt apt-get update + upgrade -y --force-confold
pacman pacman -Syu --noconfirm
zypper zypper --non-interactive update
apk apk -U upgrade
macos softwareupdate --install --recommended
brew brew no update + upgrade
snap snap refresh
flatpak_sys flatpak update --system -y --noninteractive
flatpak_user flatpak no update --user -y --noninteractive
npm_global npm depende Reinstala cada global a @latest
pipx pipx no upgrade-all
rustup rustup no update
cargo cargo-install-update no cargo install-update -a
gh_ext gh no extension upgrade --all
firmware fwupdmgr no no Solo informa

Sin argumentos, up corre solo los pasos cuyo binario existe aquí. Un gestor que no tienes instalado no es una omisión que reportar: es ruido. Si lo pides por nombre y no está, entonces sí se te dice: AUSENTE.

Códigos de salida

0 si todo fue bien. Si no, el número de pasos que fallaron.

Estado Significado
ok Actualizado
nada que hacer Ya estaba al día
AUSENTE (bin) Lo pediste por nombre y ese binario no está aquí
SIN PERMISOS El paso necesita root y no lo conseguiste (cuenta como fallo)
TIMEOUT (Ns) Un comando del paso pasó del límite y fue matado. El límite es por comando, no por paso: npm_global lanza un npm install por paquete y cada uno tiene sus N segundos
FALLO (rc=N) El gestor devolvió error. N es su código real

Cómo se probó

Un actualizador que corre con root y no se ha probado no es una herramienta: es una apuesta. Esto es lo que se ejecutó de verdad, y lo que no.

Paso Probado Dónde
apt ✅ ejecución real contenedor debian:stable (Debian 13)
pacman ✅ ejecución real contenedor archlinux:latest
zypper actualización real aplicada contenedor opensuse/tumbleweed
apk actualización real aplicada contenedor alpine:3.22
pipx ✅ ejecución real contenedor debian:stable
rustup ✅ ejecución real contenedor rust:slim
gh_ext ✅ ejecución real host Fedora 43
firmware ✅ ejecución real host Fedora 43 (detectó un dbx pendiente)
flatpak_user ✅ ejecución real host Fedora 43
dnf actualización real aplicada host Fedora 43: transacción de 1419 paquetes (kernel, glibc, systemd)
npm_global ⚠️ parcial solo el camino "sin globales instalados"
cargo ⚠️ solo detección nombre del binario verificado en el Cargo.toml del crate
flatpak_sys requiere root interactivo
snap requiere systemd
brew sin máquina con brew
macos sin máquina Darwin. softwareupdate no se ha ejecutado nunca

Portabilidad, verificada igual:

  • Bash 3.2.57 (la versión que trae macOS desde 2007): parsea y ejecuta el script. Contenedor bash:3.2, ejecución real del paso apk.
  • Sin GNU timeout (Alpine sin coreutils, y macOS de fábrica): avisa por stderr y sigue funcionando sin límite de tiempo.
  • Máquina sin ningún gestor conocido: sale con código 1 y un mensaje, no con un error de bash.

Si usas macOS, el paso macos es código no probado corriendo como root. Empieza por up -n y decide tú.


Diseño

Multi-OS sin ramas

No hay detección de distribución. No hay if [[ $ID == fedora ]]. La tabla de pasos es la única estructura de datos, y la detección es "¿existe el binario?". Añadir un sistema operativo es añadir filas, no ramas.

PASOS=(
    "apt|apt-get|1|1"      # nombre | binario | puede_necesitar_root | por_defecto
)

Consecuencia directa: el mismo script en Fedora corre dnf, en Debian corre apt, y en Alpine corre apk, sin una sola condicional de plataforma. Si el modelo de datos es el correcto, los casos especiales desaparecen.

Lo que copié de topgrade

Cuatro cosas, y solo cuatro:

  1. Detección por existencia del binario, no por configuración.
  2. Fallo parcial no aborta. Un paso roto no cancela los otros.
  3. Elevación una vez al principio, con keep-alive. Si no, la credencial caduca a los 5 minutos y te pregunta a mitad de la tanda.
  4. Resumen final tabulado. No lees 2000 líneas de scroll para saber qué falló.

Lo que rechacé, y por qué

Todo esto son problemas reales, documentados en sus propios issues:

Problema Aquí
Salta pasos en silencio (#530) AUSENTE, SIN PERMISOS y nada que hacer son estados distintos
Se cuelga y hay que matarlo (#288, #563, #380) timeout -k 10 por paso y stdin cerrado
Asume que 0 = ok para todos los gestores Cada paso traduce su código de salida
Un paso rompe al siguiente (#1039) Los pasos son independientes
Config TOML de 524 líneas de ejemplo (#1472) Sin config
Se auto-actualiza y se rompe (#959) No se toca a sí mismo
174 pasos = 170 issues abiertos permanentes 16 pasos, y probados uno a uno

Privilegios

sudo, o doas si no hay sudo, o nada si ya eres root (contenedores, su -). Se aplica al comando concreto, nunca al proceso entero:

sudo up     # ❌ NO. Correrías npm -g y cargo como root.
up          # ✅ Sí. Cada paso eleva solo lo que necesita.

brew se niega a correr como root, y tiene razón. Por eso su fila dice 0.

Códigos de salida reales de cada gestor

Esto es la mitad del trabajo de un meta-updater, y es donde casi todos fallan:

  • dnf5 check-upgrade100 significa hay actualizaciones, 0 significa nada que hacer. Contrato scriptable sin parsear texto. Lo uso para no lanzar un upgrade vacío ni imprimir un paso inútil.
  • zypper100/101 significan actualizaciones aplicadas, no error. 106 es un repositorio que no se pudo leer: molesto, no fatal.
  • fwupdmgr get-updates2 = nada que hacer, 3 = nada soportado.
  • fwupdmgr refresh --force → falla si los metadatos son recientes. Se ignora.
  • dnf5 needs-restarting -r1 = hace falta reiniciar. Cualquier otro código es un error suyo, y un error no es motivo para decirte que reinicies.

Un meta-updater que trate cualquier código distinto de 0 como error te va a mentir todos los días.

Actualizar no es borrar

Tres decisiones del mismo principio:

  • apt-get upgrade, no dist-upgrade. dist-upgrade desinstala paquetes para resolver conflictos.
  • zypper update, no dup. dup puede cambiarte medio sistema. (Aun así, update puede sustituir paquetes: en las pruebas, Tumbleweed cambió libcurl-mini4 por libcurl4. Es su resolutor, no el script.)
  • flatpak --noninteractive. No es solo para automatizar: le impide proponerte desinstalar runtimes EOL. Para limpiar, flatpak uninstall --unused, aparte.

Y --force-confold en apt: ante un fichero de configuración que tú modificaste, se queda con el tuyo en vez de abrir un diálogo que cuelga la tanda entera.

npm

npm update -g está roto de facto: no actualiza los globales por el caret implícito de semver (npm#17209), y en su día llegó a borrarlos todos (npm/cli#3175).

Lo que sí funciona: enumerar npm root -g y reinstalar cada paquete a @latest, uno a uno. Sin jq, sin parsear JSON: se leen los directorios (con soporte para @scope/pkg).

El root es dinámico: si el directorio global es tuyo (npm de brew, o prefix en $HOME) no usa sudo; si es /usr/local/lib/node_modules de root, sí.

Firmware

up firmware es opt-in y solo informa. Refresca metadatos, lista lo disponible y te imprime el comando para aplicarlo:

Hay firmware disponible. Aplícalo tú, enchufado a la corriente:
  fwupdmgr update

Un flasheo interrumpido convierte el portátil en un ladrillo. fwupd además exige corriente alterna y umbral de batería, y falla en portátiles con límite de carga aunque estén enchufados. Eso no va en un barrido diario desatendido.

Reinicio

Al terminar, avisa si hay kernel o servicios actualizados que siguen corriendo en su versión vieja: dnf5 needs-restarting -r en Fedora, /var/run/reboot-required en Debian y Ubuntu.

No reinicia nada. Te lo dice.


Extenderlo

Un paso son dos cosas: una fila en la tabla y una función.

PASOS=(
    ...
    "xbps|xbps-install|1|1"      # nombre | binario | root | por_defecto
)

# Contrato: 0 = actualizado, 2 = no había nada que hacer, otro = fallo.
paso_xbps() {
    run_root xbps-install -Suy
}

run imprime el comando, respeta el dry-run, aplica el timeout y cierra stdin. run_root hace lo mismo elevando. Eso es todo: no hay registro, ni plugin API, ni interfaz que implementar.

Pruébalo antes de mandarlo. En contenedor cuesta un minuto:

podman run --rm -v "$PWD/up:/usr/local/bin/up:ro" docker.io/library/debian:stable up -n

Licencia

MIT. Ver LICENSE.

About

Actualiza el software de tu máquina desde la consola. Un script bash, cero dependencias, Linux y macOS.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages