Aller + = versionner le package

Article écrit en février 2018.

Go doit ajouter le contrôle de version des packages.

Plus précisément, vous devez ajouter le concept de versioning au dictionnaire de travail et aux outils des développeurs Go afin que tout le monde utilise les mêmes numéros de version lorsqu'ils mentionnent le programme à créer, exécuter ou analyser. La commande go doit indiquer exactement quelles versions de quels packages se trouvent dans un assembly particulier.

La numérotation des versions vous permet de créer des assemblages reproductibles: si je publie la dernière version de mon programme, vous obtiendrez non seulement la dernière version de mon code, mais aussi les mêmes versions exactes de tous les packages dont mon code dépend, afin que nous créons des fichiers binaires complètement équivalents.

Le contrôle de version garantit également que demain le programme sera construit exactement de la même manière qu'aujourd'hui. Même si de nouvelles versions des dépendances sont publiées, go ne les utilisera pas sans une commande spéciale.

Bien que vous deviez ajouter un contrôle de version, vous ne devez pas renoncer aux principaux avantages de la commande go : c'est la simplicité, la vitesse et la compréhensibilité. Aujourd'hui, de nombreux programmeurs ne font pas attention aux versions et tout fonctionne bien. Si vous faites le bon modèle, les programmeurs ne feront toujours pas attention aux numéros de version, tout fonctionnera mieux et deviendra plus clair. Les workflows existants changeront à peine. La sortie de nouvelles versions est très simple. En général, le contrôle de version doit être abandonné et ne pas détourner l'attention du développeur.

En bref, vous devez ajouter un contrôle de version du package, mais ne pas rompre. Dans cet article, nous suggérons comment procéder, et présentons également un prototype que vous pouvez essayer maintenant et qui, je l'espère, deviendra la base d'une éventuelle intégration go . J'espère que cet article sera le début d'une discussion productive sur ce qui fonctionne et ce qui ne fonctionne pas. Sur la base de cette discussion, je ferai des ajustements à la fois à ma proposition et au prototype, puis je présenterai la proposition officielle pour ajouter une fonction facultative à Go 1.11.

Cette proposition conserve tous les avantages de go get , mais ajoute des versions reproductibles, prend en charge le contrôle de version sémantique, élimine la commercialisation, supprime GOPATH au profit d'un flux de travail basé sur le projet et offre un départ en douceur de dep et de ses prédécesseurs. Cependant, cette proposition n'en est encore qu'à ses débuts. Si les détails ne sont pas corrects, nous les corrigerons avant que le travail n'entre dans la distribution principale de Go.

Situation générale


Avant d'examiner la proposition, regardons la situation actuelle et comment nous nous y sommes retrouvés. Cette section est peut-être un peu trop grande, mais l'histoire apporte des leçons importantes et aide à comprendre pourquoi nous voulons changer quelque chose. Si cela ne vous intéresse pas, vous pouvez immédiatement consulter l' offre ou lire l' article de blog qui l' accompagne avec un exemple .

Makefile , goinstall et go get


En novembre 2009, le compilateur, l'éditeur de liens et plusieurs bibliothèques ont été publiés avec la version initiale de Go. Pour compiler et lier les programmes, il a fallu exécuter 6g et 6l , et nous avons inclus des exemples de makefiles dans le kit. Le shell gobuild minimal pourrait compiler un paquet et écrire le makefile correspondant (dans la plupart des cas). Il n'y avait aucun moyen établi de partager le code avec d'autres. Nous savions que cela ne suffisait pas - mais nous avons publié ce que nous avions, en prévoyant de développer le reste avec la communauté.

En février 2010, nous avons proposé goinstall , une commande simple pour télécharger des packages à partir de référentiels de systèmes de contrôle de version tels que Bitbucket et GitHub. Goinstall introduit des conventions sur les chemins d'importation qui sont désormais généralement acceptées. Mais à cette époque, aucun code ne suivait ces conventions; goinstall au départ qu'avec des packages qui n'importaient que la bibliothèque standard. Mais les développeurs sont rapidement passés à un accord unique que nous connaissons aujourd'hui, et l'ensemble des packages Go publiés est devenu un écosystème holistique.

