diff --git a/coverage-badge.svg b/coverage-badge.svg index b686468..fdab882 100644 --- a/coverage-badge.svg +++ b/coverage-badge.svg @@ -11,7 +11,7 @@ coverage coverage - 20.8% - 20.8% + 20.5% + 20.5% diff --git a/internal/translations/default.pot b/internal/translations/default.pot index 13eeea8..fe6da00 100644 --- a/internal/translations/default.pot +++ b/internal/translations/default.pot @@ -299,13 +299,13 @@ msgstr "" msgid "Enable interactive questions and prompts" msgstr "" -#: main.go:90 +#: main.go:91 msgid "" "Running ALR as root is forbidden as it may cause catastrophic damage to your " "system" msgstr "" -#: main.go:124 +#: main.go:125 msgid "Error while running app" msgstr "" @@ -457,6 +457,46 @@ msgstr "" msgid "Pull all repositories that have changed" msgstr "" +#: search.go:36 +msgid "Search packages" +msgstr "" + +#: search.go:42 +msgid "Search by name" +msgstr "" + +#: search.go:47 +msgid "Search by description" +msgstr "" + +#: search.go:52 +msgid "Search by repository" +msgstr "" + +#: search.go:57 +msgid "Search by provides" +msgstr "" + +#: search.go:62 +msgid "Format output using a Go template" +msgstr "" + +#: search.go:94 +msgid "At least one search parameter is required" +msgstr "" + +#: search.go:100 +msgid "Error db search" +msgstr "" + +#: search.go:109 +msgid "Error parsing format template" +msgstr "" + +#: search.go:124 +msgid "Error executing template" +msgstr "" + #: upgrade.go:47 msgid "Upgrade all installed packages" msgstr "" diff --git a/internal/translations/po/ru/default.po b/internal/translations/po/ru/default.po index 88c2415..9a19c9a 100644 --- a/internal/translations/po/ru/default.po +++ b/internal/translations/po/ru/default.po @@ -312,7 +312,7 @@ msgstr "Аргументы, которые будут переданы мене msgid "Enable interactive questions and prompts" msgstr "Включение интерактивных вопросов и запросов" -#: main.go:90 +#: main.go:91 msgid "" "Running ALR as root is forbidden as it may cause catastrophic damage to your " "system" @@ -320,7 +320,7 @@ msgstr "" "Запуск ALR от имени root запрещён, так как это может привести к " "катастрофическому повреждению вашей системы" -#: main.go:124 +#: main.go:125 msgid "Error while running app" msgstr "Ошибка при запуске приложения" @@ -479,6 +479,49 @@ msgstr "Ошибка при удалении пакетов из базы дан msgid "Pull all repositories that have changed" msgstr "Скачать все изменённые репозитории" +#: search.go:36 +msgid "Search packages" +msgstr "" + +#: search.go:42 +msgid "Search by name" +msgstr "" + +#: search.go:47 +msgid "Search by description" +msgstr "" + +#: search.go:52 +#, fuzzy +msgid "Search by repository" +msgstr "Добавить новый репозиторий" + +#: search.go:57 +msgid "Search by provides" +msgstr "" + +#: search.go:62 +msgid "Format output using a Go template" +msgstr "" + +#: search.go:94 +msgid "At least one search parameter is required" +msgstr "" + +#: search.go:100 +msgid "Error db search" +msgstr "" + +#: search.go:109 +#, fuzzy +msgid "Error parsing format template" +msgstr "Ошибка при разборе файла выпуска операционной системы" + +#: search.go:124 +#, fuzzy +msgid "Error executing template" +msgstr "Ошибка при получении пакетов" + #: upgrade.go:47 msgid "Upgrade all installed packages" msgstr "Обновить все установленные пакеты" diff --git a/main.go b/main.go index c62fb5e..3d548f5 100644 --- a/main.go +++ b/main.go @@ -81,6 +81,7 @@ func GetApp() *cli.App { GenCmd(), HelperCmd(), VersionCmd(), + SearchCmd(), }, Before: func(c *cli.Context) error { ctx := c.Context diff --git a/search.go b/search.go new file mode 100644 index 0000000..e2ace08 --- /dev/null +++ b/search.go @@ -0,0 +1,136 @@ +// 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 main + +import ( + "fmt" + "log/slog" + "os" + "strings" + "text/template" + + "github.com/leonelquinteros/gotext" + "github.com/urfave/cli/v2" + + "gitea.plemya-x.ru/Plemya-x/ALR/internal/config" + database "gitea.plemya-x.ru/Plemya-x/ALR/internal/db" +) + +func SearchCmd() *cli.Command { + return &cli.Command{ + Name: "search", + Usage: gotext.Get("Search packages"), + Aliases: []string{"s"}, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "name", + Aliases: []string{"n"}, + Usage: gotext.Get("Search by name"), + }, + &cli.StringFlag{ + Name: "description", + Aliases: []string{"d"}, + Usage: gotext.Get("Search by description"), + }, + &cli.StringFlag{ + Name: "repository", + Aliases: []string{"repo"}, + Usage: gotext.Get("Search by repository"), + }, + &cli.StringFlag{ + Name: "provides", + Aliases: []string{"p"}, + Usage: gotext.Get("Search by provides"), + }, + &cli.StringFlag{ + Name: "format", + Aliases: []string{"f"}, + Usage: gotext.Get("Format output using a Go template"), + }, + }, + Action: func(c *cli.Context) error { + ctx := c.Context + cfg := config.New() + db := database.New(cfg) + err := db.Init(ctx) + defer db.Close() + + if err != nil { + slog.Error(gotext.Get("Error db init"), "err", err) + os.Exit(1) + } + + var conditions []string + if name := c.String("name"); name != "" { + conditions = append(conditions, fmt.Sprintf("name LIKE '%%%s%%'", name)) + } + if description := c.String("description"); description != "" { + conditions = append(conditions, fmt.Sprintf("description LIKE '%%%s%%'", description)) + } + if repo := c.String("repository"); repo != "" { + conditions = append(conditions, fmt.Sprintf("repository = '%s'", repo)) + } + if provides := c.String("provides"); provides != "" { + conditions = append(conditions, fmt.Sprintf("EXISTS (SELECT 1 FROM json_each(provides) WHERE value = '%s')", provides)) + } + query := "" + if len(conditions) > 0 { + query = strings.Join(conditions, " AND ") + } else { + slog.Error(gotext.Get("At least one search parameter is required")) + os.Exit(1) + } + + result, err := db.GetPkgs(ctx, query) + if err != nil { + slog.Error(gotext.Get("Error db search"), "err", err) + os.Exit(1) + } + + format := c.String("format") + var tmpl *template.Template + if format != "" { + tmpl, err = template.New("format").Parse(format) + if err != nil { + slog.Error(gotext.Get("Error parsing format template"), "err", err) + os.Exit(1) + } + } + + for result.Next() { + var dbPkg database.Package + err = result.StructScan(&dbPkg) + if err != nil { + os.Exit(1) + } + + if tmpl != nil { + err = tmpl.Execute(os.Stdout, dbPkg) + if err != nil { + slog.Error(gotext.Get("Error executing template"), "err", err) + os.Exit(1) + } + fmt.Println() + } else { + fmt.Println(dbPkg.Name) + } + } + + return nil + }, + } +}