feat: add files() function #19
							
								
								
									
										14
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								go.mod
									
									
									
									
									
								
							| @@ -1,8 +1,8 @@ | |||||||
| module gitea.plemya-x.ru/Plemya-x/ALR | module gitea.plemya-x.ru/Plemya-x/ALR | ||||||
|  |  | ||||||
| go 1.21 | go 1.22 | ||||||
|  |  | ||||||
| toolchain go1.21.3 | toolchain go1.23.5 | ||||||
|  |  | ||||||
| require ( | require ( | ||||||
| 	github.com/AlecAivazis/survey/v2 v2.3.7 | 	github.com/AlecAivazis/survey/v2 v2.3.7 | ||||||
| @@ -34,7 +34,7 @@ require ( | |||||||
| 	golang.org/x/text v0.21.0 | 	golang.org/x/text v0.21.0 | ||||||
| 	gopkg.in/yaml.v3 v3.0.1 | 	gopkg.in/yaml.v3 v3.0.1 | ||||||
| 	modernc.org/sqlite v1.25.0 | 	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 | 	plemya-x.ru/fakeroot v0.0.0-20240601131003-c638a3543283 | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -110,11 +110,11 @@ require ( | |||||||
| 	github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect | 	github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect | ||||||
| 	gitlab.com/digitalxero/go-conventional-commit v1.0.7 // indirect | 	gitlab.com/digitalxero/go-conventional-commit v1.0.7 // indirect | ||||||
| 	go4.org v0.0.0-20200411211856-f5505b9728dd // indirect | 	go4.org v0.0.0-20200411211856-f5505b9728dd // indirect | ||||||
| 	golang.org/x/mod v0.17.0 // indirect | 	golang.org/x/mod v0.18.0 // indirect | ||||||
| 	golang.org/x/net v0.25.0 // indirect | 	golang.org/x/net v0.26.0 // indirect | ||||||
| 	golang.org/x/sync v0.10.0 // indirect | 	golang.org/x/sync v0.10.0 // indirect | ||||||
| 	golang.org/x/term v0.24.0 // indirect | 	golang.org/x/term v0.25.0 // indirect | ||||||
| 	golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect | 	golang.org/x/tools v0.22.0 // indirect | ||||||
| 	gopkg.in/warnings.v0 v0.1.2 // indirect | 	gopkg.in/warnings.v0 v0.1.2 // indirect | ||||||
| 	lukechampine.com/uint128 v1.2.0 // indirect | 	lukechampine.com/uint128 v1.2.0 // indirect | ||||||
| 	modernc.org/cc/v3 v3.40.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.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= | ||||||
| github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= | 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.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 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= | ||||||
| github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= | 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= | 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.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 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= | ||||||
| golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= | 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-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-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||||
| golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/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.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 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= | ||||||
| golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= | 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-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-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= | ||||||
| golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/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.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 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= | ||||||
| golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= | 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.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.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||||||
| golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/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.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 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.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-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-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||||
| golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/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= | 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 h1:lSTjdP/1xsddtaKfGg7Myu7DnlHItd3/M2tomOcNNBg= | ||||||
| mvdan.cc/sh/v3 v3.7.0/go.mod h1:K2gwkaesF/D7av7Kxl0HbF5kGOd2ArupNTX3X44+8l8= | 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 h1:BXCLPeA8g2M6qYngicyxyB/2Bo4J54Q9Rb+8jMmE3ik= | ||||||
| plemya-x.ru/fakeroot v0.0.0-20240601131003-c638a3543283/go.mod h1:itzL9Jx52VXOhRaucFHuMpa3y7iwjnuLGdNvypoh/S4= | 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= | 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 { | 	return func(ctx context.Context, opts ...interp.RunnerOption) error { | ||||||
| 		sub := d.Runner.Subshell() | 		sub := d.Runner.Subshell() | ||||||
| 		for _, opt := range opts { | 		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) | 		return sub.Run(ctx, fn) | ||||||
| 	}, true | 	}, true | ||||||
|   | |||||||
| @@ -24,6 +24,7 @@ import ( | |||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"io" | 	"io" | ||||||
| 	"os" | 	"os" | ||||||
|  | 	"path" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| 	"strings" | 	"strings" | ||||||
| @@ -55,12 +56,17 @@ var Helpers = handlers.ExecFuncs{ | |||||||
| 	"install-completion":   installCompletionCmd, | 	"install-completion":   installCompletionCmd, | ||||||
| 	"install-library":      installLibraryCmd, | 	"install-library":      installLibraryCmd, | ||||||
| 	"git-version":          gitVersionCmd, | 	"git-version":          gitVersionCmd, | ||||||
|  |  | ||||||
|  | 	"files-find-lang": filesFindLangCmd, | ||||||
|  | 	"files-find-doc":  filesFindDocCmd, | ||||||
| } | } | ||||||
|  |  | ||||||
| // Restricted contains restricted read-only helper commands | // Restricted contains restricted read-only helper commands | ||||||
| // that don't modify any state | // that don't modify any state | ||||||
| var Restricted = handlers.ExecFuncs{ | var Restricted = handlers.ExecFuncs{ | ||||||
| 	"git-version": gitVersionCmd, | 	"git-version":     gitVersionCmd, | ||||||
|  | 	"files-find-lang": filesFindLangCmd, | ||||||
|  | 	"files-find-doc":  filesFindDocCmd, | ||||||
| } | } | ||||||
|  |  | ||||||
| func installHelperCmd(prefix string, perms os.FileMode) handlers.ExecFunc { | 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 | 	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 { | func helperInstall(from, to string, perms os.FileMode) error { | ||||||
| 	err := os.MkdirAll(filepath.Dir(to), 0o755) | 	err := os.MkdirAll(filepath.Dir(to), 0o755) | ||||||
| 	if err != nil { | 	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" | msgid "Downloading source" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: internal/logger/log.go:44 | #: internal/logger/log.go:47 | ||||||
| msgid "ERROR" | msgid "ERROR" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @@ -323,35 +323,43 @@ msgstr "" | |||||||
| msgid "Installing dependencies" | msgid "Installing dependencies" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: pkg/build/build.go:435 | #: pkg/build/build.go:439 | ||||||
| msgid "Executing version()" | msgid "Executing version()" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: pkg/build/build.go:460 | #: pkg/build/build.go:459 | ||||||
|  | msgid "Updating version" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
|  | #: pkg/build/build.go:464 | ||||||
| msgid "Executing prepare()" | msgid "Executing prepare()" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: pkg/build/build.go:470 | #: pkg/build/build.go:474 | ||||||
| msgid "Executing build()" | msgid "Executing build()" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: pkg/build/build.go:482 | #: pkg/build/build.go:486 | ||||||
| msgid "Executing package()" | msgid "Executing package()" | ||||||
| msgstr "" | 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" | msgid "AutoProv is not implemented for this package format, so it's skiped" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: pkg/build/build.go:568 | #: pkg/build/build.go:612 | ||||||
| msgid "AutoReq is not implemented for this package format, so it's skiped" | msgid "AutoReq is not implemented for this package format, so it's skiped" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: pkg/build/build.go:653 | #: pkg/build/build.go:719 | ||||||
| msgid "Would you like to remove the build dependencies?" | msgid "Would you like to remove the build dependencies?" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: pkg/build/build.go:759 | #: pkg/build/build.go:825 | ||||||
| msgid "The checksums array must be the same length as sources" | msgid "The checksums array must be the same length as sources" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @@ -437,10 +445,14 @@ msgstr "" | |||||||
| msgid "Pull all repositories that have changed" | msgid "Pull all repositories that have changed" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: upgrade.go:47 | #: upgrade.go:46 | ||||||
| msgid "Upgrade all installed packages" | msgid "Upgrade all installed packages" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: upgrade.go:83 | #: upgrade.go:82 | ||||||
| msgid "Error checking for updates" | msgid "Error checking for updates" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
|  | #: upgrade.go:93 | ||||||
|  | msgid "There is nothing to do." | ||||||
|  | msgstr "" | ||||||
|   | |||||||
| @@ -259,7 +259,7 @@ msgstr "" | |||||||
| msgid "Downloading source" | msgid "Downloading source" | ||||||
| msgstr "Скачивание источника" | msgstr "Скачивание источника" | ||||||
|  |  | ||||||
| #: internal/logger/log.go:44 | #: internal/logger/log.go:47 | ||||||
| msgid "ERROR" | msgid "ERROR" | ||||||
| msgstr "ОШИБКА" | msgstr "ОШИБКА" | ||||||
|  |  | ||||||
| @@ -331,35 +331,43 @@ msgstr "" | |||||||
| msgid "Installing dependencies" | msgid "Installing dependencies" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: pkg/build/build.go:435 | #: pkg/build/build.go:439 | ||||||
| msgid "Executing version()" | msgid "Executing version()" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: pkg/build/build.go:460 | #: pkg/build/build.go:459 | ||||||
|  | msgid "Updating version" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
|  | #: pkg/build/build.go:464 | ||||||
| msgid "Executing prepare()" | msgid "Executing prepare()" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: pkg/build/build.go:470 | #: pkg/build/build.go:474 | ||||||
| msgid "Executing build()" | msgid "Executing build()" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: pkg/build/build.go:482 | #: pkg/build/build.go:486 | ||||||
| msgid "Executing package()" | msgid "Executing package()" | ||||||
| msgstr "" | 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" | msgid "AutoProv is not implemented for this package format, so it's skiped" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: pkg/build/build.go:568 | #: pkg/build/build.go:612 | ||||||
| msgid "AutoReq is not implemented for this package format, so it's skiped" | msgid "AutoReq is not implemented for this package format, so it's skiped" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: pkg/build/build.go:653 | #: pkg/build/build.go:719 | ||||||
| msgid "Would you like to remove the build dependencies?" | msgid "Would you like to remove the build dependencies?" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: pkg/build/build.go:759 | #: pkg/build/build.go:825 | ||||||
| msgid "The checksums array must be the same length as sources" | msgid "The checksums array must be the same length as sources" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @@ -446,10 +454,14 @@ msgstr "" | |||||||
| msgid "Pull all repositories that have changed" | msgid "Pull all repositories that have changed" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: upgrade.go:47 | #: upgrade.go:46 | ||||||
| msgid "Upgrade all installed packages" | msgid "Upgrade all installed packages" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: upgrade.go:83 | #: upgrade.go:82 | ||||||
| msgid "Error checking for updates" | msgid "Error checking for updates" | ||||||
| msgstr "" | 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 | 		return nil, nil, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	err = executeFunctions(ctx, dec, dirs, vars) // Выполняем специальные функции | 	funcOut, err := executeFunctions(ctx, dec, dirs, vars) // Выполняем специальные функции | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, nil, err | 		return nil, nil, err | ||||||
| 	} | 	} | ||||||
| @@ -165,7 +165,7 @@ func BuildPackage(ctx context.Context, opts types.BuildOpts) ([]string, []string | |||||||
|  |  | ||||||
| 	pkgFormat := getPkgFormat(opts.Manager) // Получаем формат пакета | 	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 { | 	if err != nil { | ||||||
| 		return nil, nil, err | 		return nil, nil, err | ||||||
| 	} | 	} | ||||||
| @@ -428,40 +428,44 @@ func buildALRDeps(ctx context.Context, opts types.BuildOpts, vars *types.BuildVa | |||||||
| 	return builtPaths, builtNames, repoDeps, nil | 	return builtPaths, builtNames, repoDeps, nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | type FunctionsOutput struct { | ||||||
|  | 	Contents *[]string | ||||||
|  | } | ||||||
|  |  | ||||||
| // Функция executeFunctions выполняет специальные функции ALR, такие как version(), prepare() и т.д. | // Функция 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") | 	version, ok := dec.GetFunc("version") | ||||||
| 	if ok { | 	if ok { | ||||||
| 		slog.Info(gotext.Get("Executing version()")) | 		slog.Info(gotext.Get("Executing version()")) | ||||||
|  |  | ||||||
| 		buf := &bytes.Buffer{} | 		buf := &bytes.Buffer{} | ||||||
|  |  | ||||||
| 		err = version( | 		err := version( | ||||||
| 			ctx, | 			ctx, | ||||||
| 			interp.Dir(dirs.SrcDir), | 			interp.Dir(dirs.SrcDir), | ||||||
| 			interp.StdIO(os.Stdin, buf, os.Stderr), | 			interp.StdIO(os.Stdin, buf, os.Stderr), | ||||||
| 		) | 		) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return err | 			return nil, err | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		newVer := strings.TrimSpace(buf.String()) | 		newVer := strings.TrimSpace(buf.String()) | ||||||
| 		err = setVersion(ctx, dec.Runner, newVer) | 		err = setVersion(ctx, dec.Runner, newVer) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return err | 			return nil, err | ||||||
| 		} | 		} | ||||||
| 		vars.Version = newVer | 		vars.Version = newVer | ||||||
|  |  | ||||||
| 		slog.Info("Updating version", "new", newVer) | 		slog.Info(gotext.Get("Updating version"), "new", newVer) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	prepare, ok := dec.GetFunc("prepare") | 	prepare, ok := dec.GetFunc("prepare") | ||||||
| 	if ok { | 	if ok { | ||||||
| 		slog.Info(gotext.Get("Executing prepare()")) | 		slog.Info(gotext.Get("Executing prepare()")) | ||||||
|  |  | ||||||
| 		err = prepare(ctx, interp.Dir(dirs.SrcDir)) | 		err := prepare(ctx, interp.Dir(dirs.SrcDir)) | ||||||
| 		if err != nil { | 		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 { | 	if ok { | ||||||
| 		slog.Info(gotext.Get("Executing build()")) | 		slog.Info(gotext.Get("Executing build()")) | ||||||
|  |  | ||||||
| 		err = build(ctx, interp.Dir(dirs.SrcDir)) | 		err := build(ctx, interp.Dir(dirs.SrcDir)) | ||||||
| 		if err != nil { | 		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") | 		packageFn, ok := dec.GetFunc("package") | ||||||
| 		if ok { | 		if ok { | ||||||
| 			slog.Info(gotext.Get("Executing package()")) | 			slog.Info(gotext.Get("Executing package()")) | ||||||
| 			err = packageFn(ctx, interp.Dir(dirs.SrcDir)) | 			err := packageFn(ctx, interp.Dir(dirs.SrcDir)) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return err | 				return nil, err | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @@ -502,11 +506,51 @@ func executeFunctions(ctx context.Context, dec *decoder.Decoder, dirs types.Dire | |||||||
| 		break | 		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 создает метаданные для пакета, который будет собран. | // Функция 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 := getBasePkgInfo(vars) | ||||||
| 	pkgInfo.Description = vars.Description | 	pkgInfo.Description = vars.Description | ||||||
| 	pkgInfo.Platform = "linux" | 	pkgInfo.Platform = "linux" | ||||||
| @@ -541,7 +585,7 @@ func buildPkgMetadata(ctx context.Context, vars *types.BuildVars, dirs types.Dir | |||||||
| 		pkgInfo.Arch = "all" | 		pkgInfo.Arch = "all" | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	contents, err := buildContents(vars, dirs) | 	contents, err := buildContents(vars, dirs, preferedContents) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| @@ -574,21 +618,27 @@ func buildPkgMetadata(ctx context.Context, vars *types.BuildVars, dirs types.Dir | |||||||
|  |  | ||||||
| // Функция buildContents создает секцию содержимого пакета, которая содержит файлы, | // Функция 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{} | 	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() { | 		if fi.IsDir() { | ||||||
| 			f, err := os.Open(path) | 			f, err := os.Open(path) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return err | 				return err | ||||||
| 			} | 			} | ||||||
|  | 			defer f.Close() | ||||||
|  |  | ||||||
| 			// Если директория пустая, пропускаем её | 			if !prefered { | ||||||
| 			_, err = f.Readdirnames(1) | 				_, err = f.Readdirnames(1) | ||||||
| 			if err != io.EOF { | 				if err != io.EOF { | ||||||
| 				return nil | 					return nil | ||||||
|  | 				} | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			contents = append(contents, &files.Content{ | 			contents = append(contents, &files.Content{ | ||||||
| @@ -599,16 +649,14 @@ func buildContents(vars *types.BuildVars, dirs types.Directories) ([]*files.Cont | |||||||
| 					MTime: fi.ModTime(), | 					MTime: fi.ModTime(), | ||||||
| 				}, | 				}, | ||||||
| 			}) | 			}) | ||||||
|  | 			return nil | ||||||
| 			return f.Close() |  | ||||||
| 		} | 		} | ||||||
| 		// Если файл является символической ссылкой, прорабатываем это |  | ||||||
| 		if fi.Mode()&os.ModeSymlink != 0 { | 		if fi.Mode()&os.ModeSymlink != 0 { | ||||||
| 			link, err := os.Readlink(path) | 			link, err := os.Readlink(path) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return err | 				return err | ||||||
| 			} | 			} | ||||||
| 			// Удаляем pkgdir из пути символической ссылки |  | ||||||
| 			link = strings.TrimPrefix(link, dirs.PkgDir) | 			link = strings.TrimPrefix(link, dirs.PkgDir) | ||||||
|  |  | ||||||
| 			contents = append(contents, &files.Content{ | 			contents = append(contents, &files.Content{ | ||||||
| @@ -620,10 +668,9 @@ func buildContents(vars *types.BuildVars, dirs types.Directories) ([]*files.Cont | |||||||
| 					Mode:  fi.Mode(), | 					Mode:  fi.Mode(), | ||||||
| 				}, | 				}, | ||||||
| 			}) | 			}) | ||||||
|  |  | ||||||
| 			return nil | 			return nil | ||||||
| 		} | 		} | ||||||
| 		// Обрабатываем обычные файлы |  | ||||||
| 		fileContent := &files.Content{ | 		fileContent := &files.Content{ | ||||||
| 			Source:      path, | 			Source:      path, | ||||||
| 			Destination: trimmed, | 			Destination: trimmed, | ||||||
| @@ -634,16 +681,35 @@ func buildContents(vars *types.BuildVars, dirs types.Directories) ([]*files.Cont | |||||||
| 			}, | 			}, | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// Если файл должен быть сохранен, установите его тип как config|noreplace |  | ||||||
| 		if slices.Contains(vars.Backup, trimmed) { | 		if slices.Contains(vars.Backup, trimmed) { | ||||||
| 			fileContent.Type = "config|noreplace" | 			fileContent.Type = "config|noreplace" | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		contents = append(contents, fileContent) | 		contents = append(contents, fileContent) | ||||||
|  |  | ||||||
| 		return nil | 		return nil | ||||||
| 	}) | 	} | ||||||
| 	return contents, err |  | ||||||
|  | 	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) | ||||||
|  | 		}) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return contents, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| // Функция removeBuildDeps спрашивает у пользователя, хочет ли он удалить зависимости, | // Функция removeBuildDeps спрашивает у пользователя, хочет ли он удалить зависимости, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user