Goinstall a également corrigé les Makefiles, et avec eux la complexité des options de construction personnalisées. Bien qu'il soit parfois gênant que les auteurs de packages ne puissent pas générer de code lors de chaque génération, cette simplification est extrêmement importante pour les utilisateurs de packages: ils n'ont pas à s'inquiéter d'installer le même ensemble d'outils que l'auteur a utilisé. Cette simplification est également cruciale pour le fonctionnement des outils. Makefile est une recette étape par étape requise pour compiler un package; et l'application d'un autre outil comme go vet ou autocompletion au même package peut être assez difficile. Même obtenir des dépendances correctement, pour reconstruire des packages si nécessaire et seulement si nécessaire, est beaucoup plus compliqué avec des Makefiles arbitraires. Bien qu'à cette époque certaines personnes aient objecté qu'elles étaient privées de flexibilité, mais avec le recul, il devient clair que l'abandon du Makefile était la bonne étape: les avantages l'emportent de loin sur les inconvénients.

En décembre 2011, en préparation de Go 1, nous avons introduit la commande go , qui a remplacé goinstall par go get .

En général, go get introduit des changements importants: il a permis aux développeurs de go d'échanger du code source et d'utiliser le travail de chacun. Il a également isolé des parties du système de construction à l'intérieur de la commande go , de sorte qu'une automatisation importante à l'aide d'outils est devenue possible. Mais go get manquer du concept de contrôle de version. Dans les toutes premières discussions sur goinstall, il est devenu clair: vous devez faire quelque chose avec le contrôle de version. Malheureusement, on ne savait pas exactement quoi faire. Au moins, dans l'équipe Go, nous ne comprenions pas cela clairement. Lorsque go get demande un package, il obtient toujours la dernière copie, déléguant les opérations de téléchargement et de mise à jour à un système de contrôle de version tel que Git ou Mercurial. Un tel "travail aveugle" a entraîné au moins deux défauts importants.

Gestion des versions et stabilité de l'API


Le premier inconvénient majeur de go get est que sans le concept de contrôle de version, il ne peut rien dire à l'utilisateur des changements à attendre dans cette mise à jour.

