Personnalisation des fichiers binaires Go avec les balises de construction

introduction

Dans Go, unbuild tag, ou une contrainte de construction, est un identifiant ajouté à un morceau de code qui détermine quand le fichier doit être inclus dans un package pendant le processusbuild. Cela vous permet de créer différentes versions de votre application Go à partir du même code source et de basculer entre elles de manière rapide et organisée. De nombreux développeurs utilisent des balises de construction pour améliorer le flux de travail de la création d'applications compatibles multiplates-formes, telles que des programmes nécessitant des modifications de code pour prendre en compte les écarts entre différents systèmes d'exploitation. Les balises de construction sont également utilisées pour lesintegration testing, vous permettant de basculer rapidement entre le code intégré et le code avec unmock service or stub, et pour différents niveaux d'ensembles de fonctionnalités au sein d'une application.

Prenons comme exemple le problème des différents ensembles de fonctionnalités client. Lors de l'écriture de certaines applications, vous souhaiterez peut-être contrôler les fonctionnalités à inclure dans le binaire, comme une application qui offre les niveauxFree,Pro etEnterprise. Au fur et à mesure que le client augmente son niveau d'abonnement dans ces applications, davantage de fonctionnalités sont déverrouillées et disponibles. Pour résoudre ce problème, vous pouvez gérer des projets séparés et essayer de les synchroniser les uns avec les autres en utilisant les instructionsimport. Bien que cette approche puisse fonctionner, elle deviendrait avec le temps fastidieuse et sujette aux erreurs. Une approche alternative consisterait à utiliser des balises de construction.

Dans cet article, vous utiliserez les balises de construction dans Go pour générer différents fichiers binaires exécutables proposant les jeux de fonctionnalités Free, Pro et Enterprise d'un exemple d'application. Chacune disposera d'un ensemble de fonctionnalités différent, la version gratuite étant la version par défaut.

Conditions préalables

Pour suivre l'exemple de cet article, vous aurez besoin de:

Construire la version gratuite

Commençons par créer la version gratuite de l'application, car ce sera la valeur par défaut lors de l'exécution dego build sans aucune balise de construction. Plus tard, nous utiliserons des balises de construction pour ajouter sélectivement d’autres parties à notre programme.

Dans le répertoiresrc, créez un dossier avec le nom de votre application. Ce tutoriel utiliseraapp:

mkdir app

Déplacer dans ce dossier:

cd app

Ensuite, créez un nouveau fichier texte dans l'éditeur de texte de votre choix nommémain.go:

nano main.go

Nous allons maintenant définir la version gratuite de l’application. Ajoutez le contenu suivant àmain.go:

main.go

package main

import "fmt"

var features = []string{
  "Free Feature #1",
  "Free Feature #2",
}

func main() {
  for _, f := range features {
    fmt.Println(">", f)
  }
}

Dans ce fichier, nous avons créé un programme qui déclare unslice nomméfeatures, qui contient deuxstrings qui représentent les fonctionnalités de notre application gratuite. La fonctionmain() de l'application utilise unfor loop to range à travers la tranchefeatures et imprime toutes les fonctionnalités disponibles à l'écran.

Enregistrez et quittez le fichier. Maintenant que ce fichier est enregistré, il ne sera plus nécessaire de le modifier pour le reste de l'article. Au lieu de cela, nous utiliserons des balises de construction pour modifier les fonctionnalités des fichiers binaires que nous allons créer à partir de celles-ci.

Construisez et exécutez le programme:

go build
./app

Vous recevrez le résultat suivant:

Output> Free Feature #1
> Free Feature #2

Le programme a imprimé nos deux fonctionnalités gratuites, complétant ainsi la version gratuite de notre application.

Jusqu'à présent, vous avez créé une application comportant un ensemble de fonctionnalités très basiques. Ensuite, vous allez créer un moyen d’ajouter plus de fonctionnalités à l’application au moment de la construction.

Ajout des fonctionnalités Pro avecgo build

Nous avons jusqu'à présent évité d'apporter des modifications àmain.go, en simulant un environnement de production commun dans lequel du code doit être ajouté sans changer et éventuellement casser le code principal. Comme nous ne pouvons pas modifier le fichiermain.go, nous devrons utiliser un autre mécanisme pour injecter plus de fonctionnalités dans la tranchefeatures à l'aide de balises de construction.

Créons un nouveau fichier appelépro.go qui utilisera une fonctioninit() pour ajouter plus de fonctionnalités à la tranchefeatures:

nano pro.go

Une fois que l'éditeur a ouvert le fichier, ajoutez les lignes suivantes:

pro.go

package main

func init() {
  features = append(features,
    "Pro Feature #1",
    "Pro Feature #2",
  )
}

Dans ce code, nous avons utiliséinit() pour exécuter du code avant la fonctionmain() de notre application, suivi deappend() pour ajouter les fonctionnalités Pro à la tranchefeatures. Enregistrez et quittez le fichier.

Compilez et exécutez l'application en utilisantgo build:

go build

Puisqu'il y a maintenant deux fichiers dans notre répertoire courant (pro.go etmain.go),go build créera un binaire à partir des deux. Exécutez ce binaire:

