Hola a todos. En previsión del comienzo del curso para desarrolladores de Golang, hemos preparado otra traducción interesante para usted.
Los módulos son una forma de lidiar con las dependencias en Go. Inicialmente presentados como un experimento, se supone que los módulos deben introducirse en el campo como un nuevo estándar para administrar paquetes desde la versión 1.13.Considero que este tema es bastante inusual para principiantes que vienen de otros idiomas, por lo que decidí recopilar algunas ideas y consejos aquí para ayudar a otros como yo a tener una idea de la administración de paquetes en Go. Comenzaremos con una introducción general y luego pasaremos a los aspectos menos obvios, incluido el uso de la carpeta del proveedor, el uso de módulos con Docker en desarrollo, dependencias de herramientas, etc.Si ya está familiarizado con los módulos Go y conoce el Wiki, como el dorso de tu mano, este artículo probablemente no te sea muy útil. Pero por lo demás, sin embargo, puede ahorrar varias horas de prueba y error.Entonces, si estás en camino, súbete y disfruta del viaje.
Inicio rápido
Si el control de versiones ya está integrado en su proyecto, simplemente puede ejecutargo mod init
O especifique la ruta al módulo manualmente. Esto es algo así como un nombre, URL y ruta de importación para su paquete:go mod init github.com/you/hello
Esto creará un archivo go.mod
, que también define los requisitos del proyecto y lochit dependiendo de su versión correcta (como una analogía para usted, es como package.json
, y se package-lock.json
combina en un solo archivo):module github.com/you/hello
go 1.12
Ejecute go get
para agregar una nueva dependencia a su proyecto: tenga encuenta que aunque no puede especificar un rango de versiones con go get, lo que define aquí no es una versión específica, sino una versión mínima. Como veremos más adelante, hay una manera de actualizar correctamente las dependencias según semver.# use Git tags
go get github.com/go-chi/chi@v4.0.1
# or Git branch name
go get github.com/go-chi/chi@master
# or Git commit hash
go get github.com/go-chi/chi@08c92af
Ahora nuestro archivo es el go.mod
siguiente:module github.com/you/hello
go 1.12
require github.com/go-chi/chi v4.0.2+incompatible
El sufijo se +incompatible
agrega a todos los paquetes que aún no están configurados para los módulos Go o que infringen sus reglas de control de versiones.Como no hemos importado este paquete en ningún lugar de nuestro proyecto, se marcó como // indirect
. Podemos ordenar esto con el siguiente comando:go mod tidy
Dependiendo del estado actual de su repositorio, eliminará un módulo no utilizado o eliminará un comentario // indirect
.Si alguna dependencia por sí misma no tiene go.mod
(por ejemplo, aún no está configurada para módulos), entonces todas sus dependencias se escribirán en el archivo padre go.mod
(como opción, su archivo go.mod)
junto con un comentario // indirect
para indicar que no son de importación directa En suplan global, el objetivo go mod tidy
también es agregar las dependencias necesarias para otras combinaciones de SO, arquitecturas y etiquetas de compilación. Asegúrese de ejecutarlo antes de cada lanzamiento.También asegúrese de crear un archivo después de agregar la dependenciago.sum
. Puede pensar que este es un archivo de bloqueo. Pero, de hecho, go.mod
ya proporciona suficiente información para compilaciones 100% reproducibles. El archivo go.sum
se crea con fines de verificación: contiene las sumas de verificación criptográficas esperadas del contenido de las versiones individuales del módulo.En parte porque no es go.sum
un archivo de bloqueo, guarda las sumas de verificación escritas para la versión del módulo, incluso después de dejar de usar este módulo. Esto le permite verificar las sumas de verificación si reanuda su uso más tarde, lo que proporciona seguridad adicional.
Mkcert acaba de migrar a los módulos (con proveedor / para compatibilidad con versiones anteriores) y todo salió sin problemas
https://github.com/FiloSottile/mkcert/commit/26ac5f35395fb9cba3805faf1a5a04d260271291
$ GO111MODULE=on go1.11rc1 mod init
$ GO111MODULE=on go1.11rc1 mod vendor
$ git add go.mod go.sum vendor
$ git rm Gopkg.lock Gopkg.toml Makefile

