Comment importer des paquets locaux sans gopath

171

J'ai utilisé GOPATHmais pour ce problème actuel auquel je suis confronté, cela n'aide pas. Je souhaite pouvoir créer des packages spécifiques à un projet:

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

J'ai essayé plusieurs méthodes, mais comment puis-je package1.gotravailler dans le binary1.goou le binary2.goet ainsi de suite?

Par exemple; Je veux pouvoir import "package1", puis être en mesure de fonctionner go build binary1.goet tout fonctionne bien sans que l'erreur soit générée que le package ne peut pas être trouvé sur GOROOTou GOPATH. La raison pour laquelle j'ai besoin de ce type de fonctionnalité est pour les projets à grande échelle; Je ne veux pas avoir à référencer plusieurs autres packages ou à les conserver dans un seul gros fichier.

Flimzy
la source
2
Vous êtes censé mettre les fichiers source de chaque binaire dans son propre répertoire.
fuz le
Tous les .gofichiers d'un même répertoire font partie du même package et vous n'avez pas besoin de importfichiers dans le même package (c'est-à-dire le même répertoire). Vous avez mentionné travailler en dehors de GOPATH, qui est l'une des capacités du nouveau système de modules Go. Cette réponse couvre la structure du module, l'importation de packages locaux, l'organisation des packages dans un module, le fait d'avoir ou non plusieurs modules dans un seul référentiel, etc.
typique182
3
Et ce comportement convient-il à tout le monde? Que vous ne pouvez pas importer vos sous-packages locaux à moins que vous ne spécifiiez le git/repo/to/my/projectchemin complet ? Je ne vois tout simplement pas la raison pour laquelle quiconque voudrait ce comportement. Que faire si vous déplacez votre projet vers un autre emplacement (image Docker par exemple), vous devez à nouveau modifier tous les chemins? Je cherche des réponses sur les raisons pour lesquelles c'est si compliqué.
milosmns
@milosmns voir ma réponse stackoverflow.com/a/60915633/175071
Timo Huovinen

Réponses:

176

Go résumé de la gestion des dépendances:

  • vgo si votre version go est: x >= go 1.11
  • depou vendorsi votre version go est:go 1.6 >= x < go 1.11
  • Manuellement si votre version go est: x < go 1.6

Edit 3: Go 1.11 a une fonctionnalité vgoqui remplacera dep .

Pour l'utiliser vgo, consultez la documentation des modules . TLDR ci-dessous:

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

Cette méthode crée un fichier appelé go.moddans votre répertoire de projets. Vous pouvez ensuite créer votre projet avec go build. Si GO111MODULE=autoest défini, votre projet ne peut pas être au format $GOPATH.


Edit 2: La méthode de vente est toujours valide et fonctionne sans problème. vendorest en grande partie un processus manuel, à cause de cela depet vgoont été créés.


Edit 1: Bien que mon ancienne méthode fonctionne, ce n'est plus la manière «correcte» de le faire. Vous devez utiliser les fonctionnalités du fournisseurvgo , ou dep(pour l'instant) qui sont activées par défaut dans Go 1.6; voir . Vous ajoutez essentiellement vos packages "externes" ou "dépendants" dans un vendorrépertoire; lors de la compilation, le compilateur utilisera ces packages en premier.


A trouvé. J'ai pu importer un package local avec GOPATHen créant un sous-dossier de package1puis en important avec import "./package1"in binary1.goet des binary2.goscripts comme celui-ci:

binary1.go

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

Donc, ma structure de répertoires actuelle ressemble à ceci:

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

Je dois également noter que les chemins relatifs (au moins dans go 1.5) fonctionnent également; par exemple:

import "../packageX"

la source
4
Cela fonctionne bien jusqu'à ce que vous ayez deux sous-dossiers dont l'un se réfère à un autre. Par exemple, si package2 était également un sous-dossier et qu'il avait besoin de package1, le système s'arrête.
Carl
7
import "../package1"
Felix Rabe
12
Les chemins d'importation relatifs sont une mauvaise idée .
Dave C
1
si #golang fournit un 'espace de noms', je peux être d'accord avec vous que 'chemin d'importation relatif' ou 'sous-packages' sont de mauvaises idées '.
mission.liao
1
Le nom de la fonction doit commencer par le mot
capitilisé
71

Il n'existe pas de "paquet local". L'organisation des packages sur un disque est orthogonale à toute relation parent / enfant des packages. La seule véritable hiérarchie formée par les packages est l'arborescence des dépendances, qui dans le cas général ne reflète pas l'arborescence des répertoires.

Juste utiliser

import "myproject/packageN"

et ne combattez pas le système de construction sans raison valable. Enregistrer une douzaine de caractères par importation dans un programme non trivial n'est pas une bonne raison, car, par exemple, les projets avec des chemins d'importation relatifs ne sont pas accessibles.

Le concept des chemins d'importation a des propriétés importantes:

  • Les chemins d'importation peuvent être uniques au monde.
  • En conjonction avec GOPATH, le chemin d'importation peut être traduit sans ambiguïté en chemin de répertoire.
  • Tout chemin de répertoire sous GOPATH peut être traduit sans ambiguïté en chemin d'importation.

