Compare commits

..

4 Commits

12 changed files with 137 additions and 114 deletions

@ -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">97.00%</text> <text x="100" y="15" fill="#010101" fill-opacity=".3">100.00%</text>
<text x="100" y="14">97.00%</text> <text x="100" y="14">100.00%</text>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 940 B

After

Width:  |  Height:  |  Size: 942 B

@ -31,10 +31,21 @@ func TestE2EIssue32Interactive(t *testing.T) {
"issue-32-interactive", "issue-32-interactive",
COMMON_SYSTEMS, COMMON_SYSTEMS,
func(t *testing.T, r e2e.Runnable) { func(t *testing.T, r e2e.Runnable) {
err := r.Exec(e2e.NewCommand( assert.NoError(t, r.Exec(e2e.NewCommand(
"sudo", "alr", "--interactive=false", "remove", "ca-certificates", "sudo", "alr", "--interactive=false", "remove", "ca-certificates",
)) )))
assert.NoError(t, err)
assert.NoError(t, r.Exec(e2e.NewCommand(
"sudo", "alr", "--interactive=false", "remove", "openssl",
)))
assert.NoError(t, r.Exec(e2e.NewCommand(
"alr", "fix",
)))
assert.NoError(t, r.Exec(e2e.NewCommand(
"sudo", "alr", "--interactive=false", "install", "ca-certificates",
)))
}, },
) )
} }

