Como importar pacotes locais sem gopath

171

Eu usei, GOPATHmas para este problema atual que estou enfrentando, não ajuda. Quero poder criar pacotes específicos para um projeto:

myproject/
├── binary1.go
├── binary2.go
├── package1.go
└── package2.go

Eu tentei várias maneiras, mas como faço para obter package1.goa trabalhar no binary1.goou binary2.goe assim por diante?

Por exemplo; Desejo import "package1"poder executar e, em seguida, executar go build binary1.goe tudo funciona bem sem o erro de que o pacote não pode ser encontrado em GOROOTou GOPATH. A razão pela qual eu preciso desse tipo de funcionalidade é para projetos de grande escala; Eu não quero ter que fazer referência a vários outros pacotes ou mantê-los em um arquivo grande.

Flimzy
fonte
2
Você deve colocar os arquivos de origem de cada binário em seu próprio diretório.
fuz 9/07/2013
Todos os .goarquivos em um único diretório fazem parte do mesmo pacote e você não precisa de importarquivos no mesmo pacote (ou seja, o mesmo diretório). Você mencionou trabalhar fora do GOPATH, que é um dos recursos do novo sistema de módulos Go. Esta resposta tampas módulo estrutura, a importação de pacotes locais, organizando pacotes dentro de um módulo, se deve ou não ter vários módulos no repositório único, etc.
typical182
3
E esse comportamento está bem com todo mundo? Que você basicamente não pode importar seus subpacotes locais, a menos que você especifique o git/repo/to/my/projectcaminho inteiro ? Só não vejo a razão pela qual alguém iria querer esse comportamento. E se você mover seu projeto para outro local (por exemplo, imagem do Docker), precisará alterar todos os caminhos novamente? Estou procurando respostas por que isso é tão complicado.
Milosmns 18/08/19
@milosmns veja minha resposta stackoverflow.com/a/60915633/175071
Timo Huovinen

Respostas:

176

Resumo do gerenciamento de dependências:

  • vgo se a sua versão for: x >= go 1.11
  • depou vendorse a sua versão for:go 1.6 >= x < go 1.11
  • Manualmente, se a sua versão for: x < go 1.6

Editar 3: O Go 1.11 possui um recurso vgoque será substituído dep .

Para usar vgo, consulte a documentação dos módulos . TLDR abaixo:

export GO111MODULE=on
go mod init
go mod vendor # if you have vendor/ folder, will automatically integrate
go build

Este método cria um arquivo chamado go.modno diretório de projetos. Você pode criar seu projeto com go build. Se GO111MODULE=autoestiver definido, seu projeto não poderá estar $GOPATH.


Edição 2: o método de venda ainda é válido e funciona sem problemas. vendoré em grande parte um processo manual, por causa disso depe vgofoi criado.


Edit 1: Enquanto minha maneira antiga funciona, não é mais a maneira "correta" de fazê-lo. Você deve usar os recursos do fornecedorvgo , ou dep(por enquanto) habilitados por padrão no Go 1.6; veja . Você basicamente adiciona seus pacotes "externos" ou "dependentes" em um vendordiretório; após a compilação, o compilador usará esses pacotes primeiro.


Encontrado. Consegui importar o pacote local GOPATHcriando uma subpasta package1e depois importando com import "./package1"in binary1.goe binary2.goscripts como este:

binary1.go

...
import (
        "./package1"
      )
...

Portanto, minha estrutura de diretórios atual se parece com isso:

myproject/
├── binary1.go
├── binary2.go
├── package1/
   └── package1.go
└── package2.go

Devo também notar que caminhos relativos (pelo menos em go 1.5) também funcionam; por exemplo:

import "../packageX"