Tout ce qui précède est ruiné en utilisant des chemins d'importation relatifs. Ne fais pas ça.

PS: Il y a peu d'endroits dans le code hérité des tests du compilateur Go qui utilisent des importations relatives. ATM, c'est la seule raison pour laquelle les importations relatives sont prises en charge.

zzzz
la source
2
Je recommande de jeter un œil à cette vidéo d'introduction pour une meilleure compréhension des packages et du GOPATH . youtube.com/watch?v=XCsL89YtqCs
Joshua Pinter
7
Je pense que c'est un mauvais conseil. Si vous finissez par utiliser gopkg.in pour le contrôle de version, par exemple, vous n'avez pas de chance avec les chemins d'importation absolus pour vos "mini" paquets, comme décrit ci-dessus. Soit vous cassez le référentiel source, soit le référentiel versionné devient inutile.
Greg
import "myproject/packageN". myprojectest le nom du dossier qui contient mon projet?
securecurve
C'est complètement faux, comment puis-je l'utiliser avec des référentiels privés maintenant?
agilob
44

Vous essayez peut-être de modulariser votre package. Je suppose que package1et package2font, d'une certaine manière, partie du même package, mais pour plus de lisibilité, vous les divisez en plusieurs fichiers.

Si le cas précédent était le vôtre, vous pourriez utiliser le même nom de package dans ces multiples fichiers et ce sera comme s'il y avait le même fichier.

Ceci est un exemple:

add.go

package math

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

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

Je ne suis pas un expert de Go et c'est mon premier article dans StackOveflow, donc si vous avez des conseils, ils seront bien reçus.

Juan Jose Tugores
la source
23

J'ai un problème similaire et la solution que j'utilise actuellement utilise les modules Go 1.11. J'ai la structure suivante

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

Et je suis capable d'importer package1 et package2 à partir de project1 et project2 en utilisant

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

Après avoir couru go mod init projects. Je peux utiliser les go buildrépertoires project1 et project2 ou je peux le faire à go build -o project1/exe project1/*.gopartir du répertoire projets.

L'inconvénient de cette méthode est que tous vos projets finissent par partager la même liste de dépendances dans go.mod. Je cherche toujours une solution à ce problème, mais il semble que cela puisse être fondamental.

Wombat fou
la source
9

Depuis l'introduction de go.mod , je pense que la gestion des packages locaux et externes devient plus facile. Utilisation de go.mod , il est également possible d'avoir un projet go en dehors du GOPATH.

Importer le package local:

Créez un dossier demoproject et exécutez la commande suivante pour générer le fichier go.mod

go mod init demoproject

J'ai une structure de projet comme ci-dessous dans le répertoire demoproject .

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

À des fins de démonstration, insérez le code suivant dans le fichier model.go .

package model

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

Dans main.go , j'ai importé le modèle Employee en me référant à "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)
}

Importer une dépendance externe:

Exécutez simplement la go getcommande dans le répertoire du projet.

Par exemple:

go get -u google.golang.org/grpc

Il doit inclure la dépendance de module dans le fichier 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
la source
can't load package: package .: no Go files in...(aller dans le dossier go.mod)
Sebi2020
Une telle banalité mais il m'a fallu un temps embarrassant pour trouver la réponse et votre message était le plus lisible et le plus utile. Je vous remercie!
Harold Cavendish le
8

Pour ajouter un package "local" à votre projet, ajoutez un dossier (par exemple "package_name"). Et mettez vos fichiers d'implémentation dans ce dossier.

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

Dans votre package mainfaire ceci:

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

package_nameest le nom du dossier et il doit correspondre au nom du package utilisé dans les fichiers n'importe quel nom1.go et n'importe quel nom2.go. En d'autres termes, tous les fichiers avec un sous-répertoire doivent appartenir au même package.

Vous pouvez en outre imbriquer davantage de sous-répertoires tant que vous spécifiez le chemin d'accès complet au dossier parent lors de l'importation.

Homan
la source
2
C'est une bonne suggestion, sauf que pendant toute panique du noyau, la trace de la pile qui est vidée du binaire montre le chemin github.com par exemple, pas toujours le comportement le plus souhaitable. Il existe des indicateurs pour supprimer cela, mais cela ne devrait pas être nécessaire uniquement pour une organisation simple des paquets, et j'ai constaté que cela échouait à l'occasion.
Kenny Powers
package myproject/package_name is not in GOROOT (/usr/lib/go-1.14/src/myproject/package_name)
Sebi2020
3

Vous pouvez utiliser replace

go modo init example.com/my/foo

toto / 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

toto / 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")
}

L'importation d'un paquet local revient à importer un paquet externe

sauf dans le fichier go.mod, vous remplacez ce nom de package externe par un dossier local.

Le chemin d'accès au dossier peut être complet ou relatif "/ chemin / vers / 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 -à-votre-module-local /

Timo Huovinen
la source