forked from Plemya-x/ALR
		
	Merge pull request 'feat: add files() function' (#19) from Maks1mS/ALR:feat/files-function into master
Reviewed-on: Plemya-x/ALR#19
This commit is contained in:
		
							
								
								
									
										14
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								go.mod
									
									
									
									
									
								
							@@ -1,8 +1,8 @@
 | 
			
		||||
module gitea.plemya-x.ru/Plemya-x/ALR
 | 
			
		||||
 | 
			
		||||
go 1.21
 | 
			
		||||
go 1.22
 | 
			
		||||
 | 
			
		||||
toolchain go1.21.3
 | 
			
		||||
toolchain go1.23.5
 | 
			
		||||
 | 
			
		||||
require (
 | 
			
		||||
	github.com/AlecAivazis/survey/v2 v2.3.7
 | 
			
		||||
@@ -34,7 +34,7 @@ require (
 | 
			
		||||
	golang.org/x/text v0.21.0
 | 
			
		||||
	gopkg.in/yaml.v3 v3.0.1
 | 
			
		||||
	modernc.org/sqlite v1.25.0
 | 
			
		||||
	mvdan.cc/sh/v3 v3.7.0
 | 
			
		||||
	mvdan.cc/sh/v3 v3.10.0
 | 
			
		||||
	plemya-x.ru/fakeroot v0.0.0-20240601131003-c638a3543283
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -110,11 +110,11 @@ require (
 | 
			
		||||
	github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
 | 
			
		||||
	gitlab.com/digitalxero/go-conventional-commit v1.0.7 // indirect
 | 
			
		||||
	go4.org v0.0.0-20200411211856-f5505b9728dd // indirect
 | 
			
		||||
	golang.org/x/mod v0.17.0 // indirect
 | 
			
		||||
	golang.org/x/net v0.25.0 // indirect
 | 
			
		||||
	golang.org/x/mod v0.18.0 // indirect
 | 
			
		||||
	golang.org/x/net v0.26.0 // indirect
 | 
			
		||||
	golang.org/x/sync v0.10.0 // indirect
 | 
			
		||||
	golang.org/x/term v0.24.0 // indirect
 | 
			
		||||
	golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
 | 
			
		||||
	golang.org/x/term v0.25.0 // indirect
 | 
			
		||||
	golang.org/x/tools v0.22.0 // indirect
 | 
			
		||||
	gopkg.in/warnings.v0 v0.1.2 // indirect
 | 
			
		||||
	lukechampine.com/uint128 v1.2.0 // indirect
 | 
			
		||||
	modernc.org/cc/v3 v3.40.0 // indirect
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								go.sum
									
									
									
									
									
								
							@@ -97,6 +97,7 @@ github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t
 | 
			
		||||
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
 | 
			
		||||
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
 | 
			
		||||
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
 | 
			
		||||
github.com/creack/pty v1.1.23 h1:4M6+isWdcStXEf15G/RbrMPOQj1dZ7HPZCGwE4kOeP0=
 | 
			
		||||
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
 | 
			
		||||
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
 | 
			
		||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
			
		||||
@@ -404,6 +405,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91
 | 
			
		||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 | 
			
		||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
 | 
			
		||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
 | 
			
		||||
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
 | 
			
		||||
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
 | 
			
		||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 | 
			
		||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 | 
			
		||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 | 
			
		||||
@@ -426,6 +429,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 | 
			
		||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
 | 
			
		||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
 | 
			
		||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
 | 
			
		||||
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
 | 
			
		||||
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
 | 
			
		||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 | 
			
		||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 | 
			
		||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 | 
			
		||||
@@ -478,6 +483,8 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
 | 
			
		||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
 | 
			
		||||
golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
 | 
			
		||||
golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
 | 
			
		||||
golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
 | 
			
		||||
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
 | 
			
		||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
			
		||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
			
		||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
			
		||||
@@ -520,6 +527,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
 | 
			
		||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
 | 
			
		||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
 | 
			
		||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
 | 
			
		||||
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
 | 
			
		||||
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
 | 
			
		||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 | 
			
		||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 | 
			
		||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 | 
			
		||||
@@ -605,6 +614,8 @@ modernc.org/z v1.7.3 h1:zDJf6iHjrnB+WRD88stbXokugjyc0/pB91ri1gO6LZY=
 | 
			
		||||
modernc.org/z v1.7.3/go.mod h1:Ipv4tsdxZRbQyLq9Q1M6gdbkxYzdlrciF2Hi/lS7nWE=
 | 
			
		||||
mvdan.cc/sh/v3 v3.7.0 h1:lSTjdP/1xsddtaKfGg7Myu7DnlHItd3/M2tomOcNNBg=
 | 
			
		||||
mvdan.cc/sh/v3 v3.7.0/go.mod h1:K2gwkaesF/D7av7Kxl0HbF5kGOd2ArupNTX3X44+8l8=
 | 
			
		||||
mvdan.cc/sh/v3 v3.10.0 h1:v9z7N1DLZ7owyLM/SXZQkBSXcwr2IGMm2LY2pmhVXj4=
 | 
			
		||||
mvdan.cc/sh/v3 v3.10.0/go.mod h1:z/mSSVyLFGZzqb3ZIKojjyqIx/xbmz/UHdCSv9HmqXY=
 | 
			
		||||
plemya-x.ru/fakeroot v0.0.0-20240601131003-c638a3543283 h1:BXCLPeA8g2M6qYngicyxyB/2Bo4J54Q9Rb+8jMmE3ik=
 | 
			
		||||
plemya-x.ru/fakeroot v0.0.0-20240601131003-c638a3543283/go.mod h1:itzL9Jx52VXOhRaucFHuMpa3y7iwjnuLGdNvypoh/S4=
 | 
			
		||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
 | 
			
		||||
 
 | 
			
		||||
@@ -177,7 +177,35 @@ func (d *Decoder) GetFunc(name string) (ScriptFunc, bool) {
 | 
			
		||||
	return func(ctx context.Context, opts ...interp.RunnerOption) error {
 | 
			
		||||
		sub := d.Runner.Subshell()
 | 
			
		||||
		for _, opt := range opts {
 | 
			
		||||
			opt(sub)
 | 
			
		||||
			err := opt(sub)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return sub.Run(ctx, fn)
 | 
			
		||||
	}, true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type PrepareFunc func(context.Context, *interp.Runner) error
 | 
			
		||||
 | 
			
		||||
func (d *Decoder) GetFuncP(name string, prepare PrepareFunc) (ScriptFunc, bool) {
 | 
			
		||||
	fn := d.getFunc(name)
 | 
			
		||||
	if fn == nil {
 | 
			
		||||
		return nil, false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return func(ctx context.Context, opts ...interp.RunnerOption) error {
 | 
			
		||||
		sub := d.Runner.Subshell()
 | 
			
		||||
		for _, opt := range opts {
 | 
			
		||||
			err := opt(sub)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if prepare != nil {
 | 
			
		||||
			if err := prepare(ctx, sub); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return sub.Run(ctx, fn)
 | 
			
		||||
	}, true
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,7 @@ import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
@@ -55,12 +56,17 @@ var Helpers = handlers.ExecFuncs{
 | 
			
		||||
	"install-completion":   installCompletionCmd,
 | 
			
		||||
	"install-library":      installLibraryCmd,
 | 
			
		||||
	"git-version":          gitVersionCmd,
 | 
			
		||||
 | 
			
		||||
	"files-find-lang": filesFindLangCmd,
 | 
			
		||||
	"files-find-doc":  filesFindDocCmd,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Restricted contains restricted read-only helper commands
 | 
			
		||||
// that don't modify any state
 | 
			
		||||
var Restricted = handlers.ExecFuncs{
 | 
			
		||||
	"git-version":     gitVersionCmd,
 | 
			
		||||
	"files-find-lang": filesFindLangCmd,
 | 
			
		||||
	"files-find-doc":  filesFindDocCmd,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func installHelperCmd(prefix string, perms os.FileMode) handlers.ExecFunc {
 | 
			
		||||
@@ -256,6 +262,114 @@ func gitVersionCmd(hc interp.HandlerContext, cmd string, args []string) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func filesFindLangCmd(hc interp.HandlerContext, cmd string, args []string) error {
 | 
			
		||||
	namePattern := "*.mo"
 | 
			
		||||
	if len(args) > 0 {
 | 
			
		||||
		namePattern = args[0] + ".mo"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	localePath := "./usr/share/locale/"
 | 
			
		||||
	realPath := path.Join(hc.Dir, localePath)
 | 
			
		||||
 | 
			
		||||
	info, err := os.Stat(realPath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("files-find-lang: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	if !info.IsDir() {
 | 
			
		||||
		return fmt.Errorf("files-find-lang: %s is not a directory", localePath)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var langFiles []string
 | 
			
		||||
	err = filepath.Walk(realPath, func(p string, info os.FileInfo, err error) error {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if !info.IsDir() && matchNamePattern(info.Name(), namePattern) {
 | 
			
		||||
			relPath, relErr := filepath.Rel(hc.Dir, p)
 | 
			
		||||
			if relErr != nil {
 | 
			
		||||
				return relErr
 | 
			
		||||
			}
 | 
			
		||||
			langFiles = append(langFiles, "./"+relPath)
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("files-find-lang: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, file := range langFiles {
 | 
			
		||||
		fmt.Fprintln(hc.Stdout, file)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func filesFindDocCmd(hc interp.HandlerContext, cmd string, args []string) error {
 | 
			
		||||
	namePattern := "*"
 | 
			
		||||
	if len(args) > 0 {
 | 
			
		||||
		namePattern = args[0]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	docPath := "./usr/share/doc/"
 | 
			
		||||
	docRealPath := path.Join(hc.Dir, docPath)
 | 
			
		||||
 | 
			
		||||
	info, err := os.Stat(docRealPath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("files-find-doc: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	if !info.IsDir() {
 | 
			
		||||
		return fmt.Errorf("files-find-doc: %s is not a directory", docPath)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var docFiles []string
 | 
			
		||||
 | 
			
		||||
	entries, err := os.ReadDir(docRealPath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	for _, entry := range entries {
 | 
			
		||||
		if matchNamePattern(entry.Name(), namePattern) {
 | 
			
		||||
			targetPath := filepath.Join(docRealPath, entry.Name())
 | 
			
		||||
			targetInfo, err := os.Stat(targetPath)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			if targetInfo.IsDir() {
 | 
			
		||||
				err := filepath.Walk(targetPath, func(subPath string, subInfo os.FileInfo, subErr error) error {
 | 
			
		||||
					relPath, err := filepath.Rel(hc.Dir, subPath)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return err
 | 
			
		||||
					}
 | 
			
		||||
					docFiles = append(docFiles, "./"+relPath)
 | 
			
		||||
					return nil
 | 
			
		||||
				})
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("files-find-doc: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, file := range docFiles {
 | 
			
		||||
		fmt.Fprintln(hc.Stdout, file)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func matchNamePattern(name, pattern string) bool {
 | 
			
		||||
	matched, err := filepath.Match(pattern, name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return matched
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func helperInstall(from, to string, perms os.FileMode) error {
 | 
			
		||||
	err := os.MkdirAll(filepath.Dir(to), 0o755)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										216
									
								
								internal/shutils/helpers/helpers_internal_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								internal/shutils/helpers/helpers_internal_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,216 @@
 | 
			
		||||
// ALR - Any Linux Repository
 | 
			
		||||
// Copyright (C) 2025 Евгений Храмов
 | 
			
		||||
//
 | 
			
		||||
// 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 helpers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"context"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
	"mvdan.cc/sh/v3/interp"
 | 
			
		||||
	"mvdan.cc/sh/v3/syntax"
 | 
			
		||||
 | 
			
		||||
	"gitea.plemya-x.ru/Plemya-x/ALR/internal/shutils/handlers"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type testCase struct {
 | 
			
		||||
	name           string
 | 
			
		||||
	dirsToCreate   []string
 | 
			
		||||
	filesToCreate  []string
 | 
			
		||||
	expectedOutput []string
 | 
			
		||||
	args           string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestFindFilesDoc(t *testing.T) {
 | 
			
		||||
	tests := []testCase{
 | 
			
		||||
		{
 | 
			
		||||
			name: "All dirs",
 | 
			
		||||
			dirsToCreate: []string{
 | 
			
		||||
				"usr/share/doc/yandex-browser-stable/subdir",
 | 
			
		||||
				"usr/share/doc/firefox",
 | 
			
		||||
			},
 | 
			
		||||
			filesToCreate: []string{
 | 
			
		||||
				"usr/share/doc/yandex-browser-stable/README.md",
 | 
			
		||||
				"usr/share/doc/yandex-browser-stable/subdir/nested-file.txt",
 | 
			
		||||
				"usr/share/doc/firefox/README.md",
 | 
			
		||||
			},
 | 
			
		||||
			expectedOutput: []string{
 | 
			
		||||
				"./usr/share/doc/yandex-browser-stable",
 | 
			
		||||
				"./usr/share/doc/yandex-browser-stable/README.md",
 | 
			
		||||
				"./usr/share/doc/yandex-browser-stable/subdir",
 | 
			
		||||
				"./usr/share/doc/yandex-browser-stable/subdir/nested-file.txt",
 | 
			
		||||
				"./usr/share/doc/firefox",
 | 
			
		||||
				"./usr/share/doc/firefox/README.md",
 | 
			
		||||
			},
 | 
			
		||||
			args: "",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "Only selected dir",
 | 
			
		||||
			dirsToCreate: []string{
 | 
			
		||||
				"usr/share/doc/yandex-browser-stable/subdir",
 | 
			
		||||
				"usr/share/doc/firefox",
 | 
			
		||||
				"usr/share/doc/foo/yandex-browser-stable",
 | 
			
		||||
			},
 | 
			
		||||
			filesToCreate: []string{
 | 
			
		||||
				"usr/share/doc/yandex-browser-stable/README.md",
 | 
			
		||||
				"usr/share/doc/yandex-browser-stable/subdir/nested-file.txt",
 | 
			
		||||
				"usr/share/doc/firefox/README.md",
 | 
			
		||||
				"usr/share/doc/firefox/yandex-browser-stable",
 | 
			
		||||
				"usr/share/doc/foo/yandex-browser-stable/README.md",
 | 
			
		||||
			},
 | 
			
		||||
			expectedOutput: []string{
 | 
			
		||||
				"./usr/share/doc/yandex-browser-stable",
 | 
			
		||||
				"./usr/share/doc/yandex-browser-stable/README.md",
 | 
			
		||||
				"./usr/share/doc/yandex-browser-stable/subdir",
 | 
			
		||||
				"./usr/share/doc/yandex-browser-stable/subdir/nested-file.txt",
 | 
			
		||||
			},
 | 
			
		||||
			args: "yandex-browser-stable",
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, tc := range tests {
 | 
			
		||||
		t.Run(tc.name, func(t *testing.T) {
 | 
			
		||||
			tempDir, err := os.MkdirTemp("", "test-files-find-doc")
 | 
			
		||||
			assert.NoError(t, err)
 | 
			
		||||
			defer os.RemoveAll(tempDir)
 | 
			
		||||
 | 
			
		||||
			for _, dir := range tc.dirsToCreate {
 | 
			
		||||
				dirPath := filepath.Join(tempDir, dir)
 | 
			
		||||
				err := os.MkdirAll(dirPath, 0o755)
 | 
			
		||||
				assert.NoError(t, err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			for _, file := range tc.filesToCreate {
 | 
			
		||||
				filePath := filepath.Join(tempDir, file)
 | 
			
		||||
				err := os.WriteFile(filePath, []byte("test content"), 0o644)
 | 
			
		||||
				assert.NoError(t, err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			helpers := handlers.ExecFuncs{
 | 
			
		||||
				"files-find-doc": filesFindDocCmd,
 | 
			
		||||
			}
 | 
			
		||||
			buf := &bytes.Buffer{}
 | 
			
		||||
			runner, err := interp.New(
 | 
			
		||||
				interp.Dir(tempDir),
 | 
			
		||||
				interp.StdIO(os.Stdin, buf, os.Stderr),
 | 
			
		||||
				interp.ExecHandler(helpers.ExecHandler(interp.DefaultExecHandler(1000))),
 | 
			
		||||
			)
 | 
			
		||||
			assert.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
			scriptContent := `
 | 
			
		||||
shopt -s globstar
 | 
			
		||||
files-find-doc ` + tc.args
 | 
			
		||||
 | 
			
		||||
			script, err := syntax.NewParser().Parse(strings.NewReader(scriptContent), "")
 | 
			
		||||
			assert.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
			err = runner.Run(context.Background(), script)
 | 
			
		||||
			assert.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
			contents := strings.Fields(strings.TrimSpace(buf.String()))
 | 
			
		||||
			assert.ElementsMatch(t, tc.expectedOutput, contents)
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestFindLang(t *testing.T) {
 | 
			
		||||
	tests := []testCase{
 | 
			
		||||
		{
 | 
			
		||||
			name: "All dirs",
 | 
			
		||||
			dirsToCreate: []string{
 | 
			
		||||
				"usr/share/locale/ru/LC_MESSAGES",
 | 
			
		||||
				"usr/share/locale/tr/LC_MESSAGES",
 | 
			
		||||
			},
 | 
			
		||||
			filesToCreate: []string{
 | 
			
		||||
				"usr/share/locale/ru/LC_MESSAGES/yandex-disk.mo",
 | 
			
		||||
				"usr/share/locale/ru/LC_MESSAGES/yandex-disk-indicator.mo",
 | 
			
		||||
				"usr/share/locale/tr/LC_MESSAGES/yandex-disk.mo",
 | 
			
		||||
			},
 | 
			
		||||
			expectedOutput: []string{
 | 
			
		||||
				"./usr/share/locale/ru/LC_MESSAGES/yandex-disk.mo",
 | 
			
		||||
				"./usr/share/locale/ru/LC_MESSAGES/yandex-disk-indicator.mo",
 | 
			
		||||
				"./usr/share/locale/tr/LC_MESSAGES/yandex-disk.mo",
 | 
			
		||||
			},
 | 
			
		||||
			args: "",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "All dirs",
 | 
			
		||||
			dirsToCreate: []string{
 | 
			
		||||
				"usr/share/locale/ru/LC_MESSAGES",
 | 
			
		||||
				"usr/share/locale/tr/LC_MESSAGES",
 | 
			
		||||
			},
 | 
			
		||||
			filesToCreate: []string{
 | 
			
		||||
				"usr/share/locale/ru/LC_MESSAGES/yandex-disk.mo",
 | 
			
		||||
				"usr/share/locale/ru/LC_MESSAGES/yandex-disk-indicator.mo",
 | 
			
		||||
				"usr/share/locale/tr/LC_MESSAGES/yandex-disk.mo",
 | 
			
		||||
			},
 | 
			
		||||
			expectedOutput: []string{
 | 
			
		||||
				"./usr/share/locale/ru/LC_MESSAGES/yandex-disk.mo",
 | 
			
		||||
				"./usr/share/locale/tr/LC_MESSAGES/yandex-disk.mo",
 | 
			
		||||
			},
 | 
			
		||||
			args: "yandex-disk",
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, tc := range tests {
 | 
			
		||||
		t.Run(tc.name, func(t *testing.T) {
 | 
			
		||||
			tempDir, err := os.MkdirTemp("", "test-files-find-lang")
 | 
			
		||||
			assert.NoError(t, err)
 | 
			
		||||
			defer os.RemoveAll(tempDir)
 | 
			
		||||
 | 
			
		||||
			for _, dir := range tc.dirsToCreate {
 | 
			
		||||
				dirPath := filepath.Join(tempDir, dir)
 | 
			
		||||
				err := os.MkdirAll(dirPath, 0o755)
 | 
			
		||||
				assert.NoError(t, err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			for _, file := range tc.filesToCreate {
 | 
			
		||||
				filePath := filepath.Join(tempDir, file)
 | 
			
		||||
				err := os.WriteFile(filePath, []byte("test content"), 0o644)
 | 
			
		||||
				assert.NoError(t, err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			helpers := handlers.ExecFuncs{
 | 
			
		||||
				"files-find-lang": filesFindLangCmd,
 | 
			
		||||
			}
 | 
			
		||||
			buf := &bytes.Buffer{}
 | 
			
		||||
			runner, err := interp.New(
 | 
			
		||||
				interp.Dir(tempDir),
 | 
			
		||||
				interp.StdIO(os.Stdin, buf, os.Stderr),
 | 
			
		||||
				interp.ExecHandler(helpers.ExecHandler(interp.DefaultExecHandler(1000))),
 | 
			
		||||
			)
 | 
			
		||||
			assert.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
			scriptContent := `
 | 
			
		||||
shopt -s globstar
 | 
			
		||||
files-find-lang ` + tc.args
 | 
			
		||||
 | 
			
		||||
			script, err := syntax.NewParser().Parse(strings.NewReader(scriptContent), "")
 | 
			
		||||
			assert.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
			err = runner.Run(context.Background(), script)
 | 
			
		||||
			assert.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
			contents := strings.Fields(strings.TrimSpace(buf.String()))
 | 
			
		||||
			assert.ElementsMatch(t, tc.expectedOutput, contents)
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -251,7 +251,7 @@ msgstr ""
 | 
			
		||||
msgid "Downloading source"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: internal/logger/log.go:44
 | 
			
		||||
#: internal/logger/log.go:47
 | 
			
		||||
msgid "ERROR"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
@@ -323,35 +323,43 @@ msgstr ""
 | 
			
		||||
msgid "Installing dependencies"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: pkg/build/build.go:435
 | 
			
		||||
#: pkg/build/build.go:439
 | 
			
		||||
msgid "Executing version()"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: pkg/build/build.go:460
 | 
			
		||||
#: pkg/build/build.go:459
 | 
			
		||||
msgid "Updating version"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: pkg/build/build.go:464
 | 
			
		||||
msgid "Executing prepare()"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: pkg/build/build.go:470
 | 
			
		||||
#: pkg/build/build.go:474
 | 
			
		||||
msgid "Executing build()"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: pkg/build/build.go:482
 | 
			
		||||
#: pkg/build/build.go:486
 | 
			
		||||
msgid "Executing package()"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: pkg/build/build.go:557
 | 
			
		||||
#: pkg/build/build.go:524
 | 
			
		||||
msgid "Executing files()"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: pkg/build/build.go:601
 | 
			
		||||
msgid "AutoProv is not implemented for this package format, so it's skiped"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: pkg/build/build.go:568
 | 
			
		||||
#: pkg/build/build.go:612
 | 
			
		||||
msgid "AutoReq is not implemented for this package format, so it's skiped"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: pkg/build/build.go:653
 | 
			
		||||
#: pkg/build/build.go:719
 | 
			
		||||
msgid "Would you like to remove the build dependencies?"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: pkg/build/build.go:759
 | 
			
		||||
#: pkg/build/build.go:825
 | 
			
		||||
msgid "The checksums array must be the same length as sources"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
@@ -437,10 +445,14 @@ msgstr ""
 | 
			
		||||
msgid "Pull all repositories that have changed"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: upgrade.go:47
 | 
			
		||||
#: upgrade.go:46
 | 
			
		||||
msgid "Upgrade all installed packages"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: upgrade.go:83
 | 
			
		||||
#: upgrade.go:82
 | 
			
		||||
msgid "Error checking for updates"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: upgrade.go:93
 | 
			
		||||
msgid "There is nothing to do."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 
 | 
			
		||||
@@ -259,7 +259,7 @@ msgstr ""
 | 
			
		||||
msgid "Downloading source"
 | 
			
		||||
msgstr "Скачивание источника"
 | 
			
		||||
 | 
			
		||||
#: internal/logger/log.go:44
 | 
			
		||||
#: internal/logger/log.go:47
 | 
			
		||||
msgid "ERROR"
 | 
			
		||||
msgstr "ОШИБКА"
 | 
			
		||||
 | 
			
		||||
@@ -331,35 +331,43 @@ msgstr ""
 | 
			
		||||
msgid "Installing dependencies"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: pkg/build/build.go:435
 | 
			
		||||
#: pkg/build/build.go:439
 | 
			
		||||
msgid "Executing version()"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: pkg/build/build.go:460
 | 
			
		||||
#: pkg/build/build.go:459
 | 
			
		||||
msgid "Updating version"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: pkg/build/build.go:464
 | 
			
		||||
msgid "Executing prepare()"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: pkg/build/build.go:470
 | 
			
		||||
#: pkg/build/build.go:474
 | 
			
		||||
msgid "Executing build()"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: pkg/build/build.go:482
 | 
			
		||||
#: pkg/build/build.go:486
 | 
			
		||||
msgid "Executing package()"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: pkg/build/build.go:557
 | 
			
		||||
#: pkg/build/build.go:524
 | 
			
		||||
msgid "Executing files()"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: pkg/build/build.go:601
 | 
			
		||||
msgid "AutoProv is not implemented for this package format, so it's skiped"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: pkg/build/build.go:568
 | 
			
		||||
#: pkg/build/build.go:612
 | 
			
		||||
msgid "AutoReq is not implemented for this package format, so it's skiped"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: pkg/build/build.go:653
 | 
			
		||||
#: pkg/build/build.go:719
 | 
			
		||||
msgid "Would you like to remove the build dependencies?"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: pkg/build/build.go:759
 | 
			
		||||
#: pkg/build/build.go:825
 | 
			
		||||
msgid "The checksums array must be the same length as sources"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
@@ -446,10 +454,14 @@ msgstr ""
 | 
			
		||||
msgid "Pull all repositories that have changed"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: upgrade.go:47
 | 
			
		||||
#: upgrade.go:46
 | 
			
		||||
msgid "Upgrade all installed packages"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: upgrade.go:83
 | 
			
		||||
#: upgrade.go:82
 | 
			
		||||
msgid "Error checking for updates"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: upgrade.go:93
 | 
			
		||||
msgid "There is nothing to do."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 
 | 
			
		||||
@@ -156,7 +156,7 @@ func BuildPackage(ctx context.Context, opts types.BuildOpts) ([]string, []string
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = executeFunctions(ctx, dec, dirs, vars) // Выполняем специальные функции
 | 
			
		||||
	funcOut, err := executeFunctions(ctx, dec, dirs, vars) // Выполняем специальные функции
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -165,7 +165,7 @@ func BuildPackage(ctx context.Context, opts types.BuildOpts) ([]string, []string
 | 
			
		||||
 | 
			
		||||
	pkgFormat := getPkgFormat(opts.Manager) // Получаем формат пакета
 | 
			
		||||
 | 
			
		||||
	pkgInfo, err := buildPkgMetadata(ctx, vars, dirs, pkgFormat, info, append(repoDeps, builtNames...)) // Собираем метаданные пакета
 | 
			
		||||
	pkgInfo, err := buildPkgMetadata(ctx, vars, dirs, pkgFormat, info, append(repoDeps, builtNames...), funcOut.Contents) // Собираем метаданные пакета
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -428,40 +428,44 @@ func buildALRDeps(ctx context.Context, opts types.BuildOpts, vars *types.BuildVa
 | 
			
		||||
	return builtPaths, builtNames, repoDeps, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type FunctionsOutput struct {
 | 
			
		||||
	Contents *[]string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Функция executeFunctions выполняет специальные функции ALR, такие как version(), prepare() и т.д.
 | 
			
		||||
func executeFunctions(ctx context.Context, dec *decoder.Decoder, dirs types.Directories, vars *types.BuildVars) (err error) {
 | 
			
		||||
func executeFunctions(ctx context.Context, dec *decoder.Decoder, dirs types.Directories, vars *types.BuildVars) (*FunctionsOutput, error) {
 | 
			
		||||
	version, ok := dec.GetFunc("version")
 | 
			
		||||
	if ok {
 | 
			
		||||
		slog.Info(gotext.Get("Executing version()"))
 | 
			
		||||
 | 
			
		||||
		buf := &bytes.Buffer{}
 | 
			
		||||
 | 
			
		||||
		err = version(
 | 
			
		||||
		err := version(
 | 
			
		||||
			ctx,
 | 
			
		||||
			interp.Dir(dirs.SrcDir),
 | 
			
		||||
			interp.StdIO(os.Stdin, buf, os.Stderr),
 | 
			
		||||
		)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		newVer := strings.TrimSpace(buf.String())
 | 
			
		||||
		err = setVersion(ctx, dec.Runner, newVer)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		vars.Version = newVer
 | 
			
		||||
 | 
			
		||||
		slog.Info("Updating version", "new", newVer)
 | 
			
		||||
		slog.Info(gotext.Get("Updating version"), "new", newVer)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	prepare, ok := dec.GetFunc("prepare")
 | 
			
		||||
	if ok {
 | 
			
		||||
		slog.Info(gotext.Get("Executing prepare()"))
 | 
			
		||||
 | 
			
		||||
		err = prepare(ctx, interp.Dir(dirs.SrcDir))
 | 
			
		||||
		err := prepare(ctx, interp.Dir(dirs.SrcDir))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -469,9 +473,9 @@ func executeFunctions(ctx context.Context, dec *decoder.Decoder, dirs types.Dire
 | 
			
		||||
	if ok {
 | 
			
		||||
		slog.Info(gotext.Get("Executing build()"))
 | 
			
		||||
 | 
			
		||||
		err = build(ctx, interp.Dir(dirs.SrcDir))
 | 
			
		||||
		err := build(ctx, interp.Dir(dirs.SrcDir))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -480,9 +484,9 @@ func executeFunctions(ctx context.Context, dec *decoder.Decoder, dirs types.Dire
 | 
			
		||||
		packageFn, ok := dec.GetFunc("package")
 | 
			
		||||
		if ok {
 | 
			
		||||
			slog.Info(gotext.Get("Executing package()"))
 | 
			
		||||
			err = packageFn(ctx, interp.Dir(dirs.SrcDir))
 | 
			
		||||
			err := packageFn(ctx, interp.Dir(dirs.SrcDir))
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -502,11 +506,51 @@ func executeFunctions(ctx context.Context, dec *decoder.Decoder, dirs types.Dire
 | 
			
		||||
		break
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
	output := &FunctionsOutput{}
 | 
			
		||||
 | 
			
		||||
	files, ok := dec.GetFuncP("files", func(ctx context.Context, s *interp.Runner) error {
 | 
			
		||||
		// It should be done via interp.RunnerOption,
 | 
			
		||||
		// but due to the issues below, it cannot be done.
 | 
			
		||||
		// - https://github.com/mvdan/sh/issues/962
 | 
			
		||||
		// - https://github.com/mvdan/sh/issues/1125
 | 
			
		||||
		script, err := syntax.NewParser().Parse(strings.NewReader("cd $pkgdir && shopt -s globstar"), "")
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		return s.Run(ctx, script)
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	if ok {
 | 
			
		||||
		slog.Info(gotext.Get("Executing files()"))
 | 
			
		||||
 | 
			
		||||
		buf := &bytes.Buffer{}
 | 
			
		||||
 | 
			
		||||
		err := files(
 | 
			
		||||
			ctx,
 | 
			
		||||
			interp.Dir(dirs.PkgDir),
 | 
			
		||||
			interp.StdIO(os.Stdin, buf, os.Stderr),
 | 
			
		||||
		)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		contents := strings.Fields(strings.TrimSpace(buf.String()))
 | 
			
		||||
		output.Contents = &contents
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return output, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Функция buildPkgMetadata создает метаданные для пакета, который будет собран.
 | 
			
		||||
func buildPkgMetadata(ctx context.Context, vars *types.BuildVars, dirs types.Directories, pkgFormat string, info *distro.OSRelease, deps []string) (*nfpm.Info, error) {
 | 
			
		||||
func buildPkgMetadata(
 | 
			
		||||
	ctx context.Context,
 | 
			
		||||
	vars *types.BuildVars,
 | 
			
		||||
	dirs types.Directories,
 | 
			
		||||
	pkgFormat string,
 | 
			
		||||
	info *distro.OSRelease,
 | 
			
		||||
	deps []string,
 | 
			
		||||
	preferedContents *[]string,
 | 
			
		||||
) (*nfpm.Info, error) {
 | 
			
		||||
	pkgInfo := getBasePkgInfo(vars)
 | 
			
		||||
	pkgInfo.Description = vars.Description
 | 
			
		||||
	pkgInfo.Platform = "linux"
 | 
			
		||||
@@ -541,7 +585,7 @@ func buildPkgMetadata(ctx context.Context, vars *types.BuildVars, dirs types.Dir
 | 
			
		||||
		pkgInfo.Arch = "all"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	contents, err := buildContents(vars, dirs)
 | 
			
		||||
	contents, err := buildContents(vars, dirs, preferedContents)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -574,22 +618,28 @@ func buildPkgMetadata(ctx context.Context, vars *types.BuildVars, dirs types.Dir
 | 
			
		||||
 | 
			
		||||
// Функция buildContents создает секцию содержимого пакета, которая содержит файлы,
 | 
			
		||||
// которые будут включены в конечный пакет.
 | 
			
		||||
func buildContents(vars *types.BuildVars, dirs types.Directories) ([]*files.Content, error) {
 | 
			
		||||
func buildContents(vars *types.BuildVars, dirs types.Directories, preferedContents *[]string) ([]*files.Content, error) {
 | 
			
		||||
	contents := []*files.Content{}
 | 
			
		||||
	err := filepath.Walk(dirs.PkgDir, func(path string, fi os.FileInfo, err error) error {
 | 
			
		||||
		trimmed := strings.TrimPrefix(path, dirs.PkgDir)
 | 
			
		||||
 | 
			
		||||
	processPath := func(path, trimmed string, prefered bool) error {
 | 
			
		||||
		fi, err := os.Lstat(path)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if fi.IsDir() {
 | 
			
		||||
			f, err := os.Open(path)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			defer f.Close()
 | 
			
		||||
 | 
			
		||||
			// Если директория пустая, пропускаем её
 | 
			
		||||
			if !prefered {
 | 
			
		||||
				_, err = f.Readdirnames(1)
 | 
			
		||||
				if err != io.EOF {
 | 
			
		||||
					return nil
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			contents = append(contents, &files.Content{
 | 
			
		||||
				Source:      path,
 | 
			
		||||
@@ -599,16 +649,14 @@ func buildContents(vars *types.BuildVars, dirs types.Directories) ([]*files.Cont
 | 
			
		||||
					MTime: fi.ModTime(),
 | 
			
		||||
				},
 | 
			
		||||
			})
 | 
			
		||||
 | 
			
		||||
			return f.Close()
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
		// Если файл является символической ссылкой, прорабатываем это
 | 
			
		||||
 | 
			
		||||
		if fi.Mode()&os.ModeSymlink != 0 {
 | 
			
		||||
			link, err := os.Readlink(path)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			// Удаляем pkgdir из пути символической ссылки
 | 
			
		||||
			link = strings.TrimPrefix(link, dirs.PkgDir)
 | 
			
		||||
 | 
			
		||||
			contents = append(contents, &files.Content{
 | 
			
		||||
@@ -620,10 +668,9 @@ func buildContents(vars *types.BuildVars, dirs types.Directories) ([]*files.Cont
 | 
			
		||||
					Mode:  fi.Mode(),
 | 
			
		||||
				},
 | 
			
		||||
			})
 | 
			
		||||
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
		// Обрабатываем обычные файлы
 | 
			
		||||
 | 
			
		||||
		fileContent := &files.Content{
 | 
			
		||||
			Source:      path,
 | 
			
		||||
			Destination: trimmed,
 | 
			
		||||
@@ -634,16 +681,35 @@ func buildContents(vars *types.BuildVars, dirs types.Directories) ([]*files.Cont
 | 
			
		||||
			},
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Если файл должен быть сохранен, установите его тип как config|noreplace
 | 
			
		||||
		if slices.Contains(vars.Backup, trimmed) {
 | 
			
		||||
			fileContent.Type = "config|noreplace"
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		contents = append(contents, fileContent)
 | 
			
		||||
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if preferedContents != nil {
 | 
			
		||||
		for _, trimmed := range *preferedContents {
 | 
			
		||||
			path := filepath.Join(dirs.PkgDir, trimmed)
 | 
			
		||||
			if err := processPath(path, trimmed, true); err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		err := filepath.Walk(dirs.PkgDir, func(path string, fi os.FileInfo, err error) error {
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			trimmed := strings.TrimPrefix(path, dirs.PkgDir)
 | 
			
		||||
			return processPath(path, trimmed, false)
 | 
			
		||||
		})
 | 
			
		||||
	return contents, err
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return contents, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Функция removeBuildDeps спрашивает у пользователя, хочет ли он удалить зависимости,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user