fix parsing overrides
This commit is contained in:
		
							
								
								
									
										1
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								Makefile
									
									
									
									
									
								
							| @@ -21,6 +21,7 @@ build: check-no-root $(BIN) | ||||
|  | ||||
| export CGO_ENABLED := 0 | ||||
| $(BIN): | ||||
| 	go generate ./... | ||||
| 	go build -ldflags="-X 'gitea.plemya-x.ru/Plemya-x/ALR/internal/config.Version=$(GIT_VERSION)'" -o $@ | ||||
|  | ||||
| check-no-root: | ||||
|   | ||||
| @@ -11,7 +11,7 @@ | ||||
|     <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="14">coverage</text> | ||||
|         <text x="86" y="15" fill="#010101" fill-opacity=".3">20.1%</text> | ||||
|         <text x="86" y="14">20.1%</text> | ||||
|         <text x="86" y="15" fill="#010101" fill-opacity=".3">19.7%</text> | ||||
|         <text x="86" y="14">19.7%</text> | ||||
|     </g> | ||||
| </svg> | ||||
|   | ||||
| Before Width: | Height: | Size: 926 B After Width: | Height: | Size: 926 B | 
							
								
								
									
										251
									
								
								generators/alrsh-package/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										251
									
								
								generators/alrsh-package/main.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,251 @@ | ||||
