refactor: move pkg/ to internal/ and update imports
	
		
			
	
		
	
	
				
					
				
			Restructure project by relocating package contents from pkg/ to internal/ to better reflect internal-only usage. This commit is initial step to prepare project for public api
This commit is contained in:
		
							
								
								
									
										266
									
								
								internal/repos/utils.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										266
									
								
								internal/repos/utils.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,266 @@ | ||||
| // 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 repos | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"path/filepath" | ||||
| 	"reflect" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/go-git/go-git/v5" | ||||
| 	"github.com/go-git/go-git/v5/plumbing" | ||||
| 	"github.com/go-git/go-git/v5/plumbing/format/diff" | ||||
| 	"github.com/go-git/go-git/v5/plumbing/transport" | ||||
| 	"github.com/go-git/go-git/v5/plumbing/transport/client" | ||||
|  | ||||
| 	"mvdan.cc/sh/v3/interp" | ||||
| 	"mvdan.cc/sh/v3/syntax" | ||||
|  | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/db" | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/distro" | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/parser" | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/shutils/decoder" | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/types" | ||||
| ) | ||||
|  | ||||
| // isValid makes sure the path of the file being updated is valid. | ||||
| // It checks to make sure the file is not within a nested directory | ||||
| // and that it is called alr.sh. | ||||
| func isValid(from, to diff.File) bool { | ||||
| 	var path string | ||||
| 	if from != nil { | ||||
| 		path = from.Path() | ||||
| 	} | ||||
| 	if to != nil { | ||||
| 		path = to.Path() | ||||
| 	} | ||||
|  | ||||
| 	match, _ := filepath.Match("*/*.sh", path) | ||||
| 	return match | ||||
| } | ||||
|  | ||||
| func parseScript( | ||||
| 	ctx context.Context, | ||||
| 	repo types.Repo, | ||||
| 	syntaxParser *syntax.Parser, | ||||
| 	runner *interp.Runner, | ||||
| 	r io.ReadCloser, | ||||
| ) ([]*db.Package, error) { | ||||
| 	fl, err := syntaxParser.Parse(r, "alr.sh") | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	runner.Reset() | ||||
| 	err = runner.Run(ctx, fl) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	d := decoder.New(&distro.OSRelease{}, runner) | ||||
| 	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 | ||||
| 	} | ||||
|  | ||||
| 	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 db.JSON[[]string] `sh:"architectures"` | ||||
| 	Licenses      db.JSON[[]string] `sh:"license"` | ||||
| 	Provides      db.JSON[[]string] `sh:"provides"` | ||||
| 	Conflicts     db.JSON[[]string] `sh:"conflicts"` | ||||
| 	Replaces      db.JSON[[]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:        db.NewJSON(map[string]string{}), | ||||
| 		Summary:      db.NewJSON(map[string]string{}), | ||||
| 		Description:  db.NewJSON(map[string]string{}), | ||||
| 		Homepage:     db.NewJSON(map[string]string{}), | ||||
| 		Maintainer:   db.NewJSON(map[string]string{}), | ||||
| 		Depends:      db.NewJSON(map[string][]string{}), | ||||
| 		BuildDepends: db.NewJSON(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, "_") | ||||
|  | ||||
| 				field := pkgVal.FieldByName(field) | ||||
| 				varVal := field.FieldByName("Val") | ||||
| 				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) { | ||||
| 	remote, err := r.Remote(git.DefaultRemoteName) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	endpoint, err := transport.NewEndpoint(remote.Config().URLs[0]) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	gitClient, err := client.NewClient(endpoint) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	session, err := gitClient.NewUploadPackSession(endpoint, nil) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	info, err := session.AdvertisedReferences() | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	refs, err := info.AllReferences() | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	return refs["HEAD"].Target(), nil | ||||
| } | ||||
|  | ||||
| func resolveHash(r *git.Repository, ref string) (*plumbing.Hash, error) { | ||||
| 	var err error | ||||
|  | ||||
| 	if ref == "" { | ||||
| 		reference, err := getHeadReference(r) | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("failed to get head reference %w", err) | ||||
| 		} | ||||
| 		ref = reference.Short() | ||||
| 	} | ||||
|  | ||||
| 	hsh, err := r.ResolveRevision(git.DefaultRemoteName + "/" + plumbing.Revision(ref)) | ||||
| 	if err != nil { | ||||
| 		hsh, err = r.ResolveRevision(plumbing.Revision(ref)) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return hsh, nil | ||||
| } | ||||
		Reference in New Issue
	
	Block a user