8 Commits

Author SHA1 Message Date
1e52d30f4c fix list command
All checks were successful
Pre-commit / pre-commit (pull_request) Successful in 1m35s
2025-05-13 23:31:56 +03:00
40ec0ac6e1 add --upgradable option for list
All checks were successful
Pre-commit / pre-commit (pull_request) Successful in 1m36s
2025-05-13 23:26:12 +03:00
443e481561 fix support of multiple packages in one alr.sh
All checks were successful
Pre-commit / pre-commit (pull_request) Successful in 1m37s
2025-05-13 21:55:23 +03:00
c892310f69 fix Makefile
All checks were successful
Pre-commit / pre-commit (pull_request) Successful in 2m49s
2025-05-12 20:11:55 +03:00
750513b119 fix ci
Some checks failed
Pre-commit / pre-commit (pull_request) Failing after 2m36s
2025-05-12 19:46:52 +03:00
ce1836b646 ci: use go 1.24
Some checks failed
Pre-commit / pre-commit (pull_request) Failing after 3m52s
2025-05-12 19:30:15 +03:00
56b9f3211c ci: add simple workflow for pre-commit
Some checks failed
Pre-commit / pre-commit (pull_request) Failing after 5m29s
2025-05-12 19:22:50 +03:00
fae63e28f9 fix license-header.tmpl 2025-05-12 19:22:28 +03:00
17 changed files with 471 additions and 157 deletions

View 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

View File

@@ -54,7 +54,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 +76,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 ./...

View File

@@ -11,7 +11,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="33.5" y="15" fill="#010101" fill-opacity=".3">coverage</text> <text x="33.5" y="15" fill="#010101" fill-opacity=".3">coverage</text>
<text x="33.5" y="14">coverage</text> <text x="33.5" y="14">coverage</text>
<text x="86" y="15" fill="#010101" fill-opacity=".3">17.0%</text> <text x="86" y="15" fill="#010101" fill-opacity=".3">17.1%</text>
<text x="86" y="14">17.0%</text> <text x="86" y="14">17.1%</text>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 926 B

After

Width:  |  Height:  |  Size: 926 B

View File

@@ -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,

View File

@@ -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"

View 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")
},
)
}

View 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)
},
)
}

View File

@@ -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

View File

@@ -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 ""
@@ -327,10 +327,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 ""
@@ -397,35 +417,35 @@ 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."
@@ -495,22 +515,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 ""

View File

@@ -5,15 +5,15 @@
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"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
"X-Generator: Gtranslator 48.0\n" "X-Generator: Gtranslator 48.0\n"
#: build.go:42 #: build.go:42
@@ -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 "Сделано"
@@ -335,10 +335,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 и выйти"
@@ -409,35 +429,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."
@@ -509,22 +529,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 "Обновить все установленные пакеты"

View File

@@ -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
View File

@@ -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

View File

@@ -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
View 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
}

View File

@@ -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)
if err != nil {
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) err = rs.db.InsertPackage(ctx, *pkg)
if err != nil { if err != nil {
return err 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,16 +336,17 @@ 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
} }
for _, pkg := range pkgs {
err = rs.db.DeletePkgs(ctx, "name = ? AND repository = ?", pkg.Name, repo.Name) err = rs.db.DeletePkgs(ctx, "name = ? AND repository = ?", pkg.Name, repo.Name)
if err != nil { if err != nil {
return err return err
} }
}
case actionUpdate: case actionUpdate:
if filepath.Base(action.File) != "alr.sh" { if filepath.Base(action.File) != "alr.sh" {
action.File = filepath.Join(filepath.Dir(action.File), "alr.sh") action.File = filepath.Join(filepath.Dir(action.File), "alr.sh")

View File

@@ -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 {

View File

@@ -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,
})
} }
} }