Preguntas frecuentes: ¿Debería comprometerme go.sum
en git?
A: definitivamente sí. Con él, los propietarios de sus fuentes no necesitan confiar en otros repositorios de GitHub y propietarios de rutas de importación personalizadas. Ya en camino a nosotros, algo mejor, pero por ahora este es el mismo modelo que los hashes en los archivos de bloqueo.
Los comandos go build
y go test
cargarán automáticamente todas las dependencias que faltan, aunque puede hacerlo explícitamente con la ayuda de go mod download
rellenar previamente cachés locales que pueden ser útiles para CI.Por defecto, todos nuestros paquetes de todos los proyectos se cargan en el directorio $GOPATH/pkg/mod
. Discutiremos esto con más detalle más adelante.Actualización de versiones de paquetes
Puede usar go get -u
cualquiera go get -u=patch
para actualizar las dependencias a la última versión menor o parche, respectivamente.Pero no puede actualizar a versiones principales como esa. El código incluido en los módulos Go debe cumplir técnicamente con las siguientes reglas:- Match semver (ejemplo, etiqueta VCS v1.2.3).
- Si el módulo es la versión v2 o superior, la versión principal del módulo debe incluirse tanto
/vN
al final de la ruta del módulo utilizada en el archivo go.mod
como en la ruta de importación del paquete:
import "github.com/you/hello/v2"
Aparentemente, esto se hace para que se puedan importar diferentes versiones de paquetes en un ensamblaje (consulte el problema de dependencia del diamante ).En pocas palabras, Go espera que seas muy cuidadoso al presentar versiones principales.Sustitución de módulos importados
Puede especificar el módulo necesario para su propia bifurcación o incluso la ruta local al archivo utilizando la directiva replace
:go mod edit -replace github.com/go-chi/chi=./packages/chi
Resultado:module github.com/you/hello
go 1.12
require github.com/go-chi/chi v4.0.2+incompatible
replace github.com/go-chi/chi => ./packages/chi
Puede eliminar la línea manualmente o ejecutar:go mod edit -dropreplace github.com/go-chi/chi
Gestión de dependencias del proyecto
Históricamente, todo el código de Go se almacenaba en un mono-repositorio gigante, porque así es como Google organiza su base de código, y esto afecta el diseño del lenguaje.Los módulos Go son una desviación de este enfoque. Ya no necesita mantener todos sus proyectos $GOPATH
.Sin embargo, técnicamente todas sus dependencias descargadas todavía están ubicadas $GOPATH/pkg/mod
. Si usa contenedores Docker para el desarrollo local, esto puede ser un problema, ya que las dependencias se almacenan fuera del proyecto. Por defecto, simplemente no son visibles en su IDE.
Esto generalmente no es un problema para otros idiomas, pero esto es lo que encontré por primera vez al trabajar con la base de código Go.Afortunadamente, hay varias formas (indocumentadas) de resolver este problema.Opción 1. Instale GOPATH dentro del directorio de su proyecto.
A primera vista, esto puede parecer contradictorio, pero si ejecuta Go desde un contenedor , puede anular GOPATH para que apunte al directorio del proyecto para que los paquetes sean accesibles desde el host:version: '3.7'
services:
app:
command: tail -f /dev/null
image: golang:1.12.6-stretch
environment:
# - /code/.go/pkg/mod
- GOPATH=/code/.go
ports:
- 8000:8000
volumes:
- ./:/code:cached
working_dir: /code
Los IDE populares deberían poder instalar GOPATH en el nivel del proyecto (espacio de trabajo):
el único inconveniente de este enfoque es la falta de interacción con el tiempo de ejecución de Go en la computadora host. Debe ejecutar todos los comandos Go dentro del contenedor.Opción 2: vender sus dependencias
Otra forma es copiar las dependencias de su proyecto en una carpeta vendor
:go mod vendor
Debe notarse de inmediato: NO permitimos que Go cargue directamente materiales a la carpeta del proveedor: esto no es posible con los módulos. Simplemente copiamos los paquetes ya descargados.Además, si desata sus dependencias, como en el ejemplo anterior, borre $GOPATH/pkg/mod
y luego intente agregar varias dependencias nuevas a su proyecto, verá lo siguiente:- Go reconstruirá el caché de descarga para todos los paquetes de software
$GOPATH/pkg/mod/cache
. - Todos los módulos cargados se copiarán a
$GOPATH/pkg/mod
. - Y finalmente, Go copiará estos módulos a una
vendor
carpeta, eliminando ejemplos, pruebas y algunos otros archivos de los que no depende directamente.
Además, hay muchas cosas que faltan en esta carpeta de proveedor recién creada:
un archivo típico de Docker Compose tiene este aspecto (tenga en cuenta los enlaces de volumen):version: '3.7'
services:
app:
command: tail -f /dev/null
image: golang:1.12.6-stretch
ports:
- 8000:8000
volumes:
# go,
- modules:/go/pkg/mod/cache
- ./:/code:cached
working_dir: /code
volumes:
modules:
driver: local
Tenga en cuenta que NO hago cómics con esta carpeta del proveedor en el sistema de control de versiones o no la voy a usar en producción. Este es un script de desarrollo estrictamente local, que generalmente se puede encontrar en otros idiomas.Sin embargo, cuando leo los comentarios de algunos mantenedores de Go y algunas ofertas relacionadas con la venta parcial (?), Tengo la impresión de que esta función originalmente no estaba destinada a este caso de usuario.Uno de los comentaristas en reddit me ayudó a arrojar algo de luz sobre esto:Por lo general, las personas venden sus dependencias por razones como el deseo de tener ensamblajes ajustados sin acceso a la red, así como la disponibilidad de una copia de las dependencias preparadas en caso de falla de github o la desaparición del repositorio, y la posibilidad de una auditoría más fácil de los cambios en las dependencias utilizando herramientas estándar de VCS, etc. .Sí, no parece nada del hecho de que yo podría estar interesado.De acuerdo con el comando Ir, puede habilitar fácilmente la venta mediante la configuración de una variable de entorno GOFLAGS=-mod=vendor
. No recomiendo hacer esto. El uso de indicadores simplemente se romperá go get
sin proporcionar ningún otro beneficio a su flujo de trabajo diario: de
hecho, el único lugar que necesita para habilitar la venta es su IDE:
Después de algunas pruebas y errores, se me ocurrió el siguiente procedimiento para agregar dependencias de proveedores en este enfoque.Paso 1. Requisito
Puede requerir una dependencia con go get
:go get github.com/rs/zerolog@v1.14.3
Paso 2. Importar
Luego impórtelo en algún lugar de su código:import (
_ "github.com/rs/zerolog"
)
Paso 3. Venta
Finalmente, vuelve a abrir tus dependencias:go mod vendor
Hay una propuesta pendiente para permitir que el proveedor go mod acepte ciertas plantillas de módulos que pueden (o no) resolver algunos de los problemas asociados con este flujo de trabajo.go mod vendor
ya requiere automáticamente las importaciones perdidas, por lo que el paso 1 es opcional en este flujo de trabajo (si no desea especificar restricciones de versión). Sin embargo, sin el paso 2, no recogerá el paquete descargado.Este enfoque funciona mejor con el sistema host, pero es bastante confuso cuando se trata de editar sus dependencias.
Personalmente, creo que redefinir GOPATH es un enfoque más limpio, ya que no sacrifica la funcionalidad go get
. Sin embargo, quería mostrar ambas estrategias, porque la carpeta del proveedor puede ser más familiar para las personas que vienen de otros lenguajes, como PHP, Ruby, Javascript, etc. Como puede ver en el fraude descrito en este artículo, este No es una opción particularmente buena para ir.Dependencias de herramientas
Es posible que necesitemos instalar algunas herramientas basadas en Go que no se importan, sino que se usan como parte del entorno de desarrollo del proyecto. Un ejemplo simple de dicha herramienta es CompileDaemon , que puede monitorear su código en busca de cambios y reiniciar su aplicación.El enfoque oficialmente recomendado es agregar un tools.go
archivo (el nombre no importa) con el siguiente contenido:
package tools
import (
_ "github.com/githubnemo/CompileDaemon"
)
- La limitación
// +build tools
evita que sus ensamblajes regulares realmente importen su herramienta. - La expresión de importación permite que los comandos go escriban con precisión la información de la versión de sus herramientas en
go.mod
su archivo de módulo.
Entonces eso es todo. Espero que no estés tan confundido como yo cuando comencé a usar los módulos Go. Puede visitar el wiki de Go Modules para obtener más detalles.
Súbete al curso.