Skip to content

Commit c21353d

Browse files
committed
feat(cpython): hacer scripts idempotentes y sin fallas silenciosas
Mejoras principales: 1. **build_cpython.sh** - Idempotencia y robustez: - Agregar flag --force para sobrescribir artifacts sin prompt interactivo - Limpiar instalaciones previas en /opt/python-X.Y.Z antes de instalar - Validar downloads completos (no vacíos) antes de extraer - Detectar tarballs corruptos y eliminarlos automáticamente - Manejo explícito de errores en operaciones sudo - Verificar que artifacts generados son legibles - Reutilizar código fuente existente en /tmp (con opción de re-download con --force) 2. **bootstrap.sh** - Manejo de errores mejorado: - Validar éxito de apt-get update y upgrade (no silent failures) - Usar DEBIAN_FRONTEND=noninteractive para evitar prompts - Validar que directorios creados son escribibles - Manejo de errores en verificación de paquetes instalados - Todos los comandos críticos verifican códigos de salida 3. **cleanup.sh** - Nuevo script para idempotencia: - Limpiar builds temporales (/tmp/cpython-build) - Limpiar instalaciones (/opt/python-*) - Limpiar artifacts generados (.tgz, .sha256) - Mostrar estado actual del entorno - Soporte para limpieza selectiva o completa 4. **README.md** - Documentación actualizada: - Documentar flag --force para build_cpython.sh - Documentar script cleanup.sh con ejemplos - Explicar características de idempotencia - Explicar manejo de errores sin fallas silenciosas Beneficios: - Scripts pueden ejecutarse múltiples veces sin efectos secundarios - Todos los errores se reportan explícitamente (exit code != 0) - Ambiente reproducible para troubleshooting - No requiere intervención manual (fully automated) - Apropiado para CI/CD pipelines Testing recomendado: - Ejecutar build_cpython.sh dos veces (debe fallar en segundo intento sin --force) - Ejecutar con --force (debe sobrescribir exitosamente) - Interrumpir build a mitad (ctrl-c) y re-ejecutar (debe reanudar/limpiar) - Ejecutar cleanup.sh para verificar limpieza completa Relacionado: requisitos de usuario sobre scripts sin fallas silenciosas e idempotentes
1 parent b9cddc3 commit c21353d

4 files changed

Lines changed: 344 additions & 25 deletions

File tree

infrastructure/cpython/README.md

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,20 +110,27 @@ infrastructure/cpython/artifacts/
110110

111111
**Sintaxis**:
112112
```bash
113-
./scripts/build_cpython.sh <version> [build-number]
113+
./scripts/build_cpython.sh <version> [build-number] [--force]
114114
```
115115

116116
**Argumentos**:
117117
- `version`: Versión de Python (formato X.Y.Z, ejemplo: 3.12.6)
118118
- `build-number`: Número de build (opcional, default: 1)
119+
- `--force`: Sobrescribir artefacto existente sin preguntar
119120

120121
**Ejemplos**:
121122
```bash
122123
./scripts/build_cpython.sh 3.12.6 # Build 1 de Python 3.12.6
123124
./scripts/build_cpython.sh 3.12.6 2 # Build 2 (rebuild)
124125
./scripts/build_cpython.sh 3.11.9 # Python 3.11.9
126+
./scripts/build_cpython.sh 3.12.6 1 --force # Sobrescribir build existente
125127
```
126128

129+
**Características**:
130+
- **Idempotente**: Puede ejecutarse múltiples veces, detecta instalaciones previas
131+
- **Sin fallas silenciosas**: Todos los errores se reportan con códigos de salida
132+
- **Validación robusta**: Verifica descargas, extracciones, y compilaciones
133+
127134
**Flags de compilación**:
128135
- `--enable-optimizations`: Profile-Guided Optimization (PGO)
129136
- `--with-lto`: Link-Time Optimization
@@ -161,6 +168,34 @@ infrastructure/cpython/artifacts/
161168
- 0: Validación exitosa
162169
- 1: Validación falló
163170

