web-dev-qa-db-fra.com

Organiser le code local dans des packages à l'aide de modules Go

Je ne trouve pas de moyen de factoriser du code à partir de main.go dans un package local lors de l'utilisation de modules Go (version go> = 1.11) en dehors de $GOPATH.

Je n'importe pas de dépendances externes qui doivent être incluses dans go.mod, J'essaie juste d'organiser localement le code source de ce module Go.

Le fichier main.go:

package main

// this import does not work
import "./stuff"

func main() {
    stuff.PrintBaz()
}

Le fichier ./stuff/bar.go (faisant semblant d'être un package local):

package stuff

import "log"

type Bar struct {
    Baz int
}

func PrintBaz() {
    baz := Bar{42}
    log.Printf("Bar struct: %v", baz)
}

Le fichier go.mod (commande go mod init foo):

module foo

go 1.12

Lors de l'exécution de go run main.go:

  • Si je import "./stuff", alors je vois build command-line-arguments: cannot find module for path _/home/<PATH_TO>/fooprj/stuff.
  • Si je import "stuff", alors je vois build command-line-arguments: cannot load stuff: cannot find module providing package stuff.
  • Si je import stuff "./stuff" avec un alias de package, puis je revois: build command-line-arguments: cannot find module for path _/home/<PATH_TO>/fooprj/stuff.

Je ne trouve pas de moyen de faire fonctionner les packages locaux avec les modules go.

  • Quel est le problème avec le code ci-dessus?
  • Comment puis-je importer des packages locaux dans un autre code Go à l'intérieur d'un projet défini avec des modules Go (fichier go.mod)?
18
TPPZ

Vous devez d'abord choisir un nom pour votre projet et l'écrire dans le fichier go.mod. Ce nom appartient au répertoire racine du projet. Chaque nouveau package que vous créez doit se trouver dans son propre sous-répertoire et son nom doit correspondre au nom du répertoire.

go.mod:

module myprojectname

ou (manière préférée, voir @ typique182 réponse ci-dessous pour plus de détails)

module github.com/myname/myproject

Importez ensuite les packages de votre projet comme:

import myprojectname/stuff

ou

import github.com/myname/myproject/stuff

Les fichiers du package stuff doivent se trouver dans le répertoire stuff du projet. Vous nommez ces fichiers comme vous le souhaitez.

Il est également possible de créer une structure de projet plus profonde. Par exemple, vous avez décidé de séparer les fichiers de code source des autres (comme les configurations d'applications, les fichiers docker, les fichiers statiques, etc.). Déplaçons le répertoire stuff dans pkg, chaque fichier go dans pkg/stuff ont toujours stuff nom du package. Pour importer un paquet de trucs, écrivez simplement:

import myprojectname/pkg/stuff

Rien ne vous empêche de créer plus de niveaux dans la hiérarchie comme github.com/myuser/myproject/pkg/db/provider/postgresql, où:

  • github.com/myuser/myproject - nom du projet.
  • postgresql - nom du package.
  • pkg/db/provider/postgresql - chemin vers le package par rapport à la racine du projet.

Vous pouvez en savoir plus sur les modules go ici: https://github.com/golang/go/wiki/Modules

Consultez ce référentiel pour obtenir des informations utiles sur les différents modèles utilisés dans l'organisation de projet: https://github.com/golang-standards/project-layout Si vous allez dans le répertoire pkg vous va découvrir quels projets open source utilisent le répertoire pkg dans leur structure.

20
Vadim Ashikhman

Structure du module

L'approche la plus courante et la plus simple est:

  • Utilisez un seul go.mod par référentiel, et
  • Placez le single go.mod fichier dans la racine du référentiel, et
  • Utilisez le nom du référentiel comme chemin du module déclaré dans la ligne module dans le go.mod
    • (Si vous utilisez un chemin d'importation personnalisé tel que me.io/mymod plutôt que d'utiliser un chemin d'importation basé sur l'hôte VCS, vous utiliseriez le chemin d'importation personnalisé au lieu du nom du référentiel dans votre go.mod).

Par exemple, si votre dépôt est github.com/my/repo, vous placez un seul go.mod dans la racine du référentiel, la première ligne indiquant module github.com/my/repo. Cela peut être créé en cd 'à la racine du référentiel et en exécutant go mod init github.com/my/repo.

Suivre cela vous aide à rester sur la bonne voie avec les modules, et cela évite plusieurs subtilités.

Russ Cox a commenté dans # 26664 :

Pour tous, sauf les utilisateurs expérimentés, vous souhaiterez probablement adopter la convention habituelle selon laquelle un dépôt = un module. Il est important pour l'évolution à long terme des options de stockage de code qu'un dépôt peut contienne plusieurs modules, mais ce n'est certainement pas quelque chose que vous voulez faire par défaut.

Il y a beaucoup plus sur les référentiels multi-modules dans la "Référentiels multi-modules" FAQ section sur le wiki des modules. Ces 6 ou plus FAQ dans cette section devraient être lues dans leur intégralité par quiconque envisage de déroger à la recommandation ci-dessus.

Organisation des packages dans un module

Une fois que vous avez configuré votre go.mod, vous pouvez organiser vos packages dans des répertoires comme bon vous semble dans des répertoires sous le répertoire contenant le go.mod, ainsi que dans le répertoire avec le go.mod. Trois bons articles sur la façon d'organiser votre code dans des packages:

Ces articles sont des classiques qui sont antérieurs à l'introduction des modules, mais les philosophies qu'ils contiennent s'appliquent toujours à la façon d'organiser vos packages dans un module.

Importer d'autres packages dans le même module

Lorsque vous importez un autre package avec des modules, vous utilisez toujours le chemin complet, y compris le chemin du module. Cela est vrai même lors de l'importation d'un autre package dans le même module. Par exemple, si un module a déclaré son identité dans son go.mod comme module github.com/my/repo, et vous aviez cette organisation:

repo/
├── go.mod      <<<<< Note go.mod is located in repo root
├── pkg1
│   └── pkg1.go
└── pkg2
    └── pkg1.go

Ensuite pkg1 importerait son package homologue en tant que import "github.com/my/repo/pkg2". Notez que vous ne pouvez pas utiliser des chemins d'importation relatifs comme import "../pkg2" ou import "./subpkg". (Cela fait partie de ce que OP a frappé ci-dessus avec import "./stuff").

Modules vs référentiels vs packages vs chemins d'importation

Un module Go est une collection de packages Go associés qui sont versionnés ensemble comme une seule unité. Les modules enregistrent des exigences de dépendance précises et créent des versions reproductibles.

Résumé de la relation entre les référentiels, les modules et les packages:

  • Un référentiel contient un ou plusieurs Go modules (le plus souvent exactement un module dans la racine du référentiel).
  • Chaque module contient un ou plusieurs Go packages.
  • Chaque paquet consiste en un ou plusieurs Go fichiers source qui résident tous dans un répertoire unique.
  • Allez le code source:
    • déclare son propre package avec un package foo déclaration.
    • a automatiquement accès à un autre code source Go dans le même package.
    • importe le code d'un autre paquet via un chemin d'importation fourni dans une instruction d'importation telle que import "github.com/my/repo/pkg1". Le chemin d'importation commence toujours par le chemin de module de ce package, que ce package se trouve dans le même module ou dans un module différent.
22
typical182