refactor: keep only one struct for package
This commit is contained in:
		| @@ -11,7 +11,7 @@ | |||||||
|     <g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"> |     <g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"> | ||||||
|         <text x="33.5" y="15" fill="#010101" fill-opacity=".3">coverage</text> |         <text x="33.5" y="15" fill="#010101" fill-opacity=".3">coverage</text> | ||||||
|         <text x="33.5" y="14">coverage</text> |         <text x="33.5" y="14">coverage</text> | ||||||
|         <text x="86" y="15" fill="#010101" fill-opacity=".3">16.5%</text> |         <text x="86" y="15" fill="#010101" fill-opacity=".3">17.6%</text> | ||||||
|         <text x="86" y="14">16.5%</text> |         <text x="86" y="14">17.6%</text> | ||||||
|     </g> |     </g> | ||||||
| </svg> | </svg> | ||||||
|   | |||||||
| Before Width: | Height: | Size: 926 B After Width: | Height: | Size: 926 B | 
| @@ -31,8 +31,8 @@ func TestE2EGroupAndSummaryField(t *testing.T) { | |||||||
| 		RPM_SYSTEMS, | 		RPM_SYSTEMS, | ||||||
| 		func(t *testing.T, r e2e.Runnable) { | 		func(t *testing.T, r e2e.Runnable) { | ||||||
| 			defaultPrepare(t, r) | 			defaultPrepare(t, r) | ||||||
| 			execShouldNoError(t, r, "sh", "-c", "alr search --name test-group-and-summary --format \"{{.Group}}\" | grep ^System/Base$") | 			execShouldNoError(t, r, "sh", "-c", "alr search --name test-group-and-summary --format \"{{.Group.Resolved}}\" | grep ^System/Base$") | ||||||
| 			execShouldNoError(t, r, "sh", "-c", "alr search --name test-group-and-summary --format \"{{.Summary}}\" | grep \"^Custom summary$\"") | 			execShouldNoError(t, r, "sh", "-c", "alr search --name test-group-and-summary --format \"{{.Summary.Resolved}}\" | grep \"^Custom summary$\"") | ||||||
| 		}, | 		}, | ||||||
| 	) | 	) | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										5
									
								
								info.go
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								info.go
									
									
									
									
									
								
							| @@ -32,6 +32,7 @@ import ( | |||||||
| 	appbuilder "gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils/app_builder" | 	appbuilder "gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils/app_builder" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/overrides" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/overrides" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/utils" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/utils" | ||||||
|  | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro" | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -88,6 +89,7 @@ func InfoCmd() *cli.Command { | |||||||
| 				New(ctx). | 				New(ctx). | ||||||
| 				WithConfig(). | 				WithConfig(). | ||||||
| 				WithDB(). | 				WithDB(). | ||||||
|  | 				WithDistroInfo(). | ||||||
| 				WithRepos(). | 				WithRepos(). | ||||||
| 				Build() | 				Build() | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| @@ -136,7 +138,8 @@ func InfoCmd() *cli.Command { | |||||||
|  |  | ||||||
| 			for _, pkg := range pkgs { | 			for _, pkg := range pkgs { | ||||||
| 				if !all { | 				if !all { | ||||||
| 					err = yaml.NewEncoder(os.Stdout).Encode(overrides.ResolvePackage(&pkg, names)) | 					alrsh.ResolvePackage(&pkg, names) | ||||||
|  | 					err = yaml.NewEncoder(os.Stdout).Encode(pkg) | ||||||
| 					if err != nil { | 					if err != nil { | ||||||
| 						return cliutils.FormatCliExit(gotext.Get("Error encoding script variables"), err) | 						return cliutils.FormatCliExit(gotext.Get("Error encoding script variables"), err) | ||||||
| 					} | 					} | ||||||
|   | |||||||
| @@ -24,13 +24,13 @@ import ( | |||||||
| 	"context" | 	"context" | ||||||
| 	"encoding/gob" | 	"encoding/gob" | ||||||
| 	"errors" | 	"errors" | ||||||
|  | 	"fmt" | ||||||
| 	"log/slog" | 	"log/slog" | ||||||
|  |  | ||||||
| 	"github.com/leonelquinteros/gotext" | 	"github.com/leonelquinteros/gotext" | ||||||
|  |  | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils" | 	"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/config" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/db" |  | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/manager" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/manager" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh" | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro" | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro" | ||||||
| @@ -158,7 +158,7 @@ func GetBuiltName(deps []*BuiltDep) []string { | |||||||
| } | } | ||||||
|  |  | ||||||
| type PackageFinder interface { | type PackageFinder interface { | ||||||
| 	FindPkgs(ctx context.Context, pkgs []string) (map[string][]db.Package, []string, error) | 	FindPkgs(ctx context.Context, pkgs []string) (map[string][]alrsh.Package, []string, error) | ||||||
| } | } | ||||||
|  |  | ||||||
| type Config interface { | type Config interface { | ||||||
| @@ -173,12 +173,12 @@ type FunctionsOutput struct { | |||||||
| // EXECUTORS | // EXECUTORS | ||||||
|  |  | ||||||
| type ScriptResolverExecutor interface { | type ScriptResolverExecutor interface { | ||||||
| 	ResolveScript(ctx context.Context, pkg *db.Package) *ScriptInfo | 	ResolveScript(ctx context.Context, pkg *alrsh.Package) *ScriptInfo | ||||||
| } | } | ||||||
|  |  | ||||||
| type ScriptExecutor interface { | type ScriptExecutor interface { | ||||||
| 	ReadScript(ctx context.Context, scriptPath string) (*alrsh.ALRSh, error) | 	ReadScript(ctx context.Context, scriptPath string) (*alrsh.ScriptFile, error) | ||||||
| 	ExecuteFirstPass(ctx context.Context, input *BuildInput, sf *alrsh.ALRSh) (string, []*types.BuildVars, error) | 	ExecuteFirstPass(ctx context.Context, input *BuildInput, sf *alrsh.ScriptFile) (string, []*alrsh.Package, error) | ||||||
| 	PrepareDirs( | 	PrepareDirs( | ||||||
| 		ctx context.Context, | 		ctx context.Context, | ||||||
| 		input *BuildInput, | 		input *BuildInput, | ||||||
| @@ -187,8 +187,8 @@ type ScriptExecutor interface { | |||||||
| 	ExecuteSecondPass( | 	ExecuteSecondPass( | ||||||
| 		ctx context.Context, | 		ctx context.Context, | ||||||
| 		input *BuildInput, | 		input *BuildInput, | ||||||
| 		sf *alrsh.ALRSh, | 		sf *alrsh.ScriptFile, | ||||||
| 		varsOfPackages []*types.BuildVars, | 		varsOfPackages []*alrsh.Package, | ||||||
| 		repoDeps []string, | 		repoDeps []string, | ||||||
| 		builtDeps []*BuiltDep, | 		builtDeps []*BuiltDep, | ||||||
| 		basePkg string, | 		basePkg string, | ||||||
| @@ -196,18 +196,18 @@ type ScriptExecutor interface { | |||||||
| } | } | ||||||
|  |  | ||||||
| type CacheExecutor interface { | type CacheExecutor interface { | ||||||
| 	CheckForBuiltPackage(ctx context.Context, input *BuildInput, vars *types.BuildVars) (string, bool, error) | 	CheckForBuiltPackage(ctx context.Context, input *BuildInput, vars *alrsh.Package) (string, bool, error) | ||||||
| } | } | ||||||
|  |  | ||||||
| type ScriptViewerExecutor interface { | type ScriptViewerExecutor interface { | ||||||
| 	ViewScript(ctx context.Context, input *BuildInput, sf *alrsh.ALRSh, basePkg string) error | 	ViewScript(ctx context.Context, input *BuildInput, sf *alrsh.ScriptFile, basePkg string) error | ||||||
| } | } | ||||||
|  |  | ||||||
| type CheckerExecutor interface { | type CheckerExecutor interface { | ||||||
| 	PerformChecks( | 	PerformChecks( | ||||||
| 		ctx context.Context, | 		ctx context.Context, | ||||||
| 		input *BuildInput, | 		input *BuildInput, | ||||||
| 		vars *types.BuildVars, | 		vars *alrsh.Package, | ||||||
| 	) (bool, error) | 	) (bool, error) | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -285,7 +285,7 @@ func (b *BuildArgs) PkgFormat() string { | |||||||
|  |  | ||||||
| type BuildPackageFromDbArgs struct { | type BuildPackageFromDbArgs struct { | ||||||
| 	BuildArgs | 	BuildArgs | ||||||
| 	Package  *db.Package | 	Package  *alrsh.Package | ||||||
| 	Packages []string | 	Packages []string | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -334,19 +334,19 @@ func (b *Builder) BuildPackage( | |||||||
| 	slog.Debug("ReadScript") | 	slog.Debug("ReadScript") | ||||||
| 	sf, err := b.scriptExecutor.ReadScript(ctx, scriptPath) | 	sf, err := b.scriptExecutor.ReadScript(ctx, scriptPath) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, fmt.Errorf("failed reading script: %w", err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	slog.Debug("ExecuteFirstPass") | 	slog.Debug("ExecuteFirstPass") | ||||||
| 	basePkg, varsOfPackages, err := b.scriptExecutor.ExecuteFirstPass(ctx, input, sf) | 	basePkg, varsOfPackages, err := b.scriptExecutor.ExecuteFirstPass(ctx, input, sf) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, fmt.Errorf("failed ExecuteFirstPass: %w", err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	var builtDeps []*BuiltDep | 	var builtDeps []*BuiltDep | ||||||
|  |  | ||||||
| 	if !input.opts.Clean { | 	if !input.opts.Clean { | ||||||
| 		var remainingVars []*types.BuildVars | 		var remainingVars []*alrsh.Package | ||||||
| 		for _, vars := range varsOfPackages { | 		for _, vars := range varsOfPackages { | ||||||
| 			builtPkgPath, ok, err := b.cacheExecutor.CheckForBuiltPackage(ctx, input, vars) | 			builtPkgPath, ok, err := b.cacheExecutor.CheckForBuiltPackage(ctx, input, vars) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| @@ -367,6 +367,7 @@ func (b *Builder) BuildPackage( | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	slog.Debug("ViewScript") | 	slog.Debug("ViewScript") | ||||||
|  | 	slog.Debug("", "varsOfPackages", varsOfPackages) | ||||||
| 	err = b.scriptViewerExecutor.ViewScript(ctx, input, sf, basePkg) | 	err = b.scriptViewerExecutor.ViewScript(ctx, input, sf, basePkg) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| @@ -390,11 +391,11 @@ func (b *Builder) BuildPackage( | |||||||
| 	sources := []string{} | 	sources := []string{} | ||||||
| 	checksums := []string{} | 	checksums := []string{} | ||||||
| 	for _, vars := range varsOfPackages { | 	for _, vars := range varsOfPackages { | ||||||
| 		buildDepends = append(buildDepends, vars.BuildDepends...) | 		buildDepends = append(buildDepends, vars.BuildDepends.Resolved()...) | ||||||
| 		optDepends = append(optDepends, vars.OptDepends...) | 		optDepends = append(optDepends, vars.OptDepends.Resolved()...) | ||||||
| 		depends = append(depends, vars.Depends...) | 		depends = append(depends, vars.Depends.Resolved()...) | ||||||
| 		sources = append(sources, vars.Sources...) | 		sources = append(sources, vars.Sources.Resolved()...) | ||||||
| 		checksums = append(checksums, vars.Checksums...) | 		checksums = append(checksums, vars.Checksums.Resolved()...) | ||||||
| 	} | 	} | ||||||
| 	buildDepends = removeDuplicates(buildDepends) | 	buildDepends = removeDuplicates(buildDepends) | ||||||
| 	optDepends = removeDuplicates(optDepends) | 	optDepends = removeDuplicates(optDepends) | ||||||
| @@ -481,7 +482,7 @@ func (b *Builder) BuildPackage( | |||||||
|  |  | ||||||
| type InstallPkgsArgs struct { | type InstallPkgsArgs struct { | ||||||
| 	BuildArgs | 	BuildArgs | ||||||
| 	AlrPkgs    []db.Package | 	AlrPkgs    []alrsh.Package | ||||||
| 	NativePkgs []string | 	NativePkgs []string | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -492,7 +493,7 @@ func (b *Builder) InstallALRPackages( | |||||||
| 		BuildOptsProvider | 		BuildOptsProvider | ||||||
| 		PkgFormatProvider | 		PkgFormatProvider | ||||||
| 	}, | 	}, | ||||||
| 	alrPkgs []db.Package, | 	alrPkgs []alrsh.Package, | ||||||
| ) error { | ) error { | ||||||
| 	for _, pkg := range alrPkgs { | 	for _, pkg := range alrPkgs { | ||||||
| 		res, err := b.BuildPackageFromDb( | 		res, err := b.BuildPackageFromDb( | ||||||
| @@ -539,7 +540,7 @@ func (b *Builder) BuildALRDeps( | |||||||
|  |  | ||||||
| 		found, notFound, err := b.repos.FindPkgs(ctx, depends) // Поиск зависимостей | 		found, notFound, err := b.repos.FindPkgs(ctx, depends) // Поиск зависимостей | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, nil, err | 			return nil, nil, fmt.Errorf("failed FindPkgs: %w", err) | ||||||
| 		} | 		} | ||||||
| 		repoDeps = notFound | 		repoDeps = notFound | ||||||
|  |  | ||||||
| @@ -551,7 +552,7 @@ func (b *Builder) BuildALRDeps( | |||||||
| 			input.BuildOpts().Interactive, | 			input.BuildOpts().Interactive, | ||||||
| 		) | 		) | ||||||
| 		type item struct { | 		type item struct { | ||||||
| 			pkg      *db.Package | 			pkg      *alrsh.Package | ||||||
| 			packages []string | 			packages []string | ||||||
| 		} | 		} | ||||||
| 		pkgsMap := make(map[string]*item) | 		pkgsMap := make(map[string]*item) | ||||||
| @@ -586,7 +587,7 @@ func (b *Builder) BuildALRDeps( | |||||||
| 				}, | 				}, | ||||||
| 			) | 			) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return nil, nil, err | 				return nil, nil, fmt.Errorf("failed build package from db: %w", err) | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			buildDeps = append(buildDeps, res...) | 			buildDeps = append(buildDeps, res...) | ||||||
|   | |||||||
| @@ -23,7 +23,7 @@ import ( | |||||||
|  |  | ||||||
| 	"github.com/goreleaser/nfpm/v2" | 	"github.com/goreleaser/nfpm/v2" | ||||||
|  |  | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types" | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type Cache struct { | type Cache struct { | ||||||
| @@ -33,7 +33,7 @@ type Cache struct { | |||||||
| func (c *Cache) CheckForBuiltPackage( | func (c *Cache) CheckForBuiltPackage( | ||||||
| 	ctx context.Context, | 	ctx context.Context, | ||||||
| 	input *BuildInput, | 	input *BuildInput, | ||||||
| 	vars *types.BuildVars, | 	vars *alrsh.Package, | ||||||
| ) (string, bool, error) { | ) (string, bool, error) { | ||||||
| 	filename, err := pkgFileName(input, vars) | 	filename, err := pkgFileName(input, vars) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @@ -56,7 +56,7 @@ func pkgFileName( | |||||||
| 		PkgFormatProvider | 		PkgFormatProvider | ||||||
| 		RepositoryProvider | 		RepositoryProvider | ||||||
| 	}, | 	}, | ||||||
| 	vars *types.BuildVars, | 	vars *alrsh.Package, | ||||||
| ) (string, error) { | ) (string, error) { | ||||||
| 	pkgInfo := getBasePkgInfo(vars, input) | 	pkgInfo := getBasePkgInfo(vars, input) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -25,7 +25,7 @@ import ( | |||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/cpu" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/cpu" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/manager" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/manager" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types" | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type Checker struct { | type Checker struct { | ||||||
| @@ -35,7 +35,7 @@ type Checker struct { | |||||||
| func (c *Checker) PerformChecks( | func (c *Checker) PerformChecks( | ||||||
| 	ctx context.Context, | 	ctx context.Context, | ||||||
| 	input *BuildInput, | 	input *BuildInput, | ||||||
| 	vars *types.BuildVars, | 	vars *alrsh.Package, | ||||||
| ) (bool, error) { | ) (bool, error) { | ||||||
| 	if !cpu.IsCompatibleWith(cpu.Arch(), vars.Architectures) { // Проверяем совместимость архитектуры | 	if !cpu.IsCompatibleWith(cpu.Arch(), vars.Architectures) { // Проверяем совместимость архитектуры | ||||||
| 		cont, err := cliutils.YesNoPrompt( | 		cont, err := cliutils.YesNoPrompt( | ||||||
|   | |||||||
| @@ -29,7 +29,6 @@ import ( | |||||||
|  |  | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/logger" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/logger" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh" | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var HandshakeConfig = plugin.HandshakeConfig{ | var HandshakeConfig = plugin.HandshakeConfig{ | ||||||
| @@ -51,13 +50,13 @@ type ScriptExecutorRPCServer struct { | |||||||
| // ReadScript | // ReadScript | ||||||
| // | // | ||||||
|  |  | ||||||
| func (s *ScriptExecutorRPC) ReadScript(ctx context.Context, scriptPath string) (*alrsh.ALRSh, error) { | func (s *ScriptExecutorRPC) ReadScript(ctx context.Context, scriptPath string) (*alrsh.ScriptFile, error) { | ||||||
| 	var resp *alrsh.ALRSh | 	var resp *alrsh.ScriptFile | ||||||
| 	err := s.client.Call("Plugin.ReadScript", scriptPath, &resp) | 	err := s.client.Call("Plugin.ReadScript", scriptPath, &resp) | ||||||
| 	return resp, err | 	return resp, err | ||||||
| } | } | ||||||
|  |  | ||||||
| func (s *ScriptExecutorRPCServer) ReadScript(scriptPath string, resp *alrsh.ALRSh) error { | func (s *ScriptExecutorRPCServer) ReadScript(scriptPath string, resp *alrsh.ScriptFile) error { | ||||||
| 	file, err := s.Impl.ReadScript(context.Background(), scriptPath) | 	file, err := s.Impl.ReadScript(context.Background(), scriptPath) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| @@ -73,15 +72,15 @@ func (s *ScriptExecutorRPCServer) ReadScript(scriptPath string, resp *alrsh.ALRS | |||||||
|  |  | ||||||
| type ExecuteFirstPassArgs struct { | type ExecuteFirstPassArgs struct { | ||||||
| 	Input *BuildInput | 	Input *BuildInput | ||||||
| 	Sf    *alrsh.ALRSh | 	Sf    *alrsh.ScriptFile | ||||||
| } | } | ||||||
|  |  | ||||||
| type ExecuteFirstPassResp struct { | type ExecuteFirstPassResp struct { | ||||||
| 	BasePkg        string | 	BasePkg        string | ||||||
| 	VarsOfPackages []*types.BuildVars | 	VarsOfPackages []*alrsh.Package | ||||||
| } | } | ||||||
|  |  | ||||||
| func (s *ScriptExecutorRPC) ExecuteFirstPass(ctx context.Context, input *BuildInput, sf *alrsh.ALRSh) (string, []*types.BuildVars, error) { | func (s *ScriptExecutorRPC) ExecuteFirstPass(ctx context.Context, input *BuildInput, sf *alrsh.ScriptFile) (string, []*alrsh.Package, error) { | ||||||
| 	var resp *ExecuteFirstPassResp | 	var resp *ExecuteFirstPassResp | ||||||
| 	err := s.client.Call("Plugin.ExecuteFirstPass", &ExecuteFirstPassArgs{ | 	err := s.client.Call("Plugin.ExecuteFirstPass", &ExecuteFirstPassArgs{ | ||||||
| 		Input: input, | 		Input: input, | ||||||
| @@ -149,8 +148,8 @@ func (s *ScriptExecutorRPCServer) PrepareDirs(args *PrepareDirsArgs, reply *stru | |||||||
|  |  | ||||||
| type ExecuteSecondPassArgs struct { | type ExecuteSecondPassArgs struct { | ||||||
| 	Input          *BuildInput | 	Input          *BuildInput | ||||||
| 	Sf             *alrsh.ALRSh | 	Sf             *alrsh.ScriptFile | ||||||
| 	VarsOfPackages []*types.BuildVars | 	VarsOfPackages []*alrsh.Package | ||||||
| 	RepoDeps       []string | 	RepoDeps       []string | ||||||
| 	BuiltDeps      []*BuiltDep | 	BuiltDeps      []*BuiltDep | ||||||
| 	BasePkg        string | 	BasePkg        string | ||||||
| @@ -159,8 +158,8 @@ type ExecuteSecondPassArgs struct { | |||||||
| func (s *ScriptExecutorRPC) ExecuteSecondPass( | func (s *ScriptExecutorRPC) ExecuteSecondPass( | ||||||
| 	ctx context.Context, | 	ctx context.Context, | ||||||
| 	input *BuildInput, | 	input *BuildInput, | ||||||
| 	sf *alrsh.ALRSh, | 	sf *alrsh.ScriptFile, | ||||||
| 	varsOfPackages []*types.BuildVars, | 	varsOfPackages []*alrsh.Package, | ||||||
| 	repoDeps []string, | 	repoDeps []string, | ||||||
| 	builtDeps []*BuiltDep, | 	builtDeps []*BuiltDep, | ||||||
| 	basePkg string, | 	basePkg string, | ||||||
|   | |||||||
| @@ -53,11 +53,11 @@ func NewLocalScriptExecutor(cfg Config) *LocalScriptExecutor { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (e *LocalScriptExecutor) ReadScript(ctx context.Context, scriptPath string) (*alrsh.ALRSh, error) { | func (e *LocalScriptExecutor) ReadScript(ctx context.Context, scriptPath string) (*alrsh.ScriptFile, error) { | ||||||
| 	return alrsh.ReadFromLocal(scriptPath) | 	return alrsh.ReadFromLocal(scriptPath) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (e *LocalScriptExecutor) ExecuteFirstPass(ctx context.Context, input *BuildInput, sf *alrsh.ALRSh) (string, []*types.BuildVars, error) { | func (e *LocalScriptExecutor) ExecuteFirstPass(ctx context.Context, input *BuildInput, sf *alrsh.ScriptFile) (string, []*alrsh.Package, error) { | ||||||
| 	return sf.ParseBuildVars(ctx, input.info, input.packages) | 	return sf.ParseBuildVars(ctx, input.info, input.packages) | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -86,8 +86,8 @@ func (e *LocalScriptExecutor) PrepareDirs( | |||||||
| func (e *LocalScriptExecutor) ExecuteSecondPass( | func (e *LocalScriptExecutor) ExecuteSecondPass( | ||||||
| 	ctx context.Context, | 	ctx context.Context, | ||||||
| 	input *BuildInput, | 	input *BuildInput, | ||||||
| 	sf *alrsh.ALRSh, | 	sf *alrsh.ScriptFile, | ||||||
| 	varsOfPackages []*types.BuildVars, | 	varsOfPackages []*alrsh.Package, | ||||||
| 	repoDeps []string, | 	repoDeps []string, | ||||||
| 	builtDeps []*BuiltDep, | 	builtDeps []*BuiltDep, | ||||||
| 	basePkg string, | 	basePkg string, | ||||||
| @@ -126,7 +126,7 @@ func (e *LocalScriptExecutor) ExecuteSecondPass( | |||||||
|  |  | ||||||
| 	for _, vars := range varsOfPackages { | 	for _, vars := range varsOfPackages { | ||||||
| 		packageName := "" | 		packageName := "" | ||||||
| 		if vars.Base != "" { | 		if vars.BasePkgName != "" { | ||||||
| 			packageName = vars.Name | 			packageName = vars.Name | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @@ -194,24 +194,25 @@ func buildPkgMetadata( | |||||||
| 		PkgFormatProvider | 		PkgFormatProvider | ||||||
| 		RepositoryProvider | 		RepositoryProvider | ||||||
| 	}, | 	}, | ||||||
| 	vars *types.BuildVars, | 	vars *alrsh.Package, | ||||||
| 	dirs types.Directories, | 	dirs types.Directories, | ||||||
| 	deps []string, | 	deps []string, | ||||||
| 	preferedContents *[]string, | 	preferedContents *[]string, | ||||||
| ) (*nfpm.Info, error) { | ) (*nfpm.Info, error) { | ||||||
| 	pkgInfo := getBasePkgInfo(vars, input) | 	pkgInfo := getBasePkgInfo(vars, input) | ||||||
| 	pkgInfo.Description = vars.Description | 	slog.Warn("vars.Description", "vars.Description", vars.Description, "vars.Description.Resolved", vars.Description.Resolved()) | ||||||
|  | 	pkgInfo.Description = vars.Description.Resolved() | ||||||
| 	pkgInfo.Platform = "linux" | 	pkgInfo.Platform = "linux" | ||||||
| 	pkgInfo.Homepage = vars.Homepage | 	pkgInfo.Homepage = vars.Homepage.Resolved() | ||||||
| 	pkgInfo.License = strings.Join(vars.Licenses, ", ") | 	pkgInfo.License = strings.Join(vars.Licenses, ", ") | ||||||
| 	pkgInfo.Maintainer = vars.Maintainer | 	pkgInfo.Maintainer = vars.Maintainer.Resolved() | ||||||
| 	pkgInfo.Overridables = nfpm.Overridables{ | 	pkgInfo.Overridables = nfpm.Overridables{ | ||||||
| 		Conflicts: append(vars.Conflicts, vars.Name), | 		Conflicts: append(vars.Conflicts, vars.Name), | ||||||
| 		Replaces:  vars.Replaces, | 		Replaces:  vars.Replaces, | ||||||
| 		Provides:  append(vars.Provides, vars.Name), | 		Provides:  append(vars.Provides, vars.Name), | ||||||
| 		Depends:   deps, | 		Depends:   deps, | ||||||
| 	} | 	} | ||||||
| 	pkgInfo.Section = vars.Group | 	pkgInfo.Section = vars.Group.Resolved() | ||||||
|  |  | ||||||
| 	pkgFormat := input.PkgFormat() | 	pkgFormat := input.PkgFormat() | ||||||
| 	info := input.OSRelease() | 	info := input.OSRelease() | ||||||
| @@ -224,12 +225,12 @@ func buildPkgMetadata( | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if pkgFormat == "rpm" { | 	if pkgFormat == "rpm" { | ||||||
| 		pkgInfo.RPM.Group = vars.Group | 		pkgInfo.RPM.Group = vars.Group.Resolved() | ||||||
|  |  | ||||||
| 		if vars.Summary != "" { | 		if vars.Summary.Resolved() != "" { | ||||||
| 			pkgInfo.RPM.Summary = vars.Summary | 			pkgInfo.RPM.Summary = vars.Summary.Resolved() | ||||||
| 		} else { | 		} else { | ||||||
| 			lines := strings.SplitN(vars.Description, "\n", 2) | 			lines := strings.SplitN(vars.Description.Resolved(), "\n", 2) | ||||||
| 			pkgInfo.RPM.Summary = lines[0] | 			pkgInfo.RPM.Summary = lines[0] | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -250,17 +251,17 @@ func buildPkgMetadata( | |||||||
| 	} | 	} | ||||||
| 	pkgInfo.Overridables.Contents = contents | 	pkgInfo.Overridables.Contents = contents | ||||||
|  |  | ||||||
| 	if len(vars.AutoProv) == 1 && decoder.IsTruthy(vars.AutoProv[0]) { | 	if len(vars.AutoProv.Resolved()) == 1 && decoder.IsTruthy(vars.AutoProv.Resolved()[0]) { | ||||||
| 		f := finddeps.New(info, pkgFormat) | 		f := finddeps.New(info, pkgFormat) | ||||||
| 		err = f.FindProvides(ctx, pkgInfo, dirs, vars.AutoProvSkipList) | 		err = f.FindProvides(ctx, pkgInfo, dirs, vars.AutoProvSkipList.Resolved()) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, err | 			return nil, err | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if len(vars.AutoReq) == 1 && decoder.IsTruthy(vars.AutoReq[0]) { | 	if len(vars.AutoReq.Resolved()) == 1 && decoder.IsTruthy(vars.AutoReq.Resolved()[0]) { | ||||||
| 		f := finddeps.New(info, pkgFormat) | 		f := finddeps.New(info, pkgFormat) | ||||||
| 		err = f.FindRequires(ctx, pkgInfo, dirs, vars.AutoReqSkipList) | 		err = f.FindRequires(ctx, pkgInfo, dirs, vars.AutoReqSkipList.Resolved()) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, err | 			return nil, err | ||||||
| 		} | 		} | ||||||
|   | |||||||
| @@ -20,7 +20,7 @@ import ( | |||||||
| 	"context" | 	"context" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
|  |  | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/db" | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type ScriptResolver struct { | type ScriptResolver struct { | ||||||
| @@ -34,7 +34,7 @@ type ScriptInfo struct { | |||||||
|  |  | ||||||
| func (s *ScriptResolver) ResolveScript( | func (s *ScriptResolver) ResolveScript( | ||||||
| 	ctx context.Context, | 	ctx context.Context, | ||||||
| 	pkg *db.Package, | 	pkg *alrsh.Package, | ||||||
| ) *ScriptInfo { | ) *ScriptInfo { | ||||||
| 	var repository, script string | 	var repository, script string | ||||||
|  |  | ||||||
|   | |||||||
| @@ -34,7 +34,7 @@ type ScriptViewer struct { | |||||||
| func (s *ScriptViewer) ViewScript( | func (s *ScriptViewer) ViewScript( | ||||||
| 	ctx context.Context, | 	ctx context.Context, | ||||||
| 	input *BuildInput, | 	input *BuildInput, | ||||||
| 	a *alrsh.ALRSh, | 	a *alrsh.ScriptFile, | ||||||
| 	basePkg string, | 	basePkg string, | ||||||
| ) error { | ) error { | ||||||
| 	return cliutils.PromptViewScript( | 	return cliutils.PromptViewScript( | ||||||
|   | |||||||
| @@ -40,6 +40,7 @@ import ( | |||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/cpu" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/cpu" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/manager" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/manager" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/overrides" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/overrides" | ||||||
|  | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro" | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types" | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types" | ||||||
| ) | ) | ||||||
| @@ -59,7 +60,7 @@ func prepareDirs(dirs types.Directories) error { | |||||||
|  |  | ||||||
| // Функция buildContents создает секцию содержимого пакета, которая содержит файлы, | // Функция buildContents создает секцию содержимого пакета, которая содержит файлы, | ||||||
| // которые будут включены в конечный пакет. | // которые будут включены в конечный пакет. | ||||||
| func buildContents(vars *types.BuildVars, dirs types.Directories, preferedContents *[]string) ([]*files.Content, error) { | func buildContents(vars *alrsh.Package, dirs types.Directories, preferedContents *[]string) ([]*files.Content, error) { | ||||||
| 	contents := []*files.Content{} | 	contents := []*files.Content{} | ||||||
|  |  | ||||||
| 	processPath := func(path, trimmed string, prefered bool) error { | 	processPath := func(path, trimmed string, prefered bool) error { | ||||||
| @@ -122,7 +123,7 @@ func buildContents(vars *types.BuildVars, dirs types.Directories, preferedConten | |||||||
| 			}, | 			}, | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if slices.Contains(vars.Backup, trimmed) { | 		if slices.Contains(vars.Backup.Resolved(), trimmed) { | ||||||
| 			fileContent.Type = "config|noreplace" | 			fileContent.Type = "config|noreplace" | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @@ -155,7 +156,7 @@ func buildContents(vars *types.BuildVars, dirs types.Directories, preferedConten | |||||||
|  |  | ||||||
| var RegexpALRPackageName = regexp.MustCompile(`^(?P<package>[^+]+)\+alr-(?P<repo>.+)$`) | var RegexpALRPackageName = regexp.MustCompile(`^(?P<package>[^+]+)\+alr-(?P<repo>.+)$`) | ||||||
|  |  | ||||||
| func getBasePkgInfo(vars *types.BuildVars, input interface { | func getBasePkgInfo(vars *alrsh.Package, input interface { | ||||||
| 	RepositoryProvider | 	RepositoryProvider | ||||||
| 	OsInfoProvider | 	OsInfoProvider | ||||||
| }, | }, | ||||||
| @@ -211,39 +212,39 @@ func createBuildEnvVars(info *distro.OSRelease, dirs types.Directories) []string | |||||||
| } | } | ||||||
|  |  | ||||||
| // Функция setScripts добавляет скрипты-перехватчики к метаданным пакета. | // Функция setScripts добавляет скрипты-перехватчики к метаданным пакета. | ||||||
| func setScripts(vars *types.BuildVars, info *nfpm.Info, scriptDir string) { | func setScripts(vars *alrsh.Package, info *nfpm.Info, scriptDir string) { | ||||||
| 	if vars.Scripts.PreInstall != "" { | 	if vars.Scripts.Resolved().PreInstall != "" { | ||||||
| 		info.Scripts.PreInstall = filepath.Join(scriptDir, vars.Scripts.PreInstall) | 		info.Scripts.PreInstall = filepath.Join(scriptDir, vars.Scripts.Resolved().PreInstall) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if vars.Scripts.PostInstall != "" { | 	if vars.Scripts.Resolved().PostInstall != "" { | ||||||
| 		info.Scripts.PostInstall = filepath.Join(scriptDir, vars.Scripts.PostInstall) | 		info.Scripts.PostInstall = filepath.Join(scriptDir, vars.Scripts.Resolved().PostInstall) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if vars.Scripts.PreRemove != "" { | 	if vars.Scripts.Resolved().PreRemove != "" { | ||||||
| 		info.Scripts.PreRemove = filepath.Join(scriptDir, vars.Scripts.PreRemove) | 		info.Scripts.PreRemove = filepath.Join(scriptDir, vars.Scripts.Resolved().PreRemove) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if vars.Scripts.PostRemove != "" { | 	if vars.Scripts.Resolved().PostRemove != "" { | ||||||
| 		info.Scripts.PostRemove = filepath.Join(scriptDir, vars.Scripts.PostRemove) | 		info.Scripts.PostRemove = filepath.Join(scriptDir, vars.Scripts.Resolved().PostRemove) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if vars.Scripts.PreUpgrade != "" { | 	if vars.Scripts.Resolved().PreUpgrade != "" { | ||||||
| 		info.ArchLinux.Scripts.PreUpgrade = filepath.Join(scriptDir, vars.Scripts.PreUpgrade) | 		info.ArchLinux.Scripts.PreUpgrade = filepath.Join(scriptDir, vars.Scripts.Resolved().PreUpgrade) | ||||||
| 		info.APK.Scripts.PreUpgrade = filepath.Join(scriptDir, vars.Scripts.PreUpgrade) | 		info.APK.Scripts.PreUpgrade = filepath.Join(scriptDir, vars.Scripts.Resolved().PreUpgrade) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if vars.Scripts.PostUpgrade != "" { | 	if vars.Scripts.Resolved().PostUpgrade != "" { | ||||||
| 		info.ArchLinux.Scripts.PostUpgrade = filepath.Join(scriptDir, vars.Scripts.PostUpgrade) | 		info.ArchLinux.Scripts.PostUpgrade = filepath.Join(scriptDir, vars.Scripts.Resolved().PostUpgrade) | ||||||
| 		info.APK.Scripts.PostUpgrade = filepath.Join(scriptDir, vars.Scripts.PostUpgrade) | 		info.APK.Scripts.PostUpgrade = filepath.Join(scriptDir, vars.Scripts.Resolved().PostUpgrade) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if vars.Scripts.PreTrans != "" { | 	if vars.Scripts.Resolved().PreTrans != "" { | ||||||
| 		info.RPM.Scripts.PreTrans = filepath.Join(scriptDir, vars.Scripts.PreTrans) | 		info.RPM.Scripts.PreTrans = filepath.Join(scriptDir, vars.Scripts.Resolved().PreTrans) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if vars.Scripts.PostTrans != "" { | 	if vars.Scripts.Resolved().PostTrans != "" { | ||||||
| 		info.RPM.Scripts.PostTrans = filepath.Join(scriptDir, vars.Scripts.PostTrans) | 		info.RPM.Scripts.PostTrans = filepath.Join(scriptDir, vars.Scripts.Resolved().PostTrans) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -123,8 +123,15 @@ func (b *AppBuilder) withRepos(enablePull, forcePull bool) *AppBuilder { | |||||||
|  |  | ||||||
| 	cfg := b.deps.Cfg | 	cfg := b.deps.Cfg | ||||||
| 	db := b.deps.DB | 	db := b.deps.DB | ||||||
| 	if cfg == nil || db == nil { | 	info := b.deps.Info | ||||||
| 		b.err = errors.New("config and db are required before initializing repos") |  | ||||||
|  | 	if info == nil { | ||||||
|  | 		b.WithDistroInfo() | ||||||
|  | 		info = b.deps.Info | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if cfg == nil || db == nil || info == nil { | ||||||
|  | 		b.err = errors.New("config, db and info are required before initializing repos") | ||||||
| 		return b | 		return b | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -28,8 +28,8 @@ import ( | |||||||
| 	"github.com/AlecAivazis/survey/v2" | 	"github.com/AlecAivazis/survey/v2" | ||||||
| 	"github.com/leonelquinteros/gotext" | 	"github.com/leonelquinteros/gotext" | ||||||
|  |  | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/db" |  | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/pager" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/pager" | ||||||
|  | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // YesNoPrompt asks the user a yes or no question, using def as the default answer | // YesNoPrompt asks the user a yes or no question, using def as the default answer | ||||||
| @@ -102,8 +102,8 @@ func ShowScript(path, name, style string) error { | |||||||
|  |  | ||||||
| // FlattenPkgs attempts to flatten the a map of slices of packages into a single slice | // FlattenPkgs attempts to flatten the a map of slices of packages into a single slice | ||||||
| // of packages by prompting the user if multiple packages match. | // of packages by prompting the user if multiple packages match. | ||||||
| func FlattenPkgs(ctx context.Context, found map[string][]db.Package, verb string, interactive bool) []db.Package { | func FlattenPkgs(ctx context.Context, found map[string][]alrsh.Package, verb string, interactive bool) []alrsh.Package { | ||||||
| 	var outPkgs []db.Package | 	var outPkgs []alrsh.Package | ||||||
| 	for _, pkgs := range found { | 	for _, pkgs := range found { | ||||||
| 		if len(pkgs) > 1 && interactive { | 		if len(pkgs) > 1 && interactive { | ||||||
| 			choice, err := PkgPrompt(ctx, pkgs, verb, interactive) | 			choice, err := PkgPrompt(ctx, pkgs, verb, interactive) | ||||||
| @@ -120,7 +120,7 @@ func FlattenPkgs(ctx context.Context, found map[string][]db.Package, verb string | |||||||
| } | } | ||||||
|  |  | ||||||
| // PkgPrompt asks the user to choose between multiple packages. | // PkgPrompt asks the user to choose between multiple packages. | ||||||
| func PkgPrompt(ctx context.Context, options []db.Package, verb string, interactive bool) (db.Package, error) { | func PkgPrompt(ctx context.Context, options []alrsh.Package, verb string, interactive bool) (alrsh.Package, error) { | ||||||
| 	if !interactive { | 	if !interactive { | ||||||
| 		return options[0], nil | 		return options[0], nil | ||||||
| 	} | 	} | ||||||
| @@ -138,7 +138,7 @@ func PkgPrompt(ctx context.Context, options []db.Package, verb string, interacti | |||||||
| 	var choice int | 	var choice int | ||||||
| 	err := survey.AskOne(prompt, &choice) | 	err := survey.AskOne(prompt, &choice) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return db.Package{}, err | 		return alrsh.Package{}, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return options[choice], nil | 	return options[choice], nil | ||||||
|   | |||||||
| @@ -20,6 +20,7 @@ import ( | |||||||
| 	"errors" | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"log/slog" | 	"log/slog" | ||||||
|  | 	"runtime/debug" | ||||||
|  |  | ||||||
| 	"github.com/leonelquinteros/gotext" | 	"github.com/leonelquinteros/gotext" | ||||||
| 	"github.com/urfave/cli/v2" | 	"github.com/urfave/cli/v2" | ||||||
| @@ -44,10 +45,12 @@ func HandleExitCoder(err error) { | |||||||
| 				slog.Error(err.Error()) | 				slog.Error(err.Error()) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 		debug.PrintStack() | ||||||
| 		cli.OsExiter(exitErr.ExitCode()) | 		cli.OsExiter(exitErr.ExitCode()) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	debug.PrintStack() | ||||||
| 	slog.Error(err.Error()) | 	slog.Error(err.Error()) | ||||||
| 	cli.OsExiter(1) | 	cli.OsExiter(1) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -28,32 +28,11 @@ import ( | |||||||
| 	"xorm.io/xorm" | 	"xorm.io/xorm" | ||||||
|  |  | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/config" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/config" | ||||||
|  | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| const CurrentVersion = 5 | const CurrentVersion = 5 | ||||||
|  |  | ||||||
| type Package struct { |  | ||||||
| 	BasePkgName   string              `sh:"basepkg_name" xorm:"notnull 'basepkg_name'"` |  | ||||||
| 	Name          string              `sh:"name,required" xorm:"notnull unique(name_repo) 'name'"` |  | ||||||
| 	Version       string              `sh:"version,required" xorm:"notnull 'version'"` |  | ||||||
| 	Release       int                 `sh:"release" xorm:"notnull 'release'"` |  | ||||||
| 	Epoch         uint                `sh:"epoch" xorm:"'epoch'"` |  | ||||||
| 	Summary       map[string]string   `xorm:"json 'summary'"` |  | ||||||
| 	Description   map[string]string   `xorm:"json 'description'"` |  | ||||||
| 	Group         map[string]string   `xorm:"json 'group_name'"` |  | ||||||
| 	Homepage      map[string]string   `xorm:"json 'homepage'"` |  | ||||||
| 	Maintainer    map[string]string   `xorm:"json 'maintainer'"` |  | ||||||
| 	Architectures []string            `sh:"architectures" xorm:"json 'architectures'"` |  | ||||||
| 	Licenses      []string            `sh:"license" xorm:"json 'licenses'"` |  | ||||||
| 	Provides      []string            `sh:"provides" xorm:"json 'provides'"` |  | ||||||
| 	Conflicts     []string            `sh:"conflicts" xorm:"json 'conflicts'"` |  | ||||||
| 	Replaces      []string            `sh:"replaces" xorm:"json 'replaces'"` |  | ||||||
| 	Depends       map[string][]string `xorm:"json 'depends'"` |  | ||||||
| 	BuildDepends  map[string][]string `xorm:"json 'builddepends'"` |  | ||||||
| 	OptDepends    map[string][]string `xorm:"json 'optdepends'"` |  | ||||||
| 	Repository    string              `xorm:"notnull unique(name_repo) 'repository'"` |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type Version struct { | type Version struct { | ||||||
| 	Version int `xorm:"'version'"` | 	Version int `xorm:"'version'"` | ||||||
| } | } | ||||||
| @@ -76,6 +55,8 @@ func New(config Config) *Database { | |||||||
| func (d *Database) Connect() error { | func (d *Database) Connect() error { | ||||||
| 	dsn := d.config.GetPaths().DBPath | 	dsn := d.config.GetPaths().DBPath | ||||||
| 	engine, err := xorm.NewEngine("sqlite", dsn) | 	engine, err := xorm.NewEngine("sqlite", dsn) | ||||||
|  | 	// engine.SetLogLevel(log.LOG_DEBUG) | ||||||
|  | 	// engine.ShowSQL(true) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| @@ -87,7 +68,7 @@ func (d *Database) Init(ctx context.Context) error { | |||||||
| 	if err := d.Connect(); err != nil { | 	if err := d.Connect(); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	if err := d.engine.Sync2(new(Package), new(Version)); err != nil { | 	if err := d.engine.Sync2(new(alrsh.Package), new(Version)); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	ver, ok := d.GetVersion(ctx) | 	ver, ok := d.GetVersion(ctx) | ||||||
| @@ -119,10 +100,10 @@ func (d *Database) addVersion(ver int) error { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (d *Database) reset() error { | func (d *Database) reset() error { | ||||||
| 	return d.engine.DropTables(new(Package), new(Version)) | 	return d.engine.DropTables(new(alrsh.Package), new(Version)) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (d *Database) InsertPackage(ctx context.Context, pkg Package) error { | func (d *Database) InsertPackage(ctx context.Context, pkg alrsh.Package) error { | ||||||
| 	session := d.engine.Context(ctx) | 	session := d.engine.Context(ctx) | ||||||
|  |  | ||||||
| 	affected, err := session.Where("name = ? AND repository = ?", pkg.Name, pkg.Repository).Update(&pkg) | 	affected, err := session.Where("name = ? AND repository = ?", pkg.Name, pkg.Repository).Update(&pkg) | ||||||
| @@ -140,14 +121,14 @@ func (d *Database) InsertPackage(ctx context.Context, pkg Package) error { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (d *Database) GetPkgs(_ context.Context, where string, args ...any) ([]Package, error) { | func (d *Database) GetPkgs(_ context.Context, where string, args ...any) ([]alrsh.Package, error) { | ||||||
| 	var pkgs []Package | 	var pkgs []alrsh.Package | ||||||
| 	err := d.engine.Where(where, args...).Find(&pkgs) | 	err := d.engine.Where(where, args...).Find(&pkgs) | ||||||
| 	return pkgs, err | 	return pkgs, err | ||||||
| } | } | ||||||
|  |  | ||||||
| func (d *Database) GetPkg(where string, args ...any) (*Package, error) { | func (d *Database) GetPkg(where string, args ...any) (*alrsh.Package, error) { | ||||||
| 	var pkg Package | 	var pkg alrsh.Package | ||||||
| 	has, err := d.engine.Where(where, args...).Get(&pkg) | 	has, err := d.engine.Where(where, args...).Get(&pkg) | ||||||
| 	if err != nil || !has { | 	if err != nil || !has { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| @@ -156,12 +137,12 @@ func (d *Database) GetPkg(where string, args ...any) (*Package, error) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (d *Database) DeletePkgs(_ context.Context, where string, args ...any) error { | func (d *Database) DeletePkgs(_ context.Context, where string, args ...any) error { | ||||||
| 	_, err := d.engine.Where(where, args...).Delete(&Package{}) | 	_, err := d.engine.Where(where, args...).Delete(&alrsh.Package{}) | ||||||
| 	return err | 	return err | ||||||
| } | } | ||||||
|  |  | ||||||
| func (d *Database) IsEmpty() bool { | func (d *Database) IsEmpty() bool { | ||||||
| 	count, err := d.engine.Count(new(Package)) | 	count, err := d.engine.Count(new(alrsh.Package)) | ||||||
| 	return err != nil || count == 0 | 	return err != nil || count == 0 | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -25,8 +25,11 @@ import ( | |||||||
| 	"strings" | 	"strings" | ||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
|  |  | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/config" | 	"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/db" | ||||||
|  | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type TestALRConfig struct{} | type TestALRConfig struct{} | ||||||
| @@ -43,35 +46,38 @@ func prepareDb() *db.Database { | |||||||
| 	return database | 	return database | ||||||
| } | } | ||||||
|  |  | ||||||
| var testPkg = db.Package{ | var testPkg = alrsh.Package{ | ||||||
| 	Name:    "test", | 	Name:    "test", | ||||||
| 	Version: "0.0.1", | 	Version: "0.0.1", | ||||||
| 	Release: 1, | 	Release: 1, | ||||||
| 	Epoch:   2, | 	Epoch:   2, | ||||||
| 	Description: map[string]string{ | 	Description: alrsh.OverridableFromMap(map[string]string{ | ||||||
| 		"en": "Test package", | 		"en": "Test package", | ||||||
| 		"ru": "Проверочный пакет", | 		"ru": "Проверочный пакет", | ||||||
| 	}, | 	}), | ||||||
| 	Homepage: map[string]string{ | 	Homepage: alrsh.OverridableFromMap(map[string]string{ | ||||||
| 		"en": "https://gitea.plemya-x.ru/xpamych/ALR", | 		"en": "https://gitea.plemya-x.ru/xpamych/ALR", | ||||||
| 	}, | 	}), | ||||||
| 	Maintainer: map[string]string{ | 	Maintainer: alrsh.OverridableFromMap(map[string]string{ | ||||||
| 		"en": "Evgeniy Khramov <xpamych@yandex.ru>", | 		"en": "Evgeniy Khramov <xpamych@yandex.ru>", | ||||||
| 		"ru": "Евгений Храмов <xpamych@yandex.ru>", | 		"ru": "Евгений Храмов <xpamych@yandex.ru>", | ||||||
| 	}, | 	}), | ||||||
| 	Architectures: []string{"arm64", "amd64"}, | 	Architectures: []string{"arm64", "amd64"}, | ||||||
| 	Licenses:      []string{"GPL-3.0-or-later"}, | 	Licenses:      []string{"GPL-3.0-or-later"}, | ||||||
| 	Provides:      []string{"test"}, | 	Provides:      []string{"test"}, | ||||||
| 	Conflicts:     []string{"test"}, | 	Conflicts:     []string{"test"}, | ||||||
| 	Replaces:      []string{"test-old"}, | 	Replaces:      []string{"test-old"}, | ||||||
| 	Depends: map[string][]string{ | 	Depends: alrsh.OverridableFromMap(map[string][]string{ | ||||||
| 		"": {"sudo"}, | 		"": {"sudo"}, | ||||||
| 	}, | 	}), | ||||||
| 	BuildDepends: map[string][]string{ | 	BuildDepends: alrsh.OverridableFromMap(map[string][]string{ | ||||||
| 		"":     {"golang"}, | 		"":     {"golang"}, | ||||||
| 		"arch": {"go"}, | 		"arch": {"go"}, | ||||||
| 	}, | 	}), | ||||||
| 	Repository: "default", | 	Repository: "default", | ||||||
|  | 	Summary:    alrsh.OverridableFromMap(map[string]string{}), | ||||||
|  | 	Group:      alrsh.OverridableFromMap(map[string]string{}), | ||||||
|  | 	OptDepends: alrsh.OverridableFromMap(map[string][]string{}), | ||||||
| } | } | ||||||
|  |  | ||||||
| func TestInit(t *testing.T) { | func TestInit(t *testing.T) { | ||||||
| @@ -106,9 +112,7 @@ func TestInsertPackage(t *testing.T) { | |||||||
| 		t.Fatalf("Expected 1 package, got %d", len(pkgs)) | 		t.Fatalf("Expected 1 package, got %d", len(pkgs)) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if !reflect.DeepEqual(testPkg, pkgs[0]) { | 	assert.Equal(t, testPkg, pkgs[0]) | ||||||
| 		t.Errorf("Expected test package to be the same as database package") |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func TestGetPkgs(t *testing.T) { | func TestGetPkgs(t *testing.T) { | ||||||
|   | |||||||
| @@ -21,7 +21,6 @@ package overrides | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"reflect" |  | ||||||
| 	"regexp" | 	"regexp" | ||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
| @@ -29,7 +28,6 @@ import ( | |||||||
| 	"golang.org/x/text/language" | 	"golang.org/x/text/language" | ||||||
|  |  | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/cpu" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/cpu" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/db" |  | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro" | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -150,65 +148,6 @@ func (o *Opts) WithLanguageTags(langs []string) *Opts { | |||||||
| 	return out | 	return out | ||||||
| } | } | ||||||
|  |  | ||||||
| // ResolvedPackage is a ALR package after its overrides |  | ||||||
| // have been resolved |  | ||||||
| type ResolvedPackage struct { |  | ||||||
| 	Name          string   `sh:"name"` |  | ||||||
| 	Version       string   `sh:"version"` |  | ||||||
| 	Release       int      `sh:"release"` |  | ||||||
| 	Epoch         uint     `sh:"epoch"` |  | ||||||
| 	Group         string   `db:"group_name"` |  | ||||||
| 	Summary       string   `db:"summary"` |  | ||||||
| 	Description   string   `db:"description"` |  | ||||||
| 	Homepage      string   `db:"homepage"` |  | ||||||
| 	Maintainer    string   `db:"maintainer"` |  | ||||||
| 	Architectures []string `sh:"architectures"` |  | ||||||
| 	Licenses      []string `sh:"license"` |  | ||||||
| 	Provides      []string `sh:"provides"` |  | ||||||
| 	Conflicts     []string `sh:"conflicts"` |  | ||||||
| 	Replaces      []string `sh:"replaces"` |  | ||||||
| 	Depends       []string `sh:"deps"` |  | ||||||
| 	BuildDepends  []string `sh:"build_deps"` |  | ||||||
| 	OptDepends    []string `sh:"opt_deps"` |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func ResolvePackage(pkg *db.Package, overrides []string) *ResolvedPackage { |  | ||||||
| 	out := &ResolvedPackage{} |  | ||||||
| 	outVal := reflect.ValueOf(out).Elem() |  | ||||||
| 	pkgVal := reflect.ValueOf(pkg).Elem() |  | ||||||
|  |  | ||||||
| 	for i := 0; i < outVal.NumField(); i++ { |  | ||||||
| 		fieldVal := outVal.Field(i) |  | ||||||
| 		fieldType := fieldVal.Type() |  | ||||||
| 		pkgFieldVal := pkgVal.FieldByName(outVal.Type().Field(i).Name) |  | ||||||
| 		pkgFieldType := pkgFieldVal.Type() |  | ||||||
|  |  | ||||||
| 		if strings.HasPrefix(pkgFieldType.String(), "db.JSON") { |  | ||||||
| 			pkgFieldVal = pkgFieldVal.FieldByName("Val") |  | ||||||
| 			pkgFieldType = pkgFieldVal.Type() |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if pkgFieldType.AssignableTo(fieldType) { |  | ||||||
| 			fieldVal.Set(pkgFieldVal) |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if pkgFieldVal.Kind() == reflect.Map && pkgFieldType.Elem().AssignableTo(fieldType) { |  | ||||||
| 			for _, override := range overrides { |  | ||||||
| 				overrideVal := pkgFieldVal.MapIndex(reflect.ValueOf(override)) |  | ||||||
| 				if !overrideVal.IsValid() { |  | ||||||
| 					continue |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				fieldVal.Set(overrideVal) |  | ||||||
| 				break |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return out |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func parseLangs(langs []string, tags []language.Tag) ([]string, error) { | func parseLangs(langs []string, tags []language.Tag) ([]string, error) { | ||||||
| 	out := make([]string, len(tags)+len(langs)) | 	out := make([]string, len(tags)+len(langs)) | ||||||
| 	for i, tag := range tags { | 	for i, tag := range tags { | ||||||
|   | |||||||
| @@ -22,11 +22,11 @@ package repos | |||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
|  |  | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/db" | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func (rs *Repos) FindPkgs(ctx context.Context, pkgs []string) (map[string][]db.Package, []string, error) { | func (rs *Repos) FindPkgs(ctx context.Context, pkgs []string) (map[string][]alrsh.Package, []string, error) { | ||||||
| 	found := map[string][]db.Package{} | 	found := map[string][]alrsh.Package{} | ||||||
| 	notFound := []string(nil) | 	notFound := []string(nil) | ||||||
|  |  | ||||||
| 	for _, pkgName := range pkgs { | 	for _, pkgName := range pkgs { | ||||||
|   | |||||||
| @@ -24,8 +24,8 @@ import ( | |||||||
| 	"strings" | 	"strings" | ||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/db" |  | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/repos" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/repos" | ||||||
|  | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types" | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -89,31 +89,31 @@ func TestFindPkgsEmpty(t *testing.T) { | |||||||
| 		e.Db, | 		e.Db, | ||||||
| 	) | 	) | ||||||
|  |  | ||||||
| 	err := e.Db.InsertPackage(e.Ctx, db.Package{ | 	err := e.Db.InsertPackage(e.Ctx, alrsh.Package{ | ||||||
| 		Name:       "test1", | 		Name:       "test1", | ||||||
| 		Repository: "default", | 		Repository: "default", | ||||||
| 		Version:    "0.0.1", | 		Version:    "0.0.1", | ||||||
| 		Release:    1, | 		Release:    1, | ||||||
| 		Description: map[string]string{ | 		Provides:   []string{""}, | ||||||
|  | 		Description: alrsh.OverridableFromMap(map[string]string{ | ||||||
| 			"en": "Test package 1", | 			"en": "Test package 1", | ||||||
| 			"ru": "Проверочный пакет 1", | 			"ru": "Проверочный пакет 1", | ||||||
| 		}, | 		}), | ||||||
| 		Provides: []string{""}, |  | ||||||
| 	}) | 	}) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		t.Fatalf("Expected no error, got %s", err) | 		t.Fatalf("Expected no error, got %s", err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	err = e.Db.InsertPackage(e.Ctx, db.Package{ | 	err = e.Db.InsertPackage(e.Ctx, alrsh.Package{ | ||||||
| 		Name:       "test2", | 		Name:       "test2", | ||||||
| 		Repository: "default", | 		Repository: "default", | ||||||
| 		Version:    "0.0.1", | 		Version:    "0.0.1", | ||||||
| 		Release:    1, | 		Release:    1, | ||||||
| 		Description: map[string]string{ | 		Provides:   []string{"test"}, | ||||||
|  | 		Description: alrsh.OverridableFromMap(map[string]string{ | ||||||
| 			"en": "Test package 2", | 			"en": "Test package 2", | ||||||
| 			"ru": "Проверочный пакет 2", | 			"ru": "Проверочный пакет 2", | ||||||
| 		}, | 		}), | ||||||
| 		Provides: []string{"test"}, |  | ||||||
| 	}) | 	}) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		t.Fatalf("Expected no error, got %s", err) | 		t.Fatalf("Expected no error, got %s", err) | ||||||
|   | |||||||
| @@ -27,6 +27,7 @@ import ( | |||||||
|  |  | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/config" | 	"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/db" | ||||||
|  | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types" | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -84,10 +85,10 @@ build_deps=('golang') | |||||||
| 				result, err := database.GetPkgs(ctx, "1 = 1") | 				result, err := database.GetPkgs(ctx, "1 = 1") | ||||||
| 				assert.NoError(t, err) | 				assert.NoError(t, err) | ||||||
| 				pkgCount := 0 | 				pkgCount := 0 | ||||||
| 				for _, dbPkg := range result { | 				for _, pkg := range result { | ||||||
| 					assert.Equal(t, "foo", dbPkg.Name) | 					assert.Equal(t, "foo", pkg.Name) | ||||||
| 					assert.Equal(t, map[string]string{"": "main desc"}, dbPkg.Description) | 					assert.Equal(t, alrsh.OverridableFromMap(map[string]string{"": "main desc"}), pkg.Description) | ||||||
| 					assert.Equal(t, map[string][]string{"": {"sudo"}}, dbPkg.Depends) | 					assert.Equal(t, alrsh.OverridableFromMap(map[string][]string{"": {"sudo"}}), pkg.Depends) | ||||||
| 					pkgCount++ | 					pkgCount++ | ||||||
| 				} | 				} | ||||||
| 				assert.Equal(t, 1, pkgCount) | 				assert.Equal(t, 1, pkgCount) | ||||||
| @@ -119,18 +120,18 @@ meta_buz() { | |||||||
| 				assert.NoError(t, err) | 				assert.NoError(t, err) | ||||||
|  |  | ||||||
| 				pkgCount := 0 | 				pkgCount := 0 | ||||||
| 				for _, dbPkg := range result { | 				for _, pkg := range result { | ||||||
| 					if err != nil { | 					if err != nil { | ||||||
| 						t.Errorf("Expected no error, got %s", err) | 						t.Errorf("Expected no error, got %s", err) | ||||||
| 					} | 					} | ||||||
| 					if dbPkg.Name == "bar" { | 					if pkg.Name == "bar" { | ||||||
| 						assert.Equal(t, map[string]string{"": "foo desc"}, dbPkg.Description) | 						assert.Equal(t, alrsh.OverridableFromMap(map[string]string{"": "foo desc"}), pkg.Description) | ||||||
| 						assert.Equal(t, map[string][]string{"": {"sudo"}}, dbPkg.Depends) | 						assert.Equal(t, alrsh.OverridableFromMap(map[string][]string{"": {"sudo"}}), pkg.Depends) | ||||||
| 					} | 					} | ||||||
|  |  | ||||||
| 					if dbPkg.Name == "buz" { | 					if pkg.Name == "buz" { | ||||||
| 						assert.Equal(t, map[string]string{"": "main desc"}, dbPkg.Description) | 						assert.Equal(t, alrsh.OverridableFromMap(map[string]string{"": "main desc"}), pkg.Description) | ||||||
| 						assert.Equal(t, map[string][]string{"": {"sudo", "doas"}}, dbPkg.Depends) | 						assert.Equal(t, alrsh.OverridableFromMap(map[string][]string{"": {"sudo", "doas"}}), pkg.Depends) | ||||||
| 					} | 					} | ||||||
| 					pkgCount++ | 					pkgCount++ | ||||||
| 				} | 				} | ||||||
|   | |||||||
| @@ -18,12 +18,9 @@ package repos | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
| 	"errors" |  | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"io" | 	"io" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
| 	"reflect" |  | ||||||
| 	"strings" |  | ||||||
|  |  | ||||||
| 	"github.com/go-git/go-git/v5" | 	"github.com/go-git/go-git/v5" | ||||||
| 	"github.com/go-git/go-git/v5/plumbing" | 	"github.com/go-git/go-git/v5/plumbing" | ||||||
| @@ -34,9 +31,7 @@ import ( | |||||||
| 	"mvdan.cc/sh/v3/interp" | 	"mvdan.cc/sh/v3/interp" | ||||||
| 	"mvdan.cc/sh/v3/syntax" | 	"mvdan.cc/sh/v3/syntax" | ||||||
|  |  | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/db" | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/parser" |  | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/shutils/decoder" |  | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro" | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types" | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types" | ||||||
| ) | ) | ||||||
| @@ -63,149 +58,19 @@ func parseScript( | |||||||
| 	syntaxParser *syntax.Parser, | 	syntaxParser *syntax.Parser, | ||||||
| 	runner *interp.Runner, | 	runner *interp.Runner, | ||||||
| 	r io.ReadCloser, | 	r io.ReadCloser, | ||||||
| ) ([]*db.Package, error) { | ) ([]*alrsh.Package, error) { | ||||||
| 	fl, err := syntaxParser.Parse(r, "alr.sh") | 	f, err := alrsh.ReadFromIOReader(r, "/tmp") | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  | 	_, dbPkgs, err := f.ParseBuildVars(ctx, &distro.OSRelease{}, []string{}) | ||||||
| 	runner.Reset() |  | ||||||
| 	err = runner.Run(ctx, fl) |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  | 	for _, pkg := range dbPkgs { | ||||||
| 	d := decoder.New(&distro.OSRelease{}, runner) | 		pkg.Repository = repo.Name | ||||||
| 	d.Overrides = false |  | ||||||
| 	d.LikeDistros = false |  | ||||||
|  |  | ||||||
| 	pkgNames, err := parser.ParseNames(d) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, fmt.Errorf("failed parsing package names: %w", err) |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if len(pkgNames.Names) == 0 { |  | ||||||
| 		return nil, errors.New("package name is missing") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var dbPkgs []*db.Package |  | ||||||
|  |  | ||||||
| 	if len(pkgNames.Names) > 1 { |  | ||||||
| 		if pkgNames.BasePkgName == "" { |  | ||||||
| 			pkgNames.BasePkgName = pkgNames.Names[0] |  | ||||||
| 		} |  | ||||||
| 		for _, pkgName := range pkgNames.Names { |  | ||||||
| 			pkgInfo := PackageInfo{} |  | ||||||
| 			funcName := fmt.Sprintf("meta_%s", pkgName) |  | ||||||
| 			runner.Reset() |  | ||||||
| 			err = runner.Run(ctx, fl) |  | ||||||
| 			if err != nil { |  | ||||||
| 				return nil, err |  | ||||||
| 			} |  | ||||||
| 			meta, ok := d.GetFuncWithSubshell(funcName) |  | ||||||
| 			if !ok { |  | ||||||
| 				return nil, fmt.Errorf("func %s is missing", funcName) |  | ||||||
| 			} |  | ||||||
| 			r, err := meta(ctx) |  | ||||||
| 			if err != nil { |  | ||||||
| 				return nil, err |  | ||||||
| 			} |  | ||||||
| 			d := decoder.New(&distro.OSRelease{}, r) |  | ||||||
| 			d.Overrides = false |  | ||||||
| 			d.LikeDistros = false |  | ||||||
| 			err = d.DecodeVars(&pkgInfo) |  | ||||||
| 			if err != nil { |  | ||||||
| 				return nil, err |  | ||||||
| 			} |  | ||||||
| 			pkg := pkgInfo.ToPackage(repo.Name) |  | ||||||
| 			resolveOverrides(r, pkg) |  | ||||||
| 			pkg.Name = pkgName |  | ||||||
| 			pkg.BasePkgName = pkgNames.BasePkgName |  | ||||||
| 			dbPkgs = append(dbPkgs, pkg) |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 	return dbPkgs, nil | 	return dbPkgs, nil | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	pkg := EmptyPackage(repo.Name) |  | ||||||
| 	err = d.DecodeVars(pkg) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	resolveOverrides(runner, pkg) |  | ||||||
| 	dbPkgs = append(dbPkgs, pkg) |  | ||||||
|  |  | ||||||
| 	return dbPkgs, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type PackageInfo struct { |  | ||||||
| 	Version       string   `sh:"version,required"` |  | ||||||
| 	Release       int      `sh:"release,required"` |  | ||||||
| 	Epoch         uint     `sh:"epoch"` |  | ||||||
| 	Architectures []string `sh:"architectures"` |  | ||||||
| 	Licenses      []string `sh:"license"` |  | ||||||
| 	Provides      []string `sh:"provides"` |  | ||||||
| 	Conflicts     []string `sh:"conflicts"` |  | ||||||
| 	Replaces      []string `sh:"replaces"` |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (inf *PackageInfo) ToPackage(repoName string) *db.Package { |  | ||||||
| 	pkg := EmptyPackage(repoName) |  | ||||||
| 	pkg.Version = inf.Version |  | ||||||
| 	pkg.Release = inf.Release |  | ||||||
| 	pkg.Epoch = inf.Epoch |  | ||||||
| 	pkg.Architectures = inf.Architectures |  | ||||||
| 	pkg.Licenses = inf.Licenses |  | ||||||
| 	pkg.Provides = inf.Provides |  | ||||||
| 	pkg.Conflicts = inf.Conflicts |  | ||||||
| 	pkg.Replaces = inf.Replaces |  | ||||||
| 	return pkg |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func EmptyPackage(repoName string) *db.Package { |  | ||||||
| 	return &db.Package{ |  | ||||||
| 		Group:        map[string]string{}, |  | ||||||
| 		Summary:      map[string]string{}, |  | ||||||
| 		Description:  map[string]string{}, |  | ||||||
| 		Homepage:     map[string]string{}, |  | ||||||
| 		Maintainer:   map[string]string{}, |  | ||||||
| 		Depends:      map[string][]string{}, |  | ||||||
| 		BuildDepends: map[string][]string{}, |  | ||||||
| 		Repository:   repoName, |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| var overridable = map[string]string{ |  | ||||||
| 	"deps":       "Depends", |  | ||||||
| 	"build_deps": "BuildDepends", |  | ||||||
| 	"desc":       "Description", |  | ||||||
| 	"homepage":   "Homepage", |  | ||||||
| 	"maintainer": "Maintainer", |  | ||||||
| 	"group":      "Group", |  | ||||||
| 	"summary":    "Summary", |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func resolveOverrides(runner *interp.Runner, pkg *db.Package) { |  | ||||||
| 	pkgVal := reflect.ValueOf(pkg).Elem() |  | ||||||
| 	for name, val := range runner.Vars { |  | ||||||
| 		for prefix, field := range overridable { |  | ||||||
| 			if strings.HasPrefix(name, prefix) { |  | ||||||
| 				override := strings.TrimPrefix(name, prefix) |  | ||||||
| 				override = strings.TrimPrefix(override, "_") |  | ||||||
|  |  | ||||||
| 				varVal := pkgVal.FieldByName(field) |  | ||||||
| 				varType := varVal.Type() |  | ||||||
|  |  | ||||||
| 				switch varType.Elem().String() { |  | ||||||
| 				case "[]string": |  | ||||||
| 					varVal.SetMapIndex(reflect.ValueOf(override), reflect.ValueOf(val.List)) |  | ||||||
| 				case "string": |  | ||||||
| 					varVal.SetMapIndex(reflect.ValueOf(override), reflect.ValueOf(val.Str)) |  | ||||||
| 				} |  | ||||||
| 				break |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func getHeadReference(r *git.Repository) (plumbing.ReferenceName, error) { | func getHeadReference(r *git.Repository) (plumbing.ReferenceName, error) { | ||||||
|   | |||||||
| @@ -22,12 +22,11 @@ package search | |||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
|  |  | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/db" | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh" | ||||||
| 	database "gitea.plemya-x.ru/Plemya-x/ALR/internal/db" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type PackagesProvider interface { | type PackagesProvider interface { | ||||||
| 	GetPkgs(ctx context.Context, where string, args ...any) ([]db.Package, error) | 	GetPkgs(ctx context.Context, where string, args ...any) ([]alrsh.Package, error) | ||||||
| } | } | ||||||
|  |  | ||||||
| type Searcher struct { | type Searcher struct { | ||||||
| @@ -43,7 +42,7 @@ func New(pp PackagesProvider) *Searcher { | |||||||
| func (s *Searcher) Search( | func (s *Searcher) Search( | ||||||
| 	ctx context.Context, | 	ctx context.Context, | ||||||
| 	opts *SearchOptions, | 	opts *SearchOptions, | ||||||
| ) ([]database.Package, error) { | ) ([]alrsh.Package, error) { | ||||||
| 	where, args := opts.WhereClause() | 	where, args := opts.WhereClause() | ||||||
| 	packages, err := s.pp.GetPkgs(ctx, where, args...) | 	packages, err := s.pp.GetPkgs(ctx, where, args...) | ||||||
| 	return packages, err | 	return packages, err | ||||||
|   | |||||||
| @@ -22,6 +22,8 @@ package decoder | |||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
| 	"errors" | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"log/slog" | ||||||
| 	"reflect" | 	"reflect" | ||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
| @@ -52,7 +54,7 @@ type InvalidTypeError struct { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (ite InvalidTypeError) Error() string { | func (ite InvalidTypeError) Error() string { | ||||||
| 	return "variable '" + ite.name + "' is of type " + ite.vartype + ", but " + ite.exptype + " is expected" | 	return fmt.Sprintf("variable '%s' is of type %s, but %s is expected", ite.name, ite.vartype, ite.exptype) | ||||||
| } | } | ||||||
|  |  | ||||||
| // Decoder provides methods for decoding variable values | // Decoder provides methods for decoding variable values | ||||||
| @@ -80,10 +82,58 @@ func (d *Decoder) DecodeVar(name string, val any) error { | |||||||
|  |  | ||||||
| 	dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ | 	dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ | ||||||
| 		WeaklyTypedInput: true, | 		WeaklyTypedInput: true, | ||||||
|  | 		DecodeHook: mapstructure.DecodeHookFuncValue(func(from, to reflect.Value) (interface{}, error) { | ||||||
|  | 			if strings.Contains(to.Type().String(), "alrsh.OverridableField") { | ||||||
|  | 				if to.Kind() != reflect.Ptr && to.CanAddr() { | ||||||
|  | 					to = to.Addr() | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				names, err := overrides.Resolve(d.info, overrides.DefaultOpts.WithName(name)) | ||||||
|  | 				if err != nil { | ||||||
|  | 					return nil, err | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				isNotSet := true | ||||||
|  |  | ||||||
|  | 				setMethod := to.MethodByName("Set") | ||||||
|  | 				setResolvedMethod := to.MethodByName("SetResolved") | ||||||
|  |  | ||||||
|  | 				for _, varName := range names { | ||||||
|  | 					val := d.getVarNoOverrides(varName) | ||||||
|  | 					if val == nil { | ||||||
|  | 						continue | ||||||
|  | 					} | ||||||
|  |  | ||||||
|  | 					t := setMethod.Type().In(1) | ||||||
|  |  | ||||||
|  | 					newVal := from | ||||||
|  |  | ||||||
|  | 					if !newVal.Type().AssignableTo(t) { | ||||||
|  | 						newVal = reflect.New(t) | ||||||
|  | 						err = d.DecodeVar(name, newVal.Interface()) | ||||||
|  | 						if err != nil { | ||||||
|  | 							return nil, err | ||||||
|  | 						} | ||||||
|  | 						newVal = newVal.Elem() | ||||||
|  | 					} | ||||||
|  |  | ||||||
|  | 					if isNotSet { | ||||||
|  | 						setResolvedMethod.Call([]reflect.Value{newVal}) | ||||||
|  | 					} | ||||||
|  |  | ||||||
|  | 					override := strings.TrimPrefix(strings.TrimPrefix(varName, name), "_") | ||||||
|  | 					setMethod.Call([]reflect.Value{reflect.ValueOf(override), newVal}) | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				return to, nil | ||||||
|  | 			} | ||||||
|  | 			return from.Interface(), nil | ||||||
|  | 		}), | ||||||
| 		Result:  val, | 		Result:  val, | ||||||
| 		TagName: "sh", | 		TagName: "sh", | ||||||
| 	}) | 	}) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  | 		slog.Warn("err", "err", err) | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -243,7 +293,16 @@ func (d *Decoder) getVar(name string) *expand.Variable { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	for _, varName := range names { | 	for _, varName := range names { | ||||||
| 		val, ok := d.Runner.Vars[varName] | 		res := d.getVarNoOverrides(varName) | ||||||
|  | 		if res != nil { | ||||||
|  | 			return res | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d *Decoder) getVarNoOverrides(name string) *expand.Variable { | ||||||
|  | 	val, ok := d.Runner.Vars[name] | ||||||
| 	if ok { | 	if ok { | ||||||
| 		// Resolve nameref variables | 		// Resolve nameref variables | ||||||
| 		_, resolved := val.Resolve(expand.FuncEnviron(func(s string) string { | 		_, resolved := val.Resolve(expand.FuncEnviron(func(s string) string { | ||||||
| @@ -256,7 +315,6 @@ func (d *Decoder) getVar(name string) *expand.Variable { | |||||||
|  |  | ||||||
| 		return &val | 		return &val | ||||||
| 	} | 	} | ||||||
| 	} |  | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -114,35 +114,35 @@ msgstr "" | |||||||
| msgid "Error parsing os-release file" | msgid "Error parsing os-release file" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: info.go:41 | #: info.go:42 | ||||||
| msgid "Print information about a package" | msgid "Print information about a package" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: info.go:46 | #: info.go:47 | ||||||
| msgid "Show all information, not just for the current distro" | msgid "Show all information, not just for the current distro" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: info.go:67 | #: info.go:68 | ||||||
| msgid "Error getting packages" | msgid "Error getting packages" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: info.go:82 | #: info.go:83 | ||||||
| msgid "Command info expected at least 1 argument, got %d" | msgid "Command info expected at least 1 argument, got %d" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: info.go:102 | #: info.go:104 | ||||||
| msgid "Error finding packages" | msgid "Error finding packages" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: info.go:116 | #: info.go:118 | ||||||
| msgid "Can't detect system language" | msgid "Can't detect system language" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: info.go:133 | #: info.go:135 | ||||||
| msgid "Error resolving overrides" | msgid "Error resolving overrides" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: info.go:141 info.go:146 | #: info.go:144 info.go:149 | ||||||
| msgid "Error encoding script variables" | msgid "Error encoding script variables" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @@ -174,19 +174,19 @@ msgstr "" | |||||||
| msgid "Error removing packages" | msgid "Error removing packages" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: internal/build/build.go:375 | #: internal/build/build.go:376 | ||||||
| msgid "Building package" | msgid "Building package" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: internal/build/build.go:404 | #: internal/build/build.go:405 | ||||||
| msgid "The checksums array must be the same length as sources" | msgid "The checksums array must be the same length as sources" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: internal/build/build.go:446 | #: internal/build/build.go:447 | ||||||
| msgid "Downloading sources" | msgid "Downloading sources" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: internal/build/build.go:538 | #: internal/build/build.go:539 | ||||||
| msgid "Installing dependencies" | msgid "Installing dependencies" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @@ -224,15 +224,15 @@ msgstr "" | |||||||
| msgid "Building package metadata" | msgid "Building package metadata" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: internal/build/script_executor.go:275 | #: internal/build/script_executor.go:276 | ||||||
| msgid "Executing prepare()" | msgid "Executing prepare()" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: internal/build/script_executor.go:284 | #: internal/build/script_executor.go:285 | ||||||
| msgid "Executing build()" | msgid "Executing build()" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: internal/build/script_executor.go:313 internal/build/script_executor.go:333 | #: internal/build/script_executor.go:314 internal/build/script_executor.go:334 | ||||||
| msgid "Executing %s()" | msgid "Executing %s()" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @@ -244,15 +244,15 @@ msgstr "" | |||||||
| msgid "Error initialization database" | msgid "Error initialization database" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: internal/cliutils/app_builder/builder.go:135 | #: internal/cliutils/app_builder/builder.go:142 | ||||||
| msgid "Error pulling repositories" | msgid "Error pulling repositories" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: internal/cliutils/app_builder/builder.go:152 | #: internal/cliutils/app_builder/builder.go:159 | ||||||
| msgid "Error parsing os release" | msgid "Error parsing os release" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: internal/cliutils/app_builder/builder.go:165 | #: internal/cliutils/app_builder/builder.go:172 | ||||||
| msgid "Unable to detect a supported package manager on the system" | msgid "Unable to detect a supported package manager on the system" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @@ -336,17 +336,17 @@ msgstr "" | |||||||
| msgid "OPTIONS" | msgid "OPTIONS" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: internal/cliutils/utils.go:69 | #: internal/cliutils/utils.go:72 | ||||||
| msgid "" | msgid "" | ||||||
| "This command is deprecated and would be removed in the future, use \"%s\" " | "This command is deprecated and would be removed in the future, use \"%s\" " | ||||||
| "instead!" | "instead!" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: internal/db/db.go:95 | #: internal/db/db.go:76 | ||||||
| msgid "Database version mismatch; resetting" | msgid "Database version mismatch; resetting" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: internal/db/db.go:101 | #: internal/db/db.go:82 | ||||||
| msgid "" | msgid "" | ||||||
| "Database version does not exist. Run alr fix if something isn't working." | "Database version does not exist. Run alr fix if something isn't working." | ||||||
| msgstr "" | msgstr "" | ||||||
| @@ -541,14 +541,14 @@ msgstr "" | |||||||
| msgid "Error while executing search" | msgid "Error while executing search" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: upgrade.go:47 | #: upgrade.go:48 | ||||||
| msgid "Upgrade all installed packages" | msgid "Upgrade all installed packages" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: upgrade.go:105 upgrade.go:122 | #: upgrade.go:106 upgrade.go:123 | ||||||
| msgid "Error checking for updates" | msgid "Error checking for updates" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: upgrade.go:125 | #: upgrade.go:126 | ||||||
| msgid "There is nothing to do." | msgid "There is nothing to do." | ||||||
| msgstr "" | msgstr "" | ||||||
|   | |||||||
| @@ -121,35 +121,35 @@ msgstr "Такой вспомогательной команды нет" | |||||||
| msgid "Error parsing os-release file" | msgid "Error parsing os-release file" | ||||||
| msgstr "Ошибка при разборе файла выпуска операционной системы" | msgstr "Ошибка при разборе файла выпуска операционной системы" | ||||||
|  |  | ||||||
| #: info.go:41 | #: info.go:42 | ||||||
| msgid "Print information about a package" | msgid "Print information about a package" | ||||||
| msgstr "Отобразить информацию о пакете" | msgstr "Отобразить информацию о пакете" | ||||||
|  |  | ||||||
| #: info.go:46 | #: info.go:47 | ||||||
| msgid "Show all information, not just for the current distro" | msgid "Show all information, not just for the current distro" | ||||||
| msgstr "Показывать всю информацию, не только для текущего дистрибутива" | msgstr "Показывать всю информацию, не только для текущего дистрибутива" | ||||||
|  |  | ||||||
| #: info.go:67 | #: info.go:68 | ||||||
| msgid "Error getting packages" | msgid "Error getting packages" | ||||||
| msgstr "Ошибка при получении пакетов" | msgstr "Ошибка при получении пакетов" | ||||||
|  |  | ||||||
| #: info.go:82 | #: info.go:83 | ||||||
| msgid "Command info expected at least 1 argument, got %d" | msgid "Command info expected at least 1 argument, got %d" | ||||||
| msgstr "Для команды info ожидался хотя бы 1 аргумент, получено %d" | msgstr "Для команды info ожидался хотя бы 1 аргумент, получено %d" | ||||||
|  |  | ||||||
| #: info.go:102 | #: info.go:104 | ||||||
| msgid "Error finding packages" | msgid "Error finding packages" | ||||||
| msgstr "Ошибка при поиске пакетов" | msgstr "Ошибка при поиске пакетов" | ||||||
|  |  | ||||||
| #: info.go:116 | #: info.go:118 | ||||||
| msgid "Can't detect system language" | msgid "Can't detect system language" | ||||||
| msgstr "Ошибка при определении языка системы" | msgstr "Ошибка при определении языка системы" | ||||||
|  |  | ||||||
| #: info.go:133 | #: info.go:135 | ||||||
| msgid "Error resolving overrides" | msgid "Error resolving overrides" | ||||||
| msgstr "Ошибка устранения переорпеделений" | msgstr "Ошибка устранения переорпеделений" | ||||||
|  |  | ||||||
| #: info.go:141 info.go:146 | #: info.go:144 info.go:149 | ||||||
| msgid "Error encoding script variables" | msgid "Error encoding script variables" | ||||||
| msgstr "Ошибка кодирования переменных скрита" | msgstr "Ошибка кодирования переменных скрита" | ||||||
|  |  | ||||||
| @@ -181,19 +181,19 @@ msgstr "Для команды remove ожидался хотя бы 1 аргум | |||||||
| msgid "Error removing packages" | msgid "Error removing packages" | ||||||
| msgstr "Ошибка при удалении пакетов" | msgstr "Ошибка при удалении пакетов" | ||||||
|  |  | ||||||
| #: internal/build/build.go:375 | #: internal/build/build.go:376 | ||||||
| msgid "Building package" | msgid "Building package" | ||||||
| msgstr "Сборка пакета" | msgstr "Сборка пакета" | ||||||
|  |  | ||||||
| #: internal/build/build.go:404 | #: internal/build/build.go:405 | ||||||
| msgid "The checksums array must be the same length as sources" | msgid "The checksums array must be the same length as sources" | ||||||
| msgstr "Массив контрольных сумм должен быть той же длины, что и источники" | msgstr "Массив контрольных сумм должен быть той же длины, что и источники" | ||||||
|  |  | ||||||
| #: internal/build/build.go:446 | #: internal/build/build.go:447 | ||||||
| msgid "Downloading sources" | msgid "Downloading sources" | ||||||
| msgstr "Скачивание источников" | msgstr "Скачивание источников" | ||||||
|  |  | ||||||
| #: internal/build/build.go:538 | #: internal/build/build.go:539 | ||||||
| msgid "Installing dependencies" | msgid "Installing dependencies" | ||||||
| msgstr "Установка зависимостей" | msgstr "Установка зависимостей" | ||||||
|  |  | ||||||
| @@ -235,15 +235,15 @@ msgstr "" | |||||||
| msgid "Building package metadata" | msgid "Building package metadata" | ||||||
| msgstr "Сборка метаданных пакета" | msgstr "Сборка метаданных пакета" | ||||||
|  |  | ||||||
| #: internal/build/script_executor.go:275 | #: internal/build/script_executor.go:276 | ||||||
| msgid "Executing prepare()" | msgid "Executing prepare()" | ||||||
| msgstr "Выполнение prepare()" | msgstr "Выполнение prepare()" | ||||||
|  |  | ||||||
| #: internal/build/script_executor.go:284 | #: internal/build/script_executor.go:285 | ||||||
| msgid "Executing build()" | msgid "Executing build()" | ||||||
| msgstr "Выполнение build()" | msgstr "Выполнение build()" | ||||||
|  |  | ||||||
| #: internal/build/script_executor.go:313 internal/build/script_executor.go:333 | #: internal/build/script_executor.go:314 internal/build/script_executor.go:334 | ||||||
| msgid "Executing %s()" | msgid "Executing %s()" | ||||||
| msgstr "Выполнение %s()" | msgstr "Выполнение %s()" | ||||||
|  |  | ||||||
| @@ -255,15 +255,15 @@ msgstr "Ошибка при загрузке" | |||||||
| msgid "Error initialization database" | msgid "Error initialization database" | ||||||
| msgstr "Ошибка инициализации базы данных" | msgstr "Ошибка инициализации базы данных" | ||||||
|  |  | ||||||
| #: internal/cliutils/app_builder/builder.go:135 | #: internal/cliutils/app_builder/builder.go:142 | ||||||
| msgid "Error pulling repositories" | msgid "Error pulling repositories" | ||||||
| msgstr "Ошибка при извлечении репозиториев" | msgstr "Ошибка при извлечении репозиториев" | ||||||
|  |  | ||||||
| #: internal/cliutils/app_builder/builder.go:152 | #: internal/cliutils/app_builder/builder.go:159 | ||||||
| msgid "Error parsing os release" | msgid "Error parsing os release" | ||||||
| msgstr "Ошибка при разборе файла выпуска операционной системы" | msgstr "Ошибка при разборе файла выпуска операционной системы" | ||||||
|  |  | ||||||
| #: internal/cliutils/app_builder/builder.go:165 | #: internal/cliutils/app_builder/builder.go:172 | ||||||
| msgid "Unable to detect a supported package manager on the system" | msgid "Unable to detect a supported package manager on the system" | ||||||
| msgstr "Не удалось обнаружить поддерживаемый менеджер пакетов в системе" | msgstr "Не удалось обнаружить поддерживаемый менеджер пакетов в системе" | ||||||
|  |  | ||||||
| @@ -347,7 +347,7 @@ msgstr "КАТЕГОРИЯ" | |||||||
| msgid "OPTIONS" | msgid "OPTIONS" | ||||||
| msgstr "ПАРАМЕТРЫ" | msgstr "ПАРАМЕТРЫ" | ||||||
|  |  | ||||||
| #: internal/cliutils/utils.go:69 | #: internal/cliutils/utils.go:72 | ||||||
| msgid "" | msgid "" | ||||||
| "This command is deprecated and would be removed in the future, use \"%s\" " | "This command is deprecated and would be removed in the future, use \"%s\" " | ||||||
| "instead!" | "instead!" | ||||||
| @@ -355,11 +355,11 @@ msgstr "" | |||||||
| "Эта команда устарела и будет удалена в будущем, используйте вместо нее \"%s" | "Эта команда устарела и будет удалена в будущем, используйте вместо нее \"%s" | ||||||
| "\"!" | "\"!" | ||||||
|  |  | ||||||
| #: internal/db/db.go:95 | #: internal/db/db.go:76 | ||||||
| msgid "Database version mismatch; resetting" | msgid "Database version mismatch; resetting" | ||||||
| msgstr "Несоответствие версий базы данных; сброс настроек" | msgstr "Несоответствие версий базы данных; сброс настроек" | ||||||
|  |  | ||||||
| #: internal/db/db.go:101 | #: internal/db/db.go:82 | ||||||
| msgid "" | msgid "" | ||||||
| "Database version does not exist. Run alr fix if something isn't working." | "Database version does not exist. Run alr fix if something isn't working." | ||||||
| msgstr "" | msgstr "" | ||||||
| @@ -557,15 +557,15 @@ msgstr "Иcкать по provides" | |||||||
| msgid "Error while executing search" | msgid "Error while executing search" | ||||||
| msgstr "Ошибка при выполнении поиска" | msgstr "Ошибка при выполнении поиска" | ||||||
|  |  | ||||||
| #: upgrade.go:47 | #: upgrade.go:48 | ||||||
| msgid "Upgrade all installed packages" | msgid "Upgrade all installed packages" | ||||||
| msgstr "Обновить все установленные пакеты" | msgstr "Обновить все установленные пакеты" | ||||||
|  |  | ||||||
| #: upgrade.go:105 upgrade.go:122 | #: upgrade.go:106 upgrade.go:123 | ||||||
| msgid "Error checking for updates" | msgid "Error checking for updates" | ||||||
| msgstr "Ошибка при проверке обновлений" | msgstr "Ошибка при проверке обновлений" | ||||||
|  |  | ||||||
| #: upgrade.go:125 | #: upgrade.go:126 | ||||||
| msgid "There is nothing to do." | msgid "There is nothing to do." | ||||||
| msgstr "Здесь нечего делать." | msgstr "Здесь нечего делать." | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								list.go
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								list.go
									
									
									
									
									
								
							| @@ -32,9 +32,9 @@ import ( | |||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/build" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/build" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils" | ||||||
| 	appbuilder "gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils/app_builder" | 	appbuilder "gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils/app_builder" | ||||||
| 	database "gitea.plemya-x.ru/Plemya-x/ALR/internal/db" |  | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/manager" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/manager" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/utils" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/utils" | ||||||
|  | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func ListCmd() *cli.Command { | func ListCmd() *cli.Command { | ||||||
| @@ -69,9 +69,9 @@ func ListCmd() *cli.Command { | |||||||
| 				WithConfig(). | 				WithConfig(). | ||||||
| 				WithDB(). | 				WithDB(). | ||||||
| 				WithManager(). | 				WithManager(). | ||||||
|  | 				WithDistroInfo(). | ||||||
| 				// autoPull only | 				// autoPull only | ||||||
| 				WithRepos(). | 				WithRepos(). | ||||||
| 				WithDistroInfo(). |  | ||||||
| 				Build() | 				Build() | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return err | 				return err | ||||||
| @@ -159,7 +159,7 @@ func ListCmd() *cli.Command { | |||||||
| 				} | 				} | ||||||
|  |  | ||||||
| 				type packageInfo struct { | 				type packageInfo struct { | ||||||
| 					Package *database.Package | 					Package *alrsh.Package | ||||||
| 					Version string | 					Version string | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -38,7 +38,7 @@ import ( | |||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types" | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type ALRSh struct { | type ScriptFile struct { | ||||||
| 	file *syntax.File | 	file *syntax.File | ||||||
| 	path string | 	path string | ||||||
| } | } | ||||||
| @@ -72,97 +72,134 @@ func createBuildEnvVars(info *distro.OSRelease, dirs types.Directories) []string | |||||||
| 	return env | 	return env | ||||||
| } | } | ||||||
|  |  | ||||||
| func (s *ALRSh) ParseBuildVars(ctx context.Context, info *distro.OSRelease, packages []string) (string, []*types.BuildVars, error) { | func (s *ScriptFile) ParseBuildVars(ctx context.Context, info *distro.OSRelease, packages []string) (string, []*Package, error) { | ||||||
| 	varsOfPackages := []*types.BuildVars{} | 	runner, err := s.createRunner(info) | ||||||
|  |  | ||||||
| 	scriptDir := filepath.Dir(s.path) |  | ||||||
| 	env := createBuildEnvVars(info, types.Directories{ScriptDir: scriptDir}) |  | ||||||
|  |  | ||||||
| 	runner, err := interp.New( |  | ||||||
| 		interp.Env(expand.ListEnviron(env...)),                               // Устанавливаем окружение |  | ||||||
| 		interp.StdIO(os.Stdin, os.Stderr, os.Stderr),                         // Устанавливаем стандартный ввод-вывод |  | ||||||
| 		interp.ExecHandler(helpers.Restricted.ExecHandler(handlers.NopExec)), // Ограничиваем выполнение |  | ||||||
| 		interp.ReadDirHandler2(handlers.RestrictedReadDir(scriptDir)),        // Ограничиваем чтение директорий |  | ||||||
| 		interp.StatHandler(handlers.RestrictedStat(scriptDir)),               // Ограничиваем доступ к статистике файлов |  | ||||||
| 		interp.OpenHandler(handlers.RestrictedOpen(scriptDir)),               // Ограничиваем открытие файлов |  | ||||||
| 		interp.Dir(scriptDir), |  | ||||||
| 	) |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return "", nil, err | 		return "", nil, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	err = runner.Run(ctx, s.file) // Запускаем скрипт | 	if err := runScript(ctx, runner, s.file); err != nil { | ||||||
|  | 		return "", nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	dec := newDecoder(info, runner) | ||||||
|  |  | ||||||
|  | 	pkgNames, err := ParseNames(dec) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return "", nil, err | 		return "", nil, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	dec := decoder.New(info, runner) // Создаём новый декодер | 	if len(pkgNames.Names) == 0 { | ||||||
|  |  | ||||||
| 	type Packages struct { |  | ||||||
| 		BasePkgName string   `sh:"basepkg_name"` |  | ||||||
| 		Names       []string `sh:"name"` |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var pkgs Packages |  | ||||||
| 	err = dec.DecodeVars(&pkgs) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return "", nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	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 | 	targetPackages := packages | ||||||
|  | 	if len(targetPackages) == 0 { | ||||||
|  | 		targetPackages = pkgNames.Names | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	if len(pkgs.Names) == 1 { | 	varsOfPackages, err := s.createPackagesForBuildVars(ctx, dec, pkgNames, targetPackages) | ||||||
| 		err = dec.DecodeVars(&vars) |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return "", nil, err | 		return "", nil, err | ||||||
| 	} | 	} | ||||||
| 		varsOfPackages = append(varsOfPackages, &vars) |  | ||||||
|  |  | ||||||
| 		return vars.Name, varsOfPackages, nil | 	baseName := pkgNames.BasePkgName | ||||||
|  | 	if len(pkgNames.Names) == 1 { | ||||||
|  | 		baseName = pkgNames.Names[0] | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	var pkgNames []string | 	return baseName, varsOfPackages, nil | ||||||
|  | } | ||||||
|  |  | ||||||
| 	if len(packages) != 0 { | func (s *ScriptFile) createRunner(info *distro.OSRelease) (*interp.Runner, error) { | ||||||
| 		pkgNames = packages | 	scriptDir := filepath.Dir(s.path) | ||||||
| 	} else { | 	env := createBuildEnvVars(info, types.Directories{ScriptDir: scriptDir}) | ||||||
| 		pkgNames = pkgs.Names |  | ||||||
|  | 	return interp.New( | ||||||
|  | 		interp.Env(expand.ListEnviron(env...)), | ||||||
|  | 		interp.StdIO(os.Stdin, os.Stderr, os.Stderr), | ||||||
|  | 		interp.ExecHandler(helpers.Restricted.ExecHandler(handlers.NopExec)), | ||||||
|  | 		interp.ReadDirHandler2(handlers.RestrictedReadDir(scriptDir)), | ||||||
|  | 		interp.StatHandler(handlers.RestrictedStat(scriptDir)), | ||||||
|  | 		interp.OpenHandler(handlers.RestrictedOpen(scriptDir)), | ||||||
|  | 		interp.Dir(scriptDir), | ||||||
|  | 	) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s *ScriptFile) createPackagesForBuildVars( | ||||||
|  | 	ctx context.Context, | ||||||
|  | 	dec *decoder.Decoder, | ||||||
|  | 	pkgNames *PackageNames, | ||||||
|  | 	targetPackages []string, | ||||||
|  | ) ([]*Package, error) { | ||||||
|  | 	var varsOfPackages []*Package | ||||||
|  |  | ||||||
|  | 	if len(pkgNames.Names) == 1 { | ||||||
|  | 		var pkg Package | ||||||
|  | 		pkg.Name = pkgNames.Names[0] | ||||||
|  | 		if err := dec.DecodeVars(&pkg); err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		varsOfPackages = append(varsOfPackages, &pkg) | ||||||
|  | 		return varsOfPackages, nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	for _, pkgName := range pkgNames { | 	for _, pkgName := range targetPackages { | ||||||
| 		var preVars types.BuildVarsPre | 		pkg, err := s.createPackageFromMeta(ctx, dec, pkgName, pkgNames.BasePkgName) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		varsOfPackages = append(varsOfPackages, pkg) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return varsOfPackages, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s *ScriptFile) createPackageFromMeta( | ||||||
|  | 	ctx context.Context, | ||||||
|  | 	dec *decoder.Decoder, | ||||||
|  | 	pkgName, basePkgName string, | ||||||
|  | ) (*Package, error) { | ||||||
| 	funcName := fmt.Sprintf("meta_%s", pkgName) | 	funcName := fmt.Sprintf("meta_%s", pkgName) | ||||||
| 	meta, ok := dec.GetFuncWithSubshell(funcName) | 	meta, ok := dec.GetFuncWithSubshell(funcName) | ||||||
| 	if !ok { | 	if !ok { | ||||||
| 			return "", nil, fmt.Errorf("func %s is missing", funcName) | 		return nil, fmt.Errorf("func %s is missing", funcName) | ||||||
| 	} | 	} | ||||||
| 		r, err := meta(ctx) |  | ||||||
|  | 	metaRunner, err := meta(ctx) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 			return "", nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 		d := decoder.New(&distro.OSRelease{}, r) |  | ||||||
| 		err = d.DecodeVars(&preVars) | 	metaDecoder := decoder.New(&distro.OSRelease{}, metaRunner) | ||||||
| 		if err != nil { |  | ||||||
| 			return "", nil, err | 	var vars Package | ||||||
|  | 	if err := metaDecoder.DecodeVars(&vars); err != nil { | ||||||
|  | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 		vars := preVars.ToBuildVars() |  | ||||||
| 	vars.Name = pkgName | 	vars.Name = pkgName | ||||||
| 		vars.Base = pkgs.BasePkgName | 	vars.BasePkgName = basePkgName | ||||||
|  |  | ||||||
| 		varsOfPackages = append(varsOfPackages, &vars) | 	return &vars, nil | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return pkgs.BasePkgName, varsOfPackages, nil |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func (a *ALRSh) Path() string { | func runScript(ctx context.Context, runner *interp.Runner, fl *syntax.File) error { | ||||||
|  | 	runner.Reset() | ||||||
|  | 	return runner.Run(ctx, fl) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func newDecoder(info *distro.OSRelease, runner *interp.Runner) *decoder.Decoder { | ||||||
|  | 	d := decoder.New(info, runner) | ||||||
|  | 	// d.Overrides = false | ||||||
|  | 	// d.LikeDistros = false | ||||||
|  | 	return d | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (a *ScriptFile) Path() string { | ||||||
| 	return a.path | 	return a.path | ||||||
| } | } | ||||||
|  |  | ||||||
| func (a *ALRSh) File() *syntax.File { | func (a *ScriptFile) File() *syntax.File { | ||||||
| 	return a.file | 	return a.file | ||||||
| } | } | ||||||
|   | |||||||
| @@ -24,7 +24,7 @@ import ( | |||||||
| 	"mvdan.cc/sh/v3/syntax/typedjson" | 	"mvdan.cc/sh/v3/syntax/typedjson" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func (s *ALRSh) GobEncode() ([]byte, error) { | func (s *ScriptFile) GobEncode() ([]byte, error) { | ||||||
| 	var buf bytes.Buffer | 	var buf bytes.Buffer | ||||||
| 	enc := gob.NewEncoder(&buf) | 	enc := gob.NewEncoder(&buf) | ||||||
| 	if err := enc.Encode(s.path); err != nil { | 	if err := enc.Encode(s.path); err != nil { | ||||||
| @@ -41,7 +41,7 @@ func (s *ALRSh) GobEncode() ([]byte, error) { | |||||||
| 	return buf.Bytes(), nil | 	return buf.Bytes(), nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (s *ALRSh) GobDecode(data []byte) error { | func (s *ScriptFile) GobDecode(data []byte) error { | ||||||
| 	buf := bytes.NewBuffer(data) | 	buf := bytes.NewBuffer(data) | ||||||
| 	dec := gob.NewDecoder(buf) | 	dec := gob.NewDecoder(buf) | ||||||
| 	if err := dec.Decode(&s.path); err != nil { | 	if err := dec.Decode(&s.path); err != nil { | ||||||
|   | |||||||
							
								
								
									
										146
									
								
								pkg/alrsh/overridable.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								pkg/alrsh/overridable.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,146 @@ | |||||||
|  | // 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 alrsh | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"encoding/gob" | ||||||
|  | 	"encoding/json" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type OverridableField[T any] struct { | ||||||
|  | 	data map[string]T | ||||||
|  | 	// It can't be a pointer | ||||||
|  | 	// | ||||||
|  | 	// See https://gitea.com/xorm/xorm/issues/2431 | ||||||
|  | 	resolved T | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (f *OverridableField[T]) Set(key string, value T) { | ||||||
|  | 	if f.data == nil { | ||||||
|  | 		f.data = make(map[string]T) | ||||||
|  | 	} | ||||||
|  | 	f.data[key] = value | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (f *OverridableField[T]) Get(key string) T { | ||||||
|  | 	if f.data == nil { | ||||||
|  | 		f.data = make(map[string]T) | ||||||
|  | 	} | ||||||
|  | 	return f.data[key] | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (f *OverridableField[T]) Has(key string) (T, bool) { | ||||||
|  | 	if f.data == nil { | ||||||
|  | 		f.data = make(map[string]T) | ||||||
|  | 	} | ||||||
|  | 	val, ok := f.data[key] | ||||||
|  | 	return val, ok | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (f *OverridableField[T]) SetResolved(value T) { | ||||||
|  | 	f.resolved = value | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (f *OverridableField[T]) Resolved() T { | ||||||
|  | 	return f.resolved | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (f *OverridableField[T]) All() map[string]T { | ||||||
|  | 	return f.data | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (o *OverridableField[T]) Resolve(overrides []string) { | ||||||
|  | 	for _, override := range overrides { | ||||||
|  | 		if v, ok := o.Has(override); ok { | ||||||
|  | 			o.SetResolved(v) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (f *OverridableField[T]) ToDB() ([]byte, error) { | ||||||
|  | 	var data map[string]T | ||||||
|  |  | ||||||
|  | 	if f.data == nil { | ||||||
|  | 		data = make(map[string]T) | ||||||
|  | 	} else { | ||||||
|  | 		data = f.data | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return json.Marshal(data) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (f *OverridableField[T]) FromDB(data []byte) error { | ||||||
|  | 	if len(data) == 0 { | ||||||
|  | 		*f = OverridableField[T]{data: make(map[string]T)} | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var temp map[string]T | ||||||
|  | 	if err := json.Unmarshal(data, &temp); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if temp == nil { | ||||||
|  | 		temp = make(map[string]T) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	*f = OverridableField[T]{data: temp} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type overridableFieldGobPayload[T any] struct { | ||||||
|  | 	Data     map[string]T | ||||||
|  | 	Resolved T | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (f *OverridableField[T]) GobEncode() ([]byte, error) { | ||||||
|  | 	var buf bytes.Buffer | ||||||
|  | 	enc := gob.NewEncoder(&buf) | ||||||
|  |  | ||||||
|  | 	payload := overridableFieldGobPayload[T]{ | ||||||
|  | 		Data:     f.data, | ||||||
|  | 		Resolved: f.resolved, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if err := enc.Encode(payload); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return buf.Bytes(), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (f *OverridableField[T]) GobDecode(data []byte) error { | ||||||
|  | 	dec := gob.NewDecoder(bytes.NewBuffer(data)) | ||||||
|  |  | ||||||
|  | 	var payload overridableFieldGobPayload[T] | ||||||
|  | 	if err := dec.Decode(&payload); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	f.data = payload.Data | ||||||
|  | 	f.resolved = payload.Resolved | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func OverridableFromMap[T any](data map[string]T) OverridableField[T] { | ||||||
|  | 	if data == nil { | ||||||
|  | 		data = make(map[string]T) | ||||||
|  | 	} | ||||||
|  | 	return OverridableField[T]{ | ||||||
|  | 		data: data, | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										105
									
								
								pkg/alrsh/package.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								pkg/alrsh/package.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,105 @@ | |||||||
|  | // 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 alrsh | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"reflect" | ||||||
|  | 	"strings" | ||||||
|  |  | ||||||
|  | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/shutils/decoder" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type PackageNames struct { | ||||||
|  | 	BasePkgName string   `sh:"basepkg_name"` | ||||||
|  | 	Names       []string `sh:"name"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func ParseNames(dec *decoder.Decoder) (*PackageNames, error) { | ||||||
|  | 	var pkgs PackageNames | ||||||
|  | 	err := dec.DecodeVars(&pkgs) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, fmt.Errorf("fail parse names: %w", err) | ||||||
|  | 	} | ||||||
|  | 	return &pkgs, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type Package struct { | ||||||
|  | 	Repository  string `xorm:"pk 'repository'"` | ||||||
|  | 	Name        string `xorm:"pk 'name'"` | ||||||
|  | 	BasePkgName string `xorm:"notnull 'basepkg_name'"` | ||||||
|  |  | ||||||
|  | 	Version       string   `sh:"version" xorm:"notnull 'version'"` | ||||||
|  | 	Release       int      `sh:"release" xorm:"notnull 'release'"` | ||||||
|  | 	Epoch         uint     `sh:"epoch" xorm:"'epoch'"` | ||||||
|  | 	Architectures []string `sh:"architectures" xorm:"json 'architectures'"` | ||||||
|  | 	Licenses      []string `sh:"license" xorm:"json 'licenses'"` | ||||||
|  | 	Provides      []string `sh:"provides" xorm:"json 'provides'"` | ||||||
|  | 	Conflicts     []string `sh:"conflicts" xorm:"json 'conflicts'"` | ||||||
|  | 	Replaces      []string `sh:"replaces" xorm:"json 'replaces'"` | ||||||
|  |  | ||||||
|  | 	Summary          OverridableField[string]   `sh:"summary" xorm:"'summary'"` | ||||||
|  | 	Description      OverridableField[string]   `sh:"desc" xorm:"'description'"` | ||||||
|  | 	Group            OverridableField[string]   `sh:"group" xorm:"'group_name'"` | ||||||
|  | 	Homepage         OverridableField[string]   `sh:"homepage" xorm:"'homepage'"` | ||||||
|  | 	Maintainer       OverridableField[string]   `sh:"maintainer" xorm:"'maintainer'"` | ||||||
|  | 	Depends          OverridableField[[]string] `sh:"deps" xorm:"'depends'"` | ||||||
|  | 	BuildDepends     OverridableField[[]string] `sh:"build_deps" xorm:"'builddepends'"` | ||||||
|  | 	OptDepends       OverridableField[[]string] `sh:"opt_deps" xorm:"'optdepends'"` | ||||||
|  | 	Sources          OverridableField[[]string] `sh:"sources" xorm:"-"` | ||||||
|  | 	Checksums        OverridableField[[]string] `sh:"checksums" xorm:"-"` | ||||||
|  | 	Backup           OverridableField[[]string] `sh:"backup" xorm:"-"` | ||||||
|  | 	Scripts          OverridableField[Scripts]  `sh:"scripts" xorm:"-"` | ||||||
|  | 	AutoReq          OverridableField[[]string] `sh:"auto_req" xorm:"-"` | ||||||
|  | 	AutoProv         OverridableField[[]string] `sh:"auto_prov" xorm:"-"` | ||||||
|  | 	AutoReqSkipList  OverridableField[[]string] `sh:"auto_req_skiplist" xorm:"-"` | ||||||
|  | 	AutoProvSkipList OverridableField[[]string] `sh:"auto_prov_skiplist" xorm:"-"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type Scripts struct { | ||||||
|  | 	PreInstall  string `sh:"preinstall"` | ||||||
|  | 	PostInstall string `sh:"postinstall"` | ||||||
|  | 	PreRemove   string `sh:"preremove"` | ||||||
|  | 	PostRemove  string `sh:"postremove"` | ||||||
|  | 	PreUpgrade  string `sh:"preupgrade"` | ||||||
|  | 	PostUpgrade string `sh:"postupgrade"` | ||||||
|  | 	PreTrans    string `sh:"pretrans"` | ||||||
|  | 	PostTrans   string `sh:"posttrans"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func ResolvePackage(p *Package, overrides []string) { | ||||||
|  | 	val := reflect.ValueOf(p).Elem() | ||||||
|  | 	typ := val.Type() | ||||||
|  |  | ||||||
|  | 	for i := range val.NumField() { | ||||||
|  | 		field := val.Field(i) | ||||||
|  | 		fieldType := typ.Field(i) | ||||||
|  |  | ||||||
|  | 		if !field.CanInterface() { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if field.Kind() == reflect.Struct && strings.HasPrefix(fieldType.Type.String(), "alrsh.OverridableField") { | ||||||
|  | 			of := field.Addr().Interface() | ||||||
|  | 			if res, ok := of.(interface { | ||||||
|  | 				Resolve([]string) | ||||||
|  | 			}); ok { | ||||||
|  | 				res.Resolve(overrides) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -18,6 +18,7 @@ package alrsh | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"io" | ||||||
| 	"io/fs" | 	"io/fs" | ||||||
| 	"os" | 	"os" | ||||||
|  |  | ||||||
| @@ -30,23 +31,27 @@ func (fs *localFs) Open(name string) (fs.File, error) { | |||||||
| 	return os.Open(name) | 	return os.Open(name) | ||||||
| } | } | ||||||
|  |  | ||||||
| func ReadFromFS(fsys fs.FS, script string) (*ALRSh, error) { | func ReadFromIOReader(r io.Reader, script string) (*ScriptFile, error) { | ||||||
|  | 	file, err := syntax.NewParser().Parse(r, "alr.sh") | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return &ScriptFile{ | ||||||
|  | 		file: file, | ||||||
|  | 		path: script, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func ReadFromFS(fsys fs.FS, script string) (*ScriptFile, error) { | ||||||
| 	fl, err := fsys.Open(script) | 	fl, err := fsys.Open(script) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("failed to open alr.sh: %w", err) | 		return nil, fmt.Errorf("failed to open alr.sh: %w", err) | ||||||
| 	} | 	} | ||||||
| 	defer fl.Close() | 	defer fl.Close() | ||||||
|  |  | ||||||
| 	file, err := syntax.NewParser().Parse(fl, "alr.sh") | 	return ReadFromIOReader(fl, script) | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return &ALRSh{ |  | ||||||
| 		file: file, |  | ||||||
| 		path: script, |  | ||||||
| 	}, nil |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func ReadFromLocal(script string) (*ALRSh, error) { | func ReadFromLocal(script string) (*ScriptFile, error) { | ||||||
| 	return ReadFromFS(&localFs{}, script) | 	return ReadFromFS(&localFs{}, script) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -24,49 +24,6 @@ type BuildOpts struct { | |||||||
| 	Interactive bool | 	Interactive bool | ||||||
| } | } | ||||||
|  |  | ||||||
| type BuildVarsPre struct { |  | ||||||
| 	Version          string   `sh:"version,required"` |  | ||||||
| 	Release          int      `sh:"release,required"` |  | ||||||
| 	Epoch            uint     `sh:"epoch"` |  | ||||||
| 	Summary          string   `sh:"summary"` |  | ||||||
| 	Description      string   `sh:"desc"` |  | ||||||
| 	Group            string   `sh:"group"` |  | ||||||
| 	Homepage         string   `sh:"homepage"` |  | ||||||
| 	Maintainer       string   `sh:"maintainer"` |  | ||||||
| 	Architectures    []string `sh:"architectures"` |  | ||||||
| 	Licenses         []string `sh:"license"` |  | ||||||
| 	Provides         []string `sh:"provides"` |  | ||||||
| 	Conflicts        []string `sh:"conflicts"` |  | ||||||
| 	Depends          []string `sh:"deps"` |  | ||||||
| 	BuildDepends     []string `sh:"build_deps"` |  | ||||||
| 	OptDepends       []string `sh:"opt_deps"` |  | ||||||
| 	Replaces         []string `sh:"replaces"` |  | ||||||
| 	Sources          []string `sh:"sources"` |  | ||||||
| 	Checksums        []string `sh:"checksums"` |  | ||||||
| 	Backup           []string `sh:"backup"` |  | ||||||
| 	Scripts          Scripts  `sh:"scripts"` |  | ||||||
| 	AutoReq          []string `sh:"auto_req"` |  | ||||||
| 	AutoProv         []string `sh:"auto_prov"` |  | ||||||
| 	AutoReqSkipList  []string `sh:"auto_req_skiplist"` |  | ||||||
| 	AutoProvSkipList []string `sh:"auto_prov_skiplist"` |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (bv *BuildVarsPre) ToBuildVars() BuildVars { |  | ||||||
| 	return BuildVars{ |  | ||||||
| 		Name:         "", |  | ||||||
| 		Base:         "", |  | ||||||
| 		BuildVarsPre: *bv, |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // BuildVars represents the script variables required |  | ||||||
| // to build a package |  | ||||||
| type BuildVars struct { |  | ||||||
| 	Name string `sh:"name,required"` |  | ||||||
| 	Base string |  | ||||||
| 	BuildVarsPre |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type Scripts struct { | type Scripts struct { | ||||||
| 	PreInstall  string `sh:"preinstall"` | 	PreInstall  string `sh:"preinstall"` | ||||||
| 	PostInstall string `sh:"postinstall"` | 	PostInstall string `sh:"postinstall"` | ||||||
|   | |||||||
							
								
								
									
										21
									
								
								search.go
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								search.go
									
									
									
									
									
								
							| @@ -27,10 +27,10 @@ import ( | |||||||
|  |  | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils" | ||||||
| 	appbuilder "gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils/app_builder" | 	appbuilder "gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils/app_builder" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/db" |  | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/overrides" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/overrides" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/search" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/search" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/utils" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/utils" | ||||||
|  | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro" | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -139,27 +139,16 @@ func SearchCmd() *cli.Command { | |||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			for _, dbPkg := range packages { | 			for _, pkg := range packages { | ||||||
| 				var pkg any | 				alrsh.ResolvePackage(&pkg, names) | ||||||
| 				if !all { |  | ||||||
| 					pkg = overrides.ResolvePackage(&dbPkg, names) |  | ||||||
| 				} else { |  | ||||||
| 					pkg = &dbPkg |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				if tmpl != nil { | 				if tmpl != nil { | ||||||
| 					err = tmpl.Execute(os.Stdout, pkg) | 					err = tmpl.Execute(os.Stdout, &pkg) | ||||||
| 					if err != nil { | 					if err != nil { | ||||||
| 						return cliutils.FormatCliExit(gotext.Get("Error executing template"), err) | 						return cliutils.FormatCliExit(gotext.Get("Error executing template"), err) | ||||||
| 					} | 					} | ||||||
| 					fmt.Println() | 					fmt.Println() | ||||||
| 				} else { | 				} else { | ||||||
| 					switch v := pkg.(type) { | 					fmt.Println(pkg.Name) | ||||||
| 					case *overrides.ResolvedPackage: |  | ||||||
| 						fmt.Println(v.Name) |  | ||||||
| 					case *db.Package: |  | ||||||
| 						fmt.Println(v.Name) |  | ||||||
| 					} |  | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -37,6 +37,7 @@ import ( | |||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/overrides" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/overrides" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/search" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/search" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/utils" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/utils" | ||||||
|  | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro" | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types" | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types" | ||||||
| ) | ) | ||||||
| @@ -130,8 +131,8 @@ func UpgradeCmd() *cli.Command { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func mapUptatesInfoToPackages(updates []UpdateInfo) []database.Package { | func mapUptatesInfoToPackages(updates []UpdateInfo) []alrsh.Package { | ||||||
| 	var pkgs []database.Package | 	var pkgs []alrsh.Package | ||||||
| 	for _, info := range updates { | 	for _, info := range updates { | ||||||
| 		pkgs = append(pkgs, *info.Package) | 		pkgs = append(pkgs, *info.Package) | ||||||
| 	} | 	} | ||||||
| @@ -139,7 +140,7 @@ func mapUptatesInfoToPackages(updates []UpdateInfo) []database.Package { | |||||||
| } | } | ||||||
|  |  | ||||||
| type UpdateInfo struct { | type UpdateInfo struct { | ||||||
| 	Package *database.Package | 	Package *alrsh.Package | ||||||
|  |  | ||||||
| 	FromVersion string | 	FromVersion string | ||||||
| 	ToVersion   string | 	ToVersion   string | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user