./app

Cela vous donnera le jeu de fonctionnalités suivant:

Output> Free Feature #1
> Free Feature #2
> Pro Feature #1
> Pro Feature #2

L'application inclut désormais les fonctionnalités Pro et Free. Toutefois, cela n’est pas souhaitable: étant donné qu’il n’ya pas de distinction entre les versions, la version gratuite inclut désormais les fonctionnalités supposées être disponibles uniquement dans la version Pro. Pour résoudre ce problème, vous pouvez inclure plus de code pour gérer les différents niveaux de l'application, ou vous pouvez utiliser des balises de construction pour indiquer à la chaîne d'outils Go les fichiers.go à construire et ceux à ignorer. Ajoutons des balises de construction à l’étape suivante.

Ajout de balises de construction

Vous pouvez maintenant utiliser les balises de construction pour distinguer la version Pro de votre application de la version gratuite.

Commençons par examiner à quoi ressemble une balise de construction:

// +build tag_name

En mettant cette ligne de code comme première ligne de votre package et en remplaçanttag_name par le nom de votre balise de construction, vous marquerez ce package comme un code pouvant être inclus de manière sélective dans le binaire final. Voyons cela en action en ajoutant une balise de construction au fichierpro.go pour indiquer à la commandego build de l'ignorer à moins que la balise ne soit spécifiée. Ouvrez le fichier dans votre éditeur de texte:

nano pro.go

Ajoutez ensuite la ligne en surbrillance suivante:

pro.go

// +build pro

package main

func init() {
  features = append(features,
    "Pro Feature #1",
    "Pro Feature #2",
  )
}

En haut du fichierpro.go, nous avons ajouté// +build pro suivi d'un saut de ligne vide. Cette nouvelle ligne est obligatoire, sinon Go l'interprète comme un commentaire. Les déclarations de balises de construction doivent également être tout en haut d'un fichier.go. Rien, pas même les commentaires, ne peut être supérieur aux balises de construction.

La déclaration+build indique à la commandego build que ce n'est pas un commentaire, mais plutôt une balise de construction. La deuxième partie est la balisepro. En ajoutant cette balise en haut du fichierpro.go, la commandego build n'inclura désormais que le fichierpro.go avec la balisepro est présente.

Compilez et exécutez l'application à nouveau:

go build
./app

Vous recevrez le résultat suivant:

Output> Free Feature #1
> Free Feature #2

Étant donné que le fichierpro.go nécessite la présence d'une balisepro, le fichier est ignoré et l'application se compile sans elle.

Lors de l'exécution de la commandego build, nous pouvons utiliser l'indicateur-tags pour inclure conditionnellement du code dans la source compilée en ajoutant la balise elle-même comme argument. Faisons ceci pour le tagpro:

go build -tags pro

Cela produira les éléments suivants:

Output> Free Feature #1
> Free Feature #2
> Pro Feature #1
> Pro Feature #2

Désormais, nous n'obtenons les fonctionnalités supplémentaires que lorsque nous construisons l'application en utilisant la balise de constructionpro.

C'est bien s'il n'y a que deux versions, mais les choses se compliquent lorsque vous ajoutez plus de balises. Pour ajouter la version Enterprise de notre application à l'étape suivante, nous utiliserons plusieurs balises de construction associées à une logique booléenne.

Construire une logique booléenne

Lorsqu'il y a plusieurs balises de construction dans un package Go, les balises interagissent les unes avec les autres à l'aide deBoolean logic. Pour démontrer cela, nous ajouterons le niveau Entreprise de notre application en utilisant à la fois la balisepro et la baliseenterprise.

Pour créer un binaire d'entreprise, nous devrons inclure à la fois les fonctionnalités par défaut, les fonctionnalités de niveau Pro et un nouvel ensemble de fonctionnalités pour l'entreprise. Tout d'abord, ouvrez un éditeur et créez un nouveau fichier,enterprise.go, qui ajoutera les nouvelles fonctionnalités Enterprise:

nano enterprise.go

Le contenu deenterprise.go semblera presque identique àpro.go mais contiendra de nouvelles fonctionnalités. Ajoutez les lignes suivantes au fichier:

enterprise.go

package main

func init() {
  features = append(features,
    "Enterprise Feature #1",
    "Enterprise Feature #2",
  )
}

Enregistrez et quittez le fichier.

Actuellement, le fichierenterprise.go n'a pas de balises de construction, et comme vous l'avez appris lorsque vous avez ajoutépro.go, cela signifie que ces fonctionnalités seront ajoutées à la version gratuite lors de l'exécution dego.build. Pourpro.go, vous avez ajouté// +build pro et une nouvelle ligne en haut du fichier pour indiquer àgo build qu'il ne doit être inclus que lorsque-tags pro est utilisé. Dans cette situation, vous n'aviez besoin que d'une seule balise de construction pour atteindre l'objectif. Lors de l’ajout des nouvelles fonctionnalités Enterprise, vous devez d’abord disposer des fonctionnalités Pro.

Ajoutons d'abord la prise en charge de la balise de constructionpro àenterprise.go. Ouvrez le fichier avec votre éditeur de texte:

