Olá a todos. Antecipando o início do curso Golang Developer, preparamos outra tradução interessante para você.
Os módulos são uma maneira de lidar com dependências no Go. Inicialmente apresentados como um experimento, os módulos devem ser introduzidos no campo como um novo padrão para gerenciar pacotes da versão 1.13.Acho esse tópico incomum o suficiente para iniciantes vindos de outros idiomas e, por isso, decidi coletar algumas idéias e dicas aqui para ajudar outras pessoas como eu a ter uma idéia do gerenciamento de pacotes no Go. Começaremos com uma introdução geral e passaremos para os aspectos menos óbvios, incluindo o uso da pasta vendor, o uso de módulos com o Docker no desenvolvimento, as dependências de ferramentas etc.Se você já conhece os módulos Go e conhece o Wiki, como as costas da sua mão, este artigo provavelmente não será muito útil para você. Porém, quanto ao resto, ele pode economizar várias horas de tentativa e erro.Então, se você estiver a caminho, entre e aproveite o passeio.
Começo rápido
Se o controle de versão já estiver integrado ao seu projeto, você pode simplesmente executargo mod init
Ou especifique o caminho para o módulo manualmente. É algo como um nome, URL e caminho de importação para o seu pacote:go mod init github.com/you/hello
Isso criará um arquivo go.mod
, que também define os requisitos e o lochit do projeto, dependendo da versão correta (como uma analogia para você, como é package.json
, e package-lock.json
combinada em um único arquivo):module github.com/you/hello
go 1.12
Execute go get
para adicionar uma nova dependência ao seu projeto:Observe que, embora você não possa especificar um intervalo de versões com go get, o que você define aqui não é uma versão específica, mas uma versão mínima. Como veremos mais adiante, existe uma maneira de atualizar as dependências normalmente de acordo com sempre.# 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
Agora, nosso arquivo é go.mod
o seguinte:module github.com/you/hello
go 1.12
require github.com/go-chi/chi v4.0.2+incompatible
O sufixo é +incompatible
adicionado a todos os pacotes que ainda não estão configurados para os módulos Go ou violam suas regras de controle de versão.Como não importamos este pacote em nenhum lugar do nosso projeto, ele foi marcado como // indirect
. Podemos arrumar isso com o seguinte comando:go mod tidy
Dependendo do estado atual do seu repositório, ele excluirá um módulo não utilizado ou excluirá um comentário // indirect
.Se alguma dependência por si só não tiver go.mod
(por exemplo, ainda não estiver configurada para módulos), todas as dependências serão gravadas no arquivo pai go.mod
(como opção, seu arquivo go.mod)
juntamente com um comentário // indirect
para indicar que não são de importação direta Em seuplano global, o objetivo go mod tidy
também é adicionar as dependências necessárias para outras combinações de SO, arquiteturas e tags de compilação. Execute-o antes de cada versão.Certifique-se de criar um arquivo após adicionar a dependênciago.sum
. Você pode pensar que este é um arquivo de bloqueio. Mas, na verdade, ele go.mod
já fornece informações suficientes para compilações 100% reproduzíveis. O arquivo go.sum
é criado para fins de verificação: contém as somas de verificação criptográficas esperadas do conteúdo de versões individuais do módulo.Em parte porque não é go.sum
um arquivo de bloqueio, ele salva as somas de verificação escritas para a versão do módulo, mesmo depois que você para de usá-lo. Isso permite que você verifique as somas de verificação se continuar usando-o posteriormente, o que fornece segurança adicional.
O Mkcert acabou de migrar para os módulos (com fornecedor / para compatibilidade com versões anteriores) e tudo correu bem
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

