diff --git a/assets/coverage-badge.svg b/assets/coverage-badge.svg index cfa4439..5a9d2fc 100644 --- a/assets/coverage-badge.svg +++ b/assets/coverage-badge.svg @@ -11,7 +11,7 @@ coverage coverage - 15.7% - 15.7% + 15.8% + 15.8% diff --git a/helper.go b/helper.go index 074e702..19eaf39 100644 --- a/helper.go +++ b/helper.go @@ -71,19 +71,19 @@ func HelperCmd() *cli.Command { helper, ok := helpers.Helpers[c.Args().First()] if !ok { slog.Error(gotext.Get("No such helper command"), "name", c.Args().First()) - os.Exit(1) + return cli.Exit(gotext.Get("No such helper command"), 1) } wd, err := os.Getwd() if err != nil { - slog.Error(gotext.Get("Error getting working directory"), "err", err) - os.Exit(1) + slog.Error(gotext.Get("Error getting working directory")) + return cli.Exit(err, 1) } info, err := distro.ParseOSRelease(ctx) if err != nil { - slog.Error(gotext.Get("Error getting working directory"), "err", err) - os.Exit(1) + slog.Error(gotext.Get("Error parsing os-release file")) + return cli.Exit(err, 1) } hc := interp.HandlerContext{ diff --git a/info.go b/info.go index 02f462c..a2555be 100644 --- a/info.go +++ b/info.go @@ -31,7 +31,6 @@ import ( "gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils" appbuilder "gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils/app_builder" - "gitea.plemya-x.ru/Plemya-x/ALR/internal/config" database "gitea.plemya-x.ru/Plemya-x/ALR/internal/db" "gitea.plemya-x.ru/Plemya-x/ALR/internal/overrides" "gitea.plemya-x.ru/Plemya-x/ALR/internal/utils" @@ -49,31 +48,26 @@ func InfoCmd() *cli.Command { Usage: gotext.Get("Show all information, not just for the current distro"), }, }, - BashComplete: func(c *cli.Context) { + BashComplete: cliutils.BashCompleteWithError(func(c *cli.Context) error { if err := utils.ExitIfCantDropCapsToAlrUser(); err != nil { - slog.Error("Can't drop caps") - os.Exit(1) + return err } ctx := c.Context - cfg := config.New() - err := cfg.Load() + deps, err := appbuilder. + New(ctx). + WithConfig(). + WithDB(). + Build() if err != nil { - slog.Error(gotext.Get("Error loading config"), "err", err) - os.Exit(1) + return err } + defer deps.Defer() - db := database.New(cfg) - err = db.Init(ctx) + result, err := deps.DB.GetPkgs(c.Context, "true") if err != nil { - slog.Error(gotext.Get("Error initialization database"), "err", err) - os.Exit(1) - } - - result, err := db.GetPkgs(c.Context, "true") - if err != nil { - slog.Error(gotext.Get("Error getting packages"), "err", err) - os.Exit(1) + slog.Error(gotext.Get("Error getting packages")) + return cli.Exit(err, 1) } defer result.Close() @@ -81,13 +75,14 @@ func InfoCmd() *cli.Command { var pkg database.Package err = result.StructScan(&pkg) if err != nil { - slog.Error(gotext.Get("Error iterating over packages"), "err", err) - os.Exit(1) + slog.Error(gotext.Get("Error iterating over packages")) + return cli.Exit(err, 1) } fmt.Println(pkg.Name) } - }, + return nil + }), Action: func(c *cli.Context) error { if err := utils.ExitIfCantDropCapsToAlrUser(); err != nil { return err diff --git a/internal/cliutils/app_builder/builder.go b/internal/cliutils/app_builder/builder.go index 6ced528..0aa9bf4 100644 --- a/internal/cliutils/app_builder/builder.go +++ b/internal/cliutils/app_builder/builder.go @@ -92,6 +92,16 @@ func (b *AppBuilder) WithDB() *AppBuilder { } func (b *AppBuilder) WithRepos() *AppBuilder { + b.withRepos(false) + return b +} + +func (b *AppBuilder) WithReposForcePull() *AppBuilder { + b.withRepos(true) + return b +} + +func (b *AppBuilder) withRepos(forcePull bool) *AppBuilder { if b.err != nil { return b } @@ -105,7 +115,7 @@ func (b *AppBuilder) WithRepos() *AppBuilder { rs := repos.New(cfg, db) - if cfg.AutoPull() { + if forcePull || cfg.AutoPull() { if err := rs.Pull(b.ctx, cfg.Repos()); err != nil { slog.Error(gotext.Get("Error pulling repositories"), "err", err) b.err = cli.Exit("", 1) diff --git a/internal/cliutils/utils.go b/internal/cliutils/utils.go new file mode 100644 index 0000000..fca0c8d --- /dev/null +++ b/internal/cliutils/utils.go @@ -0,0 +1,48 @@ +// 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 . + +package cliutils + +import ( + "fmt" + "log/slog" + + "github.com/urfave/cli/v2" +) + +type BashCompleteWithErrorFunc func(c *cli.Context) error + +func BashCompleteWithError(f BashCompleteWithErrorFunc) cli.BashCompleteFunc { + return func(c *cli.Context) { HandleExitCoder(f(c)) } +} + +func HandleExitCoder(err error) { + if err == nil { + return + } + + if exitErr, ok := err.(cli.ExitCoder); ok { + if err.Error() != "" { + if _, ok := exitErr.(cli.ErrorFormatter); ok { + slog.Error(fmt.Sprintf("%+v\n", err)) + } else { + slog.Error(err.Error()) + } + } + cli.OsExiter(exitErr.ExitCode()) + return + } +} diff --git a/internal/translations/default.pot b/internal/translations/default.pot index 2a9d038..ee8b45c 100644 --- a/internal/translations/default.pot +++ b/internal/translations/default.pot @@ -122,47 +122,47 @@ msgstr "" msgid "The directory that the install commands will install to" msgstr "" -#: helper.go:73 +#: helper.go:73 helper.go:74 msgid "No such helper command" msgstr "" -#: info.go:44 -msgid "Print information about a package" -msgstr "" - -#: info.go:49 -msgid "Show all information, not just for the current distro" -msgstr "" - -#: info.go:75 -msgid "Error getting packages" -msgstr "" - -#: info.go:84 -msgid "Error iterating over packages" -msgstr "" - -#: info.go:98 -msgid "Command info expected at least 1 argument, got %d" -msgstr "" - -#: info.go:118 -msgid "Error finding packages" -msgstr "" - -#: info.go:134 -msgid "Can't detect system language" -msgstr "" - -#: info.go:144 +#: helper.go:85 msgid "Error parsing os-release file" msgstr "" -#: info.go:153 +#: info.go:43 +msgid "Print information about a package" +msgstr "" + +#: info.go:48 +msgid "Show all information, not just for the current distro" +msgstr "" + +#: info.go:69 +msgid "Error getting packages" +msgstr "" + +#: info.go:78 +msgid "Error iterating over packages" +msgstr "" + +#: info.go:93 +msgid "Command info expected at least 1 argument, got %d" +msgstr "" + +#: info.go:113 +msgid "Error finding packages" +msgstr "" + +#: info.go:129 +msgid "Can't detect system language" +msgstr "" + +#: info.go:148 msgid "Error resolving overrides" msgstr "" -#: info.go:162 info.go:168 +#: info.go:157 info.go:163 msgid "Error encoding script variables" msgstr "" @@ -315,7 +315,7 @@ msgstr "" msgid "You need to be root to perform this action" msgstr "" -#: list.go:41 +#: list.go:40 msgid "List ALR repo packages" msgstr "" @@ -323,19 +323,19 @@ msgstr "" msgid "Print the current ALR version and exit" msgstr "" -#: main.go:79 +#: main.go:61 msgid "Arguments to be passed on to the package manager" msgstr "" -#: main.go:85 +#: main.go:67 msgid "Enable interactive questions and prompts" msgstr "" -#: main.go:185 +#: main.go:148 msgid "Show help" msgstr "" -#: main.go:189 +#: main.go:152 msgid "Error while running app" msgstr "" @@ -419,51 +419,51 @@ msgid "" "updating ALR if something doesn't work." msgstr "" -#: repo.go:41 +#: repo.go:42 msgid "Add a new repository" msgstr "" -#: repo.go:48 +#: repo.go:49 msgid "Name of the new repo" msgstr "" -#: repo.go:54 +#: repo.go:55 msgid "URL of the new repo" msgstr "" -#: repo.go:92 repo.go:172 +#: repo.go:93 repo.go:173 msgid "Error saving config" msgstr "" -#: repo.go:97 repo.go:199 +#: repo.go:98 msgid "Can't drop privileges" msgstr "" -#: repo.go:104 repo.go:110 repo.go:219 +#: repo.go:105 repo.go:111 msgid "Error pulling repos" msgstr "" -#: repo.go:122 +#: repo.go:123 msgid "Remove an existing repository" msgstr "" -#: repo.go:129 +#: repo.go:130 msgid "Name of the repo to be deleted" msgstr "" -#: repo.go:158 +#: repo.go:159 msgid "Repo does not exist" msgstr "" -#: repo.go:166 +#: repo.go:167 msgid "Error removing repo directory" msgstr "" -#: repo.go:183 +#: repo.go:184 msgid "Error removing packages from database" msgstr "" -#: repo.go:195 +#: repo.go:196 msgid "Pull all repositories that have changed" msgstr "" diff --git a/internal/translations/po/ru/default.po b/internal/translations/po/ru/default.po index 285a637..e7deda5 100644 --- a/internal/translations/po/ru/default.po +++ b/internal/translations/po/ru/default.po @@ -136,48 +136,48 @@ msgstr "Запустить вспомогательную команду ALR" msgid "The directory that the install commands will install to" msgstr "Каталог, в который будут устанавливать команды установки" -#: helper.go:73 +#: helper.go:73 helper.go:74 msgid "No such helper command" msgstr "Такой вспомогательной команды нет" -#: info.go:44 +#: helper.go:85 +msgid "Error parsing os-release file" +msgstr "Ошибка при разборе файла выпуска операционной системы" + +#: info.go:43 msgid "Print information about a package" msgstr "Отобразить информацию о пакете" -#: info.go:49 +#: info.go:48 msgid "Show all information, not just for the current distro" msgstr "Показывать всю информацию, не только для текущего дистрибутива" -#: info.go:75 +#: info.go:69 msgid "Error getting packages" msgstr "Ошибка при получении пакетов" -#: info.go:84 +#: info.go:78 msgid "Error iterating over packages" msgstr "Ошибка при переборе пакетов" -#: info.go:98 +#: info.go:93 msgid "Command info expected at least 1 argument, got %d" msgstr "Для команды info ожидался хотя бы 1 аргумент, получено %d" -#: info.go:118 +#: info.go:113 msgid "Error finding packages" msgstr "Ошибка при поиске пакетов" -#: info.go:134 +#: info.go:129 #, fuzzy msgid "Can't detect system language" msgstr "Ошибка при парсинге языка системы" -#: info.go:144 -msgid "Error parsing os-release file" -msgstr "Ошибка при разборе файла выпуска операционной системы" - -#: info.go:153 +#: info.go:148 msgid "Error resolving overrides" msgstr "Ошибка устранения переорпеделений" -#: info.go:162 info.go:168 +#: info.go:157 info.go:163 msgid "Error encoding script variables" msgstr "Ошибка кодирования переменных скрита" @@ -331,7 +331,7 @@ msgstr "ОШИБКА" msgid "You need to be root to perform this action" msgstr "" -#: list.go:41 +#: list.go:40 msgid "List ALR repo packages" msgstr "Список пакетов репозитория ALR" @@ -339,19 +339,19 @@ msgstr "Список пакетов репозитория ALR" msgid "Print the current ALR version and exit" msgstr "Показать текущую версию ALR и выйти" -#: main.go:79 +#: main.go:61 msgid "Arguments to be passed on to the package manager" msgstr "Аргументы, которые будут переданы менеджеру пакетов" -#: main.go:85 +#: main.go:67 msgid "Enable interactive questions and prompts" msgstr "Включение интерактивных вопросов и запросов" -#: main.go:185 +#: main.go:148 msgid "Show help" msgstr "Показать справку" -#: main.go:189 +#: main.go:152 msgid "Error while running app" msgstr "Ошибка при запуске приложения" @@ -441,52 +441,52 @@ msgstr "" "Минимальная версия ALR для ALR-репозитория выше текущей версии. Попробуйте " "обновить ALR, если что-то не работает." -#: repo.go:41 +#: repo.go:42 msgid "Add a new repository" msgstr "Добавить новый репозиторий" -#: repo.go:48 +#: repo.go:49 msgid "Name of the new repo" msgstr "Название нового репозитория" -#: repo.go:54 +#: repo.go:55 msgid "URL of the new repo" msgstr "URL-адрес нового репозитория" -#: repo.go:92 repo.go:172 +#: repo.go:93 repo.go:173 #, fuzzy msgid "Error saving config" msgstr "Ошибка при кодировании конфигурации" -#: repo.go:97 repo.go:199 +#: repo.go:98 msgid "Can't drop privileges" msgstr "" -#: repo.go:104 repo.go:110 repo.go:219 +#: repo.go:105 repo.go:111 msgid "Error pulling repos" msgstr "Ошибка при извлечении репозиториев" -#: repo.go:122 +#: repo.go:123 msgid "Remove an existing repository" msgstr "Удалить существующий репозиторий" -#: repo.go:129 +#: repo.go:130 msgid "Name of the repo to be deleted" msgstr "Название репозитория удалён" -#: repo.go:158 +#: repo.go:159 msgid "Repo does not exist" msgstr "Репозитория не существует" -#: repo.go:166 +#: repo.go:167 msgid "Error removing repo directory" msgstr "Ошибка при удалении каталога репозитория" -#: repo.go:183 +#: repo.go:184 msgid "Error removing packages from database" msgstr "Ошибка при удалении пакетов из базы данных" -#: repo.go:195 +#: repo.go:196 msgid "Pull all repositories that have changed" msgstr "Скачать все изменённые репозитории" diff --git a/list.go b/list.go index 413951a..c92e87b 100644 --- a/list.go +++ b/list.go @@ -22,7 +22,6 @@ package main import ( "fmt" "log/slog" - "os" "github.com/leonelquinteros/gotext" "github.com/urfave/cli/v2" @@ -77,8 +76,8 @@ func ListCmd() *cli.Command { result, err := db.GetPkgs(ctx, where, args...) if err != nil { - slog.Error(gotext.Get("Error getting packages"), "err", err) - os.Exit(1) + slog.Error(gotext.Get("Error getting packages")) + return cli.Exit(err, 1) } defer result.Close() @@ -86,14 +85,13 @@ func ListCmd() *cli.Command { if c.Bool("installed") { mgr := manager.Detect() if mgr == nil { - slog.Error(gotext.Get("Unable to detect a supported package manager on the system")) - os.Exit(1) + return cli.Exit(gotext.Get("Unable to detect a supported package manager on the system"), 1) } installed, err := mgr.ListInstalled(&manager.Opts{AsRoot: false}) if err != nil { slog.Error(gotext.Get("Error listing installed packages"), "err", err) - os.Exit(1) + return cli.Exit(err, 1) } for pkgName, version := range installed { @@ -110,7 +108,7 @@ func ListCmd() *cli.Command { var pkg database.Package err := result.StructScan(&pkg) if err != nil { - return err + return cli.Exit(err, 1) } if slices.Contains(cfg.IgnorePkgUpdates(), pkg.Name) { @@ -130,11 +128,6 @@ func ListCmd() *cli.Command { fmt.Printf("%s/%s %s\n", pkg.Repository, pkg.Name, version) } - if err != nil { - slog.Error(gotext.Get("Error iterating over packages"), "err", err) - os.Exit(1) - } - return nil }, } diff --git a/main.go b/main.go index acffacb..3a28be3 100644 --- a/main.go +++ b/main.go @@ -21,10 +21,10 @@ package main import ( "context" - "fmt" "log/slog" "os" "os/signal" + "strings" "syscall" "github.com/leonelquinteros/gotext" @@ -50,24 +50,6 @@ func VersionCmd() *cli.Command { } } -func HandleExitCoder(err error) { - if err == nil { - return - } - - if exitErr, ok := err.(cli.ExitCoder); ok { - if err.Error() != "" { - if _, ok := exitErr.(cli.ErrorFormatter); ok { - slog.Error(fmt.Sprintf("%+v\n", err)) - } else { - slog.Error(err.Error()) - } - } - cli.OsExiter(exitErr.ExitCode()) - return - } -} - func GetApp() *cli.App { return &cli.App{ Name: "alr", @@ -100,41 +82,22 @@ func GetApp() *cli.App { HelperCmd(), VersionCmd(), SearchCmd(), - // TEST + // Internal commands InternalBuildCmd(), InternalInstallCmd(), InternalMountCmd(), InternalUnmountCmd(), - // InternalBuild2Cmd(), }, Before: func(c *cli.Context) error { - /* - cfg := config.New() - err := cfg.Load() - if err != nil { - slog.Error(gotext.Get("Error loading config"), "err", err) - os.Exit(1) - } - - /* - cmd := c.Args().First() - if cmd != "helper" && !cfg.AllowRunAsRoot() && os.Geteuid() == 0 { - slog.Error(gotext.Get("Running ALR as root is forbidden as it may cause catastrophic damage to your system")) - os.Exit(1) - } - - - if trimmed := strings.TrimSpace(c.String("pm-args")); trimmed != "" { - args := strings.Split(trimmed, " ") - manager.Args = append(manager.Args, args...) - } - - return nil - */ + if trimmed := strings.TrimSpace(c.String("pm-args")); trimmed != "" { + args := strings.Split(trimmed, " ") + manager.Args = append(manager.Args, args...) + } return nil }, EnableBashCompletion: true, - ExitErrHandler: func(c *cli.Context, err error) { + ExitErrHandler: func(cCtx *cli.Context, err error) { + cliutils.HandleExitCoder(err) }, } } diff --git a/repo.go b/repo.go index 7a599c2..2c5428c 100644 --- a/repo.go +++ b/repo.go @@ -28,6 +28,7 @@ import ( "github.com/urfave/cli/v2" "golang.org/x/exp/slices" + appbuilder "gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils/app_builder" "gitea.plemya-x.ru/Plemya-x/ALR/internal/config" database "gitea.plemya-x.ru/Plemya-x/ALR/internal/db" "gitea.plemya-x.ru/Plemya-x/ALR/internal/types" @@ -195,30 +196,22 @@ func RefreshCmd() *cli.Command { Usage: gotext.Get("Pull all repositories that have changed"), Aliases: []string{"ref"}, Action: func(c *cli.Context) error { - if utils.DropCapsToAlrUser() != nil { - slog.Error(gotext.Get("Can't drop privileges")) - os.Exit(1) + if err := utils.ExitIfCantDropCapsToAlrUser(); err != nil { + return err } ctx := c.Context - cfg := config.New() - err := cfg.Load() - if err != nil { - slog.Error(gotext.Get("Error loading config"), "err", err) - os.Exit(1) - } - db := database.New(cfg) - err = db.Init(ctx) + deps, err := appbuilder. + New(ctx). + WithConfig(). + WithDB(). + WithReposForcePull(). + Build() if err != nil { - os.Exit(1) - } - rs := repos.New(cfg, db) - err = rs.Pull(ctx, cfg.Repos()) - if err != nil { - slog.Error(gotext.Get("Error pulling repos"), "err", err) - os.Exit(1) + return err } + defer deps.Defer() return nil }, }