diff --git a/bash/functions/infra/analyze_disk_space.md b/bash/functions/infra/analyze_disk_space.md new file mode 100644 index 00000000..53e76dd1 --- /dev/null +++ b/bash/functions/infra/analyze_disk_space.md @@ -0,0 +1,52 @@ +--- +name: analyze_disk_space +kind: function +lang: bash +domain: infra +version: "1.0.0" +purity: impure +signature: "analyze_disk_space([target_dir: string], [mode: string]) -> void" +description: "Analiza el uso de espacio en disco. Modos: partitions (df con filtros), top-dirs (du top 10), top-files (find top 20), inodes (df -i), all (todos). Emite advertencias si el uso supera el 90%." +tags: [bash, disk, space, analysis, filesystem] +uses_functions: [] +uses_types: [] +returns: [] +returns_optional: false +error_type: "error_go_core" +imports: [] +params: + - name: target_dir + desc: "directorio a analizar para top-dirs y top-files (default: /)" + - name: mode + desc: "qué analizar: partitions|top-dirs|top-files|inodes|all (default: all)" +output: "informe de uso de disco a stdout; advertencias a stdout si uso >90%; exit code 1 si modo desconocido" +tested: false +tests: [] +test_file_path: "" +file_path: "bash/functions/infra/analyze_disk_space.sh" +source_repo: "https://gitea-dgg044oo04woo4ggcsws4gk0.organic-machine.com/egutierrez/DevLauncher.git" +source_license: "MIT" +source_file: "scripts/linux/gestion_linux/espacio_disponible.sh" +--- + +## Ejemplo + +```bash +source bash/functions/infra/analyze_disk_space.sh + +# Análisis completo del directorio raíz +analyze_disk_space + +# Solo particiones +analyze_disk_space / partitions + +# Top directorios en home +analyze_disk_space "$HOME" top-dirs + +# Solo inodos +analyze_disk_space / inodes +``` + +## Notas + +Excluye tmpfs, devtmpfs y loop de los resultados de df. No realiza ninguna limpieza destructiva. El modo top-files puede tardar en sistemas con muchos archivos. diff --git a/bash/functions/infra/analyze_disk_space.sh b/bash/functions/infra/analyze_disk_space.sh new file mode 100644 index 00000000..0d50138b --- /dev/null +++ b/bash/functions/infra/analyze_disk_space.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env bash +# analyze_disk_space +# ------------------ +# Analiza el uso de espacio en disco: particiones, directorios más grandes, +# archivos más grandes e inodos. +# +# USO: +# source analyze_disk_space.sh +# analyze_disk_space [target_dir] [mode] +# +# ARGUMENTOS: +# target_dir Directorio a analizar (default: /) +# mode Modo de análisis: partitions|top-dirs|top-files|inodes|all (default: all) + +analyze_disk_space() { + local target_dir="${1:-/}" + local mode="${2:-all}" + + _ads_partitions() { + echo "=== Espacio en sistemas de archivos ===" + df -h --output=source,fstype,size,used,avail,pcent,target 2>/dev/null \ + | grep -v "tmpfs\|devtmpfs\|loop" | column -t + echo "" + + local high_usage + high_usage="$(df -h | awk 'NR>1 && $5+0 > 90 {print $6, $5}' | grep -v "tmpfs\|devtmpfs" || true)" + if [[ -n "$high_usage" ]]; then + echo "ADVERTENCIA: Discos con uso >90%:" + echo "$high_usage" + echo "" + fi + } + + _ads_top_dirs() { + local dir="${1:-.}" + echo "=== Top 10 carpetas más grandes en: $(realpath "$dir") ===" + du -h --max-depth=1 "$dir" 2>/dev/null | sort -rh | head -11 \ + | awk '{printf "%-10s %s\n", $1, $2}' + echo "" + } + + _ads_top_files() { + local dir="${1:-.}" + echo "=== Top 20 archivos más grandes en: $(realpath "$dir") ===" + find "$dir" -type f -exec du -h {} + 2>/dev/null | sort -rh | head -20 \ + | awk '{printf "%-10s %s\n", $1, $2}' + echo "" + } + + _ads_inodes() { + echo "=== Inodos disponibles ===" + df -i 2>/dev/null | grep -v "tmpfs\|devtmpfs\|loop" | column -t + echo "" + + local high_inodes + high_inodes="$(df -i | awk 'NR>1 && $5+0 > 90 {print $6, $5}' | grep -v "tmpfs\|devtmpfs" || true)" + if [[ -n "$high_inodes" ]]; then + echo "ADVERTENCIA: Sistemas de archivos con >90% de inodos usados:" + echo "$high_inodes" + echo "" + fi + } + + case "$mode" in + partitions) + _ads_partitions + ;; + top-dirs) + _ads_top_dirs "$target_dir" + ;; + top-files) + _ads_top_files "$target_dir" + ;; + inodes) + _ads_inodes + ;; + all) + _ads_partitions + _ads_top_dirs "$target_dir" + _ads_top_files "$target_dir" + _ads_inodes + ;; + *) + echo "analyze_disk_space: modo desconocido '${mode}'. Usa: partitions|top-dirs|top-files|inodes|all" >&2 + return 1 + ;; + esac +} + +# Ejecutar si se invoca directamente +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + analyze_disk_space "$@" +fi diff --git a/bash/functions/infra/detect_wsl.md b/bash/functions/infra/detect_wsl.md new file mode 100644 index 00000000..f4d9b075 --- /dev/null +++ b/bash/functions/infra/detect_wsl.md @@ -0,0 +1,46 @@ +--- +name: detect_wsl +kind: function +lang: bash +domain: infra +version: "1.0.0" +purity: impure +signature: "detect_wsl([--check]) -> void" +description: "Detecta si el sistema es WSL (Windows Subsystem for Linux). Con --check retorna solo exit code (0=WSL, 1=no WSL) sin output. Sin argumentos imprime versión WSL, usuario Windows, distribución, hostname, unidades montadas y ruta Windows del directorio actual." +tags: [bash, wsl, windows, detect, integration] +uses_functions: [] +uses_types: [] +returns: [] +returns_optional: false +error_type: "error_go_core" +imports: [] +params: + - name: --check + desc: "flag: solo detecta y retorna exit code sin producir output (0=WSL, 1=no WSL)" +output: "sin output con --check; informe del entorno WSL a stdout sin argumentos; exit code 1 si no es WSL" +tested: false +tests: [] +test_file_path: "" +file_path: "bash/functions/infra/detect_wsl.sh" +source_repo: "https://gitea-dgg044oo04woo4ggcsws4gk0.organic-machine.com/egutierrez/DevLauncher.git" +source_license: "MIT" +source_file: "scripts/linux/gestion_linux/wsl_host.sh" +--- + +## Ejemplo + +```bash +source bash/functions/infra/detect_wsl.sh + +# Verificar si es WSL en scripts (sin output) +if detect_wsl --check; then + echo "Estamos en WSL" +fi + +# Mostrar información completa del entorno WSL +detect_wsl +``` + +## Notas + +Usa tres métodos de detección en orden: /proc/version, /proc/sys/kernel/osrelease, y la presencia de /mnt/c + WSLInterop. No incluye las acciones interactivas del script original (abrir PowerShell, CMD, Explorer, VS Code). diff --git a/bash/functions/infra/detect_wsl.sh b/bash/functions/infra/detect_wsl.sh new file mode 100644 index 00000000..c02c98c9 --- /dev/null +++ b/bash/functions/infra/detect_wsl.sh @@ -0,0 +1,97 @@ +#!/usr/bin/env bash +# detect_wsl +# ---------- +# Detecta si el sistema actual es WSL (Windows Subsystem for Linux). +# Con --check solo retorna exit code (0=WSL, 1=no WSL) sin output. +# Sin argumentos, imprime información completa del entorno WSL. +# +# USO: +# source detect_wsl.sh +# detect_wsl [--check] + +detect_wsl() { + local check_only=false + [[ "${1:-}" == "--check" ]] && check_only=true + + # Detección interna de WSL + _is_wsl() { + if [[ -f /proc/version ]] && grep -qi "microsoft\|wsl" /proc/version; then + return 0 + fi + if [[ -f /proc/sys/kernel/osrelease ]] && grep -qi "microsoft\|wsl" /proc/sys/kernel/osrelease; then + return 0 + fi + if [[ -d /mnt/c ]] && [[ -f /proc/sys/fs/binfmt_misc/WSLInterop ]]; then + return 0 + fi + return 1 + } + + _get_wsl_version() { + if [[ -f /proc/version ]]; then + if grep -qi "WSL2" /proc/version; then + echo "WSL2" + elif grep -qi "microsoft" /proc/version; then + echo "WSL1" + else + echo "Unknown" + fi + else + echo "Unknown" + fi + } + + _get_windows_username() { + if [[ -n "${WSLENV:-}" ]]; then + cmd.exe /c "echo %USERNAME%" 2>/dev/null | tr -d '\r\n' || echo "Unknown" + else + echo "Unknown" + fi + } + + # Modo --check: solo exit code + if [[ "$check_only" == true ]]; then + _is_wsl && return 0 || return 1 + fi + + # Modo informativo + if ! _is_wsl; then + echo "detect_wsl: este sistema NO es WSL" >&2 + return 1 + fi + + local wsl_version + wsl_version="$(_get_wsl_version)" + + local win_user + win_user="$(_get_windows_username)" + + local distro="Unknown" + if [[ -f /etc/os-release ]]; then + distro="$(. /etc/os-release && echo "${PRETTY_NAME:-${ID:-Unknown}}")" + fi + + echo "=== Entorno WSL ===" + echo " Versión de WSL: ${wsl_version}" + echo " Usuario Windows: ${win_user}" + echo " Distribución: ${distro}" + echo " Hostname: $(hostname)" + echo "" + + echo "=== Unidades de Windows montadas ===" + ls /mnt/ 2>/dev/null | grep -E "^[a-z]$" | while IFS= read -r drive; do + echo " ${drive}: → /mnt/${drive}" + done + echo "" + + local current_win_path + current_win_path="$(wslpath -w "$(pwd)" 2>/dev/null || echo "N/A")" + echo "=== Directorio actual en Windows ===" + echo " ${current_win_path}" + echo "" +} + +# Ejecutar si se invoca directamente +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + detect_wsl "$@" +fi diff --git a/bash/functions/infra/install_go.md b/bash/functions/infra/install_go.md new file mode 100644 index 00000000..77e8203c --- /dev/null +++ b/bash/functions/infra/install_go.md @@ -0,0 +1,49 @@ +--- +name: install_go +kind: function +lang: bash +domain: infra +version: "1.0.0" +purity: impure +signature: "install_go([version: string], [--force]) -> void" +description: "Instala Go en Linux descargando desde go.dev/dl. Detecta arquitectura automáticamente (amd64/arm64/armv6l). Idempotente: omite la instalación si Go ya está presente (a menos que se use --force). Configura PATH en ~/.bashrc o ~/.zshrc." +tags: [bash, install, go, golang] +uses_functions: [] +uses_types: [] +returns: [] +returns_optional: false +error_type: "error_go_core" +imports: [] +params: + - name: version + desc: "versión de Go a instalar, ej: 1.22.0 (default: 1.22.0)" + - name: --force + desc: "flag para reinstalar aunque Go ya esté instalado" +output: "progreso a stdout; exit code 1 si la arquitectura no es soportada o falla la descarga" +tested: false +tests: [] +test_file_path: "" +file_path: "bash/functions/infra/install_go.sh" +source_repo: "https://gitea-dgg044oo04woo4ggcsws4gk0.organic-machine.com/egutierrez/DevLauncher.git" +source_license: "MIT" +source_file: "scripts/linux/instaladores/instalar_go.sh" +--- + +## Ejemplo + +```bash +source bash/functions/infra/install_go.sh + +# Instalar versión por defecto (1.22.0) +install_go + +# Instalar versión específica +install_go 1.23.0 + +# Reinstalar aunque ya esté instalado +install_go 1.22.0 --force +``` + +## Notas + +Requiere `curl` y `sudo`. Instala en `/usr/local/go`. Crea `$HOME/go/{bin,src,pkg}` como GOPATH. Después de instalar, hay que recargar el shell (`source ~/.bashrc`) o abrir una nueva terminal. diff --git a/bash/functions/infra/install_go.sh b/bash/functions/infra/install_go.sh new file mode 100644 index 00000000..fdd78f6c --- /dev/null +++ b/bash/functions/infra/install_go.sh @@ -0,0 +1,115 @@ +#!/usr/bin/env bash +# install_go +# ---------- +# Instala Go en Linux. Detecta arquitectura automáticamente (amd64/arm64/armv6l). +# Descarga desde go.dev/dl, instala en /usr/local y configura PATH en el shell config. +# +# USO: +# source install_go.sh +# install_go [version] [--force] +# +# ARGUMENTOS: +# version Versión de Go a instalar (default: 1.22.0) +# --force Reinstala aunque Go ya esté instalado + +install_go() { + local version="1.22.0" + local force=false + + for arg in "$@"; do + case "$arg" in + --force) force=true ;; + *) [[ "$arg" =~ ^[0-9] ]] && version="$arg" ;; + esac + done + + local go_os="linux" + local go_arch + + # Detectar arquitectura + local arch + arch="$(uname -m)" + case "$arch" in + x86_64) go_arch="amd64" ;; + aarch64|arm64) go_arch="arm64" ;; + armv6l) go_arch="armv6l" ;; + *) + echo "install_go: arquitectura no soportada: ${arch}" >&2 + return 1 + ;; + esac + + # Verificar si ya está instalado + if command -v go &>/dev/null && [[ "$force" != true ]]; then + local current_version + current_version="$(go version | awk '{print $3}' | sed 's/go//')" + echo "install_go: Go ya está instalado (versión: ${current_version}). Usa --force para reinstalar." + return 0 + fi + + local tarball="go${version}.${go_os}-${go_arch}.tar.gz" + local url="https://go.dev/dl/${tarball}" + local install_dir="/usr/local" + + echo "Instalando Go ${version} para ${go_os}-${go_arch}..." + + # Eliminar versión anterior si existe + if command -v go &>/dev/null; then + echo "Eliminando versión anterior..." + sudo rm -rf "${install_dir}/go" + fi + + # Descargar en directorio temporal + local tmp_dir + tmp_dir="$(mktemp -d)" + + echo "Descargando ${url}..." + if ! curl -LO --output-dir "$tmp_dir" "$url"; then + echo "install_go: error al descargar Go ${version}. Verifica la versión en: https://go.dev/dl/" >&2 + rm -rf "$tmp_dir" + return 1 + fi + + echo "Instalando en ${install_dir}..." + sudo tar -C "$install_dir" -xzf "${tmp_dir}/${tarball}" + rm -rf "$tmp_dir" + + # Configurar PATH en shell config + local shell_config="" + if [[ -f "$HOME/.bashrc" ]]; then + shell_config="$HOME/.bashrc" + elif [[ -f "$HOME/.zshrc" ]]; then + shell_config="$HOME/.zshrc" + fi + + if [[ -n "$shell_config" ]]; then + if ! grep -q "export PATH=\$PATH:${install_dir}/go/bin" "$shell_config"; then + { + echo "" + echo "# Go configuration" + echo "export PATH=\$PATH:${install_dir}/go/bin" + echo "export GOPATH=\$HOME/go" + echo "export PATH=\$PATH:\$GOPATH/bin" + } >> "$shell_config" + echo "Variables de PATH añadidas a ${shell_config}" + else + echo "Variables de entorno ya configuradas en ${shell_config}" + fi + fi + + # Crear estructura GOPATH + mkdir -p "$HOME/go"/{bin,src,pkg} + + # Verificar instalación + export PATH="$PATH:${install_dir}/go/bin" + local installed_version + installed_version="$("${install_dir}/go/bin/go" version)" + echo "" + echo "Go instalado correctamente: ${installed_version}" + echo "Reinicia tu terminal o ejecuta: source ${shell_config:-~/.bashrc}" +} + +# Ejecutar si se invoca directamente +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + install_go "$@" +fi diff --git a/bash/functions/infra/install_nodejs.md b/bash/functions/infra/install_nodejs.md new file mode 100644 index 00000000..f4bdbd47 --- /dev/null +++ b/bash/functions/infra/install_nodejs.md @@ -0,0 +1,45 @@ +--- +name: install_nodejs +kind: function +lang: bash +domain: infra +version: "1.0.0" +purity: impure +signature: "install_nodejs([version: string]) -> void" +description: "Instala Node.js en Linux usando nvm. Instala nvm v0.39.7 si no está presente. Instala la versión de Node indicada, la activa con 'nvm use' y la configura como default. Idempotente si nvm ya está instalado." +tags: [bash, install, nodejs, nvm] +uses_functions: [] +uses_types: [] +returns: [] +returns_optional: false +error_type: "error_go_core" +imports: [] +params: + - name: version + desc: "versión principal de Node.js a instalar (default: 20)" +output: "progreso a stdout con versión instalada; exit code 1 si nvm no queda disponible" +tested: false +tests: [] +test_file_path: "" +file_path: "bash/functions/infra/install_nodejs.sh" +source_repo: "https://gitea-dgg044oo04woo4ggcsws4gk0.organic-machine.com/egutierrez/DevLauncher.git" +source_license: "MIT" +source_file: "scripts/linux/instaladores/instalar_nodejs.sh" +--- + +## Ejemplo + +```bash +source bash/functions/infra/install_nodejs.sh + +# Instalar Node.js 20 (LTS por defecto) +install_nodejs + +# Instalar versión específica +install_nodejs 18 +install_nodejs 21 +``` + +## Notas + +Requiere `curl`. nvm se instala en `$HOME/.nvm`. Después de instalar en una sesión nueva, hay que recargar el shell para que los comandos `node` y `npm` queden disponibles globalmente. diff --git a/bash/functions/infra/install_nodejs.sh b/bash/functions/infra/install_nodejs.sh new file mode 100644 index 00000000..f889c320 --- /dev/null +++ b/bash/functions/infra/install_nodejs.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +# install_nodejs +# -------------- +# Instala Node.js en Linux usando nvm (Node Version Manager). +# Instala nvm si no está presente, luego instala la versión de Node indicada +# y la configura como default. +# +# USO: +# source install_nodejs.sh +# install_nodejs [version] +# +# ARGUMENTOS: +# version Versión principal de Node.js (default: 20) + +install_nodejs() { + local node_version="${1:-20}" + + echo "Instalando Node.js v${node_version} mediante nvm..." + echo "" + + # Informar si Node ya está instalado + if command -v node &>/dev/null; then + local current_version + current_version="$(node --version)" + echo "Node.js ya está instalado: ${current_version}" + echo "Continuando con la instalación/actualización..." + fi + + # Instalar nvm si no está presente + if [[ -d "$HOME/.nvm" ]]; then + echo "nvm ya está instalado." + export NVM_DIR="$HOME/.nvm" + # shellcheck disable=SC1091 + [[ -s "$NVM_DIR/nvm.sh" ]] && source "$NVM_DIR/nvm.sh" + else + echo "Descargando e instalando nvm..." + curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash + + export NVM_DIR="$HOME/.nvm" + # shellcheck disable=SC1091 + [[ -s "$NVM_DIR/nvm.sh" ]] && source "$NVM_DIR/nvm.sh" + echo "nvm instalado correctamente." + fi + + # Verificar que nvm esté disponible + if ! command -v nvm &>/dev/null; then + echo "install_nodejs: nvm no está disponible después de la instalación" >&2 + echo " Ejecuta: source ~/.bashrc (o abre una nueva terminal)" >&2 + return 1 + fi + + echo "" + echo "Instalando Node.js v${node_version}..." + nvm install "$node_version" + nvm use "$node_version" + nvm alias default "$node_version" + + local installed_node + local installed_npm + installed_node="$(node --version)" + installed_npm="$(npm --version)" + + echo "" + echo "Node.js instalado correctamente:" + echo " Node.js: ${installed_node}" + echo " npm: ${installed_npm}" + echo "" + echo "Si es una instalación nueva, reinicia tu terminal o ejecuta:" + echo " source ~/.bashrc # o ~/.zshrc según tu shell" +} + +# Ejecutar si se invoca directamente +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + install_nodejs "$@" +fi diff --git a/bash/functions/infra/install_pnpm.md b/bash/functions/infra/install_pnpm.md new file mode 100644 index 00000000..4d8387c8 --- /dev/null +++ b/bash/functions/infra/install_pnpm.md @@ -0,0 +1,40 @@ +--- +name: install_pnpm +kind: function +lang: bash +domain: infra +version: "1.0.0" +purity: impure +signature: "install_pnpm() -> void" +description: "Instala pnpm globalmente usando npm (npm install -g pnpm). Verifica que npm esté disponible. Idempotente: si pnpm ya está instalado, informa y termina sin hacer nada." +tags: [bash, install, pnpm, node] +uses_functions: [] +uses_types: [] +returns: [] +returns_optional: false +error_type: "error_go_core" +imports: [] +params: + - name: "(ninguno)" + desc: "no acepta argumentos" +output: "progreso a stdout con versión instalada; exit code 1 si npm no está disponible o falla la instalación" +tested: false +tests: [] +test_file_path: "" +file_path: "bash/functions/infra/install_pnpm.sh" +source_repo: "https://gitea-dgg044oo04woo4ggcsws4gk0.organic-machine.com/egutierrez/DevLauncher.git" +source_license: "MIT" +source_file: "scripts/linux/instaladores/instalar_pnpm.sh" +--- + +## Ejemplo + +```bash +source bash/functions/infra/install_pnpm.sh + +install_pnpm +``` + +## Notas + +Requiere Node.js/npm instalado previamente. Si la instalación global falla por permisos, usar `sudo npm install -g pnpm` manualmente. Idempotente: vuelve a ejecutarse sin error si pnpm ya existe. diff --git a/bash/functions/infra/install_pnpm.sh b/bash/functions/infra/install_pnpm.sh new file mode 100644 index 00000000..edea182d --- /dev/null +++ b/bash/functions/infra/install_pnpm.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +# install_pnpm +# ------------ +# Instala pnpm globalmente usando npm. +# Verifica que npm esté disponible antes de instalar. +# Idempotente: informa si pnpm ya está instalado. +# +# USO: +# source install_pnpm.sh +# install_pnpm + +install_pnpm() { + echo "Instalando pnpm..." + echo "" + + # Verificar si pnpm ya está instalado + if command -v pnpm &>/dev/null; then + local current_version + current_version="$(pnpm --version 2>/dev/null || echo "desconocida")" + echo "pnpm ya está instalado (versión: ${current_version})." + return 0 + fi + + # Verificar que npm esté disponible + if ! command -v npm &>/dev/null; then + echo "install_pnpm: npm no está instalado (requerido para instalar pnpm)" >&2 + echo " Instala Node.js primero con install_nodejs" >&2 + return 1 + fi + + local npm_version + npm_version="$(npm --version 2>/dev/null || echo "?")" + echo "npm detectado: ${npm_version}" + echo "" + + echo "Instalando pnpm globalmente (npm install -g pnpm)..." + if ! npm install -g pnpm; then + echo "install_pnpm: falló la instalación de pnpm" >&2 + echo " Intenta con sudo: sudo npm install -g pnpm" >&2 + return 1 + fi + + # Verificar instalación + if ! command -v pnpm &>/dev/null; then + echo "install_pnpm: pnpm no está disponible después de la instalación" >&2 + echo " Verifica que npm/bin esté en tu PATH" >&2 + return 1 + fi + + local installed_version + installed_version="$(pnpm --version)" + echo "" + echo "pnpm instalado correctamente: ${installed_version}" + echo "" + echo "Comandos útiles:" + echo " pnpm install - Instalar dependencias" + echo " pnpm add - Agregar paquete" + echo " pnpm run - Ejecutar script" +} + +# Ejecutar si se invoca directamente +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + install_pnpm "$@" +fi diff --git a/bash/functions/infra/install_python312.md b/bash/functions/infra/install_python312.md new file mode 100644 index 00000000..6ee4fcff --- /dev/null +++ b/bash/functions/infra/install_python312.md @@ -0,0 +1,40 @@ +--- +name: install_python312 +kind: function +lang: bash +domain: infra +version: "1.0.0" +purity: impure +signature: "install_python312() -> void" +description: "Instala Python 3.12 detectando la distribución Linux automáticamente. Ubuntu/Debian/Mint usan deadsnakes PPA; Fedora/RHEL usan dnf; Arch/Manjaro usan pacman. Instala también python3.12-venv, python3.12-dev y verifica pip. Idempotente." +tags: [bash, install, python, python312] +uses_functions: [] +uses_types: [] +returns: [] +returns_optional: false +error_type: "error_go_core" +imports: [] +params: + - name: "(ninguno)" + desc: "no acepta argumentos; detecta la distribución automáticamente" +output: "progreso a stdout; exit code 1 si la distribución no es soportada o falla la instalación" +tested: false +tests: [] +test_file_path: "" +file_path: "bash/functions/infra/install_python312.sh" +source_repo: "https://gitea-dgg044oo04woo4ggcsws4gk0.organic-machine.com/egutierrez/DevLauncher.git" +source_license: "MIT" +source_file: "scripts/linux/instaladores/instalar_python312.sh" +--- + +## Ejemplo + +```bash +source bash/functions/infra/install_python312.sh + +install_python312 +``` + +## Notas + +Requiere `sudo`. Para distribuciones no soportadas, se recomienda usar pyenv. Idempotente: si `python3.12` ya existe en PATH, informa y termina sin hacer nada. diff --git a/bash/functions/infra/install_python312.sh b/bash/functions/infra/install_python312.sh new file mode 100644 index 00000000..b2a9af29 --- /dev/null +++ b/bash/functions/infra/install_python312.sh @@ -0,0 +1,136 @@ +#!/usr/bin/env bash +# install_python312 +# ----------------- +# Instala Python 3.12 en Linux detectando la distribución automáticamente. +# - Ubuntu/Debian/Pop/Mint/Elementary: usa deadsnakes PPA +# - Fedora/RHEL/CentOS: usa dnf +# - Arch/Manjaro: usa pacman +# Instala también python3.12-venv, python3.12-dev y verifica pip. +# +# USO: +# source install_python312.sh +# install_python312 + +install_python312() { + echo "Instalando Python 3.12..." + echo "" + + # Detectar distribución + local distro="unknown" + if [[ -f /etc/os-release ]]; then + # shellcheck disable=SC1091 + distro="$(. /etc/os-release && echo "${ID:-unknown}")" + echo "Distribución detectada: ${distro}" + else + echo "install_python312: no se pudo detectar la distribución" >&2 + fi + echo "" + + # Verificar si Python 3.12 ya está instalado + if command -v python3.12 &>/dev/null; then + local current_version + current_version="$(python3.12 --version 2>&1)" + echo "Python 3.12 ya está instalado: ${current_version}" + return 0 + fi + + case "$distro" in + ubuntu|debian|pop|mint|elementary) + echo "Instalando Python 3.12 usando deadsnakes PPA..." + echo "" + + echo "Actualizando repositorios..." + if ! sudo apt update; then + echo "install_python312: falló la actualización de repositorios" >&2 + return 1 + fi + + echo "Verificando software-properties-common..." + if ! dpkg -l 2>/dev/null | grep -q software-properties-common; then + if ! sudo apt install -y software-properties-common; then + echo "install_python312: falló la instalación de software-properties-common" >&2 + return 1 + fi + fi + + echo "Añadiendo deadsnakes PPA..." + if ! sudo add-apt-repository -y ppa:deadsnakes/ppa; then + echo "install_python312: falló al añadir deadsnakes PPA" >&2 + return 1 + fi + + echo "Actualizando lista de paquetes..." + if ! sudo apt update; then + echo "install_python312: falló la actualización después de añadir PPA" >&2 + return 1 + fi + + echo "Instalando Python 3.12 y herramientas..." + if ! sudo apt install -y python3.12 python3.12-venv python3.12-dev python3-pip; then + echo "install_python312: falló la instalación de Python 3.12" >&2 + return 1 + fi + ;; + + fedora|rhel|centos) + echo "Instalando Python 3.12 usando dnf..." + if ! sudo dnf install -y python3.12 python3.12-devel; then + echo "install_python312: falló la instalación con dnf" >&2 + return 1 + fi + ;; + + arch|manjaro) + echo "Instalando Python 3.12 usando pacman..." + if ! sudo pacman -S --noconfirm python; then + echo "install_python312: falló la instalación con pacman" >&2 + return 1 + fi + ;; + + *) + echo "install_python312: distribución no soportada automáticamente: ${distro}" >&2 + echo " Opciones manuales:" >&2 + echo " - Compilar desde fuente: https://www.python.org/downloads/" >&2 + echo " - Usar pyenv: curl https://pyenv.run | bash" >&2 + return 1 + ;; + esac + + echo "" + + # Verificar instalación + if ! command -v python3.12 &>/dev/null; then + echo "install_python312: Python 3.12 no está disponible después de la instalación" >&2 + echo " Puede que necesites reiniciar la terminal" >&2 + return 1 + fi + + local installed_version + installed_version="$(python3.12 --version 2>&1)" + echo "Python 3.12 instalado correctamente: ${installed_version}" + echo "" + + # Verificar pip + echo "Verificando pip para Python 3.12..." + if ! python3.12 -m pip --version &>/dev/null; then + echo "pip no disponible, instalando..." + if ! python3.12 -m ensurepip --upgrade; then + echo " Instala pip manualmente: curl -sS https://bootstrap.pypa.io/get-pip.py | python3.12" + else + echo "pip instalado para Python 3.12" + fi + else + echo "pip disponible para Python 3.12" + fi + + echo "" + echo "Comandos útiles:" + echo " python3.12 -m venv .venv - Crear entorno virtual" + echo " source .venv/bin/activate - Activar entorno" +} + +# Ejecutar si se invoca directamente +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + install_python312 "$@" +fi diff --git a/bash/functions/infra/install_uv.md b/bash/functions/infra/install_uv.md new file mode 100644 index 00000000..49888252 --- /dev/null +++ b/bash/functions/infra/install_uv.md @@ -0,0 +1,45 @@ +--- +name: install_uv +kind: function +lang: bash +domain: infra +version: "1.0.0" +purity: impure +signature: "install_uv() -> void" +description: "Instala uv, el gestor de paquetes Python ultra-rápido escrito en Rust, usando el instalador oficial de astral.sh. Configura PATH en ~/.bashrc y ~/.zshrc. Idempotente: si uv ya está instalado, informa y termina." +tags: [bash, install, uv, python] +uses_functions: [] +uses_types: [] +returns: [] +returns_optional: false +error_type: "error_go_core" +imports: [] +params: + - name: "(ninguno)" + desc: "no acepta argumentos" +output: "progreso a stdout; exit code 1 si curl no está disponible o falla la instalación" +tested: false +tests: [] +test_file_path: "" +file_path: "bash/functions/infra/install_uv.sh" +source_repo: "https://gitea-dgg044oo04woo4ggcsws4gk0.organic-machine.com/egutierrez/DevLauncher.git" +source_license: "MIT" +source_file: "scripts/linux/instaladores/instalar_uv.sh" +--- + +## Ejemplo + +```bash +source bash/functions/infra/install_uv.sh + +install_uv + +# Uso posterior +uv venv +source .venv/bin/activate +uv pip install requests pandas +``` + +## Notas + +Instala en `$HOME/.cargo/bin`. Requiere `curl`. uv es compatible con pip pero 10-100x más rápido. Después de instalar en una sesión nueva, hay que recargar el shell. diff --git a/bash/functions/infra/install_uv.sh b/bash/functions/infra/install_uv.sh new file mode 100644 index 00000000..e100db38 --- /dev/null +++ b/bash/functions/infra/install_uv.sh @@ -0,0 +1,88 @@ +#!/usr/bin/env bash +# install_uv +# ---------- +# Instala uv — gestor de paquetes Python ultra-rápido escrito en Rust. +# Usa el instalador oficial de astral.sh. Configura PATH en ~/.bashrc y ~/.zshrc. +# +# USO: +# source install_uv.sh +# install_uv + +install_uv() { + echo "Instalando uv (gestor de paquetes Python)..." + echo "" + + # Verificar si uv ya está instalado + if command -v uv &>/dev/null; then + local current_version + current_version="$(uv --version 2>/dev/null || echo "desconocida")" + echo "uv ya está instalado (versión: ${current_version})." + return 0 + fi + + # Verificar curl + if ! command -v curl &>/dev/null; then + echo "install_uv: curl no está instalado (requerido)" >&2 + echo " Instálalo con: sudo apt install curl" >&2 + return 1 + fi + + echo "Descargando e instalando uv (instalador oficial astral.sh)..." + if ! curl -LsSf https://astral.sh/uv/install.sh | sh; then + echo "install_uv: falló la instalación de uv" >&2 + echo " Verifica tu conexión a internet y permisos" >&2 + return 1 + fi + + echo "" + + # Configurar PATH en ~/.bashrc + if ! grep -q ".cargo/bin" "$HOME/.bashrc" 2>/dev/null; then + { + echo "" + echo "# uv and cargo binaries" + echo 'export PATH="$HOME/.cargo/bin:$PATH"' + } >> "$HOME/.bashrc" + echo "PATH añadido a ~/.bashrc" + else + echo "PATH ya configurado en ~/.bashrc" + fi + + # Configurar PATH en ~/.zshrc si existe + if [[ -f "$HOME/.zshrc" ]]; then + if ! grep -q ".cargo/bin" "$HOME/.zshrc" 2>/dev/null; then + { + echo "" + echo "# uv and cargo binaries" + echo 'export PATH="$HOME/.cargo/bin:$PATH"' + } >> "$HOME/.zshrc" + echo "PATH añadido a ~/.zshrc" + fi + fi + + # Cargar PATH en la sesión actual + export PATH="$HOME/.cargo/bin:$PATH" + + echo "" + + # Verificar instalación + if ! command -v uv &>/dev/null; then + echo "uv instalado pero no está en el PATH actual." + echo " Ejecuta: source ~/.bashrc (o abre una nueva terminal)" + else + local installed_version + installed_version="$(uv --version)" + echo "uv instalado correctamente: ${installed_version}" + fi + + echo "" + echo "Comandos útiles de uv:" + echo " uv venv - Crear entorno virtual" + echo " uv pip install - Instalar paquete" + echo " uv pip sync requirements.txt - Sincronizar dependencias" +} + +# Ejecutar si se invoca directamente +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + install_uv "$@" +fi diff --git a/bash/functions/infra/install_volta.md b/bash/functions/infra/install_volta.md new file mode 100644 index 00000000..8fd5a610 --- /dev/null +++ b/bash/functions/infra/install_volta.md @@ -0,0 +1,45 @@ +--- +name: install_volta +kind: function +lang: bash +domain: infra +version: "1.0.0" +purity: impure +signature: "install_volta() -> void" +description: "Instala Volta, el gestor de versiones de Node.js, usando el instalador oficial de get.volta.sh. Configura VOLTA_HOME y PATH en ~/.bashrc y ~/.zshrc. Idempotente: si Volta ya está instalado, informa y termina." +tags: [bash, install, volta, node] +uses_functions: [] +uses_types: [] +returns: [] +returns_optional: false +error_type: "error_go_core" +imports: [] +params: + - name: "(ninguno)" + desc: "no acepta argumentos" +output: "progreso a stdout; exit code 1 si curl no está disponible o falla la instalación" +tested: false +tests: [] +test_file_path: "" +file_path: "bash/functions/infra/install_volta.sh" +source_repo: "https://gitea-dgg044oo04woo4ggcsws4gk0.organic-machine.com/egutierrez/DevLauncher.git" +source_license: "MIT" +source_file: "scripts/linux/instaladores/instalar_volta.sh" +--- + +## Ejemplo + +```bash +source bash/functions/infra/install_volta.sh + +install_volta + +# Uso posterior (tras recargar shell) +volta install node +volta install pnpm +volta list +``` + +## Notas + +Volta se instala en `$HOME/.volta`. Requiere `curl`. A diferencia de nvm, Volta gestiona versiones de Node.js a nivel de proyecto via `package.json`. Después de instalar, recargar el shell con `source ~/.bashrc`. diff --git a/bash/functions/infra/install_volta.sh b/bash/functions/infra/install_volta.sh new file mode 100644 index 00000000..b00e3509 --- /dev/null +++ b/bash/functions/infra/install_volta.sh @@ -0,0 +1,100 @@ +#!/usr/bin/env bash +# install_volta +# ------------- +# Instala Volta — gestor de versiones de Node.js rápido y confiable. +# Usa el instalador oficial de get.volta.sh. Configura VOLTA_HOME y PATH +# en ~/.bashrc y ~/.zshrc. +# +# USO: +# source install_volta.sh +# install_volta + +install_volta() { + echo "Instalando Volta (gestor de versiones Node.js)..." + echo "" + + # Verificar si Volta ya está instalado + if command -v volta &>/dev/null; then + local current_version + current_version="$(volta --version 2>/dev/null || echo "desconocida")" + echo "Volta ya está instalado (versión: ${current_version})." + return 0 + fi + + # Verificar curl + if ! command -v curl &>/dev/null; then + echo "install_volta: curl no está instalado (requerido)" >&2 + echo " Instálalo con: sudo apt install curl" >&2 + return 1 + fi + + echo "Descargando e instalando Volta (instalador oficial)..." + if ! curl https://get.volta.sh | bash; then + echo "install_volta: falló la instalación de Volta" >&2 + echo " Verifica tu conexión a internet" >&2 + return 1 + fi + + echo "" + + # Configurar variables de entorno + local volta_home="$HOME/.volta" + export VOLTA_HOME="$volta_home" + export PATH="$volta_home/bin:$PATH" + + # Configurar en ~/.bashrc + if ! grep -q "VOLTA_HOME" "$HOME/.bashrc" 2>/dev/null; then + { + echo "" + echo "# Volta configuration" + echo 'export VOLTA_HOME="$HOME/.volta"' + echo 'export PATH="$VOLTA_HOME/bin:$PATH"' + } >> "$HOME/.bashrc" + echo "Variables añadidas a ~/.bashrc" + else + echo "Variables ya configuradas en ~/.bashrc" + fi + + # Configurar en ~/.zshrc si existe + if [[ -f "$HOME/.zshrc" ]]; then + if ! grep -q "VOLTA_HOME" "$HOME/.zshrc" 2>/dev/null; then + { + echo "" + echo "# Volta configuration" + echo 'export VOLTA_HOME="$HOME/.volta"' + echo 'export PATH="$VOLTA_HOME/bin:$PATH"' + } >> "$HOME/.zshrc" + echo "Variables añadidas a ~/.zshrc" + fi + fi + + echo "" + + # Verificar instalación + if command -v volta &>/dev/null; then + local installed_version + installed_version="$(volta --version)" + echo "Volta instalado correctamente: ${installed_version}" + elif [[ -f "$HOME/.volta/bin/volta" ]]; then + echo "Volta instalado en ${HOME}/.volta/bin pero no está en PATH actual." + echo " Ejecuta: source ~/.bashrc (o abre una nueva terminal)" + else + echo "install_volta: Volta no está disponible después de la instalación" >&2 + return 1 + fi + + echo "" + echo "Próximos pasos:" + echo " 1. source ~/.bashrc - Recargar shell" + echo " 2. volta install node - Instalar Node.js" + echo " 3. volta install pnpm - Instalar pnpm" + echo "" + echo "Comandos útiles:" + echo " volta install node@20 - Instalar Node.js v20" + echo " volta list - Ver herramientas instaladas" +} + +# Ejecutar si se invoca directamente +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + install_volta "$@" +fi diff --git a/bash/functions/infra/install_wails.md b/bash/functions/infra/install_wails.md new file mode 100644 index 00000000..230eab5c --- /dev/null +++ b/bash/functions/infra/install_wails.md @@ -0,0 +1,46 @@ +--- +name: install_wails +kind: function +lang: bash +domain: infra +version: "1.0.0" +purity: impure +signature: "install_wails() -> void" +description: "Instala Wails v2 (framework de apps de escritorio Go). Detecta la distribución Linux e instala las dependencias de sistema (GTK3, WebKit2GTK, build tools) y luego el CLI via 'go install ...@latest'. Requiere Go instalado previamente." +tags: [bash, install, wails, desktop] +uses_functions: [] +uses_types: [] +returns: [] +returns_optional: false +error_type: "error_go_core" +imports: [] +params: + - name: "(ninguno)" + desc: "no acepta argumentos; detecta la distribución automáticamente" +output: "progreso a stdout; exit code 1 si Go no está disponible, no se detecta la distribución, o falla la instalación" +tested: false +tests: [] +test_file_path: "" +file_path: "bash/functions/infra/install_wails.sh" +source_repo: "https://gitea-dgg044oo04woo4ggcsws4gk0.organic-machine.com/egutierrez/DevLauncher.git" +source_license: "MIT" +source_file: "scripts/linux/instaladores/instalar_wails.sh" +--- + +## Ejemplo + +```bash +source bash/functions/infra/install_wails.sh + +install_wails + +# Verificar +wails doctor + +# Crear proyecto +wails init -n my-desktop-app -t react +``` + +## Notas + +Requiere Go y sudo. Para distribuciones no listadas (opensuse, etc.) instala las dependencias manualmente y luego procede con el CLI. Templates disponibles: vanilla, vue, react, svelte, lit, angular. diff --git a/bash/functions/infra/install_wails.sh b/bash/functions/infra/install_wails.sh new file mode 100644 index 00000000..5bdd0770 --- /dev/null +++ b/bash/functions/infra/install_wails.sh @@ -0,0 +1,123 @@ +#!/usr/bin/env bash +# install_wails +# ------------- +# Instala Wails v2 — framework para aplicaciones de escritorio en Go. +# Detecta la distribución Linux e instala las dependencias de sistema necesarias +# (GTK3, WebKit2GTK, build tools) y luego instala el CLI de Wails via go install. +# +# USO: +# source install_wails.sh +# install_wails + +install_wails() { + echo "Instalando Wails..." + echo "" + + # Verificar Go + if ! command -v go &>/dev/null; then + echo "install_wails: Go no está instalado (requerido)" >&2 + echo " Instálalo primero con install_go" >&2 + return 1 + fi + + local go_version + go_version="$(go version)" + echo "Go detectado: ${go_version}" + echo "" + + # Detectar distribución + local distro="unknown" + if [[ -f /etc/os-release ]]; then + # shellcheck disable=SC1091 + distro="$(. /etc/os-release && echo "${ID:-unknown}")" + else + echo "install_wails: no se pudo detectar la distribución de Linux" >&2 + return 1 + fi + + echo "Instalando dependencias del sistema para ${distro}..." + case "$distro" in + ubuntu|debian|linuxmint|pop) + sudo apt update + if ! sudo apt install -y libgtk-3-dev libwebkit2gtk-4.0-dev build-essential pkg-config; then + echo "install_wails: falló la instalación de dependencias de sistema" >&2 + return 1 + fi + ;; + fedora|rhel|centos) + if ! sudo dnf install -y gtk3-devel webkit2gtk3-devel gcc-c++ pkgconfig; then + echo "install_wails: falló la instalación de dependencias de sistema" >&2 + return 1 + fi + ;; + arch|manjaro) + if ! sudo pacman -Sy --noconfirm gtk3 webkit2gtk base-devel; then + echo "install_wails: falló la instalación de dependencias de sistema" >&2 + return 1 + fi + ;; + opensuse*) + if ! sudo zypper install -y gtk3-devel webkit2gtk3-devel gcc-c++ pkg-config; then + echo "install_wails: falló la instalación de dependencias de sistema" >&2 + return 1 + fi + ;; + *) + echo "Distribución no reconocida: ${distro}" + echo "Instala manualmente: gtk3, webkit2gtk, build-essential, pkg-config" + echo "Continuando con la instalación de Wails CLI..." + ;; + esac + + echo "" + echo "Instalando Wails CLI (go install github.com/wailsapp/wails/v2/cmd/wails@latest)..." + if ! go install github.com/wailsapp/wails/v2/cmd/wails@latest; then + echo "install_wails: falló la instalación del CLI de Wails" >&2 + return 1 + fi + + # Asegurar que $GOPATH/bin esté en PATH + if [[ ":$PATH:" != *":$HOME/go/bin:"* ]]; then + local shell_config="" + if [[ -f "$HOME/.bashrc" ]]; then + shell_config="$HOME/.bashrc" + elif [[ -f "$HOME/.zshrc" ]]; then + shell_config="$HOME/.zshrc" + fi + + if [[ -n "$shell_config" ]]; then + if ! grep -q 'export PATH=\$PATH:\$HOME/go/bin' "$shell_config" 2>/dev/null; then + { + echo "" + echo "# Go binaries" + echo 'export PATH=$PATH:$HOME/go/bin' + } >> "$shell_config" + echo "PATH de Go añadido a ${shell_config}" + fi + fi + export PATH="$PATH:$HOME/go/bin" + fi + + echo "" + + # Verificar instalación + if command -v wails &>/dev/null; then + local wails_version + wails_version="$(wails version 2>/dev/null || echo "instalado")" + echo "Wails instalado correctamente: ${wails_version}" + echo "" + echo "Comandos básicos de Wails:" + echo " wails init -n myapp -t vanilla - Crear proyecto" + echo " wails dev - Modo desarrollo" + echo " wails build - Build producción" + echo " wails doctor - Verificar instalación" + else + echo "Wails instalado pero no está en PATH." + echo " Reinicia tu terminal o ejecuta: source ~/.bashrc" + fi +} + +# Ejecutar si se invoca directamente +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + install_wails "$@" +fi diff --git a/bash/functions/infra/list_listening_ports.md b/bash/functions/infra/list_listening_ports.md new file mode 100644 index 00000000..5c5affc5 --- /dev/null +++ b/bash/functions/infra/list_listening_ports.md @@ -0,0 +1,50 @@ +--- +name: list_listening_ports +kind: function +lang: bash +domain: infra +version: "1.0.0" +purity: impure +signature: "list_listening_ports([mode: string]) -> void" +description: "Lista puertos activos del sistema usando ss (preferido) o netstat como fallback. Modos: all (LISTEN), tcp, udp, established (conexiones activas), stats (resumen + interfaces). Imprime salida tabulada a stdout." +tags: [bash, ports, network, listening, monitoring] +uses_functions: [] +uses_types: [] +returns: [] +returns_optional: false +error_type: "error_go_core" +imports: [] +params: + - name: mode + desc: "qué listar: all|tcp|udp|established|stats (default: all)" +output: "tabla de puertos/conexiones a stdout; exit code 1 si no hay ss ni netstat, o si el modo es desconocido" +tested: false +tests: [] +test_file_path: "" +file_path: "bash/functions/infra/list_listening_ports.sh" +source_repo: "https://gitea-dgg044oo04woo4ggcsws4gk0.organic-machine.com/egutierrez/DevLauncher.git" +source_license: "MIT" +source_file: "scripts/linux/gestion_linux/puertos_activos.sh" +--- + +## Ejemplo + +```bash +source bash/functions/infra/list_listening_ports.sh + +# Todos los puertos en escucha +list_listening_ports + +# Solo TCP +list_listening_ports tcp + +# Conexiones establecidas +list_listening_ports established + +# Estadísticas e interfaces +list_listening_ports stats +``` + +## Notas + +Prefiere `ss` (iproute2) sobre `netstat` (net-tools). El modo `established` limita a 30 filas para no saturar el terminal. No incluye monitor en tiempo real (solo snapshot). diff --git a/bash/functions/infra/list_listening_ports.sh b/bash/functions/infra/list_listening_ports.sh new file mode 100644 index 00000000..bcc963b3 --- /dev/null +++ b/bash/functions/infra/list_listening_ports.sh @@ -0,0 +1,108 @@ +#!/usr/bin/env bash +# list_listening_ports +# -------------------- +# Lista puertos activos en el sistema usando ss o netstat. +# Soporta filtrado por protocolo y estadísticas de red. +# +# USO: +# source list_listening_ports.sh +# list_listening_ports [mode] +# +# ARGUMENTOS: +# mode Modo de listado: all|tcp|udp|established|stats (default: all) + +list_listening_ports() { + local mode="${1:-all}" + + _has_ss() { + command -v ss &>/dev/null + } + + _has_netstat() { + command -v netstat &>/dev/null + } + + _require_net_tool() { + if ! _has_ss && ! _has_netstat; then + echo "list_listening_ports: no se encontró ss ni netstat en el sistema" >&2 + return 1 + fi + } + + _llp_all() { + echo "=== Puertos en escucha (LISTEN) ===" + if _has_ss; then + ss -tulnp 2>/dev/null | awk 'NR==1 || /LISTEN/ {print}' | column -t + elif _has_netstat; then + netstat -tulnp 2>/dev/null | awk 'NR<=2 || /LISTEN/ {print}' | column -t + fi + echo "" + } + + _llp_tcp() { + echo "=== Puertos TCP ===" + if _has_ss; then + ss -tnlp 2>/dev/null | column -t + elif _has_netstat; then + netstat -tnlp 2>/dev/null | column -t + fi + echo "" + } + + _llp_udp() { + echo "=== Puertos UDP ===" + if _has_ss; then + ss -unlp 2>/dev/null | column -t + elif _has_netstat; then + netstat -unlp 2>/dev/null | column -t + fi + echo "" + } + + _llp_established() { + echo "=== Conexiones TCP establecidas ===" + local count=0 + if _has_ss; then + ss -tnp 2>/dev/null | awk 'NR==1 || /ESTAB/ {print}' | column -t | head -30 + count="$(ss -tnp 2>/dev/null | grep -c ESTAB || echo 0)" + elif _has_netstat; then + netstat -tnp 2>/dev/null | awk 'NR<=2 || /ESTABLISHED/ {print}' | column -t | head -30 + count="$(netstat -tnp 2>/dev/null | grep -c ESTABLISHED || echo 0)" + fi + echo "" + echo "Total de conexiones establecidas: ${count}" + echo "" + } + + _llp_stats() { + echo "=== Estadísticas de red ===" + if _has_ss; then + ss -s 2>/dev/null + echo "" + echo "=== Interfaces de red ===" + ip -br addr 2>/dev/null || ifconfig -a 2>/dev/null || echo "No se pudo obtener info de interfaces" + elif _has_netstat; then + netstat -s 2>/dev/null | head -50 + fi + echo "" + } + + _require_net_tool || return 1 + + case "$mode" in + all) _llp_all ;; + tcp) _llp_tcp ;; + udp) _llp_udp ;; + established) _llp_established ;; + stats) _llp_stats ;; + *) + echo "list_listening_ports: modo desconocido '${mode}'. Usa: all|tcp|udp|established|stats" >&2 + return 1 + ;; + esac +} + +# Ejecutar si se invoca directamente +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + list_listening_ports "$@" +fi