| // 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 main | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"go/format" | ||||
| 	"go/parser" | ||||
| 	"go/token" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"reflect" | ||||
| 	"strings" | ||||
| 	"text/template" | ||||
| ) | ||||
|  | ||||
| func resolvedStructGenerator(buf *bytes.Buffer, fields []*ast.Field) { | ||||
| 	contentTemplate := template.Must(template.New("").Parse(` | ||||
| type {{ .EntityNameLower }}Resolved struct { | ||||
| {{ .StructFields }} | ||||
| } | ||||
| `)) | ||||
|  | ||||
| 	var structFieldsBuilder strings.Builder | ||||
|  | ||||
| 	for _, field := range fields { | ||||
| 		for _, name := range field.Names { | ||||
| 			// Поле с типом | ||||
| 			fieldTypeStr := exprToString(field.Type) | ||||
|  | ||||
| 			// Структура поля | ||||
| 			var buf bytes.Buffer | ||||
| 			buf.WriteString("\t") | ||||
| 			buf.WriteString(name.Name) | ||||
| 			buf.WriteString(" ") | ||||
| 			buf.WriteString(fieldTypeStr) | ||||
|  | ||||
| 			// Обработка json-тега | ||||
| 			jsonTag := "" | ||||
| 			if field.Tag != nil { | ||||
| 				raw := strings.Trim(field.Tag.Value, "`") | ||||
| 				tag := reflect.StructTag(raw) | ||||
| 				if val := tag.Get("json"); val != "" { | ||||
| 					jsonTag = val | ||||
| 				} | ||||
| 			} | ||||
| 			if jsonTag == "" { | ||||
| 				jsonTag = strings.ToLower(name.Name) | ||||
| 			} | ||||
| 			buf.WriteString(fmt.Sprintf(" `json:\"%s\"`", jsonTag)) | ||||
| 			buf.WriteString("\n") | ||||
| 			structFieldsBuilder.Write(buf.Bytes()) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	params := struct { | ||||
| 		EntityNameLower string | ||||
| 		StructFields    string | ||||
| 	}{ | ||||
| 		EntityNameLower: "package", | ||||
| 		StructFields:    structFieldsBuilder.String(), | ||||
| 	} | ||||
|  | ||||
| 	err := contentTemplate.Execute(buf, params) | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("execute template: %v", err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func toResolvedFuncGenerator(buf *bytes.Buffer, fields []*ast.Field) { | ||||
| 	contentTemplate := template.Must(template.New("").Parse(` | ||||
| func {{ .EntityName }}ToResolved(src *{{ .EntityName }}) {{ .EntityNameLower }}Resolved { | ||||
| 	return {{ .EntityNameLower }}Resolved{ | ||||
| {{ .Assignments }} | ||||
| 	} | ||||
| } | ||||
| `)) | ||||
|  | ||||
| 	var assignmentsBuilder strings.Builder | ||||
|  | ||||
| 	for _, field := range fields { | ||||
| 		for _, name := range field.Names { | ||||
| 			var assignBuf bytes.Buffer | ||||
| 			assignBuf.WriteString("\t\t") | ||||
| 			assignBuf.WriteString(name.Name) | ||||
| 			assignBuf.WriteString(": ") | ||||
| 			if isOverridableField(field.Type) { | ||||
| 				assignBuf.WriteString(fmt.Sprintf("src.%s.Resolved()", name.Name)) | ||||
| 			} else { | ||||
| 				assignBuf.WriteString(fmt.Sprintf("src.%s", name.Name)) | ||||
| 			} | ||||
| 			assignBuf.WriteString(",\n") | ||||
| 			assignmentsBuilder.Write(assignBuf.Bytes()) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	params := struct { | ||||
| 		EntityName      string | ||||
| 		EntityNameLower string | ||||
| 		Assignments     string | ||||
| 	}{ | ||||
| 		EntityName:      "Package", | ||||
| 		EntityNameLower: "package", | ||||
| 		Assignments:     assignmentsBuilder.String(), | ||||
| 	} | ||||
|  | ||||
| 	err := contentTemplate.Execute(buf, params) | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("execute template: %v", err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func resolveFuncGenerator(buf *bytes.Buffer, fields []*ast.Field) { | ||||
| 	contentTemplate := template.Must(template.New("").Parse(` | ||||
| func Resolve{{ .EntityName }}(pkg *{{ .EntityName }}, overrides []string) { | ||||
| {{.Code}}} | ||||
| `)) | ||||
|  | ||||
| 	var codeBuilder strings.Builder | ||||
|  | ||||
| 	for _, field := range fields { | ||||
| 		for _, name := range field.Names { | ||||
| 			if isOverridableField(field.Type) { | ||||
| 				var buf bytes.Buffer | ||||
| 				buf.WriteString(fmt.Sprintf("\t\tpkg.%s.Resolve(overrides)\n", name.Name)) | ||||
| 				codeBuilder.Write(buf.Bytes()) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	params := struct { | ||||
| 		EntityName string | ||||
| 		Code       string | ||||
| 	}{ | ||||
| 		EntityName: "Package", | ||||
| 		Code:       codeBuilder.String(), | ||||
| 	} | ||||
|  | ||||
| 	err := contentTemplate.Execute(buf, params) | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("execute template: %v", err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func main() { | ||||
| 	path := os.Getenv("GOFILE") | ||||
| 	if path == "" { | ||||
| 		log.Fatal("GOFILE must be set") | ||||
| 	} | ||||
|  | ||||
| 	fset := token.NewFileSet() | ||||
| 	node, err := parser.ParseFile(fset, path, nil, parser.AllErrors) | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("parsing file: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	entityName := "Package" // имя структуры, которую анализируем | ||||
|  | ||||
| 	found := false | ||||
|  | ||||
| 	fields := make([]*ast.Field, 0) | ||||
|  | ||||
| 	// Ищем структуру с нужным именем | ||||
| 	for _, decl := range node.Decls { | ||||
| 		genDecl, ok := decl.(*ast.GenDecl) | ||||
| 		if !ok || genDecl.Tok != token.TYPE { | ||||
| 			continue | ||||
| 		} | ||||
| 		for _, spec := range genDecl.Specs { | ||||
| 			typeSpec := spec.(*ast.TypeSpec) | ||||
| 			if typeSpec.Name.Name != entityName { | ||||
| 				continue | ||||
| 			} | ||||
| 			structType, ok := typeSpec.Type.(*ast.StructType) | ||||
| 			if !ok { | ||||
| 				continue | ||||
| 			} | ||||
| 			fields = structType.Fields.List | ||||
| 			found = true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if !found { | ||||
| 		log.Fatalf("struct %s not found", entityName) | ||||
| 	} | ||||
|  | ||||
| 	var buf bytes.Buffer | ||||
|  | ||||
| 	buf.WriteString("// DO NOT EDIT MANUALLY. This file is generated.\n") | ||||
| 	buf.WriteString("package alrsh") | ||||
|  | ||||
| 	resolvedStructGenerator(&buf, fields) | ||||
| 	toResolvedFuncGenerator(&buf, fields) | ||||
| 	resolveFuncGenerator(&buf, fields) | ||||
|  | ||||
| 	// Форматируем вывод | ||||
| 	formatted, err := format.Source(buf.Bytes()) | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("formatting: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	outPath := strings.TrimSuffix(path, ".go") + "_gen.go" | ||||
| 	outFile, err := os.Create(outPath) | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("create file: %v", err) | ||||
| 	} | ||||
| 	_, err = outFile.Write(formatted) | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("writing output: %v", err) | ||||
| 	} | ||||
| 	outFile.Close() | ||||
| } | ||||
|  | ||||
| func exprToString(expr ast.Expr) string { | ||||
| 	if t, ok := expr.(*ast.IndexExpr); ok { | ||||
| 		if ident, ok := t.X.(*ast.Ident); ok && ident.Name == "OverridableField" { | ||||
| 			return exprToString(t.Index) // T | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	var buf bytes.Buffer | ||||
| 	if err := format.Node(&buf, token.NewFileSet(), expr); err != nil { | ||||
| 		return "<invalid>" | ||||
| 	} | ||||
| 	return buf.String() | ||||
| } | ||||
|  | ||||
| func isOverridableField(expr ast.Expr) bool { | ||||
| 	indexExpr, ok := expr.(*ast.IndexExpr) | ||||
| 	if !ok { | ||||
| 		return false | ||||
| 	} | ||||
| 	ident, ok := indexExpr.X.(*ast.Ident) | ||||
| 	return ok && ident.Name == "OverridableField" | ||||
| } | ||||
							
								
								
									
										3
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								go.mod
									
									
									
									
									
								
							| @@ -18,6 +18,7 @@ require ( | ||||
| 	github.com/efficientgo/e2e v0.14.1-0.20240418111536-97db25a0c6c0 | ||||
| 	github.com/go-git/go-billy/v5 v5.6.0 | ||||
| 	github.com/go-git/go-git/v5 v5.13.0 | ||||
| 	github.com/goccy/go-yaml v1.18.0 | ||||
| 	github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 | ||||
| 	github.com/goreleaser/nfpm/v2 v2.41.0 | ||||
| 	github.com/hashicorp/go-hclog v0.14.1 | ||||
| @@ -38,7 +39,6 @@ require ( | ||||
| 	golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 | ||||
| 	golang.org/x/sys v0.31.0 | ||||
| 	golang.org/x/text v0.23.0 | ||||
| 	gopkg.in/yaml.v3 v3.0.1 | ||||
| 	modernc.org/sqlite v1.25.0 | ||||
| 	mvdan.cc/sh/v3 v3.10.0 | ||||
| 	xorm.io/xorm v1.3.9 | ||||
| @@ -139,6 +139,7 @@ require ( | ||||
| 	google.golang.org/grpc v1.58.3 // indirect | ||||
| 	google.golang.org/protobuf v1.36.1 // indirect | ||||
| 	gopkg.in/warnings.v0 v0.1.2 // indirect | ||||
| 	gopkg.in/yaml.v3 v3.0.1 // indirect | ||||
| 	lukechampine.com/uint128 v1.2.0 // indirect | ||||
| 	modernc.org/cc/v3 v3.40.0 // indirect | ||||
| 	modernc.org/ccgo/v3 v3.16.13 // indirect | ||||
|   | ||||
							
								
								
									
										2
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.sum
									
									
									
									
									
								
							| @@ -164,6 +164,8 @@ github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= | ||||
| github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= | ||||
| github.com/goccy/go-json v0.8.1 h1:4/Wjm0JIJaTDm8K1KcGrLHJoa8EsJ13YWeX+6Kfq6uI= | ||||
| github.com/goccy/go-json v0.8.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= | ||||
| github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= | ||||
| github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= | ||||
| github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= | ||||
| github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= | ||||
| github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= | ||||
|   | ||||
							
								
								
									
										44
									
								
								info.go
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								info.go
									
									
									
									
									
								
							| @@ -23,10 +23,10 @@ import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
|  | ||||
| 	"github.com/goccy/go-yaml" | ||||
| 	"github.com/jeandeaual/go-locale" | ||||
| 	"github.com/leonelquinteros/gotext" | ||||
| 	"github.com/urfave/cli/v2" | ||||
| 	"gopkg.in/yaml.v3" | ||||
|  | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils" | ||||
| 	appbuilder "gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils/app_builder" | ||||
| @@ -121,35 +121,27 @@ func InfoCmd() *cli.Command { | ||||
| 				systemLang = "en" | ||||
| 			} | ||||
|  | ||||
| 			if !all { | ||||
| 				info, err := distro.ParseOSRelease(ctx) | ||||
| 				if err != nil { | ||||
| 					return cliutils.FormatCliExit(gotext.Get("Error parsing os-release file"), err) | ||||
| 				} | ||||
| 				names, err = overrides.Resolve( | ||||
| 					info, | ||||
| 					overrides.DefaultOpts. | ||||
| 						WithLanguages([]string{systemLang}), | ||||
| 				) | ||||
| 				if err != nil { | ||||
| 					return cliutils.FormatCliExit(gotext.Get("Error resolving overrides"), err) | ||||
| 				} | ||||
| 			info, err := distro.ParseOSRelease(ctx) | ||||
| 			if err != nil { | ||||
| 				return cliutils.FormatCliExit(gotext.Get("Error parsing os-release file"), err) | ||||
| 			} | ||||
| 			names, err = overrides.Resolve( | ||||
| 				info, | ||||
| 				overrides.DefaultOpts. | ||||
| 					WithLanguages([]string{systemLang}), | ||||
| 			) | ||||
| 			if err != nil { | ||||
| 				return cliutils.FormatCliExit(gotext.Get("Error resolving overrides"), err) | ||||
| 			} | ||||
|  | ||||
| 			for _, pkg := range pkgs { | ||||
| 				if !all { | ||||
| 					alrsh.ResolvePackage(&pkg, names) | ||||
| 					err = yaml.NewEncoder(os.Stdout).Encode(pkg) | ||||
| 					if err != nil { | ||||
| 						return cliutils.FormatCliExit(gotext.Get("Error encoding script variables"), err) | ||||
| 					} | ||||
| 				} else { | ||||
| 					err = yaml.NewEncoder(os.Stdout).Encode(pkg) | ||||
| 					if err != nil { | ||||
| 						return cliutils.FormatCliExit(gotext.Get("Error encoding script variables"), err) | ||||
| 					} | ||||
| 				alrsh.ResolvePackage(&pkg, names) | ||||
| 				view := alrsh.NewPackageView(pkg) | ||||
| 				view.Resolved = !all | ||||
| 				err = yaml.NewEncoder(os.Stdout, yaml.UseJSONMarshaler(), yaml.OmitEmpty()).Encode(view) | ||||
| 				if err != nil { | ||||
| 					return cliutils.FormatCliExit(gotext.Get("Error encoding script variables"), err) | ||||
| 				} | ||||
|  | ||||
| 				fmt.Println("---") | ||||
| 			} | ||||
|  | ||||
|   | ||||
| @@ -367,7 +367,7 @@ func (b *Builder) BuildPackage( | ||||
| 	} | ||||
|  | ||||
| 	slog.Debug("ViewScript") | ||||
| 	slog.Debug("", "varsOfPackages", varsOfPackages) | ||||
| 	slog.Debug("", "varsOfPackages", varsOfPackages[0]) | ||||
| 	err = b.scriptViewerExecutor.ViewScript(ctx, input, sf, basePkg) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
|   | ||||
| @@ -23,7 +23,6 @@ import ( | ||||
| 	"context" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"log/slog" | ||||
| 	"reflect" | ||||
| 	"strings" | ||||
|  | ||||
| @@ -75,75 +74,99 @@ func New(info *distro.OSRelease, runner *interp.Runner) *Decoder { | ||||
| // DecodeVar decodes a variable to val using reflection. | ||||
| // Structs should use the "sh" struct tag. | ||||
| func (d *Decoder) DecodeVar(name string, val any) error { | ||||
| 	variable := d.getVar(name) | ||||
| 	if variable == nil { | ||||
| 		return VarNotFoundError{name} | ||||
| 	} | ||||
| 	origType := reflect.TypeOf(val).Elem() | ||||
| 	isOverridableField := strings.Contains(origType.String(), "OverridableField[") | ||||
|  | ||||
| 	dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ | ||||
| 		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() | ||||
| 				} | ||||
| 	if !isOverridableField { | ||||
| 		variable := d.getVarNoOverrides(name) | ||||
| 		if variable == nil { | ||||
| 			return VarNotFoundError{name} | ||||
| 		} | ||||
|  | ||||
| 				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 | ||||
| 		dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ | ||||
| 			WeaklyTypedInput: true, | ||||
| 			Result:           val, // передаем указатель на новое значение | ||||
| 			TagName:          "sh", | ||||
| 			DecodeHook: mapstructure.DecodeHookFuncValue(func(from, to reflect.Value) (interface{}, error) { | ||||
| 				if from.Kind() == reflect.Slice && to.Kind() == reflect.String { | ||||
| 					s, ok := from.Interface().([]string) | ||||
| 					if ok && len(s) == 1 { | ||||
| 						return s[0], nil | ||||
| 					} | ||||
|  | ||||
| 					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 from.Interface(), nil | ||||
| 			}), | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 				return to, nil | ||||
| 		switch variable.Kind { | ||||
| 		case expand.Indexed: | ||||
| 			return dec.Decode(variable.List) | ||||
| 		case expand.Associative: | ||||
| 			return dec.Decode(variable.Map) | ||||
| 		default: | ||||
| 			return dec.Decode(variable.Str) | ||||
| 		} | ||||
| 	} else { | ||||
| 		vars := d.getVarsByPrefix(name) | ||||
|  | ||||
| 		if len(vars) == 0 { | ||||
| 			return VarNotFoundError{name} | ||||
| 		} | ||||
|  | ||||
| 		reflectVal := reflect.ValueOf(val) | ||||
| 		overridableVal := reflect.ValueOf(val).Elem() | ||||
|  | ||||
| 		dataField := overridableVal.FieldByName("data") | ||||
| 		if !dataField.IsValid() { | ||||
| 			return fmt.Errorf("data field not found in OverridableField") | ||||
| 		} | ||||
| 		mapType := dataField.Type() // map[string]T | ||||
| 		elemType := mapType.Elem()  // T | ||||
|  | ||||
| 		var overridablePtr reflect.Value | ||||
| 		if reflectVal.Kind() == reflect.Ptr { | ||||
| 			overridablePtr = reflectVal | ||||
| 		} else { | ||||
| 			if !reflectVal.CanAddr() { | ||||
| 				return fmt.Errorf("OverridableField value is not addressable") | ||||
| 			} | ||||
| 			return from.Interface(), nil | ||||
| 		}), | ||||
| 		Result:  val, | ||||
| 		TagName: "sh", | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		slog.Warn("err", "err", err) | ||||
| 		return err | ||||
| 	} | ||||
| 			overridablePtr = reflectVal.Addr() | ||||
| 		} | ||||
|  | ||||
| 	switch variable.Kind { | ||||
| 	case expand.Indexed: | ||||
| 		return dec.Decode(variable.List) | ||||
| 	case expand.Associative: | ||||
| 		return dec.Decode(variable.Map) | ||||
| 	default: | ||||
| 		return dec.Decode(variable.Str) | ||||
| 		setValue := overridablePtr.MethodByName("Set") | ||||
| 		if !setValue.IsValid() { | ||||
| 			return fmt.Errorf("method Set not found on OverridableField") | ||||
| 		} | ||||
|  | ||||
| 		for _, v := range vars { | ||||
| 			varName := v.Name | ||||
|  | ||||
| 			key := strings.TrimPrefix(strings.TrimPrefix(varName, name), "_") | ||||
| 			newVal := reflect.New(elemType) | ||||
|  | ||||
| 			if err := d.DecodeVar(varName, newVal.Interface()); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| 			keyValue := reflect.ValueOf(key) | ||||
| 			setValue.Call([]reflect.Value{keyValue, newVal.Elem()}) | ||||
| 		} | ||||
|  | ||||
| 		resolveValue := overridablePtr.MethodByName("Resolve") | ||||
| 		if !resolveValue.IsValid() { | ||||
| 			return fmt.Errorf("method Resolve not found on OverridableField") | ||||
| 		} | ||||
|  | ||||
| 		names, err := overrides.Resolve(d.info, overrides.DefaultOpts) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		resolveValue.Call([]reflect.Value{reflect.ValueOf(names)}) | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -284,23 +307,6 @@ func (d *Decoder) getFunc(name string) *syntax.Stmt { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // getVar gets a variable based on its name, taking into account | ||||
| // override variables and nameref variables. | ||||
| func (d *Decoder) getVar(name string) *expand.Variable { | ||||
| 	names, err := overrides.Resolve(d.info, overrides.DefaultOpts.WithName(name)) | ||||
| 	if err != nil { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	for _, varName := range names { | ||||
| 		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 { | ||||
| @@ -318,6 +324,32 @@ func (d *Decoder) getVarNoOverrides(name string) *expand.Variable { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type vars struct { | ||||
| 	Name  string | ||||
| 	Value *expand.Variable | ||||
| } | ||||
|  | ||||
| func (d *Decoder) getVarsByPrefix(prefix string) []*vars { | ||||
| 	result := make([]*vars, 0) | ||||
| 	for name, val := range d.Runner.Vars { | ||||
| 		if !strings.HasPrefix(name, prefix) { | ||||
| 			continue | ||||
| 		} | ||||
| 		switch prefix { | ||||
| 		case "auto_req": | ||||
| 			if strings.HasPrefix(name, "auto_req_skiplist") { | ||||
| 				continue | ||||
| 			} | ||||
| 		case "auto_prov": | ||||
| 			if strings.HasPrefix(name, "auto_prov_skiplist") { | ||||
| 				continue | ||||
| 			} | ||||
| 		} | ||||
| 		result = append(result, &vars{name, &val}) | ||||
| 	} | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| func IsTruthy(value string) bool { | ||||
| 	value = strings.ToLower(strings.TrimSpace(value)) | ||||
| 	return value == "true" || value == "yes" || value == "1" | ||||
|   | ||||
| @@ -32,24 +32,25 @@ import ( | ||||
| 	"mvdan.cc/sh/v3/syntax" | ||||
|  | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/shutils/decoder" | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh" | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro" | ||||
| ) | ||||
|  | ||||
| type BuildVars struct { | ||||
| 	Name          string   `sh:"name,required"` | ||||
| 	Version       string   `sh:"version,required"` | ||||
| 	Release       int      `sh:"release,required"` | ||||
| 	Epoch         uint     `sh:"epoch"` | ||||
| 	Description   string   `sh:"desc"` | ||||
| 	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"` | ||||
| 	Replaces      []string `sh:"replaces"` | ||||
| 	Name          string                           `sh:"name,required"` | ||||
| 	Version       string                           `sh:"version,required"` | ||||
| 	Release       int                              `sh:"release,required"` | ||||
| 	Epoch         uint                             `sh:"epoch"` | ||||
| 	Description   alrsh.OverridableField[string]   `sh:"desc"` | ||||
| 	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  alrsh.OverridableField[[]string] `sh:"build_deps"` | ||||
| 	Replaces      alrsh.OverridableField[[]string] `sh:"replaces"` | ||||
| } | ||||
|  | ||||
| const testScript = ` | ||||
| @@ -113,22 +114,34 @@ func TestDecodeVars(t *testing.T) { | ||||
| 	} | ||||
|  | ||||
| 	expected := BuildVars{ | ||||
| 		Name:          "test", | ||||
| 		Version:       "0.0.1", | ||||
| 		Release:       1, | ||||
| 		Epoch:         2, | ||||
| 		Description:   "Test package", | ||||
| 		Name:    "test", | ||||
| 		Version: "0.0.1", | ||||
| 		Release: 1, | ||||
| 		Epoch:   2, | ||||
| 		Description: alrsh.OverridableFromMap(map[string]string{ | ||||
| 			"": "Test package", | ||||
| 		}), | ||||
| 		Homepage:      "https://gitea.plemya-x.ru/xpamych/ALR", | ||||
| 		Maintainer:    "Евгений Храмов <xpamych@yandex.ru>", | ||||
| 		Architectures: []string{"arm64", "amd64"}, | ||||
| 		Licenses:      []string{"GPL-3.0-or-later"}, | ||||
| 		Provides:      []string{"test"}, | ||||
| 		Conflicts:     []string{"test"}, | ||||
| 		Replaces:      []string{"test-legacy"}, | ||||
| 		Depends:       []string{"sudo"}, | ||||
| 		BuildDepends:  []string{"go"}, | ||||
| 		Replaces: alrsh.OverridableFromMap(map[string][]string{ | ||||
| 			"":        {"test-old"}, | ||||
| 			"test_os": {"test-legacy"}, | ||||
| 		}), | ||||
| 		Depends: []string{"sudo"}, | ||||
| 		BuildDepends: alrsh.OverridableFromMap(map[string][]string{ | ||||
| 			"":     {"golang"}, | ||||
| 			"arch": {"go"}, | ||||
| 		}), | ||||
| 	} | ||||
|  | ||||
| 	expected.Description.SetResolved("Test package") | ||||
| 	expected.Replaces.SetResolved([]string{"test-legacy"}) | ||||
| 	expected.BuildDepends.SetResolved([]string{"go"}) | ||||
|  | ||||
| 	if !reflect.DeepEqual(bv, expected) { | ||||
| 		t.Errorf("Expected %v, got %v", expected, bv) | ||||
| 	} | ||||
|   | ||||
| @@ -138,11 +138,11 @@ msgstr "" | ||||
| msgid "Can't detect system language" | ||||
| msgstr "" | ||||
|  | ||||
| #: info.go:135 | ||||
| #: info.go:134 | ||||
| msgid "Error resolving overrides" | ||||
| msgstr "" | ||||
|  | ||||
| #: info.go:144 info.go:149 | ||||
| #: info.go:143 | ||||
| msgid "Error encoding script variables" | ||||
| msgstr "" | ||||
|  | ||||
|   | ||||
| @@ -145,11 +145,11 @@ msgstr "Ошибка при поиске пакетов" | ||||
| msgid "Can't detect system language" | ||||
| msgstr "Ошибка при определении языка системы" | ||||
|  | ||||
| #: info.go:135 | ||||
| #: info.go:134 | ||||
| msgid "Error resolving overrides" | ||||
| msgstr "Ошибка устранения переорпеделений" | ||||
|  | ||||
| #: info.go:144 info.go:149 | ||||
| #: info.go:143 | ||||
| msgid "Error encoding script variables" | ||||
| msgstr "Ошибка кодирования переменных скрита" | ||||
|  | ||||
|   | ||||
| @@ -68,10 +68,12 @@ func (o *OverridableField[T]) Resolve(overrides []string) { | ||||
| 	for _, override := range overrides { | ||||
| 		if v, ok := o.Has(override); ok { | ||||
| 			o.SetResolved(v) | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Database serialization (JSON) | ||||
| func (f *OverridableField[T]) ToDB() ([]byte, error) { | ||||
| 	var data map[string]T | ||||
|  | ||||
| @@ -103,6 +105,7 @@ func (f *OverridableField[T]) FromDB(data []byte) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Gob serialization | ||||
| type overridableFieldGobPayload[T any] struct { | ||||
| 	Data     map[string]T | ||||
| 	Resolved T | ||||
| @@ -136,6 +139,48 @@ func (f *OverridableField[T]) GobDecode(data []byte) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type overridableFieldJSONPayload[T any] struct { | ||||
| 	Resolved *T           `json:"resolved,omitempty,omitzero"` | ||||
| 	Data     map[string]T `json:"overrides,omitempty,omitzero"` | ||||
| } | ||||
|  | ||||
| func (f OverridableField[T]) MarshalJSON() ([]byte, error) { | ||||
| 	data := make(map[string]T) | ||||
|  | ||||
| 	for k, v := range f.data { | ||||
| 		if k == "" { | ||||
| 			data["default"] = v | ||||
| 		} else { | ||||
| 			data[k] = v | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	payload := overridableFieldJSONPayload[T]{ | ||||
| 		Data:     data, | ||||
| 		Resolved: &f.resolved, | ||||
| 	} | ||||
|  | ||||
| 	return json.Marshal(payload) | ||||
| } | ||||
|  | ||||
| func (f *OverridableField[T]) UnmarshalJSON(data []byte) error { | ||||
| 	var payload overridableFieldJSONPayload[T] | ||||
| 	if err := json.Unmarshal(data, &payload); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if payload.Data == nil { | ||||
| 		payload.Data = make(map[string]T) | ||||
| 	} | ||||
|  | ||||
| 	f.data = payload.Data | ||||
| 	if payload.Resolved != nil { | ||||
| 		f.resolved = *payload.Resolved | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func OverridableFromMap[T any](data map[string]T) OverridableField[T] { | ||||
| 	if data == nil { | ||||
| 		data = make(map[string]T) | ||||
|   | ||||
| @@ -14,9 +14,12 @@ | ||||
| // You should have received a copy of the GNU General Public License | ||||
| // along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  | ||||
| //go:generate go run ../../generators/alrsh-package | ||||
|  | ||||
| package alrsh | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
| 	"strings" | ||||
| @@ -39,38 +42,38 @@ func ParseNames(dec *decoder.Decoder) (*PackageNames, error) { | ||||
| } | ||||
|  | ||||
| type Package struct { | ||||
| 	Repository  string `xorm:"pk 'repository'"` | ||||
| 	Name        string `xorm:"pk 'name'"` | ||||
| 	BasePkgName string `xorm:"notnull 'basepkg_name'"` | ||||
| 	Repository  string `xorm:"pk 'repository'" json:"repository"` | ||||
| 	Name        string `xorm:"pk 'name'" json:"name"` | ||||
| 	BasePkgName string `xorm:"notnull 'basepkg_name'" json:"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'"` | ||||
| 	Version       string   `sh:"version" xorm:"notnull 'version'" json:"version"` | ||||
| 	Release       int      `sh:"release" xorm:"notnull 'release'" json:"release"` | ||||
| 	Epoch         uint     `sh:"epoch" xorm:"'epoch'" json:"epoch"` | ||||
| 	Architectures []string `sh:"architectures" xorm:"json 'architectures'" json:"architectures"` | ||||
| 	Licenses      []string `sh:"license" xorm:"json 'licenses'" json:"license"` | ||||
| 	Provides      []string `sh:"provides" xorm:"json 'provides'" json:"provides"` | ||||
| 	Conflicts     []string `sh:"conflicts" xorm:"json 'conflicts'" json:"conflicts"` | ||||
| 	Replaces      []string `sh:"replaces" xorm:"json 'replaces'" 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:"-"` | ||||
| 	Summary          OverridableField[string]   `sh:"summary" xorm:"'summary'" json:"summary"` | ||||
| 	Description      OverridableField[string]   `sh:"desc" xorm:"'description'" json:"description"` | ||||
| 	Group            OverridableField[string]   `sh:"group" xorm:"'group_name'" json:"group"` | ||||
| 	Homepage         OverridableField[string]   `sh:"homepage" xorm:"'homepage'" json:"homepage"` | ||||
| 	Maintainer       OverridableField[string]   `sh:"maintainer" xorm:"'maintainer'" json:"maintainer"` | ||||
| 	Depends          OverridableField[[]string] `sh:"deps" xorm:"'depends'" json:"deps"` | ||||
| 	BuildDepends     OverridableField[[]string] `sh:"build_deps" xorm:"'builddepends'" json:"build_deps"` | ||||
| 	OptDepends       OverridableField[[]string] `sh:"opt_deps" xorm:"'optdepends'" json:"opt_deps,omitempty"` | ||||
| 	Sources          OverridableField[[]string] `sh:"sources" xorm:"-" json:"sources"` | ||||
| 	Checksums        OverridableField[[]string] `sh:"checksums" xorm:"-" json:"checksums,omitempty"` | ||||
| 	Backup           OverridableField[[]string] `sh:"backup" xorm:"-" json:"backup"` | ||||
| 	Scripts          OverridableField[Scripts]  `sh:"scripts" xorm:"-" json:"scripts,omitempty"` | ||||
| 	AutoReq          OverridableField[[]string] `sh:"auto_req" xorm:"-" json:"auto_req"` | ||||
| 	AutoProv         OverridableField[[]string] `sh:"auto_prov" xorm:"-" json:"auto_prov"` | ||||
| 	AutoReqSkipList  OverridableField[[]string] `sh:"auto_req_skiplist" xorm:"-" json:"auto_req_skiplist,omitempty"` | ||||
| 	AutoProvSkipList OverridableField[[]string] `sh:"auto_prov_skiplist" xorm:"-" json:"auto_prov_skiplist,omitempty"` | ||||
|  | ||||
| 	FireJailed       OverridableField[bool]              `sh:"firejailed" xorm:"-"` | ||||
| 	FireJailProfiles OverridableField[map[string]string] `sh:"firejail_profiles" xorm:"-"` | ||||
| 	FireJailed       OverridableField[bool]              `sh:"firejailed" xorm:"-" json:"firejailed"` | ||||
| 	FireJailProfiles OverridableField[map[string]string] `sh:"firejail_profiles" xorm:"-" json:"firejail_profiles,omitempty"` | ||||
| } | ||||
|  | ||||
| type Scripts struct { | ||||
| @@ -84,25 +87,70 @@ type Scripts struct { | ||||
| 	PostTrans   string `sh:"posttrans"` | ||||
| } | ||||
|  | ||||
| func ResolvePackage(p *Package, overrides []string) { | ||||
| 	val := reflect.ValueOf(p).Elem() | ||||
| 	typ := val.Type() | ||||
| func (p Package) MarshalJSONWithOptions(includeOverrides bool) ([]byte, error) { | ||||
| 	// Сначала сериализуем обычным способом для получения базовой структуры | ||||
| 	type PackageAlias Package | ||||
| 	baseData, err := json.Marshal(PackageAlias(p)) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	for i := range val.NumField() { | ||||
| 		field := val.Field(i) | ||||
| 		fieldType := typ.Field(i) | ||||
| 	// Десериализуем в map для модификации | ||||
| 	var result map[string]json.RawMessage | ||||
| 	if err := json.Unmarshal(baseData, &result); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 		if !field.CanInterface() { | ||||
| 	// Теперь заменяем OverridableField поля | ||||
| 	v := reflect.ValueOf(p) | ||||
| 	t := reflect.TypeOf(p) | ||||
|  | ||||
| 	for i := 0; i < v.NumField(); i++ { | ||||
| 		field := v.Field(i) | ||||
| 		fieldType := t.Field(i) | ||||
|  | ||||
| 		jsonTag := fieldType.Tag.Get("json") | ||||
| 		if jsonTag == "" || jsonTag == "-" { | ||||
| 			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) | ||||
| 		fieldName := jsonTag | ||||
| 		if commaIdx := strings.Index(jsonTag, ","); commaIdx != -1 { | ||||
| 			fieldName = jsonTag[:commaIdx] | ||||
| 		} | ||||
|  | ||||
| 		if field.Type().Name() == "OverridableField" || | ||||
| 			(field.Type().Kind() == reflect.Struct && | ||||
| 				strings.Contains(field.Type().String(), "OverridableField")) { | ||||
|  | ||||
| 			fieldPtr := field.Addr() | ||||
|  | ||||
| 			resolvedMethod := fieldPtr.MethodByName("Resolved") | ||||
| 			if resolvedMethod.IsValid() { | ||||
| 				resolved := resolvedMethod.Call(nil)[0] | ||||
|  | ||||
| 				fieldData := map[string]interface{}{ | ||||
| 					"resolved": resolved.Interface(), | ||||
| 				} | ||||
|  | ||||
| 				if includeOverrides { | ||||
| 					allMethod := field.MethodByName("All") | ||||
| 					if allMethod.IsValid() { | ||||
| 						overrides := allMethod.Call(nil)[0] | ||||
| 						if !overrides.IsNil() && overrides.Len() > 0 { | ||||
| 							fieldData["overrides"] = overrides.Interface() | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				fieldJSON, err := json.Marshal(fieldData) | ||||
| 				if err != nil { | ||||
| 					return nil, err | ||||
| 				} | ||||
| 				result[fieldName] = json.RawMessage(fieldJSON) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return json.Marshal(result) | ||||
| } | ||||
|   | ||||
							
								
								
									
										105
									
								
								pkg/alrsh/package_gen.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								pkg/alrsh/package_gen.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/>. | ||||
|  | ||||
| // DO NOT EDIT MANUALLY. This file is generated. | ||||
| package alrsh | ||||
|  | ||||
| type packageResolved struct { | ||||
| 	Repository       string            `json:"repository"` | ||||
| 	Name             string            `json:"name"` | ||||
| 	BasePkgName      string            `json:"basepkg_name"` | ||||
| 	Version          string            `json:"version"` | ||||
| 	Release          int               `json:"release"` | ||||
| 	Epoch            uint              `json:"epoch"` | ||||
| 	Architectures    []string          `json:"architectures"` | ||||
| 	Licenses         []string          `json:"license"` | ||||
| 	Provides         []string          `json:"provides"` | ||||
| 	Conflicts        []string          `json:"conflicts"` | ||||
| 	Replaces         []string          `json:"replaces"` | ||||
| 	Summary          string            `json:"summary"` | ||||
| 	Description      string            `json:"description"` | ||||
| 	Group            string            `json:"group"` | ||||
| 	Homepage         string            `json:"homepage"` | ||||
| 	Maintainer       string            `json:"maintainer"` | ||||
| 	Depends          []string          `json:"deps"` | ||||
| 	BuildDepends     []string          `json:"build_deps"` | ||||
| 	OptDepends       []string          `json:"opt_deps,omitempty"` | ||||
| 	Sources          []string          `json:"sources"` | ||||
| 	Checksums        []string          `json:"checksums,omitempty"` | ||||
| 	Backup           []string          `json:"backup"` | ||||
| 	Scripts          Scripts           `json:"scripts,omitempty"` | ||||
| 	AutoReq          []string          `json:"auto_req"` | ||||
| 	AutoProv         []string          `json:"auto_prov"` | ||||
| 	AutoReqSkipList  []string          `json:"auto_req_skiplist,omitempty"` | ||||
| 	AutoProvSkipList []string          `json:"auto_prov_skiplist,omitempty"` | ||||
| 	FireJailed       bool              `json:"firejailed"` | ||||
| 	FireJailProfiles map[string]string `json:"firejail_profiles,omitempty"` | ||||
| } | ||||
|  | ||||
| func PackageToResolved(src *Package) packageResolved { | ||||
| 	return packageResolved{ | ||||
| 		Repository:       src.Repository, | ||||
| 		Name:             src.Name, | ||||
| 		BasePkgName:      src.BasePkgName, | ||||
| 		Version:          src.Version, | ||||
| 		Release:          src.Release, | ||||
| 		Epoch:            src.Epoch, | ||||
| 		Architectures:    src.Architectures, | ||||
| 		Licenses:         src.Licenses, | ||||
| 		Provides:         src.Provides, | ||||
| 		Conflicts:        src.Conflicts, | ||||
| 		Replaces:         src.Replaces, | ||||
| 		Summary:          src.Summary.Resolved(), | ||||
| 		Description:      src.Description.Resolved(), | ||||
| 		Group:            src.Group.Resolved(), | ||||
| 		Homepage:         src.Homepage.Resolved(), | ||||
| 		Maintainer:       src.Maintainer.Resolved(), | ||||
| 		Depends:          src.Depends.Resolved(), | ||||
| 		BuildDepends:     src.BuildDepends.Resolved(), | ||||
| 		OptDepends:       src.OptDepends.Resolved(), | ||||
| 		Sources:          src.Sources.Resolved(), | ||||
| 		Checksums:        src.Checksums.Resolved(), | ||||
| 		Backup:           src.Backup.Resolved(), | ||||
| 		Scripts:          src.Scripts.Resolved(), | ||||
| 		AutoReq:          src.AutoReq.Resolved(), | ||||
| 		AutoProv:         src.AutoProv.Resolved(), | ||||
| 		AutoReqSkipList:  src.AutoReqSkipList.Resolved(), | ||||
| 		AutoProvSkipList: src.AutoProvSkipList.Resolved(), | ||||
| 		FireJailed:       src.FireJailed.Resolved(), | ||||
| 		FireJailProfiles: src.FireJailProfiles.Resolved(), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func ResolvePackage(pkg *Package, overrides []string) { | ||||
| 	pkg.Summary.Resolve(overrides) | ||||
| 	pkg.Description.Resolve(overrides) | ||||
| 	pkg.Group.Resolve(overrides) | ||||
| 	pkg.Homepage.Resolve(overrides) | ||||
| 	pkg.Maintainer.Resolve(overrides) | ||||
| 	pkg.Depends.Resolve(overrides) | ||||
| 	pkg.BuildDepends.Resolve(overrides) | ||||
| 	pkg.OptDepends.Resolve(overrides) | ||||
| 	pkg.Sources.Resolve(overrides) | ||||
| 	pkg.Checksums.Resolve(overrides) | ||||
| 	pkg.Backup.Resolve(overrides) | ||||
| 	pkg.Scripts.Resolve(overrides) | ||||
| 	pkg.AutoReq.Resolve(overrides) | ||||
| 	pkg.AutoProv.Resolve(overrides) | ||||
| 	pkg.AutoReqSkipList.Resolve(overrides) | ||||
| 	pkg.AutoProvSkipList.Resolve(overrides) | ||||
| 	pkg.FireJailed.Resolve(overrides) | ||||
| 	pkg.FireJailProfiles.Resolve(overrides) | ||||
| } | ||||
							
								
								
									
										37
									
								
								pkg/alrsh/view.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								pkg/alrsh/view.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| // 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 "encoding/json" | ||||
|  | ||||
| type PackageView struct { | ||||
| 	pkg Package | ||||
|  | ||||
| 	Resolved bool | ||||
| } | ||||
|  | ||||
| func NewPackageView(v Package) PackageView { | ||||
| 	return PackageView{pkg: v} | ||||
| } | ||||
|  | ||||
| func (p PackageView) MarshalJSON() ([]byte, error) { | ||||
| 	if p.Resolved { | ||||
| 		return json.Marshal(PackageToResolved(&p.pkg)) | ||||
| 	} else { | ||||
| 		return json.Marshal(p.pkg) | ||||
| 	} | ||||
| } | ||||
		Reference in New Issue
	
	Block a user