@ -46,6 +46,9 @@ func HandleExitCoder(err error) {
cli.OsExiter(exitErr.ExitCode()) cli.OsExiter(exitErr.ExitCode())
return return
} }
slog.Error(err.Error())
cli.OsExiter(1)
} }
func FormatCliExit(msg string, err error) cli.ExitCoder { func FormatCliExit(msg string, err error) cli.ExitCoder {

@ -312,7 +312,7 @@ msgid "ERROR"
msgstr "" msgstr ""
#: internal/utils/cmd.go:95 #: internal/utils/cmd.go:95
msgid "Error dropping capabilities" msgid "Error on dropping capabilities"
msgstr "" msgstr ""
#: internal/utils/cmd.go:123 #: internal/utils/cmd.go:123
@ -347,19 +347,19 @@ msgstr ""
msgid "Error while running app" msgid "Error while running app"
msgstr "" msgstr ""
#: pkg/build/build.go:394 #: pkg/build/build.go:395
msgid "Building package" msgid "Building package"
msgstr "" msgstr ""
#: pkg/build/build.go:423 #: pkg/build/build.go:424
msgid "The checksums array must be the same length as sources" msgid "The checksums array must be the same length as sources"
msgstr "" msgstr ""
#: pkg/build/build.go:454 #: pkg/build/build.go:455
msgid "Downloading sources" msgid "Downloading sources"
msgstr "" msgstr ""
#: pkg/build/build.go:543 #: pkg/build/build.go:549
msgid "Installing dependencies" msgid "Installing dependencies"
msgstr "" msgstr ""
@ -440,7 +440,7 @@ msgid "URL of the new repo"
msgstr "" msgstr ""
#: repo.go:79 #: repo.go:79
msgid "Repo %s already exists" msgid "Repo \"%s\" already exists"
msgstr "" msgstr ""
#: repo.go:90 repo.go:167 #: repo.go:90 repo.go:167

@ -5,16 +5,16 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: unnamed project\n" "Project-Id-Version: unnamed project\n"
"PO-Revision-Date: 2025-03-09 17:31+0300\n" "PO-Revision-Date: 2025-04-18 07:38+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 47.1\n" "X-Generator: Gtranslator 48.0\n"
#: build.go:42 #: build.go:42
msgid "Build a local package" msgid "Build a local package"
@ -43,16 +43,15 @@ msgstr "Ошибка при получении рабочего каталога
#: build.go:118 #: build.go:118
msgid "Cannot get absolute script path" msgid "Cannot get absolute script path"
msgstr "" msgstr "Невозможно получить абсолютный путь к скрипту"
#: build.go:148 #: build.go:148
msgid "Package not found" msgid "Package not found"
msgstr "Пакет не найден" msgstr "Пакет не найден"
#: build.go:161 #: build.go:161
#, fuzzy
msgid "Nothing to build" msgid "Nothing to build"
msgstr "Исполнение build()" msgstr "Нечего собирать"
#: build.go:218 #: build.go:218
msgid "Error building package" msgid "Error building package"
@ -71,24 +70,20 @@ msgid "Attempt to fix problems with ALR"
msgstr "Попытка устранить проблемы с ALR" msgstr "Попытка устранить проблемы с ALR"
#: fix.go:59 #: fix.go:59
#, fuzzy
msgid "Clearing cache directory" msgid "Clearing cache directory"
msgstr "Удаление каталога кэша" msgstr "Очистка каталога кэша"
#: fix.go:64 #: fix.go:64
#, fuzzy
msgid "Unable to open cache directory" msgid "Unable to open cache directory"
msgstr "Не удалось удалить каталог кэша" msgstr "Невозможно открыть каталог кэша"
#: fix.go:70 #: fix.go:70
#, fuzzy
msgid "Unable to read cache directory contents" msgid "Unable to read cache directory contents"
msgstr "Не удалось удалить каталог кэша" msgstr "Невозможно прочитать содержимое каталога кэша"
#: fix.go:76 #: fix.go:76
#, fuzzy
msgid "Unable to remove cache item (%s)" msgid "Unable to remove cache item (%s)"
msgstr "Не удалось удалить каталог кэша" msgstr "Невозможно удалить элемент кэша (%s)"
#: fix.go:80 #: fix.go:80
msgid "Rebuilding cache" msgid "Rebuilding cache"
@ -151,9 +146,8 @@ msgid "Error finding packages"
msgstr "Ошибка при поиске пакетов" msgstr "Ошибка при поиске пакетов"
#: info.go:124 #: info.go:124
#, fuzzy
msgid "Can't detect system language" msgid "Can't detect system language"
msgstr "Ошибка при парсинге языка системы" msgstr "Ошибка при определении языка системы"
#: info.go:141 #: info.go:141
msgid "Error resolving overrides" msgid "Error resolving overrides"
@ -192,9 +186,8 @@ msgid "Error removing packages"
msgstr "Ошибка при удалении пакетов" msgstr "Ошибка при удалении пакетов"
#: internal/cliutils/app_builder/builder.go:75 #: internal/cliutils/app_builder/builder.go:75
#, fuzzy
msgid "Error loading config" msgid "Error loading config"
msgstr "Ошибка при кодировании конфигурации" msgstr "Ошибка при загрузке"
#: internal/cliutils/app_builder/builder.go:96 #: internal/cliutils/app_builder/builder.go:96
msgid "Error initialization database" msgid "Error initialization database"
@ -327,17 +320,16 @@ msgid "ERROR"
msgstr "ОШИБКА" msgstr "ОШИБКА"
#: internal/utils/cmd.go:95 #: internal/utils/cmd.go:95
#, fuzzy msgid "Error on dropping capabilities"
msgid "Error dropping capabilities" msgstr "Ошибка при понижении привилегий"
msgstr "Ошибка при открытии базы данных"
#: internal/utils/cmd.go:123 #: internal/utils/cmd.go:123
msgid "You need to be root to perform this action" msgid "You need to be root to perform this action"
msgstr "" msgstr "Вы должны быть root чтобы выполнить это"
#: internal/utils/cmd.go:165 #: internal/utils/cmd.go:165
msgid "You need to be a %s member to perform this action" msgid "You need to be a %s member to perform this action"
msgstr "" msgstr "Вы должны быть членом %s чтобы выполнить это"
#: list.go:41 #: list.go:41
msgid "List ALR repo packages" msgid "List ALR repo packages"
@ -363,19 +355,19 @@ msgstr "Показать справку"
msgid "Error while running app" msgid "Error while running app"
msgstr "Ошибка при запуске приложения" msgstr "Ошибка при запуске приложения"
#: pkg/build/build.go:394 #: pkg/build/build.go:395
msgid "Building package" msgid "Building package"
msgstr "Сборка пакета" msgstr "Сборка пакета"
#: pkg/build/build.go:423 #: pkg/build/build.go:424
msgid "The checksums array must be the same length as sources" msgid "The checksums array must be the same length as sources"
msgstr "Массив контрольных сумм должен быть той же длины, что и источники" msgstr "Массив контрольных сумм должен быть той же длины, что и источники"
#: pkg/build/build.go:454 #: pkg/build/build.go:455
msgid "Downloading sources" msgid "Downloading sources"
msgstr "Скачивание источников" msgstr "Скачивание источников"
#: pkg/build/build.go:543 #: pkg/build/build.go:549
msgid "Installing dependencies" msgid "Installing dependencies"
msgstr "Установка зависимостей" msgstr "Установка зависимостей"
@ -419,15 +411,15 @@ msgstr "Сборка метаданных пакета"
#: pkg/build/script_executor.go:356 #: pkg/build/script_executor.go:356
msgid "Executing prepare()" msgid "Executing prepare()"
msgstr "Исполнение prepare()" msgstr "Выполнение prepare()"
#: pkg/build/script_executor.go:365 #: pkg/build/script_executor.go:365
msgid "Executing build()" msgid "Executing build()"
msgstr "Исполнение build()" msgstr "Выполнение build()"
#: pkg/build/script_executor.go:394 pkg/build/script_executor.go:414 #: pkg/build/script_executor.go:394 pkg/build/script_executor.go:414
msgid "Executing %s()" msgid "Executing %s()"
msgstr "Исполнение %s()" msgstr "Выполнение %s()"
#: pkg/repos/pull.go:79 #: pkg/repos/pull.go:79
msgid "Pulling repository" msgid "Pulling repository"
@ -462,14 +454,12 @@ msgid "URL of the new repo"
msgstr "URL-адрес нового репозитория" msgstr "URL-адрес нового репозитория"
#: repo.go:79 #: repo.go:79
#, fuzzy msgid "Repo \"%s\" already exists"
msgid "Repo %s already exists" msgstr "Репозиторий \"%s\" уже существует"
msgstr "Репозитория не существует"
#: repo.go:90 repo.go:167 #: repo.go:90 repo.go:167
#, fuzzy
msgid "Error saving config" msgid "Error saving config"
msgstr "Ошибка при кодировании конфигурации" msgstr "Ошибка при сохранении конфигурации"
#: repo.go:116 #: repo.go:116
msgid "Remove an existing repository" msgid "Remove an existing repository"
@ -480,9 +470,8 @@ msgid "Name of the repo to be deleted"
msgstr "Название репозитория удалён" msgstr "Название репозитория удалён"
#: repo.go:156 #: repo.go:156
#, fuzzy
msgid "Repo \"%s\" does not exist" msgid "Repo \"%s\" does not exist"
msgstr "Репозитория не существует" msgstr "Репозитория \"%s\" не существует"
#: repo.go:163 #: repo.go:163
msgid "Error removing repo directory" msgid "Error removing repo directory"
@ -521,9 +510,8 @@ msgid "Format output using a Go template"
msgstr "Формат выходных данных с использованием шаблона Go" msgstr "Формат выходных данных с использованием шаблона Go"
#: search.go:96 #: search.go:96
#, fuzzy
msgid "Error while executing search" msgid "Error while executing search"
msgstr "Ошибка при запуске приложения" msgstr "Ошибка при выполнении поиска"
#: search.go:104 #: search.go:104
msgid "Error parsing format template" msgid "Error parsing format template"

@ -92,14 +92,14 @@ func ExitIfCantDropGidToAlr() cli.ExitCoder {
func ExitIfCantDropCapsToAlrUser() cli.ExitCoder { func ExitIfCantDropCapsToAlrUser() cli.ExitCoder {
err := DropCapsToAlrUser() err := DropCapsToAlrUser()
if err != nil { if err != nil {
return cliutils.FormatCliExit(gotext.Get("Error dropping capabilities"), err) return cliutils.FormatCliExit(gotext.Get("Error on dropping capabilities"), err)
} }
return nil return nil
} }
func ExitIfCantSetNoNewPrivs() cli.ExitCoder { func ExitIfCantSetNoNewPrivs() cli.ExitCoder {
if err := NoNewPrivs(); err != nil { if err := NoNewPrivs(); err != nil {
return cliutils.FormatCliExit("error no new privs", err) return cliutils.FormatCliExit("error on NoNewPrivs", err)
} }
return nil return nil

@ -35,6 +35,7 @@ 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/types" "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/manager"
) )
type BuildInput struct { type BuildInput struct {
@ -233,8 +234,8 @@ type CheckerExecutor interface {
} }
type InstallerExecutor interface { type InstallerExecutor interface {
InstallLocal(paths []string) error InstallLocal(paths []string, opts *manager.Opts) error
Install(pkgs []string) error Install(pkgs []string, opts *manager.Opts) error
RemoveAlreadyInstalled(pkgs []string) ([]string, error) RemoveAlreadyInstalled(pkgs []string) ([]string, error)
} }
@ -521,7 +522,12 @@ func (b *Builder) InstallALRPackages(
return err return err
} }
err = b.installerExecutor.InstallLocal(res.PackagePaths) err = b.installerExecutor.InstallLocal(
res.PackagePaths,
&manager.Opts{
NoConfirm: !input.BuildOpts().Interactive,
},
)
if err != nil { if err != nil {
return err return err
} }
@ -681,14 +687,18 @@ func (i *Builder) InstallPkgs(
} }
if len(builtPaths) > 0 { if len(builtPaths) > 0 {
err = i.installerExecutor.InstallLocal(builtPaths) err = i.installerExecutor.InstallLocal(builtPaths, &manager.Opts{
NoConfirm: !input.BuildOpts().Interactive,
})
if err != nil { if err != nil {
return err return err
} }
} }
if len(repoDeps) > 0 { if len(repoDeps) > 0 {
err = i.installerExecutor.Install(repoDeps) err = i.installerExecutor.Install(repoDeps, &manager.Opts{
NoConfirm: !input.BuildOpts().Interactive,
})
if err != nil { if err != nil {
return err return err
} }

@ -28,12 +28,12 @@ func NewInstaller(mgr manager.Manager) *Installer {
type Installer struct{ mgr manager.Manager } type Installer struct{ mgr manager.Manager }
func (i *Installer) InstallLocal(paths []string) error { func (i *Installer) InstallLocal(paths []string, opts *manager.Opts) error {
return i.mgr.InstallLocal(nil, paths...) return i.mgr.InstallLocal(opts, paths...)
} }
func (i *Installer) Install(pkgs []string) error { func (i *Installer) Install(pkgs []string, opts *manager.Opts) error {
return i.mgr.Install(nil, pkgs...) return i.mgr.Install(opts, pkgs...)
} }
func (i *Installer) RemoveAlreadyInstalled(pkgs []string) ([]string, error) { func (i *Installer) RemoveAlreadyInstalled(pkgs []string) ([]string, error) {

40
pkg/build/safe_common.go Normal file

@ -0,0 +1,40 @@
// 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 build
import (
"os"
"os/exec"
"strings"
)
func setCommonCmdEnv(cmd *exec.Cmd) {
cmd.Env = []string{
"HOME=/var/cache/alr",
"LOGNAME=alr",
"USER=alr",
"PATH=/usr/bin:/bin:/usr/local/bin",
}
for _, env := range os.Environ() {
if strings.HasPrefix(env, "LANG=") ||
strings.HasPrefix(env, "LANGUAGE=") ||
strings.HasPrefix(env, "LC_") ||
strings.HasPrefix(env, "ALR_LOG_LEVEL=") {
cmd.Env = append(cmd.Env, env)
}
}
}

@ -28,6 +28,7 @@ import (
"github.com/hashicorp/go-plugin" "github.com/hashicorp/go-plugin"
"gitea.plemya-x.ru/Plemya-x/ALR/internal/logger" "gitea.plemya-x.ru/Plemya-x/ALR/internal/logger"
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/manager"
) )
type InstallerPlugin struct { type InstallerPlugin struct {
@ -42,21 +43,31 @@ type InstallerRPCServer struct {
Impl InstallerExecutor Impl InstallerExecutor
} }
func (r *InstallerRPC) InstallLocal(paths []string) error { type InstallArgs struct {
return r.client.Call("Plugin.InstallLocal", paths, nil) PackagesOrPaths []string
Opts *manager.Opts
} }
func (s *InstallerRPCServer) InstallLocal(paths []string, reply *struct{}) error { func (r *InstallerRPC) InstallLocal(paths []string, opts *manager.Opts) error {
return s.Impl.InstallLocal(paths) return r.client.Call("Plugin.InstallLocal", &InstallArgs{
PackagesOrPaths: paths,
Opts: opts,
}, nil)
} }
func (r *InstallerRPC) Install(pkgs []string) error { func (s *InstallerRPCServer) InstallLocal(args *InstallArgs, reply *struct{}) error {
return r.client.Call("Plugin.Install", pkgs, nil) return s.Impl.InstallLocal(args.PackagesOrPaths, args.Opts)
} }
func (s *InstallerRPCServer) Install(pkgs []string, reply *struct{}) error { func (r *InstallerRPC) Install(pkgs []string, opts *manager.Opts) error {
slog.Debug("install", "pkgs", pkgs) return r.client.Call("Plugin.Install", &InstallArgs{
return s.Impl.Install(pkgs) PackagesOrPaths: pkgs,
Opts: opts,
}, nil)
}
func (s *InstallerRPCServer) Install(args *InstallArgs, reply *struct{}) error {
return s.Impl.Install(args.PackagesOrPaths, args.Opts)
} }
func (r *InstallerRPC) RemoveAlreadyInstalled(paths []string) ([]string, error) { func (r *InstallerRPC) RemoveAlreadyInstalled(paths []string) ([]string, error) {
@ -90,28 +101,7 @@ func GetSafeInstaller() (InstallerExecutor, func(), error) {
return nil, nil, err return nil, nil, err
} }
cmd := exec.Command(executable, "_internal-installer") cmd := exec.Command(executable, "_internal-installer")
cmd.Env = []string{ setCommonCmdEnv(cmd)
"HOME=/var/cache/alr",
"LOGNAME=alr",
"USER=alr",
"PATH=/usr/bin:/bin:/usr/local/bin",
"ALR_LOG_LEVEL=DEBUG",
}
/*
uid, gid, err := utils.GetUidGidAlrUser()
if err != nil {
return nil, nil, err
}
cmd.SysProcAttr = &syscall.SysProcAttr{
Credential: &syscall.Credential{
Uid: uint32(uid),
Gid: uint32(gid),
},
}
*/
slog.Debug("safe installer setup", "uid", syscall.Getuid(), "gid", syscall.Getgid()) slog.Debug("safe installer setup", "uid", syscall.Getuid(), "gid", syscall.Getgid())

@ -226,26 +226,7 @@ func GetSafeScriptExecutor() (ScriptExecutor, func(), error) {
} }
cmd := exec.Command(executable, "_internal-safe-script-executor") cmd := exec.Command(executable, "_internal-safe-script-executor")
cmd.Env = []string{ setCommonCmdEnv(cmd)
"HOME=/var/cache/alr",
"LOGNAME=alr",
"USER=alr",
"PATH=/usr/bin:/bin:/usr/local/bin",
"ALR_LOG_LEVEL=DEBUG",
}
/*
uid, gid, err := utils.GetUidGidAlrUser()
if err != nil {
return nil, nil, err
}
cmd.SysProcAttr = &syscall.SysProcAttr{
Credential: &syscall.Credential{
Uid: uint32(uid),
Gid: uint32(gid),
},
}
*/
client := plugin.NewClient(&plugin.ClientConfig{ client := plugin.NewClient(&plugin.ClientConfig{
HandshakeConfig: HandshakeConfig, HandshakeConfig: HandshakeConfig,

@ -76,7 +76,7 @@ func AddRepoCmd() *cli.Command {
reposSlice := cfg.Repos() reposSlice := cfg.Repos()
for _, repo := range reposSlice { for _, repo := range reposSlice {
if repo.URL == repoURL || repo.Name == name { if repo.URL == repoURL || repo.Name == name {
return cliutils.FormatCliExit(gotext.Get("Repo %s already exists", repo.Name), nil) return cliutils.FormatCliExit(gotext.Get("Repo \"%s\" already exists", repo.Name), nil)
} }
} }
reposSlice = append(reposSlice, types.Repo{ reposSlice = append(reposSlice, types.Repo{