Módulos y paquetes
Vaca organiza los programas en módulos, igual que Go:
- un módulo declara su nombre, su archivo de entrada y sus dependencias en
vaca.mod; vacasin argumentos ejecuta la entrada y llama aprincipal();- las dependencias se declaran con una ruta de repositorio y una versión semver;
vaca instalarcopia el código a.vaca/paquetes/y fija versión, commit y hash envaca.lock;vaca construirgenera un único archivo de producción verificado.
No hay un registro central: cada ruta apunta a un repositorio git.
Crear un módulo
mkdir mi-api
cd mi-api
vaca init ejemplo.com/mi-api
Se crean dos archivos:
vaca.mod # nombre, versión, entrada y dependencias
iniciar.vaca # punto de entrada
vaca.mod:
# Módulo de Vaca
modulo ejemplo.com/mi-api
version 0.1.0
inicio iniciar.vaca
iniciar.vaca:
# Punto de entrada del módulo ejemplo.com/mi-api.
fn principal() {
imprimir("Hola desde ejemplo.com/mi-api")
}
Al ejecutar vaca en el directorio del módulo (o en cualquier subdirectorio),
Vaca busca la raíz, ejecuta iniciar.vaca y llama a principal() si existe.
vaca # módulo actual
vaca . # equivalente
vaca run # equivalente
vaca archivo.vaca ejecuta un archivo suelto y, si define principal(),
también la llama. Es útil para scripts, pruebas y para ejecutar la entrada del
módulo directamente.
Para cambiar la entrada:
inicio cmd/api/servidor.vaca
Importar subpaquetes del propio módulo
# util.vaca
fn despedida(nombre) {
retornar "Adiós, " + nombre
}
# iniciar.vaca
importar "ejemplo.com/mi-api/util"
fn principal() {
imprimir(util.despedida("Vaca"))
}
La ruta se resuelve dentro de la raíz del módulo. Se busca, en orden:
<ruta>.vaca<ruta>/paquete.vaca<ruta>/index.vaca<ruta>/modulo.vaca
No se permite .. ni escapar de la raíz del módulo.
Añadir una dependencia
vaca agregar github.com/usuario/util@1.2.0
Sin versión, se elige la última etiqueta semver:
vaca agregar github.com/usuario/util
El manifiesto añade una línea:
modulo ejemplo.com/mi-api
version 0.1.0
inicio iniciar.vaca
requiere github.com/usuario/util ^1.2.0
Después:
vaca instalar
Importar el paquete
importar "github.com/usuario/util"
imprimir(util.saludo("Vaca"))
El alias por defecto es el último segmento de la ruta (util). Puedes
cambiarlo:
importar "github.com/usuario/util" como herramientas
imprimir(herramientas.saludo("Vaca"))
Un paquete debe exponer un archivo de entrada en la raíz del repositorio, en este orden:
paquete.vacaindex.vacamodulo.vaca<ultimo-segmento>.vaca
Las funciones, constantes y variables de nivel superior de ese archivo forman la API del paquete. Sus importaciones relativas se cargan desde el propio paquete.
Versiones
Las versiones se leen de las etiquetas del repositorio (v1.2.3 o 1.2.3).
Las etiquetas que no son semver se ignoran.
| Restricción | Ejemplo | Acepta |
|---|---|---|
| Exacta | 1.2.3 |
Solo 1.2.3 |
| Compatible | ^1.2.3 |
>=1.2.3 y <2.0.0 |
| Aproximada | ~1.2.3 |
>=1.2.3 y <1.3.0 |
| Mínima | >=1.2.0 |
1.2.0 o superior |
| Máxima | <2.0.0 |
Anterior a 2.0.0 |
| Cualquiera | * |
La última versión |
Para 0.x, ^0.2.3 acepta >=0.2.3 y <0.3.0.
Dependencias transitivas
Si un paquete incluye su propio vaca.mod, sus dependencias también se
instalan. Los manifiestos antiguos en vaca.paquete (JSON) se siguen leyendo.
Si dos paquetes piden versiones incompatibles del mismo módulo, vaca instalar
falla y muestra las restricciones en conflicto.
Orígenes
Por defecto, la URL es https://<ruta>.git. Puedes cambiarla por paquete:
origen ejemplo.com/util https://git.ejemplo.com/util.git
origen ejemplo.com/pruebas file:///home/yo/pruebas
Se admiten https://, ssh://, file:// y git@. Para repositorios privados,
usa las credenciales de git que ya tengas configuradas (SSH o un helper de
credenciales); Vaca no guarda tokens. Se rechazan ext:: y argumentos que
empiecen por -.
Reemplazos locales
Para desarrollar un paquete y una aplicación a la vez:
requiere ejemplo.com/util ^1.2.0
reemplaza ejemplo.com/util ../util
vaca instalar copia el directorio local a .vaca/paquetes/ (excluye .git,
.vaca y vaca.lock). Vuelve a ejecutarlo después de cambiar el paquete. Los
reemplazos no se aplican a las dependencias transitivas de tus dependencias.
Lockfile e integridad
vaca.lock fija, para cada paquete:
- la versión elegida;
- el commit exacto (
git rev-parse HEAD); - un hash SHA-256 del árbol de archivos.
Si vuelves a instalar y el paquete ya está en .vaca/paquetes/ con el mismo
hash, no se usa la red. Si el hash o el commit no coinciden con el lock,
vaca instalar falla: revisa el cambio antes de ejecutar vaca actualizar.
{
"paquetes": {
"ejemplo.com/util": {
"version": "1.2.0",
"commit": "0f3c…",
"hash": "sha256:…"
}
}
}
Construir para producción
vaca instalar # solo si hay dependencias
vaca construir
Empaquetado .vaca/dist/mi-api.vaca (12.4 KiB)
módulo: ejemplo.com/mi-api
entrada: iniciar.vaca
sha256: d52795c9…
copia este archivo al servidor y ejecuta: vaca mi-api.vaca
El artefacto incluye:
- todos los archivos
.vacadel módulo; vaca.modyvaca.lock;- las dependencias de
.vaca/paquetes/.
Al ejecutarlo, Vaca verifica el SHA-256 y carga los módulos en memoria. Si un solo byte cambia:
error de ejecución: 'mi-api.vaca': el bundle está corrupto: el hash no coincide
También se escribe .vaca/dist/mi-api.vaca.sha256 para verificar la descarga:
sha256sum -c mi-api.vaca.sha256
Límites defensivos al leer bundles ajenos: 8192 archivos, 64 MiB en total y
rutas sin ... El bundle contiene código, no datos: .env, CSV,
certificados y demás archivos se leen del sistema de archivos en ejecución.
Comandos
| Comando | Efecto |
|---|---|
vaca init <modulo> |
Crea vaca.mod e iniciar.vaca |
vaca |
Ejecuta la entrada del módulo y principal() |
vaca construir |
Genera .vaca/dist/<nombre>.vaca |
vaca agregar <ruta>[@version] |
Añade la dependencia y ejecuta la instalación |
vaca instalar |
Descarga y verifica todas las dependencias |
vaca actualizar |
Re-resuelve las versiones ignorando el lock |
vaca listar |
Muestra módulo, entrada, dependencias y hashes |
vaca limpiar |
Borra .vaca/paquetes y vaca.lock |
Seguridad
- Los paquetes ejecutan código con los permisos del proceso. Revisa el código antes de instalar algo de un tercero.
- Usa siempre
https://para orígenes remotos;file://está pensado para desarrollo y pruebas. - El lockfile y el hash detectan cambios inesperados, pero no sustituyen una auditoría: fijan lo que ya decidiste confiar.
- No hay firmas criptográficas de paquetes ni registro central.
.vaca/está en.gitignorepor defecto. Si quieres distribuir el código vendorizado, quita esa línea y añade.vaca/al repositorio, o guarda solovaca.lock.- Fija versiones exactas en producción (
1.2.3) si necesitas control total;^es cómodo pero puede traer cambios menores.
Limitaciones actuales
- Una sola versión por módulo en cada proyecto.
- El resolvedor elige la versión más alta que cumpla todas las restricciones conocidas; si aparece una restricción nueva que la invalida, vuelve a resolver.
- No hay subpaquetes con manifiesto propio dentro del mismo repositorio: cada ruta de dependencia es un repositorio.
- No se soportan etiquetas de preversión (
1.0.0-beta). - Requiere
gitinstalado para descargar paquetes.