DevGang
Авторизоваться

Переменные времени сборки в Go 

Установка переменных во время сборки может предоставить нашему приложению ценные метаданные, которые не были доступны при написании кода или даже во время выполнения. Мы можем контролировать флаги функций или информацию о сборке, например номер версии, без постоянного обновления кода Go.

Управление версиями проекта Go

Представьте, что у нас есть version/version.go в основном пакете github.com/benweidig/goapp

package version

import (
    "fmt"
    "time"
)

var (
    Version = "dev"
    CommitHash = "n/a"
    BuildTimestamp = "n/a"
)

func BuildVersion() string {
    return fmt.Sprintf("%s-%s (%s)", Version, CommitHash, BuildTimestamp)
}

Два свойства определяют любую сборку:

  1. Version: Идентификатор версии вашего приложения.
  2. CommitHash: Для воспроизводимых сборок важно знать, какая фиксация использовалась для создания определенного двоичного файла.
  3. BuildTimestamp: Еще одно динамическое значение, зависящее от самой сборки.

Конечно, мы могли бы просто обновлять версию каждый раз, прежде чем создавать новый двоичный файл. Но CommitHash - это динамическое значение, которое нельзя установить до фиксации кода: хэш фиксации, используемый для создания приложения, не будет тем, который задан в коде. Отметка времени сборки также зависит от самой сборки и не может быть установлена заранее.

Все эти свойства необходимы для создания воспроизводимых сборок. Поэтому мы установим их во время сборки вместо того, чтобы обновлять наш код перед его компиляцией с помощью флагов компоновщика.

Флаги компоновщика приходят на помощь

Процесс сборки Go go build - поддерживает флаги компоновщика, которые будут переданы базовому вызову go tool link, что позволяет нам устанавливать общедоступные переменные в вашем коде во время сборки.

Чтобы передать флаг компоновщика, мы должны добавить аргумент -ldflags:

go build -ldflags="-linkerflag"

Нас интересует флаг компоновщика -X, который устанавливает переменную во время компоновки:

go build -ldflags="-X 'full_package_path.variable=value'"

Это большое предостережение заключается в том, что разрешены только значения string, как вы, возможно, уже догадались из того, как эти значения цитируются.

В случае с нашим файлом version.go вызов будет выглядеть так:

go build -ldflags = "- X 'github.com/benweidig/goapp/version.Version=1.0.0'"

Вместо того, чтобы писать версию непосредственно в вызове, мы должны использовать сценарий для автоматического получения требуемых значений.

Скрипты сборки

Пока что мы просто перенесли бремя записи текущей версии из файла Go на команду сборки. Давайте автоматизируем этот шаг с помощью сценария git. Другие свойства также могут быть получены в таком скрипте:

#!/usr/bin/env bash
# STEP 1: Determinate the required values
PACKAGE="github.com/benweidig/goapp"
VERSION="$(git describe --tags --always --abbrev=0 --match='v[0-9]*.[0-9]*.[0-9]*' 2> /dev/null | sed 's/^.//')"
COMMIT_HASH="$(git rev-parse --short HEAD)"
BUILD_TIMESTAMP=$(date '+%Y-%m-%dT%H:%M:%S')
# STEP 2: Build the ldflags
LDFLAGS=(
  "-X '${PACKAGE}/version.Version=${VERSION}'"
  "-X '${PACKAGE}/version.CommitHash=${COMMIT_HASH}'"
  "-X '${PACKAGE}/version.BuildTime=${BUILD_TIMESTAMP}'"
)
# STEP 3: Actual Go build process
go build -ldflags="${LDFLAGS[*]}"

Общая концепция сценария должна легко адаптироваться к вашим собственным потребностям CI/CD. Лично я использую Makefile для своего Git-helper Tortuga.

Заключение

Внедрение динамических значений во время сборки с помощью флагов компоновщика - мощное дополнение к вашему набору инструментов. Вы можете предоставить информацию о сборке, как показано в статье, или использовать ее для управления флагами функций или чего-либо еще, что зависит от самого контекста сборки, а не от информации, доступной во время выполнения.

Источник:

#Golang
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу