feat: add group and summary fields #69
| @@ -113,6 +113,10 @@ var AUTOREQ_AUTOPROV_SYSTEMS []string = []string{ | ||||
| 	"fedora-41", | ||||
| } | ||||
|  | ||||
| var RPM_SYSTEMS []string = []string{ | ||||
| 	"fedora-41", | ||||
| } | ||||
|  | ||||
| var COMMON_SYSTEMS []string = []string{ | ||||
| 	"ubuntu-24.04", | ||||
| } | ||||
|   | ||||
							
								
								
									
										56
									
								
								e2e-tests/group_and_summary_field_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								e2e-tests/group_and_summary_field_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| // 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 TestE2EGroupAndSummaryField(t *testing.T) { | ||||
| 	dockerMultipleRun( | ||||
| 		t, | ||||
| 		"group-and-summary-field", | ||||
| 		RPM_SYSTEMS, | ||||
| 		func(t *testing.T, r e2e.Runnable) { | ||||
| 			err := r.Exec(e2e.NewCommand( | ||||
| 				"sudo", | ||||
| 				"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( | ||||
| 				"sh", "-c", "alr search --name test-group-and-summary --format \"{{.Group}}\" | grep ^System/Base$", | ||||
| 			)) | ||||
| 			assert.NoError(t, err) | ||||
|  | ||||
| 			err = r.Exec(e2e.NewCommand( | ||||
| 				"sh", "-c", "alr search --name test-group-and-summary --format \"{{.Summary}}\" | grep \"^Custom summary$\"", | ||||
| 			)) | ||||
| 			assert.NoError(t, err) | ||||
| 		}, | ||||
| 	) | ||||
| } | ||||
| @@ -31,7 +31,7 @@ import ( | ||||
|  | ||||
| // CurrentVersion is the current version of the database. | ||||
| // The database is reset if its version doesn't match this. | ||||
| const CurrentVersion = 3 | ||||
| const CurrentVersion = 4 | ||||
|  | ||||
| // Package is a ALR package's database representation | ||||
| type Package struct { | ||||
| @@ -40,7 +40,9 @@ type Package struct { | ||||
| 	Version       string                    `sh:"version,required" db:"version"` | ||||
| 	Release       int                       `sh:"release,required" db:"release"` | ||||
| 	Epoch         uint                      `sh:"epoch" db:"epoch"` | ||||
| 	Summary       JSON[map[string]string]   `db:"summary"` | ||||
| 	Description   JSON[map[string]string]   `db:"description"` | ||||
| 	Group         JSON[map[string]string]   `db:"group_name"` | ||||
| 	Homepage      JSON[map[string]string]   `db:"homepage"` | ||||
| 	Maintainer    JSON[map[string]string]   `db:"maintainer"` | ||||
| 	Architectures JSON[[]string]            `sh:"architectures" db:"architectures"` | ||||
| @@ -106,7 +108,9 @@ func (d *Database) initDB(ctx context.Context) error { | ||||
| 			version       TEXT NOT NULL, | ||||
| 			release       INT  NOT NULL, | ||||
| 			epoch         INT, | ||||
| 			summary       TEXT CHECK(summary = 'null' OR (JSON_VALID(summary) AND JSON_TYPE(summary) = 'object')), | ||||
| 			description   TEXT CHECK(description = 'null' OR (JSON_VALID(description) AND JSON_TYPE(description) = 'object')), | ||||
| 			group_name    TEXT CHECK(group_name = 'null' OR (JSON_VALID(group_name) AND JSON_TYPE(group_name) = 'object')), | ||||
| 			homepage      TEXT CHECK(homepage = 'null' OR (JSON_VALID(homepage) AND JSON_TYPE(homepage) = 'object')), | ||||
| 			maintainer    TEXT CHECK(maintainer = 'null' OR (JSON_VALID(maintainer) AND JSON_TYPE(maintainer) = 'object')), | ||||
| 			architectures TEXT CHECK(architectures = 'null' OR (JSON_VALID(architectures) AND JSON_TYPE(architectures) = 'array')), | ||||
| @@ -204,7 +208,9 @@ func (d *Database) InsertPackage(ctx context.Context, pkg Package) error { | ||||
| 			version, | ||||
| 			release, | ||||
| 			epoch, | ||||
| 			summary, | ||||
| 			description, | ||||
| 			group_name, | ||||
| 			homepage, | ||||
| 			maintainer, | ||||
| 			architectures, | ||||
| @@ -222,7 +228,9 @@ func (d *Database) InsertPackage(ctx context.Context, pkg Package) error { | ||||
| 			:version, | ||||
| 			:release, | ||||
| 			:epoch, | ||||
| 			:summary, | ||||
| 			:description, | ||||
| 			:group_name, | ||||
| 			:homepage, | ||||
| 			:maintainer, | ||||
| 			:architectures, | ||||
|   | ||||
| @@ -157,6 +157,8 @@ type ResolvedPackage struct { | ||||
| 	Version       string   `sh:"version"` | ||||
| 	Release       int      `sh:"release"` | ||||
| 	Epoch         uint     `sh:"epoch"` | ||||
| 	Group         string   `db:"group_name"` | ||||
| 	Summary       string   `db:"summary"` | ||||
| 	Description   string   `db:"description"` | ||||
| 	Homepage      string   `db:"homepage"` | ||||
| 	Maintainer    string   `db:"maintainer"` | ||||
|   | ||||
| @@ -274,11 +274,11 @@ msgstr "" | ||||
| msgid "OPTIONS" | ||||
| msgstr "" | ||||
|  | ||||
| #: internal/db/db.go:133 | ||||
| #: internal/db/db.go:137 | ||||
| msgid "Database version mismatch; resetting" | ||||
| msgstr "" | ||||
|  | ||||
| #: internal/db/db.go:140 | ||||
| #: internal/db/db.go:144 | ||||
| msgid "" | ||||
| "Database version does not exist. Run alr fix if something isn't working." | ||||
| msgstr "" | ||||
| @@ -397,15 +397,15 @@ msgstr "" | ||||
| msgid "Building package metadata" | ||||
| msgstr "" | ||||
|  | ||||
| #: pkg/build/script_executor.go:356 | ||||
| #: pkg/build/script_executor.go:368 | ||||
| msgid "Executing prepare()" | ||||
| msgstr "" | ||||
|  | ||||
| #: pkg/build/script_executor.go:365 | ||||
| #: pkg/build/script_executor.go:377 | ||||
| msgid "Executing build()" | ||||
| msgstr "" | ||||
|  | ||||
| #: pkg/build/script_executor.go:394 pkg/build/script_executor.go:414 | ||||
| #: pkg/build/script_executor.go:406 pkg/build/script_executor.go:426 | ||||
| msgid "Executing %s()" | ||||
| msgstr "" | ||||
|  | ||||
| @@ -471,39 +471,39 @@ msgstr "" | ||||
| msgid "Pull all repositories that have changed" | ||||
| msgstr "" | ||||
|  | ||||
| #: search.go:36 | ||||
| #: search.go:40 | ||||
| msgid "Search packages" | ||||
| msgstr "" | ||||
|  | ||||
| #: search.go:42 | ||||
| #: search.go:51 | ||||
| msgid "Search by name" | ||||
| msgstr "" | ||||
|  | ||||
| #: search.go:47 | ||||
| #: search.go:56 | ||||
| msgid "Search by description" | ||||
| msgstr "" | ||||
|  | ||||
| #: search.go:52 | ||||
| #: search.go:61 | ||||
| msgid "Search by repository" | ||||
| msgstr "" | ||||
|  | ||||
| #: search.go:57 | ||||
| #: search.go:66 | ||||
| msgid "Search by provides" | ||||
| msgstr "" | ||||
|  | ||||
| #: search.go:62 | ||||
| #: search.go:71 | ||||
| msgid "Format output using a Go template" | ||||
| msgstr "" | ||||
|  | ||||
| #: search.go:96 | ||||
| #: search.go:130 | ||||
| msgid "Error while executing search" | ||||
| msgstr "" | ||||
|  | ||||
| #: search.go:104 | ||||
| #: search.go:138 | ||||
| msgid "Error parsing format template" | ||||
| msgstr "" | ||||
|  | ||||
| #: search.go:112 | ||||
| #: search.go:153 | ||||
| msgid "Error executing template" | ||||
| msgstr "" | ||||
|  | ||||
|   | ||||
| @@ -12,8 +12,8 @@ msgstr "" | ||||
| "MIME-Version: 1.0\n" | ||||
| "Content-Type: text/plain; charset=UTF-8\n" | ||||
| "Content-Transfer-Encoding: 8bit\n" | ||||
| "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " | ||||
| "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" | ||||
| "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" | ||||
| "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" | ||||
| "X-Generator: Gtranslator 48.0\n" | ||||
|  | ||||
| #: build.go:42 | ||||
| @@ -281,11 +281,11 @@ msgstr "КАТЕГОРИЯ" | ||||
| msgid "OPTIONS" | ||||
| msgstr "ПАРАМЕТРЫ" | ||||
|  | ||||
| #: internal/db/db.go:133 | ||||
| #: internal/db/db.go:137 | ||||
| msgid "Database version mismatch; resetting" | ||||
| msgstr "Несоответствие версий базы данных; сброс настроек" | ||||
|  | ||||
| #: internal/db/db.go:140 | ||||
| #: internal/db/db.go:144 | ||||
| msgid "" | ||||
| "Database version does not exist. Run alr fix if something isn't working." | ||||
| msgstr "" | ||||
| @@ -409,15 +409,15 @@ msgstr "" | ||||
| msgid "Building package metadata" | ||||
| msgstr "Сборка метаданных пакета" | ||||
|  | ||||
| #: pkg/build/script_executor.go:356 | ||||
| #: pkg/build/script_executor.go:368 | ||||
| msgid "Executing prepare()" | ||||
| msgstr "Выполнение prepare()" | ||||
|  | ||||
| #: pkg/build/script_executor.go:365 | ||||
| #: pkg/build/script_executor.go:377 | ||||
| msgid "Executing build()" | ||||
| msgstr "Выполнение build()" | ||||
|  | ||||
| #: pkg/build/script_executor.go:394 pkg/build/script_executor.go:414 | ||||
| #: pkg/build/script_executor.go:406 pkg/build/script_executor.go:426 | ||||
| msgid "Executing %s()" | ||||
| msgstr "Выполнение %s()" | ||||
|  | ||||
| @@ -485,39 +485,39 @@ msgstr "Ошибка при удалении пакетов из базы дан | ||||
| msgid "Pull all repositories that have changed" | ||||
| msgstr "Скачать все изменённые репозитории" | ||||
|  | ||||
| #: search.go:36 | ||||
| #: search.go:40 | ||||
| msgid "Search packages" | ||||
| msgstr "Поиск пакетов" | ||||
|  | ||||
| #: search.go:42 | ||||
| #: search.go:51 | ||||
| msgid "Search by name" | ||||
| msgstr "Искать по имени" | ||||
|  | ||||
| #: search.go:47 | ||||
| #: search.go:56 | ||||
| msgid "Search by description" | ||||
| msgstr "Искать по описанию" | ||||
|  | ||||
| #: search.go:52 | ||||
| #: search.go:61 | ||||
| msgid "Search by repository" | ||||
| msgstr "Искать по репозиторию" | ||||
|  | ||||
| #: search.go:57 | ||||
| #: search.go:66 | ||||
| msgid "Search by provides" | ||||
| msgstr "Иcкать по provides" | ||||
|  | ||||
| #: search.go:62 | ||||
| #: search.go:71 | ||||
| msgid "Format output using a Go template" | ||||
| msgstr "Формат выходных данных с использованием шаблона Go" | ||||
|  | ||||
| #: search.go:96 | ||||
| #: search.go:130 | ||||
| msgid "Error while executing search" | ||||
| msgstr "Ошибка при выполнении поиска" | ||||
|  | ||||
| #: search.go:104 | ||||
| #: search.go:138 | ||||
| msgid "Error parsing format template" | ||||
| msgstr "Ошибка при разборе шаблона" | ||||
|  | ||||
| #: search.go:112 | ||||
| #: search.go:153 | ||||
| msgid "Error executing template" | ||||
| msgstr "Ошибка при выполнении шаблона" | ||||
|  | ||||
|   | ||||
| @@ -20,10 +20,6 @@ | ||||
| package types | ||||
|  | ||||
| type BuildOpts struct { | ||||
| 	// Script      string | ||||
| 	// Repository  string | ||||
| 	// Packages    []string | ||||
| 	// Manager     manager.Manager | ||||
| 	Clean       bool | ||||
| 	Interactive bool | ||||
| } | ||||
| @@ -32,7 +28,9 @@ type BuildVarsPre struct { | ||||
| 	Version          string   `sh:"version,required"` | ||||
| 	Release          int      `sh:"release,required"` | ||||
| 	Epoch            uint     `sh:"epoch"` | ||||
| 	Summary          string   `sh:"summary"` | ||||
| 	Description      string   `sh:"desc"` | ||||
| 	Group            string   `sh:"group"` | ||||
| 	Homepage         string   `sh:"homepage"` | ||||
| 	Maintainer       string   `sh:"maintainer"` | ||||
| 	Architectures    []string `sh:"architectures"` | ||||
|   | ||||
| @@ -304,6 +304,7 @@ func buildPkgMetadata( | ||||
| 		Provides:  append(vars.Provides, vars.Name), | ||||
| 		Depends:   deps, | ||||
| 	} | ||||
| 	pkgInfo.Section = vars.Group | ||||
|  | ||||
| 	pkgFormat := input.PkgFormat() | ||||
| 	info := input.OSRelease() | ||||
| @@ -315,6 +316,17 @@ func buildPkgMetadata( | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
| 	if pkgFormat == "rpm" { | ||||
| 		pkgInfo.RPM.Group = vars.Group | ||||
|  | ||||
| 		if vars.Summary != "" { | ||||
| 			pkgInfo.RPM.Summary = vars.Summary | ||||
| 		} else { | ||||
| 			lines := strings.SplitN(vars.Description, "\n", 2) | ||||
| 			pkgInfo.RPM.Summary = lines[0] | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if vars.Epoch != 0 { | ||||
| 		pkgInfo.Epoch = strconv.FormatUint(uint64(vars.Epoch), 10) | ||||
| 	} | ||||
|   | ||||
| @@ -79,26 +79,22 @@ type PackageInfo struct { | ||||
| } | ||||
|  | ||||
| func (inf *PackageInfo) ToPackage(repoName string) *db.Package { | ||||
| 	return &db.Package{ | ||||
| 		Version:       inf.Version, | ||||
| 		Release:       inf.Release, | ||||
| 		Epoch:         inf.Epoch, | ||||
| 		Architectures: inf.Architectures, | ||||
| 		Licenses:      inf.Licenses, | ||||
| 		Provides:      inf.Provides, | ||||
| 		Conflicts:     inf.Conflicts, | ||||
| 		Replaces:      inf.Replaces, | ||||
| 		Description:   db.NewJSON(map[string]string{}), | ||||
| 		Homepage:      db.NewJSON(map[string]string{}), | ||||
| 		Maintainer:    db.NewJSON(map[string]string{}), | ||||
| 		Depends:       db.NewJSON(map[string][]string{}), | ||||
| 		BuildDepends:  db.NewJSON(map[string][]string{}), | ||||
| 		Repository:    repoName, | ||||
| 	} | ||||
| 	pkg := EmptyPackage(repoName) | ||||
| 	pkg.Version = inf.Version | ||||
| 	pkg.Release = inf.Release | ||||
| 	pkg.Epoch = inf.Epoch | ||||
| 	pkg.Architectures = inf.Architectures | ||||
| 	pkg.Licenses = inf.Licenses | ||||
| 	pkg.Provides = inf.Provides | ||||
| 	pkg.Conflicts = inf.Conflicts | ||||
| 	pkg.Replaces = inf.Replaces | ||||
| 	return pkg | ||||
| } | ||||
|  | ||||
| func EmptyPackage(repoName string) *db.Package { | ||||
| 	return &db.Package{ | ||||
| 		Group:        db.NewJSON(map[string]string{}), | ||||
| 		Summary:      db.NewJSON(map[string]string{}), | ||||
| 		Description:  db.NewJSON(map[string]string{}), | ||||
| 		Homepage:     db.NewJSON(map[string]string{}), | ||||
| 		Maintainer:   db.NewJSON(map[string]string{}), | ||||
| @@ -114,6 +110,8 @@ var overridable = map[string]string{ | ||||
| 	"desc":       "Description", | ||||
| 	"homepage":   "Homepage", | ||||
| 	"maintainer": "Maintainer", | ||||
| 	"group":      "Group", | ||||
| 	"summary":    "Summary", | ||||
| } | ||||
|  | ||||
| func resolveOverrides(runner *interp.Runner, pkg *db.Package) { | ||||
|   | ||||
							
								
								
									
										54
									
								
								search.go
									
									
									
									
									
								
							
							
						
						
									
										54
									
								
								search.go
									
									
									
									
									
								
							| @@ -21,12 +21,16 @@ import ( | ||||
| 	"os" | ||||
| 	"text/template" | ||||
|  | ||||
| 	"github.com/jeandeaual/go-locale" | ||||
| 	"github.com/leonelquinteros/gotext" | ||||
| 	"github.com/urfave/cli/v2" | ||||
|  | ||||
| 	"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/db" | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/overrides" | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/utils" | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro" | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/search" | ||||
| ) | ||||
|  | ||||
| @@ -36,6 +40,11 @@ func SearchCmd() *cli.Command { | ||||
| 		Usage:   gotext.Get("Search packages"), | ||||
| 		Aliases: []string{"s"}, | ||||
| 		Flags: []cli.Flag{ | ||||
| 			&cli.BoolFlag{ | ||||
| 				Name:    "all", | ||||
| 				Aliases: []string{"a"}, | ||||
| 				Usage:   gotext.Get("Show all information, not just for the current distro"), | ||||
| 			}, | ||||
| 			&cli.StringFlag{ | ||||
| 				Name:    "name", | ||||
| 				Aliases: []string{"n"}, | ||||
| @@ -69,6 +78,31 @@ func SearchCmd() *cli.Command { | ||||
|  | ||||
| 			ctx := c.Context | ||||
|  | ||||
| 			var names []string | ||||
| 			all := c.Bool("all") | ||||
|  | ||||
| 			systemLang, err := locale.GetLanguage() | ||||
| 			if err != nil { | ||||
| 				return cliutils.FormatCliExit(gotext.Get("Can't detect system language"), err) | ||||
| 			} | ||||
| 			if systemLang == "" { | ||||
| 				systemLang = "en" | ||||
| 			} | ||||
| 			if !all { | ||||
| 				info, err := distro.ParseOSRelease(ctx) | ||||
| 				if err != nil { | ||||
| 					return cliutils.FormatCliExit(gotext.Get("Error parsing os-release file"), err) | ||||
| 				} | ||||
| 				names, err = overrides.Resolve( | ||||
| 					info, | ||||
| 					overrides.DefaultOpts. | ||||
| 						WithLanguages([]string{systemLang}), | ||||
| 				) | ||||
| 				if err != nil { | ||||
| 					return cliutils.FormatCliExit(gotext.Get("Error resolving overrides"), err) | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			deps, err := appbuilder. | ||||
| 				New(ctx). | ||||
| 				WithConfig(). | ||||
| @@ -79,9 +113,9 @@ func SearchCmd() *cli.Command { | ||||
| 			} | ||||
| 			defer deps.Defer() | ||||
|  | ||||
| 			db := deps.DB | ||||
| 			database := deps.DB | ||||
|  | ||||
| 			s := search.New(db) | ||||
| 			s := search.New(database) | ||||
|  | ||||
| 			packages, err := s.Search( | ||||
| 				ctx, | ||||
| @@ -106,14 +140,26 @@ func SearchCmd() *cli.Command { | ||||
| 			} | ||||
|  | ||||
| 			for _, dbPkg := range packages { | ||||
| 				var pkg any | ||||
| 				if !all { | ||||
| 					pkg = overrides.ResolvePackage(&dbPkg, names) | ||||
| 				} else { | ||||
| 					pkg = &dbPkg | ||||
| 				} | ||||
|  | ||||
| 				if tmpl != nil { | ||||
| 					err = tmpl.Execute(os.Stdout, dbPkg) | ||||
| 					err = tmpl.Execute(os.Stdout, pkg) | ||||
| 					if err != nil { | ||||
| 						return cliutils.FormatCliExit(gotext.Get("Error executing template"), err) | ||||
| 					} | ||||
| 					fmt.Println() | ||||
| 				} else { | ||||
| 					fmt.Println(dbPkg.Name) | ||||
| 					switch v := pkg.(type) { | ||||
| 					case *overrides.ResolvedPackage: | ||||
| 						fmt.Println(v.Name) | ||||
| 					case *db.Package: | ||||
| 						fmt.Println(v.Name) | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user