FAQ: Devo cometer go.sum
no git?
A: Definitivamente sim. Com isso, os proprietários de suas fontes não precisam confiar em outros repositórios do GitHub e proprietários de caminhos de importação personalizados. Já a caminho de nós, algo melhor, mas por enquanto esse é o mesmo modelo dos hashes nos arquivos de bloqueio.
Os comandos go build
e go test
carregarão automaticamente todas as dependências ausentes, embora você possa fazer isso explicitamente com a ajuda de go mod download
preencher previamente os caches locais que podem ser úteis para o IC.Por padrão, todos os nossos pacotes de todos os projetos são carregados para o diretório $GOPATH/pkg/mod
. Discutiremos isso com mais detalhes posteriormente.Atualizando versões do pacote
Você pode usar go get -u
tanto go get -u=patch
para atualizar dependências para a última versão menor ou remendo, respectivamente.Mas você não pode atualizar para versões principais como essa. O código incluído nos módulos Go deve cumprir tecnicamente as seguintes regras:- Combine semver (tag de exemplo VCS v1.2.3).
- Se o módulo for da versão v2 ou superior, a versão principal do módulo deverá ser incluída
/vN
no final do caminho do módulo usado no arquivo go.mod
e no caminho de importação do pacote:
import "github.com/you/hello/v2"
Aparentemente, isso é feito para que diferentes versões dos pacotes possam ser importadas em um assembly (consulte o problema de dependência de diamante ).Em poucas palavras, o Go espera que você seja muito cuidadoso ao apresentar as principais versões.Substituindo Módulos Importados
Você pode especificar o módulo necessário para sua própria bifurcação ou até o caminho local para o arquivo usando a diretiva 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
Você pode excluir a linha manualmente ou executar:go mod edit -dropreplace github.com/go-chi/chi
Gerenciamento de Dependências do Projeto
Historicamente, todo o código Go foi armazenado em um repositório mono gigante, porque é assim que o Google organiza sua base de códigos e isso afeta o design da linguagem.Os módulos Go são um desvio dessa abordagem. Você não precisa mais manter todos os seus projetos $GOPATH
.No entanto, tecnicamente todas as suas dependências baixadas ainda são inseridas $GOPATH/pkg/mod
. Se você usar contêineres do Docker para desenvolvimento local, isso pode ser um problema, pois as dependências são armazenadas fora do projeto. Por padrão, eles simplesmente não são visíveis no seu IDE.
Isso geralmente não é um problema para outros idiomas, mas foi o que encontrei pela primeira vez ao trabalhar com a base de código Go.Felizmente, existem várias maneiras (não documentadas) de resolver esse problema.Opção 1. Instale o GOPATH dentro do diretório do projeto.
À primeira vista, isso pode parecer contra-intuitivo, mas se você executar o Go a partir de um contêiner , poderá substituir o GOPATH para que aponte para o diretório do projeto para que os pacotes fiquem acessíveis a partir do 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
Os IDEs populares devem poder instalar o GOPATH no nível do projeto (espaço de trabalho):
A única desvantagem dessa abordagem é a falta de interação com o tempo de execução do Go no computador host. Você deve executar todos os comandos Go dentro do contêiner.Opção 2: vendendo suas dependências
Outra maneira é copiar as dependências do seu projeto para uma pasta vendor
:go mod vendor
Deve-se observar imediatamente: NÃO permitimos que o Go faça o upload direto de materiais para a pasta do fornecedor: isso não é possível com os módulos. Simplesmente copiamos pacotes já baixados.Além disso, se você desatar as suas dependências, como no exemplo acima, limpe $GOPATH/pkg/mod
e tente adicionar várias novas dependências ao seu projeto, você verá o seguinte:- O Go reconstruirá o cache de download de todos os pacotes de software
$GOPATH/pkg/mod/cache
. - Todos os módulos carregados serão copiados para
$GOPATH/pkg/mod
. - E, finalmente, o Go copiará esses módulos para uma
vendor
pasta, excluindo exemplos, testes e alguns outros arquivos dos quais você não depende diretamente.
Além disso, faltam muitas coisas nessa pasta de fornecedor recém-criada:
Um arquivo típico do Docker Compose se parece com isso (observe as ligações do volume):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
Por favor, note que eu NÃO coloque essa pasta de fornecedores em quadrinhos no sistema de controle de versão ou não a usarei na produção. Este é um script de desenvolvimento estritamente local, que geralmente pode ser encontrado em outros idiomas.No entanto, quando leio comentários de alguns mantenedores do Go e algumas ofertas relacionadas a vendas parciais (?), Tenho a impressão de que esse recurso foi originalmente destinado não a esse caso de usuário.Um dos comentaristas do reddit me ajudou a esclarecer isso:Geralmente, as pessoas vendem suas dependências por motivos como o desejo de ter assemblies restritos sem acesso à rede, além da disponibilidade de uma cópia de dependências prontas no caso de uma falha ou repositório do github desaparecer, e a capacidade de auditar com mais facilidade as alterações de dependência usando as ferramentas VCS padrão, etc. .Sim, ele não se parece com nada do fato de que eu poderia estar interessado.De acordo com o comando Ir, você pode facilmente ativar a venda, definindo uma variável de ambiente GOFLAGS=-mod=vendor
. Eu não recomendo fazer isso. O uso de sinalizadores simplesmente será interrompido go get
sem fornecer outros benefícios ao seu fluxo de trabalho diário:
Na verdade, o único local necessário para ativar a venda é o seu IDE:
Após algumas tentativas e erros, criei o procedimento a seguir para adicionar dependências de fornecedores nessa abordagem.Etapa 1. Requisito
Você pode exigir uma dependência com go get
:go get github.com/rs/zerolog@v1.14.3
Etapa 2. Importar
Em seguida, importe-o em algum lugar do seu código:import (
_ "github.com/rs/zerolog"
)
Etapa 3. Venda
Por fim, reabra suas dependências:go mod vendor
Existe uma proposta pendente para permitir que o fornecedor de mod go aceite determinados modelos de módulo que podem (ou não) resolver alguns dos problemas associados a esse fluxo de trabalho.go mod vendor
já requer importações perdidas automaticamente, portanto, a etapa 1 é opcional neste fluxo de trabalho (se você não desejar especificar restrições de versão). No entanto, sem a etapa 2, ele não receberá o pacote baixado.Essa abordagem funciona melhor com o sistema host, mas é bastante confusa quando se trata de editar suas dependências.
Pessoalmente, acho que redefinir o GOPATH é uma abordagem mais limpa, pois não sacrifica a funcionalidade go get
. No entanto, eu queria mostrar as duas estratégias, porque a pasta do fornecedor pode ser mais familiar para pessoas provenientes de outros idiomas, como PHP, Ruby, Javascript, etc. Como você pode ver na fraude descrita neste artigo, esta não é uma escolha particularmente boa para o Go.Dependências da ferramenta
Talvez seja necessário instalar algumas ferramentas baseadas em Go que não são importadas, mas usadas como parte do ambiente de desenvolvimento do projeto. Um exemplo simples dessa ferramenta é o CompileDaemon , que pode monitorar seu código em busca de alterações e reiniciar seu aplicativo.A abordagem oficialmente recomendada é adicionar um tools.go
arquivo (o nome não importa) com o seguinte conteúdo:
package tools
import (
_ "github.com/githubnemo/CompileDaemon"
)
- A limitação
// +build tools
impede que seus assemblies regulares realmente importem sua ferramenta. - A expressão import permite que os comandos go gravem com precisão as informações da versão de suas ferramentas no arquivo do
go.mod
módulo.
Então é só isso. Espero que você não fique tão confuso quanto eu quando comecei a usar os módulos Go. Você pode visitar o wiki Go Modules para obter mais detalhes.
Entre no curso.