Исправлена повторная сборка подпакетов мультипакета
All checks were successful
Pre-commit / pre-commit (pull_request) Successful in 4m37s
All checks were successful
Pre-commit / pre-commit (pull_request) Successful in 4m37s
При установке пакета с зависимостями на другие подпакеты того же мультипакета теперь каждый подпакет собирается только один раз.
This commit is contained in:
@@ -39,12 +39,13 @@ import (
|
||||
)
|
||||
|
||||
type BuildInput struct {
|
||||
opts *types.BuildOpts
|
||||
info *distro.OSRelease
|
||||
pkgFormat string
|
||||
script string
|
||||
repository string
|
||||
packages []string
|
||||
opts *types.BuildOpts
|
||||
info *distro.OSRelease
|
||||
pkgFormat string
|
||||
script string
|
||||
repository string
|
||||
packages []string
|
||||
skipDepsBuilding bool // Пропустить сборку зависимостей (используется при вызове из BuildALRDeps)
|
||||
}
|
||||
|
||||
func (bi *BuildInput) GobEncode() ([]byte, error) {
|
||||
@@ -242,9 +243,10 @@ type Builder struct {
|
||||
}
|
||||
|
||||
type BuildArgs struct {
|
||||
Opts *types.BuildOpts
|
||||
Info *distro.OSRelease
|
||||
PkgFormat_ string
|
||||
Opts *types.BuildOpts
|
||||
Info *distro.OSRelease
|
||||
PkgFormat_ string
|
||||
SkipDepsBuilding bool // Пропустить сборку зависимостей (используется при вызове из BuildALRDeps)
|
||||
}
|
||||
|
||||
func (b *BuildArgs) BuildOpts() *types.BuildOpts {
|
||||
@@ -278,12 +280,13 @@ func (b *Builder) BuildPackageFromDb(
|
||||
scriptInfo := b.scriptResolver.ResolveScript(ctx, args.Package)
|
||||
|
||||
return b.BuildPackage(ctx, &BuildInput{
|
||||
script: scriptInfo.Script,
|
||||
repository: scriptInfo.Repository,
|
||||
packages: args.Packages,
|
||||
pkgFormat: args.PkgFormat(),
|
||||
opts: args.Opts,
|
||||
info: args.Info,
|
||||
script: scriptInfo.Script,
|
||||
repository: scriptInfo.Repository,
|
||||
packages: args.Packages,
|
||||
pkgFormat: args.PkgFormat(),
|
||||
opts: args.Opts,
|
||||
info: args.Info,
|
||||
skipDepsBuilding: args.SkipDepsBuilding,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -409,9 +412,10 @@ func (b *Builder) BuildPackage(
|
||||
var filteredDepends []string
|
||||
|
||||
// Создаем набор подпакетов текущего мультипакета для исключения циклических зависимостей
|
||||
// Используем имена из varsOfPackages, так как input.packages может быть пустым
|
||||
currentPackageNames := make(map[string]struct{})
|
||||
for _, pkg := range input.packages {
|
||||
currentPackageNames[pkg] = struct{}{}
|
||||
for _, vars := range varsOfPackages {
|
||||
currentPackageNames[vars.Name] = struct{}{}
|
||||
}
|
||||
|
||||
for _, d := range depends {
|
||||
@@ -423,10 +427,16 @@ func (b *Builder) BuildPackage(
|
||||
}
|
||||
}
|
||||
|
||||
slog.Debug("BuildALRDeps")
|
||||
newBuiltDeps, repoDeps, err := b.BuildALRDeps(ctx, input, filteredDepends)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
var newBuiltDeps []*BuiltDep
|
||||
var repoDeps []string
|
||||
|
||||
// Пропускаем сборку зависимостей если флаг установлен (вызов из BuildALRDeps)
|
||||
if !input.skipDepsBuilding {
|
||||
slog.Debug("BuildALRDeps")
|
||||
newBuiltDeps, repoDeps, err = b.BuildALRDeps(ctx, input, filteredDepends)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
slog.Debug("PrepareDirs")
|
||||
@@ -580,65 +590,68 @@ func (b *Builder) BuildALRDeps(
|
||||
// Системные зависимости возвращаем как repoDeps
|
||||
repoDeps = systemDeps
|
||||
|
||||
// Шаг 2: Собираем список всех пакетов из дерева для топологической сортировки
|
||||
allFound := make(map[string][]alrsh.Package)
|
||||
for baseName, node := range depTree {
|
||||
allFound[baseName] = []alrsh.Package{*node.Package}
|
||||
}
|
||||
|
||||
// Шаг 3: Топологическая сортировка (от корней к листьям)
|
||||
sortedPkgs, err := TopologicalSort(depTree, allFound)
|
||||
// Шаг 2: Топологическая сортировка (от корней к листьям)
|
||||
sortedPkgs, err := TopologicalSort(depTree)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to sort dependencies: %w", err)
|
||||
}
|
||||
|
||||
// Шаг 3: Группируем подпакеты по basePkgName для оптимизации сборки
|
||||
// Если несколько подпакетов из одного мультипакета, собираем их вместе
|
||||
builtBasePkgs := make(map[string]bool) // Уже собранные базовые пакеты
|
||||
|
||||
// Шаг 4: Собираем пакеты в правильном порядке, проверяя кеш
|
||||
for _, basePkgName := range sortedPkgs {
|
||||
node := depTree[basePkgName]
|
||||
for _, pkgName := range sortedPkgs {
|
||||
node := depTree[pkgName]
|
||||
if node == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
pkg := node.Package
|
||||
basePkgName := node.BasePkgName
|
||||
|
||||
// Находим ВСЕ подпакеты с этим BasePkgName
|
||||
allSubpkgs, err := b.findAllSubpackages(ctx, basePkgName, pkg.Repository)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to find subpackages for %s: %w", basePkgName, err)
|
||||
// Если базовый пакет уже собран, пропускаем
|
||||
if builtBasePkgs[basePkgName] {
|
||||
continue
|
||||
}
|
||||
|
||||
// Проверяем кеш для ВСЕХ подпакетов
|
||||
// Собираем только запрошенный подпакет (или все, если запрошен basePkgName)
|
||||
packagesToBuilt := []string{pkgName}
|
||||
|
||||
// Проверяем кеш для запрошенного подпакета
|
||||
scriptInfo := b.scriptResolver.ResolveScript(ctx, pkg)
|
||||
buildInput := &BuildInput{
|
||||
script: scriptInfo.Script,
|
||||
repository: scriptInfo.Repository,
|
||||
packages: allSubpkgs,
|
||||
packages: packagesToBuilt,
|
||||
pkgFormat: input.PkgFormat(),
|
||||
opts: input.BuildOpts(),
|
||||
info: input.OSRelease(),
|
||||
}
|
||||
|
||||
cachedDeps, allInCache, err := b.checkCacheForAllSubpackages(ctx, buildInput, basePkgName, allSubpkgs)
|
||||
cachedDeps, allInCache, err := b.checkCacheForAllSubpackages(ctx, buildInput, basePkgName, packagesToBuilt)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if allInCache {
|
||||
// Все подпакеты в кеше, используем их
|
||||
// Подпакет в кеше, используем его
|
||||
buildDeps = append(buildDeps, cachedDeps...)
|
||||
continue
|
||||
}
|
||||
|
||||
// Собираем пакет (без рекурсивной сборки зависимостей, так как они уже собраны)
|
||||
// Собираем только запрошенный подпакет
|
||||
// SkipDepsBuilding: true предотвращает рекурсивный вызов BuildALRDeps
|
||||
res, err := b.BuildPackageFromDb(
|
||||
ctx,
|
||||
&BuildPackageFromDbArgs{
|
||||
Package: pkg,
|
||||
Packages: allSubpkgs,
|
||||
Packages: packagesToBuilt,
|
||||
BuildArgs: BuildArgs{
|
||||
Opts: input.BuildOpts(),
|
||||
Info: input.OSRelease(),
|
||||
PkgFormat_: input.PkgFormat(),
|
||||
Opts: input.BuildOpts(),
|
||||
Info: input.OSRelease(),
|
||||
PkgFormat_: input.PkgFormat(),
|
||||
SkipDepsBuilding: true,
|
||||
},
|
||||
},
|
||||
)
|
||||
@@ -647,6 +660,7 @@ func (b *Builder) BuildALRDeps(
|
||||
}
|
||||
|
||||
buildDeps = append(buildDeps, res...)
|
||||
builtBasePkgs[basePkgName] = true
|
||||
}
|
||||
|
||||
buildDeps = removeDuplicates(buildDeps)
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
type DependencyNode struct {
|
||||
Package *alrsh.Package
|
||||
BasePkgName string
|
||||
PkgName string // Имя конкретного подпакета (может отличаться от BasePkgName)
|
||||
Dependencies []string // Имена зависимостей
|
||||
}
|
||||
|
||||
@@ -82,8 +83,9 @@ func (b *Builder) ResolveDependencyTree(
|
||||
baseName = pkg.Name
|
||||
}
|
||||
|
||||
// Если уже обработали этот базовый пакет, пропускаем
|
||||
if resolved[baseName] != nil {
|
||||
// Используем имя конкретного подпакета как ключ (не basePkgName)
|
||||
// Это позволяет собирать только запрошенный подпакет, а не весь мультипакет
|
||||
if resolved[pkgName] != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -96,10 +98,11 @@ func (b *Builder) ResolveDependencyTree(
|
||||
allDeps := append([]string{}, deps...)
|
||||
allDeps = append(allDeps, buildDeps...)
|
||||
|
||||
// Добавляем узел в resolved
|
||||
resolved[baseName] = &DependencyNode{
|
||||
// Добавляем узел в resolved с ключом = имя подпакета
|
||||
resolved[pkgName] = &DependencyNode{
|
||||
Package: &pkg,
|
||||
BasePkgName: baseName,
|
||||
PkgName: pkgName,
|
||||
Dependencies: allDeps,
|
||||
}
|
||||
|
||||
@@ -129,8 +132,8 @@ func (b *Builder) ResolveDependencyTree(
|
||||
}
|
||||
|
||||
// TopologicalSort выполняет топологическую сортировку пакетов по зависимостям
|
||||
// Возвращает список базовых имен пакетов в порядке сборки (от корней к листьям)
|
||||
func TopologicalSort(nodes map[string]*DependencyNode, allPkgs map[string][]alrsh.Package) ([]string, error) {
|
||||
// Возвращает список имен подпакетов в порядке сборки (от корней к листьям)
|
||||
func TopologicalSort(nodes map[string]*DependencyNode) ([]string, error) {
|
||||
// Список для результата
|
||||
var result []string
|
||||
|
||||
@@ -140,51 +143,42 @@ func TopologicalSort(nodes map[string]*DependencyNode, allPkgs map[string][]alrs
|
||||
// Множество узлов в текущем пути (для обнаружения циклов)
|
||||
inStack := make(map[string]bool)
|
||||
|
||||
var visit func(basePkgName string) error
|
||||
visit = func(basePkgName string) error {
|
||||
if visited[basePkgName] {
|
||||
var visit func(pkgName string) error
|
||||
visit = func(pkgName string) error {
|
||||
if visited[pkgName] {
|
||||
return nil
|
||||
}
|
||||
|
||||
if inStack[basePkgName] {
|
||||
return fmt.Errorf("circular dependency detected: %s", basePkgName)
|
||||
if inStack[pkgName] {
|
||||
return fmt.Errorf("circular dependency detected: %s", pkgName)
|
||||
}
|
||||
|
||||
node := nodes[basePkgName]
|
||||
node := nodes[pkgName]
|
||||
if node == nil {
|
||||
// Это системный пакет, игнорируем
|
||||
// Это системный пакет или пакет не в дереве, игнорируем
|
||||
return nil
|
||||
}
|
||||
|
||||
inStack[basePkgName] = true
|
||||
inStack[pkgName] = true
|
||||
|
||||
// Посещаем все зависимости
|
||||
for _, dep := range node.Dependencies {
|
||||
// Находим базовое имя для зависимости
|
||||
depBaseName := dep
|
||||
|
||||
// Проверяем, есть ли этот пакет в allPkgs
|
||||
if pkgs, ok := allPkgs[dep]; ok && len(pkgs) > 0 {
|
||||
if pkgs[0].BasePkgName != "" {
|
||||
depBaseName = pkgs[0].BasePkgName
|
||||
}
|
||||
}
|
||||
|
||||
if err := visit(depBaseName); err != nil {
|
||||
// Используем имя зависимости напрямую (это имя подпакета)
|
||||
if err := visit(dep); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
inStack[basePkgName] = false
|
||||
visited[basePkgName] = true
|
||||
result = append(result, basePkgName)
|
||||
inStack[pkgName] = false
|
||||
visited[pkgName] = true
|
||||
result = append(result, pkgName)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Посещаем все узлы
|
||||
for basePkgName := range nodes {
|
||||
if err := visit(basePkgName); err != nil {
|
||||
for pkgName := range nodes {
|
||||
if err := visit(pkgName); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user