Cómo importar paquetes locales sin gopath

171

Lo he usado GOPATHpero para este problema actual que enfrento no ayuda. Quiero poder crear paquetes que sean específicos para un proyecto:

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

Lo intenté de varias maneras, pero ¿cómo me pongo package1.goa trabajar en el binary1.goo el binary2.goy así sucesivamente?

Por ejemplo; Quiero poder import "package1"y luego poder ejecutar go build binary1.goy todo funciona bien sin que se produzca el error de que no se puede encontrar el paquete GOROOTo GOPATH. La razón por la que necesito este tipo de funcionalidad es para proyectos a gran escala; No quiero tener que hacer referencia a varios otros paquetes o guardarlos en un archivo grande.

Flimzy
fuente
2
Se supone que debe colocar los archivos de origen para cada binario en su propio directorio.
fuz
Todos los .goarchivos en un solo directorio son parte del mismo paquete, y no necesita importarchivos en el mismo paquete (es decir, el mismo directorio). Usted mencionó trabajar fuera de GOPATH, que es una de las capacidades del nuevo sistema de módulos Go. Este respuesta cubiertas módulo de estructura, la importación de paquetes locales, la organización de los paquetes dentro de un módulo, si desea o no tener múltiples módulos en un solo repositorio, etc.
typical182
3
¿Y este comportamiento está bien con todos? ¿Que básicamente no puede importar sus subpaquetes locales a menos que especifique la git/repo/to/my/projectruta completa ? Simplemente no veo la razón por la que alguien querría este comportamiento. ¿Qué sucede si mueve su proyecto a otra ubicación (es decir, imagen de Docker), necesita alterar todas las rutas nuevamente? Estoy buscando respuestas por qué esto es tan complicado.
milosmns
@milosmns mira mi respuesta stackoverflow.com/a/60915633/175071
Timo Huovinen

Respuestas:

176

Ir resumen de gestión de dependencias:

  • vgo si su versión go es: x >= go 1.11
  • depo vendorsi tu versión go es:go 1.6 >= x < go 1.11
  • Manualmente si su versión go es: x < go 1.6

Edición 3: Go 1.11 tiene una característica vgoque reemplazará dep .

Para usar vgo, consulte la documentación de Módulos . TLDR a continuación:

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

Este método crea un archivo llamado go.moden su directorio de proyectos. Luego puede construir su proyecto con go build. Si GO111MODULE=autoestá configurado, entonces su proyecto no puede estar en $GOPATH.


Edición 2: el método de venta sigue siendo válido y funciona sin problemas. vendores en gran parte un proceso manual, por eso depy vgofueron creados.


Edición 1: Si bien mi antiguo método funciona, ya no es la forma "correcta" de hacerlo. Debería utilizar las capacidades del proveedorvgo , o dep(por ahora) que están habilitadas por defecto en Go 1.6; ver . Básicamente agrega sus paquetes "externos" o "dependientes" dentro de un vendordirectorio; Al compilar, el compilador usará estos paquetes primero.


Encontró. Pude importar el paquete local GOPATHcreando una subcarpeta package1y luego importando con import "./package1"in binary1.goy binary2.goscripts como este:

binary1.go

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

Entonces mi estructura de directorio actual se ve así:

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

También debo tener en cuenta que las rutas relativas (al menos en go 1.5) también funcionan; por ejemplo:

import "../packageX"

fuente
44
Eso funciona bien hasta que tenga dos subcarpetas con una que se refiera a otra. Por ejemplo, si package2 también era una subcarpeta y necesitaba package1, el sistema se rompe.
Carl
77
import "../package1"
Felix Rabe
12
Las rutas de importación relativas son una mala idea .
Dave C
1
si #golang proporciona 'espacio de nombres', puedo estar de acuerdo con usted en que 'ruta de importación relativa' o 'subpaquetes' son malas ideas '.
mission.liao
1
El nombre de la función debe comenzar con la palabra clave
Capitilized
71

No existe el "paquete local". La organización de paquetes en un disco es ortogonal a cualquier relación de paquetes padre / hijo. La única jerarquía real formada por paquetes es el árbol de dependencias, que en el caso general no refleja el árbol de directorios.

Solo usa

import "myproject/packageN"

y no luches contra el sistema de construcción sin una buena razón. Guardar una docena de caracteres por importación en cualquier programa no trivial no es una buena razón, porque, por ejemplo, los proyectos con rutas de importación relativas no se pueden obtener.

El concepto de rutas de importación tiene algunas propiedades importantes:

  • Las rutas de importación pueden ser globalmente únicas.
  • En conjunción con GOPATH, la ruta de importación se puede traducir inequívocamente a una ruta de directorio.
  • Cualquier ruta de directorio bajo GOPATH se puede traducir inequívocamente a una ruta de importación.