En novembre 2013, une version de Go 1.2 a ajouté une entrée FAQ avec de tels conseils concernant la gestion des versions (le texte n'a pas changé pour la version Go 1.10):

Les packages à usage général devraient conserver une compatibilité ascendante à mesure qu'ils évoluent. Les recommandations de compatibilité de Go 1 sont pertinentes ici: ne supprimez pas les noms exportés, encouragez le balisage des littéraux composés, etc. Si une nouvelle fonctionnalité est requise, ajoutez un nouveau nom au lieu de changer l'ancien. En cas de changement fondamental, créez un nouveau package avec un nouveau chemin d'importation.

En mars 2014, Gustavo Niemeyer a lancé gopkg.in sous le couvert de "API stables pour le langage Go". Ce domaine est une redirection GitHub gopkg.in/yaml.v1 qui vous permet d'importer des chemins tels que gopkg.in/yaml.v1 et gopkg.in/yaml.v2 pour diverses gopkg.in/yaml.v2 (éventuellement dans différentes branches) d'un référentiel Git. Selon le versionnage sémantique, les auteurs devraient, lorsqu'ils apportent des modifications critiques, publier une nouvelle version majeure. Ainsi, les versions ultérieures du chemin d'importation v1 remplacent les précédentes et v2 peut donner des API complètement différentes.

En août 2015, Dave Cheney a soumis une proposition de contrôle de version sémantique . Au cours des prochains mois, cela a provoqué une discussion intéressante: tout le monde semblait d'accord pour dire que le balisage sémantique des versions est une excellente idée, mais personne ne savait comment les outils devraient fonctionner avec ces versions.

Tous les arguments pour le versioning sémantique seront inévitablement critiqués en référence à la loi d' Hyrum :

Le contrat de votre API devient sans importance avec un nombre suffisant d'utilisateurs. Quelqu'un dépend de tout comportement observé du système.

Bien que la loi de Hyrum soit empiriquement correcte, le contrôle de version sémantique est toujours un moyen utile de générer des attentes sur la relation entre les versions. Une mise à niveau de 1.2.3 à 1.2.4 ne devrait pas casser votre code, et une mise à niveau de 1.2.3 à 2.0.0 pourrait très bien. Si le code cesse de fonctionner après la mise à jour vers 1.2.4, l'auteur acceptera très probablement un rapport de bogue et corrigera l'erreur dans la version 1.2.5. Si le code a cessé de fonctionner (ou même compilé) après la mise à jour vers 2.0.0, alors ce changement était beaucoup plus susceptible d'être intentionnel et, en conséquence, il est peu probable que quelque chose soit corrigé dans 2.0.1.

Je ne veux pas conclure de la loi de Hiram que le versioning sémantique est impossible. Au lieu de cela, je crois que les assemblys doivent être utilisés avec précaution, en utilisant exactement les mêmes versions de chaque dépendance que l'auteur. Autrement dit, l'assemblage par défaut doit être aussi reproductible que possible.

Assemblages distributeurs et reproductibles


Le deuxième inconvénient majeur de go get est que sans le concept de contrôle de version, une équipe ne peut pas fournir et même exprimer l'idée d'une construction reproductible. Vous ne pouvez pas être sûr que les utilisateurs compilent la même version des dépendances de code que vous. En novembre 2013, la FAQ suivante a été ajoutée à la FAQ pour Go 1.2:

Si vous utilisez un package externe et craignez qu'il ne change de façon inattendue, la solution la plus simple consiste à le copier dans le référentiel local (cette approche est utilisée par Google). Enregistrez une copie avec un nouveau chemin d'importation qui l'identifie comme une copie locale. Par exemple, vous pouvez copier original.com/pkg sur you.com/external/original.com/pkg . L'un des outils de cette procédure est le goven de Kit Rerik.

Keith Rarik a démarré ce projet en mars 2012. L'utilitaire goven copie la dépendance dans le référentiel local et met à jour tous les chemins d'importation pour refléter le nouvel emplacement. De tels changements de code source sont nécessaires, mais désagréables. Ils rendent difficile la comparaison et l'inclusion de nouvelles copies, et nécessitent également la mise à jour d'autres codes copiés à l'aide de cette dépendance.

En septembre 2013, Keith a introduit godep , "un nouvel outil pour corriger les dépendances des packages". La principale réalisation de godep été ce que nous appelons maintenant la vente, c'est-à-dire la copie des dépendances dans le projet sans changer les fichiers source, sans prise en charge directe des outils, en définissant GOPATH d'une certaine manière.

En octobre 2014, Keith a proposé d'ajouter la prise en charge des «packages externes» aux outils Go afin que les outils comprennent mieux les projets utilisant cette convention. À ce moment-là, plusieurs godep style godep étaient déjà apparus. Matt Farina a publié un article godep « godep gestionnaires de godep Sea of ​​Go» comparant godep aux godep , en particulier la glide .

En avril 2015, Dave Cheney a introduit gb , "un outil de construction basé sur un projet ... avec des générations répétées via la vente à la source", encore une fois sans réécrire les chemins d'importation (une autre motivation pour créer gb était d'éviter la nécessité de stocker du code dans des répertoires spécifiques dans GOPATH ce qui n'est pas toujours pratique).

Ce printemps-là, Jason Buberlie a examiné la situation des systèmes de gestion de packages Go, y compris la duplication d'efforts multiples et le travail vain sur des utilitaires similaires. Son enquête a clairement montré aux développeurs que la prise en charge de la vente sans réécrire les chemins d'importation doit être ajoutée à la commande go . Dans le même temps, Daniel Theofanes a commencé à préparer des spécifications pour un format de fichier qui décrit l'origine exacte et la version du code dans le répertoire du fournisseur. En juin 2015, nous avons accepté la proposition de Keith comme une expérience de vente dans Go 1.5 , qui était incluse par défaut dans Go 1.6. Nous avons encouragé les auteurs de tous les outils de vente à travailler avec Daniel pour adopter un format de fichier de métadonnées unique.

L'introduction du concept de vente dans Go a permis à des outils comme le vet d'analyser les programmes de manière plus compétente, et aujourd'hui il a été utilisé par une douzaine ou deux gestionnaires de packages ou outils de vente. En revanche, comme tout le monde a des formats de métadonnées différents, ils n'interagissent pas et ne peuvent pas facilement échanger des informations de dépendance.

Plus fondamentalement, la vente est une solution incomplète au problème du contrôle de version. Il fournit uniquement la reproductibilité de l'assemblage, mais n'aide pas à comprendre les versions du package et à décider laquelle utiliser. Les gestionnaires de packages comme glide et dep ajoutent implicitement le concept de contrôle de version à Go, configurant le répertoire des fournisseurs d'une certaine manière. Par conséquent, de nombreux outils de l'écosystème Go peuvent ne pas être en mesure d'obtenir les informations de version correctes. Il est clair que Go a besoin d'un support direct pour les versions de packages.

Expérience de gestion des packages officiels


Lors de GopherCon 2016 le Hack Day (maintenant Community Day), un groupe de militants de Go s'est réuni pour discuter largement des problèmes de gestion des packages . L'un des résultats a été la formation d'un comité et d'un groupe consultatif pour mener une gamme d'activités dans le but de créer un nouvel outil de gestion des colis . L'idée était qu'un outil unifié remplace les outils existants, bien qu'il soit toujours implémenté en dehors de la boîte à outils directe de Go à l'aide de catalogues de fournisseurs. Le comité comprenait Andrew Gerrand, Ed Muller, Jesse Frazel et Sam Boyer, dirigé par Peter Burgon. Ils ont préparé un projet de spécification , puis Sam et ses assistants ont mis en œuvre le dep . Pour une compréhension de la situation générale, voir l'article de Sam de février 2016, «So You Want to Write a Package Manager», son article de décembre 2016 «Go Dependency Management Saga», et son discours de juillet 2017 à GopherCon, «A New Era of Package Management in Allez . "

Dep effectue de nombreuses tâches: il s'agit d'une amélioration importante par rapport aux pratiques actuelles. Il s'agit d'une étape importante vers une solution future, et en même temps une expérience - nous l'appelons une «expérience officielle» - qui nous aide à mieux comprendre les besoins des développeurs. Mais dep pas un prototype direct de l'intégration possible des commandes go dans la gestion des versions des packages. Il s'agit d'un moyen puissant, flexible et presque universel d'explorer l'espace des décisions de conception. Il est similaire aux makefiles que nous avons combattus au tout début. Mais dès que nous comprendrons mieux l'espace des décisions de conception et que nous pourrons le réduire à quelques fonctions clés qui devraient être prises en charge, cela aidera l'écosystème Go à supprimer d'autres fonctions, à réduire l'expressivité et à adopter des conventions contraignantes qui rendent les bases de code Go plus cohérentes et plus faciles à comprendre.

Cet article est le début de la prochaine étape après dep : le premier prototype de l'intégration finale avec la commande go , l'équivalent batch de goinstall . Un prototype est une commande distincte que nous appelons vgo : un remplacement go avec prise en charge de la gestion des versions des packages. Il s'agit d'une nouvelle expérience, et nous verrons ce qui en sortira. Comme lors de l'annonce de goinstall , certains projets et codes sont désormais compatibles avec vgo , tandis que d'autres nécessitent des modifications. Nous supprimerons un certain contrôle et expressivité, tout comme les makefiles ont été supprimés afin de simplifier le système et d'éliminer la complexité pour les utilisateurs. Plus important encore, nous recherchons des pionniers qui aideront à expérimenter avec vgo pour obtenir le plus d'avis possible.

Démarrer une expérience avec vgo ne signifie pas arrêter le support dep : il restera disponible jusqu'à ce que nous vgo une intégration complète et ouverte avec go . Nous essaierons également de faire la transition finale de dep à intégration avec go aussi fluide que possible, sous quelque forme que se fasse cette intégration. Les projets qui n'ont pas encore été convertis en dep peuvent encore bénéficier de cette conversion (notez que godep et glide arrêté le développement actif et encouragent la migration vers dep). Peut-être que certains projets voudront passer directement à vgo si cela répond à leurs besoins.

Offrir


La proposition d'ajouter un contrôle de version à la commande go compose de quatre étapes. Tout d'abord, acceptez la règle de compatibilité d'importation , qui est indiquée par la FAQ et gopkg.in: les versions plus récentes du package avec le chemin d'importation spécifié doivent être rétrocompatibles avec les versions plus anciennes. Deuxièmement, adoptez un nouvel algorithme simple, connu sous le nom de choix de la version minimale pour déterminer quelles versions du package sont utilisées dans cet assemblage. Troisièmement, introduisez le concept du module Go: des groupes de packages qui sont versionnés dans leur ensemble et déclarent les exigences minimales qui doivent être satisfaites par leurs dépendances. Quatrièmement, déterminez comment intégrer tout cela dans votre commande go existante afin que les flux de travail de base ne changent pas de manière significative à partir d'aujourd'hui. Dans le reste de cet article, nous examinons chacune de ces étapes. Ils sont discutés plus en détail dans d' autres articles de blog .

Règle de compatibilité d'importation


Le principal problème avec les systèmes de gestion de packages est la tentative de résolution des incompatibilités. Par exemple, la plupart des systèmes autorisent le package B à déclarer qu'il a besoin du package D de la version 6 ou ultérieure, puis autorisent le package C à déclarer qu'il requiert D la version 2, 3 ou 4, mais pas la version 5 ou ultérieure. Ainsi, si vous souhaitez utiliser B et C dans votre package, vous n'avez pas de chance: vous ne pouvez sélectionner aucune version de D qui remplit les deux conditions et vous ne pouvez rien faire.

Au lieu d'un système qui bloque inévitablement l'assemblage de grands programmes, notre proposition introduit une règle de compatibilité à l'importation pour les auteurs de packages:

Si l'ancien et le nouveau package ont le même chemin d'importation, le nouveau package doit être rétrocompatible avec l'ancien package.

La règle répète la FAQ mentionnée précédemment. Ce texte se terminait par les mots: "En cas de changement radical, créez un nouveau package avec un nouveau chemin d'importation." , . , :

 import "github.com/go-yaml/yaml/v2" 

2.0.0 , . , Go . . v1 v2.

, . , , , . . .


, dep cargo , . , . -, « » - , - . , - , , , . -, , , «, X», X .

, . . , . , , . , , , , , .

. , , , . , , , , . , - . , , .

.

— . «, », «, ». : () . .

Go


Go , . , . Git , Git . , .

go.mod , . , go.mod :

 // My hello, world. module "rsc.io/hello" require ( "golang.org/x/text" v0.0.0-20180208041248-4e4a3210bb54 "rsc.io/quote" v1.5.2 ) 

, rsc.io/hello , : golang.org/x/text rsc.io/quote . , go.mod . , - .

, vgo , . rsc.io/quote , github.com/rsc/quote , , 1.5.2. golang.org/x/text . , v0.0.0-yyyymmddhhmmss-commit . v0.0.0 yyyymmddhhmmss-commit . , v0.0.0, . , .

, go.mod , , , . .

Goinstall go get , git hg , , . , bzr Bazaar. , Go HTTP zip-. go get . vgo API .

zip- - . -, . go.mod , , .

go


go . , , go build , go install , go run go test , . golang.org/x/text Go .

— GOPATH . go.mod , , go.mod , , . git clone , cd , . . GOPATH.

?


« Go» , vgo . , vgo . . .

, vgo . . go.mod . , go.mod , dep , glide , glock , godep , godeps , govend , govendor gvt , vgo go.mod .

, Go . , Go, — , go get , GOPATH GOPATH. .

- . , , vgo . , Go 1.11 Go, , Go 1.12 . , go get . , , .

go get . , . , , .

Source: https://habr.com/ru/post/fr442272/


All Articles