Merge pull request 'feat: add skiplists for auto_req and auto_prov' (#64) from Maks1mS/ALR:feat/add-skiplist into master

Reviewed-on: #64
This commit is contained in:
Евгений Храмов 2025-04-05 21:30:23 +00:00
commit 67e63d1831
14 changed files with 438 additions and 149 deletions

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

Before

Width:  |  Height:  |  Size: 926 B

After

Width:  |  Height:  |  Size: 926 B

@ -100,13 +100,19 @@ func e2eSpawn(runnable e2e.Runnable, command e2e.Command, timeout time.Duration,
var ALL_SYSTEMS []string = []string{
"ubuntu-24.04",
// "alt-sisyphus",
"alt-sisyphus",
"fedora-41",
// "archlinux",
// "alpine",
// "opensuse-leap",
// "redos-8",
}
var AUTOREQ_AUTOPROV_SYSTEMS []string = []string{
"alt-sisyphus",
"fedora-41",
}
var COMMON_SYSTEMS []string = []string{
"ubuntu-24.04",
}

@ -1,5 +1,6 @@
FROM registry.altlinux.org/sisyphus/alt:latest
RUN apt-get update && apt-get install -y ca-certificates
RUN apt-get update && apt-get install -y ca-certificates rpm-build
RUN useradd -m -s /bin/bash alr-user
USER alr-user
WORKDIR /home/alr-user
ENTRYPOINT ["tail", "-f", "/dev/null"]

@ -0,0 +1,8 @@
FROM fedora:41
RUN dnf install -y ca-certificates sudo rpm-build
RUN useradd -m -s /bin/bash alr-user && \
echo "alr-user ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/alr-user && \
chmod 0440 /etc/sudoers.d/alr-user
USER alr-user
WORKDIR /home/alr-user
ENTRYPOINT ["tail", "-f", "/dev/null"]

@ -0,0 +1,80 @@
// ALR - Any Linux Repository
// Copyright (C) 2025 Евгений Храмов
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//go:build e2e
package e2etests_test
import (
"testing"
"github.com/alecthomas/assert/v2"
"github.com/efficientgo/e2e"
)
func TestE2EIssue41AutoreqSkiplist(t *testing.T) {
dockerMultipleRun(
t,
"issue-41-autoreq-skiplist",
AUTOREQ_AUTOPROV_SYSTEMS,
func(t *testing.T, r e2e.Runnable) {
err := r.Exec(e2e.NewCommand(
"alr",
"addrepo",
"--name",
"alr-repo",
"--url",
"https://gitea.plemya-x.ru/Maks1mS/repo-for-tests.git",
))
assert.NoError(t, err)
err = r.Exec(e2e.NewCommand(
"alr",
"ref",
))
assert.NoError(t, err)
err = r.Exec(e2e.NewCommand(
"alr",
"build",
"-p",
"alr-repo/test-autoreq-autoprov",
))
assert.NoError(t, err)
err = r.Exec(e2e.NewCommand(
"sh",
"-c",
"rpm -qp --requires *.rpm | grep \"^/bin/sh$\"",
))
assert.NoError(t, err)
err = r.Exec(e2e.NewCommand(
"sh",
"-c",
"rpm -qp --requires *.rpm | grep \"^/bin/bash$\"",
))
assert.Error(t, err)
err = r.Exec(e2e.NewCommand(
"sh",
"-c",
"rpm -qp --requires *.rpm | grep \"^/bin/zsh$\"",
))
assert.Error(t, err)
},
)
}

@ -123,15 +123,29 @@ func (d *Decoder) DecodeVars(val any) error {
}
rVal := reflect.ValueOf(val).Elem()
return d.decodeStruct(rVal)
}
func (d *Decoder) decodeStruct(rVal reflect.Value) error {
for i := 0; i < rVal.NumField(); i++ {
field := rVal.Field(i)
fieldType := rVal.Type().Field(i)
// Пропускаем неэкспортируемые поля
if !fieldType.IsExported() {
continue
}
// Обрабатываем встроенные поля рекурсивно
if fieldType.Anonymous {
if field.Kind() == reflect.Struct {
if err := d.decodeStruct(field); err != nil {
return err
}
}
continue
}
name := fieldType.Name
tag := fieldType.Tag.Get("sh")
required := false
@ -160,7 +174,6 @@ func (d *Decoder) DecodeVars(val any) error {
field.Set(newVal.Elem())
}
return nil
}

@ -337,92 +337,92 @@ msgstr ""
msgid "Error while running app"
msgstr ""
#: pkg/build/build.go:156
#: pkg/build/build.go:157
msgid "Failed to prompt user to view build script"
msgstr ""
#: pkg/build/build.go:160
#: pkg/build/build.go:161
msgid "Building package"
msgstr ""
#: pkg/build/build.go:208
#: pkg/build/build.go:209
msgid "The checksums array must be the same length as sources"
msgstr ""
#: pkg/build/build.go:235
#: pkg/build/build.go:238
msgid "Downloading sources"
msgstr ""
#: pkg/build/build.go:257
#: pkg/build/build.go:260
msgid "Building package metadata"
msgstr ""
#: pkg/build/build.go:279
#: pkg/build/build.go:282
msgid "Compressing package"
msgstr ""
#: pkg/build/build.go:438
#: pkg/build/build.go:441
msgid ""
"Your system's CPU architecture doesn't match this package. Do you want to "
"build anyway?"
msgstr ""
#: pkg/build/build.go:452
#: pkg/build/build.go:455
msgid "This package is already installed"
msgstr ""
#: pkg/build/build.go:476
#: pkg/build/build.go:479
msgid "Installing build dependencies"
msgstr ""
#: pkg/build/build.go:521
#: pkg/build/build.go:524
msgid "Installing dependencies"
msgstr ""
#: pkg/build/build.go:602
#: pkg/build/build.go:605
msgid "Would you like to remove the build dependencies?"
msgstr ""
#: pkg/build/build.go:665
#: pkg/build/build.go:668
msgid "Executing prepare()"
msgstr ""
#: pkg/build/build.go:675
#: pkg/build/build.go:678
msgid "Executing build()"
msgstr ""
#: pkg/build/build.go:705 pkg/build/build.go:725
#: pkg/build/build.go:708 pkg/build/build.go:728
msgid "Executing %s()"
msgstr ""
#: pkg/build/build.go:784
#: pkg/build/build.go:787
msgid "Error installing native packages"
msgstr ""
#: pkg/build/build.go:808
#: pkg/build/build.go:811
msgid "Error installing package"
msgstr ""
#: pkg/build/build.go:867
msgid "AutoProv is not implemented for this package format, so it's skipped"
msgstr ""
#: pkg/build/build.go:878
msgid "AutoReq is not implemented for this package format, so it's skipped"
msgstr ""
#: pkg/build/findDeps.go:35
#: pkg/build/find_deps/alt_linux.go:35
msgid "Command not found on the system"
msgstr ""
#: pkg/build/findDeps.go:82
#: pkg/build/find_deps/alt_linux.go:86
msgid "Provided dependency found"
msgstr ""
#: pkg/build/findDeps.go:89
#: pkg/build/find_deps/alt_linux.go:93
msgid "Required dependency found"
msgstr ""
#: pkg/build/find_deps/empty.go:32
msgid "AutoProv is not implemented for this package format, so it's skipped"
msgstr ""
#: pkg/build/find_deps/empty.go:37
msgid "AutoReq is not implemented for this package format, so it's skipped"
msgstr ""
#: pkg/repos/pull.go:79
msgid "Pulling repository"
msgstr ""

@ -349,31 +349,31 @@ msgstr "Показать справку"
msgid "Error while running app"
msgstr "Ошибка при запуске приложения"
#: pkg/build/build.go:156
#: pkg/build/build.go:157
msgid "Failed to prompt user to view build script"
msgstr "Не удалось предложить пользователю просмотреть скрипт сборки"
#: pkg/build/build.go:160
#: pkg/build/build.go:161
msgid "Building package"
msgstr "Сборка пакета"
#: pkg/build/build.go:208
#: pkg/build/build.go:209
msgid "The checksums array must be the same length as sources"
msgstr "Массив контрольных сумм должен быть той же длины, что и источники"
#: pkg/build/build.go:235
#: pkg/build/build.go:238
msgid "Downloading sources"
msgstr "Скачивание источников"
#: pkg/build/build.go:257
#: pkg/build/build.go:260
msgid "Building package metadata"
msgstr "Сборка метаданных пакета"
#: pkg/build/build.go:279
#: pkg/build/build.go:282
msgid "Compressing package"
msgstr "Сжатие пакета"
#: pkg/build/build.go:438
#: pkg/build/build.go:441
msgid ""
"Your system's CPU architecture doesn't match this package. Do you want to "
"build anyway?"
@ -381,64 +381,64 @@ msgstr ""
"Архитектура процессора вашей системы не соответствует этому пакету. Вы все "
"равно хотите выполнить сборку?"
#: pkg/build/build.go:452
#: pkg/build/build.go:455
msgid "This package is already installed"
msgstr "Этот пакет уже установлен"
#: pkg/build/build.go:476
#: pkg/build/build.go:479
msgid "Installing build dependencies"
msgstr "Установка зависимостей сборки"
#: pkg/build/build.go:521
#: pkg/build/build.go:524
msgid "Installing dependencies"
msgstr "Установка зависимостей"
#: pkg/build/build.go:602
#: pkg/build/build.go:605
msgid "Would you like to remove the build dependencies?"
msgstr "Хотели бы вы удалить зависимости сборки?"
#: pkg/build/build.go:665
#: pkg/build/build.go:668
msgid "Executing prepare()"
msgstr "Исполнение prepare()"
#: pkg/build/build.go:675
#: pkg/build/build.go:678
msgid "Executing build()"
msgstr "Исполнение build()"
#: pkg/build/build.go:705 pkg/build/build.go:725
#: pkg/build/build.go:708 pkg/build/build.go:728
msgid "Executing %s()"
msgstr "Исполнение %s()"
#: pkg/build/build.go:784
#: pkg/build/build.go:787
msgid "Error installing native packages"
msgstr "Ошибка при установке нативных пакетов"
#: pkg/build/build.go:808
#: pkg/build/build.go:811
msgid "Error installing package"
msgstr "Ошибка при установке пакета"
#: pkg/build/build.go:867
#: pkg/build/find_deps/alt_linux.go:35
msgid "Command not found on the system"
msgstr "Команда не найдена в системе"
#: pkg/build/find_deps/alt_linux.go:86
msgid "Provided dependency found"
msgstr "Найденная предоставленная зависимость"
#: pkg/build/find_deps/alt_linux.go:93
msgid "Required dependency found"
msgstr "Найдена требуемая зависимость"
#: pkg/build/find_deps/empty.go:32
msgid "AutoProv is not implemented for this package format, so it's skipped"
msgstr ""
"AutoProv не реализовано для этого формата пакета, поэтому будет пропущено"
#: pkg/build/build.go:878
#: pkg/build/find_deps/empty.go:37
msgid "AutoReq is not implemented for this package format, so it's skipped"
msgstr ""
"AutoReq не реализовано для этого формата пакета, поэтому будет пропущено"
#: pkg/build/findDeps.go:35
msgid "Command not found on the system"
msgstr "Команда не найдена в системе"
#: pkg/build/findDeps.go:82
msgid "Provided dependency found"
msgstr "Найденная предоставленная зависимость"
#: pkg/build/findDeps.go:89
msgid "Required dependency found"
msgstr "Найдена требуемая зависимость"
#: pkg/repos/pull.go:79
msgid "Pulling repository"
msgstr "Скачивание репозитория"

@ -31,79 +31,44 @@ type BuildOpts struct {
}
type BuildVarsPre struct {
Version string `sh:"version,required"`
Release int `sh:"release,required"`
Epoch uint `sh:"epoch"`
Description string `sh:"desc"`
Homepage string `sh:"homepage"`
Maintainer string `sh:"maintainer"`
Architectures []string `sh:"architectures"`
Licenses []string `sh:"license"`
Provides []string `sh:"provides"`
Conflicts []string `sh:"conflicts"`
Depends []string `sh:"deps"`
BuildDepends []string `sh:"build_deps"`
OptDepends []string `sh:"opt_deps"`
Replaces []string `sh:"replaces"`
Sources []string `sh:"sources"`
Checksums []string `sh:"checksums"`
Backup []string `sh:"backup"`
Scripts Scripts `sh:"scripts"`
AutoReq []string `sh:"auto_req"`
AutoProv []string `sh:"auto_prov"`
Version string `sh:"version,required"`
Release int `sh:"release,required"`
Epoch uint `sh:"epoch"`
Description string `sh:"desc"`
Homepage string `sh:"homepage"`
Maintainer string `sh:"maintainer"`
Architectures []string `sh:"architectures"`
Licenses []string `sh:"license"`
Provides []string `sh:"provides"`
Conflicts []string `sh:"conflicts"`
Depends []string `sh:"deps"`
BuildDepends []string `sh:"build_deps"`
OptDepends []string `sh:"opt_deps"`
Replaces []string `sh:"replaces"`
Sources []string `sh:"sources"`
Checksums []string `sh:"checksums"`
Backup []string `sh:"backup"`
Scripts Scripts `sh:"scripts"`
AutoReq []string `sh:"auto_req"`
AutoProv []string `sh:"auto_prov"`
AutoReqSkipList []string `sh:"auto_req_skiplist"`
AutoProvSkipList []string `sh:"auto_prov_skiplist"`
}
func (bv *BuildVarsPre) ToBuildVars() BuildVars {
return BuildVars{
Name: "",
Version: bv.Version,
Release: bv.Release,
Epoch: bv.Epoch,
Description: bv.Description,
Homepage: bv.Homepage,
Maintainer: bv.Maintainer,
Architectures: bv.Architectures,
Licenses: bv.Licenses,
Provides: bv.Provides,
Conflicts: bv.Conflicts,
Depends: bv.Depends,
BuildDepends: bv.BuildDepends,
OptDepends: bv.OptDepends,
Replaces: bv.Replaces,
Sources: bv.Sources,
Checksums: bv.Checksums,
Backup: bv.Backup,
Scripts: bv.Scripts,
AutoReq: bv.AutoReq,
AutoProv: bv.AutoProv,
Name: "",
Base: "",
BuildVarsPre: *bv,
}
}
// BuildVars represents the script variables required
// to build a package
type BuildVars struct {
Name string `sh:"name,required"`
Version string `sh:"version,required"`
Release int `sh:"release,required"`
Epoch uint `sh:"epoch"`
Description string `sh:"desc"`
Homepage string `sh:"homepage"`
Maintainer string `sh:"maintainer"`
Architectures []string `sh:"architectures"`
Licenses []string `sh:"license"`
Provides []string `sh:"provides"`
Conflicts []string `sh:"conflicts"`
Depends []string `sh:"deps"`
BuildDepends []string `sh:"build_deps"`
OptDepends []string `sh:"opt_deps"`
Replaces []string `sh:"replaces"`
Sources []string `sh:"sources"`
Checksums []string `sh:"checksums"`
Backup []string `sh:"backup"`
Scripts Scripts `sh:"scripts"`
AutoReq []string `sh:"auto_req"`
AutoProv []string `sh:"auto_prov"`
Base string
Name string `sh:"name,required"`
Base string
BuildVarsPre
}
type Scripts struct {

@ -50,6 +50,7 @@ import (
"gitea.plemya-x.ru/Plemya-x/ALR/internal/shutils/handlers"
"gitea.plemya-x.ru/Plemya-x/ALR/internal/shutils/helpers"
"gitea.plemya-x.ru/Plemya-x/ALR/internal/types"
finddeps "gitea.plemya-x.ru/Plemya-x/ALR/pkg/build/find_deps"
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro"
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/manager"
)
@ -211,8 +212,10 @@ func (b *Builder) BuildPackage(ctx context.Context) ([]string, []string, error)
sources, checksums = removeDuplicatesSources(sources, checksums)
mergedVars := types.BuildVars{
Sources: sources,
Checksums: checksums,
BuildVarsPre: types.BuildVarsPre{
Sources: sources,
Checksums: checksums,
},
}
buildDeps, err := b.installBuildDeps(ctx, buildDepends) // Устанавливаем зависимости для сборки
@ -858,24 +861,18 @@ func (b *Builder) buildPkgMetadata(
pkgInfo.Overridables.Contents = contents
if len(vars.AutoProv) == 1 && decoder.IsTruthy(vars.AutoProv[0]) {
if pkgFormat == "rpm" {
err = rpmFindProvides(ctx, pkgInfo, dirs)
if err != nil {
return nil, err
}
} else {
slog.Info(gotext.Get("AutoProv is not implemented for this package format, so it's skipped"))
f := finddeps.New(b.info, pkgFormat)
err = f.FindProvides(ctx, pkgInfo, dirs, vars.AutoProvSkipList)
if err != nil {
return nil, err
}
}
if len(vars.AutoReq) == 1 && decoder.IsTruthy(vars.AutoReq[0]) {
if pkgFormat == "rpm" {
err = rpmFindRequires(ctx, pkgInfo, dirs)
if err != nil {
return nil, err
}
} else {
slog.Info(gotext.Get("AutoReq is not implemented for this package format, so it's skipped"))
f := finddeps.New(b.info, pkgFormat)
err = f.FindRequires(ctx, pkgInfo, dirs, vars.AutoReqSkipList)
if err != nil {
return nil, err
}
}

@ -14,7 +14,7 @@
// 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 build
package finddeps
import (
"bytes"
@ -30,7 +30,7 @@ import (
"gitea.plemya-x.ru/Plemya-x/ALR/internal/types"
)
func rpmFindDependencies(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Directories, command string, updateFunc func(string)) error {
func rpmFindDependenciesALTLinux(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Directories, command string, envs []string, updateFunc func(string)) error {
if _, err := exec.LookPath(command); err != nil {
slog.Info(gotext.Get("Command not found on the system"), "command", command)
return nil
@ -49,8 +49,8 @@ func rpmFindDependencies(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Dir
return nil
}
cmd := exec.Command(command)
cmd.Stdin = bytes.NewBufferString(strings.Join(paths, "\n"))
cmd := exec.CommandContext(ctx, command)
cmd.Stdin = bytes.NewBufferString(strings.Join(paths, "\n") + "\n")
cmd.Env = append(cmd.Env,
"RPM_BUILD_ROOT="+dirs.PkgDir,
"RPM_FINDPROV_METHOD=",
@ -58,6 +58,7 @@ func rpmFindDependencies(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Dir
"RPM_DATADIR=",
"RPM_SUBPACKAGE_NAME=",
)
cmd.Env = append(cmd.Env, envs...)
var out bytes.Buffer
var stderr bytes.Buffer
cmd.Stdout = &out
@ -66,6 +67,7 @@ func rpmFindDependencies(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Dir
slog.Error(stderr.String())
return err
}
slog.Debug(stderr.String())
dependencies := strings.Split(strings.TrimSpace(out.String()), "\n")
for _, dep := range dependencies {
@ -77,15 +79,17 @@ func rpmFindDependencies(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Dir
return nil
}
func rpmFindProvides(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Directories) error {
return rpmFindDependencies(ctx, pkgInfo, dirs, "/usr/lib/rpm/find-provides", func(dep string) {
type ALTLinuxFindProvReq struct{}
func (o *ALTLinuxFindProvReq) FindProvides(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Directories, skiplist []string) error {
return rpmFindDependenciesALTLinux(ctx, pkgInfo, dirs, "/usr/lib/rpm/find-provides", []string{"RPM_FINDPROV_SKIPLIST=" + strings.Join(skiplist, "\n")}, func(dep string) {
slog.Info(gotext.Get("Provided dependency found"), "dep", dep)
pkgInfo.Overridables.Provides = append(pkgInfo.Overridables.Provides, dep)
})
}
func rpmFindRequires(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Directories) error {
return rpmFindDependencies(ctx, pkgInfo, dirs, "/usr/lib/rpm/find-requires", func(dep string) {
func (o *ALTLinuxFindProvReq) FindRequires(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Directories, skiplist []string) error {
return rpmFindDependenciesALTLinux(ctx, pkgInfo, dirs, "/usr/lib/rpm/find-requires", []string{"RPM_FINDREQ_SKIPLIST=" + strings.Join(skiplist, "\n")}, func(dep string) {
slog.Info(gotext.Get("Required dependency found"), "dep", dep)
pkgInfo.Overridables.Depends = append(pkgInfo.Overridables.Depends, dep)
})

@ -0,0 +1,39 @@
// ALR - Any Linux Repository
// Copyright (C) 2025 Евгений Храмов
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package finddeps
import (
"context"
"log/slog"
"github.com/goreleaser/nfpm/v2"
"github.com/leonelquinteros/gotext"
"gitea.plemya-x.ru/Plemya-x/ALR/internal/types"
)
type EmptyFindProvReq struct{}
func (o *EmptyFindProvReq) FindProvides(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Directories, skiplist []string) error {
slog.Info(gotext.Get("AutoProv is not implemented for this package format, so it's skipped"))
return nil
}
func (o *EmptyFindProvReq) FindRequires(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Directories, skiplist []string) error {
slog.Info(gotext.Get("AutoReq is not implemented for this package format, so it's skipped"))
return nil
}

@ -0,0 +1,118 @@
// ALR - Any Linux Repository
// Copyright (C) 2025 Евгений Храмов
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package finddeps
import (
"bytes"
"context"
"fmt"
"log/slog"
"os/exec"
"path"
"strings"
"github.com/goreleaser/nfpm/v2"
"github.com/leonelquinteros/gotext"
"gitea.plemya-x.ru/Plemya-x/ALR/internal/types"
)
type FedoraFindProvReq struct{}
func rpmFindDependenciesFedora(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Directories, command string, args []string, updateFunc func(string)) error {
if _, err := exec.LookPath(command); err != nil {
slog.Info(gotext.Get("Command not found on the system"), "command", command)
return nil
}
var paths []string
for _, content := range pkgInfo.Contents {
if content.Type != "dir" {
paths = append(paths,
path.Join(dirs.PkgDir, content.Destination),
)
}
}
if len(paths) == 0 {
return nil
}
cmd := exec.CommandContext(ctx, command, args...)
cmd.Stdin = bytes.NewBufferString(strings.Join(paths, "\n") + "\n")
cmd.Env = append(cmd.Env,
"RPM_BUILD_ROOT="+dirs.PkgDir,
)
var out bytes.Buffer
var stderr bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
slog.Error(stderr.String())
return err
}
slog.Debug(stderr.String())
dependencies := strings.Split(strings.TrimSpace(out.String()), "\n")
for _, dep := range dependencies {
if dep != "" {
updateFunc(dep)
}
}
return nil
}
func (o *FedoraFindProvReq) FindProvides(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Directories, skiplist []string) error {
return rpmFindDependenciesFedora(
ctx,
pkgInfo,
dirs,
"/usr/lib/rpm/rpmdeps",
[]string{
"--define=_use_internal_dependency_generator 1",
"--provides",
fmt.Sprintf(
"--define=__provides_exclude_from %s\"",
strings.Join(skiplist, "|"),
),
},
func(dep string) {
slog.Info(gotext.Get("Provided dependency found"), "dep", dep)
pkgInfo.Overridables.Provides = append(pkgInfo.Overridables.Provides, dep)
})
}
func (o *FedoraFindProvReq) FindRequires(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Directories, skiplist []string) error {
return rpmFindDependenciesFedora(
ctx,
pkgInfo,
dirs,
"/usr/lib/rpm/rpmdeps",
[]string{
"--define=_use_internal_dependency_generator 1",
"--requires",
fmt.Sprintf(
"--define=__requires_exclude_from %s",
strings.Join(skiplist, "|"),
),
},
func(dep string) {
slog.Info(gotext.Get("Required dependency found"), "dep", dep)
pkgInfo.Overridables.Depends = append(pkgInfo.Overridables.Depends, dep)
})
}

@ -0,0 +1,58 @@
// ALR - Any Linux Repository
// Copyright (C) 2025 Евгений Храмов
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package finddeps
import (
"context"
"github.com/goreleaser/nfpm/v2"
"gitea.plemya-x.ru/Plemya-x/ALR/internal/types"
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro"
)
type ProvReqFinder interface {
FindProvides(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Directories, skiplist []string) error
FindRequires(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Directories, skiplist []string) error
}
type ProvReqService struct {
finder ProvReqFinder
}
func New(info *distro.OSRelease, pkgFormat string) *ProvReqService {
s := &ProvReqService{
finder: &EmptyFindProvReq{},
}
if pkgFormat == "rpm" {
switch info.ID {
case "altlinux":
s.finder = &ALTLinuxFindProvReq{}
case "fedora":
s.finder = &FedoraFindProvReq{}
}
}
return s
}
func (s *ProvReqService) FindProvides(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Directories, skiplist []string) error {
return s.finder.FindProvides(ctx, pkgInfo, dirs, skiplist)
}
func (s *ProvReqService) FindRequires(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Directories, skiplist []string) error {
return s.finder.FindRequires(ctx, pkgInfo, dirs, skiplist)
}