Todo lo anterior se arruina al usar rutas de importación relativas. No lo hagas.

PD: Hay pocos lugares en el código heredado en las pruebas del compilador Go que usan importaciones relativas. ATM, esta es la única razón por la cual las importaciones relativas son compatibles.

zzzz
fuente
2
Recomiendo echar un vistazo a este video de introducción para comprender mejor los paquetes y el GOPATH . youtube.com/watch?v=XCsL89YtqCs
Joshua Pinter
77
Creo que este es un mal consejo. Si termina usando gopkg.in para el control de versiones, por ejemplo, no tiene suerte con las rutas de importación absolutas para sus "mini" paquetes, como se describió anteriormente. O rompes el repositorio de origen o el versionado se vuelve inútil.
Greg
import "myproject/packageN". myprojectCuál es el nombre de la carpeta que contiene mi proyecto?
securecurve
Eso está completamente mal, ¿cómo lo uso ahora con repositorios privados?
agilob
44

Quizás estés intentando modularizar tu paquete. Supongo que package1y package2son, en cierto modo, parte del mismo paquete, pero para facilitar la lectura, los está dividiendo en varios archivos.

Si el caso anterior era suyo, podría usar el mismo nombre de paquete en esos archivos múltiples y sería como si hubiera el mismo archivo.

Esto es un ejemplo:

add.go

package math

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

restar.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
}

No soy un experto en Go y esta es mi primera publicación en StackOveflow, por lo que si tiene algún consejo, será bien recibido.

Juan jose tugores
fuente
23

Tengo un problema similar y la solución que estoy usando actualmente usa los módulos Go 1.11. Tengo la siguiente estructura

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

Y puedo importar package1 y package2 desde project1 y project2 usando

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

Después de ejecutar go mod init projects. Puedo usar go builddesde los directorios project1 y project2 o puedo hacerlo go build -o project1/exe project1/*.godesde el directorio de proyectos.

La desventaja de este método es que todos sus proyectos terminan compartiendo la misma lista de dependencias en go.mod. Todavía estoy buscando una solución a este problema, pero parece que podría ser fundamental.

Wombat loco
fuente
9

Desde la introducción de go.mod , creo que la administración de paquetes tanto locales como externos se vuelve más fácil. Usando go.mod , también es posible tener un proyecto fuera de GOPATH.

Importar paquete local:

Cree una carpeta demoproject y ejecute el siguiente comando para generar el archivo go.mod

go mod init demoproject

Tengo una estructura de proyecto como la siguiente dentro del directorio demoproject .

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

Para fines de demostración, inserte el siguiente código en el archivo model.go .

package model

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

En main.go , importé el modelo de empleado haciendo referencia a "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 dependencia externa:

Simplemente ejecute el go getcomando dentro del directorio del proyecto.

Por ejemplo:

go get -u google.golang.org/grpc

Debe incluir la dependencia del módulo en el archivo 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
fuente
can't load package: package .: no Go files in...(vaya a compilar en la carpeta de go.mod)
Sebi2020
Es una banalidad, pero me llevó una cantidad de tiempo embarazosa encontrar la respuesta y tu publicación fue la más legible y útil. ¡Gracias!
Harold Cavendish
8

Para agregar un paquete "local" a su proyecto, agregue una carpeta (por ejemplo, "nombre_paquete"). Y ponga sus archivos de implementación en esa carpeta.

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

En tus package main haz esto:

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

Dónde package_nameestá el nombre de la carpeta y debe coincidir con el nombre del paquete utilizado en los archivos whatever_name1.go y whatever_name2.go. En otras palabras, todos los archivos con un subdirectorio deben ser del mismo paquete.

Puede anidar más subdirectorios siempre que especifique la ruta completa a la carpeta principal en la importación.

Homan
fuente
2
Esta es una buena sugerencia, excepto que durante cualquier pánico del kernel, el seguimiento de la pila que se descarga del binario muestra la ruta de github.com, por ejemplo, no siempre el comportamiento más deseable. Hay indicadores para suprimir esto, pero no debería ser necesario solo para lograr una organización simple del paquete, y he descubierto que falla en ocasiones.
Kenny Powers
package myproject/package_name is not in GOROOT (/usr/lib/go-1.14/src/myproject/package_name)
Sebi2020
3

Puedes 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 un paquete local es como importar un paquete externo

excepto que dentro del archivo go.mod reemplaza el nombre del paquete externo con una carpeta local.

La ruta a la carpeta puede ser completa o relativa "/ ruta / a / bar" o "../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 -a-su-módulo-local /

Timo Huovinen
fuente