171+
#### cleanup.sh
172+
173+
**Propósito**: Limpiar entorno de compilación para rebuilds limpios (idempotencia)
174+
175+
**Sintaxis**:
176+
```bash
177+
./scripts/cleanup.sh [--all|--build|--artifacts|--install]
178+
```
179+
180+
**Opciones**:
181+
- Sin argumentos: Muestra estado actual del entorno
182+
- `--all`: Limpia todo (builds, instalaciones, artifacts)
183+
- `--build`: Limpia solo directorios de build temporales (`/tmp/cpython-build`)
184+
- `--install`: Limpia instalaciones en `/opt/python-*`
185+
- `--artifacts`: Limpia artifacts generados (`.tgz` y `.sha256`)
186+
187+
**Ejemplos**:
188+
```bash
189+
./scripts/cleanup.sh # Ver estado
190+
./scripts/cleanup.sh --build # Limpiar builds temporales
191+
./scripts/cleanup.sh --all # Limpieza completa
192+
```
193+
194+
**Casos de uso**:
195+
- Antes de rebuild para asegurar ambiente limpio
196+
- Liberar espacio en disco
197+
- Troubleshooting de compilaciones fallidas
198+
164199
---
165200

166201
## Gestión de VM

infrastructure/cpython/bootstrap.sh

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,16 @@ update_system() {
2323
log_step 1 3 "Actualizando sistema"
2424

2525
log_info "Actualizando lista de paquetes..."
26-
apt-get update -qq
26+
if ! apt-get update -qq; then
27+
log_error "Fallo al actualizar lista de paquetes"
28+
return 1
29+
fi
2730

2831
log_info "Actualizando paquetes del sistema..."
29-
apt-get upgrade -y -qq
32+
if ! apt-get upgrade -y -qq; then
33+
log_error "Fallo al actualizar paquetes del sistema"
34+
return 1
35+
fi
3036

3137
log_success "Sistema actualizado"
3238
}
@@ -37,7 +43,8 @@ install_build_dependencies() {
3743
log_info "Instalando toolchain de compilacion..."
3844

3945
# Dependencias segun: https://devguide.python.org/getting-started/setup-building/
40-
apt-get install -y -q \
46+
# Usar DEBIAN_FRONTEND=noninteractive para evitar prompts interactivos
47+
if ! DEBIAN_FRONTEND=noninteractive apt-get install -y -q \
4148
build-essential \
4249
gdb \
4350
lcov \
@@ -58,20 +65,27 @@ install_build_dependencies() {
5865
zlib1g-dev \
5966
wget \
6067
curl \
61-
ca-certificates
68+
ca-certificates; then
69+
log_error "Fallo al instalar dependencias de compilacion"
70+
log_error "Verifique conectividad de red y repositorios APT"
71+
return 1
72+
fi
6273

6374
log_success "Dependencias de compilacion instaladas"
6475

6576
log_info "Versiones de librerias criticas:"
6677
dpkg -l | grep -E "libssl-dev|libsqlite3-dev|liblzma-dev|libbz2-dev|libffi-dev" | \
67-
awk '{print " " $2 ": " $3}'
78+
awk '{print " " $2 ": " $3}' || log_warn "No se pudieron listar versiones de librerias"
6879
}
6980

7081
install_additional_tools() {
7182
log_step 3 3 "Instalando herramientas adicionales"
7283

7384
log_info "Instalando git, vim, htop..."
74-
apt-get install -y -qq git vim htop
85+
if ! DEBIAN_FRONTEND=noninteractive apt-get install -y -qq git vim htop; then
86+
log_error "Fallo al instalar herramientas adicionales"
87+
return 1
88+
fi
7589

7690
log_success "Herramientas adicionales instaladas"
7791
}
@@ -114,10 +128,28 @@ verify_installation() {
114128
setup_directories() {
115129
log_info "Configurando directorios..."
116130

117-
mkdir -p "$PROJECT_ROOT/logs"
118-
mkdir -p "$PROJECT_ROOT/artifacts/cpython"
131+
if ! mkdir -p "$PROJECT_ROOT/logs"; then
132+
log_error "Fallo al crear directorio de logs"
133+
return 1
134+
fi
135+
136+
if ! mkdir -p "$PROJECT_ROOT/artifacts/cpython"; then
137+
log_error "Fallo al crear directorio de artifacts"
138+
return 1
139+
fi
140+
141+
# Verificar que directorios son escribibles
142+
if [ ! -w "$PROJECT_ROOT/logs" ]; then
143+
log_error "Directorio de logs no es escribible"
144+
return 1
145+
fi
146+
147+
if [ ! -w "$PROJECT_ROOT/artifacts/cpython" ]; then
148+
log_error "Directorio de artifacts no es escribible"
149+
return 1
150+
fi
119151

120-
log_success "Directorios configurados"
152+
log_success "Directorios configurados y verificados"
121153
}
122154

123155
display_summary() {

infrastructure/cpython/scripts/build_cpython.sh

Lines changed: 72 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,23 @@ fi
3232

3333
# Validar argumentos
3434
if [ $# -lt 1 ]; then
35-
log_error "Uso: $0 <version> [build-number]"
35+
log_error "Uso: $0 <version> [build-number] [--force]"
3636
log_error "Ejemplo: $0 3.12.6 1"
37+
log_error " --force: Sobrescribir artefacto existente sin preguntar"
3738
exit 1
3839
fi
3940

4041
PYTHON_VERSION="$1"
4142
BUILD_NUMBER="${2:-${DEFAULT_BUILD_NUMBER:-1}}"
4243
DISTRO="${DISTRO:-ubuntu20.04}"
44+
FORCE_BUILD=0
45+
46+
# Parsear argumentos opcionales
47+
for arg in "$@"; do
48+
if [ "$arg" = "--force" ]; then
49+
FORCE_BUILD=1
50+
fi
51+
done
4352

4453
# Validar formato de version usando utilidad
4554
if ! validate_python_version "$PYTHON_VERSION"; then
@@ -63,16 +72,17 @@ log_info "Distro: $DISTRO"
6372
log_info "Artefacto: $ARTIFACT_NAME"
6473
echo ""
6574

66-
# Verificar que no existe artefacto previo
75+
# Verificar que no existe artefacto previo (idempotencia)
6776
if [ -f "$ARTIFACT_PATH" ]; then
68-
log_warn "Artefacto ya existe: $ARTIFACT_PATH"
69-
read -p "¿Sobrescribir? (y/N): " -n 1 -r
70-
echo
71-
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
72-
log_info "Abortando compilacion"
73-
exit 0
77+
if [ $FORCE_BUILD -eq 1 ]; then
78+
log_warn "Artefacto ya existe: $ARTIFACT_PATH (sobrescribiendo con --force)"
79+
rm -f "$ARTIFACT_PATH" "$ARTIFACT_PATH.sha256"
80+
else
81+
log_error "Artefacto ya existe: $ARTIFACT_PATH"
82+
log_error "Use --force para sobrescribir o elimine el artefacto manualmente"
83+
log_error "O incremente el build-number: $0 $PYTHON_VERSION $((BUILD_NUMBER + 1))"
84+
exit 1
7485
fi
75-
rm -f "$ARTIFACT_PATH" "$ARTIFACT_PATH.sha256"
7686
fi
7787

7888
# Crear directorios
@@ -89,23 +99,46 @@ log_info "Descargando codigo fuente de Python $PYTHON_VERSION..."
8999
cd "$BUILD_DIR"
90100

91101
PYTHON_URL="${PYTHON_DOWNLOAD_BASE:-https://www.python.org/ftp/python}/$PYTHON_VERSION/Python-$PYTHON_VERSION.tgz"
102+
TARBALL="Python-$PYTHON_VERSION.tgz"
92103

93104
if [ -d "$SOURCE_DIR" ]; then
94-
log_warn "Directorio de codigo fuente ya existe, usando existente"
95-
else
105+
log_warn "Directorio de codigo fuente ya existe"
106+
if [ $FORCE_BUILD -eq 1 ]; then
107+
log_warn "Eliminando directorio existente con --force"
108+
rm -rf "$SOURCE_DIR" "$TARBALL"
109+
else
110+
log_info "Usando codigo fuente existente (use --force para re-descargar)"
111+
fi
112+
fi
113+
114+
if [ ! -d "$SOURCE_DIR" ]; then
96115
log_info "Descargando desde: $PYTHON_URL"
97116
if ! wget -q --show-progress "$PYTHON_URL"; then
98117
log_error "Fallo al descargar codigo fuente"
118+
log_error "Verifique que la version $PYTHON_VERSION existe en python.org"
119+
exit 1
120+
fi
121+
122+
# Verificar que el tarball se descargo correctamente
123+
if [ ! -f "$TARBALL" ] || [ ! -s "$TARBALL" ]; then
124+
log_error "Tarball descargado esta vacio o no existe"
99125
exit 1
100126
fi
101127

102128
log_info "Extrayendo codigo fuente..."
103-
tar xzf "Python-$PYTHON_VERSION.tgz"
129+
if ! tar xzf "$TARBALL"; then
130+
log_error "Fallo al extraer tarball (posible archivo corrupto)"
131+
rm -f "$TARBALL"
132+
exit 1
133+
fi
104134

105135
if [ ! -d "$SOURCE_DIR" ]; then
106136
log_error "Directorio de codigo fuente no encontrado despues de extraccion"
137+
log_error "Estructura inesperada en tarball"
107138
exit 1
108139
fi
140+
141+
log_success "Codigo fuente extraido correctamente"
109142
fi
110143

111144
cd "$SOURCE_DIR"
@@ -149,6 +182,16 @@ fi
149182

150183
log_success "Compilacion completada"
151184

185+
# Limpiar instalacion anterior si existe (idempotencia)
186+
if [ -d "$INSTALL_PREFIX" ]; then
187+
log_warn "Instalacion previa encontrada en $INSTALL_PREFIX, eliminando..."
188+
if ! sudo rm -rf "$INSTALL_PREFIX"; then
189+
log_error "Fallo al eliminar instalacion previa (permisos sudo requeridos)"
190+
exit 1
191+
fi
192+
log_success "Instalacion previa eliminada"
193+
fi
194+
152195
# Instalar
153196
log_info "Instalando en $INSTALL_PREFIX..."
154197
if ! sudo make install 2>&1 | tee make-install.log; then
@@ -225,7 +268,10 @@ log_success "Build info guardado en $INSTALL_PREFIX/.build-info"
225268
# Incluir LICENSE de Python (PSF)
226269
log_info "Copiando LICENSE de Python..."
227270
if [ -f "LICENSE" ]; then
228-
sudo cp LICENSE "$INSTALL_PREFIX/LICENSE"
271+
if ! sudo cp LICENSE "$INSTALL_PREFIX/LICENSE"; then
272+
log_error "Fallo al copiar LICENSE (permisos sudo requeridos)"
273+
exit 1
274+
fi
229275
log_success "LICENSE copiado"
230276
else
231277
log_warn "LICENSE no encontrado en codigo fuente"
@@ -240,8 +286,19 @@ if ! sudo tar czf "$ARTIFACT_PATH" "python-$PYTHON_VERSION"; then
240286
exit 1
241287
fi
242288

243-
# Ajustar permisos
244-
sudo chown vagrant:vagrant "$ARTIFACT_PATH" 2>/dev/null || chown "$(whoami):$(whoami)" "$ARTIFACT_PATH"
289+
# Ajustar permisos del artefacto
290+
if ! sudo chown vagrant:vagrant "$ARTIFACT_PATH" 2>/dev/null; then
291+
# Fallback si no existe usuario vagrant
292+
CURRENT_USER=$(whoami)
293+
if ! chown "$CURRENT_USER:$CURRENT_USER" "$ARTIFACT_PATH" 2>/dev/null; then
294+
log_warn "No se pudieron ajustar permisos del artefacto (puede requerir sudo)"
295+
fi
296+
fi
297+
298+
if [ ! -r "$ARTIFACT_PATH" ]; then
299+
log_error "Artefacto creado pero no es legible"
300+
exit 1
301+
fi
245302

246303
ARTIFACT_SIZE=$(du -h "$ARTIFACT_PATH" | cut -f1)
247304
log_success "Artefacto creado: $ARTIFACT_PATH ($ARTIFACT_SIZE)"

0 commit comments

Comments
 (0)