nano enterprise.go

Ensuite, ajoutez la balise de construction avant la déclarationpackage main et assurez-vous d'inclure une nouvelle ligne après la balise de construction:

enterprise.go

// +build pro

package main

func init() {
  features = append(features,
    "Enterprise Feature #1",
    "Enterprise Feature #2",
  )
}

Enregistrez et quittez le fichier.

Compilez et exécutez l'application sans balises:

go build
./app

Vous recevrez le résultat suivant:

Output> Free Feature #1
> Free Feature #2

Les fonctionnalités d'entreprise n'apparaissent plus dans la version gratuite. Ajoutons maintenant la balise de constructionpro, puis construisons et exécutons à nouveau l'application:

go build -tags pro
./app

Vous recevrez le résultat suivant:

Output> Free Feature #1
> Free Feature #2
> Enterprise Feature #1
> Enterprise Feature #2
> Pro Feature #1
> Pro Feature #2

Ce n’est pas encore exactement ce dont nous avons besoin: les fonctionnalités d’entreprise apparaissent maintenant lorsque nous essayons de créer la version Pro. Pour résoudre ce problème, nous devons utiliser une autre balise de construction. Contrairement à la balisepro, cependant, nous devons maintenant nous assurer que les fonctionnalitéspro etenterprise sont disponibles.

Le système de génération Go rend compte de cette situation en permettant l'utilisation d'une logique booléenne de base dans le système de balises de construction.

Ouvrons à nouveauenterprise.go:

nano enterprise.go

Ajoutez une autre balise de construction,enterprise, sur la même ligne que la balisepro:

enterprise.go

// +build pro enterprise

package main

func init() {
  features = append(features,
    "Enterprise Feature #1",
    "Enterprise Feature #2",
  )
}

Enregistrez et fermez le fichier.

Maintenant, compilons et exécutons l'application avec la nouvelle balise de constructionenterprise.

go build -tags enterprise
./app

Cela donnera ce qui suit:

Output> Free Feature #1
> Free Feature #2
> Enterprise Feature #1
> Enterprise Feature #2

Maintenant, nous avons perdu les fonctionnalités Pro. En effet, lorsque nous mettons plusieurs balises de construction sur la même ligne dans un fichier.go,go build les interprète comme utilisant la logiqueOR. Avec l'ajout de la ligne// +build pro enterprise, le fichierenterprise.go sera construit sieither la balise de constructionpro ou la balise de constructionenterprise est présente. Nous devons configurer correctement les balises de construction pour exigerboth et utiliser la logiqueAND à la place.

Au lieu de mettre les deux balises sur la même ligne, si nous les mettons sur des lignes séparées, alorsgo build interprétera ces balises en utilisant la logiqueAND.

Ouvrez à nouveauenterprise.go et séparons les balises de construction sur plusieurs lignes.

enterprise.go

// +build pro
// +build enterprise

package main

func init() {
  features = append(features,
    "Enterprise Feature #1",
    "Enterprise Feature #2",
  )
}

Maintenant, compilez et exécutez l'application avec la nouvelle balise de constructionenterprise.

go build -tags enterprise
./app

Vous recevrez le résultat suivant:

Output> Free Feature #1
> Free Feature #2

Pas encore tout à fait là: comme une instructionAND nécessite que les deux éléments soient considérés commetrue, nous devons utiliser les balises de constructionpro etenterprise.

Essayons encore:

go build -tags "enterprise pro"
./app

Vous recevrez le résultat suivant:

Output> Free Feature #1
> Free Feature #2
> Enterprise Feature #1
> Enterprise Feature #2
> Pro Feature #1
> Pro Feature #2

Maintenant, notre application peut être construite à partir du même arbre source de plusieurs manières, ce qui permet de déverrouiller les fonctionnalités de l'application en conséquence.

Dans cet exemple, nous avons utilisé une nouvelle balise// +build pour signifier la logiqueAND, mais il existe d'autres façons de représenter la logique booléenne avec des balises de construction. Le tableau suivant contient quelques exemples de mise en forme syntaxique pour les balises de construction, ainsi que leur équivalent booléen:

Syntaxe de la balise de construction Exemple de balise de construction Instruction booléenne

Éléments séparés par des espaces

// +build pro enterprise

pro OUenterprise

Éléments séparés par des virgules

// +build pro,enterprise

pro ETenterprise

Éléments de point d'exclamation

// +build !pro

PASpro

Conclusion

Dans ce tutoriel, vous avez utilisé des balises de construction pour vous permettre de contrôler lequel de votre code a été compilé dans le binaire. Tout d'abord, vous avez déclaré les balises de construction et les avez utilisées avecgo build, puis vous avez combiné plusieurs balises avec la logique booléenne. Vous avez ensuite créé un programme représentant les différents jeux de fonctionnalités des versions Free, Pro et Enterprise, montrant le niveau de contrôle puissant que les balises de construction peuvent vous donner sur votre projet.

Si vous souhaitez en savoir plus sur les balises de compilation, jetez un œil auxGolang documentation on the subject ou continuez à explorer nosHow To Code in Go series.