Guía completa para gestionar versiones de dependencias con Go Modules

Introducción

Para gestionar dependencias en Go, anteriormente se utilizaba principalmente glide. A continuación se presenta información sobre la herramienta de gestión de versiones oficial que apareció en Go 1.11, conocida como mod.

Para comprender mejor su funcionamiento, el equipo oficial de Go proporciona tres comandos de ayuda: go help mod, go help modules y go help module-get.

Configuración de GO111MODULE

La variable de entorno GO111MODULE permite activar o desactivar el soporte para módulos. Esta varialbe acepta tres valores: off, on y auto, siendo auto el valor predeterminado.

  • GO111MODULE=off: Sin soporte de módulos. Go buscará paquetes en la ruta GOPATH y en la carpeta vendor.
  • GO111MODULE=on: Con soporte de módulos. Go ignorará GOPATH y vendor, utilizando únicamente go.mod para descargar dependencias.
  • GO111MODULE=auto: Activación automática cuando se trabaja fuera de $GOPATH/src y existe un archivo go.mod en el directorio raíz.

Al trabajar con módulos, la variable GOPATH pierde relevancia para la resolución de dependencias. Sin embargo, las dependencias descargadas se almacenan en $GOPATH/pkg/mod, los resultados de go install se placed en $GOPATH/bin.

Comandos de Go Mod

A continuación se detallan los comandos principales disponibles:

download    descarga módulos al caché local
edit        edita el archivo go.mod desde herramientas o scripts
graph       muestra el gráfico de dependencias de módulos
init        inicializa un nuevo módulo en el directorio actual
tidy        agrega módulos faltantes y elimina los no utilizados
vendor      crea una copia de las dependencias en vendor
verify      verifica que las dependencias tengan el contenido esperado
why         explica por qué se necesitan ciertos paquetes o módulos

Uso de Go Mod

Creación del archivo go.mod

En un proyecto nuevo, es necesario ejecutar go mod init para inicializar y crear el archivo go.mod, el cual contendrá las rutas y versiones de todas las dependencias.

module github.com/miusuario/observador

require (
    github.com/apex/log v1.0.0
    github.com/fatih/color v1.7.0 // indirect
    github.com/fsnotify/fsnotify v1.4.7
    github.com/go-ini/ini v1.38.2
    github.com/go-kit/kit v0.7.0
    github.com/go-logfmt/logfmt v0.3.0 // indirect
)

La etiqueta indirect indica que la librería fue incluida de manera transitiva.

El comando go mod vendor permite crear una carpeta vendor en el proyecto y copiar todas las dependencias allí.

El comando go mod download almacena las dependencias en el caché local para su uso posterior.

Visualización de información de librerías importadas

go list -m -json all

  • -json: Muestra la información en formato JSON
  • all: Muestra todas las librerías

Ruta del caché de módulos

Por defecto, el caché se encuentra en $GOPATH/pkg:

$GOPATH/pkg/mod

A continuación se muestra la estructura de archivos descargados para un proyecto:

  mod ls -lh cache/download/github.com/go-kit/kit/@v/
total 3016
-rw-r--r--  1 usuario  staff     7B Sep 29 15:37 list
-rw-------  1 usuario  staff    50B Sep 29 15:37 v0.7.0.info
-rw-------  1 usuario  staff    29B Sep 29 15:37 v0.7.0.mod
-rw-r--r--  1 usuario  staff   1.5M Sep 29 15:37 v0.7.0.zip
-rw-r--r--  1 usuario  staff    47B Sep 29 15:37 v0.7.0.ziphash

Se puede observar que para cada versión de una librería se crea una carpeta отдельная que contiene información específica de dicha versión.

Problema conocido: go mod no puede descargar paquetes de google

Para la mayoría de desarrolladores de Go en el mundo, la introducción de Go modules trajo grandes beneficios. Sin embargo, para aquellos que se encuentran en determinadas regiones con restricciones de red, esta ventaja viene acompañada de algunas dificultades.

