build

package
v0.5.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 11, 2026 License: GPL-3.0 Imports: 21 Imported by: 0

README

pkg/build

Встраиваемый простой движок для DSL сборочных рецептов на основе модулей (YAML/JSON).

Движок выполняет список модулей над файловой системой: копирует файлы, запускает shell-команды, создаёт симлинки, подключает другие рецепты и т.д. Он ничего не знает о конкретной предметной области — вызывающий сам предоставляет способности времени выполнения и может регистрировать собственные типы модулей.

Быстрый старт

package main

import (
	"context"

	"altlinux.space/alt-atomic/apm/pkg/build"
	_ "altlinux.space/alt-atomic/apm/pkg/build/modules"
	"altlinux.space/alt-atomic/apm/pkg/command"
)

// host реализует build.RuntimeContext.
type host struct {
	engine *build.Engine
	runner command.Runner
}

func (h *host) Runner() command.Runner    { return h.runner }
func (h *host) CollectOutput(text string) { h.engine.CollectOutput(text) }

func (h *host) EmitEvent(ctx context.Context, state, name, view string) {
	// колбэк прогресса; state — это build.StateBefore или build.StateAfter
}

// ExecuteInclude делегирует движку, передавая контекст обратно (или своя логика)
func (h *host) ExecuteInclude(ctx context.Context, target string) (map[string]*build.MapModule, error) {
	return h.engine.ExecuteInclude(ctx, h, target)
}

func main() {
	// build.SetLogger(myLogger)
	// build.SetTranslator(func(s string) string { return s })

	eng := build.NewEngine(build.Version{}, "myapp.module")
	h := &host{engine: eng, runner: command.NewRunner("", false)}

	cfg, err := build.ReadAndParseConfig("recipe.yml")
	if err != nil {
		panic(err)
	}

	if err := eng.Build(context.Background(), h, cfg.Modules); err != nil {
		panic(err)
	}
}
  • ver доступен в выражениях рецепта как ${{ Version.* }} (передай build.Version{}, если не нужен).
  • eventPrefix — префикс имён событий, напр. myapp.module.1, myapp.module.2.

Формат рецепта

image: "alt:sisyphus"
modules:
  - name: create dir
    type: mkdir
    body:
      targets:
        - /opt/app
      perm: "rwxr-xr-x"

  - name: copy config
    type: copy
    body:
      source: /src/app.conf
      destination: /etc/app.conf

  - name: include another config
    type: include
    body:
      targets:
        - ./extra.yml

Ключи уровня модуля, которые обрабатывает движок:

  • type — тип модуля (обязателен).
  • name — метка для логов/событий.
  • id + output — прокинуть значения в следующие модули через ${{ Modules.<id>.<key> }}.
  • if — условие expr; модуль пропускается, если false.
  • env — переменные окружения, выставляемые для этого модуля.

Выражения используют ${{ ... }} и читают Version, Env, Modules.

Свой модуль

Модуль — любая структура, реализующая Body, зарегистрированная под именем type.

package mymodules

import (
	"context"

	build "altlinux.space/alt-atomic/apm/pkg/build"
)

type EchoBody struct {
	Message string `yaml:"message" json:"message" required:""`
}

func (b *EchoBody) Execute(ctx context.Context, rt build.RuntimeContext) (any, error) {
	build.Log().Info(b.Message)
	return nil, nil
}

func init() {
	build.Register("echo", func() build.Body { return &EchoBody{} })
}

Хуки

eng.Hook(build.PreModules, func (ctx context.Context) error { return nil }) // до модулей
eng.Hook(build.PostModules, func (ctx context.Context) error { return nil }) // после модулей, даже при ошибке
eng.Hook(build.PostBuild, func (ctx context.Context) error { return nil }) // после успешного прохода

Логирование и перевод

build.SetLogger(myLogger) // реализует build.Logger
build.SetTranslator(func (s string) string { … }) // напр. gettext

Хелперы

