refactor: move pkg/ to internal/ and update imports
	
		
			
	
		
	
	
				
					
				
			Restructure project by relocating package contents from pkg/ to internal/ to better reflect internal-only usage. This commit is initial step to prepare project for public api
This commit is contained in:
		
							
								
								
									
										738
									
								
								internal/build/build.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										738
									
								
								internal/build/build.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,738 @@ | ||||
| // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan. | ||||
| // It has been modified as part of "ALR - Any Linux Repository" by the ALR Authors. | ||||
| // | ||||
| // ALR - Any Linux Repository | ||||
| // Copyright (C) 2025 The ALR Authors | ||||
| // | ||||
| // This program is free software: you can redistribute it and/or modify | ||||
| // it under the terms of the GNU General Public License as published by | ||||
| // the Free Software Foundation, either version 3 of the License, or | ||||
| // (at your option) any later version. | ||||
| // | ||||
| // This program is distributed in the hope that it will be useful, | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| // GNU General Public License for more details. | ||||
| // | ||||
| // You should have received a copy of the GNU General Public License | ||||
| // along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  | ||||
| package build | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"context" | ||||
| 	"encoding/gob" | ||||
| 	"errors" | ||||
| 	"log/slog" | ||||
|  | ||||
| 	"github.com/leonelquinteros/gotext" | ||||
| 	"mvdan.cc/sh/v3/syntax" | ||||
| 	"mvdan.cc/sh/v3/syntax/typedjson" | ||||
|  | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils" | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/config" | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/db" | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/distro" | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/manager" | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/types" | ||||
| ) | ||||
|  | ||||
| type BuildInput struct { | ||||
| 	opts       *types.BuildOpts | ||||
| 	info       *distro.OSRelease | ||||
| 	pkgFormat  string | ||||
| 	script     string | ||||
| 	repository string | ||||
| 	packages   []string | ||||
| } | ||||
|  | ||||
| func (bi *BuildInput) GobEncode() ([]byte, error) { | ||||
| 	w := new(bytes.Buffer) | ||||
| 	encoder := gob.NewEncoder(w) | ||||
|  | ||||
| 	if err := encoder.Encode(bi.opts); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if err := encoder.Encode(bi.info); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if err := encoder.Encode(bi.pkgFormat); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if err := encoder.Encode(bi.script); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if err := encoder.Encode(bi.repository); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if err := encoder.Encode(bi.packages); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return w.Bytes(), nil | ||||
| } | ||||
|  | ||||
| func (bi *BuildInput) GobDecode(data []byte) error { | ||||
| 	r := bytes.NewBuffer(data) | ||||
| 	decoder := gob.NewDecoder(r) | ||||
|  | ||||
| 	if err := decoder.Decode(&bi.opts); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err := decoder.Decode(&bi.info); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err := decoder.Decode(&bi.pkgFormat); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err := decoder.Decode(&bi.script); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err := decoder.Decode(&bi.repository); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err := decoder.Decode(&bi.packages); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (b *BuildInput) Repository() string { | ||||
| 	return b.repository | ||||
| } | ||||
|  | ||||
| func (b *BuildInput) BuildOpts() *types.BuildOpts { | ||||
| 	return b.opts | ||||
| } | ||||
|  | ||||
| func (b *BuildInput) OSRelease() *distro.OSRelease { | ||||
| 	return b.info | ||||
| } | ||||
|  | ||||
| func (b *BuildInput) PkgFormat() string { | ||||
| 	return b.pkgFormat | ||||
| } | ||||
|  | ||||
| type BuildOptsProvider interface { | ||||
| 	BuildOpts() *types.BuildOpts | ||||
| } | ||||
|  | ||||
| type OsInfoProvider interface { | ||||
| 	OSRelease() *distro.OSRelease | ||||
| } | ||||
|  | ||||
| type PkgFormatProvider interface { | ||||
| 	PkgFormat() string | ||||
| } | ||||
|  | ||||
| type RepositoryProvider interface { | ||||
| 	Repository() string | ||||
| } | ||||
|  | ||||
| // ================================================ | ||||
|  | ||||
| type ScriptFile struct { | ||||
| 	File *syntax.File | ||||
| 	Path string | ||||
| } | ||||
|  | ||||
| func (s *ScriptFile) GobEncode() ([]byte, error) { | ||||
| 	var buf bytes.Buffer | ||||
| 	enc := gob.NewEncoder(&buf) | ||||
| 	if err := enc.Encode(s.Path); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	var fileBuf bytes.Buffer | ||||
| 	if err := typedjson.Encode(&fileBuf, s.File); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	fileData := fileBuf.Bytes() | ||||
| 	if err := enc.Encode(fileData); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return buf.Bytes(), nil | ||||
| } | ||||
|  | ||||
| func (s *ScriptFile) GobDecode(data []byte) error { | ||||
| 	buf := bytes.NewBuffer(data) | ||||
| 	dec := gob.NewDecoder(buf) | ||||
| 	if err := dec.Decode(&s.Path); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	var fileData []byte | ||||
| 	if err := dec.Decode(&fileData); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	fileReader := bytes.NewReader(fileData) | ||||
| 	file, err := typedjson.Decode(fileReader) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	s.File = file.(*syntax.File) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type BuiltDep struct { | ||||
| 	Name string | ||||
| 	Path string | ||||
| } | ||||
|  | ||||
| func Map[T, R any](items []T, f func(T) R) []R { | ||||
| 	res := make([]R, len(items)) | ||||
| 	for i, item := range items { | ||||
| 		res[i] = f(item) | ||||
| 	} | ||||
| 	return res | ||||
| } | ||||
|  | ||||
| func GetBuiltPaths(deps []*BuiltDep) []string { | ||||
| 	return Map(deps, func(dep *BuiltDep) string { | ||||
| 		return dep.Path | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func GetBuiltName(deps []*BuiltDep) []string { | ||||
| 	return Map(deps, func(dep *BuiltDep) string { | ||||
| 		return dep.Name | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| type PackageFinder interface { | ||||
| 	FindPkgs(ctx context.Context, pkgs []string) (map[string][]db.Package, []string, error) | ||||
| } | ||||
|  | ||||
| type Config interface { | ||||
| 	GetPaths() *config.Paths | ||||
| 	PagerStyle() string | ||||
| } | ||||
|  | ||||
| type FunctionsOutput struct { | ||||
| 	Contents *[]string | ||||
| } | ||||
|  | ||||
| // EXECUTORS | ||||
|  | ||||
| type ScriptResolverExecutor interface { | ||||
| 	ResolveScript(ctx context.Context, pkg *db.Package) *ScriptInfo | ||||
| } | ||||
|  | ||||
| type ScriptExecutor interface { | ||||
| 	ReadScript(ctx context.Context, scriptPath string) (*ScriptFile, error) | ||||
| 	ExecuteFirstPass(ctx context.Context, input *BuildInput, sf *ScriptFile) (string, []*types.BuildVars, error) | ||||
| 	PrepareDirs( | ||||
| 		ctx context.Context, | ||||
| 		input *BuildInput, | ||||
| 		basePkg string, | ||||
| 	) error | ||||
| 	ExecuteSecondPass( | ||||
| 		ctx context.Context, | ||||
| 		input *BuildInput, | ||||
| 		sf *ScriptFile, | ||||
| 		varsOfPackages []*types.BuildVars, | ||||
| 		repoDeps []string, | ||||
| 		builtDeps []*BuiltDep, | ||||
| 		basePkg string, | ||||
| 	) ([]*BuiltDep, error) | ||||
| } | ||||
|  | ||||
| type CacheExecutor interface { | ||||
| 	CheckForBuiltPackage(ctx context.Context, input *BuildInput, vars *types.BuildVars) (string, bool, error) | ||||
| } | ||||
|  | ||||
| type ScriptViewerExecutor interface { | ||||
| 	ViewScript(ctx context.Context, input *BuildInput, sf *ScriptFile, basePkg string) error | ||||
| } | ||||
|  | ||||
| type CheckerExecutor interface { | ||||
| 	PerformChecks( | ||||
| 		ctx context.Context, | ||||
| 		input *BuildInput, | ||||
| 		vars *types.BuildVars, | ||||
| 	) (bool, error) | ||||
| } | ||||
|  | ||||
| type InstallerExecutor interface { | ||||
| 	InstallLocal(paths []string, opts *manager.Opts) error | ||||
| 	Install(pkgs []string, opts *manager.Opts) error | ||||
| 	RemoveAlreadyInstalled(pkgs []string) ([]string, error) | ||||
| } | ||||
|  | ||||
| type SourcesInput struct { | ||||
| 	Sources   []string | ||||
| 	Checksums []string | ||||
| } | ||||
|  | ||||
| type SourceDownloaderExecutor interface { | ||||
| 	DownloadSources( | ||||
| 		ctx context.Context, | ||||
| 		input *BuildInput, | ||||
| 		basePkg string, | ||||
| 		si SourcesInput, | ||||
| 	) error | ||||
| } | ||||
|  | ||||
| // | ||||
|  | ||||
| func NewBuilder( | ||||
| 	scriptResolver ScriptResolverExecutor, | ||||
| 	scriptExecutor ScriptExecutor, | ||||
| 	cacheExecutor CacheExecutor, | ||||
| 	scriptViewerExecutor ScriptViewerExecutor, | ||||
| 	checkerExecutor CheckerExecutor, | ||||
| 	installerExecutor InstallerExecutor, | ||||
| 	sourceExecutor SourceDownloaderExecutor, | ||||
| ) *Builder { | ||||
| 	return &Builder{ | ||||
| 		scriptResolver:       scriptResolver, | ||||
| 		scriptExecutor:       scriptExecutor, | ||||
| 		cacheExecutor:        cacheExecutor, | ||||
| 		scriptViewerExecutor: scriptViewerExecutor, | ||||
| 		checkerExecutor:      checkerExecutor, | ||||
| 		installerExecutor:    installerExecutor, | ||||
| 		sourceExecutor:       sourceExecutor, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type Builder struct { | ||||
| 	scriptResolver       ScriptResolverExecutor | ||||
| 	scriptExecutor       ScriptExecutor | ||||
| 	cacheExecutor        CacheExecutor | ||||
| 	scriptViewerExecutor ScriptViewerExecutor | ||||
| 	checkerExecutor      CheckerExecutor | ||||
| 	installerExecutor    InstallerExecutor | ||||
| 	sourceExecutor       SourceDownloaderExecutor | ||||
| 	repos                PackageFinder | ||||
| 	// mgr                  manager.Manager | ||||
| } | ||||
|  | ||||
| type BuildArgs struct { | ||||
| 	Opts       *types.BuildOpts | ||||
| 	Info       *distro.OSRelease | ||||
| 	PkgFormat_ string | ||||
| } | ||||
|  | ||||
| func (b *BuildArgs) BuildOpts() *types.BuildOpts { | ||||
| 	return b.Opts | ||||
| } | ||||
|  | ||||
| func (b *BuildArgs) OSRelease() *distro.OSRelease { | ||||
| 	return b.Info | ||||
| } | ||||
|  | ||||
| func (b *BuildArgs) PkgFormat() string { | ||||
| 	return b.PkgFormat_ | ||||
| } | ||||
|  | ||||
| type BuildPackageFromDbArgs struct { | ||||
| 	BuildArgs | ||||
| 	Package  *db.Package | ||||
| 	Packages []string | ||||
| } | ||||
|  | ||||
| type BuildPackageFromScriptArgs struct { | ||||
| 	BuildArgs | ||||
| 	Script   string | ||||
| 	Packages []string | ||||
| } | ||||
|  | ||||
| func (b *Builder) BuildPackageFromDb( | ||||
| 	ctx context.Context, | ||||
| 	args *BuildPackageFromDbArgs, | ||||
| ) ([]*BuiltDep, error) { | ||||
| 	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, | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func (b *Builder) BuildPackageFromScript( | ||||
| 	ctx context.Context, | ||||
| 	args *BuildPackageFromScriptArgs, | ||||
| ) ([]*BuiltDep, error) { | ||||
| 	return b.BuildPackage(ctx, &BuildInput{ | ||||
| 		script:     args.Script, | ||||
| 		repository: "default", | ||||
| 		packages:   args.Packages, | ||||
| 		pkgFormat:  args.PkgFormat(), | ||||
| 		opts:       args.Opts, | ||||
| 		info:       args.Info, | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func (b *Builder) BuildPackage( | ||||
| 	ctx context.Context, | ||||
| 	input *BuildInput, | ||||
| ) ([]*BuiltDep, error) { | ||||
| 	scriptPath := input.script | ||||
|  | ||||
| 	slog.Debug("ReadScript") | ||||
| 	sf, err := b.scriptExecutor.ReadScript(ctx, scriptPath) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	slog.Debug("ExecuteFirstPass") | ||||
| 	basePkg, varsOfPackages, err := b.scriptExecutor.ExecuteFirstPass(ctx, input, sf) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	var builtDeps []*BuiltDep | ||||
|  | ||||
| 	if !input.opts.Clean { | ||||
| 		var remainingVars []*types.BuildVars | ||||
| 		for _, vars := range varsOfPackages { | ||||
| 			builtPkgPath, ok, err := b.cacheExecutor.CheckForBuiltPackage(ctx, input, vars) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			if ok { | ||||
| 				builtDeps = append(builtDeps, &BuiltDep{ | ||||
| 					Path: builtPkgPath, | ||||
| 				}) | ||||
| 			} else { | ||||
| 				remainingVars = append(remainingVars, vars) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if len(remainingVars) == 0 { | ||||
| 			return builtDeps, nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	slog.Debug("ViewScript") | ||||
| 	err = b.scriptViewerExecutor.ViewScript(ctx, input, sf, basePkg) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	slog.Info(gotext.Get("Building package"), "name", basePkg) | ||||
|  | ||||
| 	for _, vars := range varsOfPackages { | ||||
| 		cont, err := b.checkerExecutor.PerformChecks(ctx, input, vars) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		if !cont { | ||||
| 			return nil, errors.New("exit...") | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	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) | ||||
|  | ||||
| 	if len(sources) != len(checksums) { | ||||
| 		slog.Error(gotext.Get("The checksums array must be the same length as sources")) | ||||
| 		return nil, errors.New("exit...") | ||||
| 	} | ||||
| 	sources, checksums = removeDuplicatesSources(sources, checksums) | ||||
|  | ||||
| 	slog.Debug("installBuildDeps") | ||||
| 	alrBuildDeps, err := b.installBuildDeps(ctx, input, buildDepends) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	slog.Debug("installOptDeps") | ||||
| 	_, err = b.installOptDeps(ctx, input, optDepends) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	depNames := make(map[string]struct{}) | ||||
| 	for _, dep := range alrBuildDeps { | ||||
| 		depNames[dep.Name] = struct{}{} | ||||
| 	} | ||||
|  | ||||
| 	// We filter so as not to re-build what has already been built at the `installBuildDeps` stage. | ||||
| 	var filteredDepends []string | ||||
| 	for _, d := range depends { | ||||
| 		if _, found := depNames[d]; !found { | ||||
| 			filteredDepends = append(filteredDepends, d) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	slog.Debug("BuildALRDeps") | ||||
| 	newBuiltDeps, repoDeps, err := b.BuildALRDeps(ctx, input, filteredDepends) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	slog.Debug("PrepareDirs") | ||||
| 	err = b.scriptExecutor.PrepareDirs(ctx, input, basePkg) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	slog.Info(gotext.Get("Downloading sources")) | ||||
| 	slog.Debug("DownloadSources") | ||||
| 	err = b.sourceExecutor.DownloadSources( | ||||
| 		ctx, | ||||
| 		input, | ||||
| 		basePkg, | ||||
| 		SourcesInput{ | ||||
| 			Sources:   sources, | ||||
| 			Checksums: checksums, | ||||
| 		}, | ||||
| 	) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	builtDeps = removeDuplicates(append(builtDeps, newBuiltDeps...)) | ||||
|  | ||||
| 	slog.Debug("ExecuteSecondPass") | ||||
| 	res, err := b.scriptExecutor.ExecuteSecondPass( | ||||
| 		ctx, | ||||
| 		input, | ||||
| 		sf, | ||||
| 		varsOfPackages, | ||||
| 		repoDeps, | ||||
| 		builtDeps, | ||||
| 		basePkg, | ||||
| 	) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	builtDeps = removeDuplicates(append(builtDeps, res...)) | ||||
|  | ||||
| 	return builtDeps, nil | ||||
| } | ||||
|  | ||||
| type InstallPkgsArgs struct { | ||||
| 	BuildArgs | ||||
| 	AlrPkgs    []db.Package | ||||
| 	NativePkgs []string | ||||
| } | ||||
|  | ||||
| func (b *Builder) InstallALRPackages( | ||||
| 	ctx context.Context, | ||||
| 	input interface { | ||||
| 		OsInfoProvider | ||||
| 		BuildOptsProvider | ||||
| 		PkgFormatProvider | ||||
| 	}, | ||||
| 	alrPkgs []db.Package, | ||||
| ) error { | ||||
| 	for _, pkg := range alrPkgs { | ||||
| 		res, err := b.BuildPackageFromDb( | ||||
| 			ctx, | ||||
| 			&BuildPackageFromDbArgs{ | ||||
| 				Package:  &pkg, | ||||
| 				Packages: []string{}, | ||||
| 				BuildArgs: BuildArgs{ | ||||
| 					Opts:       input.BuildOpts(), | ||||
| 					Info:       input.OSRelease(), | ||||
| 					PkgFormat_: input.PkgFormat(), | ||||
| 				}, | ||||
| 			}, | ||||
| 		) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		err = b.installerExecutor.InstallLocal( | ||||
| 			GetBuiltPaths(res), | ||||
| 			&manager.Opts{ | ||||
| 				NoConfirm: !input.BuildOpts().Interactive, | ||||
| 			}, | ||||
| 		) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (b *Builder) BuildALRDeps( | ||||
| 	ctx context.Context, | ||||
| 	input interface { | ||||
| 		OsInfoProvider | ||||
| 		BuildOptsProvider | ||||
| 		PkgFormatProvider | ||||
| 	}, | ||||
| 	depends []string, | ||||
| ) (buildDeps []*BuiltDep, repoDeps []string, err error) { | ||||
| 	if len(depends) > 0 { | ||||
| 		slog.Info(gotext.Get("Installing dependencies")) | ||||
|  | ||||
| 		found, notFound, err := b.repos.FindPkgs(ctx, depends) // Поиск зависимостей | ||||
| 		if err != nil { | ||||
| 			return nil, nil, err | ||||
| 		} | ||||
| 		repoDeps = notFound | ||||
|  | ||||
| 		// Если для некоторых пакетов есть несколько опций, упрощаем их все в один срез | ||||
| 		pkgs := cliutils.FlattenPkgs( | ||||
| 			ctx, | ||||
| 			found, | ||||
| 			"install", | ||||
| 			input.BuildOpts().Interactive, | ||||
| 		) | ||||
| 		type item struct { | ||||
| 			pkg      *db.Package | ||||
| 			packages []string | ||||
| 		} | ||||
| 		pkgsMap := make(map[string]*item) | ||||
| 		for _, pkg := range pkgs { | ||||
| 			name := pkg.BasePkgName | ||||
| 			if name == "" { | ||||
| 				name = pkg.Name | ||||
| 			} | ||||
| 			if pkgsMap[name] == nil { | ||||
| 				pkgsMap[name] = &item{ | ||||
| 					pkg: &pkg, | ||||
| 				} | ||||
| 			} | ||||
| 			pkgsMap[name].packages = append( | ||||
| 				pkgsMap[name].packages, | ||||
| 				pkg.Name, | ||||
| 			) | ||||
| 		} | ||||
|  | ||||
| 		for basePkgName := range pkgsMap { | ||||
| 			pkg := pkgsMap[basePkgName].pkg | ||||
| 			res, err := b.BuildPackageFromDb( | ||||
| 				ctx, | ||||
| 				&BuildPackageFromDbArgs{ | ||||
| 					Package:  pkg, | ||||
| 					Packages: pkgsMap[basePkgName].packages, | ||||
| 					BuildArgs: BuildArgs{ | ||||
| 						Opts:       input.BuildOpts(), | ||||
| 						Info:       input.OSRelease(), | ||||
| 						PkgFormat_: input.PkgFormat(), | ||||
| 					}, | ||||
| 				}, | ||||
| 			) | ||||
| 			if err != nil { | ||||
| 				return nil, nil, err | ||||
| 			} | ||||
|  | ||||
| 			buildDeps = append(buildDeps, res...) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	repoDeps = removeDuplicates(repoDeps) | ||||
| 	buildDeps = removeDuplicates(buildDeps) | ||||
|  | ||||
| 	return buildDeps, repoDeps, nil | ||||
| } | ||||
|  | ||||
| func (i *Builder) installBuildDeps( | ||||
| 	ctx context.Context, | ||||
| 	input interface { | ||||
| 		OsInfoProvider | ||||
| 		BuildOptsProvider | ||||
| 		PkgFormatProvider | ||||
| 	}, | ||||
| 	pkgs []string, | ||||
| ) ([]*BuiltDep, error) { | ||||
| 	var builtDeps []*BuiltDep | ||||
| 	if len(pkgs) > 0 { | ||||
| 		deps, err := i.installerExecutor.RemoveAlreadyInstalled(pkgs) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		builtDeps, err = i.InstallPkgs(ctx, input, deps) // Устанавливаем выбранные пакеты | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 	return builtDeps, nil | ||||
| } | ||||
|  | ||||
| func (i *Builder) installOptDeps( | ||||
| 	ctx context.Context, | ||||
| 	input interface { | ||||
| 		OsInfoProvider | ||||
| 		BuildOptsProvider | ||||
| 		PkgFormatProvider | ||||
| 	}, | ||||
| 	pkgs []string, | ||||
| ) ([]*BuiltDep, error) { | ||||
| 	var builtDeps []*BuiltDep | ||||
| 	optDeps, err := i.installerExecutor.RemoveAlreadyInstalled(pkgs) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if len(optDeps) > 0 { | ||||
| 		optDeps, err := cliutils.ChooseOptDepends( | ||||
| 			ctx, | ||||
| 			optDeps, | ||||
| 			"install", | ||||
| 			input.BuildOpts().Interactive, | ||||
| 		) // Пользователя просят выбрать опциональные зависимости | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		if len(optDeps) == 0 { | ||||
| 			return builtDeps, nil | ||||
| 		} | ||||
|  | ||||
| 		builtDeps, err = i.InstallPkgs(ctx, input, optDeps) // Устанавливаем выбранные пакеты | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 	return builtDeps, nil | ||||
| } | ||||
|  | ||||
| func (i *Builder) InstallPkgs( | ||||
| 	ctx context.Context, | ||||
| 	input interface { | ||||
| 		OsInfoProvider | ||||
| 		BuildOptsProvider | ||||
| 		PkgFormatProvider | ||||
| 	}, | ||||
| 	pkgs []string, | ||||
| ) ([]*BuiltDep, error) { | ||||
| 	builtDeps, repoDeps, err := i.BuildALRDeps(ctx, input, pkgs) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	if len(builtDeps) > 0 { | ||||
| 		err = i.installerExecutor.InstallLocal(GetBuiltPaths(builtDeps), &manager.Opts{ | ||||
| 			NoConfirm: !input.BuildOpts().Interactive, | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if len(repoDeps) > 0 { | ||||
| 		err = i.installerExecutor.Install(repoDeps, &manager.Opts{ | ||||
| 			NoConfirm: !input.BuildOpts().Interactive, | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return builtDeps, nil | ||||
| } | ||||
		Reference in New Issue
	
	Block a user