refactor: migrate to xorm
This commit is contained in:
@ -23,41 +23,39 @@ import (
|
||||
"context"
|
||||
"log/slog"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/leonelquinteros/gotext"
|
||||
_ "modernc.org/sqlite"
|
||||
"xorm.io/xorm"
|
||||
|
||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/config"
|
||||
)
|
||||
|
||||
// CurrentVersion is the current version of the database.
|
||||
// The database is reset if its version doesn't match this.
|
||||
const CurrentVersion = 4
|
||||
const CurrentVersion = 5
|
||||
|
||||
// Package is a ALR package's database representation
|
||||
type Package struct {
|
||||
BasePkgName string `sh:"base" db:"basepkg_name"`
|
||||
Name string `sh:"name,required" db:"name"`
|
||||
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"`
|
||||
Licenses JSON[[]string] `sh:"license" db:"licenses"`
|
||||
Provides JSON[[]string] `sh:"provides" db:"provides"`
|
||||
Conflicts JSON[[]string] `sh:"conflicts" db:"conflicts"`
|
||||
Replaces JSON[[]string] `sh:"replaces" db:"replaces"`
|
||||
Depends JSON[map[string][]string] `db:"depends"`
|
||||
BuildDepends JSON[map[string][]string] `db:"builddepends"`
|
||||
OptDepends JSON[map[string][]string] `db:"optdepends"`
|
||||
Repository string `db:"repository"`
|
||||
BasePkgName string `sh:"basepkg_name" xorm:"notnull 'basepkg_name'"`
|
||||
Name string `sh:"name,required" xorm:"notnull unique(name_repo) 'name'"`
|
||||
Version string `sh:"version,required" xorm:"notnull 'version'"`
|
||||
Release int `sh:"release" xorm:"notnull 'release'"`
|
||||
Epoch uint `sh:"epoch" xorm:"'epoch'"`
|
||||
Summary map[string]string `xorm:"json 'summary'"`
|
||||
Description map[string]string `xorm:"json 'description'"`
|
||||
Group map[string]string `xorm:"json 'group_name'"`
|
||||
Homepage map[string]string `xorm:"json 'homepage'"`
|
||||
Maintainer map[string]string `xorm:"json 'maintainer'"`
|
||||
Architectures []string `sh:"architectures" xorm:"json 'architectures'"`
|
||||
Licenses []string `sh:"license" xorm:"json 'licenses'"`
|
||||
Provides []string `sh:"provides" xorm:"json 'provides'"`
|
||||
Conflicts []string `sh:"conflicts" xorm:"json 'conflicts'"`
|
||||
Replaces []string `sh:"replaces" xorm:"json 'replaces'"`
|
||||
Depends map[string][]string `xorm:"json 'depends'"`
|
||||
BuildDepends map[string][]string `xorm:"json 'builddepends'"`
|
||||
OptDepends map[string][]string `xorm:"json 'optdepends'"`
|
||||
Repository string `xorm:"notnull unique(name_repo) 'repository'"`
|
||||
}
|
||||
|
||||
type version struct {
|
||||
Version int `db:"version"`
|
||||
type Version struct {
|
||||
Version int `xorm:"'version'"`
|
||||
}
|
||||
|
||||
type Config interface {
|
||||
@ -65,7 +63,7 @@ type Config interface {
|
||||
}
|
||||
|
||||
type Database struct {
|
||||
conn *sqlx.DB
|
||||
engine *xorm.Engine
|
||||
config Config
|
||||
}
|
||||
|
||||
@ -75,181 +73,98 @@ func New(config Config) *Database {
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Database) Init(ctx context.Context) error {
|
||||
err := d.Connect(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return d.initDB(ctx)
|
||||
}
|
||||
|
||||
func (d *Database) Connect(ctx context.Context) error {
|
||||
func (d *Database) Connect() error {
|
||||
dsn := d.config.GetPaths().DBPath
|
||||
db, err := sqlx.Open("sqlite", dsn)
|
||||
engine, err := xorm.NewEngine("sqlite", dsn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.conn = db
|
||||
d.engine = engine
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Database) GetConn() *sqlx.DB {
|
||||
return d.conn
|
||||
}
|
||||
|
||||
func (d *Database) initDB(ctx context.Context) error {
|
||||
d.conn = d.conn.Unsafe()
|
||||
conn := d.conn
|
||||
_, err := conn.ExecContext(ctx, `
|
||||
CREATE TABLE IF NOT EXISTS pkgs (
|
||||
basepkg_name TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
repository TEXT NOT NULL,
|
||||
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')),
|
||||
licenses TEXT CHECK(licenses = 'null' OR (JSON_VALID(licenses) AND JSON_TYPE(licenses) = 'array')),
|
||||
provides TEXT CHECK(provides = 'null' OR (JSON_VALID(provides) AND JSON_TYPE(provides) = 'array')),
|
||||
conflicts TEXT CHECK(conflicts = 'null' OR (JSON_VALID(conflicts) AND JSON_TYPE(conflicts) = 'array')),
|
||||
replaces TEXT CHECK(replaces = 'null' OR (JSON_VALID(replaces) AND JSON_TYPE(replaces) = 'array')),
|
||||
depends TEXT CHECK(depends = 'null' OR (JSON_VALID(depends) AND JSON_TYPE(depends) = 'object')),
|
||||
builddepends TEXT CHECK(builddepends = 'null' OR (JSON_VALID(builddepends) AND JSON_TYPE(builddepends) = 'object')),
|
||||
optdepends TEXT CHECK(optdepends = 'null' OR (JSON_VALID(optdepends) AND JSON_TYPE(optdepends) = 'object')),
|
||||
UNIQUE(name, repository)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS alr_db_version (
|
||||
version INT NOT NULL
|
||||
);
|
||||
`)
|
||||
if err != nil {
|
||||
func (d *Database) Init(ctx context.Context) error {
|
||||
if err := d.Connect(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.engine.Sync2(new(Package), new(Version)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ver, ok := d.GetVersion(ctx)
|
||||
if ok && ver != CurrentVersion {
|
||||
slog.Warn(gotext.Get("Database version mismatch; resetting"), "version", ver, "expected", CurrentVersion)
|
||||
err = d.reset(ctx)
|
||||
if err != nil {
|
||||
if err := d.reset(); err != nil {
|
||||
return err
|
||||
}
|
||||
return d.initDB(ctx)
|
||||
return d.Init(ctx)
|
||||
} else if !ok {
|
||||
slog.Warn(gotext.Get("Database version does not exist. Run alr fix if something isn't working."), "version", ver, "expected", CurrentVersion)
|
||||
return d.addVersion(ctx, CurrentVersion)
|
||||
slog.Warn(gotext.Get("Database version does not exist. Run alr fix if something isn't working."))
|
||||
return d.addVersion(CurrentVersion)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Database) GetVersion(ctx context.Context) (int, bool) {
|
||||
var ver version
|
||||
err := d.conn.GetContext(ctx, &ver, "SELECT * FROM alr_db_version LIMIT 1;")
|
||||
if err != nil {
|
||||
var v Version
|
||||
has, err := d.engine.Get(&v)
|
||||
if err != nil || !has {
|
||||
return 0, false
|
||||
}
|
||||
return ver.Version, true
|
||||
return v.Version, true
|
||||
}
|
||||
|
||||
func (d *Database) addVersion(ctx context.Context, ver int) error {
|
||||
_, err := d.conn.ExecContext(ctx, `INSERT INTO alr_db_version(version) VALUES (?);`, ver)
|
||||
func (d *Database) addVersion(ver int) error {
|
||||
_, err := d.engine.Insert(&Version{Version: ver})
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Database) reset(ctx context.Context) error {
|
||||
_, err := d.conn.ExecContext(ctx, "DROP TABLE IF EXISTS pkgs;")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = d.conn.ExecContext(ctx, "DROP TABLE IF EXISTS alr_db_version;")
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Database) GetPkgs(ctx context.Context, where string, args ...any) (*sqlx.Rows, error) {
|
||||
stream, err := d.conn.QueryxContext(ctx, "SELECT * FROM pkgs WHERE "+where, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return stream, nil
|
||||
}
|
||||
|
||||
func (d *Database) GetPkg(ctx context.Context, where string, args ...any) (*Package, error) {
|
||||
out := &Package{}
|
||||
err := d.conn.GetContext(ctx, out, "SELECT * FROM pkgs WHERE "+where+" LIMIT 1", args...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (d *Database) DeletePkgs(ctx context.Context, where string, args ...any) error {
|
||||
_, err := d.conn.ExecContext(ctx, "DELETE FROM pkgs WHERE "+where, args...)
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Database) IsEmpty(ctx context.Context) bool {
|
||||
var count int
|
||||
err := d.conn.GetContext(ctx, &count, "SELECT count(1) FROM pkgs;")
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
return count == 0
|
||||
func (d *Database) reset() error {
|
||||
return d.engine.DropTables(new(Package), new(Version))
|
||||
}
|
||||
|
||||
func (d *Database) InsertPackage(ctx context.Context, pkg Package) error {
|
||||
_, err := d.conn.NamedExecContext(ctx, `
|
||||
INSERT OR REPLACE INTO pkgs (
|
||||
basepkg_name,
|
||||
name,
|
||||
repository,
|
||||
version,
|
||||
release,
|
||||
epoch,
|
||||
summary,
|
||||
description,
|
||||
group_name,
|
||||
homepage,
|
||||
maintainer,
|
||||
architectures,
|
||||
licenses,
|
||||
provides,
|
||||
conflicts,
|
||||
replaces,
|
||||
depends,
|
||||
builddepends,
|
||||
optdepends
|
||||
) VALUES (
|
||||
:basepkg_name,
|
||||
:name,
|
||||
:repository,
|
||||
:version,
|
||||
:release,
|
||||
:epoch,
|
||||
:summary,
|
||||
:description,
|
||||
:group_name,
|
||||
:homepage,
|
||||
:maintainer,
|
||||
:architectures,
|
||||
:licenses,
|
||||
:provides,
|
||||
:conflicts,
|
||||
:replaces,
|
||||
:depends,
|
||||
:builddepends,
|
||||
:optdepends
|
||||
);
|
||||
`, pkg)
|
||||
session := d.engine.Context(ctx)
|
||||
|
||||
affected, err := session.Where("name = ? AND repository = ?", pkg.Name, pkg.Repository).Update(&pkg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if affected == 0 {
|
||||
_, err = session.Insert(&pkg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Database) GetPkgs(_ context.Context, where string, args ...any) ([]Package, error) {
|
||||
var pkgs []Package
|
||||
err := d.engine.Where(where, args...).Find(&pkgs)
|
||||
return pkgs, err
|
||||
}
|
||||
|
||||
func (d *Database) GetPkg(where string, args ...any) (*Package, error) {
|
||||
var pkg Package
|
||||
has, err := d.engine.Where(where, args...).Get(&pkg)
|
||||
if err != nil || !has {
|
||||
return nil, err
|
||||
}
|
||||
return &pkg, nil
|
||||
}
|
||||
|
||||
func (d *Database) DeletePkgs(_ context.Context, where string, args ...any) error {
|
||||
_, err := d.engine.Where(where, args...).Delete(&Package{})
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Database) Close() error {
|
||||
if d.conn != nil {
|
||||
return d.conn.Close()
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
func (d *Database) IsEmpty() bool {
|
||||
count, err := d.engine.Count(new(Package))
|
||||
return err != nil || count == 0
|
||||
}
|
||||
|
||||
func (d *Database) Close() error {
|
||||
return d.engine.Close()
|
||||
}
|
||||
|
@ -25,8 +25,6 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
|
||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/config"
|
||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/db"
|
||||
)
|
||||
@ -50,29 +48,29 @@ var testPkg = db.Package{
|
||||
Version: "0.0.1",
|
||||
Release: 1,
|
||||
Epoch: 2,
|
||||
Description: db.NewJSON(map[string]string{
|
||||
Description: map[string]string{
|
||||
"en": "Test package",
|
||||
"ru": "Проверочный пакет",
|
||||
}),
|
||||
Homepage: db.NewJSON(map[string]string{
|
||||
},
|
||||
Homepage: map[string]string{
|
||||
"en": "https://gitea.plemya-x.ru/xpamych/ALR",
|
||||
}),
|
||||
Maintainer: db.NewJSON(map[string]string{
|
||||
},
|
||||
Maintainer: map[string]string{
|
||||
"en": "Evgeniy Khramov <xpamych@yandex.ru>",
|
||||
"ru": "Евгений Храмов <xpamych@yandex.ru>",
|
||||
}),
|
||||
Architectures: db.NewJSON([]string{"arm64", "amd64"}),
|
||||
Licenses: db.NewJSON([]string{"GPL-3.0-or-later"}),
|
||||
Provides: db.NewJSON([]string{"test"}),
|
||||
Conflicts: db.NewJSON([]string{"test"}),
|
||||
Replaces: db.NewJSON([]string{"test-old"}),
|
||||
Depends: db.NewJSON(map[string][]string{
|
||||
},
|
||||
Architectures: []string{"arm64", "amd64"},
|
||||
Licenses: []string{"GPL-3.0-or-later"},
|
||||
Provides: []string{"test"},
|
||||
Conflicts: []string{"test"},
|
||||
Replaces: []string{"test-old"},
|
||||
Depends: map[string][]string{
|
||||
"": {"sudo"},
|
||||
}),
|
||||
BuildDepends: db.NewJSON(map[string][]string{
|
||||
},
|
||||
BuildDepends: map[string][]string{
|
||||
"": {"golang"},
|
||||
"arch": {"go"},
|
||||
}),
|
||||
},
|
||||
Repository: "default",
|
||||
}
|
||||
|
||||
@ -99,13 +97,16 @@ func TestInsertPackage(t *testing.T) {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
dbPkg := db.Package{}
|
||||
err = sqlx.Get(database.GetConn(), &dbPkg, "SELECT * FROM pkgs WHERE name = 'test' AND repository = 'default'")
|
||||
pkgs, err := database.GetPkgs(ctx, "name = 'test' AND repository = 'default'")
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(testPkg, dbPkg) {
|
||||
if len(pkgs) != 1 {
|
||||
t.Fatalf("Expected 1 package, got %d", len(pkgs))
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(testPkg, pkgs[0]) {
|
||||
t.Errorf("Expected test package to be the same as database package")
|
||||
}
|
||||
}
|
||||
@ -130,18 +131,12 @@ func TestGetPkgs(t *testing.T) {
|
||||
t.Errorf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
result, err := database.GetPkgs(ctx, "name LIKE 'x%'")
|
||||
pkgs, err := database.GetPkgs(ctx, "name LIKE 'x%'")
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
for result.Next() {
|
||||
var dbPkg db.Package
|
||||
err = result.StructScan(&dbPkg)
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
for _, dbPkg := range pkgs {
|
||||
if !strings.HasPrefix(dbPkg.Name, "x") {
|
||||
t.Errorf("Expected package name to start with 'x', got %s", dbPkg.Name)
|
||||
}
|
||||
@ -168,7 +163,7 @@ func TestGetPkg(t *testing.T) {
|
||||
t.Errorf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
pkg, err := database.GetPkg(ctx, "name LIKE 'x%' ORDER BY name")
|
||||
pkg, err := database.GetPkg("name LIKE 'x%'")
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
@ -206,16 +201,6 @@ func TestDeletePkgs(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
var dbPkg db.Package
|
||||
err = database.GetConn().Get(&dbPkg, "SELECT * FROM pkgs WHERE name LIKE 'x%' ORDER BY name LIMIT 1;")
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
if dbPkg.Name != "x2" {
|
||||
t.Errorf("Expected x2 package, got %s", dbPkg.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestJsonArrayContains(t *testing.T) {
|
||||
@ -227,7 +212,7 @@ func TestJsonArrayContains(t *testing.T) {
|
||||
x1.Name = "x1"
|
||||
x2 := testPkg
|
||||
x2.Name = "x2"
|
||||
x2.Provides.Val = append(x2.Provides.Val, "x")
|
||||
x2.Provides = append(x2.Provides, "x")
|
||||
|
||||
err := database.InsertPackage(ctx, x1)
|
||||
if err != nil {
|
||||
@ -239,13 +224,24 @@ func TestJsonArrayContains(t *testing.T) {
|
||||
t.Errorf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
var dbPkg db.Package
|
||||
err = database.GetConn().Get(&dbPkg, "SELECT * FROM pkgs WHERE json_array_contains(provides, 'x');")
|
||||
pkgs, err := database.GetPkgs(ctx, "name = 'x2'")
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
if dbPkg.Name != "x2" {
|
||||
t.Errorf("Expected x2 package, got %s", dbPkg.Name)
|
||||
if len(pkgs) != 1 || pkgs[0].Name != "x2" {
|
||||
t.Errorf("Expected x2 package, got %v", pkgs)
|
||||
}
|
||||
|
||||
// Verify the provides field contains 'x'
|
||||
found := false
|
||||
for _, p := range pkgs[0].Provides {
|
||||
if p == "x" {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Errorf("Expected provides to contain 'x'")
|
||||
}
|
||||
}
|
||||
|
@ -1,80 +0,0 @@
|
||||
// ALR - Any Linux Repository
|
||||
// Copyright (C) 2025 The ALR Authors
|
||||
//
|
||||
// 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 db
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// JSON represents a JSON value in the database
|
||||
type JSON[T any] struct {
|
||||
Val T
|
||||
}
|
||||
|
||||
// NewJSON creates a new database JSON value
|
||||
func NewJSON[T any](v T) JSON[T] {
|
||||
return JSON[T]{Val: v}
|
||||
}
|
||||
|
||||
func (s *JSON[T]) Scan(val any) error {
|
||||
if val == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch val := val.(type) {
|
||||
case string:
|
||||
err := json.Unmarshal([]byte(val), &s.Val)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case sql.NullString:
|
||||
if val.Valid {
|
||||
err := json.Unmarshal([]byte(val.String), &s.Val)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
default:
|
||||
return errors.New("sqlite json types must be strings")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s JSON[T]) Value() (driver.Value, error) {
|
||||
data, err := json.Marshal(s.Val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return string(data), nil
|
||||
}
|
||||
|
||||
func (s JSON[T]) MarshalYAML() (any, error) {
|
||||
return s.Val, nil
|
||||
}
|
||||
|
||||
func (s JSON[T]) String() string {
|
||||
return fmt.Sprint(s.Val)
|
||||
}
|
||||
|
||||
func (s JSON[T]) GoString() string {
|
||||
return fmt.Sprintf("%#v", s.Val)
|
||||
}
|
@ -40,17 +40,10 @@ func (rs *Repos) FindPkgs(ctx context.Context, pkgs []string) (map[string][]db.P
|
||||
}
|
||||
|
||||
added := 0
|
||||
for result.Next() {
|
||||
var pkg db.Package
|
||||
err = result.StructScan(&pkg)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
for _, pkg := range result {
|
||||
added++
|
||||
found[pkgName] = append(found[pkgName], pkg)
|
||||
}
|
||||
result.Close()
|
||||
|
||||
if added == 0 {
|
||||
result, err := rs.db.GetPkgs(ctx, "name LIKE ?", pkgName)
|
||||
@ -58,18 +51,10 @@ func (rs *Repos) FindPkgs(ctx context.Context, pkgs []string) (map[string][]db.P
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
for result.Next() {
|
||||
var pkg db.Package
|
||||
err = result.StructScan(&pkg)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
for _, pkg := range result {
|
||||
added++
|
||||
found[pkgName] = append(found[pkgName], pkg)
|
||||
}
|
||||
|
||||
result.Close()
|
||||
}
|
||||
|
||||
if added == 0 {
|
||||
|
@ -94,11 +94,11 @@ func TestFindPkgsEmpty(t *testing.T) {
|
||||
Repository: "default",
|
||||
Version: "0.0.1",
|
||||
Release: 1,
|
||||
Description: db.NewJSON(map[string]string{
|
||||
Description: map[string]string{
|
||||
"en": "Test package 1",
|
||||
"ru": "Проверочный пакет 1",
|
||||
}),
|
||||
Provides: db.NewJSON([]string{""}),
|
||||
},
|
||||
Provides: []string{""},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
@ -109,11 +109,11 @@ func TestFindPkgsEmpty(t *testing.T) {
|
||||
Repository: "default",
|
||||
Version: "0.0.1",
|
||||
Release: 1,
|
||||
Description: db.NewJSON(map[string]string{
|
||||
Description: map[string]string{
|
||||
"en": "Test package 2",
|
||||
"ru": "Проверочный пакет 2",
|
||||
}),
|
||||
Provides: db.NewJSON([]string{"test"}),
|
||||
},
|
||||
Provides: []string{"test"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
|
@ -130,7 +130,7 @@ func (rs *Repos) Pull(ctx context.Context, repos []types.Repo) error {
|
||||
// If the DB was not present at startup, that means it's
|
||||
// empty. In this case, we need to update the DB fully
|
||||
// rather than just incrementally.
|
||||
if rs.db.IsEmpty(ctx) {
|
||||
if rs.db.IsEmpty() {
|
||||
err = rs.processRepoFull(ctx, repo, repoDir)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -84,16 +84,10 @@ build_deps=('golang')
|
||||
result, err := database.GetPkgs(ctx, "1 = 1")
|
||||
assert.NoError(t, err)
|
||||
pkgCount := 0
|
||||
for result.Next() {
|
||||
var dbPkg db.Package
|
||||
err = result.StructScan(&dbPkg)
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
for _, dbPkg := range result {
|
||||
assert.Equal(t, "foo", dbPkg.Name)
|
||||
assert.Equal(t, db.NewJSON(map[string]string{"": "main desc"}), dbPkg.Description)
|
||||
assert.Equal(t, db.NewJSON(map[string][]string{"": {"sudo"}}), dbPkg.Depends)
|
||||
assert.Equal(t, map[string]string{"": "main desc"}, dbPkg.Description)
|
||||
assert.Equal(t, map[string][]string{"": {"sudo"}}, dbPkg.Depends)
|
||||
pkgCount++
|
||||
}
|
||||
assert.Equal(t, 1, pkgCount)
|
||||
@ -125,20 +119,18 @@ meta_buz() {
|
||||
assert.NoError(t, err)
|
||||
|
||||
pkgCount := 0
|
||||
for result.Next() {
|
||||
var dbPkg db.Package
|
||||
err = result.StructScan(&dbPkg)
|
||||
for _, dbPkg := range result {
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, got %s", err)
|
||||
}
|
||||
if dbPkg.Name == "bar" {
|
||||
assert.Equal(t, db.NewJSON(map[string]string{"": "foo desc"}), dbPkg.Description)
|
||||
assert.Equal(t, db.NewJSON(map[string][]string{"": {"sudo"}}), dbPkg.Depends)
|
||||
assert.Equal(t, map[string]string{"": "foo desc"}, dbPkg.Description)
|
||||
assert.Equal(t, map[string][]string{"": {"sudo"}}, dbPkg.Depends)
|
||||
}
|
||||
|
||||
if dbPkg.Name == "buz" {
|
||||
assert.Equal(t, db.NewJSON(map[string]string{"": "main desc"}), dbPkg.Description)
|
||||
assert.Equal(t, db.NewJSON(map[string][]string{"": {"sudo", "doas"}}), dbPkg.Depends)
|
||||
assert.Equal(t, map[string]string{"": "main desc"}, dbPkg.Description)
|
||||
assert.Equal(t, map[string][]string{"": {"sudo", "doas"}}, dbPkg.Depends)
|
||||
}
|
||||
pkgCount++
|
||||
}
|
||||
|
@ -129,15 +129,7 @@ func TestPull(t *testing.T) {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
var pkgAmt int
|
||||
for result.Next() {
|
||||
var dbPkg db.Package
|
||||
err = result.StructScan(&dbPkg)
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, got %s", err)
|
||||
}
|
||||
pkgAmt++
|
||||
}
|
||||
pkgAmt := len(result)
|
||||
|
||||
if pkgAmt == 0 {
|
||||
t.Errorf("Expected at least 1 matching package, but got %d", pkgAmt)
|
||||
|
@ -139,14 +139,14 @@ func parseScript(
|
||||
}
|
||||
|
||||
type PackageInfo struct {
|
||||
Version string `sh:"version,required"`
|
||||
Release int `sh:"release,required"`
|
||||
Epoch uint `sh:"epoch"`
|
||||
Architectures db.JSON[[]string] `sh:"architectures"`
|
||||
Licenses db.JSON[[]string] `sh:"license"`
|
||||
Provides db.JSON[[]string] `sh:"provides"`
|
||||
Conflicts db.JSON[[]string] `sh:"conflicts"`
|
||||
Replaces db.JSON[[]string] `sh:"replaces"`
|
||||
Version string `sh:"version,required"`
|
||||
Release int `sh:"release,required"`
|
||||
Epoch uint `sh:"epoch"`
|
||||
Architectures []string `sh:"architectures"`
|
||||
Licenses []string `sh:"license"`
|
||||
Provides []string `sh:"provides"`
|
||||
Conflicts []string `sh:"conflicts"`
|
||||
Replaces []string `sh:"replaces"`
|
||||
}
|
||||
|
||||
func (inf *PackageInfo) ToPackage(repoName string) *db.Package {
|
||||
@ -164,13 +164,13 @@ func (inf *PackageInfo) ToPackage(repoName string) *db.Package {
|
||||
|
||||
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{}),
|
||||
Depends: db.NewJSON(map[string][]string{}),
|
||||
BuildDepends: db.NewJSON(map[string][]string{}),
|
||||
Group: map[string]string{},
|
||||
Summary: map[string]string{},
|
||||
Description: map[string]string{},
|
||||
Homepage: map[string]string{},
|
||||
Maintainer: map[string]string{},
|
||||
Depends: map[string][]string{},
|
||||
BuildDepends: map[string][]string{},
|
||||
Repository: repoName,
|
||||
}
|
||||
}
|
||||
@ -193,8 +193,7 @@ func resolveOverrides(runner *interp.Runner, pkg *db.Package) {
|
||||
override := strings.TrimPrefix(name, prefix)
|
||||
override = strings.TrimPrefix(override, "_")
|
||||
|
||||
field := pkgVal.FieldByName(field)
|
||||
varVal := field.FieldByName("Val")
|
||||
varVal := pkgVal.FieldByName(field)
|
||||
varType := varVal.Type()
|
||||
|
||||
switch varType.Elem().String() {
|
||||
|
@ -22,13 +22,12 @@ package search
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
|
||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/db"
|
||||
database "gitea.plemya-x.ru/Plemya-x/ALR/internal/db"
|
||||
)
|
||||
|
||||
type PackagesProvider interface {
|
||||
GetPkgs(ctx context.Context, where string, args ...any) (*sqlx.Rows, error)
|
||||
GetPkgs(ctx context.Context, where string, args ...any) ([]db.Package, error)
|
||||
}
|
||||
|
||||
type Searcher struct {
|
||||
@ -45,22 +44,7 @@ func (s *Searcher) Search(
|
||||
ctx context.Context,
|
||||
opts *SearchOptions,
|
||||
) ([]database.Package, error) {
|
||||
var packages []database.Package
|
||||
|
||||
where, args := opts.WhereClause()
|
||||
result, err := s.pp.GetPkgs(ctx, where, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for result.Next() {
|
||||
var dbPkg database.Package
|
||||
err = result.StructScan(&dbPkg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
packages = append(packages, dbPkg)
|
||||
}
|
||||
|
||||
return packages, nil
|
||||
packages, err := s.pp.GetPkgs(ctx, where, args...)
|
||||
return packages, err
|
||||
}
|
||||
|
@ -80,20 +80,8 @@ func (d *Decoder) DecodeVar(name string, val any) error {
|
||||
|
||||
dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
|
||||
WeaklyTypedInput: true,
|
||||
DecodeHook: mapstructure.DecodeHookFuncValue(func(from, to reflect.Value) (interface{}, error) {
|
||||
if strings.Contains(to.Type().String(), "db.JSON") {
|
||||
valType := to.FieldByName("Val").Type()
|
||||
if !from.Type().AssignableTo(valType) {
|
||||
return nil, InvalidTypeError{name, from.Type().String(), valType.String()}
|
||||
}
|
||||
|
||||
to.FieldByName("Val").Set(from)
|
||||
return to, nil
|
||||
}
|
||||
return from.Interface(), nil
|
||||
}),
|
||||
Result: val,
|
||||
TagName: "sh",
|
||||
Result: val,
|
||||
TagName: "sh",
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -114,67 +114,63 @@ msgstr ""
|
||||
msgid "Error parsing os-release file"
|
||||
msgstr ""
|
||||
|
||||
#: info.go:42
|
||||
#: info.go:41
|
||||
msgid "Print information about a package"
|
||||
msgstr ""
|
||||
|
||||
#: info.go:47
|
||||
#: info.go:46
|
||||
msgid "Show all information, not just for the current distro"
|
||||
msgstr ""
|
||||
|
||||
#: info.go:68
|
||||
#: info.go:67
|
||||
msgid "Error getting packages"
|
||||
msgstr ""
|
||||
|
||||
#: info.go:76
|
||||
msgid "Error iterating over packages"
|
||||
msgstr ""
|
||||
|
||||
#: info.go:90
|
||||
#: info.go:82
|
||||
msgid "Command info expected at least 1 argument, got %d"
|
||||
msgstr ""
|
||||
|
||||
#: info.go:110
|
||||
#: info.go:102
|
||||
msgid "Error finding packages"
|
||||
msgstr ""
|
||||
|
||||
#: info.go:124
|
||||
#: info.go:116
|
||||
msgid "Can't detect system language"
|
||||
msgstr ""
|
||||
|
||||
#: info.go:141
|
||||
#: info.go:133
|
||||
msgid "Error resolving overrides"
|
||||
msgstr ""
|
||||
|
||||
#: info.go:149 info.go:154
|
||||
#: info.go:141 info.go:146
|
||||
msgid "Error encoding script variables"
|
||||
msgstr ""
|
||||
|
||||
#: install.go:40
|
||||
#: install.go:39
|
||||
msgid "Install a new package"
|
||||
msgstr ""
|
||||
|
||||
#: install.go:52
|
||||
#: install.go:51
|
||||
msgid "Command install expected at least 1 argument, got %d"
|
||||
msgstr ""
|
||||
|
||||
#: install.go:114
|
||||
#: install.go:113
|
||||
msgid "Error when installing the package"
|
||||
msgstr ""
|
||||
|
||||
#: install.go:159
|
||||
#: install.go:151
|
||||
msgid "Remove an installed package"
|
||||
msgstr ""
|
||||
|
||||
#: install.go:178
|
||||
#: install.go:170
|
||||
msgid "Error listing installed packages"
|
||||
msgstr ""
|
||||
|
||||
#: install.go:215
|
||||
#: install.go:199
|
||||
msgid "Command remove expected at least 1 argument, got %d"
|
||||
msgstr ""
|
||||
|
||||
#: install.go:230
|
||||
#: install.go:214
|
||||
msgid "Error removing packages"
|
||||
msgstr ""
|
||||
|
||||
@ -346,11 +342,11 @@ msgid ""
|
||||
"instead!"
|
||||
msgstr ""
|
||||
|
||||
#: internal/db/db.go:137
|
||||
#: internal/db/db.go:95
|
||||
msgid "Database version mismatch; resetting"
|
||||
msgstr ""
|
||||
|
||||
#: internal/db/db.go:144
|
||||
#: internal/db/db.go:101
|
||||
msgid ""
|
||||
"Database version does not exist. Run alr fix if something isn't working."
|
||||
msgstr ""
|
||||
@ -429,11 +425,11 @@ msgstr ""
|
||||
msgid "No packages for upgrade"
|
||||
msgstr ""
|
||||
|
||||
#: list.go:102 list.go:187
|
||||
#: list.go:102 list.go:184
|
||||
msgid "Error parsing format template"
|
||||
msgstr ""
|
||||
|
||||
#: list.go:108 list.go:191
|
||||
#: list.go:108 list.go:188
|
||||
msgid "Error executing template"
|
||||
msgstr ""
|
||||
|
||||
|
@ -121,67 +121,63 @@ msgstr "Такой вспомогательной команды нет"
|
||||
msgid "Error parsing os-release file"
|
||||
msgstr "Ошибка при разборе файла выпуска операционной системы"
|
||||
|
||||
#: info.go:42
|
||||
#: info.go:41
|
||||
msgid "Print information about a package"
|
||||
msgstr "Отобразить информацию о пакете"
|
||||
|
||||
#: info.go:47
|
||||
#: info.go:46
|
||||
msgid "Show all information, not just for the current distro"
|
||||
msgstr "Показывать всю информацию, не только для текущего дистрибутива"
|
||||
|
||||
#: info.go:68
|
||||
#: info.go:67
|
||||
msgid "Error getting packages"
|
||||
msgstr "Ошибка при получении пакетов"
|
||||
|
||||
#: info.go:76
|
||||
msgid "Error iterating over packages"
|
||||
msgstr "Ошибка при переборе пакетов"
|
||||
|
||||
#: info.go:90
|
||||
#: info.go:82
|
||||
msgid "Command info expected at least 1 argument, got %d"
|
||||
msgstr "Для команды info ожидался хотя бы 1 аргумент, получено %d"
|
||||
|
||||
#: info.go:110
|
||||
#: info.go:102
|
||||
msgid "Error finding packages"
|
||||
msgstr "Ошибка при поиске пакетов"
|
||||
|
||||
#: info.go:124
|
||||
#: info.go:116
|
||||
msgid "Can't detect system language"
|
||||
msgstr "Ошибка при определении языка системы"
|
||||
|
||||
#: info.go:141
|
||||
#: info.go:133
|
||||
msgid "Error resolving overrides"
|
||||
msgstr "Ошибка устранения переорпеделений"
|
||||
|
||||
#: info.go:149 info.go:154
|
||||
#: info.go:141 info.go:146
|
||||
msgid "Error encoding script variables"
|
||||
msgstr "Ошибка кодирования переменных скрита"
|
||||
|
||||
#: install.go:40
|
||||
#: install.go:39
|
||||
msgid "Install a new package"
|
||||
msgstr "Установить новый пакет"
|
||||
|
||||
#: install.go:52
|
||||
#: install.go:51
|
||||
msgid "Command install expected at least 1 argument, got %d"
|
||||
msgstr "Для команды install ожидался хотя бы 1 аргумент, получено %d"
|
||||
|
||||
#: install.go:114
|
||||
#: install.go:113
|
||||
msgid "Error when installing the package"
|
||||
msgstr "Ошибка при установке пакета"
|
||||
|
||||
#: install.go:159
|
||||
#: install.go:151
|
||||
msgid "Remove an installed package"
|
||||
msgstr "Удалить установленный пакет"
|
||||
|
||||
#: install.go:178
|
||||
#: install.go:170
|
||||
msgid "Error listing installed packages"
|
||||
msgstr "Ошибка при составлении списка установленных пакетов"
|
||||
|
||||
#: install.go:215
|
||||
#: install.go:199
|
||||
msgid "Command remove expected at least 1 argument, got %d"
|
||||
msgstr "Для команды remove ожидался хотя бы 1 аргумент, получено %d"
|
||||
|
||||
#: install.go:230
|
||||
#: install.go:214
|
||||
msgid "Error removing packages"
|
||||
msgstr "Ошибка при удалении пакетов"
|
||||
|
||||
@ -359,11 +355,11 @@ msgstr ""
|
||||
"Эта команда устарела и будет удалена в будущем, используйте вместо нее \"%s"
|
||||
"\"!"
|
||||
|
||||
#: internal/db/db.go:137
|
||||
#: internal/db/db.go:95
|
||||
msgid "Database version mismatch; resetting"
|
||||
msgstr "Несоответствие версий базы данных; сброс настроек"
|
||||
|
||||
#: internal/db/db.go:144
|
||||
#: internal/db/db.go:101
|
||||
msgid ""
|
||||
"Database version does not exist. Run alr fix if something isn't working."
|
||||
msgstr ""
|
||||
@ -445,11 +441,11 @@ msgstr "Ошибка при получении пакетов для обнов
|
||||
msgid "No packages for upgrade"
|
||||
msgstr "Нет пакетов к обновлению"
|
||||
|
||||
#: list.go:102 list.go:187
|
||||
#: list.go:102 list.go:184
|
||||
msgid "Error parsing format template"
|
||||
msgstr "Ошибка при разборе шаблона"
|
||||
|
||||
#: list.go:108 list.go:191
|
||||
#: list.go:108 list.go:188
|
||||
msgid "Error executing template"
|
||||
msgstr "Ошибка при выполнении шаблона"
|
||||
|
||||
@ -573,6 +569,9 @@ msgstr "Ошибка при проверке обновлений"
|
||||
msgid "There is nothing to do."
|
||||
msgstr "Здесь нечего делать."
|
||||
|
||||
#~ msgid "Error iterating over packages"
|
||||
#~ msgstr "Ошибка при переборе пакетов"
|
||||
|
||||
#~ msgid "Error pulling repos"
|
||||
#~ msgstr "Ошибка при извлечении репозиториев"
|
||||
|
||||
|
Reference in New Issue
Block a user