wip: add support of building multiple packages at once

This commit is contained in:
Maxim Slipenko 2025-02-12 14:11:46 +03:00
parent 083df3c7aa
commit e773e3ee12
7 changed files with 309 additions and 218 deletions

@ -76,7 +76,8 @@ func BuildCmd() *cli.Command {
os.Exit(1) os.Exit(1)
} }
var script, packageName string var script string
var packages []string
// Проверяем, установлен ли флаг script (-s) // Проверяем, установлен ли флаг script (-s)
@ -85,7 +86,7 @@ func BuildCmd() *cli.Command {
switch { switch {
case c.IsSet("script"): case c.IsSet("script"):
script = c.String("script") script = c.String("script")
packageName = c.String("script-package") packages = append(packages, c.String("script-package"))
case c.IsSet("package"): case c.IsSet("package"):
// TODO: handle multiple packages // TODO: handle multiple packages
packageInput := c.String("package") packageInput := c.String("package")
@ -107,7 +108,7 @@ func BuildCmd() *cli.Command {
if pkg[0].BasePkgName != "" { if pkg[0].BasePkgName != "" {
script = filepath.Join(repoDir, pkg[0].Repository, pkg[0].BasePkgName, "alr.sh") script = filepath.Join(repoDir, pkg[0].Repository, pkg[0].BasePkgName, "alr.sh")
packageName = pkg[0].Name packages = append(packages, pkg[0].Name)
} else { } else {
script = filepath.Join(repoDir, pkg[0].Repository, pkg[0].Name, "alr.sh") script = filepath.Join(repoDir, pkg[0].Repository, pkg[0].Name, "alr.sh")
} }
@ -140,7 +141,7 @@ func BuildCmd() *cli.Command {
builder := build.NewBuilder( builder := build.NewBuilder(
ctx, ctx,
types.BuildOpts{ types.BuildOpts{
Package: packageName, Packages: packages,
Script: script, Script: script,
Manager: mgr, Manager: mgr,
Clean: c.Bool("clean"), Clean: c.Bool("clean"),

@ -34,31 +34,31 @@ msgstr ""
msgid "Error db init" msgid "Error db init"
msgstr "" msgstr ""
#: build.go:104 #: build.go:105
msgid "Package not found" msgid "Package not found"
msgstr "" msgstr ""
#: build.go:122 #: build.go:123
msgid "Error pulling repositories" msgid "Error pulling repositories"
msgstr "" msgstr ""
#: build.go:130 #: build.go:131
msgid "Unable to detect a supported package manager on the system" msgid "Unable to detect a supported package manager on the system"
msgstr "" msgstr ""
#: build.go:136 #: build.go:137
msgid "Error parsing os release" msgid "Error parsing os release"
msgstr "" msgstr ""
#: build.go:157 #: build.go:158
msgid "Error building package" msgid "Error building package"
msgstr "" msgstr ""
#: build.go:164 #: build.go:165
msgid "Error getting working directory" msgid "Error getting working directory"
msgstr "" msgstr ""
#: build.go:173 #: build.go:174
msgid "Error moving the package" msgid "Error moving the package"
msgstr "" msgstr ""
@ -309,77 +309,69 @@ msgstr ""
msgid "Error while running app" msgid "Error while running app"
msgstr "" msgstr ""
#: pkg/build/build.go:135 #: pkg/build/build.go:153
msgid "Failed to prompt user to view build script" msgid "Failed to prompt user to view build script"
msgstr "" msgstr ""
#: pkg/build/build.go:139 #: pkg/build/build.go:157
msgid "Building package" msgid "Building package"
msgstr "" msgstr ""
#: pkg/build/build.go:183 #: pkg/build/build.go:228
msgid "Downloading sources" msgid "Downloading sources"
msgstr "" msgstr ""
#: pkg/build/build.go:195 #: pkg/build/build.go:246
msgid "Building package metadata" msgid "Building package metadata"
msgstr "" msgstr ""
#: pkg/build/build.go:217 #: pkg/build/build.go:268
msgid "Compressing package" msgid "Compressing package"
msgstr "" msgstr ""
#: pkg/build/build.go:359 #: pkg/build/build.go:419
msgid "" msgid ""
"Your system's CPU architecture doesn't match this package. Do you want to " "Your system's CPU architecture doesn't match this package. Do you want to "
"build anyway?" "build anyway?"
msgstr "" msgstr ""
#: pkg/build/build.go:373 #: pkg/build/build.go:433
msgid "This package is already installed" msgid "This package is already installed"
msgstr "" msgstr ""
#: pkg/build/build.go:397 #: pkg/build/build.go:457
msgid "Installing build dependencies" msgid "Installing build dependencies"
msgstr "" msgstr ""
#: pkg/build/build.go:408 #: pkg/build/build.go:468
msgid "Installing dependencies" msgid "Installing dependencies"
msgstr "" msgstr ""
#: pkg/build/build.go:449 #: pkg/build/build.go:521
msgid "The checksums array must be the same length as sources" msgid "The checksums array must be the same length as sources"
msgstr "" msgstr ""
#: pkg/build/build.go:500 #: pkg/build/build.go:572
msgid "Would you like to remove the build dependencies?" msgid "Would you like to remove the build dependencies?"
msgstr "" msgstr ""
#: pkg/build/build.go:537 #: pkg/build/build.go:635
msgid "Executing version()"
msgstr ""
#: pkg/build/build.go:557
msgid "Updating version"
msgstr ""
#: pkg/build/build.go:562
msgid "Executing prepare()" msgid "Executing prepare()"
msgstr "" msgstr ""
#: pkg/build/build.go:572 #: pkg/build/build.go:645
msgid "Executing build()" msgid "Executing build()"
msgstr "" msgstr ""
#: pkg/build/build.go:588 pkg/build/build.go:616 #: pkg/build/build.go:675 pkg/build/build.go:695
msgid "Executing %s()" msgid "Executing %s()"
msgstr "" msgstr ""
#: pkg/build/build.go:675 #: pkg/build/build.go:754
msgid "Error installing native packages" msgid "Error installing native packages"
msgstr "" msgstr ""
#: pkg/build/build.go:701 #: pkg/build/build.go:795
msgid "Error installing package" msgid "Error installing package"
msgstr "" msgstr ""
@ -395,11 +387,11 @@ msgstr ""
msgid "Required dependency found" msgid "Required dependency found"
msgstr "" msgstr ""
#: pkg/build/utils.go:136 #: pkg/build/utils.go:133
msgid "AutoProv is not implemented for this package format, so it's skipped" msgid "AutoProv is not implemented for this package format, so it's skipped"
msgstr "" msgstr ""
#: pkg/build/utils.go:147 #: pkg/build/utils.go:144
msgid "AutoReq is not implemented for this package format, so it's skipped" msgid "AutoReq is not implemented for this package format, so it's skipped"
msgstr "" msgstr ""

@ -41,32 +41,32 @@ msgstr "Создайте пакет с нуля, даже если уже име
msgid "Error db init" msgid "Error db init"
msgstr "" msgstr ""
#: build.go:104 #: build.go:105
msgid "Package not found" msgid "Package not found"
msgstr "" msgstr ""
#: build.go:122 #: build.go:123
msgid "Error pulling repositories" msgid "Error pulling repositories"
msgstr "Ошибка при извлечении репозиториев" msgstr "Ошибка при извлечении репозиториев"
#: build.go:130 #: build.go:131
msgid "Unable to detect a supported package manager on the system" msgid "Unable to detect a supported package manager on the system"
msgstr "Не удалось обнаружить поддерживаемый менеджер пакетов в системе" msgstr "Не удалось обнаружить поддерживаемый менеджер пакетов в системе"
#: build.go:136 #: build.go:137
#, fuzzy #, fuzzy
msgid "Error parsing os release" msgid "Error parsing os release"
msgstr "Ошибка при разборе файла выпуска операционной системы" msgstr "Ошибка при разборе файла выпуска операционной системы"
#: build.go:157 #: build.go:158
msgid "Error building package" msgid "Error building package"
msgstr "Ошибка при сборке пакета" msgstr "Ошибка при сборке пакета"
#: build.go:164 #: build.go:165
msgid "Error getting working directory" msgid "Error getting working directory"
msgstr "Ошибка при получении рабочего каталога" msgstr "Ошибка при получении рабочего каталога"
#: build.go:173 #: build.go:174
msgid "Error moving the package" msgid "Error moving the package"
msgstr "Ошибка при перемещении пакета" msgstr "Ошибка при перемещении пакета"
@ -324,27 +324,27 @@ msgstr ""
msgid "Error while running app" msgid "Error while running app"
msgstr "Ошибка при запуске приложения" msgstr "Ошибка при запуске приложения"
#: pkg/build/build.go:135 #: pkg/build/build.go:153
msgid "Failed to prompt user to view build script" msgid "Failed to prompt user to view build script"
msgstr "Не удалось предложить пользователю просмотреть скрипт сборки" msgstr "Не удалось предложить пользователю просмотреть скрипт сборки"
#: pkg/build/build.go:139 #: pkg/build/build.go:157
msgid "Building package" msgid "Building package"
msgstr "Сборка пакета" msgstr "Сборка пакета"
#: pkg/build/build.go:183 #: pkg/build/build.go:228
msgid "Downloading sources" msgid "Downloading sources"
msgstr "Скачивание источников" msgstr "Скачивание источников"
#: pkg/build/build.go:195 #: pkg/build/build.go:246
msgid "Building package metadata" msgid "Building package metadata"
msgstr "Сборка метаданных пакета" msgstr "Сборка метаданных пакета"
#: pkg/build/build.go:217 #: pkg/build/build.go:268
msgid "Compressing package" msgid "Compressing package"
msgstr "Сжатие пакета" msgstr "Сжатие пакета"
#: pkg/build/build.go:359 #: pkg/build/build.go:419
msgid "" msgid ""
"Your system's CPU architecture doesn't match this package. Do you want to " "Your system's CPU architecture doesn't match this package. Do you want to "
"build anyway?" "build anyway?"
@ -352,52 +352,44 @@ msgstr ""
"Архитектура процессора вашей системы не соответствует этому пакету. Вы все " "Архитектура процессора вашей системы не соответствует этому пакету. Вы все "
"равно хотите выполнить сборку?" "равно хотите выполнить сборку?"
#: pkg/build/build.go:373 #: pkg/build/build.go:433
msgid "This package is already installed" msgid "This package is already installed"
msgstr "Этот пакет уже установлен" msgstr "Этот пакет уже установлен"
#: pkg/build/build.go:397 #: pkg/build/build.go:457
msgid "Installing build dependencies" msgid "Installing build dependencies"
msgstr "Установка зависимостей сборки" msgstr "Установка зависимостей сборки"
#: pkg/build/build.go:408 #: pkg/build/build.go:468
msgid "Installing dependencies" msgid "Installing dependencies"
msgstr "Установка зависимостей" msgstr "Установка зависимостей"
#: pkg/build/build.go:449 #: pkg/build/build.go:521
msgid "The checksums array must be the same length as sources" msgid "The checksums array must be the same length as sources"
msgstr "Массив контрольных сумм должен быть той же длины, что и источники" msgstr "Массив контрольных сумм должен быть той же длины, что и источники"
#: pkg/build/build.go:500 #: pkg/build/build.go:572
msgid "Would you like to remove the build dependencies?" msgid "Would you like to remove the build dependencies?"
msgstr "Хотели бы вы удалить зависимости сборки?" msgstr "Хотели бы вы удалить зависимости сборки?"
#: pkg/build/build.go:537 #: pkg/build/build.go:635
msgid "Executing version()"
msgstr "Исполнение версия()"
#: pkg/build/build.go:557
msgid "Updating version"
msgstr "Обновление версии"
#: pkg/build/build.go:562
msgid "Executing prepare()" msgid "Executing prepare()"
msgstr "Исполнение prepare()" msgstr "Исполнение prepare()"
#: pkg/build/build.go:572 #: pkg/build/build.go:645
msgid "Executing build()" msgid "Executing build()"
msgstr "Исполнение build()" msgstr "Исполнение build()"
#: pkg/build/build.go:588 pkg/build/build.go:616 #: pkg/build/build.go:675 pkg/build/build.go:695
#, fuzzy #, fuzzy
msgid "Executing %s()" msgid "Executing %s()"
msgstr "Исполнение files()" msgstr "Исполнение files()"
#: pkg/build/build.go:675 #: pkg/build/build.go:754
msgid "Error installing native packages" msgid "Error installing native packages"
msgstr "Ошибка при установке нативных пакетов" msgstr "Ошибка при установке нативных пакетов"
#: pkg/build/build.go:701 #: pkg/build/build.go:795
msgid "Error installing package" msgid "Error installing package"
msgstr "Ошибка при установке пакета" msgstr "Ошибка при установке пакета"
@ -413,12 +405,12 @@ msgstr "Найденная предоставленная зависимость
msgid "Required dependency found" msgid "Required dependency found"
msgstr "Найдена требуемая зависимость" msgstr "Найдена требуемая зависимость"
#: pkg/build/utils.go:136 #: pkg/build/utils.go:133
msgid "AutoProv is not implemented for this package format, so it's skipped" msgid "AutoProv is not implemented for this package format, so it's skipped"
msgstr "" msgstr ""
"AutoProv не реализовано для этого формата пакета, поэтому будет пропущено" "AutoProv не реализовано для этого формата пакета, поэтому будет пропущено"
#: pkg/build/utils.go:147 #: pkg/build/utils.go:144
msgid "AutoReq is not implemented for this package format, so it's skipped" msgid "AutoReq is not implemented for this package format, so it's skipped"
msgstr "" msgstr ""
"AutoReq не реализовано для этого формата пакета, поэтому будет пропущено" "AutoReq не реализовано для этого формата пакета, поэтому будет пропущено"
@ -499,5 +491,11 @@ msgstr "Ошибка при проверке обновлений"
msgid "There is nothing to do." msgid "There is nothing to do."
msgstr "Здесь нечего делать." msgstr "Здесь нечего делать."
#~ msgid "Executing version()"
#~ msgstr "Исполнение версия()"
#~ msgid "Updating version"
#~ msgstr "Обновление версии"
#~ msgid "Executing package()" #~ msgid "Executing package()"
#~ msgstr "Исполнение package()" #~ msgstr "Исполнение package()"

@ -23,7 +23,7 @@ import "gitea.plemya-x.ru/Plemya-x/ALR/pkg/manager"
type BuildOpts struct { type BuildOpts struct {
Script string Script string
Package string Packages []string
Manager manager.Manager Manager manager.Manager
Clean bool Clean bool
Interactive bool Interactive bool

@ -85,11 +85,11 @@ func NewBuilder(
} }
} }
func (b *Builder) UpdateOptsFromPkg(pkg *db.Package) { func (b *Builder) UpdateOptsFromPkg(pkg *db.Package, packages []string) {
repodir := b.config.GetPaths(b.ctx).RepoDir repodir := b.config.GetPaths(b.ctx).RepoDir
if pkg.BasePkgName != "" { if pkg.BasePkgName != "" {
b.opts.Script = filepath.Join(repodir, pkg.Repository, pkg.BasePkgName, "alr.sh") b.opts.Script = filepath.Join(repodir, pkg.Repository, pkg.BasePkgName, "alr.sh")
b.opts.Package = pkg.Name b.opts.Packages = packages
} else { } else {
b.opts.Script = filepath.Join(repodir, pkg.Repository, pkg.Name, "alr.sh") b.opts.Script = filepath.Join(repodir, pkg.Repository, pkg.Name, "alr.sh")
} }
@ -103,23 +103,41 @@ func (b *Builder) BuildPackage(ctx context.Context) ([]string, []string, error)
// Первый проход предназначен для получения значений переменных и выполняется // Первый проход предназначен для получения значений переменных и выполняется
// до отображения скрипта, чтобы предотвратить выполнение вредоносного кода. // до отображения скрипта, чтобы предотвратить выполнение вредоносного кода.
vars, err := b.executeFirstPass(fl) basePkg, varsOfPackages, err := b.executeFirstPass(fl)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
dirs := b.getDirs(vars) dirs := b.getDirs(basePkg)
builtPaths := make([]string, 0)
// Если флаг opts.Clean не установлен, и пакет уже собран, // Если флаг opts.Clean не установлен, и пакет уже собран,
// возвращаем его, а не собираем заново. // возвращаем его, а не собираем заново.
if !b.opts.Clean { if !b.opts.Clean {
builtPkgPath, ok, err := checkForBuiltPackage(b.opts.Manager, vars, getPkgFormat(b.opts.Manager), dirs.BaseDir) var remainingVars []*types.BuildVars
if err != nil {
return nil, nil, err for _, vars := range varsOfPackages {
builtPkgPath, ok, err := checkForBuiltPackage(
b.opts.Manager,
vars,
getPkgFormat(b.opts.Manager),
dirs.BaseDir,
b.info,
)
if err != nil {
return nil, nil, err
}
if ok {
builtPaths = append(builtPaths, builtPkgPath)
} else {
remainingVars = append(remainingVars, vars)
}
} }
if ok { if len(remainingVars) == 0 {
return []string{builtPkgPath}, nil, err return builtPaths, nil, nil
} }
} }
@ -127,7 +145,7 @@ func (b *Builder) BuildPackage(ctx context.Context) ([]string, []string, error)
err = cliutils.PromptViewScript( err = cliutils.PromptViewScript(
ctx, ctx,
b.opts.Script, b.opts.Script,
vars.Name, basePkg,
b.config.PagerStyle(ctx), b.config.PagerStyle(ctx),
b.opts.Interactive, b.opts.Interactive,
) )
@ -136,7 +154,7 @@ func (b *Builder) BuildPackage(ctx context.Context) ([]string, []string, error)
os.Exit(1) os.Exit(1)
} }
slog.Info(gotext.Get("Building package"), "name", vars.Name, "version", vars.Version) slog.Info(gotext.Get("Building package"), "name", basePkg)
// Второй проход будет использоваться для выполнения реального кода, // Второй проход будет использоваться для выполнения реального кода,
// поэтому он не ограничен. Скрипт уже был показан // поэтому он не ограничен. Скрипт уже был показан
@ -152,11 +170,13 @@ func (b *Builder) BuildPackage(ctx context.Context) ([]string, []string, error)
return nil, nil, err return nil, nil, err
} }
cont, err := b.performChecks(ctx, vars, installed) // Выполняем различные проверки for _, vars := range varsOfPackages {
if err != nil { cont, err := b.performChecks(ctx, vars, installed) // Выполняем различные проверки
return nil, nil, err if err != nil {
} else if !cont { return nil, nil, err
os.Exit(1) // Если проверки не пройдены, выходим из программы } else if !cont {
os.Exit(1) // Если проверки не пройдены, выходим из программы
}
} }
// Подготавливаем директории для сборки // Подготавливаем директории для сборки
@ -165,60 +185,97 @@ func (b *Builder) BuildPackage(ctx context.Context) ([]string, []string, error)
return nil, nil, err return nil, nil, err
} }
buildDeps, err := b.installBuildDeps(ctx, vars) // Устанавливаем зависимости для сборки buildDepends := []string{}
optDepends := []string{}
depends := []string{}
sources := []string{}
checksums := []string{}
for _, vars := range varsOfPackages {
buildDepends = append(buildDepends, vars.BuildDepends...)
optDepends = append(optDepends, vars.OptDepends...)
depends = append(depends, vars.Depends...)
sources = append(sources, vars.Sources...)
checksums = append(checksums, vars.Checksums...)
}
buildDepends = removeDuplicates(buildDepends)
optDepends = removeDuplicates(optDepends)
depends = removeDuplicates(depends)
sources = removeDuplicates(sources)
checksums = removeDuplicates(checksums)
mergedVars := types.BuildVars{
Sources: sources,
Checksums: checksums,
}
buildDeps, err := b.installBuildDeps(ctx, buildDepends) // Устанавливаем зависимости для сборки
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
err = b.installOptDeps(ctx, vars) // Устанавливаем опциональные зависимости err = b.installOptDeps(ctx, optDepends) // Устанавливаем опциональные зависимости
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
builtPaths, builtNames, repoDeps, err := b.buildALRDeps(ctx, vars) // Собираем зависимости newBuildPaths, builtNames, repoDeps, err := b.buildALRDeps(ctx, depends) // Собираем зависимости
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
builtPaths = append(builtPaths, newBuildPaths...)
slog.Info(gotext.Get("Downloading sources")) // Записываем в лог загрузку источников slog.Info(gotext.Get("Downloading sources")) // Записываем в лог загрузку источников
err = b.getSources(ctx, dirs, vars) // Загружаем исходники err = b.getSources(ctx, dirs, &mergedVars) // Загружаем исходники
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
funcOut, err := b.executeFunctions(ctx, dec, dirs, vars) // Выполняем специальные функции err = b.executeFunctions(ctx, dec, dirs) // Выполняем специальные функции
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
slog.Info(gotext.Get("Building package metadata"), "name", vars.Name) for _, vars := range varsOfPackages {
funcOut, err := b.executePackageFunctions(ctx, dec, dirs, vars.Name)
if err != nil {
return nil, nil, err
}
pkgFormat := getPkgFormat(b.opts.Manager) // Получаем формат пакета slog.Info(gotext.Get("Building package metadata"), "name", basePkg)
pkgInfo, err := buildPkgMetadata(ctx, vars, dirs, pkgFormat, b.info, append(repoDeps, builtNames...), funcOut.Contents) // Собираем метаданные пакета pkgFormat := getPkgFormat(b.opts.Manager) // Получаем формат пакета
if err != nil {
return nil, nil, err
}
packager, err := nfpm.Get(pkgFormat) // Получаем упаковщик для формата пакета pkgInfo, err := buildPkgMetadata(ctx, vars, dirs, pkgFormat, b.info, append(repoDeps, builtNames...), funcOut.Contents) // Собираем метаданные пакета
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
pkgName := packager.ConventionalFileName(pkgInfo) // Получаем имя файла пакета packager, err := nfpm.Get(pkgFormat) // Получаем упаковщик для формата пакета
pkgPath := filepath.Join(dirs.BaseDir, pkgName) // Определяем путь к пакету if err != nil {
return nil, nil, err
}
pkgFile, err := os.Create(pkgPath) // Создаём файл пакета pkgName := packager.ConventionalFileName(pkgInfo) // Получаем имя файла пакета
if err != nil { pkgPath := filepath.Join(dirs.BaseDir, pkgName) // Определяем путь к пакету
return nil, nil, err
}
slog.Info(gotext.Get("Compressing package"), "name", pkgName) // Логгируем сжатие пакета pkgFile, err := os.Create(pkgPath) // Создаём файл пакета
if err != nil {
return nil, nil, err
}
err = packager.Package(pkgInfo, pkgFile) // Упаковываем пакет slog.Info(gotext.Get("Compressing package"), "name", pkgName) // Логгируем сжатие пакета
if err != nil {
return nil, nil, err err = packager.Package(pkgInfo, pkgFile) // Упаковываем пакет
if err != nil {
return nil, nil, err
}
// Добавляем путь и имя только что собранного пакета в
// соответствующие срезы
builtPaths = append(builtPaths, pkgPath)
builtNames = append(builtNames, vars.Name)
} }
err = b.removeBuildDeps(ctx, buildDeps) // Удаляем зависимости для сборки err = b.removeBuildDeps(ctx, buildDeps) // Удаляем зависимости для сборки
@ -226,11 +283,6 @@ func (b *Builder) BuildPackage(ctx context.Context) ([]string, []string, error)
return nil, nil, err return nil, nil, err
} }
// Добавляем путь и имя только что собранного пакета в
// соответствующие срезы
builtPaths = append(builtPaths, pkgPath)
builtNames = append(builtNames, vars.Name)
// Удаляем дубликаты из pkgPaths и pkgNames. // Удаляем дубликаты из pkgPaths и pkgNames.
// Дубликаты могут появиться, если несколько зависимостей // Дубликаты могут появиться, если несколько зависимостей
// зависят от одних и тех же пакетов. // зависят от одних и тех же пакетов.
@ -244,7 +296,9 @@ func (b *Builder) BuildPackage(ctx context.Context) ([]string, []string, error)
// чтобы извлечь переменные сборки без выполнения реального кода. // чтобы извлечь переменные сборки без выполнения реального кода.
func (b *Builder) executeFirstPass( func (b *Builder) executeFirstPass(
fl *syntax.File, fl *syntax.File,
) (*types.BuildVars, error) { ) (string, []*types.BuildVars, error) {
varsOfPackages := []*types.BuildVars{}
scriptDir := filepath.Dir(b.opts.Script) // Получаем директорию скрипта scriptDir := filepath.Dir(b.opts.Script) // Получаем директорию скрипта
env := createBuildEnvVars(b.info, types.Directories{ScriptDir: scriptDir}) // Создаём переменные окружения для сборки env := createBuildEnvVars(b.info, types.Directories{ScriptDir: scriptDir}) // Создаём переменные окружения для сборки
@ -257,12 +311,12 @@ func (b *Builder) executeFirstPass(
interp.OpenHandler(handlers.RestrictedOpen(scriptDir)), // Ограничиваем открытие файлов interp.OpenHandler(handlers.RestrictedOpen(scriptDir)), // Ограничиваем открытие файлов
) )
if err != nil { if err != nil {
return nil, err return "", nil, err
} }
err = runner.Run(b.ctx, fl) // Запускаем скрипт err = runner.Run(b.ctx, fl) // Запускаем скрипт
if err != nil { if err != nil {
return nil, err return "", nil, err
} }
dec := decoder.New(b.info, runner) // Создаём новый декодер dec := decoder.New(b.info, runner) // Создаём новый декодер
@ -275,47 +329,53 @@ func (b *Builder) executeFirstPass(
var pkgs packages var pkgs packages
err = dec.DecodeVars(&pkgs) err = dec.DecodeVars(&pkgs)
if err != nil { if err != nil {
return nil, err return "", nil, err
} }
if len(pkgs.Names) == 0 { if len(pkgs.Names) == 0 {
return nil, errors.New("package name is missing") return "", nil, errors.New("package name is missing")
} }
var vars types.BuildVars var vars types.BuildVars
if len(pkgs.Names) == 1 { if len(pkgs.Names) == 1 {
err = dec.DecodeVars(&vars) // Декодируем переменные err = dec.DecodeVars(&vars) // Декодируем переменные
if err != nil { if err != nil {
return nil, err return "", nil, err
} }
return &vars, nil varsOfPackages = append(varsOfPackages, &vars)
return vars.Name, varsOfPackages, nil
} }
if b.opts.Package == "" { if len(b.opts.Packages) == 0 {
return nil, errors.New("script has multiple packages but package is not specified") return "", nil, errors.New("script has multiple packages but package is not specified")
} }
var preVars types.BuildVarsPre for _, pkgName := range b.opts.Packages {
funcName := fmt.Sprintf("meta_%s", b.opts.Package) var preVars types.BuildVarsPre
meta, ok := dec.GetFuncSub(funcName) funcName := fmt.Sprintf("meta_%s", pkgName)
if !ok { meta, ok := dec.GetFuncSub(funcName)
return nil, errors.New("func is missing") if !ok {
} return "", nil, errors.New("func is missing")
r, err := meta(b.ctx) }
if err != nil { r, err := meta(b.ctx)
return nil, err if err != nil {
} return "", nil, err
d := decoder.New(&distro.OSRelease{}, r) }
err = d.DecodeVars(&preVars) d := decoder.New(&distro.OSRelease{}, r)
if err != nil { err = d.DecodeVars(&preVars)
return nil, err if err != nil {
} return "", nil, err
vars = preVars.ToBuildVars() }
vars.Name = b.opts.Package vars := preVars.ToBuildVars()
vars.Name = pkgName
return &vars, nil // Возвращаем переменные сборки varsOfPackages = append(varsOfPackages, &vars)
}
return pkgs.BasePkgName, varsOfPackages, nil // Возвращаем переменные сборки
} }
// Функция getDirs возвращает соответствующие директории для скрипта // Функция getDirs возвращает соответствующие директории для скрипта
func (b *Builder) getDirs(vars *types.BuildVars) types.Directories { func (b *Builder) getDirs(basePkg string) types.Directories {
baseDir := filepath.Join(b.config.GetPaths(b.ctx).PkgsDir, vars.Name) // Определяем базовую директорию baseDir := filepath.Join(b.config.GetPaths(b.ctx).PkgsDir, basePkg) // Определяем базовую директорию
return types.Directories{ return types.Directories{
BaseDir: baseDir, BaseDir: baseDir,
SrcDir: filepath.Join(baseDir, "src"), SrcDir: filepath.Join(baseDir, "src"),
@ -381,10 +441,10 @@ func (b *Builder) performChecks(ctx context.Context, vars *types.BuildVars, inst
// Функция installBuildDeps устанавливает все зависимости сборки, которые еще не установлены, и возвращает // Функция installBuildDeps устанавливает все зависимости сборки, которые еще не установлены, и возвращает
// срез, содержащий имена всех установленных пакетов. // срез, содержащий имена всех установленных пакетов.
func (b *Builder) installBuildDeps(ctx context.Context, vars *types.BuildVars) ([]string, error) { func (b *Builder) installBuildDeps(ctx context.Context, buildDepends []string) ([]string, error) {
var buildDeps []string var buildDeps []string
if len(vars.BuildDepends) > 0 { if len(buildDepends) > 0 {
deps, err := removeAlreadyInstalled(b.opts, vars.BuildDepends) deps, err := removeAlreadyInstalled(b.opts, buildDepends)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -403,11 +463,11 @@ func (b *Builder) installBuildDeps(ctx context.Context, vars *types.BuildVars) (
return buildDeps, nil return buildDeps, nil
} }
func (b *Builder) buildALRDeps(ctx context.Context, vars *types.BuildVars) (builtPaths, builtNames, repoDeps []string, err error) { func (b *Builder) buildALRDeps(ctx context.Context, depends []string) (builtPaths, builtNames, repoDeps []string, err error) {
if len(vars.Depends) > 0 { if len(depends) > 0 {
slog.Info(gotext.Get("Installing dependencies")) slog.Info(gotext.Get("Installing dependencies"))
found, notFound, err := b.repos.FindPkgs(ctx, vars.Depends) // Поиск зависимостей found, notFound, err := b.repos.FindPkgs(ctx, depends) // Поиск зависимостей
if err != nil { if err != nil {
return nil, nil, nil, err return nil, nil, nil, err
} }
@ -416,10 +476,24 @@ func (b *Builder) buildALRDeps(ctx context.Context, vars *types.BuildVars) (buil
// Если для некоторых пакетов есть несколько опций, упрощаем их все в один срез // Если для некоторых пакетов есть несколько опций, упрощаем их все в один срез
pkgs := cliutils.FlattenPkgs(ctx, found, "install", b.opts.Interactive) pkgs := cliutils.FlattenPkgs(ctx, found, "install", b.opts.Interactive)
type x struct {
pkg *db.Package
packages []string
}
xx := make(map[string]*x)
for _, pkg := range pkgs { for _, pkg := range pkgs {
if xx[pkg.BasePkgName] == nil {
xx[pkg.BasePkgName] = &x{
pkg: &pkg,
}
}
xx[pkg.BasePkgName].packages = append(xx[pkg.BasePkgName].packages, pkg.Name)
}
for basePkgName := range xx {
pkg := xx[basePkgName].pkg
newB := *b newB := *b
newB.UpdateOptsFromPkg(&pkg) newB.UpdateOptsFromPkg(pkg, xx[basePkgName].packages)
// Собираем зависимости // Собираем зависимости
pkgPaths, pkgNames, err := newB.BuildPackage(ctx) pkgPaths, pkgNames, err := newB.BuildPackage(ctx)
@ -431,8 +505,6 @@ func (b *Builder) buildALRDeps(ctx context.Context, vars *types.BuildVars) (buil
builtPaths = append(builtPaths, pkgPaths...) builtPaths = append(builtPaths, pkgPaths...)
// Добавляем пути всех собранных пакетов в builtPaths // Добавляем пути всех собранных пакетов в builtPaths
builtNames = append(builtNames, pkgNames...) builtNames = append(builtNames, pkgNames...)
// Добавляем имя текущего пакета в builtNames
builtNames = append(builtNames, filepath.Base(filepath.Dir(newB.opts.Script)))
} }
} }
@ -530,32 +602,33 @@ func (b *Builder) executeFunctions(
ctx context.Context, ctx context.Context,
dec *decoder.Decoder, dec *decoder.Decoder,
dirs types.Directories, dirs types.Directories,
vars *types.BuildVars, ) error {
) (*FunctionsOutput, error) { /*
version, ok := dec.GetFunc("version") version, ok := dec.GetFunc("version")
if ok { if ok {
slog.Info(gotext.Get("Executing version()")) slog.Info(gotext.Get("Executing version()"))
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
err := version( err := version(
ctx, ctx,
interp.Dir(dirs.SrcDir), interp.Dir(dirs.SrcDir),
interp.StdIO(os.Stdin, buf, os.Stderr), interp.StdIO(os.Stdin, buf, os.Stderr),
) )
if err != nil { if err != nil {
return nil, err return nil, err
}
newVer := strings.TrimSpace(buf.String())
err = setVersion(ctx, dec.Runner, newVer)
if err != nil {
return nil, err
}
vars.Version = newVer
slog.Info(gotext.Get("Updating version"), "new", newVer)
} }
*/
newVer := strings.TrimSpace(buf.String())
err = setVersion(ctx, dec.Runner, newVer)
if err != nil {
return nil, err
}
vars.Version = newVer
slog.Info(gotext.Get("Updating version"), "new", newVer)
}
prepare, ok := dec.GetFunc("prepare") prepare, ok := dec.GetFunc("prepare")
if ok { if ok {
@ -563,7 +636,7 @@ func (b *Builder) executeFunctions(
err := prepare(ctx, interp.Dir(dirs.SrcDir)) err := prepare(ctx, interp.Dir(dirs.SrcDir))
if err != nil { if err != nil {
return nil, err return err
} }
} }
@ -573,15 +646,29 @@ func (b *Builder) executeFunctions(
err := build(ctx, interp.Dir(dirs.SrcDir)) err := build(ctx, interp.Dir(dirs.SrcDir))
if err != nil { if err != nil {
return nil, err return err
} }
} }
return nil
}
func (b *Builder) executePackageFunctions(
ctx context.Context,
dec *decoder.Decoder,
dirs types.Directories,
packageName string,
) (*FunctionsOutput, error) {
output := &FunctionsOutput{}
var packageFuncName string var packageFuncName string
if b.opts.Package == "" { var filesFuncName string
if packageName == "" {
filesFuncName = "files"
packageFuncName = "package" packageFuncName = "package"
} else { } else {
packageFuncName = fmt.Sprintf("package_%s", b.opts.Package) packageFuncName = fmt.Sprintf("package_%s", packageName)
filesFuncName = fmt.Sprintf("files_%s", packageName)
} }
packageFn, ok := dec.GetFunc(packageFuncName) packageFn, ok := dec.GetFunc(packageFuncName)
if ok { if ok {
@ -592,14 +679,6 @@ func (b *Builder) executeFunctions(
} }
} }
output := &FunctionsOutput{}
var filesFuncName string
if b.opts.Package == "" {
filesFuncName = "files"
} else {
filesFuncName = fmt.Sprintf("files_%s", b.opts.Package)
}
files, ok := dec.GetFuncP(filesFuncName, func(ctx context.Context, s *interp.Runner) error { files, ok := dec.GetFuncP(filesFuncName, func(ctx context.Context, s *interp.Runner) error {
// It should be done via interp.RunnerOption, // It should be done via interp.RunnerOption,
// but due to the issues below, it cannot be done. // but due to the issues below, it cannot be done.
@ -636,8 +715,8 @@ func (b *Builder) executeFunctions(
return output, nil return output, nil
} }
func (b *Builder) installOptDeps(ctx context.Context, vars *types.BuildVars) error { func (b *Builder) installOptDeps(ctx context.Context, optDepends []string) error {
optDeps, err := removeAlreadyInstalled(b.opts, vars.OptDepends) optDeps, err := removeAlreadyInstalled(b.opts, optDepends)
if err != nil { if err != nil {
return err return err
} }
@ -683,9 +762,24 @@ func (b *Builder) InstallPkgs(
} }
func (b *Builder) InstallALRPackages(ctx context.Context, pkgs []db.Package, opts types.BuildOpts) { func (b *Builder) InstallALRPackages(ctx context.Context, pkgs []db.Package, opts types.BuildOpts) {
type x struct {
pkg *db.Package
packages []string
}
xx := make(map[string]*x)
for _, pkg := range pkgs { for _, pkg := range pkgs {
if xx[pkg.BasePkgName] == nil {
xx[pkg.BasePkgName] = &x{
pkg: &pkg,
}
}
xx[pkg.BasePkgName].packages = append(xx[pkg.BasePkgName].packages, pkg.Name)
}
for basePkgName := range xx {
pkg := xx[basePkgName].pkg
builder := *b builder := *b
builder.UpdateOptsFromPkg(&pkg) builder.UpdateOptsFromPkg(pkg, xx[basePkgName].packages)
builtPkgs, _, err := builder.BuildPackage(ctx) builtPkgs, _, err := builder.BuildPackage(ctx)
// Выполняем сборку пакета // Выполняем сборку пакета

@ -191,7 +191,7 @@ rm -f %s`, tmpFilePath)
fl, err := syntax.NewParser().Parse(strings.NewReader(testScript), "alr.sh") fl, err := syntax.NewParser().Parse(strings.NewReader(testScript), "alr.sh")
assert.NoError(t, err) assert.NoError(t, err)
_, err = b.executeFirstPass(fl) _, _, err = b.executeFirstPass(fl)
assert.NoError(t, err) assert.NoError(t, err)
_, err = os.Stat(tmpFilePath) _, err = os.Stat(tmpFilePath)
@ -203,7 +203,7 @@ func TestExecuteFirstPassIsCorrect(t *testing.T) {
Name string Name string
Script string Script string
Opts types.BuildOpts Opts types.BuildOpts
Expected func(t *testing.T, vars *types.BuildVars) Expected func(t *testing.T, vars []*types.BuildVars)
} }
for _, tc := range []testCase{{ for _, tc := range []testCase{{
@ -220,12 +220,13 @@ maintainer='Ivan Ivanov'
Manager: &TestManager{}, Manager: &TestManager{},
Interactive: false, Interactive: false,
}, },
Expected: func(t *testing.T, vars *types.BuildVars) { Expected: func(t *testing.T, vars []*types.BuildVars) {
assert.Equal(t, vars.Name, "test") assert.Equal(t, 1, len(vars))
assert.Equal(t, vars.Version, "1.0.0") assert.Equal(t, vars[0].Name, "test")
assert.Equal(t, vars.Release, int(1)) assert.Equal(t, vars[0].Version, "1.0.0")
assert.Equal(t, vars.Epoch, uint(2)) assert.Equal(t, vars[0].Release, int(1))
assert.Equal(t, vars.Description, "Test package") assert.Equal(t, vars[0].Epoch, uint(2))
assert.Equal(t, vars[0].Description, "Test package")
}, },
}, { }, {
Name: "multiple packages", Name: "multiple packages",
@ -248,13 +249,14 @@ meta_bar() {
} }
`, `,
Opts: types.BuildOpts{ Opts: types.BuildOpts{
Package: "foo", Packages: []string{"foo"},
Manager: &TestManager{}, Manager: &TestManager{},
Interactive: false, Interactive: false,
}, },
Expected: func(t *testing.T, vars *types.BuildVars) { Expected: func(t *testing.T, vars []*types.BuildVars) {
assert.Equal(t, vars.Name, "foo") assert.Equal(t, 1, len(vars))
assert.Equal(t, vars.Description, "Foo package") assert.Equal(t, vars[0].Name, "foo")
assert.Equal(t, vars[0].Description, "Foo package")
}, },
}} { }} {
t.Run(tc.Name, func(t *testing.T) { t.Run(tc.Name, func(t *testing.T) {
@ -275,10 +277,10 @@ meta_bar() {
fl, err := syntax.NewParser().Parse(strings.NewReader(tc.Script), "alr.sh") fl, err := syntax.NewParser().Parse(strings.NewReader(tc.Script), "alr.sh")
assert.NoError(t, err) assert.NoError(t, err)
vars, err := b.executeFirstPass(fl) _, allVars, err := b.executeFirstPass(fl)
assert.NoError(t, err) assert.NoError(t, err)
tc.Expected(t, vars) tc.Expected(t, allVars)
}) })
} }
} }

@ -34,7 +34,6 @@ import (
_ "github.com/goreleaser/nfpm/v2/deb" _ "github.com/goreleaser/nfpm/v2/deb"
_ "github.com/goreleaser/nfpm/v2/rpm" _ "github.com/goreleaser/nfpm/v2/rpm"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"mvdan.cc/sh/v3/interp"
"mvdan.cc/sh/v3/syntax" "mvdan.cc/sh/v3/syntax"
"github.com/goreleaser/nfpm/v2" "github.com/goreleaser/nfpm/v2"
@ -88,7 +87,7 @@ func buildPkgMetadata(
deps []string, deps []string,
preferedContents *[]string, preferedContents *[]string,
) (*nfpm.Info, error) { ) (*nfpm.Info, error) {
pkgInfo := getBasePkgInfo(vars) pkgInfo := getBasePkgInfo(vars, info)
pkgInfo.Description = vars.Description pkgInfo.Description = vars.Description
pkgInfo.Platform = "linux" pkgInfo.Platform = "linux"
pkgInfo.Homepage = vars.Homepage pkgInfo.Homepage = vars.Homepage
@ -108,8 +107,6 @@ func buildPkgMetadata(
}) })
} }
pkgInfo.Release = overrides.ReleasePlatformSpecific(vars.Release, info)
if vars.Epoch != 0 { if vars.Epoch != 0 {
pkgInfo.Epoch = strconv.FormatUint(uint64(vars.Epoch), 10) pkgInfo.Epoch = strconv.FormatUint(uint64(vars.Epoch), 10)
} }
@ -249,8 +246,14 @@ func buildContents(vars *types.BuildVars, dirs types.Directories, preferedConten
// Функция checkForBuiltPackage пытается обнаружить ранее собранный пакет и вернуть его путь // Функция checkForBuiltPackage пытается обнаружить ранее собранный пакет и вернуть его путь
// и true, если нашла. Если нет, возвратит "", false, nil. // и true, если нашла. Если нет, возвратит "", false, nil.
func checkForBuiltPackage(mgr manager.Manager, vars *types.BuildVars, pkgFormat, baseDir string) (string, bool, error) { func checkForBuiltPackage(
filename, err := pkgFileName(vars, pkgFormat) mgr manager.Manager,
vars *types.BuildVars,
pkgFormat,
baseDir string,
info *distro.OSRelease,
) (string, bool, error) {
filename, err := pkgFileName(vars, pkgFormat, info)
if err != nil { if err != nil {
return "", false, err return "", false, err
} }
@ -265,20 +268,20 @@ func checkForBuiltPackage(mgr manager.Manager, vars *types.BuildVars, pkgFormat,
return pkgPath, true, nil return pkgPath, true, nil
} }
func getBasePkgInfo(vars *types.BuildVars) *nfpm.Info { func getBasePkgInfo(vars *types.BuildVars, info *distro.OSRelease) *nfpm.Info {
return &nfpm.Info{ return &nfpm.Info{
Name: vars.Name, Name: vars.Name,
Arch: cpu.Arch(), Arch: cpu.Arch(),
Version: vars.Version, Version: vars.Version,
Release: strconv.Itoa(vars.Release), Release: overrides.ReleasePlatformSpecific(vars.Release, info),
Epoch: strconv.FormatUint(uint64(vars.Epoch), 10), Epoch: strconv.FormatUint(uint64(vars.Epoch), 10),
} }
} }
// pkgFileName returns the filename of the package if it were to be built. // pkgFileName returns the filename of the package if it were to be built.
// This is used to check if the package has already been built. // This is used to check if the package has already been built.
func pkgFileName(vars *types.BuildVars, pkgFormat string) (string, error) { func pkgFileName(vars *types.BuildVars, pkgFormat string, info *distro.OSRelease) (string, error) {
pkgInfo := getBasePkgInfo(vars) pkgInfo := getBasePkgInfo(vars, info)
packager, err := nfpm.Get(pkgFormat) packager, err := nfpm.Get(pkgFormat)
if err != nil { if err != nil {
@ -366,6 +369,7 @@ func setScripts(vars *types.BuildVars, info *nfpm.Info, scriptDir string) {
} }
} }
/*
// Функция setVersion изменяет переменную версии в скрипте runner. // Функция setVersion изменяет переменную версии в скрипте runner.
// Она используется для установки версии на вывод функции version(). // Она используется для установки версии на вывод функции version().
func setVersion(ctx context.Context, r *interp.Runner, to string) error { func setVersion(ctx context.Context, r *interp.Runner, to string) error {
@ -375,7 +379,7 @@ func setVersion(ctx context.Context, r *interp.Runner, to string) error {
} }
return r.Run(ctx, fl) return r.Run(ctx, fl)
} }
*/
// Returns not installed dependencies // Returns not installed dependencies
func removeAlreadyInstalled(opts types.BuildOpts, dependencies []string) ([]string, error) { func removeAlreadyInstalled(opts types.BuildOpts, dependencies []string) ([]string, error) {
filteredPackages := []string{} filteredPackages := []string{}