fonte
4
Isso funciona bem até que você tenha duas subpastas, uma referindo-se à outra. Por exemplo, se package2 também era uma subpasta e precisava do package1, o sistema quebra.
Carl
7
import "../package1"
Felix Rabe
12
Caminhos de importação relativos são uma má ideia .
Dave C
1
se #golang fornecer 'espaço para nome', posso concordar com você que 'caminho de importação relativo' ou 'subpacotes' são más idéias '.
mission.liao
1
Nome da função deve começar com Capitilized palavra-chave
kokemomuke
71

Não existe "pacote local". A organização de pacotes em um disco é ortogonal a qualquer relação pai / filho de pacotes. A única hierarquia real formada por pacotes é a árvore de dependências, que geralmente não reflete a árvore de diretórios.

Apenas use

import "myproject/packageN"

e não lute contra o sistema de construção sem um bom motivo. Salvar uma dúzia de caracteres por importação em qualquer programa não trivial não é um bom motivo, porque, por exemplo, projetos com caminhos de importação relativos não são aceitáveis.

O conceito de caminhos de importação tem algumas propriedades importantes:

  • Os caminhos de importação podem ser globalmente exclusivos.
  • Em conjunto com o GOPATH, o caminho de importação pode ser convertido sem ambiguidade em um caminho de diretório.
  • Qualquer caminho de diretório no GOPATH pode ser convertido de maneira inequívoca em um caminho de importação.

Todas as opções acima são arruinadas usando caminhos de importação relativos. Não faça isso.

PS: Existem poucos lugares no código legado nos testes do compilador Go que usam importações relativas. ATM, esse é o único motivo pelo qual as importações relativas são suportadas.

zzzz
fonte
2
Eu recomendo dar uma olhada neste vídeo de introdução para uma melhor compreensão dos pacotes e do GOPATH . youtube.com/watch?v=XCsL89YtqCs
Joshua Pinter
7
Eu acho que isso é um mau conselho. Se você acabar usando o gopkg.in para controle de versão, por exemplo, estará sem sorte com os caminhos de importação absolutos para seus "mini" pacotes, como descrito acima. Você interrompe o repositório de origem ou o versionado se torna inútil.
Greg
import "myproject/packageN". myprojecté o nome da pasta que contém meu projeto?
9788 securecurve
Isso é completamente errado, como eu o uso com repositórios particulares agora?
agilob
44

Talvez você esteja tentando modularizar seu pacote. Estou assumindo que package1e package2são, de certa forma, parte do mesmo pacote, mas para facilitar a leitura que você está dividindo aqueles em vários arquivos.

Se o caso anterior fosse seu, você poderia usar o mesmo nome de pacote nesses múltiplos arquivos e será como se houvesse o mesmo arquivo.

Isto é um exemplo:

add.go

package math

func add(n1, n2 int) int {
   return n1 + n2
}

subtract.go

package math

func subtract(n1, n2 int) int {
    return n1 - n2
}

donothing.go

package math

func donothing(n1, n2 int) int {
    s := add(n1, n2)
    s = subtract(n1, n2)
    return s
}

Não sou especialista em Go e esta é a minha primeira postagem no StackOveflow; portanto, se você tiver alguns conselhos, será bem recebido.

Juan Jose Tugores
fonte
23

Eu tenho um problema semelhante e a solução que estou usando atualmente usa os módulos Go 1.11. Eu tenho a seguinte estrutura

- projects
  - go.mod
  - go.sum
  - project1
    - main.go
  - project2
    - main.go
  - package1
    - lib.go
  - package2
    - lib.go

E eu sou capaz de importar package1 e package2 do projeto1 e projeto2 usando

import (
    "projects/package1"
    "projects/package2"
)

