Compare commits
	
		
			10 Commits
		
	
	
		
			v0.0.13
			...
			686da3e036
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 686da3e036 | |||
| 131f455eff | |||
| 1e52d30f4c | |||
| 40ec0ac6e1 | |||
| 443e481561 | |||
| c892310f69 | |||
| 750513b119 | |||
| ce1836b646 | |||
| 56b9f3211c | |||
| fae63e28f9 | 
							
								
								
									
										52
									
								
								.gitea/workflows/e2e-tests.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								.gitea/workflows/e2e-tests.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | |||||||
|  | # 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/>. | ||||||
|  |  | ||||||
|  | name: E2E | ||||||
|  |  | ||||||
|  | on: | ||||||
|  |   push: | ||||||
|  |     branches: [ main ] | ||||||
|  |   pull_request: | ||||||
|  |  | ||||||
|  |  | ||||||
|  | jobs: | ||||||
|  |   tests: | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  |  | ||||||
|  |     container: | ||||||
|  |       image: registry.altlinux.org/p11/node:latest | ||||||
|  |  | ||||||
|  |     steps: | ||||||
|  |       - name: Checkout | ||||||
|  |         uses: https://github.com/actions/checkout@v4 | ||||||
|  |        | ||||||
|  |       - name: Set up Go | ||||||
|  |         uses: https://github.com/actions/setup-go@v5 | ||||||
|  |         with: | ||||||
|  |           go-version: '1.24'         | ||||||
|  |        | ||||||
|  |       - name: Install deps | ||||||
|  |         run: apt-get update && apt-get install -y podman podman-docker | ||||||
|  |  | ||||||
|  |       - name: Start Podman service | ||||||
|  |         run: nohup podman system service -t 0 unix:/tmp/podman.sock & | ||||||
|  |  | ||||||
|  |       - name: Run E2E tests | ||||||
|  |         env: | ||||||
|  |           DOCKER_HOST: unix:/tmp/podman.sock | ||||||
|  |           IGNORE_ROOT_CHECK: 1 | ||||||
|  |         run: | | ||||||
|  |           make e2e-test | ||||||
							
								
								
									
										49
									
								
								.gitea/workflows/pre-commit.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								.gitea/workflows/pre-commit.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | |||||||
|  | # 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/>. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | name: Pre-commit | ||||||
|  |  | ||||||
|  | on: | ||||||
|  |   push: | ||||||
|  |     branches: [ main ] | ||||||
|  |   pull_request: | ||||||
|  |  | ||||||
|  |  | ||||||
|  | jobs: | ||||||
|  |   pre-commit: | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  |  | ||||||
|  |     steps: | ||||||
|  |       - name: Checkout | ||||||
|  |         uses: https://github.com/actions/checkout@v4 | ||||||
|  |  | ||||||
|  |       - name: Set up Go | ||||||
|  |         uses: https://github.com/actions/setup-go@v5 | ||||||
|  |         with: | ||||||
|  |           go-version: '1.24' | ||||||
|  |        | ||||||
|  |       - name: Set up Python for pre-commit | ||||||
|  |         uses: https://github.com/actions/setup-python@v5 | ||||||
|  |         with: | ||||||
|  |           python-version: '3.12' | ||||||
|  |        | ||||||
|  |       - name: Install deps | ||||||
|  |         run: apt-get update && apt-get install -y gettext bc | ||||||
|  |  | ||||||
|  |       - run: pip install pre-commit | ||||||
|  |       - run: pre-commit install | ||||||
|  |       - run: pre-commit run --all-files | ||||||
							
								
								
									
										11
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								Makefile
									
									
									
									
									
								
							| @@ -1,6 +1,6 @@ | |||||||
