diff --git a/build.go b/build.go index 2c63799..a033182 100644 --- a/build.go +++ b/build.go @@ -117,7 +117,7 @@ func BuildCmd() *cli.Command { os.Exit(1) } - builder := build.New( + builder := build.NewBuilder( ctx, types.BuildOpts{ Package: packageName, diff --git a/coverage-badge.svg b/coverage-badge.svg index b7b7768..b686468 100644 --- a/coverage-badge.svg +++ b/coverage-badge.svg @@ -11,7 +11,7 @@ coverage coverage - 19.7% - 19.7% + 20.8% + 20.8% diff --git a/install.go b/install.go index 54982b4..2706ada 100644 --- a/install.go +++ b/install.go @@ -29,9 +29,10 @@ import ( "gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils" "gitea.plemya-x.ru/Plemya-x/ALR/internal/config" - "gitea.plemya-x.ru/Plemya-x/ALR/internal/db" + database "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/pkg/build" + "gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro" "gitea.plemya-x.ru/Plemya-x/ALR/pkg/manager" "gitea.plemya-x.ru/Plemya-x/ALR/pkg/repos" ) @@ -63,22 +64,52 @@ func InstallCmd() *cli.Command { os.Exit(1) } - if config.GetInstance(ctx).AutoPull(ctx) { - err := repos.Pull(ctx, config.Config(ctx).Repos) + cfg := config.New() + db := database.New(cfg) + rs := repos.New(cfg, db) + err := db.Init(ctx) + if err != nil { + slog.Error(gotext.Get("Error db init"), "err", err) + os.Exit(1) + } + + if cfg.AutoPull(ctx) { + err := rs.Pull(ctx, cfg.Repos(ctx)) if err != nil { slog.Error(gotext.Get("Error pulling repositories"), "err", err) os.Exit(1) } } - found, notFound, err := repos.FindPkgs(ctx, args.Slice()) + found, notFound, err := rs.FindPkgs(ctx, args.Slice()) if err != nil { slog.Error(gotext.Get("Error finding packages"), "err", err) os.Exit(1) } pkgs := cliutils.FlattenPkgs(ctx, found, "install", c.Bool("interactive")) - build.InstallPkgs(ctx, pkgs, notFound, types.BuildOpts{ + + opts := types.BuildOpts{ + Manager: mgr, + Clean: c.Bool("clean"), + Interactive: c.Bool("interactive"), + } + + info, err := distro.ParseOSRelease(ctx) + if err != nil { + slog.Error(gotext.Get("Error parsing os release"), "err", err) + os.Exit(1) + } + + builder := build.NewBuilder( + ctx, + opts, + rs, + info, + cfg, + ) + + builder.InstallPkgs(ctx, pkgs, notFound, types.BuildOpts{ Manager: mgr, Clean: c.Bool("clean"), Interactive: c.Bool("interactive"), @@ -86,6 +117,8 @@ func InstallCmd() *cli.Command { return nil }, BashComplete: func(c *cli.Context) { + cfg := config.New() + db := database.New(cfg) result, err := db.GetPkgs(c.Context, "true") if err != nil { slog.Error(gotext.Get("Error getting packages"), "err", err) @@ -94,7 +127,7 @@ func InstallCmd() *cli.Command { defer result.Close() for result.Next() { - var pkg db.Package + var pkg database.Package err = result.StructScan(&pkg) if err != nil { slog.Error(gotext.Get("Error iterating over packages"), "err", err) diff --git a/internal/translations/default.pot b/internal/translations/default.pot index f2e3d0a..9b9b614 100644 --- a/internal/translations/default.pot +++ b/internal/translations/default.pot @@ -138,31 +138,31 @@ msgstr "" msgid "Error encoding script variables" msgstr "" -#: install.go:42 +#: install.go:43 msgid "Install a new package" msgstr "" -#: install.go:56 +#: install.go:57 msgid "Command install expected at least 1 argument, got %d" msgstr "" -#: install.go:91 +#: install.go:124 msgid "Error getting packages" msgstr "" -#: install.go:100 +#: install.go:133 msgid "Error iterating over packages" msgstr "" -#: install.go:113 +#: install.go:146 msgid "Remove an installed package" msgstr "" -#: install.go:118 +#: install.go:151 msgid "Command remove expected at least 1 argument, got %d" msgstr "" -#: install.go:130 +#: install.go:163 msgid "Error removing packages" msgstr "" @@ -301,78 +301,78 @@ msgstr "" msgid "Error while running app" msgstr "" -#: pkg/build/build.go:116 +#: pkg/build/build.go:135 msgid "Failed to prompt user to view build script" msgstr "" -#: pkg/build/build.go:120 +#: pkg/build/build.go:139 msgid "Building package" msgstr "" -#: pkg/build/build.go:164 +#: pkg/build/build.go:183 msgid "Downloading sources" msgstr "" -#: pkg/build/build.go:176 +#: pkg/build/build.go:195 msgid "Building package metadata" msgstr "" -#: pkg/build/build.go:198 +#: pkg/build/build.go:217 msgid "Compressing package" msgstr "" -#: pkg/build/build.go:322 +#: pkg/build/build.go:341 msgid "" "Your system's CPU architecture doesn't match this package. Do you want to " "build anyway?" msgstr "" -#: pkg/build/build.go:336 +#: pkg/build/build.go:355 msgid "This package is already installed" msgstr "" -#: pkg/build/build.go:360 +#: pkg/build/build.go:379 msgid "Installing build dependencies" msgstr "" -#: pkg/build/build.go:371 +#: pkg/build/build.go:390 msgid "Installing dependencies" msgstr "" -#: pkg/build/build.go:419 +#: pkg/build/build.go:431 msgid "The checksums array must be the same length as sources" msgstr "" -#: pkg/build/build.go:470 +#: pkg/build/build.go:482 msgid "Would you like to remove the build dependencies?" msgstr "" -#: pkg/build/build.go:507 +#: pkg/build/build.go:519 msgid "Executing version()" msgstr "" -#: pkg/build/build.go:527 +#: pkg/build/build.go:539 msgid "Updating version" msgstr "" -#: pkg/build/build.go:532 +#: pkg/build/build.go:544 msgid "Executing prepare()" msgstr "" -#: pkg/build/build.go:542 +#: pkg/build/build.go:554 msgid "Executing build()" msgstr "" -#: pkg/build/build.go:558 pkg/build/build.go:586 +#: pkg/build/build.go:570 pkg/build/build.go:598 msgid "Executing %s()" msgstr "" -#: pkg/build/build_legacy.go:196 -msgid "AutoProv is not implemented for this package format, so it's skipped" +#: pkg/build/build.go:657 +msgid "Error installing native packages" msgstr "" -#: pkg/build/build_legacy.go:207 -msgid "AutoReq is not implemented for this package format, so it's skipped" +#: pkg/build/build.go:683 +msgid "Error installing package" msgstr "" #: pkg/build/findDeps.go:35 @@ -387,12 +387,12 @@ msgstr "" msgid "Required dependency found" msgstr "" -#: pkg/build/install.go:44 -msgid "Error installing native packages" +#: pkg/build/utils.go:136 +msgid "AutoProv is not implemented for this package format, so it's skipped" msgstr "" -#: pkg/build/install.go:94 -msgid "Error installing package" +#: pkg/build/utils.go:147 +msgid "AutoReq is not implemented for this package format, so it's skipped" msgstr "" #: pkg/repos/pull.go:79 @@ -461,10 +461,10 @@ msgstr "" msgid "Upgrade all installed packages" msgstr "" -#: upgrade.go:83 +#: upgrade.go:90 msgid "Error checking for updates" msgstr "" -#: upgrade.go:94 +#: upgrade.go:112 msgid "There is nothing to do." msgstr "" diff --git a/internal/translations/po/ru/default.po b/internal/translations/po/ru/default.po index de06d3b..c31e583 100644 --- a/internal/translations/po/ru/default.po +++ b/internal/translations/po/ru/default.po @@ -146,31 +146,31 @@ msgstr "Ошибка устранения переорпеделений" msgid "Error encoding script variables" msgstr "Ошибка кодирования переменных скрита" -#: install.go:42 +#: install.go:43 msgid "Install a new package" msgstr "Установить новый пакет" -#: install.go:56 +#: install.go:57 msgid "Command install expected at least 1 argument, got %d" msgstr "Для команды install ожидался хотя бы 1 аргумент, получено %d" -#: install.go:91 +#: install.go:124 msgid "Error getting packages" msgstr "Ошибка при получении пакетов" -#: install.go:100 +#: install.go:133 msgid "Error iterating over packages" msgstr "Ошибка при переборе пакетов" -#: install.go:113 +#: install.go:146 msgid "Remove an installed package" msgstr "Удалить установленный пакет" -#: install.go:118 +#: install.go:151 msgid "Command remove expected at least 1 argument, got %d" msgstr "Для команды remove ожидался хотя бы 1 аргумент, получено %d" -#: install.go:130 +#: install.go:163 msgid "Error removing packages" msgstr "Ошибка при удалении пакетов" @@ -316,27 +316,27 @@ msgstr "" msgid "Error while running app" msgstr "Ошибка при запуске приложения" -#: pkg/build/build.go:116 +#: pkg/build/build.go:135 msgid "Failed to prompt user to view build script" msgstr "Не удалось предложить пользователю просмотреть скрипт сборки" -#: pkg/build/build.go:120 +#: pkg/build/build.go:139 msgid "Building package" msgstr "Сборка пакета" -#: pkg/build/build.go:164 +#: pkg/build/build.go:183 msgid "Downloading sources" msgstr "Скачивание источников" -#: pkg/build/build.go:176 +#: pkg/build/build.go:195 msgid "Building package metadata" msgstr "Сборка метаданных пакета" -#: pkg/build/build.go:198 +#: pkg/build/build.go:217 msgid "Compressing package" msgstr "Сжатие пакета" -#: pkg/build/build.go:322 +#: pkg/build/build.go:341 msgid "" "Your system's CPU architecture doesn't match this package. Do you want to " "build anyway?" @@ -344,56 +344,54 @@ msgstr "" "Архитектура процессора вашей системы не соответствует этому пакету. Вы все " "равно хотите выполнить сборку?" -#: pkg/build/build.go:336 +#: pkg/build/build.go:355 msgid "This package is already installed" msgstr "Этот пакет уже установлен" -#: pkg/build/build.go:360 +#: pkg/build/build.go:379 msgid "Installing build dependencies" msgstr "Установка зависимостей сборки" -#: pkg/build/build.go:371 +#: pkg/build/build.go:390 msgid "Installing dependencies" msgstr "Установка зависимостей" -#: pkg/build/build.go:419 +#: pkg/build/build.go:431 msgid "The checksums array must be the same length as sources" msgstr "Массив контрольных сумм должен быть той же длины, что и источники" -#: pkg/build/build.go:470 +#: pkg/build/build.go:482 msgid "Would you like to remove the build dependencies?" msgstr "Хотели бы вы удалить зависимости сборки?" -#: pkg/build/build.go:507 +#: pkg/build/build.go:519 msgid "Executing version()" msgstr "Исполнение версия()" -#: pkg/build/build.go:527 +#: pkg/build/build.go:539 msgid "Updating version" msgstr "Обновление версии" -#: pkg/build/build.go:532 +#: pkg/build/build.go:544 msgid "Executing prepare()" msgstr "Исполнение prepare()" -#: pkg/build/build.go:542 +#: pkg/build/build.go:554 msgid "Executing build()" msgstr "Исполнение build()" -#: pkg/build/build.go:558 pkg/build/build.go:586 +#: pkg/build/build.go:570 pkg/build/build.go:598 #, fuzzy msgid "Executing %s()" msgstr "Исполнение files()" -#: pkg/build/build_legacy.go:196 -msgid "AutoProv is not implemented for this package format, so it's skipped" -msgstr "" -"AutoProv не реализовано для этого формата пакета, поэтому будет пропущено" +#: pkg/build/build.go:657 +msgid "Error installing native packages" +msgstr "Ошибка при установке нативных пакетов" -#: pkg/build/build_legacy.go:207 -msgid "AutoReq is not implemented for this package format, so it's skipped" -msgstr "" -"AutoReq не реализовано для этого формата пакета, поэтому будет пропущено" +#: pkg/build/build.go:683 +msgid "Error installing package" +msgstr "Ошибка при установке пакета" #: pkg/build/findDeps.go:35 msgid "Command not found on the system" @@ -407,13 +405,15 @@ msgstr "Найденная предоставленная зависимость msgid "Required dependency found" msgstr "Найдена требуемая зависимость" -#: pkg/build/install.go:44 -msgid "Error installing native packages" -msgstr "Ошибка при установке нативных пакетов" +#: pkg/build/utils.go:136 +msgid "AutoProv is not implemented for this package format, so it's skipped" +msgstr "" +"AutoProv не реализовано для этого формата пакета, поэтому будет пропущено" -#: pkg/build/install.go:94 -msgid "Error installing package" -msgstr "Ошибка при установке пакета" +#: pkg/build/utils.go:147 +msgid "AutoReq is not implemented for this package format, so it's skipped" +msgstr "" +"AutoReq не реализовано для этого формата пакета, поэтому будет пропущено" #: pkg/repos/pull.go:79 msgid "Pulling repository" @@ -483,11 +483,11 @@ msgstr "Скачать все изменённые репозитории" msgid "Upgrade all installed packages" msgstr "Обновить все установленные пакеты" -#: upgrade.go:83 +#: upgrade.go:90 msgid "Error checking for updates" msgstr "Ошибка при проверке обновлений" -#: upgrade.go:94 +#: upgrade.go:112 msgid "There is nothing to do." msgstr "Здесь нечего делать." diff --git a/pkg/build/build.go b/pkg/build/build.go index 9125530..56cd4b0 100644 --- a/pkg/build/build.go +++ b/pkg/build/build.go @@ -41,6 +41,7 @@ import ( "gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils" "gitea.plemya-x.ru/Plemya-x/ALR/internal/config" "gitea.plemya-x.ru/Plemya-x/ALR/internal/cpu" + "gitea.plemya-x.ru/Plemya-x/ALR/internal/db" "gitea.plemya-x.ru/Plemya-x/ALR/internal/dl" "gitea.plemya-x.ru/Plemya-x/ALR/internal/dlcache" "gitea.plemya-x.ru/Plemya-x/ALR/internal/shutils/decoder" @@ -49,23 +50,31 @@ import ( "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/manager" - "gitea.plemya-x.ru/Plemya-x/ALR/pkg/repos" ) +type PackageFinder interface { + FindPkgs(ctx context.Context, pkgs []string) (map[string][]db.Package, []string, error) +} + +type Config interface { + GetPaths(ctx context.Context) *config.Paths + PagerStyle(ctx context.Context) string +} + type Builder struct { ctx context.Context opts types.BuildOpts info *distro.OSRelease - repos *repos.Repos - config *config.ALRConfig + repos PackageFinder + config Config } -func New( +func NewBuilder( ctx context.Context, opts types.BuildOpts, - repos *repos.Repos, + repos PackageFinder, info *distro.OSRelease, - config *config.ALRConfig, + config Config, ) *Builder { return &Builder{ ctx: ctx, @@ -76,6 +85,16 @@ func New( } } +func (b *Builder) UpdateOptsFromPkg(pkg *db.Package) { + repodir := b.config.GetPaths(b.ctx).RepoDir + if pkg.BasePkgName != "" { + b.opts.Script = filepath.Join(repodir, pkg.Repository, pkg.BasePkgName, "alr.sh") + b.opts.Package = pkg.Name + } else { + b.opts.Script = filepath.Join(repodir, pkg.Repository, pkg.Name, "alr.sh") + } +} + func (b *Builder) BuildPackage(ctx context.Context) ([]string, []string, error) { fl, err := readScript(b.opts.Script) if err != nil { @@ -151,7 +170,7 @@ func (b *Builder) BuildPackage(ctx context.Context) ([]string, []string, error) return nil, nil, err } - err = installOptDeps(ctx, b.repos, vars, b.opts) // Устанавливаем опциональные зависимости + err = b.installOptDeps(ctx, vars) // Устанавливаем опциональные зависимости if err != nil { return nil, nil, err } @@ -352,7 +371,7 @@ func (b *Builder) installBuildDeps(ctx context.Context, vars *types.BuildVars) ( return nil, err } - found, notFound, err := repos.FindPkgs(ctx, deps) // Находим пакеты-зависимости + found, notFound, err := b.repos.FindPkgs(ctx, deps) // Находим пакеты-зависимости if err != nil { return nil, err } @@ -361,7 +380,7 @@ func (b *Builder) installBuildDeps(ctx context.Context, vars *types.BuildVars) ( flattened := cliutils.FlattenPkgs(ctx, found, "install", b.opts.Interactive) // Уплощаем список зависимостей buildDeps = packageNames(flattened) - InstallPkgs(ctx, flattened, notFound, b.opts) // Устанавливаем пакеты + b.InstallPkgs(ctx, flattened, notFound, b.opts) // Устанавливаем пакеты } return buildDeps, nil } @@ -370,7 +389,7 @@ func (b *Builder) buildALRDeps(ctx context.Context, vars *types.BuildVars) (buil if len(vars.Depends) > 0 { slog.Info(gotext.Get("Installing dependencies")) - found, notFound, err := repos.FindPkgs(ctx, vars.Depends) // Поиск зависимостей + found, notFound, err := b.repos.FindPkgs(ctx, vars.Depends) // Поиск зависимостей if err != nil { return nil, nil, nil, err } @@ -380,16 +399,9 @@ func (b *Builder) buildALRDeps(ctx context.Context, vars *types.BuildVars) (buil pkgs := cliutils.FlattenPkgs(ctx, found, "install", b.opts.Interactive) for _, pkg := range pkgs { - newOpts := b.opts - UpdateOpts(ctx, &newOpts, &pkg) - newB := New( - ctx, - newOpts, - b.repos, - b.info, - b.config, - ) + newB := *b + newB.UpdateOptsFromPkg(&pkg) // Собираем зависимости pkgPaths, pkgNames, err := newB.BuildPackage(ctx) @@ -402,7 +414,7 @@ func (b *Builder) buildALRDeps(ctx context.Context, vars *types.BuildVars) (buil // Добавляем пути всех собранных пакетов в builtPaths builtNames = append(builtNames, pkgNames...) // Добавляем имя текущего пакета в builtNames - builtNames = append(builtNames, filepath.Base(filepath.Dir(newOpts.Script))) + builtNames = append(builtNames, filepath.Base(filepath.Dir(newB.opts.Script))) } } @@ -605,3 +617,72 @@ func (b *Builder) executeFunctions( return output, nil } + +func (b *Builder) installOptDeps(ctx context.Context, vars *types.BuildVars) error { + optDeps, err := removeAlreadyInstalled(b.opts, vars.OptDepends) + if err != nil { + return err + } + if len(optDeps) > 0 { + optDeps, err := cliutils.ChooseOptDepends(ctx, optDeps, "install", b.opts.Interactive) // Пользователя просят выбрать опциональные зависимости + if err != nil { + return err + } + + if len(optDeps) == 0 { + return nil + } + + found, notFound, err := b.repos.FindPkgs(ctx, optDeps) // Находим опциональные зависимости + if err != nil { + return err + } + + flattened := cliutils.FlattenPkgs(ctx, found, "install", b.opts.Interactive) + b.InstallPkgs(ctx, flattened, notFound, b.opts) // Устанавливаем выбранные пакеты + } + return nil +} + +func (b *Builder) InstallPkgs( + ctx context.Context, + alrPkgs []db.Package, + nativePkgs []string, + opts types.BuildOpts, +) { + if len(nativePkgs) > 0 { + err := opts.Manager.Install(nil, nativePkgs...) + // Если есть нативные пакеты, выполняем их установку + if err != nil { + slog.Error(gotext.Get("Error installing native packages"), "err", err) + os.Exit(1) + // Логируем и завершаем выполнение при ошибке + } + } + + b.InstallALRPackages(ctx, alrPkgs, opts) + // Устанавливаем скрипты сборки через функцию InstallScripts +} + +func (b *Builder) InstallALRPackages(ctx context.Context, pkgs []db.Package, opts types.BuildOpts) { + for _, pkg := range pkgs { + builder := *b + builder.UpdateOptsFromPkg(&pkg) + + builtPkgs, _, err := builder.BuildPackage(ctx) + // Выполняем сборку пакета + if err != nil { + slog.Error(gotext.Get("Error building package"), "err", err) + os.Exit(1) + // Логируем и завершаем выполнение при ошибке сборки + } + + err = opts.Manager.InstallLocal(nil, builtPkgs...) + // Устанавливаем локально собранные пакеты + if err != nil { + slog.Error(gotext.Get("Error installing package"), "err", err) + os.Exit(1) + // Логируем и завершаем выполнение при ошибке установки + } + } +} diff --git a/pkg/build/build_internal_test.go b/pkg/build/build_internal_test.go index e09fac0..afffcbd 100644 --- a/pkg/build/build_internal_test.go +++ b/pkg/build/build_internal_test.go @@ -18,10 +18,18 @@ package build import ( "context" + "fmt" + "os" + "strings" "testing" + "github.com/stretchr/testify/assert" + "mvdan.cc/sh/v3/syntax" + + "gitea.plemya-x.ru/Plemya-x/ALR/internal/config" "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/pkg/distro" "gitea.plemya-x.ru/Plemya-x/ALR/pkg/manager" ) @@ -134,93 +142,143 @@ func (m *TestManager) IsInstalled(pkg string) (bool, error) { return true, nil } -// TODO: fix test -func TestInstallBuildDeps(t *testing.T) { - type testEnv struct { - pf PackageFinder - vars *types.BuildVars - opts types.BuildOpts +type TestConfig struct{} - // Contains pkgs captured by FindPkgsFunc - // capturedPkgs []string +func (c *TestConfig) PagerStyle(ctx context.Context) string { + return "native" +} + +func (c *TestConfig) GetPaths(ctx context.Context) *config.Paths { + return &config.Paths{ + CacheDir: "/tmp", + } +} + +func TestExecuteFirstPassIsSecure(t *testing.T) { + cfg := &TestConfig{} + pf := &TestPackageFinder{} + info := &distro.OSRelease{} + m := &TestManager{} + + opts := types.BuildOpts{ + Manager: m, + Interactive: false, } + ctx := context.Background() + + b := NewBuilder( + ctx, + opts, + pf, + info, + cfg, + ) + + tmpFile, err := os.CreateTemp("", "testfile-") + assert.NoError(t, err) + tmpFilePath := tmpFile.Name() + defer os.Remove(tmpFilePath) + + _, err = os.Stat(tmpFilePath) + assert.NoError(t, err) + + testScript := fmt.Sprintf(`name='test' +version=1.0.0 +release=1 +rm -f %s`, tmpFilePath) + + fl, err := syntax.NewParser().Parse(strings.NewReader(testScript), "alr.sh") + assert.NoError(t, err) + + _, err = b.executeFirstPass(fl) + assert.NoError(t, err) + + _, err = os.Stat(tmpFilePath) + assert.NoError(t, err) +} + +func TestExecuteFirstPassIsCorrect(t *testing.T) { type testCase struct { Name string - Prepare func() *testEnv - Expected func(t *testing.T, e *testEnv, res []string, err error) + Script string + Opts types.BuildOpts + Expected func(t *testing.T, vars *types.BuildVars) } - for _, tc := range []testCase{ - /* - { - Name: "install only needed deps", - Prepare: func() *testEnv { - pf := TestPackageFinder{} - vars := types.BuildVars{} - m := TestManager{} - opts := types.BuildOpts{ - Manager: &m, - Interactive: false, - } + for _, tc := range []testCase{{ + Name: "single package", + Script: `name='test' +version='1.0.0' +release=1 +epoch=2 +desc="Test package" +homepage='https://example.com' +maintainer='Ivan Ivanov' +`, + Opts: types.BuildOpts{ + Manager: &TestManager{}, + Interactive: false, + }, + Expected: func(t *testing.T, vars *types.BuildVars) { + assert.Equal(t, vars.Name, "test") + assert.Equal(t, vars.Version, "1.0.0") + assert.Equal(t, vars.Release, int(1)) + assert.Equal(t, vars.Epoch, uint(2)) + assert.Equal(t, vars.Description, "Test package") + }, + }, { + Name: "multiple packages", + Script: `name=( + foo + bar +) - env := &testEnv{ - pf: &pf, - vars: &vars, - opts: opts, - capturedPkgs: []string{}, - } +version='0.0.1' +release=1 +epoch=2 +desc="Test package" - pf.FindPkgsFunc = func(ctx context.Context, pkgs []string) (map[string][]db.Package, []string, error) { - env.capturedPkgs = append(env.capturedPkgs, pkgs...) - result := make(map[string][]db.Package) - result["bar"] = []db.Package{{ - Name: "bar-pkg", - }} - result["buz"] = []db.Package{{ - Name: "buz-pkg", - }} +meta_foo() { + desc="Foo package" +} - return result, []string{}, nil - } +meta_bar() { - vars.BuildDepends = []string{ - "foo", - "bar", - "buz", - } - m.IsInstalledFunc = func(pkg string) (bool, error) { - if pkg == "foo" { - return true, nil - } else { - return false, nil - } - } +} +`, + Opts: types.BuildOpts{ + Package: "foo", + Manager: &TestManager{}, + Interactive: false, + }, + Expected: func(t *testing.T, vars *types.BuildVars) { + assert.Equal(t, vars.Name, "foo") + assert.Equal(t, vars.Description, "Foo package") + }, + }} { + t.Run(tc.Name, func(t *testing.T) { + cfg := &TestConfig{} + pf := &TestPackageFinder{} + info := &distro.OSRelease{} - return env - }, - Expected: func(t *testing.T, e *testEnv, res []string, err error) { - assert.NoError(t, err) - assert.Len(t, res, 2) - assert.ElementsMatch(t, res, []string{"bar-pkg", "buz-pkg"}) - - assert.ElementsMatch(t, e.capturedPkgs, []string{"bar", "buz"}) - }, - }, - */ - } { - t.Run(tc.Name, func(tt *testing.T) { ctx := context.Background() - env := tc.Prepare() - result, err := installBuildDeps( + b := NewBuilder( ctx, - env.pf, - env.vars, - env.opts, + tc.Opts, + pf, + info, + cfg, ) - tc.Expected(tt, env, result, err) + fl, err := syntax.NewParser().Parse(strings.NewReader(tc.Script), "alr.sh") + assert.NoError(t, err) + + vars, err := b.executeFirstPass(fl) + assert.NoError(t, err) + + tc.Expected(t, vars) }) } } diff --git a/pkg/build/install.go b/pkg/build/install.go deleted file mode 100644 index bdb8c2e..0000000 --- a/pkg/build/install.go +++ /dev/null @@ -1,99 +0,0 @@ -// This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan. -// It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов. -// -// 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 build - -import ( - "context" - "log/slog" - "os" - "path/filepath" - - "github.com/leonelquinteros/gotext" - - "gitea.plemya-x.ru/Plemya-x/ALR/internal/config" - "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/pkg/distro" - "gitea.plemya-x.ru/Plemya-x/ALR/pkg/repos" -) - -// InstallPkgs устанавливает нативные пакеты с использованием менеджера пакетов, -// затем строит и устанавливает пакеты ALR -func InstallPkgs(ctx context.Context, alrPkgs []db.Package, nativePkgs []string, opts types.BuildOpts) { - if len(nativePkgs) > 0 { - err := opts.Manager.Install(nil, nativePkgs...) - // Если есть нативные пакеты, выполняем их установку - if err != nil { - slog.Error(gotext.Get("Error installing native packages"), "err", err) - os.Exit(1) - // Логируем и завершаем выполнение при ошибке - } - } - - InstallALRPackages(ctx, alrPkgs, opts) - // Устанавливаем скрипты сборки через функцию InstallScripts -} - -func UpdateOpts(ctx context.Context, opts *types.BuildOpts, pkg *db.Package) { - repodir := config.GetPaths(ctx).RepoDir - if pkg.BasePkgName != "" { - opts.Script = filepath.Join(repodir, pkg.Repository, pkg.BasePkgName, "alr.sh") - opts.Package = pkg.Name - } else { - opts.Script = filepath.Join(repodir, pkg.Repository, pkg.Name, "alr.sh") - } -} - -// InstallALRPackages строит и устанавливает переданные alr скрипты сборки -func InstallALRPackages(ctx context.Context, pkgs []db.Package, opts types.BuildOpts) { - info, err := distro.ParseOSRelease(ctx) - if err != nil { - slog.Error(gotext.Get("Error parsing os release"), "err", err) - os.Exit(1) - } - - for _, pkg := range pkgs { - UpdateOpts(ctx, &opts, &pkg) - - builder := New( - ctx, - opts, - repos.GetInstance(ctx), - info, - config.GetInstance(ctx), - ) - - builtPkgs, _, err := builder.BuildPackage(ctx) - // Выполняем сборку пакета - if err != nil { - slog.Error(gotext.Get("Error building package"), "err", err) - os.Exit(1) - // Логируем и завершаем выполнение при ошибке сборки - } - - err = opts.Manager.InstallLocal(nil, builtPkgs...) - // Устанавливаем локально собранные пакеты - if err != nil { - slog.Error(gotext.Get("Error installing package"), "err", err) - os.Exit(1) - // Логируем и завершаем выполнение при ошибке установки - } - } -} diff --git a/pkg/build/build_legacy.go b/pkg/build/utils.go similarity index 81% rename from pkg/build/build_legacy.go rename to pkg/build/utils.go index aee4286..e4e879a 100644 --- a/pkg/build/build_legacy.go +++ b/pkg/build/utils.go @@ -1,6 +1,3 @@ -// This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan. -// It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов. -// // ALR - Any Linux Repository // Copyright (C) 2025 Евгений Храмов // @@ -43,7 +40,6 @@ import ( "github.com/goreleaser/nfpm/v2" "github.com/goreleaser/nfpm/v2/files" - "gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils" "gitea.plemya-x.ru/Plemya-x/ALR/internal/cpu" "gitea.plemya-x.ru/Plemya-x/ALR/internal/db" "gitea.plemya-x.ru/Plemya-x/ALR/internal/overrides" @@ -82,62 +78,6 @@ func prepareDirs(dirs types.Directories) error { return os.MkdirAll(dirs.PkgDir, 0o755) // Создаем директорию для пакетов } -type PackageFinder interface { - FindPkgs(ctx context.Context, pkgs []string) (map[string][]db.Package, []string, error) -} - -// Функция installBuildDeps устанавливает все зависимости сборки, которые еще не установлены, и возвращает -// срез, содержащий имена всех установленных пакетов. -func installBuildDeps(ctx context.Context, repos PackageFinder, vars *types.BuildVars, opts types.BuildOpts) ([]string, error) { - var buildDeps []string - if len(vars.BuildDepends) > 0 { - deps, err := removeAlreadyInstalled(opts, vars.BuildDepends) - if err != nil { - return nil, err - } - - found, notFound, err := repos.FindPkgs(ctx, deps) // Находим пакеты-зависимости - if err != nil { - return nil, err - } - - slog.Info(gotext.Get("Installing build dependencies")) // Логгируем установку зависимостей - - flattened := cliutils.FlattenPkgs(ctx, found, "install", opts.Interactive) // Уплощаем список зависимостей - buildDeps = packageNames(flattened) - InstallPkgs(ctx, flattened, notFound, opts) // Устанавливаем пакеты - } - return buildDeps, nil -} - -// Функция installOptDeps спрашивает у пользователя, какие, если таковые имеются, опциональные зависимости он хочет установить. -// Если пользователь решает установить какие-либо опциональные зависимости, выполняется их установка. -func installOptDeps(ctx context.Context, repos PackageFinder, vars *types.BuildVars, opts types.BuildOpts) error { - optDeps, err := removeAlreadyInstalled(opts, vars.OptDepends) - if err != nil { - return err - } - if len(optDeps) > 0 { - optDeps, err := cliutils.ChooseOptDepends(ctx, optDeps, "install", opts.Interactive) // Пользователя просят выбрать опциональные зависимости - if err != nil { - return err - } - - if len(optDeps) == 0 { - return nil - } - - found, notFound, err := repos.FindPkgs(ctx, optDeps) // Находим опциональные зависимости - if err != nil { - return err - } - - flattened := cliutils.FlattenPkgs(ctx, found, "install", opts.Interactive) - InstallPkgs(ctx, flattened, notFound, opts) // Устанавливаем выбранные пакеты - } - return nil -} - // Функция buildPkgMetadata создает метаданные для пакета, который будет собран. func buildPkgMetadata( ctx context.Context, diff --git a/pkg/repos/repos_legacy.go b/pkg/repos/repos_legacy.go index 046b6fb..d9f0973 100644 --- a/pkg/repos/repos_legacy.go +++ b/pkg/repos/repos_legacy.go @@ -40,7 +40,7 @@ func Pull(ctx context.Context, repos []types.Repo) error { // It also returns a slice that contains the names of all packages that were not found. // // Deprecated: use struct method -func FindPkgs(ctx context.Context, pkgs []string) (map[string][]database.Package, []string, error) { +func FindPkgs_(ctx context.Context, pkgs []string) (map[string][]database.Package, []string, error) { return GetInstance(ctx).FindPkgs(ctx, pkgs) } diff --git a/upgrade.go b/upgrade.go index e7b152a..553cf41 100644 --- a/upgrade.go +++ b/upgrade.go @@ -32,7 +32,7 @@ import ( "golang.org/x/exp/slices" "gitea.plemya-x.ru/Plemya-x/ALR/internal/config" - "gitea.plemya-x.ru/Plemya-x/ALR/internal/db" + 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/types" "gitea.plemya-x.ru/Plemya-x/ALR/pkg/build" @@ -56,7 +56,14 @@ func UpgradeCmd() *cli.Command { Action: func(c *cli.Context) error { ctx := c.Context - cfg := config.GetInstance(ctx) + cfg := config.New() + db := database.New(cfg) + rs := repos.New(cfg, db) + err := db.Init(ctx) + if err != nil { + slog.Error(gotext.Get("Error db init"), "err", err) + os.Exit(1) + } info, err := distro.ParseOSRelease(ctx) if err != nil { @@ -71,21 +78,32 @@ func UpgradeCmd() *cli.Command { } if cfg.AutoPull(ctx) { - err = repos.Pull(ctx, config.Config(ctx).Repos) + err = rs.Pull(ctx, cfg.Repos(ctx)) if err != nil { slog.Error(gotext.Get("Error pulling repos"), "err", err) os.Exit(1) } } - updates, err := checkForUpdates(ctx, mgr, info) + updates, err := checkForUpdates(ctx, mgr, cfg, rs, info) if err != nil { slog.Error(gotext.Get("Error checking for updates"), "err", err) os.Exit(1) } if len(updates) > 0 { - build.InstallPkgs(ctx, updates, nil, types.BuildOpts{ + builder := build.NewBuilder( + ctx, + types.BuildOpts{ + Manager: mgr, + Clean: c.Bool("clean"), + Interactive: c.Bool("interactive"), + }, + rs, + info, + cfg, + ) + builder.InstallPkgs(ctx, updates, nil, types.BuildOpts{ Manager: mgr, Clean: c.Bool("clean"), Interactive: c.Bool("interactive"), @@ -99,27 +117,33 @@ func UpgradeCmd() *cli.Command { } } -func checkForUpdates(ctx context.Context, mgr manager.Manager, info *distro.OSRelease) ([]db.Package, error) { +func checkForUpdates( + ctx context.Context, + mgr manager.Manager, + cfg *config.ALRConfig, + rs *repos.Repos, + info *distro.OSRelease, +) ([]database.Package, error) { installed, err := mgr.ListInstalled(nil) if err != nil { return nil, err } pkgNames := maps.Keys(installed) - found, _, err := repos.FindPkgs(ctx, pkgNames) + found, _, err := rs.FindPkgs(ctx, pkgNames) if err != nil { return nil, err } - var out []db.Package + var out []database.Package for pkgName, pkgs := range found { - if slices.Contains(config.Config(ctx).IgnorePkgUpdates, pkgName) { + if slices.Contains(cfg.IgnorePkgUpdates(ctx), pkgName) { continue } if len(pkgs) > 1 { // Puts the element with the highest version first - slices.SortFunc(pkgs, func(a, b db.Package) int { + slices.SortFunc(pkgs, func(a, b database.Package) int { return vercmp.Compare(a.Version, b.Version) }) }