El motivo radica en que, en modo módulo, Go ya no busca paquetes en la ubicación tradicional de GOPATH ni en el directorio vendor, sino que utiliza el caché local en GOPATH/pkg/mod (en Go 1.11 era esta ubicación, aunque podría variar en versiones posteriores).

Como es ampliamente conocido, en ciertas regiones no es posible utilizar go get ni git clone para obtener algunos paquetes de terceros. El caso más común son los paquetes bajo golang.org/x. En el modo tradicional GOPATH, existía una solución alternativa: clonar primero los paquetes desde mirrors en GitHub y luego renombrarlos a golang.org/x/xxx. También era posible colocar estos paquetes en el directorio vendor y commitearlos al repositorio.

Sin embargo, tras la llegada de los módulos, una vez activado el modo módulo, go build ya no considera los paquetes en GOPATH ni en vendor. En su lugar, consulta el caché en GOPATH/pkg/mod; si no encuentra el módulo, procederá a descargar una versión específica. Para los módulos bajo golang.org/x/xxx, esta descarga suele fallar en regiones con restricciones.

Algunos podrían sugerir continuar utilizando mirrors y renombrando paquetes. En teoría es posible, pero en la práctica resulta bastante tedioso. Veamos la estructura del directorio de caché local de Go modules:

  /Users/usuario/go/pkg/mod $tree -L 7
.
├── cache
│   └── download
│       └── golang.org
│           └── x
│               └── text
│                   └── @v
│                       ├── list
│                       ├── v0.1.0.info
│                       ├── v0.1.0.mod
│                       ├── v0.1.0.zip
│                       ├── v0.1.0.ziphash
│                       ├── v0.3.0.info
│                       ├── v0.3.0.mod
│                       ├── v0.3.0.zip
│                       └── v0.3.0.ziphash
└── golang.org
    └── x
        ├── text@v0.1.0
        └── text@v0.3.0

La estructura del directorio mod está cuidadosamente diseñada. En cache/download se almacena la "metainformación" de cada módulo, junto con archivos zip de cada versión. En este ejemplo se可以看到 para el módulo golang.org/x/text existen dos versiones (v0.1.0 y v0.3.0) con su información y código fuente correspondiente.

Si se intentara replicar el enfoque del modo GOPATH mediante "descarga desde mirror más renombrado", sería necesario crear manualmente la metainformación para cada versión del módulo, incluyendo los archivos como xx.info, xxx.mod, entre otros. Este enfoque resulta poco práctico y su "experiencia de usuario" no es óptima.

Solución: Go Module Proxy

Entonces, ¿cómo pueden los desarrolladores en regiones con restricciones de red disfrutar de los beneficios de Go modules? ¡El problema tiene solución! La respuesta se encuentra en Go 1.11.

Junto con la introducción de Go modules, Go 1.11 también incorporó el concepto de Go module proxy (consultar go help goproxy).

De manera predeterminada, el comando go get, ya sea en modo GOPATH o en modo módulo, descarga directamente los módulos desde servicios VCS como GitHub o GitLab. Sin embargo, en Go 1.11 es posible modificar este comportamiento mediante la variable de entorno GOPROXY, permitiendo que los comandos de Go descarguen módulos desde otras fuentes.

Por ejemplo:

export GOPROXY=https://goproxy.io

Una vez configurado de esta manera, los comandos de Go utilizarán el protocolo de descarga de módulos para interactuar con el proxy y descargar la versión específica del módulo.

Si se configura un servidor proxy de módulos de Go en un VPS extranjero, sería posible descargar módulos como los ubicados bajo golang.org/x. Además, otros problemas secundarios como la lentitud al obtener paquetes desde GitHub podrían verse solucionados.

Aunque el propósito original de Go proxy no fue resolver las limitaciones de descarga en regiones con restricciones de red, es innegable que GOPROXY proporciona a los desarrolladores mayor control y capacidad de intervención sobre la obtención de módulos y paquetes, basándose en el sistema de versionado de Go.

Referencias

Etiquetas: Go golang go-modules go-mod dependency-management

Publicado el 6-22 07:22