| NAME := alr | NAME := alr | ||||||
| GIT_VERSION = $(shell git describe --tags ) | GIT_VERSION = $(shell git describe --tags ) | ||||||
|  | IGNORE_ROOT_CHECK ?= 0 | ||||||
| DESTDIR ?= | DESTDIR ?= | ||||||
| PREFIX ?= /usr/local | PREFIX ?= /usr/local | ||||||
| BIN := ./$(NAME) | BIN := ./$(NAME) | ||||||
| @@ -24,8 +24,9 @@ $(BIN): | |||||||
| 	go build -ldflags="-X 'gitea.plemya-x.ru/Plemya-x/ALR/internal/config.Version=$(GIT_VERSION)'" -o $@ | 	go build -ldflags="-X 'gitea.plemya-x.ru/Plemya-x/ALR/internal/config.Version=$(GIT_VERSION)'" -o $@ | ||||||
|  |  | ||||||
| check-no-root: | check-no-root: | ||||||
| 	@if [[ "$$(whoami)" == 'root' ]]; then \ | 	@if [[ "$(IGNORE_ROOT_CHECK)" != "1" ]] && [[ "$$(whoami)" == 'root' ]]; then \ | ||||||
| 		echo "This target shouldn't run as root" 1>&2; \ | 		echo "This target shouldn't run as root" 1>&2; \ | ||||||
|  | 		echo "Set IGNORE_ROOT_CHECK=1 to override" 1>&2; \ | ||||||
| 		exit 1; \ | 		exit 1; \ | ||||||
| 	fi | 	fi | ||||||
|  |  | ||||||
| @@ -54,7 +55,7 @@ uninstall: | |||||||
| clean clear: | clean clear: | ||||||
| 	rm -f $(BIN) | 	rm -f $(BIN) | ||||||
|  |  | ||||||
| OLD_FILES=$$(< old-files) | OLD_FILES=$(shell cat old-files) | ||||||
| IGNORE_OLD_FILES := $(foreach file,$(shell cat old-files),-ignore $(file)) | IGNORE_OLD_FILES := $(foreach file,$(shell cat old-files),-ignore $(file)) | ||||||
| update-license: | update-license: | ||||||
| 	$(ADD_LICENSE_BIN) -v -f license-header-old-files.tmpl $(OLD_FILES) | 	$(ADD_LICENSE_BIN) -v -f license-header-old-files.tmpl $(OLD_FILES) | ||||||
| @@ -76,7 +77,9 @@ test-coverage: | |||||||
| update-deps-cve: | update-deps-cve: | ||||||
| 	bash scripts/update-deps-cve.sh | 	bash scripts/update-deps-cve.sh | ||||||
|  |  | ||||||
| e2e-test: clean build | prepare-for-e2e-test: clean build | ||||||
| 	rm -f ./e2e-tests/alr | 	rm -f ./e2e-tests/alr | ||||||
| 	cp alr e2e-tests | 	cp alr e2e-tests | ||||||
|  |  | ||||||
|  | e2e-test: prepare-for-e2e-test | ||||||
| 	go test -tags=e2e ./... | 	go test -tags=e2e ./... | ||||||
| @@ -12,7 +12,7 @@ | |||||||
|     <g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"> |     <g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"> | ||||||
|         <text x="37" y="15" fill="#010101" fill-opacity=".3">ru translate</text> |         <text x="37" y="15" fill="#010101" fill-opacity=".3">ru translate</text> | ||||||
|         <text x="37" y="14">ru translate</text> |         <text x="37" y="14">ru translate</text> | ||||||
|         <text x="100" y="15" fill="#010101" fill-opacity=".3">100.00%</text> |         <text x="100" y="15" fill="#010101" fill-opacity=".3">96.00%</text> | ||||||
|         <text x="100" y="14">100.00%</text> |         <text x="100" y="14">96.00%</text> | ||||||
|     </g> |     </g> | ||||||
| </svg> | </svg> | ||||||
|   | |||||||
| Before Width: | Height: | Size: 942 B After Width: | Height: | Size: 940 B | 
							
								
								
									
										6
									
								
								build.go
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								build.go
									
									
									
									
									
								
							| @@ -118,7 +118,11 @@ func BuildCmd() *cli.Command { | |||||||
| 					return cliutils.FormatCliExit(gotext.Get("Cannot get absolute script path"), err) | 					return cliutils.FormatCliExit(gotext.Get("Cannot get absolute script path"), err) | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
| 				packages = append(packages, c.String("script-package")) | 				subpackage := c.String("subpackage") | ||||||
|  |  | ||||||
|  | 				if subpackage != "" { | ||||||
|  | 					packages = append(packages, subpackage) | ||||||
|  | 				} | ||||||
|  |  | ||||||
| 				scriptArgs = &build.BuildPackageFromScriptArgs{ | 				scriptArgs = &build.BuildPackageFromScriptArgs{ | ||||||
| 					Script:    script, | 					Script:    script, | ||||||
|   | |||||||
| @@ -175,6 +175,11 @@ func dockerMultipleRun(t *testing.T, name string, ids []string, f func(t *testin | |||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func simpleExec(t *testing.T, r e2e.Runnable, cmd string, args ...string) { | ||||||
|  | 	err := r.Exec(e2e.NewCommand(cmd, args...)) | ||||||
|  | 	assert.NoError(t, err) | ||||||
|  | } | ||||||
|  |  | ||||||
| func runTestCommands(t *testing.T, r e2e.Runnable, timeout time.Duration, expects []expect.Batcher) { | func runTestCommands(t *testing.T, r e2e.Runnable, timeout time.Duration, expects []expect.Batcher) { | ||||||
| 	exp, _, err, _ := e2eSpawn( | 	exp, _, err, _ := e2eSpawn( | ||||||
| 		r, | 		r, | ||||||
| @@ -188,3 +193,5 @@ func runTestCommands(t *testing.T, r e2e.Runnable, timeout time.Duration, expect | |||||||
| 	) | 	) | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | const REPO_FOR_E2E_TESTS = "https://gitea.plemya-x.ru/Maks1mS/repo-for-tests.git" | ||||||
|   | |||||||
							
								
								
									
										50
									
								
								e2e-tests/issue_74_upgradable_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								e2e-tests/issue_74_upgradable_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | |||||||
|  | // 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/>. | ||||||
|  |  | ||||||
|  | //go:build e2e | ||||||
|  |  | ||||||
|  | package e2etests_test | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"testing" | ||||||
|  |  | ||||||
|  | 	"github.com/efficientgo/e2e" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func TestE2EIssue74Upgradable(t *testing.T) { | ||||||
|  | 	dockerMultipleRun( | ||||||
|  | 		t, | ||||||
|  | 		"issue-74-upgradable", | ||||||
|  | 		COMMON_SYSTEMS, | ||||||
|  | 		func(t *testing.T, r e2e.Runnable) { | ||||||
|  | 			simpleExec(t, r, "sudo", | ||||||
|  | 				"alr", | ||||||
|  | 				"addrepo", | ||||||
|  | 				"--name", | ||||||
|  | 				"alr-repo", | ||||||
|  | 				"--url", | ||||||
|  | 				REPO_FOR_E2E_TESTS, | ||||||
|  | 			) | ||||||
|  | 			simpleExec(t, r, "sudo", "sh", "-c", "sed -i 's/ref = .*/ref = \"bd26236cd7\"/' /etc/alr/alr.toml") | ||||||
|  | 			simpleExec(t, r, "alr", "ref") | ||||||
|  | 			simpleExec(t, r, "sudo", "alr", "in", "bar-pkg") | ||||||
|  | 			simpleExec(t, r, "sh", "-c", "test $(alr list -U | wc -l) -eq 0 || exit 1") | ||||||
|  | 			simpleExec(t, r, "sudo", "sh", "-c", "sed -i 's/ref = .*/ref = \"d9a3541561\"/' /etc/alr/alr.toml") | ||||||
|  | 			simpleExec(t, r, "sudo", "alr", "ref") | ||||||
|  | 			simpleExec(t, r, "sh", "-c", "test $(alr list -U | wc -l) -eq 1 || exit 1") | ||||||
|  | 		}, | ||||||
|  | 	) | ||||||
|  | } | ||||||
							
								
								
									
										59
									
								
								e2e-tests/issue_81_multiple_packages_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								e2e-tests/issue_81_multiple_packages_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | |||||||
|  | // 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/>. | ||||||
|  |  | ||||||
|  | //go:build e2e | ||||||
|  |  | ||||||
|  | package e2etests_test | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"testing" | ||||||
|  |  | ||||||
|  | 	"github.com/efficientgo/e2e" | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func TestE2EIssue81MultiplePackages(t *testing.T) { | ||||||
|  | 	dockerMultipleRun( | ||||||
|  | 		t, | ||||||
|  | 		"issue-81-multiple-packages", | ||||||
|  | 		COMMON_SYSTEMS, | ||||||
|  | 		func(t *testing.T, r e2e.Runnable) { | ||||||
|  | 			err := r.Exec(e2e.NewCommand( | ||||||
|  | 				"sudo", | ||||||
|  | 				"alr", | ||||||
|  | 				"addrepo", | ||||||
|  | 				"--name", | ||||||
|  | 				"alr-repo", | ||||||
|  | 				"--url", | ||||||
|  | 				REPO_FOR_E2E_TESTS, | ||||||
|  | 			)) | ||||||
|  | 			assert.NoError(t, err) | ||||||
|  |  | ||||||
|  | 			err = r.Exec(e2e.NewCommand( | ||||||
|  | 				"sudo", "alr", "ref", | ||||||
|  | 			)) | ||||||
|  | 			assert.NoError(t, err) | ||||||
|  |  | ||||||
|  | 			err = r.Exec(e2e.NewCommand( | ||||||
|  | 				"sudo", "alr", "in", "first-package-with-dashes", | ||||||
|  | 			)) | ||||||
|  | 			assert.NoError(t, err) | ||||||
|  |  | ||||||
|  | 			err = r.Exec(e2e.NewCommand("cat", "/opt/first-package")) | ||||||
|  | 			assert.NoError(t, err) | ||||||
|  | 		}, | ||||||
|  | 	) | ||||||
|  | } | ||||||
| @@ -21,6 +21,7 @@ import ( | |||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"log/slog" | 	"log/slog" | ||||||
|  |  | ||||||
|  | 	"github.com/leonelquinteros/gotext" | ||||||
| 	"github.com/urfave/cli/v2" | 	"github.com/urfave/cli/v2" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -61,3 +62,11 @@ func FormatCliExitWithCode(msg string, err error, exitCode int) cli.ExitCoder { | |||||||
| 	} | 	} | ||||||
| 	return cli.Exit(fmt.Errorf("%s: %w", msg, err), exitCode) | 	return cli.Exit(fmt.Errorf("%s: %w", msg, err), exitCode) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func WarnLegacyCommand(newSyntax string) { | ||||||
|  | 	slog.Warn( | ||||||
|  | 		gotext.Get( | ||||||
|  | 			"This command is deprecated and would be removed in the future, use \"%s\" instead!", newSyntax, | ||||||
|  | 		), | ||||||
|  | 	) | ||||||
|  | } | ||||||
|   | |||||||
| @@ -104,7 +104,7 @@ func Resolve(info *distro.OSRelease, opts *Opts) ([]string, error) { | |||||||
| 	out = append(out, opts.Name) | 	out = append(out, opts.Name) | ||||||
|  |  | ||||||
| 	for index, item := range out { | 	for index, item := range out { | ||||||
| 		out[index] = strings.TrimPrefix(strings.ReplaceAll(item, "-", "_"), "_") | 		out[index] = strings.TrimPrefix(item, "_") | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return out, nil | 	return out, nil | ||||||
|   | |||||||
| @@ -38,23 +38,23 @@ msgstr "" | |||||||
| msgid "Cannot get absolute script path" | msgid "Cannot get absolute script path" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: build.go:148 | #: build.go:152 | ||||||
| msgid "Package not found" | msgid "Package not found" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: build.go:161 | #: build.go:165 | ||||||
| msgid "Nothing to build" | msgid "Nothing to build" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: build.go:218 | #: build.go:222 | ||||||
| msgid "Error building package" | msgid "Error building package" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: build.go:225 | #: build.go:229 | ||||||
| msgid "Error moving the package" | msgid "Error moving the package" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: build.go:229 | #: build.go:233 | ||||||
| msgid "Done" | msgid "Done" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @@ -278,6 +278,12 @@ msgstr "" | |||||||
| msgid "OPTIONS" | msgid "OPTIONS" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
|  | #: internal/cliutils/utils.go:69 | ||||||
|  | msgid "" | ||||||
|  | "This command is deprecated and would be removed in the future, use \"%s\" " | ||||||
|  | "instead!" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
| #: internal/db/db.go:137 | #: internal/db/db.go:137 | ||||||
| msgid "Database version mismatch; resetting" | msgid "Database version mismatch; resetting" | ||||||
| msgstr "" | msgstr "" | ||||||
| @@ -327,10 +333,30 @@ msgstr "" | |||||||
| msgid "You need to be root to perform this action" | msgid "You need to be root to perform this action" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: list.go:41 | #: list.go:43 | ||||||
| msgid "List ALR repo packages" | msgid "List ALR repo packages" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
|  | #: list.go:57 | ||||||
|  | msgid "Format output using a Go template" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
|  | #: list.go:89 | ||||||
|  | msgid "Error getting packages for upgrade" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
|  | #: list.go:92 | ||||||
|  | msgid "No packages for upgrade" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
|  | #: list.go:102 list.go:187 | ||||||
|  | msgid "Error parsing format template" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
|  | #: list.go:108 list.go:191 | ||||||
|  | msgid "Error executing template" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
| #: main.go:45 | #: main.go:45 | ||||||
| msgid "Print the current ALR version and exit" | msgid "Print the current ALR version and exit" | ||||||
| msgstr "" | msgstr "" | ||||||
| @@ -343,11 +369,11 @@ msgstr "" | |||||||
| msgid "Enable interactive questions and prompts" | msgid "Enable interactive questions and prompts" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: main.go:145 | #: main.go:146 | ||||||
| msgid "Show help" | msgid "Show help" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: main.go:149 | #: main.go:150 | ||||||
| msgid "Error while running app" | msgid "Error while running app" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @@ -397,82 +423,94 @@ msgstr "" | |||||||
| msgid "AutoReq is not implemented for this package format, so it's skipped" | msgid "AutoReq is not implemented for this package format, so it's skipped" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: pkg/build/script_executor.go:237 | #: pkg/build/script_executor.go:241 | ||||||
| msgid "Building package metadata" | msgid "Building package metadata" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: pkg/build/script_executor.go:368 | #: pkg/build/script_executor.go:372 | ||||||
| msgid "Executing prepare()" | msgid "Executing prepare()" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: pkg/build/script_executor.go:377 | #: pkg/build/script_executor.go:381 | ||||||
| msgid "Executing build()" | msgid "Executing build()" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: pkg/build/script_executor.go:406 pkg/build/script_executor.go:426 | #: pkg/build/script_executor.go:410 pkg/build/script_executor.go:430 | ||||||
| msgid "Executing %s()" | msgid "Executing %s()" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: pkg/repos/pull.go:80 | #: pkg/repos/pull.go:77 | ||||||
| msgid "Pulling repository" | msgid "Pulling repository" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: pkg/repos/pull.go:116 | #: pkg/repos/pull.go:113 | ||||||
| msgid "Repository up to date" | msgid "Repository up to date" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: pkg/repos/pull.go:207 | #: pkg/repos/pull.go:204 | ||||||
| msgid "Git repository does not appear to be a valid ALR repo" | msgid "Git repository does not appear to be a valid ALR repo" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: pkg/repos/pull.go:223 | #: pkg/repos/pull.go:220 | ||||||
| msgid "" | msgid "" | ||||||
| "ALR repo's minimum ALR version is greater than the current version. Try " | "ALR repo's minimum ALR version is greater than the current version. Try " | ||||||
| "updating ALR if something doesn't work." | "updating ALR if something doesn't work." | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: repo.go:39 | #: refresh.go:30 | ||||||
| msgid "Add a new repository" | msgid "Pull all repositories that have changed" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: repo.go:46 | #: repo.go:39 | ||||||
| msgid "Name of the new repo" | msgid "Manage repos" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
|  | #: repo.go:50 repo.go:220 | ||||||
|  | msgid "Remove an existing repository" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: repo.go:52 | #: repo.go:52 | ||||||
| msgid "URL of the new repo" | msgid "<name>" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: repo.go:75 | #: repo.go:82 | ||||||
| msgid "Repo \"%s\" already exists" | msgid "Repo \"%s\" does not exist" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: repo.go:86 repo.go:159 | #: repo.go:89 | ||||||
|  | msgid "Error removing repo directory" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
|  | #: repo.go:93 repo.go:160 | ||||||
| msgid "Error saving config" | msgid "Error saving config" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: repo.go:112 | #: repo.go:112 | ||||||
| msgid "Remove an existing repository" |  | ||||||
| msgstr "" |  | ||||||
|  |  | ||||||
| #: repo.go:119 |  | ||||||
| msgid "Name of the repo to be deleted" |  | ||||||
| msgstr "" |  | ||||||
|  |  | ||||||
| #: repo.go:148 |  | ||||||
| msgid "Repo \"%s\" does not exist" |  | ||||||
| msgstr "" |  | ||||||
|  |  | ||||||
| #: repo.go:155 |  | ||||||
| msgid "Error removing repo directory" |  | ||||||
| msgstr "" |  | ||||||
|  |  | ||||||
| #: repo.go:178 |  | ||||||
| msgid "Error removing packages from database" | msgid "Error removing packages from database" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: repo.go:189 | #: repo.go:123 repo.go:190 | ||||||
| msgid "Pull all repositories that have changed" | msgid "Add a new repository" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
|  | #: repo.go:124 | ||||||
|  | msgid "<name> <url>" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
|  | #: repo.go:149 | ||||||
|  | msgid "Repo \"%s\" already exists" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
|  | #: repo.go:197 | ||||||
|  | msgid "Name of the new repo" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
|  | #: repo.go:203 | ||||||
|  | msgid "URL of the new repo" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
|  | #: repo.go:227 | ||||||
|  | msgid "Name of the repo to be deleted" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: search.go:40 | #: search.go:40 | ||||||
| @@ -495,22 +533,10 @@ msgstr "" | |||||||
| msgid "Search by provides" | msgid "Search by provides" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: search.go:71 |  | ||||||
| msgid "Format output using a Go template" |  | ||||||
| msgstr "" |  | ||||||
|  |  | ||||||
| #: search.go:130 | #: search.go:130 | ||||||
| msgid "Error while executing search" | msgid "Error while executing search" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: search.go:138 |  | ||||||
| msgid "Error parsing format template" |  | ||||||
| msgstr "" |  | ||||||
|  |  | ||||||
| #: search.go:153 |  | ||||||
| msgid "Error executing template" |  | ||||||
| msgstr "" |  | ||||||
|  |  | ||||||
| #: upgrade.go:47 | #: upgrade.go:47 | ||||||
| msgid "Upgrade all installed packages" | msgid "Upgrade all installed packages" | ||||||
| msgstr "" | msgstr "" | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ | |||||||
| msgid "" | msgid "" | ||||||
| msgstr "" | msgstr "" | ||||||
| "Project-Id-Version: unnamed project\n" | "Project-Id-Version: unnamed project\n" | ||||||
| "PO-Revision-Date: 2025-04-27 18:27+0300\n" | "PO-Revision-Date: 2025-05-13 23:24+0300\n" | ||||||
| "Last-Translator: Maxim Slipenko <maks1ms@alt-gnome.ru>\n" | "Last-Translator: Maxim Slipenko <maks1ms@alt-gnome.ru>\n" | ||||||
| "Language-Team: Russian\n" | "Language-Team: Russian\n" | ||||||
| "Language: ru\n" | "Language: ru\n" | ||||||
| @@ -45,23 +45,23 @@ msgstr "Ошибка при получении рабочего каталога | |||||||
| msgid "Cannot get absolute script path" | msgid "Cannot get absolute script path" | ||||||
| msgstr "Невозможно получить абсолютный путь к скрипту" | msgstr "Невозможно получить абсолютный путь к скрипту" | ||||||
|  |  | ||||||
| #: build.go:148 | #: build.go:152 | ||||||
| msgid "Package not found" | msgid "Package not found" | ||||||
| msgstr "Пакет не найден" | msgstr "Пакет не найден" | ||||||
|  |  | ||||||
| #: build.go:161 | #: build.go:165 | ||||||
| msgid "Nothing to build" | msgid "Nothing to build" | ||||||
| msgstr "Нечего собирать" | msgstr "Нечего собирать" | ||||||
|  |  | ||||||
| #: build.go:218 | #: build.go:222 | ||||||
| msgid "Error building package" | msgid "Error building package" | ||||||
| msgstr "Ошибка при сборке пакета" | msgstr "Ошибка при сборке пакета" | ||||||
|  |  | ||||||
| #: build.go:225 | #: build.go:229 | ||||||
| msgid "Error moving the package" | msgid "Error moving the package" | ||||||
| msgstr "Ошибка при перемещении пакета" | msgstr "Ошибка при перемещении пакета" | ||||||
|  |  | ||||||
| #: build.go:229 | #: build.go:233 | ||||||
| msgid "Done" | msgid "Done" | ||||||
| msgstr "Сделано" | msgstr "Сделано" | ||||||
|  |  | ||||||
| @@ -285,6 +285,12 @@ msgstr "КАТЕГОРИЯ" | |||||||
| msgid "OPTIONS" | msgid "OPTIONS" | ||||||
| msgstr "ПАРАМЕТРЫ" | msgstr "ПАРАМЕТРЫ" | ||||||
|  |  | ||||||
|  | #: internal/cliutils/utils.go:69 | ||||||
|  | msgid "" | ||||||
|  | "This command is deprecated and would be removed in the future, use \"%s\" " | ||||||
|  | "instead!" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
| #: internal/db/db.go:137 | #: internal/db/db.go:137 | ||||||
| msgid "Database version mismatch; resetting" | msgid "Database version mismatch; resetting" | ||||||
| msgstr "Несоответствие версий базы данных; сброс настроек" | msgstr "Несоответствие версий базы данных; сброс настроек" | ||||||
| @@ -335,10 +341,30 @@ msgstr "Вы должны быть членом %s чтобы выполнить | |||||||
| msgid "You need to be root to perform this action" | msgid "You need to be root to perform this action" | ||||||
| msgstr "Вы должны быть root чтобы выполнить это" | msgstr "Вы должны быть root чтобы выполнить это" | ||||||
|  |  | ||||||
| #: list.go:41 | #: list.go:43 | ||||||
| msgid "List ALR repo packages" | msgid "List ALR repo packages" | ||||||
| msgstr "Список пакетов репозитория ALR" | msgstr "Список пакетов репозитория ALR" | ||||||
|  |  | ||||||
|  | #: list.go:57 | ||||||
|  | msgid "Format output using a Go template" | ||||||
|  | msgstr "Формат выходных данных с использованием шаблона Go" | ||||||
|  |  | ||||||
|  | #: list.go:89 | ||||||
|  | msgid "Error getting packages for upgrade" | ||||||
|  | msgstr "Ошибка при получении пакетов для обновления" | ||||||
|  |  | ||||||
|  | #: list.go:92 | ||||||
|  | msgid "No packages for upgrade" | ||||||
|  | msgstr "Нет пакетов к обновлению" | ||||||
|  |  | ||||||
|  | #: list.go:102 list.go:187 | ||||||
|  | msgid "Error parsing format template" | ||||||
|  | msgstr "Ошибка при разборе шаблона" | ||||||
|  |  | ||||||
|  | #: list.go:108 list.go:191 | ||||||
|  | msgid "Error executing template" | ||||||
|  | msgstr "Ошибка при выполнении шаблона" | ||||||
|  |  | ||||||
| #: main.go:45 | #: main.go:45 | ||||||
| msgid "Print the current ALR version and exit" | msgid "Print the current ALR version and exit" | ||||||
| msgstr "Показать текущую версию ALR и выйти" | msgstr "Показать текущую версию ALR и выйти" | ||||||
| @@ -351,11 +377,11 @@ msgstr "Аргументы, которые будут переданы мене | |||||||
| msgid "Enable interactive questions and prompts" | msgid "Enable interactive questions and prompts" | ||||||
| msgstr "Включение интерактивных вопросов и запросов" | msgstr "Включение интерактивных вопросов и запросов" | ||||||
|  |  | ||||||
| #: main.go:145 | #: main.go:146 | ||||||
| msgid "Show help" | msgid "Show help" | ||||||
| msgstr "Показать справку" | msgstr "Показать справку" | ||||||
|  |  | ||||||
| #: main.go:149 | #: main.go:150 | ||||||
| msgid "Error while running app" | msgid "Error while running app" | ||||||
| msgstr "Ошибка при запуске приложения" | msgstr "Ошибка при запуске приложения" | ||||||
|  |  | ||||||
| @@ -409,35 +435,35 @@ msgid "AutoReq is not implemented for this package format, so it's skipped" | |||||||
| msgstr "" | msgstr "" | ||||||
| "AutoReq не реализовано для этого формата пакета, поэтому будет пропущено" | "AutoReq не реализовано для этого формата пакета, поэтому будет пропущено" | ||||||
|  |  | ||||||
| #: pkg/build/script_executor.go:237 | #: pkg/build/script_executor.go:241 | ||||||
| msgid "Building package metadata" | msgid "Building package metadata" | ||||||
| msgstr "Сборка метаданных пакета" | msgstr "Сборка метаданных пакета" | ||||||
|  |  | ||||||
| #: pkg/build/script_executor.go:368 | #: pkg/build/script_executor.go:372 | ||||||
| msgid "Executing prepare()" | msgid "Executing prepare()" | ||||||
| msgstr "Выполнение prepare()" | msgstr "Выполнение prepare()" | ||||||
|  |  | ||||||
| #: pkg/build/script_executor.go:377 | #: pkg/build/script_executor.go:381 | ||||||
| msgid "Executing build()" | msgid "Executing build()" | ||||||
| msgstr "Выполнение build()" | msgstr "Выполнение build()" | ||||||
|  |  | ||||||
| #: pkg/build/script_executor.go:406 pkg/build/script_executor.go:426 | #: pkg/build/script_executor.go:410 pkg/build/script_executor.go:430 | ||||||
| msgid "Executing %s()" | msgid "Executing %s()" | ||||||
| msgstr "Выполнение %s()" | msgstr "Выполнение %s()" | ||||||
|  |  | ||||||
| #: pkg/repos/pull.go:80 | #: pkg/repos/pull.go:77 | ||||||
| msgid "Pulling repository" | msgid "Pulling repository" | ||||||
| msgstr "Скачивание репозитория" | msgstr "Скачивание репозитория" | ||||||
|  |  | ||||||
| #: pkg/repos/pull.go:116 | #: pkg/repos/pull.go:113 | ||||||
| msgid "Repository up to date" | msgid "Repository up to date" | ||||||
| msgstr "Репозиторий уже обновлён" | msgstr "Репозиторий уже обновлён" | ||||||
|  |  | ||||||
| #: pkg/repos/pull.go:207 | #: pkg/repos/pull.go:204 | ||||||
| msgid "Git repository does not appear to be a valid ALR repo" | msgid "Git repository does not appear to be a valid ALR repo" | ||||||
| msgstr "Репозиторий Git не поддерживается репозиторием ALR" | msgstr "Репозиторий Git не поддерживается репозиторием ALR" | ||||||
|  |  | ||||||
| #: pkg/repos/pull.go:223 | #: pkg/repos/pull.go:220 | ||||||
| msgid "" | msgid "" | ||||||
| "ALR repo's minimum ALR version is greater than the current version. Try " | "ALR repo's minimum ALR version is greater than the current version. Try " | ||||||
| "updating ALR if something doesn't work." | "updating ALR if something doesn't work." | ||||||
| @@ -445,49 +471,61 @@ msgstr "" | |||||||
| "Минимальная версия ALR для ALR-репозитория выше текущей версии. Попробуйте " | "Минимальная версия ALR для ALR-репозитория выше текущей версии. Попробуйте " | ||||||
| "обновить ALR, если что-то не работает." | "обновить ALR, если что-то не работает." | ||||||
|  |  | ||||||
| #: repo.go:39 | #: refresh.go:30 | ||||||
| msgid "Add a new repository" | msgid "Pull all repositories that have changed" | ||||||
| msgstr "Добавить новый репозиторий" | msgstr "Скачать все изменённые репозитории" | ||||||
|  |  | ||||||
| #: repo.go:46 | #: repo.go:39 | ||||||
| msgid "Name of the new repo" | msgid "Manage repos" | ||||||
| msgstr "Название нового репозитория" | msgstr "" | ||||||
|  |  | ||||||
|  | #: repo.go:50 repo.go:220 | ||||||
|  | msgid "Remove an existing repository" | ||||||
|  | msgstr "Удалить существующий репозиторий" | ||||||
|  |  | ||||||
| #: repo.go:52 | #: repo.go:52 | ||||||
| msgid "URL of the new repo" | msgid "<name>" | ||||||
| msgstr "URL-адрес нового репозитория" | msgstr "" | ||||||
|  |  | ||||||
| #: repo.go:75 | #: repo.go:82 | ||||||
| msgid "Repo \"%s\" already exists" | msgid "Repo \"%s\" does not exist" | ||||||
| msgstr "Репозиторий \"%s\" уже существует" | msgstr "Репозитория \"%s\" не существует" | ||||||
|  |  | ||||||
| #: repo.go:86 repo.go:159 | #: repo.go:89 | ||||||
|  | msgid "Error removing repo directory" | ||||||
|  | msgstr "Ошибка при удалении каталога репозитория" | ||||||
|  |  | ||||||
|  | #: repo.go:93 repo.go:160 | ||||||
| msgid "Error saving config" | msgid "Error saving config" | ||||||
| msgstr "Ошибка при сохранении конфигурации" | msgstr "Ошибка при сохранении конфигурации" | ||||||
|  |  | ||||||
| #: repo.go:112 | #: repo.go:112 | ||||||
| msgid "Remove an existing repository" |  | ||||||
| msgstr "Удалить существующий репозиторий" |  | ||||||
|  |  | ||||||
| #: repo.go:119 |  | ||||||
| msgid "Name of the repo to be deleted" |  | ||||||
| msgstr "Название репозитория  удалён" |  | ||||||
|  |  | ||||||
| #: repo.go:148 |  | ||||||
| msgid "Repo \"%s\" does not exist" |  | ||||||
| msgstr "Репозитория \"%s\" не существует" |  | ||||||
|  |  | ||||||
| #: repo.go:155 |  | ||||||
| msgid "Error removing repo directory" |  | ||||||
| msgstr "Ошибка при удалении каталога репозитория" |  | ||||||
|  |  | ||||||
| #: repo.go:178 |  | ||||||
| msgid "Error removing packages from database" | msgid "Error removing packages from database" | ||||||
| msgstr "Ошибка при удалении пакетов из базы данных" | msgstr "Ошибка при удалении пакетов из базы данных" | ||||||
|  |  | ||||||
| #: repo.go:189 | #: repo.go:123 repo.go:190 | ||||||
| msgid "Pull all repositories that have changed" | msgid "Add a new repository" | ||||||
| msgstr "Скачать все изменённые репозитории" | msgstr "Добавить новый репозиторий" | ||||||
|  |  | ||||||
|  | #: repo.go:124 | ||||||
|  | msgid "<name> <url>" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
|  | #: repo.go:149 | ||||||
|  | msgid "Repo \"%s\" already exists" | ||||||
|  | msgstr "Репозиторий \"%s\" уже существует" | ||||||
|  |  | ||||||
|  | #: repo.go:197 | ||||||
|  | msgid "Name of the new repo" | ||||||
|  | msgstr "Название нового репозитория" | ||||||
|  |  | ||||||
|  | #: repo.go:203 | ||||||
|  | msgid "URL of the new repo" | ||||||
|  | msgstr "URL-адрес нового репозитория" | ||||||
|  |  | ||||||
|  | #: repo.go:227 | ||||||
|  | msgid "Name of the repo to be deleted" | ||||||
|  | msgstr "Название репозитория  удалён" | ||||||
|  |  | ||||||
| #: search.go:40 | #: search.go:40 | ||||||
| msgid "Search packages" | msgid "Search packages" | ||||||
| @@ -509,22 +547,10 @@ msgstr "Искать по репозиторию" | |||||||
| msgid "Search by provides" | msgid "Search by provides" | ||||||
| msgstr "Иcкать по provides" | msgstr "Иcкать по provides" | ||||||
|  |  | ||||||
| #: search.go:71 |  | ||||||
| msgid "Format output using a Go template" |  | ||||||
| msgstr "Формат выходных данных с использованием шаблона Go" |  | ||||||
|  |  | ||||||
| #: search.go:130 | #: search.go:130 | ||||||
| msgid "Error while executing search" | msgid "Error while executing search" | ||||||
| msgstr "Ошибка при выполнении поиска" | msgstr "Ошибка при выполнении поиска" | ||||||
|  |  | ||||||
| #: search.go:138 |  | ||||||
| msgid "Error parsing format template" |  | ||||||
| msgstr "Ошибка при разборе шаблона" |  | ||||||
|  |  | ||||||
| #: search.go:153 |  | ||||||
| msgid "Error executing template" |  | ||||||
| msgstr "Ошибка при выполнении шаблона" |  | ||||||
|  |  | ||||||
| #: upgrade.go:47 | #: upgrade.go:47 | ||||||
| msgid "Upgrade all installed packages" | msgid "Upgrade all installed packages" | ||||||
| msgstr "Обновить все установленные пакеты" | msgstr "Обновить все установленные пакеты" | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| ALR - Any Linux Repository | ALR - Any Linux Repository | ||||||
| Copyright (C) {{ .Year }} Евгений Храмов | Copyright (C) {{ .Year }} The ALR Authors | ||||||
|  |  | ||||||
| This program is free software: you can redistribute it and/or modify | 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 | it under the terms of the GNU General Public License as published by | ||||||
|   | |||||||
							
								
								
									
										72
									
								
								list.go
									
									
									
									
									
								
							
							
						
						
									
										72
									
								
								list.go
									
									
									
									
									
								
							| @@ -22,10 +22,12 @@ package main | |||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"log/slog" | 	"log/slog" | ||||||
|  | 	"os" | ||||||
|  | 	"slices" | ||||||
|  | 	"text/template" | ||||||
|  |  | ||||||
| 	"github.com/leonelquinteros/gotext" | 	"github.com/leonelquinteros/gotext" | ||||||
| 	"github.com/urfave/cli/v2" | 	"github.com/urfave/cli/v2" | ||||||
| 	"golang.org/x/exp/slices" |  | ||||||
|  |  | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils" | ||||||
| 	appbuilder "gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils/app_builder" | 	appbuilder "gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils/app_builder" | ||||||
| @@ -45,6 +47,15 @@ func ListCmd() *cli.Command { | |||||||
| 				Name:    "installed", | 				Name:    "installed", | ||||||
| 				Aliases: []string{"I"}, | 				Aliases: []string{"I"}, | ||||||
| 			}, | 			}, | ||||||
|  | 			&cli.BoolFlag{ | ||||||
|  | 				Name:    "upgradable", | ||||||
|  | 				Aliases: []string{"U"}, | ||||||
|  | 			}, | ||||||
|  | 			&cli.StringFlag{ | ||||||
|  | 				Name:    "format", | ||||||
|  | 				Aliases: []string{"f"}, | ||||||
|  | 				Usage:   gotext.Get("Format output using a Go template"), | ||||||
|  | 			}, | ||||||
| 		}, | 		}, | ||||||
| 		Action: func(c *cli.Context) error { | 		Action: func(c *cli.Context) error { | ||||||
| 			if err := utils.ExitIfCantDropCapsToAlrUserNoPrivs(); err != nil { | 			if err := utils.ExitIfCantDropCapsToAlrUserNoPrivs(); err != nil { | ||||||
| @@ -57,8 +68,10 @@ func ListCmd() *cli.Command { | |||||||
| 				New(ctx). | 				New(ctx). | ||||||
| 				WithConfig(). | 				WithConfig(). | ||||||
| 				WithDB(). | 				WithDB(). | ||||||
|  | 				WithManager(). | ||||||
| 				// autoPull only | 				// autoPull only | ||||||
| 				WithRepos(). | 				WithRepos(). | ||||||
|  | 				WithDistroInfo(). | ||||||
| 				Build() | 				Build() | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return err | 				return err | ||||||
| @@ -67,6 +80,39 @@ func ListCmd() *cli.Command { | |||||||
|  |  | ||||||
| 			cfg := deps.Cfg | 			cfg := deps.Cfg | ||||||
| 			db := deps.DB | 			db := deps.DB | ||||||
|  | 			mgr := deps.Manager | ||||||
|  | 			info := deps.Info | ||||||
|  |  | ||||||
|  | 			if c.Bool("upgradable") { | ||||||
|  | 				updates, err := checkForUpdates(ctx, mgr, db, info) | ||||||
|  | 				if err != nil { | ||||||
|  | 					return cliutils.FormatCliExit(gotext.Get("Error getting packages for upgrade"), err) | ||||||
|  | 				} | ||||||
|  | 				if len(updates) == 0 { | ||||||
|  | 					slog.Info(gotext.Get("No packages for upgrade")) | ||||||
|  | 					return nil | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				format := c.String("format") | ||||||
|  | 				if format == "" { | ||||||
|  | 					format = "{{.Package.Repository}}/{{.Package.Name}} {{.FromVersion}} -> {{.ToVersion}}\n" | ||||||
|  | 				} | ||||||
|  | 				tmpl, err := template.New("format").Parse(format) | ||||||
|  | 				if err != nil { | ||||||
|  | 					return cliutils.FormatCliExit(gotext.Get("Error parsing format template"), err) | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				for _, updateInfo := range updates { | ||||||
|  | 					err = tmpl.Execute(os.Stdout, updateInfo) | ||||||
|  | 					if err != nil { | ||||||
|  | 						return cliutils.FormatCliExit(gotext.Get("Error executing template"), err) | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				return nil | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// TODO: refactor code below | ||||||
|  |  | ||||||
| 			where := "true" | 			where := "true" | ||||||
| 			args := []any(nil) | 			args := []any(nil) | ||||||
| @@ -115,17 +161,35 @@ func ListCmd() *cli.Command { | |||||||
| 					continue | 					continue | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
| 				version := pkg.Version | 				type packageInfo struct { | ||||||
|  | 					Package *database.Package | ||||||
|  | 					Version string | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				pkgInfo := &packageInfo{} | ||||||
|  | 				pkgInfo.Package = &pkg | ||||||
|  | 				pkgInfo.Version = pkg.Version | ||||||
| 				if c.Bool("installed") { | 				if c.Bool("installed") { | ||||||
| 					instVersion, ok := installedAlrPackages[fmt.Sprintf("%s/%s", pkg.Repository, pkg.Name)] | 					instVersion, ok := installedAlrPackages[fmt.Sprintf("%s/%s", pkg.Repository, pkg.Name)] | ||||||
| 					if !ok { | 					if !ok { | ||||||
| 						continue | 						continue | ||||||
| 					} else { | 					} else { | ||||||
| 						version = instVersion | 						pkgInfo.Version = instVersion | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
| 				fmt.Printf("%s/%s %s\n", pkg.Repository, pkg.Name, version) | 				format := c.String("format") | ||||||
|  | 				if format == "" { | ||||||
|  | 					format = "{{.Package.Repository}}/{{.Package.Name}} {{.Version}}\n" | ||||||
|  | 				} | ||||||
|  | 				tmpl, err := template.New("format").Parse(format) | ||||||
|  | 				if err != nil { | ||||||
|  | 					return cliutils.FormatCliExit(gotext.Get("Error parsing format template"), err) | ||||||
|  | 				} | ||||||
|  | 				err = tmpl.Execute(os.Stdout, pkgInfo) | ||||||
|  | 				if err != nil { | ||||||
|  | 					return cliutils.FormatCliExit(gotext.Get("Error executing template"), err) | ||||||
|  | 				} | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			return nil | 			return nil | ||||||
|   | |||||||
							
								
								
									
										5
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								main.go
									
									
									
									
									
								
							| @@ -74,14 +74,15 @@ func GetApp() *cli.App { | |||||||
| 			InfoCmd(), | 			InfoCmd(), | ||||||
| 			ListCmd(), | 			ListCmd(), | ||||||
| 			BuildCmd(), | 			BuildCmd(), | ||||||
| 			AddRepoCmd(), | 			LegacyAddRepoCmd(), | ||||||
| 			RemoveRepoCmd(), | 			LegacyRemoveRepoCmd(), | ||||||
| 			RefreshCmd(), | 			RefreshCmd(), | ||||||
| 			FixCmd(), | 			FixCmd(), | ||||||
| 			GenCmd(), | 			GenCmd(), | ||||||
| 			HelperCmd(), | 			HelperCmd(), | ||||||
| 			VersionCmd(), | 			VersionCmd(), | ||||||
| 			SearchCmd(), | 			SearchCmd(), | ||||||
|  | 			RepoCmd(), | ||||||
| 			// Internal commands | 			// Internal commands | ||||||
| 			InternalBuildCmd(), | 			InternalBuildCmd(), | ||||||
| 			InternalInstallCmd(), | 			InternalInstallCmd(), | ||||||
|   | |||||||
| @@ -118,16 +118,20 @@ func (e *LocalScriptExecutor) ExecuteFirstPass(ctx context.Context, input *Build | |||||||
| 		return vars.Name, varsOfPackages, nil | 		return vars.Name, varsOfPackages, nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if len(input.packages) == 0 { | 	var pkgNames []string | ||||||
| 		return "", nil, errors.New("script has multiple packages but package is not specified") |  | ||||||
|  | 	if len(input.packages) != 0 { | ||||||
|  | 		pkgNames = input.packages | ||||||
|  | 	} else { | ||||||
|  | 		pkgNames = pkgs.Names | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	for _, pkgName := range input.packages { | 	for _, pkgName := range pkgNames { | ||||||
| 		var preVars types.BuildVarsPre | 		var preVars types.BuildVarsPre | ||||||
| 		funcName := fmt.Sprintf("meta_%s", pkgName) | 		funcName := fmt.Sprintf("meta_%s", pkgName) | ||||||
| 		meta, ok := dec.GetFuncWithSubshell(funcName) | 		meta, ok := dec.GetFuncWithSubshell(funcName) | ||||||
| 		if !ok { | 		if !ok { | ||||||
| 			return "", nil, errors.New("func is missing") | 			return "", nil, fmt.Errorf("func %s is missing", funcName) | ||||||
| 		} | 		} | ||||||
| 		r, err := meta(ctx) | 		r, err := meta(ctx) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
|   | |||||||
							
								
								
									
										38
									
								
								pkg/parser/parser.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								pkg/parser/parser.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | |||||||
|  | // 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 parser | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  |  | ||||||
|  | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/shutils/decoder" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type PackageNames struct { | ||||||
|  | 	BasePkgName string   `sh:"basepkg_name"` | ||||||
|  | 	Names       []string `sh:"name"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func ParseNames(dec *decoder.Decoder) (*PackageNames, error) { | ||||||
|  | 	var pkgs PackageNames | ||||||
|  | 	err := dec.DecodeVars(&pkgs) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, fmt.Errorf("fail parse names: %w", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return &pkgs, nil | ||||||
|  | } | ||||||
| @@ -43,11 +43,8 @@ import ( | |||||||
| 	"mvdan.cc/sh/v3/syntax" | 	"mvdan.cc/sh/v3/syntax" | ||||||
|  |  | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/config" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/config" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/db" |  | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/shutils/decoder" |  | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/shutils/handlers" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/shutils/handlers" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/types" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/types" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type actionType uint8 | type actionType uint8 | ||||||
| @@ -231,79 +228,19 @@ func (rs *Repos) Pull(ctx context.Context, repos []types.Repo) error { | |||||||
| func (rs *Repos) updatePkg(ctx context.Context, repo types.Repo, runner *interp.Runner, scriptFl io.ReadCloser) error { | func (rs *Repos) updatePkg(ctx context.Context, repo types.Repo, runner *interp.Runner, scriptFl io.ReadCloser) error { | ||||||
| 	parser := syntax.NewParser() | 	parser := syntax.NewParser() | ||||||
|  |  | ||||||
| 	defer scriptFl.Close() | 	pkgs, err := parseScript(ctx, repo, parser, runner, scriptFl) | ||||||
| 	fl, err := parser.Parse(scriptFl, "alr.sh") |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	runner.Reset() | 	for _, pkg := range pkgs { | ||||||
| 	err = runner.Run(ctx, fl) | 		err = rs.db.InsertPackage(ctx, *pkg) | ||||||
| 	if err != nil { | 		if err != nil { | ||||||
| 		return err | 			return err | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	type packages struct { |  | ||||||
| 		BasePkgName string   `sh:"basepkg_name"` |  | ||||||
| 		Names       []string `sh:"name"` |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var pkgs packages |  | ||||||
|  |  | ||||||
| 	d := decoder.New(&distro.OSRelease{}, runner) |  | ||||||
| 	d.Overrides = false |  | ||||||
| 	d.LikeDistros = false |  | ||||||
| 	err = d.DecodeVars(&pkgs) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(pkgs.Names) > 1 { |  | ||||||
| 		if pkgs.BasePkgName == "" { |  | ||||||
| 			pkgs.BasePkgName = pkgs.Names[0] |  | ||||||
| 		} | 		} | ||||||
| 		for _, pkgName := range pkgs.Names { |  | ||||||
| 			pkgInfo := PackageInfo{} |  | ||||||
| 			funcName := fmt.Sprintf("meta_%s", pkgName) |  | ||||||
| 			runner.Reset() |  | ||||||
| 			err = runner.Run(ctx, fl) |  | ||||||
| 			if err != nil { |  | ||||||
| 				return err |  | ||||||
| 			} |  | ||||||
| 			meta, ok := d.GetFuncWithSubshell(funcName) |  | ||||||
| 			if !ok { |  | ||||||
| 				return errors.New("func is missing") |  | ||||||
| 			} |  | ||||||
| 			r, err := meta(ctx) |  | ||||||
| 			if err != nil { |  | ||||||
| 				return err |  | ||||||
| 			} |  | ||||||
| 			d := decoder.New(&distro.OSRelease{}, r) |  | ||||||
| 			d.Overrides = false |  | ||||||
| 			d.LikeDistros = false |  | ||||||
| 			err = d.DecodeVars(&pkgInfo) |  | ||||||
| 			if err != nil { |  | ||||||
| 				return err |  | ||||||
| 			} |  | ||||||
| 			pkg := pkgInfo.ToPackage(repo.Name) |  | ||||||
| 			resolveOverrides(r, pkg) |  | ||||||
| 			pkg.Name = pkgName |  | ||||||
| 			pkg.BasePkgName = pkgs.BasePkgName |  | ||||||
| 			err = rs.db.InsertPackage(ctx, *pkg) |  | ||||||
| 			if err != nil { |  | ||||||
| 				return err |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		return nil |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	pkg := EmptyPackage(repo.Name) | 	return nil | ||||||
| 	err = d.DecodeVars(pkg) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	resolveOverrides(runner, pkg) |  | ||||||
| 	return rs.db.InsertPackage(ctx, *pkg) |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func (rs *Repos) processRepoChangesRunner(repoDir, scriptDir string) (*interp.Runner, error) { | func (rs *Repos) processRepoChangesRunner(repoDir, scriptDir string) (*interp.Runner, error) { | ||||||
| @@ -399,15 +336,16 @@ func (rs *Repos) processRepoChanges(ctx context.Context, repo types.Repo, r *git | |||||||
| 				return nil | 				return nil | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			var pkg db.Package | 			pkgs, err := parseScript(ctx, repo, parser, runner, r) | ||||||
| 			err = parseScript(ctx, parser, runner, r, &pkg) |  | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return err | 				return err | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			err = rs.db.DeletePkgs(ctx, "name = ? AND repository = ?", pkg.Name, repo.Name) | 			for _, pkg := range pkgs { | ||||||
| 			if err != nil { | 				err = rs.db.DeletePkgs(ctx, "name = ? AND repository = ?", pkg.Name, repo.Name) | ||||||
| 				return err | 				if err != nil { | ||||||
|  | 					return err | ||||||
|  | 				} | ||||||
| 			} | 			} | ||||||
| 		case actionUpdate: | 		case actionUpdate: | ||||||
| 			if filepath.Base(action.File) != "alr.sh" { | 			if filepath.Base(action.File) != "alr.sh" { | ||||||
|   | |||||||
| @@ -18,6 +18,7 @@ package repos | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
|  | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"io" | 	"io" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
| @@ -35,7 +36,9 @@ import ( | |||||||
|  |  | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/db" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/db" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/shutils/decoder" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/shutils/decoder" | ||||||
|  | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/types" | ||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro" | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro" | ||||||
|  | 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/parser" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // isValid makes sure the path of the file being updated is valid. | // isValid makes sure the path of the file being updated is valid. | ||||||
| @@ -54,23 +57,85 @@ func isValid(from, to diff.File) bool { | |||||||
| 	return match | 	return match | ||||||
| } | } | ||||||
|  |  | ||||||
| func parseScript(ctx context.Context, parser *syntax.Parser, runner *interp.Runner, r io.ReadCloser, pkg *db.Package) error { | func parseScript( | ||||||
| 	defer r.Close() | 	ctx context.Context, | ||||||
| 	fl, err := parser.Parse(r, "alr.sh") | 	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 { | 	if err != nil { | ||||||
| 		return err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	runner.Reset() | 	runner.Reset() | ||||||
| 	err = runner.Run(ctx, fl) | 	err = runner.Run(ctx, fl) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	d := decoder.New(&distro.OSRelease{}, runner) | 	d := decoder.New(&distro.OSRelease{}, runner) | ||||||
| 	d.Overrides = false | 	d.Overrides = false | ||||||
| 	d.LikeDistros = false | 	d.LikeDistros = false | ||||||
| 	return d.DecodeVars(pkg) |  | ||||||
|  | 	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 { | type PackageInfo struct { | ||||||
|   | |||||||
							
								
								
									
										52
									
								
								refresh.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								refresh.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | |||||||
|  | // ALR - Any Linux Repository | ||||||
|  | // Copyright (C) 2025 The ALR Authors | ||||||
|  | // | ||||||
|  | // This program is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or | ||||||
|  | // (at your option) any later version. | ||||||
|  | // | ||||||
|  | // This program is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  | // GNU General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU General Public License | ||||||
|  | // along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  | ||||||
|  | package main | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"github.com/leonelquinteros/gotext" | ||||||
|  | 	"github.com/urfave/cli/v2" | ||||||
|  |  | ||||||
|  | 	appbuilder "gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils/app_builder" | ||||||
|  | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/utils" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func RefreshCmd() *cli.Command { | ||||||
|  | 	return &cli.Command{ | ||||||
|  | 		Name:    "refresh", | ||||||
|  | 		Usage:   gotext.Get("Pull all repositories that have changed"), | ||||||
|  | 		Aliases: []string{"ref"}, | ||||||
|  | 		Action: func(c *cli.Context) error { | ||||||
|  | 			if err := utils.ExitIfCantDropCapsToAlrUser(); err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			ctx := c.Context | ||||||
|  |  | ||||||
|  | 			deps, err := appbuilder. | ||||||
|  | 				New(ctx). | ||||||
|  | 				WithConfig(). | ||||||
|  | 				WithDB(). | ||||||
|  | 				WithReposForcePull(). | ||||||
|  | 				Build() | ||||||
|  | 			if err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  | 			defer deps.Defer() | ||||||
|  | 			return nil | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										202
									
								
								repo.go
									
									
									
									
									
								
							
							
						
						
									
										202
									
								
								repo.go
									
									
									
									
									
								
							| @@ -33,96 +33,30 @@ import ( | |||||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/utils" | 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/utils" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func AddRepoCmd() *cli.Command { | func RepoCmd() *cli.Command { | ||||||
| 	return &cli.Command{ | 	return &cli.Command{ | ||||||
| 		Name:    "addrepo", | 		Name:  "repo", | ||||||
| 		Usage:   gotext.Get("Add a new repository"), | 		Usage: gotext.Get("Manage repos"), | ||||||
| 		Aliases: []string{"ar"}, | 		Subcommands: []*cli.Command{ | ||||||
| 		Flags: []cli.Flag{ | 			RemoveRepoCmd(), | ||||||
| 			&cli.StringFlag{ | 			AddRepoCmd(), | ||||||
| 				Name:     "name", |  | ||||||
| 				Aliases:  []string{"n"}, |  | ||||||
| 				Required: true, |  | ||||||
| 				Usage:    gotext.Get("Name of the new repo"), |  | ||||||
| 			}, |  | ||||||
| 			&cli.StringFlag{ |  | ||||||
| 				Name:     "url", |  | ||||||
| 				Aliases:  []string{"u"}, |  | ||||||
| 				Required: true, |  | ||||||
| 				Usage:    gotext.Get("URL of the new repo"), |  | ||||||
| 			}, |  | ||||||
| 		}, | 		}, | ||||||
| 		Action: utils.RootNeededAction(func(c *cli.Context) error { |  | ||||||
| 			name := c.String("name") |  | ||||||
| 			repoURL := c.String("url") |  | ||||||
|  |  | ||||||
| 			ctx := c.Context |  | ||||||
|  |  | ||||||
| 			deps, err := appbuilder. |  | ||||||
| 				New(ctx). |  | ||||||
| 				WithConfig(). |  | ||||||
| 				Build() |  | ||||||
| 			if err != nil { |  | ||||||
| 				return err |  | ||||||
| 			} |  | ||||||
| 			defer deps.Defer() |  | ||||||
|  |  | ||||||
| 			cfg := deps.Cfg |  | ||||||
|  |  | ||||||
| 			reposSlice := cfg.Repos() |  | ||||||
| 			for _, repo := range reposSlice { |  | ||||||
| 				if repo.URL == repoURL || repo.Name == name { |  | ||||||
| 					return cliutils.FormatCliExit(gotext.Get("Repo \"%s\" already exists", repo.Name), nil) |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 			reposSlice = append(reposSlice, types.Repo{ |  | ||||||
| 				Name: name, |  | ||||||
| 				URL:  repoURL, |  | ||||||
| 			}) |  | ||||||
| 			cfg.SetRepos(reposSlice) |  | ||||||
|  |  | ||||||
| 			err = cfg.SaveUserConfig() |  | ||||||
| 			if err != nil { |  | ||||||
| 				return cliutils.FormatCliExit(gotext.Get("Error saving config"), err) |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			if err := utils.ExitIfCantDropCapsToAlrUserNoPrivs(); err != nil { |  | ||||||
| 				return err |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			deps, err = appbuilder. |  | ||||||
| 				New(ctx). |  | ||||||
| 				UseConfig(cfg). |  | ||||||
| 				WithDB(). |  | ||||||
| 				WithReposForcePull(). |  | ||||||
| 				Build() |  | ||||||
| 			if err != nil { |  | ||||||
| 				return err |  | ||||||
| 			} |  | ||||||
| 			defer deps.Defer() |  | ||||||
|  |  | ||||||
| 			return nil |  | ||||||
| 		}), |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func RemoveRepoCmd() *cli.Command { | func RemoveRepoCmd() *cli.Command { | ||||||
| 	return &cli.Command{ | 	return &cli.Command{ | ||||||
| 		Name:    "removerepo", | 		Name:      "remove", | ||||||
| 		Usage:   gotext.Get("Remove an existing repository"), | 		Usage:     gotext.Get("Remove an existing repository"), | ||||||
| 		Aliases: []string{"rr"}, | 		Aliases:   []string{"rm"}, | ||||||
| 		Flags: []cli.Flag{ | 		ArgsUsage: gotext.Get("<name>"), | ||||||
| 			&cli.StringFlag{ |  | ||||||
| 				Name:     "name", |  | ||||||
| 				Aliases:  []string{"n"}, |  | ||||||
| 				Required: true, |  | ||||||
| 				Usage:    gotext.Get("Name of the repo to be deleted"), |  | ||||||
| 			}, |  | ||||||
| 		}, |  | ||||||
| 		Action: utils.RootNeededAction(func(c *cli.Context) error { | 		Action: utils.RootNeededAction(func(c *cli.Context) error { | ||||||
| 			ctx := c.Context | 			if c.Args().Len() < 1 { | ||||||
|  | 				return cliutils.FormatCliExit("missing args", nil) | ||||||
|  | 			} | ||||||
|  | 			name := c.Args().Get(0) | ||||||
|  |  | ||||||
| 			name := c.String("name") | 			ctx := c.Context | ||||||
|  |  | ||||||
| 			deps, err := appbuilder. | 			deps, err := appbuilder. | ||||||
| 				New(ctx). | 				New(ctx). | ||||||
| @@ -183,21 +117,56 @@ func RemoveRepoCmd() *cli.Command { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func RefreshCmd() *cli.Command { | func AddRepoCmd() *cli.Command { | ||||||
| 	return &cli.Command{ | 	return &cli.Command{ | ||||||
| 		Name:    "refresh", | 		Name:      "add", | ||||||
| 		Usage:   gotext.Get("Pull all repositories that have changed"), | 		Usage:     gotext.Get("Add a new repository"), | ||||||
| 		Aliases: []string{"ref"}, | 		ArgsUsage: gotext.Get("<name> <url>"), | ||||||
| 		Action: func(c *cli.Context) error { | 		Action: utils.RootNeededAction(func(c *cli.Context) error { | ||||||
| 			if err := utils.ExitIfCantDropCapsToAlrUser(); err != nil { | 			if c.Args().Len() < 2 { | ||||||
| 				return err | 				return cliutils.FormatCliExit("missing args", nil) | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|  | 			name := c.Args().Get(0) | ||||||
|  | 			repoURL := c.Args().Get(1) | ||||||
|  |  | ||||||
| 			ctx := c.Context | 			ctx := c.Context | ||||||
|  |  | ||||||
| 			deps, err := appbuilder. | 			deps, err := appbuilder. | ||||||
| 				New(ctx). | 				New(ctx). | ||||||
| 				WithConfig(). | 				WithConfig(). | ||||||
|  | 				Build() | ||||||
|  | 			if err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  | 			defer deps.Defer() | ||||||
|  |  | ||||||
|  | 			cfg := deps.Cfg | ||||||
|  |  | ||||||
|  | 			reposSlice := cfg.Repos() | ||||||
|  | 			for _, repo := range reposSlice { | ||||||
|  | 				if repo.URL == repoURL || repo.Name == name { | ||||||
|  | 					return cliutils.FormatCliExit(gotext.Get("Repo \"%s\" already exists", repo.Name), nil) | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			reposSlice = append(reposSlice, types.Repo{ | ||||||
|  | 				Name: name, | ||||||
|  | 				URL:  repoURL, | ||||||
|  | 			}) | ||||||
|  | 			cfg.SetRepos(reposSlice) | ||||||
|  |  | ||||||
|  | 			err = cfg.SaveUserConfig() | ||||||
|  | 			if err != nil { | ||||||
|  | 				return cliutils.FormatCliExit(gotext.Get("Error saving config"), err) | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if err := utils.ExitIfCantDropCapsToAlrUserNoPrivs(); err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			deps, err = appbuilder. | ||||||
|  | 				New(ctx). | ||||||
|  | 				UseConfig(cfg). | ||||||
| 				WithDB(). | 				WithDB(). | ||||||
| 				WithReposForcePull(). | 				WithReposForcePull(). | ||||||
| 				Build() | 				Build() | ||||||
| @@ -205,7 +174,62 @@ func RefreshCmd() *cli.Command { | |||||||
| 				return err | 				return err | ||||||
| 			} | 			} | ||||||
| 			defer deps.Defer() | 			defer deps.Defer() | ||||||
|  |  | ||||||
| 			return nil | 			return nil | ||||||
| 		}, | 		}), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // TODO: remove | ||||||
|  | // | ||||||
|  | // Deprecated: use "alr repo add" | ||||||
|  | func LegacyAddRepoCmd() *cli.Command { | ||||||
|  | 	return &cli.Command{ | ||||||
|  | 		Hidden:  true, | ||||||
|  | 		Name:    "addrepo", | ||||||
|  | 		Usage:   gotext.Get("Add a new repository"), | ||||||
|  | 		Aliases: []string{"ar"}, | ||||||
|  | 		Flags: []cli.Flag{ | ||||||
|  | 			&cli.StringFlag{ | ||||||
|  | 				Name:     "name", | ||||||
|  | 				Aliases:  []string{"n"}, | ||||||
|  | 				Required: true, | ||||||
|  | 				Usage:    gotext.Get("Name of the new repo"), | ||||||
|  | 			}, | ||||||
|  | 			&cli.StringFlag{ | ||||||
|  | 				Name:     "url", | ||||||
|  | 				Aliases:  []string{"u"}, | ||||||
|  | 				Required: true, | ||||||
|  | 				Usage:    gotext.Get("URL of the new repo"), | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		Action: utils.RootNeededAction(func(c *cli.Context) error { | ||||||
|  | 			cliutils.WarnLegacyCommand("alr repo add <name> <url>") | ||||||
|  | 			return c.App.RunContext(c.Context, []string{"", "repo", "add", c.String("name"), c.String("url")}) | ||||||
|  | 		}), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // TODO: remove | ||||||
|  | // | ||||||
|  | // Deprecated: use "alr repo rm" | ||||||
|  | func LegacyRemoveRepoCmd() *cli.Command { | ||||||
|  | 	return &cli.Command{ | ||||||
|  | 		Hidden:  true, | ||||||
|  | 		Name:    "removerepo", | ||||||
|  | 		Usage:   gotext.Get("Remove an existing repository"), | ||||||
|  | 		Aliases: []string{"rr"}, | ||||||
|  | 		Flags: []cli.Flag{ | ||||||
|  | 			&cli.StringFlag{ | ||||||
|  | 				Name:     "name", | ||||||
|  | 				Aliases:  []string{"n"}, | ||||||
|  | 				Required: true, | ||||||
|  | 				Usage:    gotext.Get("Name of the repo to be deleted"), | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		Action: utils.RootNeededAction(func(c *cli.Context) error { | ||||||
|  | 			cliutils.WarnLegacyCommand("alr repo remove <name>") | ||||||
|  | 			return c.App.RunContext(c.Context, []string{"", "repo", "remove", c.String("name")}) | ||||||
|  | 		}), | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										32
									
								
								upgrade.go
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								upgrade.go
									
									
									
									
									
								
							| @@ -116,7 +116,7 @@ func UpgradeCmd() *cli.Command { | |||||||
| 						Info:       deps.Info, | 						Info:       deps.Info, | ||||||
| 						PkgFormat_: build.GetPkgFormat(deps.Manager), | 						PkgFormat_: build.GetPkgFormat(deps.Manager), | ||||||
| 					}, | 					}, | ||||||
| 					updates, | 					mapUptatesInfoToPackages(updates), | ||||||
| 				) | 				) | ||||||
| 				if err != nil { | 				if err != nil { | ||||||
| 					return cliutils.FormatCliExit(gotext.Get("Error checking for updates"), err) | 					return cliutils.FormatCliExit(gotext.Get("Error checking for updates"), err) | ||||||
| @@ -130,12 +130,27 @@ func UpgradeCmd() *cli.Command { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func mapUptatesInfoToPackages(updates []UpdateInfo) []database.Package { | ||||||
|  | 	var pkgs []database.Package | ||||||
|  | 	for _, info := range updates { | ||||||
|  | 		pkgs = append(pkgs, *info.Package) | ||||||
|  | 	} | ||||||
|  | 	return pkgs | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type UpdateInfo struct { | ||||||
|  | 	Package *database.Package | ||||||
|  |  | ||||||
|  | 	FromVersion string | ||||||
|  | 	ToVersion   string | ||||||
|  | } | ||||||
|  |  | ||||||
| func checkForUpdates( | func checkForUpdates( | ||||||
| 	ctx context.Context, | 	ctx context.Context, | ||||||
| 	mgr manager.Manager, | 	mgr manager.Manager, | ||||||
| 	db *database.Database, | 	db *database.Database, | ||||||
| 	info *distro.OSRelease, | 	info *distro.OSRelease, | ||||||
| ) ([]database.Package, error) { | ) ([]UpdateInfo, error) { | ||||||
| 	installed, err := mgr.ListInstalled(nil) | 	installed, err := mgr.ListInstalled(nil) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| @@ -145,7 +160,7 @@ func checkForUpdates( | |||||||
|  |  | ||||||
| 	s := search.New(db) | 	s := search.New(db) | ||||||
|  |  | ||||||
| 	var out []database.Package | 	var out []UpdateInfo | ||||||
| 	for _, pkgName := range pkgNames { | 	for _, pkgName := range pkgNames { | ||||||
| 		matches := build.RegexpALRPackageName.FindStringSubmatch(pkgName) | 		matches := build.RegexpALRPackageName.FindStringSubmatch(pkgName) | ||||||
| 		if matches != nil { | 		if matches != nil { | ||||||
| @@ -179,10 +194,13 @@ func checkForUpdates( | |||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			c := vercmp.Compare(repoVer, installed[pkgName]) | 			c := vercmp.Compare(repoVer, installed[pkgName]) | ||||||
| 			if c == 0 || c == -1 { |  | ||||||
| 				continue | 			if c == 1 { | ||||||
| 			} else if c == 1 { | 				out = append(out, UpdateInfo{ | ||||||
| 				out = append(out, pkg) | 					Package:     &pkg, | ||||||
|  | 					FromVersion: installed[pkgName], | ||||||
|  | 					ToVersion:   repoVer, | ||||||
|  | 				}) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user