Разбор делится на два слоя: по источнику (файл/URL, формат определяется по расширению) и по байтам (формат задан явно).

  • ReadAndParseConfig(target) — прочитать и разобрать полный Config из файла или URL; YAML/JSON выбирается по расширению.
  • ReadAndParseModules(target) — то же для списка модулей (файл, директория или URL).
  • ReadAndParseConfigEnv(target, ver) — прочитать переменные окружения рецепта.
  • ParseYamlConfigData(bytes) / ParseJsonConfigData(bytes) — разобрать полный Config из готовых байт с явным форматом.
  • ValidateConfigRecursive(cfg, basePath) — провалидировать конфиг и все его include-цели.

Documentation

Index

Constants

View Source
const (
	StateBefore = "BEFORE"
	StateAfter  = "AFTER"
)

Progress event states (values match reply.State*).

Variables

View Source
var T_ = func(msgID string) string { return msgID }

T_ is the translation hook; identity by default.

Functions

func BodyTypeToType

func BodyTypeToType(bodyType string) string

func CheckBody

func CheckBody(v any) error

func CheckBodyValue

func CheckBodyValue(val reflect.Value) error

func CheckModules

func CheckModules(modules *[]Module) error

func ExtractExprResult

func ExtractExprResult(raw string, data any) (string, error)

func ExtractExprResultBool

func ExtractExprResultBool(raw string, data ExprData) (bool, error)

func KebabToPascal

func KebabToPascal(s string) string

func ReadAndParseModules

func ReadAndParseModules(target string) (*[]Module, error)

ReadAndParseModules reads modules from a file or URL, codec by extension.

func Register

func Register(typeName string, factory func() Body)

Register maps a module type name to its body factory.

func ResolveExpr

func ResolveExpr(str string, exprData any) (string, error)

func ResolveExprMap

func ResolveExprMap(strs map[string]string, data any) (map[string]string, error)

func ResolveExprSlice

func ResolveExprSlice(strs []string, data any) ([]string, error)

func ResolveStruct

func ResolveStruct(v any, data ExprData) error

func SetLogger

func SetLogger(l Logger)

SetLogger installs a logger; nil is ignored.

func SetTranslator

func SetTranslator(fn func(string) string)

SetTranslator installs a translation function; nil is ignored.

func ValidateConfigRecursive

func ValidateConfigRecursive(cfg *Config, basePath string, version Version) error

ValidateConfigRecursive validates a config and all its includes recursively.

Types

type Body

type Body interface {
	Execute(context.Context, RuntimeContext) (any, error)
}

Body is a build module body; its returned value becomes the module output.

func NewBody

func NewBody(typeName string) (Body, error)

NewBody creates an empty body for the given module type.

type Codec

type Codec interface {
	Name() string
	DecodeStrict(data []byte, v any) error
}

Codec decodes a build recipe document from one wire format, applying the same strict policy (unknown fields rejected) regardless of format.

type Config

type Config struct {
	// Environment vars
	Env map[string]string `yaml:"env,omitempty" json:"env,omitempty"`

	// Base image to build from
	Image string `yaml:"image,omitempty" json:"image,omitempty"`

	// Module list
	Modules []Module `yaml:"modules,omitempty" json:"modules,omitempty"`
}

func ParseJsonConfigData

func ParseJsonConfigData(data []byte) (Config, error)

func ParseYamlConfigData

func ParseYamlConfigData(data []byte) (Config, error)

func ReadAndParseConfig

func ReadAndParseConfig(target string) (Config, error)

ReadAndParseConfig reads a config from a file or URL, codec by extension.

func (*Config) CheckImage

func (cfg *Config) CheckImage() error

func (*Config) Save

func (cfg *Config) Save(filename string) error

type Engine

type Engine struct {
	// contains filtered or unexported fields
}

Engine is the neutral recipe executor: module loop, expr/env, includes, and stage hooks.

func NewEngine

func NewEngine(ver Version, eventPrefix string) *Engine

NewEngine creates an engine; eventPrefix prefixes emitted module event names.

func (*Engine) Build

func (e *Engine) Build(ctx context.Context, bc RuntimeContext, modules []Module) error