Depois de correr go mod init projects. Posso usar go buildnos diretórios project1 e project2 ou go build -o project1/exe project1/*.gono diretório de projetos.

A desvantagem desse método é que todos os seus projetos acabam compartilhando a mesma lista de dependências no go.mod. Ainda estou procurando uma solução para esse problema, mas parece que isso pode ser fundamental.

Mad Wombat
fonte
9

Desde a introdução do go.mod , acho que o gerenciamento de pacotes local e externo se torna mais fácil. Usando go.mod , é possível ter um projeto go fora do GOPATH também.

Importar pacote local:

Crie uma pasta descriptografar e execute o seguinte comando para gerar o arquivo go.mod

go mod init demoproject

Eu tenho uma estrutura de projeto como abaixo, dentro do diretório de descriptografia .

├── go.mod
└── src
    ├── main.go
    └── model
        └── model.go

Para fins de demonstração, insira o seguinte código no arquivo model.go .

package model

type Employee struct {
    Id          int32
    FirstName   string
    LastName    string
    BadgeNumber int32
}

No main.go , importei o modelo Employee referenciando "demoproject / src / model"

package main

import (
    "demoproject/src/model"
    "fmt"
)

func main() {
    fmt.Printf("Main Function")

    var employee = model.Employee{
        Id:          1,
        FirstName:   "First name",
        LastName:    "Last Name",
        BadgeNumber: 1000,
    }
    fmt.Printf(employee.FirstName)
}

Importar dependência externa:

Basta executar o go getcomando dentro do diretório do projeto.

Por exemplo:

go get -u google.golang.org/grpc

Deve incluir a dependência do módulo no arquivo go.mod

module demoproject

go 1.13

require (
    golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa // indirect
    golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 // indirect
    golang.org/x/text v0.3.2 // indirect
    google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150 // indirect
    google.golang.org/grpc v1.26.0 // indirect
)

https://blog.golang.org/using-go-modules

Tanver Hasan
fonte
can't load package: package .: no Go files in...(ir compilar na pasta go.mod)
Sebi2020 10/04
Tal banalidade, mas levei um tempo embaraçoso para encontrar a resposta e seu post foi o mais legível e útil. Obrigado!
Harold Cavendish
8

Para adicionar um pacote "local" ao seu projeto, adicione uma pasta (por exemplo "package_name"). E coloque seus arquivos de implementação nessa pasta.

src/github.com/GithubUser/myproject/
 ├── main.go
 └───package_name
       └── whatever_name1.go
       └── whatever_name2.go

No seu package mainfaça isso:

import "github.com/GithubUser/myproject/package_name"

Onde package_nameestá o nome da pasta e deve corresponder ao nome do pacote usado nos arquivos Whatever_name1.go e Whatever_name2.go. Em outras palavras, todos os arquivos com um subdiretório devem ter o mesmo pacote.

Você pode aninhar ainda mais subdiretórios, desde que especifique o caminho inteiro para a pasta pai na importação.

Homan
fonte
2
Essa é uma boa sugestão, exceto que durante qualquer pânico no kernel, o rastreamento da pilha que é despejado do binário mostra o caminho do github.com, por exemplo, nem sempre o comportamento mais desejável. Existem sinalizadores para suprimir isso, mas não deve ser necessário apenas para alcançar uma organização simples de pacotes, e descobri que ele falha ocasionalmente.
Kenny Powers
package myproject/package_name is not in GOROOT (/usr/lib/go-1.14/src/myproject/package_name)
Sebi2020 10/04
3

Você pode usar replace

go modo init example.com/my/foo

foo / go.mod

module example.com/my/foo

go 1.14

replace example.com/my/bar => /path/to/bar

require example.com/my/bar v1.0.0

foo / main.go

package main
import "example.com/bar"

func main() {
    bar.MyFunc()
}

bar / go.mod

module github.com/my/bar

go 1.14

bar / fn.go

package github.com/my/bar

import "fmt"

func MyFunc() {
    fmt.Printf("hello")
}

Importar um pacote local é como importar um pacote externo

exceto no arquivo go.mod, você substitui o nome desse pacote externo por uma pasta local.

O caminho para a pasta pode ser completo ou relativo "/ path / to / bar" ou "../bar"

https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive https://thewebivore.com/using-replace-in-go-mod-to-point -para-seu-módulo-local /

Timo Huovinen
fonte