Build runs the modules wrapped by stage hooks: PreModules → modules → PostModules → PostBuild.

func (*Engine) CollectOutput

func (e *Engine) CollectOutput(text string)

CollectOutput accumulates module output for the final report.

func (*Engine) CollectedOutput

func (e *Engine) CollectedOutput() string

CollectedOutput returns the accumulated module output.

func (*Engine) ExecuteInclude

func (e *Engine) ExecuteInclude(ctx context.Context, bc RuntimeContext, target string) (map[string]*MapModule, error)

func (*Engine) ExecuteModule

func (e *Engine) ExecuteModule(ctx context.Context, bc RuntimeContext, module Module, modulesMap map[string]*MapModule) (*MapModule, error)

func (*Engine) Hook

func (e *Engine) Hook(stage Stage, fn HookFunc)

Hook registers a stage hook.

type Envs

type Envs struct {
	Env map[string]string `yaml:"env" json:"env"`
}

func ReadAndParseConfigEnv

func ReadAndParseConfigEnv(target string, version Version) (Envs, error)

ReadAndParseConfigEnv reads env vars from a file or URL, codec by extension.

type ExprData

type ExprData struct {
	Modules map[string]*MapModule
	Env     map[string]string
	Version Version
	Arch    string
	GoArch  string
}

type HookFunc

type HookFunc func(ctx context.Context) error

HookFunc is a stage hook body.

type Logger

type Logger interface {
	Debug(args ...any)
	Debugf(format string, args ...any)
	Info(args ...any)
	Warn(args ...any)
	Warning(args ...any)
	Error(args ...any)
}

Logger is the minimal logging interface.

func Log

func Log() Logger

Log returns the active logger.

type MapModule

type MapModule struct {
	Name   string
	Type   string
	Id     string
	If     bool
	Output map[string]string
}

func (MapModule) GetLabel

func (m MapModule) GetLabel() any

type Module

type Module struct {
	// Module name, for logging
	Name string `yaml:"name,omitempty" json:"name,omitempty"`

	// Module body type
	Type string `yaml:"type" json:"type"`

	// Module ID
	Id string `yaml:"id,omitempty" json:"id,omitempty"`

	// Environmant vars for module
	Env map[string]string `yaml:"env,omitempty" json:"env,omitempty"`

	// Condition in expr language
	If string `yaml:"if,omitempty" json:"if,omitempty"`

	// Module body
	Body Body `yaml:"body" json:"body"`

	// Output data
	Output map[string]string `yaml:"output,omitempty" json:"output,omitempty"`
}

func (Module) GetLabel

func (m Module) GetLabel() any

func (*Module) UnmarshalJSON

func (m *Module) UnmarshalJSON(data []byte) error

func (*Module) UnmarshalYAML

func (m *Module) UnmarshalYAML(n ast.Node) error

type RuntimeContext

type RuntimeContext interface {
	Runner() command.Runner
	CollectOutput(text string)
	EmitEvent(ctx context.Context, state, name, view string)
	ExecuteInclude(ctx context.Context, target string) (map[string]*MapModule, error)
}

RuntimeContext is the engine's neutral capability set available to every module.

type Stage

type Stage int

Stage is a build lifecycle point where the caller attaches hooks.

const (
	// PreModules runs before the modules.
	PreModules Stage = iota
	// PostModules runs after the modules, even on error.
	PostModules
	// PostBuild runs after the modules succeed.
	PostBuild
)

type ValidationService

type ValidationService struct {
	// contains filtered or unexported fields
}

ValidationService recursively validates a config and all its includes.

func NewValidationService

func NewValidationService(exprData ExprData) *ValidationService

NewValidationService creates a validation service.

func (*ValidationService) Validate

func (v *ValidationService) Validate(modules *[]Module, basePath string) error

Validate recursively validates modules and their includes.

type Version

type Version struct {
	Major   int
	Minor   int
	Patch   int
	Commits int
	Value   string
}

Version is the build version exposed to recipe expressions (e.g. ${{ Version.Major }}).

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL