refactor(yay): move cfg inside of runtime (#2259)

* rework relationship between runtime and cfg

* separate runtime from cfg

* simplify instantiation logic

* move installer to appropriate package

* move operator to sync package

* add tests for srcinfo service

* consolidate srcinfo service in sync

* add logger to srcinfo

* add logger to preparer

* remove unused text functions

* remove remaining text.* from srcinfo

* remove global logger parts

* remove global org method exports

* remove global logger

* move text->input

* add rule to prevent fmt.Print

* update golangci go version

* remove outdated FAQs

* remove outdated FAQs
This commit is contained in:
Jo
2023-08-06 21:39:41 +02:00
committed by GitHub
parent 7483393377
commit 8916cd174b
74 changed files with 1475 additions and 1367 deletions

View File

@@ -47,6 +47,7 @@ linters:
# inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint # inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint
disable-all: true disable-all: true
enable: enable:
- forbidigo
- bodyclose - bodyclose
- dogsled - dogsled
- dupl - dupl
@@ -80,8 +81,12 @@ linters:
- whitespace - whitespace
run: run:
go: "1.18" go: "1.20"
timeout: "10m" timeout: "10m"
forbidigo:
forbid:
- p: ^fmt\.Print.*$
msg: Do not commit print statements.
issues: issues:
exclude-rules: exclude-rules:

View File

@@ -111,17 +111,6 @@ pacman -S --needed git base-devel yay
Make sure you have the `Color` option in your `/etc/pacman.conf` Make sure you have the `Color` option in your `/etc/pacman.conf`
(see issue [#123](https://github.com/Jguer/yay/issues/123)). (see issue [#123](https://github.com/Jguer/yay/issues/123)).
- **Yay is not prompting to skip packages during system upgrade.**
The default behavior was changed after
[v8.918](https://github.com/Jguer/yay/releases/tag/v8.918)
(see [3bdb534](https://github.com/Jguer/yay/commit/3bdb5343218d99d40f8a449b887348611f6bdbfc)
and issue [#554](https://github.com/Jguer/yay/issues/554)).
To restore the package-skip behavior use `--combinedupgrade` (make
it permanent by appending `--save`). Note: skipping packages will leave your
system in a
[partially-upgraded state](https://wiki.archlinux.org/index.php/System_maintenance#Partial_upgrades_are_unsupported).
- **Sometimes diffs are printed to the terminal, and other times they are paged via less. How do I fix this?** - **Sometimes diffs are printed to the terminal, and other times they are paged via less. How do I fix this?**
Yay uses `git diff` to display diffs, which by default tells less not to Yay uses `git diff` to display diffs, which by default tells less not to
@@ -137,7 +126,7 @@ pacman -S --needed git base-devel yay
`yay -{OPERATION} --aur` `yay -{OPERATION} --aur`
`yay -{OPERATION} --repo` `yay -{OPERATION} --repo`
- **An `Out Of Date AUR Packages` message is displayed. Why doesn't Yay update them?** - **A `Flagged Out Of Date AUR Packages` message is displayed. Why doesn't Yay update them?**
This message does not mean that updated AUR packages are available. It means This message does not mean that updated AUR packages are available. It means
the packages have been flagged out of date on the AUR, but the packages have been flagged out of date on the AUR, but
@@ -159,21 +148,6 @@ pacman -S --needed git base-devel yay
Check [CONTRIBUTING.md](./CONTRIBUTING.md) for more information. Check [CONTRIBUTING.md](./CONTRIBUTING.md) for more information.
- **What settings do you use?**
```sh
yay -Y --devel --combinedupgrade --batchinstall --save
```
Pacman conf options:
```conf
UseSyslog
Color
CheckSpace
VerbosePkgLists
```
## Support ## Support
All support related to Yay should be requested via GitHub issues. Since Yay is not All support related to Yay should be requested via GitHub issues. Since Yay is not

View File

@@ -2,7 +2,6 @@ package main
import ( import (
"context" "context"
"fmt"
"os" "os"
"path/filepath" "path/filepath"
@@ -11,10 +10,10 @@ import (
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/Jguer/yay/v12/pkg/db" "github.com/Jguer/yay/v12/pkg/db"
"github.com/Jguer/yay/v12/pkg/runtime"
"github.com/Jguer/yay/v12/pkg/settings" "github.com/Jguer/yay/v12/pkg/settings"
"github.com/Jguer/yay/v12/pkg/settings/exe" "github.com/Jguer/yay/v12/pkg/settings/exe"
"github.com/Jguer/yay/v12/pkg/settings/parser" "github.com/Jguer/yay/v12/pkg/settings/parser"
"github.com/Jguer/yay/v12/pkg/text"
) )
// CleanDependencies removes all dangling dependencies in system. // CleanDependencies removes all dangling dependencies in system.
@@ -49,13 +48,13 @@ func cleanRemove(ctx context.Context, cfg *settings.Configuration,
arguments, cfg.Mode, settings.NoConfirm)) arguments, cfg.Mode, settings.NoConfirm))
} }
func syncClean(ctx context.Context, cfg *settings.Configuration, cmdArgs *parser.Arguments, dbExecutor db.Executor) error { func syncClean(ctx context.Context, run *runtime.Runtime, cmdArgs *parser.Arguments, dbExecutor db.Executor) error {
keepInstalled := false keepInstalled := false
keepCurrent := false keepCurrent := false
_, removeAll, _ := cmdArgs.GetArg("c", "clean") _, removeAll, _ := cmdArgs.GetArg("c", "clean")
for _, v := range cfg.Runtime.PacmanConf.CleanMethod { for _, v := range run.PacmanConf.CleanMethod {
if v == "KeepInstalled" { if v == "KeepInstalled" {
keepInstalled = true keepInstalled = true
} else if v == "KeepCurrent" { } else if v == "KeepCurrent" {
@@ -63,14 +62,14 @@ func syncClean(ctx context.Context, cfg *settings.Configuration, cmdArgs *parser
} }
} }
if cfg.Mode.AtLeastRepo() { if run.Cfg.Mode.AtLeastRepo() {
if err := cfg.Runtime.CmdBuilder.Show(cfg.Runtime.CmdBuilder.BuildPacmanCmd(ctx, if err := run.CmdBuilder.Show(run.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, cfg.Mode, settings.NoConfirm)); err != nil { cmdArgs, run.Cfg.Mode, settings.NoConfirm)); err != nil {
return err return err
} }
} }
if !cfg.Mode.AtLeastAUR() { if !run.Cfg.Mode.AtLeastAUR() {
return nil return nil
} }
@@ -81,10 +80,10 @@ func syncClean(ctx context.Context, cfg *settings.Configuration, cmdArgs *parser
question = gotext.Get("Do you want to remove all other AUR packages from cache?") question = gotext.Get("Do you want to remove all other AUR packages from cache?")
} }
fmt.Println(gotext.Get("\nBuild directory:"), cfg.BuildDir) run.Logger.Println(gotext.Get("\nBuild directory:"), run.Cfg.BuildDir)
if text.ContinueTask(os.Stdin, question, true, settings.NoConfirm) { if run.Logger.ContinueTask(question, true, settings.NoConfirm) {
if err := cleanAUR(ctx, cfg, keepInstalled, keepCurrent, removeAll, dbExecutor); err != nil { if err := cleanAUR(ctx, run, keepInstalled, keepCurrent, removeAll, dbExecutor); err != nil {
return err return err
} }
} }
@@ -93,24 +92,24 @@ func syncClean(ctx context.Context, cfg *settings.Configuration, cmdArgs *parser
return nil return nil
} }
if text.ContinueTask(os.Stdin, gotext.Get("Do you want to remove ALL untracked AUR files?"), true, settings.NoConfirm) { if run.Logger.ContinueTask(gotext.Get("Do you want to remove ALL untracked AUR files?"), true, settings.NoConfirm) {
return cleanUntracked(ctx, cfg) return cleanUntracked(ctx, run)
} }
return nil return nil
} }
func cleanAUR(ctx context.Context, cfg *settings.Configuration, func cleanAUR(ctx context.Context, run *runtime.Runtime,
keepInstalled, keepCurrent, removeAll bool, dbExecutor db.Executor, keepInstalled, keepCurrent, removeAll bool, dbExecutor db.Executor,
) error { ) error {
cfg.Runtime.Logger.Println(gotext.Get("removing AUR packages from cache...")) run.Logger.Println(gotext.Get("removing AUR packages from cache..."))
installedBases := mapset.NewThreadUnsafeSet[string]() installedBases := mapset.NewThreadUnsafeSet[string]()
inAURBases := mapset.NewThreadUnsafeSet[string]() inAURBases := mapset.NewThreadUnsafeSet[string]()
remotePackages := dbExecutor.InstalledRemotePackages() remotePackages := dbExecutor.InstalledRemotePackages()
files, err := os.ReadDir(cfg.BuildDir) files, err := os.ReadDir(run.Cfg.BuildDir)
if err != nil { if err != nil {
return err return err
} }
@@ -130,7 +129,7 @@ func cleanAUR(ctx context.Context, cfg *settings.Configuration,
// Querying the AUR is slow and needs internet so don't do it if we // Querying the AUR is slow and needs internet so don't do it if we
// don't need to. // don't need to.
if keepCurrent { if keepCurrent {
info, errInfo := cfg.Runtime.AURClient.Get(ctx, &aur.Query{ info, errInfo := run.AURClient.Get(ctx, &aur.Query{
Needles: cachedPackages, Needles: cachedPackages,
}) })
if errInfo != nil { if errInfo != nil {
@@ -165,20 +164,20 @@ func cleanAUR(ctx context.Context, cfg *settings.Configuration,
} }
} }
dir := filepath.Join(cfg.BuildDir, file.Name()) dir := filepath.Join(run.Cfg.BuildDir, file.Name())
cfg.Runtime.Logger.Debugln("removing", dir) run.Logger.Debugln("removing", dir)
if err = os.RemoveAll(dir); err != nil { if err = os.RemoveAll(dir); err != nil {
cfg.Runtime.Logger.Warnln(gotext.Get("Unable to remove %s: %s", dir, err)) run.Logger.Warnln(gotext.Get("Unable to remove %s: %s", dir, err))
} }
} }
return nil return nil
} }
func cleanUntracked(ctx context.Context, cfg *settings.Configuration) error { func cleanUntracked(ctx context.Context, run *runtime.Runtime) error {
cfg.Runtime.Logger.Println(gotext.Get("removing untracked AUR files from cache...")) run.Logger.Println(gotext.Get("removing untracked AUR files from cache..."))
files, err := os.ReadDir(cfg.BuildDir) files, err := os.ReadDir(run.Cfg.BuildDir)
if err != nil { if err != nil {
return err return err
} }
@@ -188,12 +187,11 @@ func cleanUntracked(ctx context.Context, cfg *settings.Configuration) error {
continue continue
} }
dir := filepath.Join(cfg.BuildDir, file.Name()) dir := filepath.Join(run.Cfg.BuildDir, file.Name())
cfg.Runtime.Logger.Debugln("cleaning", dir) run.Logger.Debugln("cleaning", dir)
if isGitRepository(dir) { if isGitRepository(dir) {
if err := cfg.Runtime.CmdBuilder.Show(cfg.Runtime.CmdBuilder.BuildGitCmd(ctx, dir, "clean", "-fx")); err != nil { if err := run.CmdBuilder.Show(run.CmdBuilder.BuildGitCmd(ctx, dir, "clean", "-fx")); err != nil {
cfg.Runtime.Logger.Warnln(gotext.Get("Unable to clean:"), dir) run.Logger.Warnln(gotext.Get("Unable to clean:"), dir)
return err return err
} }
} }
@@ -206,29 +204,3 @@ func isGitRepository(dir string) bool {
_, err := os.Stat(filepath.Join(dir, ".git")) _, err := os.Stat(filepath.Join(dir, ".git"))
return !os.IsNotExist(err) return !os.IsNotExist(err)
} }
func cleanAfter(ctx context.Context, config *settings.Configuration,
cmdBuilder exe.ICmdBuilder, pkgbuildDirs map[string]string,
) {
fmt.Println(gotext.Get("removing untracked AUR files from cache..."))
i := 0
for _, dir := range pkgbuildDirs {
text.OperationInfoln(gotext.Get("Cleaning (%d/%d): %s", i+1, len(pkgbuildDirs), text.Cyan(dir)))
_, stderr, err := cmdBuilder.Capture(
cmdBuilder.BuildGitCmd(
ctx, dir, "reset", "--hard", "HEAD"))
if err != nil {
text.Errorln(gotext.Get("error resetting %s: %s", dir, stderr))
}
if err := config.Runtime.CmdBuilder.Show(
config.Runtime.CmdBuilder.BuildGitCmd(
ctx, dir, "clean", "-fx", "--exclude", "*.pkg.*")); err != nil {
fmt.Fprintln(os.Stderr, err)
}
i++
}
}

View File

@@ -15,6 +15,7 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/Jguer/yay/v12/pkg/db/mock" "github.com/Jguer/yay/v12/pkg/db/mock"
"github.com/Jguer/yay/v12/pkg/runtime"
"github.com/Jguer/yay/v12/pkg/settings" "github.com/Jguer/yay/v12/pkg/settings"
"github.com/Jguer/yay/v12/pkg/settings/exe" "github.com/Jguer/yay/v12/pkg/settings/exe"
"github.com/Jguer/yay/v12/pkg/settings/parser" "github.com/Jguer/yay/v12/pkg/settings/parser"
@@ -90,15 +91,13 @@ func TestCleanHanging(t *testing.T) {
Runner: mockRunner, Runner: mockRunner,
SudoLoopEnabled: false, SudoLoopEnabled: false,
} }
cfg := &settings.Configuration{
Runtime: &settings.Runtime{CmdBuilder: cmdBuilder},
}
run := &runtime.Runtime{CmdBuilder: cmdBuilder, Cfg: &settings.Configuration{}}
cmdArgs := parser.MakeArguments() cmdArgs := parser.MakeArguments()
cmdArgs.AddArg(tc.args...) cmdArgs.AddArg(tc.args...)
err := handleCmd(context.Background(), err := handleCmd(context.Background(),
cfg, cmdArgs, dbExc, run, cmdArgs, dbExc,
) )
require.NoError(t, err) require.NoError(t, err)

185
cmd.go
View File

@@ -17,6 +17,7 @@ import (
"github.com/Jguer/yay/v12/pkg/intrange" "github.com/Jguer/yay/v12/pkg/intrange"
"github.com/Jguer/yay/v12/pkg/news" "github.com/Jguer/yay/v12/pkg/news"
"github.com/Jguer/yay/v12/pkg/query" "github.com/Jguer/yay/v12/pkg/query"
"github.com/Jguer/yay/v12/pkg/runtime"
"github.com/Jguer/yay/v12/pkg/settings" "github.com/Jguer/yay/v12/pkg/settings"
"github.com/Jguer/yay/v12/pkg/settings/exe" "github.com/Jguer/yay/v12/pkg/settings/exe"
"github.com/Jguer/yay/v12/pkg/settings/parser" "github.com/Jguer/yay/v12/pkg/settings/parser"
@@ -25,8 +26,8 @@ import (
"github.com/Jguer/yay/v12/pkg/vcs" "github.com/Jguer/yay/v12/pkg/vcs"
) )
func usage() { func usage(logger *text.Logger) {
fmt.Println(`Usage: logger.Println(`Usage:
yay yay
yay <operation> [...] yay <operation> [...]
yay <package(s)> yay <package(s)>
@@ -146,50 +147,49 @@ getpkgbuild specific options:
-p --print Print pkgbuild of packages`) -p --print Print pkgbuild of packages`)
} }
func handleCmd(ctx context.Context, cfg *settings.Configuration, func handleCmd(ctx context.Context, run *runtime.Runtime,
cmdArgs *parser.Arguments, dbExecutor db.Executor, cmdArgs *parser.Arguments, dbExecutor db.Executor,
) error { ) error {
if cmdArgs.ExistsArg("h", "help") { if cmdArgs.ExistsArg("h", "help") {
return handleHelp(ctx, cfg, cmdArgs) return handleHelp(ctx, run, cmdArgs)
} }
if cfg.SudoLoop && cmdArgs.NeedRoot(cfg.Mode) { if run.Cfg.SudoLoop && cmdArgs.NeedRoot(run.Cfg.Mode) {
cfg.Runtime.CmdBuilder.SudoLoop() run.CmdBuilder.SudoLoop()
} }
switch cmdArgs.Op { switch cmdArgs.Op {
case "V", "version": case "V", "version":
handleVersion() handleVersion(run.Logger)
return nil return nil
case "D", "database": case "D", "database":
return cfg.Runtime.CmdBuilder.Show(cfg.Runtime.CmdBuilder.BuildPacmanCmd(ctx, return run.CmdBuilder.Show(run.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, cfg.Mode, settings.NoConfirm)) cmdArgs, run.Cfg.Mode, settings.NoConfirm))
case "F", "files": case "F", "files":
return cfg.Runtime.CmdBuilder.Show(cfg.Runtime.CmdBuilder.BuildPacmanCmd(ctx, return run.CmdBuilder.Show(run.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, cfg.Mode, settings.NoConfirm)) cmdArgs, run.Cfg.Mode, settings.NoConfirm))
case "Q", "query": case "Q", "query":
return handleQuery(ctx, cfg, cmdArgs, dbExecutor) return handleQuery(ctx, run, cmdArgs, dbExecutor)
case "R", "remove": case "R", "remove":
return handleRemove(ctx, cfg, cmdArgs, cfg.Runtime.VCSStore) return handleRemove(ctx, run, cmdArgs, run.VCSStore)
case "S", "sync": case "S", "sync":
return handleSync(ctx, cfg, cmdArgs, dbExecutor) return handleSync(ctx, run, cmdArgs, dbExecutor)
case "T", "deptest": case "T", "deptest":
return cfg.Runtime.CmdBuilder.Show(cfg.Runtime.CmdBuilder.BuildPacmanCmd(ctx, return run.CmdBuilder.Show(run.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, cfg.Mode, settings.NoConfirm)) cmdArgs, run.Cfg.Mode, settings.NoConfirm))
case "U", "upgrade": case "U", "upgrade":
return handleUpgrade(ctx, cfg, cmdArgs) return handleUpgrade(ctx, run, cmdArgs)
case "B", "build": case "B", "build":
return handleBuild(ctx, cfg, dbExecutor, cmdArgs) return handleBuild(ctx, run, dbExecutor, cmdArgs)
case "G", "getpkgbuild": case "G", "getpkgbuild":
return handleGetpkgbuild(ctx, cfg, cmdArgs, dbExecutor) return handleGetpkgbuild(ctx, run, cmdArgs, dbExecutor)
case "P", "show": case "P", "show":
return handlePrint(ctx, cfg, cmdArgs, dbExecutor) return handlePrint(ctx, run, cmdArgs, dbExecutor)
case "Y", "yay": case "Y", "yay":
return handleYay(ctx, cfg, cmdArgs, cfg.Runtime.CmdBuilder, return handleYay(ctx, run, cmdArgs, run.CmdBuilder,
dbExecutor, cfg.Runtime.QueryBuilder) dbExecutor, run.QueryBuilder)
case "W", "web": case "W", "web":
return handleWeb(ctx, cfg, cmdArgs) return handleWeb(ctx, run, cmdArgs)
} }
return errors.New(gotext.Get("unhandled operation")) return errors.New(gotext.Get("unhandled operation"))
@@ -219,19 +219,19 @@ func getFilter(cmdArgs *parser.Arguments) (upgrade.Filter, error) {
}, nil }, nil
} }
func handleQuery(ctx context.Context, cfg *settings.Configuration, cmdArgs *parser.Arguments, dbExecutor db.Executor) error { func handleQuery(ctx context.Context, run *runtime.Runtime, cmdArgs *parser.Arguments, dbExecutor db.Executor) error {
if cmdArgs.ExistsArg("u", "upgrades") { if cmdArgs.ExistsArg("u", "upgrades") {
filter, err := getFilter(cmdArgs) filter, err := getFilter(cmdArgs)
if err != nil { if err != nil {
return err return err
} }
return printUpdateList(ctx, cfg, cmdArgs, dbExecutor, return printUpdateList(ctx, run, cmdArgs, dbExecutor,
cmdArgs.ExistsDouble("u", "sysupgrade"), filter) cmdArgs.ExistsDouble("u", "sysupgrade"), filter)
} }
if err := cfg.Runtime.CmdBuilder.Show(cfg.Runtime.CmdBuilder.BuildPacmanCmd(ctx, if err := run.CmdBuilder.Show(run.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, cfg.Mode, settings.NoConfirm)); err != nil { cmdArgs, run.Cfg.Mode, settings.NoConfirm)); err != nil {
if str := err.Error(); strings.Contains(str, "exit status") { if str := err.Error(); strings.Contains(str, "exit status") {
// yay -Qdt should not output anything in case of error // yay -Qdt should not output anything in case of error
return fmt.Errorf("") return fmt.Errorf("")
@@ -243,138 +243,139 @@ func handleQuery(ctx context.Context, cfg *settings.Configuration, cmdArgs *pars
return nil return nil
} }
func handleHelp(ctx context.Context, cfg *settings.Configuration, cmdArgs *parser.Arguments) error { func handleHelp(ctx context.Context, run *runtime.Runtime, cmdArgs *parser.Arguments) error {
usage() usage(run.Logger)
switch cmdArgs.Op { switch cmdArgs.Op {
case "Y", "yay", "G", "getpkgbuild", "P", "show", "W", "web", "B", "build": case "Y", "yay", "G", "getpkgbuild", "P", "show", "W", "web", "B", "build":
return nil return nil
} }
cfg.Runtime.Logger.Println("\npacman operation specific options:") run.Logger.Println("\npacman operation specific options:")
return cfg.Runtime.CmdBuilder.Show(cfg.Runtime.CmdBuilder.BuildPacmanCmd(ctx, return run.CmdBuilder.Show(run.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, cfg.Mode, settings.NoConfirm)) cmdArgs, run.Cfg.Mode, settings.NoConfirm))
} }
func handleVersion() { func handleVersion(logger *text.Logger) {
fmt.Printf("yay v%s - libalpm v%s\n", yayVersion, alpm.Version()) logger.Printf("yay v%s - libalpm v%s\n", yayVersion, alpm.Version())
} }
func handlePrint(ctx context.Context, cfg *settings.Configuration, cmdArgs *parser.Arguments, dbExecutor db.Executor) error { func handlePrint(ctx context.Context, run *runtime.Runtime, cmdArgs *parser.Arguments, dbExecutor db.Executor) error {
switch { switch {
case cmdArgs.ExistsArg("d", "defaultconfig"): case cmdArgs.ExistsArg("d", "defaultconfig"):
tmpConfig := settings.DefaultConfig(yayVersion) tmpConfig := settings.DefaultConfig(yayVersion)
fmt.Printf("%v", tmpConfig) run.Logger.Printf("%v", tmpConfig)
return nil return nil
case cmdArgs.ExistsArg("g", "currentconfig"): case cmdArgs.ExistsArg("g", "currentconfig"):
fmt.Printf("%v", cfg) run.Logger.Printf("%v", run.Cfg)
return nil return nil
case cmdArgs.ExistsArg("w", "news"): case cmdArgs.ExistsArg("w", "news"):
double := cmdArgs.ExistsDouble("w", "news") double := cmdArgs.ExistsDouble("w", "news")
quiet := cmdArgs.ExistsArg("q", "quiet") quiet := cmdArgs.ExistsArg("q", "quiet")
return news.PrintNewsFeed(ctx, cfg.Runtime.HTTPClient, dbExecutor.LastBuildTime(), cfg.BottomUp, double, quiet) return news.PrintNewsFeed(ctx, run.HTTPClient, run.Logger,
dbExecutor.LastBuildTime(), run.Cfg.BottomUp, double, quiet)
case cmdArgs.ExistsArg("c", "complete"): case cmdArgs.ExistsArg("c", "complete"):
return completion.Show(ctx, cfg.Runtime.HTTPClient, dbExecutor, return completion.Show(ctx, run.HTTPClient, dbExecutor,
cfg.AURURL, cfg.CompletionPath, cfg.CompletionInterval, cmdArgs.ExistsDouble("c", "complete")) run.Cfg.AURURL, run.Cfg.CompletionPath, run.Cfg.CompletionInterval, cmdArgs.ExistsDouble("c", "complete"))
case cmdArgs.ExistsArg("s", "stats"): case cmdArgs.ExistsArg("s", "stats"):
return localStatistics(ctx, cfg, dbExecutor) return localStatistics(ctx, run, dbExecutor)
} }
return nil return nil
} }
func handleYay(ctx context.Context, cfg *settings.Configuration, func handleYay(ctx context.Context, run *runtime.Runtime,
cmdArgs *parser.Arguments, cmdBuilder exe.ICmdBuilder, cmdArgs *parser.Arguments, cmdBuilder exe.ICmdBuilder,
dbExecutor db.Executor, queryBuilder query.Builder, dbExecutor db.Executor, queryBuilder query.Builder,
) error { ) error {
switch { switch {
case cmdArgs.ExistsArg("gendb"): case cmdArgs.ExistsArg("gendb"):
return createDevelDB(ctx, cfg, dbExecutor) return createDevelDB(ctx, run, dbExecutor)
case cmdArgs.ExistsDouble("c"): case cmdArgs.ExistsDouble("c"):
return cleanDependencies(ctx, cfg, cmdBuilder, cmdArgs, dbExecutor, true) return cleanDependencies(ctx, run.Cfg, cmdBuilder, cmdArgs, dbExecutor, true)
case cmdArgs.ExistsArg("c", "clean"): case cmdArgs.ExistsArg("c", "clean"):
return cleanDependencies(ctx, cfg, cmdBuilder, cmdArgs, dbExecutor, false) return cleanDependencies(ctx, run.Cfg, cmdBuilder, cmdArgs, dbExecutor, false)
case len(cmdArgs.Targets) > 0: case len(cmdArgs.Targets) > 0:
return displayNumberMenu(ctx, cfg, cmdArgs.Targets, dbExecutor, queryBuilder, cmdArgs) return displayNumberMenu(ctx, run, cmdArgs.Targets, dbExecutor, queryBuilder, cmdArgs)
} }
return nil return nil
} }
func handleWeb(ctx context.Context, cfg *settings.Configuration, cmdArgs *parser.Arguments) error { func handleWeb(ctx context.Context, run *runtime.Runtime, cmdArgs *parser.Arguments) error {
switch { switch {
case cmdArgs.ExistsArg("v", "vote"): case cmdArgs.ExistsArg("v", "vote"):
return handlePackageVote(ctx, cmdArgs.Targets, cfg.Runtime.AURClient, return handlePackageVote(ctx, cmdArgs.Targets, run.AURClient, run.Logger,
cfg.Runtime.VoteClient, true) run.VoteClient, true)
case cmdArgs.ExistsArg("u", "unvote"): case cmdArgs.ExistsArg("u", "unvote"):
return handlePackageVote(ctx, cmdArgs.Targets, cfg.Runtime.AURClient, return handlePackageVote(ctx, cmdArgs.Targets, run.AURClient, run.Logger,
cfg.Runtime.VoteClient, false) run.VoteClient, false)
} }
return nil return nil
} }
func handleGetpkgbuild(ctx context.Context, cfg *settings.Configuration, cmdArgs *parser.Arguments, dbExecutor download.DBSearcher) error { func handleGetpkgbuild(ctx context.Context, run *runtime.Runtime, cmdArgs *parser.Arguments, dbExecutor download.DBSearcher) error {
if cmdArgs.ExistsArg("p", "print") { if cmdArgs.ExistsArg("p", "print") {
return printPkgbuilds(dbExecutor, cfg.Runtime.AURClient, return printPkgbuilds(dbExecutor, run.AURClient,
cfg.Runtime.HTTPClient, cmdArgs.Targets, cfg.Mode, cfg.AURURL) run.HTTPClient, run.Logger, cmdArgs.Targets, run.Cfg.Mode, run.Cfg.AURURL)
} }
return getPkgbuilds(ctx, dbExecutor, cfg.Runtime.AURClient, cfg, return getPkgbuilds(ctx, dbExecutor, run.AURClient, run,
cmdArgs.Targets, cmdArgs.ExistsArg("f", "force")) cmdArgs.Targets, cmdArgs.ExistsArg("f", "force"))
} }
func handleUpgrade(ctx context.Context, func handleUpgrade(ctx context.Context,
config *settings.Configuration, cmdArgs *parser.Arguments, run *runtime.Runtime, cmdArgs *parser.Arguments,
) error { ) error {
return config.Runtime.CmdBuilder.Show(config.Runtime.CmdBuilder.BuildPacmanCmd(ctx, return run.CmdBuilder.Show(run.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, config.Mode, settings.NoConfirm)) cmdArgs, run.Cfg.Mode, settings.NoConfirm))
} }
// -B* options // -B* options
func handleBuild(ctx context.Context, func handleBuild(ctx context.Context,
config *settings.Configuration, dbExecutor db.Executor, cmdArgs *parser.Arguments, run *runtime.Runtime, dbExecutor db.Executor, cmdArgs *parser.Arguments,
) error { ) error {
if cmdArgs.ExistsArg("i", "install") { if cmdArgs.ExistsArg("i", "install") {
return installLocalPKGBUILD(ctx, config, cmdArgs, dbExecutor) return installLocalPKGBUILD(ctx, run, cmdArgs, dbExecutor)
} }
return nil return nil
} }
func handleSync(ctx context.Context, cfg *settings.Configuration, cmdArgs *parser.Arguments, dbExecutor db.Executor) error { func handleSync(ctx context.Context, run *runtime.Runtime, cmdArgs *parser.Arguments, dbExecutor db.Executor) error {
targets := cmdArgs.Targets targets := cmdArgs.Targets
switch { switch {
case cmdArgs.ExistsArg("s", "search"): case cmdArgs.ExistsArg("s", "search"):
return syncSearch(ctx, targets, dbExecutor, cfg.Runtime.QueryBuilder, !cmdArgs.ExistsArg("q", "quiet")) return syncSearch(ctx, targets, dbExecutor, run.QueryBuilder, !cmdArgs.ExistsArg("q", "quiet"))
case cmdArgs.ExistsArg("p", "print", "print-format"): case cmdArgs.ExistsArg("p", "print", "print-format"):
return cfg.Runtime.CmdBuilder.Show(cfg.Runtime.CmdBuilder.BuildPacmanCmd(ctx, return run.CmdBuilder.Show(run.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, cfg.Mode, settings.NoConfirm)) cmdArgs, run.Cfg.Mode, settings.NoConfirm))
case cmdArgs.ExistsArg("c", "clean"): case cmdArgs.ExistsArg("c", "clean"):
return syncClean(ctx, cfg, cmdArgs, dbExecutor) return syncClean(ctx, run, cmdArgs, dbExecutor)
case cmdArgs.ExistsArg("l", "list"): case cmdArgs.ExistsArg("l", "list"):
return syncList(ctx, cfg, cfg.Runtime.HTTPClient, cmdArgs, dbExecutor) return syncList(ctx, run, run.HTTPClient, cmdArgs, dbExecutor)
case cmdArgs.ExistsArg("g", "groups"): case cmdArgs.ExistsArg("g", "groups"):
return cfg.Runtime.CmdBuilder.Show(cfg.Runtime.CmdBuilder.BuildPacmanCmd(ctx, return run.CmdBuilder.Show(run.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, cfg.Mode, settings.NoConfirm)) cmdArgs, run.Cfg.Mode, settings.NoConfirm))
case cmdArgs.ExistsArg("i", "info"): case cmdArgs.ExistsArg("i", "info"):
return syncInfo(ctx, cfg, cmdArgs, targets, dbExecutor) return syncInfo(ctx, run, cmdArgs, targets, dbExecutor)
case cmdArgs.ExistsArg("u", "sysupgrade") || len(cmdArgs.Targets) > 0: case cmdArgs.ExistsArg("u", "sysupgrade") || len(cmdArgs.Targets) > 0:
return syncInstall(ctx, cfg, cmdArgs, dbExecutor) return syncInstall(ctx, run, cmdArgs, dbExecutor)
case cmdArgs.ExistsArg("y", "refresh"): case cmdArgs.ExistsArg("y", "refresh"):
return cfg.Runtime.CmdBuilder.Show(cfg.Runtime.CmdBuilder.BuildPacmanCmd(ctx, return run.CmdBuilder.Show(run.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, cfg.Mode, settings.NoConfirm)) cmdArgs, run.Cfg.Mode, settings.NoConfirm))
} }
return nil return nil
} }
func handleRemove(ctx context.Context, cfg *settings.Configuration, cmdArgs *parser.Arguments, localCache vcs.Store) error { func handleRemove(ctx context.Context, run *runtime.Runtime, cmdArgs *parser.Arguments, localCache vcs.Store) error {
err := cfg.Runtime.CmdBuilder.Show(cfg.Runtime.CmdBuilder.BuildPacmanCmd(ctx, err := run.CmdBuilder.Show(run.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, cfg.Mode, settings.NoConfirm)) cmdArgs, run.Cfg.Mode, settings.NoConfirm))
if err == nil { if err == nil {
localCache.RemovePackages(cmdArgs.Targets) localCache.RemovePackages(cmdArgs.Targets)
} }
@@ -383,7 +384,7 @@ func handleRemove(ctx context.Context, cfg *settings.Configuration, cmdArgs *par
} }
// NumberMenu presents a CLI for selecting packages to install. // NumberMenu presents a CLI for selecting packages to install.
func displayNumberMenu(ctx context.Context, cfg *settings.Configuration, pkgS []string, dbExecutor db.Executor, func displayNumberMenu(ctx context.Context, run *runtime.Runtime, pkgS []string, dbExecutor db.Executor,
queryBuilder query.Builder, cmdArgs *parser.Arguments, queryBuilder query.Builder, cmdArgs *parser.Arguments,
) error { ) error {
queryBuilder.Execute(ctx, dbExecutor, pkgS) queryBuilder.Execute(ctx, dbExecutor, pkgS)
@@ -397,9 +398,9 @@ func displayNumberMenu(ctx context.Context, cfg *settings.Configuration, pkgS []
return nil return nil
} }
cfg.Runtime.Logger.Infoln(gotext.Get("Packages to install (eg: 1 2 3, 1-3 or ^4)")) run.Logger.Infoln(gotext.Get("Packages to install (eg: 1 2 3, 1-3 or ^4)"))
numberBuf, err := cfg.Runtime.Logger.GetInput("", false) numberBuf, err := run.Logger.GetInput("", false)
if err != nil { if err != nil {
return err return err
} }
@@ -415,27 +416,27 @@ func displayNumberMenu(ctx context.Context, cfg *settings.Configuration, pkgS []
cmdArgs.Targets = targets cmdArgs.Targets = targets
if len(cmdArgs.Targets) == 0 { if len(cmdArgs.Targets) == 0 {
fmt.Println(gotext.Get(" there is nothing to do")) run.Logger.Println(gotext.Get(" there is nothing to do"))
return nil return nil
} }
return syncInstall(ctx, cfg, cmdArgs, dbExecutor) return syncInstall(ctx, run, cmdArgs, dbExecutor)
} }
func syncList(ctx context.Context, cfg *settings.Configuration, func syncList(ctx context.Context, run *runtime.Runtime,
httpClient *http.Client, cmdArgs *parser.Arguments, dbExecutor db.Executor, httpClient *http.Client, cmdArgs *parser.Arguments, dbExecutor db.Executor,
) error { ) error {
aur := false aur := false
for i := len(cmdArgs.Targets) - 1; i >= 0; i-- { for i := len(cmdArgs.Targets) - 1; i >= 0; i-- {
if cmdArgs.Targets[i] == "aur" && cfg.Mode.AtLeastAUR() { if cmdArgs.Targets[i] == "aur" && run.Cfg.Mode.AtLeastAUR() {
cmdArgs.Targets = append(cmdArgs.Targets[:i], cmdArgs.Targets[i+1:]...) cmdArgs.Targets = append(cmdArgs.Targets[:i], cmdArgs.Targets[i+1:]...)
aur = true aur = true
} }
} }
if cfg.Mode.AtLeastAUR() && (len(cmdArgs.Targets) == 0 || aur) { if run.Cfg.Mode.AtLeastAUR() && (len(cmdArgs.Targets) == 0 || aur) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, cfg.AURURL+"/packages.gz", http.NoBody) req, err := http.NewRequestWithContext(ctx, http.MethodGet, run.Cfg.AURURL+"/packages.gz", http.NoBody)
if err != nil { if err != nil {
return err return err
} }
@@ -453,22 +454,22 @@ func syncList(ctx context.Context, cfg *settings.Configuration,
for scanner.Scan() { for scanner.Scan() {
name := scanner.Text() name := scanner.Text()
if cmdArgs.ExistsArg("q", "quiet") { if cmdArgs.ExistsArg("q", "quiet") {
fmt.Println(name) run.Logger.Println(name)
} else { } else {
fmt.Printf("%s %s %s", text.Magenta("aur"), text.Bold(name), text.Bold(text.Green(gotext.Get("unknown-version")))) run.Logger.Printf("%s %s %s", text.Magenta("aur"), text.Bold(name), text.Bold(text.Green(gotext.Get("unknown-version"))))
if dbExecutor.LocalPackage(name) != nil { if dbExecutor.LocalPackage(name) != nil {
fmt.Print(text.Bold(text.Blue(gotext.Get(" [Installed]")))) run.Logger.Print(text.Bold(text.Blue(gotext.Get(" [Installed]"))))
} }
fmt.Println() run.Logger.Println()
} }
} }
} }
if cfg.Mode.AtLeastRepo() && (len(cmdArgs.Targets) != 0 || !aur) { if run.Cfg.Mode.AtLeastRepo() && (len(cmdArgs.Targets) != 0 || !aur) {
return cfg.Runtime.CmdBuilder.Show(cfg.Runtime.CmdBuilder.BuildPacmanCmd(ctx, return run.CmdBuilder.Show(run.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, cfg.Mode, settings.NoConfirm)) cmdArgs, run.Cfg.Mode, settings.NoConfirm))
} }
return nil return nil

View File

@@ -19,6 +19,7 @@ import (
"github.com/Jguer/yay/v12/pkg/db/mock" "github.com/Jguer/yay/v12/pkg/db/mock"
mockaur "github.com/Jguer/yay/v12/pkg/dep/mock" mockaur "github.com/Jguer/yay/v12/pkg/dep/mock"
"github.com/Jguer/yay/v12/pkg/query" "github.com/Jguer/yay/v12/pkg/query"
"github.com/Jguer/yay/v12/pkg/runtime"
"github.com/Jguer/yay/v12/pkg/settings" "github.com/Jguer/yay/v12/pkg/settings"
"github.com/Jguer/yay/v12/pkg/settings/exe" "github.com/Jguer/yay/v12/pkg/settings/exe"
"github.com/Jguer/yay/v12/pkg/settings/parser" "github.com/Jguer/yay/v12/pkg/settings/parser"
@@ -103,19 +104,19 @@ func TestYogurtMenuAURDB(t *testing.T) {
}, },
} }
logger := text.NewLogger(io.Discard, os.Stderr, strings.NewReader("1\n"), true, "test") logger := text.NewLogger(io.Discard, os.Stderr, strings.NewReader("1\n"), true, "test")
cfg := &settings.Configuration{
RemoveMake: "no",
Runtime: &settings.Runtime{
Logger: logger,
CmdBuilder: cmdBuilder,
VCSStore: &vcs.Mock{},
QueryBuilder: query.NewSourceQueryBuilder(aurCache, logger, "votes", parser.ModeAny, "name",
true, false, true),
AURClient: aurCache,
},
}
err = handleCmd(context.Background(), cfg, cmdArgs, db) run := &runtime.Runtime{
Cfg: &settings.Configuration{
RemoveMake: "no",
},
Logger: logger,
CmdBuilder: cmdBuilder,
VCSStore: &vcs.Mock{},
QueryBuilder: query.NewSourceQueryBuilder(aurCache, logger, "votes", parser.ModeAny, "name",
true, false, true),
AURClient: aurCache,
}
err = handleCmd(context.Background(), run, cmdArgs, db)
require.NoError(t, err) require.NoError(t, err)
wantCapture := []string{} wantCapture := []string{}

View File

@@ -7,56 +7,3 @@ import (
) )
var ErrPackagesNotFound = errors.New(gotext.Get("could not find all required packages")) var ErrPackagesNotFound = errors.New(gotext.Get("could not find all required packages"))
type NoPkgDestsFoundError struct {
dir string
}
func (e *NoPkgDestsFoundError) Error() string {
return gotext.Get("could not find any package archives listed in %s", e.dir)
}
type SetPkgReasonError struct {
exp bool // explicit
}
func (e *SetPkgReasonError) Error() string {
reason := gotext.Get("explicit")
if !e.exp {
reason = gotext.Get("dependency")
}
return gotext.Get("error updating package install reason to %s", reason)
}
type FindPkgDestError struct {
name, pkgDest string
}
func (e *FindPkgDestError) Error() string {
return gotext.Get(
"the PKGDEST for %s is listed by makepkg but does not exist: %s",
e.name, e.pkgDest)
}
type PkgDestNotInListError struct {
name string
}
func (e *PkgDestNotInListError) Error() string {
return gotext.Get("could not find PKGDEST for: %s", e.name)
}
type FailedIgnoredPkgError struct {
pkgErrors map[string]error
}
func (e *FailedIgnoredPkgError) Error() string {
msg := gotext.Get("Failed to install the following packages. Manual intervention is required:")
for pkg, err := range e.pkgErrors {
msg += "\n" + pkg + " - " + err.Error()
}
return msg
}

22
get.go
View File

@@ -11,24 +11,24 @@ import (
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/Jguer/yay/v12/pkg/download" "github.com/Jguer/yay/v12/pkg/download"
"github.com/Jguer/yay/v12/pkg/settings" "github.com/Jguer/yay/v12/pkg/runtime"
"github.com/Jguer/yay/v12/pkg/settings/parser" "github.com/Jguer/yay/v12/pkg/settings/parser"
"github.com/Jguer/yay/v12/pkg/text" "github.com/Jguer/yay/v12/pkg/text"
) )
// yay -Gp. // yay -Gp.
func printPkgbuilds(dbExecutor download.DBSearcher, aurClient aur.QueryClient, httpClient *http.Client, targets []string, func printPkgbuilds(dbExecutor download.DBSearcher, aurClient aur.QueryClient,
httpClient *http.Client, logger *text.Logger, targets []string,
mode parser.TargetMode, aurURL string, mode parser.TargetMode, aurURL string,
) error { ) error {
pkgbuilds, err := download.PKGBUILDs(dbExecutor, aurClient, httpClient, targets, aurURL, mode) pkgbuilds, err := download.PKGBUILDs(dbExecutor, aurClient, httpClient, logger, targets, aurURL, mode)
if err != nil { if err != nil {
text.Errorln(err) logger.Errorln(err)
} }
if len(pkgbuilds) != 0 { if len(pkgbuilds) != 0 {
for target, pkgbuild := range pkgbuilds { for target, pkgbuild := range pkgbuilds {
fmt.Printf("\n\n# %s\n\n", target) logger.Printf("\n\n# %s\n\n%s", target, string(pkgbuild))
fmt.Print(string(pkgbuild))
} }
} }
@@ -41,7 +41,7 @@ func printPkgbuilds(dbExecutor download.DBSearcher, aurClient aur.QueryClient, h
} }
} }
text.Warnln(gotext.Get("Unable to find the following packages:"), " ", strings.Join(missing, ", ")) logger.Warnln(gotext.Get("Unable to find the following packages:"), " ", strings.Join(missing, ", "))
return fmt.Errorf("") return fmt.Errorf("")
} }
@@ -51,7 +51,7 @@ func printPkgbuilds(dbExecutor download.DBSearcher, aurClient aur.QueryClient, h
// yay -G. // yay -G.
func getPkgbuilds(ctx context.Context, dbExecutor download.DBSearcher, aurClient aur.QueryClient, func getPkgbuilds(ctx context.Context, dbExecutor download.DBSearcher, aurClient aur.QueryClient,
config *settings.Configuration, targets []string, force bool, run *runtime.Runtime, targets []string, force bool,
) error { ) error {
wd, err := os.Getwd() wd, err := os.Getwd()
if err != nil { if err != nil {
@@ -59,9 +59,9 @@ func getPkgbuilds(ctx context.Context, dbExecutor download.DBSearcher, aurClient
} }
cloned, errD := download.PKGBUILDRepos(ctx, dbExecutor, aurClient, cloned, errD := download.PKGBUILDRepos(ctx, dbExecutor, aurClient,
config.Runtime.CmdBuilder, targets, config.Mode, config.AURURL, wd, force) run.CmdBuilder, run.Logger, targets, run.Cfg.Mode, run.Cfg.AURURL, wd, force)
if errD != nil { if errD != nil {
text.Errorln(errD) run.Logger.Errorln(errD)
} }
if len(targets) != len(cloned) { if len(targets) != len(cloned) {
@@ -73,7 +73,7 @@ func getPkgbuilds(ctx context.Context, dbExecutor download.DBSearcher, aurClient
} }
} }
text.Warnln(gotext.Get("Unable to find the following packages:"), " ", strings.Join(missing, ", ")) run.Logger.Warnln(gotext.Get("Unable to find the following packages:"), " ", strings.Join(missing, ", "))
err = fmt.Errorf("") err = fmt.Errorf("")
} }

View File

@@ -12,19 +12,18 @@ import (
"github.com/Jguer/yay/v12/pkg/db" "github.com/Jguer/yay/v12/pkg/db"
"github.com/Jguer/yay/v12/pkg/dep" "github.com/Jguer/yay/v12/pkg/dep"
"github.com/Jguer/yay/v12/pkg/multierror" "github.com/Jguer/yay/v12/pkg/multierror"
"github.com/Jguer/yay/v12/pkg/runtime"
"github.com/Jguer/yay/v12/pkg/settings" "github.com/Jguer/yay/v12/pkg/settings"
"github.com/Jguer/yay/v12/pkg/settings/exe" "github.com/Jguer/yay/v12/pkg/settings/exe"
"github.com/Jguer/yay/v12/pkg/settings/parser" "github.com/Jguer/yay/v12/pkg/settings/parser"
"github.com/Jguer/yay/v12/pkg/sync"
gosrc "github.com/Morganamilo/go-srcinfo" gosrc "github.com/Morganamilo/go-srcinfo"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
var ( var ErrNoBuildFiles = errors.New(gotext.Get("cannot find PKGBUILD and .SRCINFO in directory"))
ErrInstallRepoPkgs = errors.New(gotext.Get("error installing repo packages"))
ErrNoBuildFiles = errors.New(gotext.Get("cannot find PKGBUILD and .SRCINFO in directory"))
)
func srcinfoExists(ctx context.Context, func srcinfoExists(ctx context.Context,
cmdBuilder exe.ICmdBuilder, targetDir string, cmdBuilder exe.ICmdBuilder, targetDir string,
@@ -56,12 +55,12 @@ func srcinfoExists(ctx context.Context,
func installLocalPKGBUILD( func installLocalPKGBUILD(
ctx context.Context, ctx context.Context,
config *settings.Configuration, run *runtime.Runtime,
cmdArgs *parser.Arguments, cmdArgs *parser.Arguments,
dbExecutor db.Executor, dbExecutor db.Executor,
) error { ) error {
aurCache := config.Runtime.AURClient aurCache := run.AURClient
noCheck := strings.Contains(config.MFlags, "--nocheck") noCheck := strings.Contains(run.Cfg.MFlags, "--nocheck")
if len(cmdArgs.Targets) < 1 { if len(cmdArgs.Targets) < 1 {
return errors.New(gotext.Get("no target directories specified")) return errors.New(gotext.Get("no target directories specified"))
@@ -69,7 +68,7 @@ func installLocalPKGBUILD(
srcInfos := map[string]*gosrc.Srcinfo{} srcInfos := map[string]*gosrc.Srcinfo{}
for _, targetDir := range cmdArgs.Targets { for _, targetDir := range cmdArgs.Targets {
if err := srcinfoExists(ctx, config.Runtime.CmdBuilder, targetDir); err != nil { if err := srcinfoExists(ctx, run.CmdBuilder, targetDir); err != nil {
return err return err
} }
@@ -83,13 +82,13 @@ func installLocalPKGBUILD(
grapher := dep.NewGrapher(dbExecutor, aurCache, false, settings.NoConfirm, grapher := dep.NewGrapher(dbExecutor, aurCache, false, settings.NoConfirm,
cmdArgs.ExistsDouble("d", "nodeps"), noCheck, cmdArgs.ExistsArg("needed"), cmdArgs.ExistsDouble("d", "nodeps"), noCheck, cmdArgs.ExistsArg("needed"),
config.Runtime.Logger.Child("grapher")) run.Logger.Child("grapher"))
graph, err := grapher.GraphFromSrcInfos(ctx, nil, srcInfos) graph, err := grapher.GraphFromSrcInfos(ctx, nil, srcInfos)
if err != nil { if err != nil {
return err return err
} }
opService := NewOperationService(ctx, config, dbExecutor) opService := sync.NewOperationService(ctx, dbExecutor, run)
multiErr := &multierror.MultiError{} multiErr := &multierror.MultiError{}
targets := graph.TopoSortedLayerMap(func(name string, ii *dep.InstallInfo) error { targets := graph.TopoSortedLayerMap(func(name string, ii *dep.InstallInfo) error {
if ii.Source == dep.Missing { if ii.Source == dep.Missing {
@@ -101,5 +100,5 @@ func installLocalPKGBUILD(
if err := multiErr.Return(); err != nil { if err := multiErr.Return(); err != nil {
return err return err
} }
return opService.Run(ctx, cmdArgs, targets, []string{}) return opService.Run(ctx, run, cmdArgs, targets, []string{})
} }

View File

@@ -6,6 +6,7 @@ package main
import ( import (
"context" "context"
"fmt" "fmt"
"io"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
@@ -19,12 +20,18 @@ import (
"github.com/Jguer/yay/v12/pkg/db/mock" "github.com/Jguer/yay/v12/pkg/db/mock"
mockaur "github.com/Jguer/yay/v12/pkg/dep/mock" mockaur "github.com/Jguer/yay/v12/pkg/dep/mock"
"github.com/Jguer/yay/v12/pkg/runtime"
"github.com/Jguer/yay/v12/pkg/settings" "github.com/Jguer/yay/v12/pkg/settings"
"github.com/Jguer/yay/v12/pkg/settings/exe" "github.com/Jguer/yay/v12/pkg/settings/exe"
"github.com/Jguer/yay/v12/pkg/settings/parser" "github.com/Jguer/yay/v12/pkg/settings/parser"
"github.com/Jguer/yay/v12/pkg/text"
"github.com/Jguer/yay/v12/pkg/vcs" "github.com/Jguer/yay/v12/pkg/vcs"
) )
func newTestLogger() *text.Logger {
return text.NewLogger(io.Discard, io.Discard, strings.NewReader(""), true, "test")
}
func TestIntegrationLocalInstall(t *testing.T) { func TestIntegrationLocalInstall(t *testing.T) {
makepkgBin := t.TempDir() + "/makepkg" makepkgBin := t.TempDir() + "/makepkg"
pacmanBin := t.TempDir() + "/pacman" pacmanBin := t.TempDir() + "/pacman"
@@ -142,21 +149,21 @@ func TestIntegrationLocalInstall(t *testing.T) {
InstalledRemotePackageNamesFn: func() []string { return []string{} }, InstalledRemotePackageNamesFn: func() []string { return []string{} },
} }
config := &settings.Configuration{ run := &runtime.Runtime{
RemoveMake: "no", Cfg: &settings.Configuration{
Runtime: &settings.Runtime{ RemoveMake: "no",
Logger: NewTestLogger(), },
CmdBuilder: cmdBuilder, Logger: newTestLogger(),
VCSStore: &vcs.Mock{}, CmdBuilder: cmdBuilder,
AURClient: &mockaur.MockAUR{ VCSStore: &vcs.Mock{},
GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) { AURClient: &mockaur.MockAUR{
return []aur.Pkg{}, nil GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
}, return []aur.Pkg{}, nil
}, },
}, },
} }
err = handleCmd(context.Background(), config, cmdArgs, db) err = handleCmd(context.Background(), run, cmdArgs, db)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, mockRunner.ShowCalls, len(wantShow)) require.Len(t, mockRunner.ShowCalls, len(wantShow))
@@ -263,20 +270,19 @@ func TestIntegrationLocalInstallMissingDep(t *testing.T) {
LocalPackageFn: func(string) mock.IPackage { return nil }, LocalPackageFn: func(string) mock.IPackage { return nil },
} }
config := &settings.Configuration{ run := &runtime.Runtime{
Runtime: &settings.Runtime{ Cfg: &settings.Configuration{},
Logger: NewTestLogger(), Logger: newTestLogger(),
CmdBuilder: cmdBuilder, CmdBuilder: cmdBuilder,
VCSStore: &vcs.Mock{}, VCSStore: &vcs.Mock{},
AURClient: &mockaur.MockAUR{ AURClient: &mockaur.MockAUR{
GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) { GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
return []aur.Pkg{}, nil return []aur.Pkg{}, nil
},
}, },
}, },
} }
err = handleCmd(context.Background(), config, cmdArgs, db) err = handleCmd(context.Background(), run, cmdArgs, db)
require.ErrorContains(t, err, wantErr.Error()) require.ErrorContains(t, err, wantErr.Error())
require.Len(t, mockRunner.ShowCalls, len(wantShow)) require.Len(t, mockRunner.ShowCalls, len(wantShow))
@@ -421,21 +427,21 @@ func TestIntegrationLocalInstallNeeded(t *testing.T) {
InstalledRemotePackageNamesFn: func() []string { return []string{} }, InstalledRemotePackageNamesFn: func() []string { return []string{} },
} }
config := &settings.Configuration{ run := &runtime.Runtime{
RemoveMake: "no", Cfg: &settings.Configuration{
Runtime: &settings.Runtime{ RemoveMake: "no",
Logger: NewTestLogger(), },
CmdBuilder: cmdBuilder, Logger: newTestLogger(),
VCSStore: &vcs.Mock{}, CmdBuilder: cmdBuilder,
AURClient: &mockaur.MockAUR{ VCSStore: &vcs.Mock{},
GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) { AURClient: &mockaur.MockAUR{
return []aur.Pkg{}, nil GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
}, return []aur.Pkg{}, nil
}, },
}, },
} }
err = handleCmd(context.Background(), config, cmdArgs, db) err = handleCmd(context.Background(), run, cmdArgs, db)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, mockRunner.ShowCalls, len(wantShow), "show calls: %v", mockRunner.ShowCalls) require.Len(t, mockRunner.ShowCalls, len(wantShow), "show calls: %v", mockRunner.ShowCalls)
@@ -585,22 +591,22 @@ func TestIntegrationLocalInstallGenerateSRCINFO(t *testing.T) {
InstalledRemotePackageNamesFn: func() []string { return []string{} }, InstalledRemotePackageNamesFn: func() []string { return []string{} },
} }
config := &settings.Configuration{ run := &runtime.Runtime{
RemoveMake: "no", Cfg: &settings.Configuration{
Debug: false, RemoveMake: "no",
Runtime: &settings.Runtime{ Debug: false,
Logger: NewTestLogger(), },
CmdBuilder: cmdBuilder, Logger: newTestLogger(),
VCSStore: &vcs.Mock{}, CmdBuilder: cmdBuilder,
AURClient: &mockaur.MockAUR{ VCSStore: &vcs.Mock{},
GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) { AURClient: &mockaur.MockAUR{
return []aur.Pkg{}, nil GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
}, return []aur.Pkg{}, nil
}, },
}, },
} }
err = handleCmd(context.Background(), config, cmdArgs, db) err = handleCmd(context.Background(), run, cmdArgs, db)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, mockRunner.ShowCalls, len(wantShow)) require.Len(t, mockRunner.ShowCalls, len(wantShow))
@@ -651,7 +657,6 @@ func TestIntegrationLocalInstallMissingFiles(t *testing.T) {
wantCapture := []string{} wantCapture := []string{}
captureOverride := func(cmd *exec.Cmd) (stdout string, stderr string, err error) { captureOverride := func(cmd *exec.Cmd) (stdout string, stderr string, err error) {
fmt.Println(cmd.Args)
if cmd.Args[1] == "--printsrcinfo" { if cmd.Args[1] == "--printsrcinfo" {
return string(srcinfo), "", nil return string(srcinfo), "", nil
} }
@@ -722,16 +727,17 @@ func TestIntegrationLocalInstallMissingFiles(t *testing.T) {
}, },
} }
config := &settings.Configuration{ config := &runtime.Runtime{
RemoveMake: "no", Cfg: &settings.Configuration{
Runtime: &settings.Runtime{ RemoveMake: "no",
Logger: NewTestLogger(), Debug: false,
CmdBuilder: cmdBuilder, },
VCSStore: &vcs.Mock{}, Logger: newTestLogger(),
AURClient: &mockaur.MockAUR{ CmdBuilder: cmdBuilder,
GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) { VCSStore: &vcs.Mock{},
return []aur.Pkg{}, nil AURClient: &mockaur.MockAUR{
}, GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
return []aur.Pkg{}, nil
}, },
}, },
} }
@@ -848,16 +854,16 @@ func TestIntegrationLocalInstallWithDepsProvides(t *testing.T) {
InstalledRemotePackageNamesFn: func() []string { return []string{} }, InstalledRemotePackageNamesFn: func() []string { return []string{} },
} }
config := &settings.Configuration{ config := &runtime.Runtime{
RemoveMake: "no", Cfg: &settings.Configuration{
Runtime: &settings.Runtime{ RemoveMake: "no",
Logger: NewTestLogger(), },
CmdBuilder: cmdBuilder, Logger: newTestLogger(),
VCSStore: &vcs.Mock{}, CmdBuilder: cmdBuilder,
AURClient: &mockaur.MockAUR{ VCSStore: &vcs.Mock{},
GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) { AURClient: &mockaur.MockAUR{
return []aur.Pkg{}, nil GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
}, return []aur.Pkg{}, nil
}, },
}, },
} }
@@ -988,21 +994,21 @@ func TestIntegrationLocalInstallTwoSrcInfosWithDeps(t *testing.T) {
InstalledRemotePackageNamesFn: func() []string { return []string{} }, InstalledRemotePackageNamesFn: func() []string { return []string{} },
} }
config := &settings.Configuration{ run := &runtime.Runtime{
RemoveMake: "no", Cfg: &settings.Configuration{
Runtime: &settings.Runtime{ RemoveMake: "no",
Logger: NewTestLogger(), },
CmdBuilder: cmdBuilder, Logger: newTestLogger(),
VCSStore: &vcs.Mock{}, CmdBuilder: cmdBuilder,
AURClient: &mockaur.MockAUR{ VCSStore: &vcs.Mock{},
GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) { AURClient: &mockaur.MockAUR{
return []aur.Pkg{}, nil GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
}, return []aur.Pkg{}, nil
}, },
}, },
} }
err = handleCmd(context.Background(), config, cmdArgs, db) err = handleCmd(context.Background(), run, cmdArgs, db)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, mockRunner.ShowCalls, len(wantShow)) require.Len(t, mockRunner.ShowCalls, len(wantShow))

68
main.go
View File

@@ -9,9 +9,8 @@ import (
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/Jguer/yay/v12/pkg/db"
"github.com/Jguer/yay/v12/pkg/db/ialpm" "github.com/Jguer/yay/v12/pkg/db/ialpm"
"github.com/Jguer/yay/v12/pkg/query" "github.com/Jguer/yay/v12/pkg/runtime"
"github.com/Jguer/yay/v12/pkg/settings" "github.com/Jguer/yay/v12/pkg/settings"
"github.com/Jguer/yay/v12/pkg/settings/parser" "github.com/Jguer/yay/v12/pkg/settings/parser"
"github.com/Jguer/yay/v12/pkg/text" "github.com/Jguer/yay/v12/pkg/text"
@@ -39,6 +38,7 @@ func initGotext() {
} }
func main() { func main() {
fallbackLog := text.NewLogger(os.Stdout, os.Stderr, os.Stdin, false, "fallback")
var ( var (
err error err error
ctx = context.Background() ctx = context.Background()
@@ -47,7 +47,7 @@ func main() {
defer func() { defer func() {
if rec := recover(); rec != nil { if rec := recover(); rec != nil {
text.Errorln(rec) fallbackLog.Errorln(rec)
debug.PrintStack() debug.PrintStack()
} }
@@ -57,15 +57,15 @@ func main() {
initGotext() initGotext()
if os.Geteuid() == 0 { if os.Geteuid() == 0 {
text.Warnln(gotext.Get("Avoid running yay as root/sudo.")) fallbackLog.Warnln(gotext.Get("Avoid running yay as root/sudo."))
} }
configPath := settings.GetConfigPath() configPath := settings.GetConfigPath()
// Parse config // Parse config
cfg, err := settings.NewConfig(configPath, yayVersion) cfg, err := settings.NewConfig(fallbackLog, configPath, yayVersion)
if err != nil { if err != nil {
if str := err.Error(); str != "" { if str := err.Error(); str != "" {
text.Errorln(str) fallbackLog.Errorln(str)
} }
ret = 1 ret = 1
@@ -73,13 +73,9 @@ func main() {
return return
} }
if cfg.Debug { if errS := cfg.RunMigrations(fallbackLog,
text.GlobalLogger.Debug = true
}
if errS := cfg.RunMigrations(
settings.DefaultMigrations(), configPath, yayVersion); errS != nil { settings.DefaultMigrations(), configPath, yayVersion); errS != nil {
text.Errorln(errS) fallbackLog.Errorln(errS)
} }
cmdArgs := parser.MakeArguments() cmdArgs := parser.MakeArguments()
@@ -87,7 +83,7 @@ func main() {
// Parse command line // Parse command line
if err = cfg.ParseCommandLine(cmdArgs); err != nil { if err = cfg.ParseCommandLine(cmdArgs); err != nil {
if str := err.Error(); str != "" { if str := err.Error(); str != "" {
text.Errorln(str) fallbackLog.Errorln(str)
} }
ret = 1 ret = 1
@@ -97,15 +93,15 @@ func main() {
if cfg.SaveConfig { if cfg.SaveConfig {
if errS := cfg.Save(configPath, yayVersion); errS != nil { if errS := cfg.Save(configPath, yayVersion); errS != nil {
text.Errorln(errS) fallbackLog.Errorln(errS)
} }
} }
// Build runtime // Build run
runtime, err := settings.BuildRuntime(cfg, cmdArgs, yayVersion) run, err := runtime.NewRuntime(cfg, cmdArgs, yayVersion)
if err != nil { if err != nil {
if str := err.Error(); str != "" { if str := err.Error(); str != "" {
text.Errorln(str) fallbackLog.Errorln(str)
} }
ret = 1 ret = 1
@@ -113,35 +109,10 @@ func main() {
return return
} }
cfg.Runtime = runtime dbExecutor, err := ialpm.NewExecutor(run.PacmanConf, run.Logger.Child("db"))
cfg.Runtime.QueryBuilder = query.NewSourceQueryBuilder(
cfg.Runtime.AURClient,
cfg.Runtime.Logger.Child("mixed.querybuilder"), cfg.SortBy,
cfg.Mode, cfg.SearchBy,
cfg.BottomUp, cfg.SingleLineResults, cfg.SeparateSources)
var useColor bool
cfg.Runtime.PacmanConf, useColor, err = settings.RetrievePacmanConfig(cmdArgs, cfg.PacmanConf)
if err != nil { if err != nil {
if str := err.Error(); str != "" { if str := err.Error(); str != "" {
text.Errorln(str) fallbackLog.Errorln(str)
}
ret = 1
return
}
cfg.Runtime.CmdBuilder.SetPacmanDBPath(cfg.Runtime.PacmanConf.DBPath)
text.UseColor = useColor
dbExecutor, err := ialpm.NewExecutor(cfg.Runtime.PacmanConf, runtime.Logger.Child("db"))
if err != nil {
if str := err.Error(); str != "" {
text.Errorln(str)
} }
ret = 1 ret = 1
@@ -151,19 +122,18 @@ func main() {
defer func() { defer func() {
if rec := recover(); rec != nil { if rec := recover(); rec != nil {
text.Errorln(rec) fallbackLog.Errorln(rec, string(debug.Stack()))
debug.PrintStack()
} }
dbExecutor.Cleanup() dbExecutor.Cleanup()
}() }()
if err = handleCmd(ctx, cfg, cmdArgs, db.Executor(dbExecutor)); err != nil { if err = handleCmd(ctx, run, cmdArgs, dbExecutor); err != nil {
if str := err.Error(); str != "" { if str := err.Error(); str != "" {
text.Errorln(str) fallbackLog.Errorln(str)
if cmdArgs.ExistsArg("c") && cmdArgs.ExistsArg("y") && cmdArgs.Op == "S" { if cmdArgs.ExistsArg("c") && cmdArgs.ExistsArg("y") && cmdArgs.Op == "S" {
// Remove after 2023-10-01 // Remove after 2023-10-01
text.Errorln("Did you mean 'yay -Yc'?") fallbackLog.Errorln("Did you mean 'yay -Yc'?")
} }
} }

View File

@@ -8,6 +8,7 @@ import (
"github.com/Jguer/yay/v12/pkg/db/ialpm" "github.com/Jguer/yay/v12/pkg/db/ialpm"
"github.com/Jguer/yay/v12/pkg/dep" "github.com/Jguer/yay/v12/pkg/dep"
"github.com/Jguer/yay/v12/pkg/runtime"
"github.com/Jguer/yay/v12/pkg/settings" "github.com/Jguer/yay/v12/pkg/settings"
"github.com/Jguer/yay/v12/pkg/settings/parser" "github.com/Jguer/yay/v12/pkg/settings/parser"
"github.com/Jguer/yay/v12/pkg/text" "github.com/Jguer/yay/v12/pkg/text"
@@ -17,44 +18,45 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
func handleCmd() error { func handleCmd(logger *text.Logger) error {
config, err := settings.NewConfig(settings.GetConfigPath(), "") cfg, err := settings.NewConfig(logger, settings.GetConfigPath(), "")
if err != nil { if err != nil {
return err return err
} }
cmdArgs := parser.MakeArguments() cmdArgs := parser.MakeArguments()
if errP := config.ParseCommandLine(cmdArgs); errP != nil { if errP := cfg.ParseCommandLine(cmdArgs); errP != nil {
return errP return errP
} }
pacmanConf, _, err := settings.RetrievePacmanConfig(cmdArgs, config.PacmanConf) run, err := runtime.NewRuntime(cfg, cmdArgs, "1.0.0")
if err != nil { if err != nil {
return err return err
} }
dbExecutor, err := ialpm.NewExecutor(pacmanConf, text.GlobalLogger) dbExecutor, err := ialpm.NewExecutor(run.PacmanConf, logger)
if err != nil { if err != nil {
return err return err
} }
aurCache, err := metadata.New( aurCache, err := metadata.New(
metadata.WithCacheFilePath( metadata.WithCacheFilePath(
filepath.Join(config.BuildDir, "aur.json"))) filepath.Join(cfg.BuildDir, "aur.json")))
if err != nil { if err != nil {
return errors.Wrap(err, gotext.Get("failed to retrieve aur Cache")) return errors.Wrap(err, gotext.Get("failed to retrieve aur Cache"))
} }
grapher := dep.NewGrapher(dbExecutor, aurCache, true, settings.NoConfirm, grapher := dep.NewGrapher(dbExecutor, aurCache, true, settings.NoConfirm,
cmdArgs.ExistsDouble("d", "nodeps"), false, false, cmdArgs.ExistsDouble("d", "nodeps"), false, false,
config.Runtime.Logger.Child("grapher")) run.Logger.Child("grapher"))
return graphPackage(context.Background(), grapher, cmdArgs.Targets) return graphPackage(context.Background(), grapher, cmdArgs.Targets)
} }
func main() { func main() {
if err := handleCmd(); err != nil { fallbackLog := text.NewLogger(os.Stdout, os.Stderr, os.Stdin, false, "fallback")
text.Errorln(err) if err := handleCmd(fallbackLog); err != nil {
fallbackLog.Errorln(err)
os.Exit(1) os.Exit(1)
} }
} }

View File

@@ -5,8 +5,6 @@ import (
"strings" "strings"
"github.com/Jguer/go-alpm/v2" "github.com/Jguer/go-alpm/v2"
"github.com/Jguer/yay/v12/pkg/text"
) )
type ( type (
@@ -244,7 +242,6 @@ func (g *Graph[T, V]) Prune(node T) []T {
// Remove edges from things that depend on `node`. // Remove edges from things that depend on `node`.
for dependent := range g.dependents[node] { for dependent := range g.dependents[node] {
last := g.dependencies.removeFromDepmap(dependent, node) last := g.dependencies.removeFromDepmap(dependent, node)
text.Debugln("pruning dependent", dependent, last)
if last { if last {
pruned = append(pruned, g.Prune(dependent)...) pruned = append(pruned, g.Prune(dependent)...)
} }
@@ -255,7 +252,6 @@ func (g *Graph[T, V]) Prune(node T) []T {
// Remove all edges from node to the things it depends on. // Remove all edges from node to the things it depends on.
for dependency := range g.dependencies[node] { for dependency := range g.dependencies[node] {
last := g.dependents.removeFromDepmap(dependency, node) last := g.dependents.removeFromDepmap(dependency, node)
text.Debugln("pruning dependency", dependency, last)
if last { if last {
pruned = append(pruned, g.Prune(dependency)...) pruned = append(pruned, g.Prune(dependency)...)
} }

View File

@@ -48,7 +48,7 @@ func AURPKGBUILDRepo(ctx context.Context, cmdBuilder exe.GitCmdBuilder, aurURL,
func AURPKGBUILDRepos( func AURPKGBUILDRepos(
ctx context.Context, ctx context.Context,
cmdBuilder exe.GitCmdBuilder, cmdBuilder exe.GitCmdBuilder, logger *text.Logger,
targets []string, aurURL, dest string, force bool, targets []string, aurURL, dest string, force bool,
) (map[string]bool, error) { ) (map[string]bool, error) {
cloned := make(map[string]bool, len(targets)) cloned := make(map[string]bool, len(targets))
@@ -80,7 +80,7 @@ func AURPKGBUILDRepos(
mux.Unlock() mux.Unlock()
} }
text.OperationInfoln( logger.OperationInfoln(
gotext.Get("(%d/%d) Downloaded PKGBUILD: %s", gotext.Get("(%d/%d) Downloaded PKGBUILD: %s",
progress, len(targets), text.Cyan(target))) progress, len(targets), text.Cyan(target)))

View File

@@ -158,7 +158,7 @@ func TestAURPKGBUILDRepos(t *testing.T) {
GitFlags: []string{}, GitFlags: []string{},
}, },
} }
cloned, err := AURPKGBUILDRepos(context.Background(), cmdBuilder, targets, "https://aur.archlinux.org", dir, false) cloned, err := AURPKGBUILDRepos(context.Background(), cmdBuilder, newTestLogger(), targets, "https://aur.archlinux.org", dir, false)
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, map[string]bool{"yay": true, "yay-bin": false, "yay-git": true}, cloned) assert.EqualValues(t, map[string]bool{"yay": true, "yay-bin": false, "yay-git": true}, cloned)

View File

@@ -81,8 +81,8 @@ func getURLName(pkg db.IPackage) string {
return name return name
} }
func PKGBUILDs(dbExecutor DBSearcher, aurClient aur.QueryClient, httpClient *http.Client, targets []string, func PKGBUILDs(dbExecutor DBSearcher, aurClient aur.QueryClient, httpClient *http.Client,
aurURL string, mode parser.TargetMode, logger *text.Logger, targets []string, aurURL string, mode parser.TargetMode,
) (map[string][]byte, error) { ) (map[string][]byte, error) {
pkgbuilds := make(map[string][]byte, len(targets)) pkgbuilds := make(map[string][]byte, len(targets))
@@ -96,7 +96,7 @@ func PKGBUILDs(dbExecutor DBSearcher, aurClient aur.QueryClient, httpClient *htt
for _, target := range targets { for _, target := range targets {
// Probably replaceable by something in query. // Probably replaceable by something in query.
dbName, name, isAUR, toSkip := getPackageUsableName(dbExecutor, aurClient, target, mode) dbName, name, isAUR, toSkip := getPackageUsableName(dbExecutor, aurClient, logger, target, mode)
if toSkip { if toSkip {
continue continue
} }
@@ -136,7 +136,7 @@ func PKGBUILDs(dbExecutor DBSearcher, aurClient aur.QueryClient, httpClient *htt
} }
func PKGBUILDRepos(ctx context.Context, dbExecutor DBSearcher, aurClient aur.QueryClient, func PKGBUILDRepos(ctx context.Context, dbExecutor DBSearcher, aurClient aur.QueryClient,
cmdBuilder exe.GitCmdBuilder, cmdBuilder exe.GitCmdBuilder, logger *text.Logger,
targets []string, mode parser.TargetMode, aurURL, dest string, force bool, targets []string, mode parser.TargetMode, aurURL, dest string, force bool,
) (map[string]bool, error) { ) (map[string]bool, error) {
cloned := make(map[string]bool, len(targets)) cloned := make(map[string]bool, len(targets))
@@ -151,7 +151,7 @@ func PKGBUILDRepos(ctx context.Context, dbExecutor DBSearcher, aurClient aur.Que
for _, target := range targets { for _, target := range targets {
// Probably replaceable by something in query. // Probably replaceable by something in query.
dbName, name, isAUR, toSkip := getPackageUsableName(dbExecutor, aurClient, target, mode) dbName, name, isAUR, toSkip := getPackageUsableName(dbExecutor, aurClient, logger, target, mode)
if toSkip { if toSkip {
continue continue
} }
@@ -184,11 +184,11 @@ func PKGBUILDRepos(ctx context.Context, dbExecutor DBSearcher, aurClient aur.Que
} }
if aur { if aur {
text.OperationInfoln( logger.OperationInfoln(
gotext.Get("(%d/%d) Downloaded PKGBUILD: %s", gotext.Get("(%d/%d) Downloaded PKGBUILD: %s",
progress, len(targets), text.Cyan(pkgName))) progress, len(targets), text.Cyan(pkgName)))
} else { } else {
text.OperationInfoln( logger.OperationInfoln(
gotext.Get("(%d/%d) Downloaded PKGBUILD from ABS: %s", gotext.Get("(%d/%d) Downloaded PKGBUILD from ABS: %s",
progress, len(targets), text.Cyan(pkgName))) progress, len(targets), text.Cyan(pkgName)))
} }
@@ -206,7 +206,7 @@ func PKGBUILDRepos(ctx context.Context, dbExecutor DBSearcher, aurClient aur.Que
// TODO: replace with dep.ResolveTargets. // TODO: replace with dep.ResolveTargets.
func getPackageUsableName(dbExecutor DBSearcher, aurClient aur.QueryClient, func getPackageUsableName(dbExecutor DBSearcher, aurClient aur.QueryClient,
target string, mode parser.TargetMode, logger *text.Logger, target string, mode parser.TargetMode,
) (dbname, pkgname string, isAUR, toSkip bool) { ) (dbname, pkgname string, isAUR, toSkip bool) {
dbName, name := text.SplitDBFromName(target) dbName, name := text.SplitDBFromName(target)
if dbName != "aur" && mode.AtLeastRepo() { if dbName != "aur" && mode.AtLeastRepo() {
@@ -239,7 +239,7 @@ func getPackageUsableName(dbExecutor DBSearcher, aurClient aur.QueryClient,
Needles: []string{name}, Needles: []string{name},
}) })
if err != nil { if err != nil {
text.Warnln(err) logger.Warnln(err)
return dbName, name, true, true return dbName, name, true, true
} }

View File

@@ -5,6 +5,7 @@ package download
import ( import (
"context" "context"
"io"
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
@@ -22,6 +23,10 @@ import (
"github.com/Jguer/yay/v12/pkg/text" "github.com/Jguer/yay/v12/pkg/text"
) )
func newTestLogger() *text.Logger {
return text.NewLogger(io.Discard, io.Discard, strings.NewReader(""), true, "test")
}
// GIVEN 2 aur packages and 1 in repo // GIVEN 2 aur packages and 1 in repo
// GIVEN package in repo is already present // GIVEN package in repo is already present
// WHEN defining package db as a target // WHEN defining package db as a target
@@ -56,7 +61,7 @@ func TestPKGBUILDReposDefinedDBPull(t *testing.T) {
absPackagesDB: map[string]string{"yay": "core"}, absPackagesDB: map[string]string{"yay": "core"},
} }
cloned, err := PKGBUILDRepos(context.Background(), searcher, mockClient, cloned, err := PKGBUILDRepos(context.Background(), searcher, mockClient,
cmdBuilder, cmdBuilder, newTestLogger(),
targets, parser.ModeAny, "https://aur.archlinux.org", dir, false) targets, parser.ModeAny, "https://aur.archlinux.org", dir, false)
assert.NoError(t, err) assert.NoError(t, err)
@@ -90,7 +95,7 @@ func TestPKGBUILDReposDefinedDBClone(t *testing.T) {
absPackagesDB: map[string]string{"yay": "core"}, absPackagesDB: map[string]string{"yay": "core"},
} }
cloned, err := PKGBUILDRepos(context.Background(), searcher, mockClient, cloned, err := PKGBUILDRepos(context.Background(), searcher, mockClient,
cmdBuilder, cmdBuilder, newTestLogger(),
targets, parser.ModeAny, "https://aur.archlinux.org", dir, false) targets, parser.ModeAny, "https://aur.archlinux.org", dir, false)
assert.NoError(t, err) assert.NoError(t, err)
@@ -124,7 +129,7 @@ func TestPKGBUILDReposClone(t *testing.T) {
absPackagesDB: map[string]string{"yay": "core"}, absPackagesDB: map[string]string{"yay": "core"},
} }
cloned, err := PKGBUILDRepos(context.Background(), searcher, mockClient, cloned, err := PKGBUILDRepos(context.Background(), searcher, mockClient,
cmdBuilder, cmdBuilder, newTestLogger(),
targets, parser.ModeAny, "https://aur.archlinux.org", dir, false) targets, parser.ModeAny, "https://aur.archlinux.org", dir, false)
assert.NoError(t, err) assert.NoError(t, err)
@@ -158,7 +163,7 @@ func TestPKGBUILDReposNotFound(t *testing.T) {
absPackagesDB: map[string]string{"yay": "core"}, absPackagesDB: map[string]string{"yay": "core"},
} }
cloned, err := PKGBUILDRepos(context.Background(), searcher, mockClient, cloned, err := PKGBUILDRepos(context.Background(), searcher, mockClient,
cmdBuilder, cmdBuilder, newTestLogger(),
targets, parser.ModeAny, "https://aur.archlinux.org", dir, false) targets, parser.ModeAny, "https://aur.archlinux.org", dir, false)
assert.NoError(t, err) assert.NoError(t, err)
@@ -192,7 +197,7 @@ func TestPKGBUILDReposRepoMode(t *testing.T) {
absPackagesDB: map[string]string{"yay": "core"}, absPackagesDB: map[string]string{"yay": "core"},
} }
cloned, err := PKGBUILDRepos(context.Background(), searcher, mockClient, cloned, err := PKGBUILDRepos(context.Background(), searcher, mockClient,
cmdBuilder, cmdBuilder, newTestLogger(),
targets, parser.ModeRepo, "https://aur.archlinux.org", dir, false) targets, parser.ModeRepo, "https://aur.archlinux.org", dir, false)
assert.NoError(t, err) assert.NoError(t, err)
@@ -230,7 +235,7 @@ func TestPKGBUILDFull(t *testing.T) {
absPackagesDB: map[string]string{"yay": "core"}, absPackagesDB: map[string]string{"yay": "core"},
} }
fetched, err := PKGBUILDs(searcher, mockClient, &http.Client{}, fetched, err := PKGBUILDs(searcher, mockClient, &http.Client{}, newTestLogger(),
targets, "https://aur.archlinux.org", parser.ModeAny) targets, "https://aur.archlinux.org", parser.ModeAny)
assert.NoError(t, err) assert.NoError(t, err)
@@ -268,7 +273,7 @@ func TestPKGBUILDReposMissingAUR(t *testing.T) {
absPackagesDB: map[string]string{"yay": "core"}, absPackagesDB: map[string]string{"yay": "core"},
} }
cloned, err := PKGBUILDRepos(context.Background(), searcher, mockClient, cloned, err := PKGBUILDRepos(context.Background(), searcher, mockClient,
cmdBuilder, cmdBuilder, newTestLogger(),
targets, parser.ModeAny, "https://aur.archlinux.org", dir, false) targets, parser.ModeAny, "https://aur.archlinux.org", dir, false)
assert.NoError(t, err) assert.NoError(t, err)

View File

@@ -9,6 +9,7 @@ import (
mapset "github.com/deckarep/golang-set/v2" mapset "github.com/deckarep/golang-set/v2"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/Jguer/yay/v12/pkg/runtime"
"github.com/Jguer/yay/v12/pkg/settings" "github.com/Jguer/yay/v12/pkg/settings"
"github.com/Jguer/yay/v12/pkg/text" "github.com/Jguer/yay/v12/pkg/text"
) )
@@ -23,7 +24,7 @@ func anyExistInCache(pkgbuildDirs map[string]string) bool {
return false return false
} }
func CleanFn(ctx context.Context, config *settings.Configuration, w io.Writer, func CleanFn(ctx context.Context, run *runtime.Runtime, w io.Writer,
pkgbuildDirsByBase map[string]string, installed mapset.Set[string], pkgbuildDirsByBase map[string]string, installed mapset.Set[string],
) error { ) error {
if len(pkgbuildDirsByBase) == 0 { if len(pkgbuildDirsByBase) == 0 {
@@ -49,25 +50,25 @@ func CleanFn(ctx context.Context, config *settings.Configuration, w io.Writer,
bases = append(bases, pkg) bases = append(bases, pkg)
} }
toClean, errClean := selectionMenu(w, pkgbuildDirsByBase, bases, installed, toClean, errClean := selectionMenu(run.Logger, pkgbuildDirsByBase, bases, installed,
gotext.Get("Packages to cleanBuild?"), gotext.Get("Packages to cleanBuild?"),
settings.NoConfirm, config.AnswerClean, skipFunc) settings.NoConfirm, run.Cfg.AnswerClean, skipFunc)
if errClean != nil { if errClean != nil {
return errClean return errClean
} }
for i, base := range toClean { for i, base := range toClean {
dir := pkgbuildDirsByBase[base] dir := pkgbuildDirsByBase[base]
text.OperationInfoln(gotext.Get("Deleting (%d/%d): %s", i+1, len(toClean), text.Cyan(dir))) run.Logger.OperationInfoln(gotext.Get("Deleting (%d/%d): %s", i+1, len(toClean), text.Cyan(dir)))
if err := config.Runtime.CmdBuilder.Show(config.Runtime.CmdBuilder.BuildGitCmd(ctx, dir, "reset", "--hard", "origin/HEAD")); err != nil { if err := run.CmdBuilder.Show(run.CmdBuilder.BuildGitCmd(ctx, dir, "reset", "--hard", "origin/HEAD")); err != nil {
text.Warnln(gotext.Get("Unable to clean:"), dir) run.Logger.Warnln(gotext.Get("Unable to clean:"), dir)
return err return err
} }
if err := config.Runtime.CmdBuilder.Show(config.Runtime.CmdBuilder.BuildGitCmd(ctx, dir, "clean", "-fdx")); err != nil { if err := run.CmdBuilder.Show(run.CmdBuilder.BuildGitCmd(ctx, dir, "clean", "-fdx")); err != nil {
text.Warnln(gotext.Get("Unable to clean:"), dir) run.Logger.Warnln(gotext.Get("Unable to clean:"), dir)
return err return err
} }

View File

@@ -5,13 +5,13 @@ import (
"context" "context"
"fmt" "fmt"
"io" "io"
"os"
"strings" "strings"
mapset "github.com/deckarep/golang-set/v2" mapset "github.com/deckarep/golang-set/v2"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/Jguer/yay/v12/pkg/multierror" "github.com/Jguer/yay/v12/pkg/multierror"
"github.com/Jguer/yay/v12/pkg/runtime"
"github.com/Jguer/yay/v12/pkg/settings" "github.com/Jguer/yay/v12/pkg/settings"
"github.com/Jguer/yay/v12/pkg/settings/exe" "github.com/Jguer/yay/v12/pkg/settings/exe"
"github.com/Jguer/yay/v12/pkg/text" "github.com/Jguer/yay/v12/pkg/text"
@@ -22,7 +22,7 @@ const (
gitDiffRefName = "AUR_SEEN" gitDiffRefName = "AUR_SEEN"
) )
func showPkgbuildDiffs(ctx context.Context, cmdBuilder exe.ICmdBuilder, func showPkgbuildDiffs(ctx context.Context, cmdBuilder exe.ICmdBuilder, logger *text.Logger,
pkgbuildDirs map[string]string, bases []string, pkgbuildDirs map[string]string, bases []string,
) error { ) error {
var errMulti multierror.MultiError var errMulti multierror.MultiError
@@ -46,7 +46,7 @@ func showPkgbuildDiffs(ctx context.Context, cmdBuilder exe.ICmdBuilder,
} }
if !hasDiff { if !hasDiff {
text.Warnln(gotext.Get("%s: No changes -- skipping", text.Cyan(pkg))) logger.Warnln(gotext.Get("%s: No changes -- skipping", text.Cyan(pkg)))
continue continue
} }
@@ -145,7 +145,7 @@ func updatePkgbuildSeenRef(ctx context.Context, cmdBuilder exe.ICmdBuilder, pkgb
return errMulti.Return() return errMulti.Return()
} }
func DiffFn(ctx context.Context, config *settings.Configuration, w io.Writer, func DiffFn(ctx context.Context, run *runtime.Runtime, w io.Writer,
pkgbuildDirsByBase map[string]string, installed mapset.Set[string], pkgbuildDirsByBase map[string]string, installed mapset.Set[string],
) error { ) error {
if len(pkgbuildDirsByBase) == 0 { if len(pkgbuildDirsByBase) == 0 {
@@ -157,23 +157,23 @@ func DiffFn(ctx context.Context, config *settings.Configuration, w io.Writer,
bases = append(bases, base) bases = append(bases, base)
} }
toDiff, errMenu := selectionMenu(w, pkgbuildDirsByBase, bases, installed, gotext.Get("Diffs to show?"), toDiff, errMenu := selectionMenu(run.Logger, pkgbuildDirsByBase, bases, installed, gotext.Get("Diffs to show?"),
settings.NoConfirm, config.AnswerDiff, nil) settings.NoConfirm, run.Cfg.AnswerDiff, nil)
if errMenu != nil || len(toDiff) == 0 { if errMenu != nil || len(toDiff) == 0 {
return errMenu return errMenu
} }
if errD := showPkgbuildDiffs(ctx, config.Runtime.CmdBuilder, pkgbuildDirsByBase, toDiff); errD != nil { if errD := showPkgbuildDiffs(ctx, run.CmdBuilder, run.Logger, pkgbuildDirsByBase, toDiff); errD != nil {
return errD return errD
} }
fmt.Println() run.Logger.Println()
if !text.ContinueTask(os.Stdin, gotext.Get("Proceed with install?"), true, false) { if !run.Logger.ContinueTask(gotext.Get("Proceed with install?"), true, false) {
return settings.ErrUserAbort{} return settings.ErrUserAbort{}
} }
if errUpd := updatePkgbuildSeenRef(ctx, config.Runtime.CmdBuilder, pkgbuildDirsByBase, toDiff); errUpd != nil { if errUpd := updatePkgbuildSeenRef(ctx, run.CmdBuilder, pkgbuildDirsByBase, toDiff); errUpd != nil {
return errUpd return errUpd
} }

View File

@@ -14,6 +14,7 @@ import (
mapset "github.com/deckarep/golang-set/v2" mapset "github.com/deckarep/golang-set/v2"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/Jguer/yay/v12/pkg/runtime"
"github.com/Jguer/yay/v12/pkg/settings" "github.com/Jguer/yay/v12/pkg/settings"
"github.com/Jguer/yay/v12/pkg/text" "github.com/Jguer/yay/v12/pkg/text"
) )
@@ -59,7 +60,7 @@ func editor(log *text.Logger, editorConfig, editorFlags string, noConfirm bool)
for { for {
log.Infoln(gotext.Get("Edit PKGBUILD with?")) log.Infoln(gotext.Get("Edit PKGBUILD with?"))
editorInput, err := text.GetInput(os.Stdin, "", noConfirm) editorInput, err := log.GetInput("", noConfirm)
if err != nil { if err != nil {
log.Errorln(err) log.Errorln(err)
continue continue
@@ -113,7 +114,7 @@ func editPkgbuilds(log *text.Logger, pkgbuildDirs map[string]string, bases []str
return nil return nil
} }
func EditFn(ctx context.Context, cfg *settings.Configuration, w io.Writer, func EditFn(ctx context.Context, run *runtime.Runtime, w io.Writer,
pkgbuildDirsByBase map[string]string, installed mapset.Set[string], pkgbuildDirsByBase map[string]string, installed mapset.Set[string],
) error { ) error {
if len(pkgbuildDirsByBase) == 0 { if len(pkgbuildDirsByBase) == 0 {
@@ -125,21 +126,21 @@ func EditFn(ctx context.Context, cfg *settings.Configuration, w io.Writer,
bases = append(bases, pkg) bases = append(bases, pkg)
} }
toEdit, errMenu := selectionMenu(w, pkgbuildDirsByBase, bases, installed, toEdit, errMenu := selectionMenu(run.Logger, pkgbuildDirsByBase, bases, installed,
gotext.Get("PKGBUILDs to edit?"), settings.NoConfirm, cfg.AnswerEdit, nil) gotext.Get("PKGBUILDs to edit?"), settings.NoConfirm, run.Cfg.AnswerEdit, nil)
if errMenu != nil || len(toEdit) == 0 { if errMenu != nil || len(toEdit) == 0 {
return errMenu return errMenu
} }
// TOFIX: remove or use srcinfo data // TOFIX: remove or use srcinfo data
if errEdit := editPkgbuilds(cfg.Runtime.Logger, pkgbuildDirsByBase, if errEdit := editPkgbuilds(run.Logger, pkgbuildDirsByBase,
toEdit, cfg.Editor, cfg.EditorFlags, nil, settings.NoConfirm); errEdit != nil { toEdit, run.Cfg.Editor, run.Cfg.EditorFlags, nil, settings.NoConfirm); errEdit != nil {
return errEdit return errEdit
} }
cfg.Runtime.Logger.Println() run.Logger.Println()
if !text.ContinueTask(os.Stdin, gotext.Get("Proceed with install?"), true, false) { if !run.Logger.ContinueTask(gotext.Get("Proceed with install?"), true, false) {
return settings.ErrUserAbort{} return settings.ErrUserAbort{}
} }

View File

@@ -2,7 +2,6 @@ package menus
import ( import (
"fmt" "fmt"
"io"
"os" "os"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
@@ -14,7 +13,9 @@ import (
mapset "github.com/deckarep/golang-set/v2" mapset "github.com/deckarep/golang-set/v2"
) )
func pkgbuildNumberMenu(w io.Writer, pkgbuildDirs map[string]string, bases []string, installed mapset.Set[string]) { func pkgbuildNumberMenu(logger *text.Logger, pkgbuildDirs map[string]string,
bases []string, installed mapset.Set[string],
) {
toPrint := "" toPrint := ""
for n, pkgBase := range bases { for n, pkgBase := range bases {
@@ -34,20 +35,20 @@ func pkgbuildNumberMenu(w io.Writer, pkgbuildDirs map[string]string, bases []str
toPrint += "\n" toPrint += "\n"
} }
fmt.Fprint(w, toPrint) logger.Print(toPrint)
} }
func selectionMenu(w io.Writer, pkgbuildDirs map[string]string, bases []string, installed mapset.Set[string], func selectionMenu(logger *text.Logger, pkgbuildDirs map[string]string, bases []string, installed mapset.Set[string],
message string, noConfirm bool, defaultAnswer string, skipFunc func(string) bool, message string, noConfirm bool, defaultAnswer string, skipFunc func(string) bool,
) ([]string, error) { ) ([]string, error) {
selected := make([]string, 0) selected := make([]string, 0)
pkgbuildNumberMenu(w, pkgbuildDirs, bases, installed) pkgbuildNumberMenu(logger, pkgbuildDirs, bases, installed)
text.Infoln(message) logger.Infoln(message)
text.Infoln(gotext.Get("%s [A]ll [Ab]ort [I]nstalled [No]tInstalled or (1 2 3, 1-3, ^4)", text.Cyan(gotext.Get("[N]one")))) logger.Infoln(gotext.Get("%s [A]ll [Ab]ort [I]nstalled [No]tInstalled or (1 2 3, 1-3, ^4)", text.Cyan(gotext.Get("[N]one"))))
selectInput, err := text.GetInput(os.Stdin, defaultAnswer, noConfirm) selectInput, err := logger.GetInput(defaultAnswer, noConfirm)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -4,11 +4,9 @@ import (
"bytes" "bytes"
"context" "context"
"encoding/xml" "encoding/xml"
"fmt"
"html" "html"
"io" "io"
"net/http" "net/http"
"os"
"strings" "strings"
"time" "time"
@@ -23,13 +21,13 @@ type item struct {
Creator string `xml:"dc:creator"` Creator string `xml:"dc:creator"`
} }
func (item *item) print(buildTime time.Time, all, quiet bool) { func (item *item) printNews(logger *text.Logger, buildTime time.Time, all, quiet bool) {
var fd string var fd string
date, err := time.Parse(time.RFC1123Z, item.PubDate) date, err := time.Parse(time.RFC1123Z, item.PubDate)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, err) logger.Errorln(err)
} else { } else {
fd = text.FormatTime(int(date.Unix())) fd = text.FormatTime(int(date.Unix()))
if !all && !buildTime.IsZero() { if !all && !buildTime.IsZero() {
@@ -39,11 +37,11 @@ func (item *item) print(buildTime time.Time, all, quiet bool) {
} }
} }
fmt.Println(text.Bold(text.Magenta(fd)), text.Bold(strings.TrimSpace(item.Title))) logger.Println(text.Bold(text.Magenta(fd)), text.Bold(strings.TrimSpace(item.Title)))
if !quiet { if !quiet {
desc := strings.TrimSpace(parseNews(item.Description)) desc := strings.TrimSpace(parseNews(item.Description))
fmt.Println(desc) logger.Println(desc)
} }
} }
@@ -60,7 +58,9 @@ type rss struct {
Channel channel `xml:"channel"` Channel channel `xml:"channel"`
} }
func PrintNewsFeed(ctx context.Context, client *http.Client, cutOffDate time.Time, bottomUp, all, quiet bool) error { func PrintNewsFeed(ctx context.Context, client *http.Client, logger *text.Logger,
cutOffDate time.Time, bottomUp, all, quiet bool,
) error {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://archlinux.org/feeds/news", http.NoBody) req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://archlinux.org/feeds/news", http.NoBody)
if err != nil { if err != nil {
return err return err
@@ -87,11 +87,11 @@ func PrintNewsFeed(ctx context.Context, client *http.Client, cutOffDate time.Tim
if bottomUp { if bottomUp {
for i := len(rssGot.Channel.Items) - 1; i >= 0; i-- { for i := len(rssGot.Channel.Items) - 1; i >= 0; i-- {
rssGot.Channel.Items[i].print(cutOffDate, all, quiet) rssGot.Channel.Items[i].printNews(logger, cutOffDate, all, quiet)
} }
} else { } else {
for i := 0; i < len(rssGot.Channel.Items); i++ { for i := 0; i < len(rssGot.Channel.Items); i++ {
rssGot.Channel.Items[i].print(cutOffDate, all, quiet) rssGot.Channel.Items[i].printNews(logger, cutOffDate, all, quiet)
} }
} }

View File

@@ -8,12 +8,15 @@ import (
"io" "io"
"net/http" "net/http"
"os" "os"
"strings"
"testing" "testing"
"time" "time"
"github.com/bradleyjkemp/cupaloy" "github.com/bradleyjkemp/cupaloy"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"gopkg.in/h2non/gock.v1" "gopkg.in/h2non/gock.v1"
"github.com/Jguer/yay/v12/pkg/text"
) )
const lastNews = ` const lastNews = `
@@ -135,17 +138,16 @@ func TestPrintNewsFeed(t *testing.T) {
defer gock.Off() defer gock.Off()
rescueStdout := os.Stdout
r, w, _ := os.Pipe() r, w, _ := os.Pipe()
os.Stdout = w logger := text.NewLogger(w, w, strings.NewReader(""), false, "logger")
err := PrintNewsFeed(context.Background(), &http.Client{}, tt.args.cutOffDate, tt.args.bottomUp, tt.args.all, tt.args.quiet) err := PrintNewsFeed(context.Background(), &http.Client{}, logger,
tt.args.cutOffDate, tt.args.bottomUp, tt.args.all, tt.args.quiet)
assert.NoError(t, err) assert.NoError(t, err)
w.Close() w.Close()
out, _ := io.ReadAll(r) out, _ := io.ReadAll(r)
cupaloy.SnapshotT(t, out) cupaloy.SnapshotT(t, out)
os.Stdout = rescueStdout
}) })
} }
} }
@@ -164,15 +166,14 @@ func TestPrintNewsFeedSameDay(t *testing.T) {
defer gock.Off() defer gock.Off()
rescueStdout := os.Stdout
r, w, _ := os.Pipe() r, w, _ := os.Pipe()
os.Stdout = w logger := text.NewLogger(w, w, strings.NewReader(""), false, "logger")
err := PrintNewsFeed(context.Background(), &http.Client{}, lastNewsTime, true, false, false) err := PrintNewsFeed(context.Background(), &http.Client{}, logger,
lastNewsTime, true, false, false)
assert.NoError(t, err) assert.NoError(t, err)
w.Close() w.Close()
out, _ := io.ReadAll(r) out, _ := io.ReadAll(r)
cupaloy.SnapshotT(t, out) cupaloy.SnapshotT(t, out)
os.Stdout = rescueStdout
} }

View File

@@ -22,9 +22,6 @@ type AURWarnings struct {
} }
func NewWarnings(logger *text.Logger) *AURWarnings { func NewWarnings(logger *text.Logger) *AURWarnings {
if logger == nil {
logger = text.GlobalLogger
}
return &AURWarnings{log: logger} return &AURWarnings{log: logger}
} }

View File

@@ -7,19 +7,19 @@ import (
"github.com/Jguer/yay/v12/pkg/text" "github.com/Jguer/yay/v12/pkg/text"
) )
func RemoveInvalidTargets(targets []string, mode parser.TargetMode) []string { func RemoveInvalidTargets(logger *text.Logger, targets []string, mode parser.TargetMode) []string {
filteredTargets := make([]string, 0) filteredTargets := make([]string, 0)
for _, target := range targets { for _, target := range targets {
dbName, _ := text.SplitDBFromName(target) dbName, _ := text.SplitDBFromName(target)
if dbName == "aur" && !mode.AtLeastAUR() { if dbName == "aur" && !mode.AtLeastAUR() {
text.Warnln(gotext.Get("%s: can't use target with option --repo -- skipping", text.Cyan(target))) logger.Warnln(gotext.Get("%s: can't use target with option --repo -- skipping", text.Cyan(target)))
continue continue
} }
if dbName != "aur" && dbName != "" && !mode.AtLeastRepo() { if dbName != "aur" && dbName != "" && !mode.AtLeastRepo() {
text.Warnln(gotext.Get("%s: can't use target with option --aur -- skipping", text.Cyan(target))) logger.Warnln(gotext.Get("%s: can't use target with option --aur -- skipping", text.Cyan(target)))
continue continue
} }

View File

@@ -130,7 +130,7 @@ func (a *abstractResults) Less(i, j int) bool {
func (s *SourceQueryBuilder) Execute(ctx context.Context, dbExecutor db.Executor, pkgS []string) { func (s *SourceQueryBuilder) Execute(ctx context.Context, dbExecutor db.Executor, pkgS []string) {
var aurErr error var aurErr error
pkgS = RemoveInvalidTargets(pkgS, s.targetMode) pkgS = RemoveInvalidTargets(s.logger, pkgS, s.targetMode)
metric := &metrics.Hamming{ metric := &metrics.Hamming{
CaseSensitive: false, CaseSensitive: false,

View File

@@ -1,4 +1,4 @@
package settings package runtime
import ( import (
"fmt" "fmt"
@@ -10,7 +10,7 @@ import (
"golang.org/x/term" "golang.org/x/term"
) )
func RetrievePacmanConfig(cmdArgs *parser.Arguments, pacmanConfigPath string) (*pacmanconf.Config, bool, error) { func retrievePacmanConfig(cmdArgs *parser.Arguments, pacmanConfigPath string) (*pacmanconf.Config, bool, error) {
root := "/" root := "/"
if value, _, exists := cmdArgs.GetArg("root", "r"); exists { if value, _, exists := cmdArgs.GetArg("root", "r"); exists {
root = value root = value

View File

@@ -1,7 +1,7 @@
//go:build !integration //go:build !integration
// +build !integration // +build !integration
package settings package runtime
import ( import (
"testing" "testing"
@@ -46,7 +46,7 @@ func TestPacmanConf(t *testing.T) {
}, },
} }
pacmanConf, color, err := RetrievePacmanConfig(parser.MakeArguments(), "../../testdata/pacman.conf") pacmanConf, color, err := retrievePacmanConfig(parser.MakeArguments(), "../../testdata/pacman.conf")
assert.Nil(t, err) assert.Nil(t, err)
assert.NotNil(t, pacmanConf) assert.NotNil(t, pacmanConf)
assert.Equal(t, color, false) assert.Equal(t, color, false)

View File

@@ -1,4 +1,4 @@
package settings package runtime
import ( import (
"context" "context"
@@ -9,8 +9,8 @@ import (
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/Jguer/yay/v12/pkg/db"
"github.com/Jguer/yay/v12/pkg/query" "github.com/Jguer/yay/v12/pkg/query"
"github.com/Jguer/yay/v12/pkg/settings"
"github.com/Jguer/yay/v12/pkg/settings/exe" "github.com/Jguer/yay/v12/pkg/settings/exe"
"github.com/Jguer/yay/v12/pkg/settings/parser" "github.com/Jguer/yay/v12/pkg/settings/parser"
"github.com/Jguer/yay/v12/pkg/text" "github.com/Jguer/yay/v12/pkg/text"
@@ -24,6 +24,7 @@ import (
) )
type Runtime struct { type Runtime struct {
Cfg *settings.Configuration
QueryBuilder query.Builder QueryBuilder query.Builder
PacmanConf *pacmanconf.Config PacmanConf *pacmanconf.Config
VCSStore vcs.Store VCSStore vcs.Store
@@ -31,13 +32,12 @@ type Runtime struct {
HTTPClient *http.Client HTTPClient *http.Client
VoteClient *vote.Client VoteClient *vote.Client
AURClient aur.QueryClient AURClient aur.QueryClient
DBExecutor db.Executor
Logger *text.Logger Logger *text.Logger
} }
func BuildRuntime(cfg *Configuration, cmdArgs *parser.Arguments, version string) (*Runtime, error) { func NewRuntime(cfg *settings.Configuration, cmdArgs *parser.Arguments, version string) (*Runtime, error) {
logger := text.NewLogger(os.Stdout, os.Stderr, os.Stdin, cfg.Debug, "runtime") logger := text.NewLogger(os.Stdout, os.Stderr, os.Stdin, cfg.Debug, "runtime")
cmdBuilder := cfg.CmdBuilder(nil) runner := exe.NewOSRunner(logger.Child("runner"))
httpClient := &http.Client{ httpClient := &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error { CheckRedirect: func(req *http.Request, via []*http.Request) error {
@@ -86,6 +86,16 @@ func BuildRuntime(cfg *Configuration, cmdArgs *parser.Arguments, version string)
aurCache = aurClient aurCache = aurClient
} }
pacmanConf, useColor, err := retrievePacmanConfig(cmdArgs, cfg.PacmanConf)
if err != nil {
return nil, err
}
// FIXME: get rid of global
text.UseColor = useColor
cmdBuilder := exe.NewCmdBuilder(cfg, runner, logger.Child("cmdbuilder"), pacmanConf.DBPath)
vcsStore := vcs.NewInfoStore( vcsStore := vcs.NewInfoStore(
cfg.VCSFilePath, cmdBuilder, cfg.VCSFilePath, cmdBuilder,
logger.Child("vcs")) logger.Child("vcs"))
@@ -94,17 +104,23 @@ func BuildRuntime(cfg *Configuration, cmdArgs *parser.Arguments, version string)
return nil, err return nil, err
} }
runtime := &Runtime{ queryBuilder := query.NewSourceQueryBuilder(
QueryBuilder: nil, aurClient,
PacmanConf: nil, logger.Child("mixed.querybuilder"), cfg.SortBy,
cfg.Mode, cfg.SearchBy,
cfg.BottomUp, cfg.SingleLineResults, cfg.SeparateSources)
run := &Runtime{
Cfg: cfg,
QueryBuilder: queryBuilder,
PacmanConf: pacmanConf,
VCSStore: vcsStore, VCSStore: vcsStore,
CmdBuilder: cmdBuilder, CmdBuilder: cmdBuilder,
HTTPClient: &http.Client{}, HTTPClient: &http.Client{},
VoteClient: voteClient, VoteClient: voteClient,
AURClient: aurCache, AURClient: aurCache,
DBExecutor: nil, Logger: logger,
Logger: text.NewLogger(os.Stdout, os.Stderr, os.Stdin, cfg.Debug, "runtime"),
} }
return runtime, nil return run, nil
} }

View File

@@ -1,16 +1,17 @@
//go:build !integration //go:build !integration
// +build !integration // +build !integration
package settings_test package runtime_test
import ( import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/Jguer/yay/v12/pkg/runtime"
"github.com/Jguer/yay/v12/pkg/settings" "github.com/Jguer/yay/v12/pkg/settings"
"github.com/Jguer/yay/v12/pkg/settings/parser" "github.com/Jguer/yay/v12/pkg/settings/parser"
"github.com/Jguer/yay/v12/pkg/text"
) )
func TestBuildRuntime(t *testing.T) { func TestBuildRuntime(t *testing.T) {
@@ -23,24 +24,23 @@ func TestBuildRuntime(t *testing.T) {
AURRPCURL: "https://aur.archlinux.org/rpc", AURRPCURL: "https://aur.archlinux.org/rpc",
BuildDir: "/tmp", BuildDir: "/tmp",
VCSFilePath: "", VCSFilePath: "",
Runtime: &settings.Runtime{Logger: text.NewLogger(nil, nil, nil, false, "")}, PacmanConf: "../../testdata/pacman.conf",
} }
cmdArgs := parser.MakeArguments() cmdArgs := parser.MakeArguments()
version := "1.0.0" version := "1.0.0"
// Call the function being tested // Call the function being tested
runtime, err := settings.BuildRuntime(cfg, cmdArgs, version) run, err := runtime.NewRuntime(cfg, cmdArgs, version)
require.NoError(t, err)
// Assert the function's output // Assert the function's output
assert.NotNil(t, runtime) assert.NotNil(t, run)
assert.Nil(t, err) assert.NotNil(t, run.QueryBuilder)
assert.Nil(t, runtime.QueryBuilder) assert.NotNil(t, run.PacmanConf)
assert.Nil(t, runtime.PacmanConf) assert.NotNil(t, run.VCSStore)
assert.NotNil(t, runtime.VCSStore) assert.NotNil(t, run.CmdBuilder)
assert.NotNil(t, runtime.CmdBuilder) assert.NotNil(t, run.HTTPClient)
assert.NotNil(t, runtime.HTTPClient) assert.NotNil(t, run.VoteClient)
assert.NotNil(t, runtime.VoteClient) assert.NotNil(t, run.AURClient)
assert.NotNil(t, runtime.AURClient) assert.NotNil(t, run.Logger)
assert.Nil(t, runtime.DBExecutor)
assert.NotNil(t, runtime.Logger)
} }

View File

@@ -5,7 +5,6 @@ import (
"strings" "strings"
"github.com/Jguer/yay/v12/pkg/settings/parser" "github.com/Jguer/yay/v12/pkg/settings/parser"
"github.com/Jguer/yay/v12/pkg/text"
) )
func (c *Configuration) ParseCommandLine(a *parser.Arguments) error { func (c *Configuration) ParseCommandLine(a *parser.Arguments) error {
@@ -15,9 +14,6 @@ func (c *Configuration) ParseCommandLine(a *parser.Arguments) error {
c.extractYayOptions(a) c.extractYayOptions(a)
// Reload CmdBuilder
c.Runtime.CmdBuilder = c.CmdBuilder(nil)
return nil return nil
} }
@@ -59,7 +55,6 @@ func (c *Configuration) handleOption(option, value string) bool {
c.CleanAfter = false c.CleanAfter = false
case "debug": case "debug":
c.Debug = true c.Debug = true
text.GlobalLogger.Debug = true
return false return false
case "devel": case "devel":
c.Devel = true c.Devel = true

View File

@@ -9,7 +9,6 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/Jguer/yay/v12/pkg/settings/exe"
"github.com/Jguer/yay/v12/pkg/settings/parser" "github.com/Jguer/yay/v12/pkg/settings/parser"
"github.com/Jguer/yay/v12/pkg/text" "github.com/Jguer/yay/v12/pkg/text"
@@ -24,53 +23,52 @@ var NoConfirm = false
// Configuration stores yay's config. // Configuration stores yay's config.
type Configuration struct { type Configuration struct {
Runtime *Runtime `json:"-"` AURURL string `json:"aururl"`
AURURL string `json:"aururl"` AURRPCURL string `json:"aurrpcurl"`
AURRPCURL string `json:"aurrpcurl"` BuildDir string `json:"buildDir"`
BuildDir string `json:"buildDir"` Editor string `json:"editor"`
Editor string `json:"editor"` EditorFlags string `json:"editorflags"`
EditorFlags string `json:"editorflags"` MakepkgBin string `json:"makepkgbin"`
MakepkgBin string `json:"makepkgbin"` MakepkgConf string `json:"makepkgconf"`
MakepkgConf string `json:"makepkgconf"` PacmanBin string `json:"pacmanbin"`
PacmanBin string `json:"pacmanbin"` PacmanConf string `json:"pacmanconf"`
PacmanConf string `json:"pacmanconf"` ReDownload string `json:"redownload"`
ReDownload string `json:"redownload"` AnswerClean string `json:"answerclean"`
AnswerClean string `json:"answerclean"` AnswerDiff string `json:"answerdiff"`
AnswerDiff string `json:"answerdiff"` AnswerEdit string `json:"answeredit"`
AnswerEdit string `json:"answeredit"` AnswerUpgrade string `json:"answerupgrade"`
AnswerUpgrade string `json:"answerupgrade"` GitBin string `json:"gitbin"`
GitBin string `json:"gitbin"` GpgBin string `json:"gpgbin"`
GpgBin string `json:"gpgbin"` GpgFlags string `json:"gpgflags"`
GpgFlags string `json:"gpgflags"` MFlags string `json:"mflags"`
MFlags string `json:"mflags"` SortBy string `json:"sortby"`
SortBy string `json:"sortby"` SearchBy string `json:"searchby"`
SearchBy string `json:"searchby"` GitFlags string `json:"gitflags"`
GitFlags string `json:"gitflags"` RemoveMake string `json:"removemake"`
RemoveMake string `json:"removemake"` SudoBin string `json:"sudobin"`
SudoBin string `json:"sudobin"` SudoFlags string `json:"sudoflags"`
SudoFlags string `json:"sudoflags"` Version string `json:"version"`
Version string `json:"version"` RequestSplitN int `json:"requestsplitn"`
RequestSplitN int `json:"requestsplitn"` CompletionInterval int `json:"completionrefreshtime"`
CompletionInterval int `json:"completionrefreshtime"` MaxConcurrentDownloads int `json:"maxconcurrentdownloads"`
MaxConcurrentDownloads int `json:"maxconcurrentdownloads"` BottomUp bool `json:"bottomup"`
BottomUp bool `json:"bottomup"` SudoLoop bool `json:"sudoloop"`
SudoLoop bool `json:"sudoloop"` TimeUpdate bool `json:"timeupdate"`
TimeUpdate bool `json:"timeupdate"` Devel bool `json:"devel"`
Devel bool `json:"devel"` CleanAfter bool `json:"cleanAfter"`
CleanAfter bool `json:"cleanAfter"` Provides bool `json:"provides"`
Provides bool `json:"provides"` PGPFetch bool `json:"pgpfetch"`
PGPFetch bool `json:"pgpfetch"` CleanMenu bool `json:"cleanmenu"`
CleanMenu bool `json:"cleanmenu"` DiffMenu bool `json:"diffmenu"`
DiffMenu bool `json:"diffmenu"` EditMenu bool `json:"editmenu"`
EditMenu bool `json:"editmenu"` CombinedUpgrade bool `json:"combinedupgrade"`
CombinedUpgrade bool `json:"combinedupgrade"` UseAsk bool `json:"useask"`
UseAsk bool `json:"useask"` BatchInstall bool `json:"batchinstall"`
BatchInstall bool `json:"batchinstall"` SingleLineResults bool `json:"singlelineresults"`
SingleLineResults bool `json:"singlelineresults"` SeparateSources bool `json:"separatesources"`
SeparateSources bool `json:"separatesources"` Debug bool `json:"debug"`
Debug bool `json:"debug"` UseRPC bool `json:"rpc"`
UseRPC bool `json:"rpc"` DoubleConfirm bool `json:"doubleconfirm"` // confirm install before and after build
DoubleConfirm bool `json:"doubleconfirm"` // confirm install before and after build
CompletionPath string `json:"-"` CompletionPath string `json:"-"`
VCSFilePath string `json:"-"` VCSFilePath string `json:"-"`
@@ -237,19 +235,16 @@ func DefaultConfig(version string) *Configuration {
Debug: false, Debug: false,
UseRPC: true, UseRPC: true,
DoubleConfirm: true, DoubleConfirm: true,
Runtime: &Runtime{ Mode: parser.ModeAny,
Logger: text.GlobalLogger,
},
Mode: parser.ModeAny,
} }
} }
func NewConfig(configPath, version string) (*Configuration, error) { func NewConfig(logger *text.Logger, configPath, version string) (*Configuration, error) {
newConfig := DefaultConfig(version) newConfig := DefaultConfig(version)
cacheHome, errCache := getCacheHome() cacheHome, errCache := getCacheHome()
if errCache != nil { if errCache != nil && logger != nil {
text.Errorln(errCache) logger.Errorln(errCache)
} }
newConfig.BuildDir = cacheHome newConfig.BuildDir = cacheHome
@@ -295,27 +290,3 @@ func (c *Configuration) load(configPath string) {
} }
} }
} }
func (c *Configuration) CmdBuilder(runner exe.Runner) exe.ICmdBuilder {
if runner == nil {
runner = &exe.OSRunner{Log: c.Runtime.Logger.Child("runner")}
}
return &exe.CmdBuilder{
GitBin: c.GitBin,
GitFlags: strings.Fields(c.GitFlags),
GPGBin: c.GpgBin,
GPGFlags: strings.Fields(c.GpgFlags),
MakepkgFlags: strings.Fields(c.MFlags),
MakepkgConfPath: c.MakepkgConf,
MakepkgBin: c.MakepkgBin,
SudoBin: c.SudoBin,
SudoFlags: strings.Fields(c.SudoFlags),
SudoLoopEnabled: c.SudoLoop,
PacmanBin: c.PacmanBin,
PacmanConfigPath: c.PacmanConf,
PacmanDBPath: "",
Runner: runner,
Log: c.Runtime.Logger.Child("cmd_builder"),
}
}

View File

@@ -36,7 +36,7 @@ func TestNewConfig(t *testing.T) {
_, err = f.WriteString(string(configJSON)) _, err = f.WriteString(string(configJSON))
assert.NoError(t, err) assert.NoError(t, err)
newConfig, err := NewConfig(GetConfigPath(), "v1.0.0") newConfig, err := NewConfig(nil, GetConfigPath(), "v1.0.0")
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, filepath.Join(cacheDir, "test-build-dir"), newConfig.BuildDir) assert.Equal(t, filepath.Join(cacheDir, "test-build-dir"), newConfig.BuildDir)
@@ -69,7 +69,7 @@ func TestNewConfigAURDEST(t *testing.T) {
_, err = f.WriteString(string(configJSON)) _, err = f.WriteString(string(configJSON))
assert.NoError(t, err) assert.NoError(t, err)
newConfig, err := NewConfig(GetConfigPath(), "v1.0.0") newConfig, err := NewConfig(nil, GetConfigPath(), "v1.0.0")
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, filepath.Join(cacheDir, "test-build-dir"), newConfig.BuildDir) assert.Equal(t, filepath.Join(cacheDir, "test-build-dir"), newConfig.BuildDir)
@@ -102,7 +102,7 @@ func TestNewConfigAURDESTTildeExpansion(t *testing.T) {
_, err = f.WriteString(string(configJSON)) _, err = f.WriteString(string(configJSON))
assert.NoError(t, err) assert.NoError(t, err)
newConfig, err := NewConfig(GetConfigPath(), "v1.0.0") newConfig, err := NewConfig(nil, GetConfigPath(), "v1.0.0")
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, filepath.Join(homeDir, "test-build-dir"), newConfig.BuildDir) assert.Equal(t, filepath.Join(homeDir, "test-build-dir"), newConfig.BuildDir)

View File

@@ -15,6 +15,7 @@ import (
mapset "github.com/deckarep/golang-set/v2" mapset "github.com/deckarep/golang-set/v2"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/Jguer/yay/v12/pkg/settings"
"github.com/Jguer/yay/v12/pkg/settings/parser" "github.com/Jguer/yay/v12/pkg/settings/parser"
"github.com/Jguer/yay/v12/pkg/text" "github.com/Jguer/yay/v12/pkg/text"
) )
@@ -38,7 +39,6 @@ type ICmdBuilder interface {
BuildMakepkgCmd(ctx context.Context, dir string, extraArgs ...string) *exec.Cmd BuildMakepkgCmd(ctx context.Context, dir string, extraArgs ...string) *exec.Cmd
BuildPacmanCmd(ctx context.Context, args *parser.Arguments, mode parser.TargetMode, noConfirm bool) *exec.Cmd BuildPacmanCmd(ctx context.Context, args *parser.Arguments, mode parser.TargetMode, noConfirm bool) *exec.Cmd
AddMakepkgFlag(string) AddMakepkgFlag(string)
SetPacmanDBPath(string)
SudoLoop() SudoLoop()
} }
@@ -60,6 +60,26 @@ type CmdBuilder struct {
Log *text.Logger Log *text.Logger
} }
func NewCmdBuilder(cfg *settings.Configuration, runner Runner, logger *text.Logger, dbPath string) *CmdBuilder {
return &CmdBuilder{
GitBin: cfg.GitBin,
GitFlags: strings.Fields(cfg.GitFlags),
GPGBin: cfg.GpgBin,
GPGFlags: strings.Fields(cfg.GpgFlags),
MakepkgFlags: strings.Fields(cfg.MFlags),
MakepkgConfPath: cfg.MakepkgConf,
MakepkgBin: cfg.MakepkgBin,
SudoBin: cfg.SudoBin,
SudoFlags: strings.Fields(cfg.SudoFlags),
SudoLoopEnabled: cfg.SudoLoop,
PacmanBin: cfg.PacmanBin,
PacmanConfigPath: cfg.PacmanConf,
PacmanDBPath: dbPath,
Runner: runner,
Log: logger,
}
}
func (c *CmdBuilder) BuildGPGCmd(ctx context.Context, extraArgs ...string) *exec.Cmd { func (c *CmdBuilder) BuildGPGCmd(ctx context.Context, extraArgs ...string) *exec.Cmd {
args := make([]string, len(c.GPGFlags), len(c.GPGFlags)+len(extraArgs)) args := make([]string, len(c.GPGFlags), len(c.GPGFlags)+len(extraArgs))
copy(args, c.GPGFlags) copy(args, c.GPGFlags)
@@ -135,10 +155,6 @@ func (c *CmdBuilder) BuildMakepkgCmd(ctx context.Context, dir string, extraArgs
return cmd return cmd
} }
func (c *CmdBuilder) SetPacmanDBPath(dbPath string) {
c.PacmanDBPath = dbPath
}
// deElevateCommand, `systemd-run` code based on pikaur. // deElevateCommand, `systemd-run` code based on pikaur.
func (c *CmdBuilder) deElevateCommand(ctx context.Context, cmd *exec.Cmd) *exec.Cmd { func (c *CmdBuilder) deElevateCommand(ctx context.Context, cmd *exec.Cmd) *exec.Cmd {
if os.Geteuid() != 0 { if os.Geteuid() != 0 {
@@ -242,7 +258,7 @@ func (c *CmdBuilder) waitLock(dbPath string) {
time.Sleep(3 * time.Second) time.Sleep(3 * time.Second)
if _, err := os.Stat(lockDBPath); err != nil { if _, err := os.Stat(lockDBPath); err != nil {
fmt.Println() c.Log.Println()
return return
} }

View File

@@ -19,6 +19,10 @@ type OSRunner struct {
Log *text.Logger Log *text.Logger
} }
func NewOSRunner(log *text.Logger) *OSRunner {
return &OSRunner{log}
}
func (r *OSRunner) Show(cmd *exec.Cmd) error { func (r *OSRunner) Show(cmd *exec.Cmd) error {
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
cmd.SysProcAttr = &syscall.SysProcAttr{ cmd.SysProcAttr = &syscall.SysProcAttr{

View File

@@ -36,6 +36,10 @@ type MockRunner struct {
CaptureFn func(cmd *exec.Cmd) (stdout string, stderr string, err error) CaptureFn func(cmd *exec.Cmd) (stdout string, stderr string, err error)
} }
func (m *MockBuilder) BuildGPGCmd(ctx context.Context, extraArgs ...string) *exec.Cmd {
return exec.CommandContext(ctx, "gpg", extraArgs...)
}
func (m *MockBuilder) BuildMakepkgCmd(ctx context.Context, dir string, extraArgs ...string) *exec.Cmd { func (m *MockBuilder) BuildMakepkgCmd(ctx context.Context, dir string, extraArgs ...string) *exec.Cmd {
var res *exec.Cmd var res *exec.Cmd
if m.BuildMakepkgCmdFn != nil { if m.BuildMakepkgCmdFn != nil {

View File

@@ -45,7 +45,7 @@ func DefaultMigrations() []configMigration {
} }
} }
func (c *Configuration) RunMigrations(migrations []configMigration, func (c *Configuration) RunMigrations(logger *text.Logger, migrations []configMigration,
configPath, newVersion string, configPath, newVersion string,
) error { ) error {
saveConfig := false saveConfig := false
@@ -53,7 +53,7 @@ func (c *Configuration) RunMigrations(migrations []configMigration,
for _, migration := range migrations { for _, migration := range migrations {
if db.VerCmp(migration.TargetVersion(), c.Version) > 0 { if db.VerCmp(migration.TargetVersion(), c.Version) > 0 {
if migration.Do(c) { if migration.Do(c) {
text.Infoln("Config migration executed (", logger.Infoln("Config migration executed (",
migration.TargetVersion(), "):", migration) migration.TargetVersion(), "):", migration)
saveConfig = true saveConfig = true

View File

@@ -16,6 +16,10 @@ import (
"github.com/Jguer/yay/v12/pkg/text" "github.com/Jguer/yay/v12/pkg/text"
) )
func newTestLogger() *text.Logger {
return text.NewLogger(io.Discard, io.Discard, strings.NewReader(""), true, "test")
}
func TestMigrationNothingToDo(t *testing.T) { func TestMigrationNothingToDo(t *testing.T) {
t.Parallel() t.Parallel()
// Create temporary file for config // Create temporary file for config
@@ -28,13 +32,10 @@ func TestMigrationNothingToDo(t *testing.T) {
config := Configuration{ config := Configuration{
Version: "99.0.0", Version: "99.0.0",
// Create runtime with runtimeVersion // Create runtime with runtimeVersion
Runtime: &Runtime{
Logger: text.NewLogger(io.Discard, io.Discard, strings.NewReader(""), false, "test"),
},
} }
// Run Migration // Run Migration
err = config.RunMigrations(DefaultMigrations(), testFilePath, "20.0.0") err = config.RunMigrations(newTestLogger(), DefaultMigrations(), testFilePath, "20.0.0")
require.NoError(t, err) require.NoError(t, err)
// Check file contents if wantSave otherwise check file empty // Check file contents if wantSave otherwise check file empty
@@ -53,9 +54,6 @@ func TestProvidesMigrationDo(t *testing.T) {
migration := &configProviderMigration{} migration := &configProviderMigration{}
config := Configuration{ config := Configuration{
Provides: true, Provides: true,
Runtime: &Runtime{
Logger: text.NewLogger(io.Discard, io.Discard, strings.NewReader(""), false, "test"),
},
} }
assert.True(t, migration.Do(&config)) assert.True(t, migration.Do(&config))
@@ -135,13 +133,10 @@ func TestProvidesMigration(t *testing.T) {
Version: tc.testConfig.Version, Version: tc.testConfig.Version,
Provides: tc.testConfig.Provides, Provides: tc.testConfig.Provides,
// Create runtime with runtimeVersion // Create runtime with runtimeVersion
Runtime: &Runtime{
Logger: text.NewLogger(io.Discard, io.Discard, strings.NewReader(""), false, "test"),
},
} }
// Run Migration // Run Migration
err = tcConfig.RunMigrations( err = tcConfig.RunMigrations(newTestLogger(),
[]configMigration{&configProviderMigration{}}, []configMigration{&configProviderMigration{}},
testFilePath, tc.newVersion) testFilePath, tc.newVersion)

62
pkg/sync/build/errors.go Normal file
View File

@@ -0,0 +1,62 @@
package build
import (
"errors"
"github.com/leonelquinteros/gotext"
)
var ErrInstallRepoPkgs = errors.New(gotext.Get("error installing repo packages"))
type FailedIgnoredPkgError struct {
pkgErrors map[string]error
}
func (e *FailedIgnoredPkgError) Error() string {
msg := gotext.Get("Failed to install the following packages. Manual intervention is required:")
for pkg, err := range e.pkgErrors {
msg += "\n" + pkg + " - " + err.Error()
}
return msg
}
type PkgDestNotInListError struct {
name string
}
func (e *PkgDestNotInListError) Error() string {
return gotext.Get("could not find PKGDEST for: %s", e.name)
}
type FindPkgDestError struct {
name, pkgDest string
}
func (e *FindPkgDestError) Error() string {
return gotext.Get(
"the PKGDEST for %s is listed by makepkg but does not exist: %s",
e.name, e.pkgDest)
}
type SetPkgReasonError struct {
exp bool // explicit
}
func (e *SetPkgReasonError) Error() string {
reason := gotext.Get("explicit")
if !e.exp {
reason = gotext.Get("dependency")
}
return gotext.Get("error updating package install reason to %s", reason)
}
type NoPkgDestsFoundError struct {
dir string
}
func (e *NoPkgDestsFoundError) Error() string {
return gotext.Get("could not find any package archives listed in %s", e.dir)
}

View File

@@ -1,4 +1,4 @@
package main package build
import ( import (
"context" "context"
@@ -54,12 +54,12 @@ func NewInstaller(dbExecutor db.Executor,
} }
} }
func (installer *Installer) CompileFailedAndIgnored() error { func (installer *Installer) CompileFailedAndIgnored() (map[string]error, error) {
if len(installer.failedAndIgnored) == 0 { if len(installer.failedAndIgnored) == 0 {
return nil return installer.failedAndIgnored, nil
} }
return &FailedIgnoredPkgError{ return installer.failedAndIgnored, &FailedIgnoredPkgError{
pkgErrors: installer.failedAndIgnored, pkgErrors: installer.failedAndIgnored,
} }
} }
@@ -234,12 +234,12 @@ func (installer *Installer) installAURPackages(ctx context.Context,
} }
installer.failedAndIgnored[name] = errMake installer.failedAndIgnored[name] = errMake
text.Errorln(gotext.Get("error making: %s", base), "-", errMake) installer.log.Errorln(gotext.Get("error making: %s", base), "-", errMake)
continue continue
} }
if len(pkgdests) == 0 { if len(pkgdests) == 0 {
text.Warnln(gotext.Get("nothing to install for %s", text.Cyan(base))) installer.log.Warnln(gotext.Get("nothing to install for %s", text.Cyan(base)))
continue continue
} }
@@ -298,10 +298,10 @@ func (installer *Installer) buildPkg(ctx context.Context,
case needed && installer.pkgsAreAlreadyInstalled(pkgdests, pkgVersion) || installer.downloadOnly: case needed && installer.pkgsAreAlreadyInstalled(pkgdests, pkgVersion) || installer.downloadOnly:
args = []string{"-c", "--nobuild", "--noextract", "--ignorearch"} args = []string{"-c", "--nobuild", "--noextract", "--ignorearch"}
pkgdests = map[string]string{} pkgdests = map[string]string{}
text.Warnln(gotext.Get("%s is up to date -- skipping", text.Cyan(base+"-"+pkgVersion))) installer.log.Warnln(gotext.Get("%s is up to date -- skipping", text.Cyan(base+"-"+pkgVersion)))
case installer.skipAlreadyBuiltPkg(isTarget, pkgdests): case installer.skipAlreadyBuiltPkg(isTarget, pkgdests):
args = []string{"-c", "--nobuild", "--noextract", "--ignorearch"} args = []string{"-c", "--nobuild", "--noextract", "--ignorearch"}
text.Warnln(gotext.Get("%s already made -- skipping build", text.Cyan(base+"-"+pkgVersion))) installer.log.Warnln(gotext.Get("%s already made -- skipping build", text.Cyan(base+"-"+pkgVersion)))
default: default:
args = []string{"-cf", "--noconfirm", "--noextract", "--noprepare", "--holdver"} args = []string{"-cf", "--noconfirm", "--noextract", "--noprepare", "--holdver"}
if installIncompatible { if installIncompatible {
@@ -333,10 +333,10 @@ func (installer *Installer) pkgsAreAlreadyInstalled(pkgdests map[string]string,
return true return true
} }
func pkgsAreBuilt(pkgdests map[string]string) bool { func pkgsAreBuilt(logger *text.Logger, pkgdests map[string]string) bool {
for _, pkgdest := range pkgdests { for _, pkgdest := range pkgdests {
if _, err := os.Stat(pkgdest); err != nil { if _, err := os.Stat(pkgdest); err != nil {
text.Debugln("pkgIsBuilt:", pkgdest, "does not exist") logger.Debugln("pkgIsBuilt:", pkgdest, "does not exist")
return false return false
} }
} }
@@ -347,14 +347,14 @@ func pkgsAreBuilt(pkgdests map[string]string) bool {
func (installer *Installer) skipAlreadyBuiltPkg(isTarget bool, pkgdests map[string]string) bool { func (installer *Installer) skipAlreadyBuiltPkg(isTarget bool, pkgdests map[string]string) bool {
switch installer.rebuildMode { switch installer.rebuildMode {
case parser.RebuildModeNo: case parser.RebuildModeNo:
return pkgsAreBuilt(pkgdests) return pkgsAreBuilt(installer.log, pkgdests)
case parser.RebuildModeYes: case parser.RebuildModeYes:
return !isTarget && pkgsAreBuilt(pkgdests) return !isTarget && pkgsAreBuilt(installer.log, pkgdests)
// case parser.RebuildModeTree: // TODO // case parser.RebuildModeTree: // TODO
// case parser.RebuildModeAll: // TODO // case parser.RebuildModeAll: // TODO
default: default:
// same as RebuildModeNo // same as RebuildModeNo
return pkgsAreBuilt(pkgdests) return pkgsAreBuilt(installer.log, pkgdests)
} }
} }

View File

@@ -1,4 +1,4 @@
package main package build
import ( import (
"context" "context"
@@ -21,7 +21,7 @@ import (
"github.com/Jguer/yay/v12/pkg/vcs" "github.com/Jguer/yay/v12/pkg/vcs"
) )
func NewTestLogger() *text.Logger { func newTestLogger() *text.Logger {
return text.NewLogger(io.Discard, io.Discard, strings.NewReader(""), true, "test") return text.NewLogger(io.Discard, io.Discard, strings.NewReader(""), true, "test")
} }
@@ -134,7 +134,7 @@ func TestInstaller_InstallNeeded(t *testing.T) {
cmdBuilder.Runner = mockRunner cmdBuilder.Runner = mockRunner
installer := NewInstaller(mockDB, cmdBuilder, &vcs.Mock{}, parser.ModeAny, installer := NewInstaller(mockDB, cmdBuilder, &vcs.Mock{}, parser.ModeAny,
parser.RebuildModeNo, false, NewTestLogger()) parser.RebuildModeNo, false, newTestLogger())
cmdArgs := parser.MakeArguments() cmdArgs := parser.MakeArguments()
cmdArgs.AddArg("needed") cmdArgs.AddArg("needed")
@@ -408,7 +408,7 @@ func TestInstaller_InstallMixedSourcesAndLayers(t *testing.T) {
cmdBuilder.Runner = mockRunner cmdBuilder.Runner = mockRunner
installer := NewInstaller(mockDB, cmdBuilder, &vcs.Mock{}, parser.ModeAny, parser.RebuildModeNo, false, NewTestLogger()) installer := NewInstaller(mockDB, cmdBuilder, &vcs.Mock{}, parser.ModeAny, parser.RebuildModeNo, false, newTestLogger())
cmdArgs := parser.MakeArguments() cmdArgs := parser.MakeArguments()
cmdArgs.AddTarget("yay") cmdArgs.AddTarget("yay")
@@ -462,7 +462,7 @@ func TestInstaller_RunPostHooks(t *testing.T) {
cmdBuilder.Runner = mockRunner cmdBuilder.Runner = mockRunner
installer := NewInstaller(mockDB, cmdBuilder, &vcs.Mock{}, parser.ModeAny, installer := NewInstaller(mockDB, cmdBuilder, &vcs.Mock{}, parser.ModeAny,
parser.RebuildModeNo, false, NewTestLogger()) parser.RebuildModeNo, false, newTestLogger())
called := false called := false
hook := func(ctx context.Context) error { hook := func(ctx context.Context) error {
@@ -593,7 +593,7 @@ func TestInstaller_CompileFailed(t *testing.T) {
cmdBuilder.Runner = mockRunner cmdBuilder.Runner = mockRunner
installer := NewInstaller(mockDB, cmdBuilder, &vcs.Mock{}, parser.ModeAny, installer := NewInstaller(mockDB, cmdBuilder, &vcs.Mock{}, parser.ModeAny,
parser.RebuildModeNo, false, NewTestLogger()) parser.RebuildModeNo, false, newTestLogger())
cmdArgs := parser.MakeArguments() cmdArgs := parser.MakeArguments()
cmdArgs.AddArg("needed") cmdArgs.AddArg("needed")
@@ -609,10 +609,11 @@ func TestInstaller_CompileFailed(t *testing.T) {
} else { } else {
require.NoError(td, errI) require.NoError(td, errI)
} }
err := installer.CompileFailedAndIgnored() failed, err := installer.CompileFailedAndIgnored()
if tc.wantErrCompile { if tc.wantErrCompile {
require.Error(td, err) require.Error(td, err)
assert.ErrorContains(td, err, "yay") assert.ErrorContains(td, err, "yay")
assert.Len(t, failed, len(tc.targets))
} else { } else {
require.NoError(td, err) require.NoError(td, err)
} }
@@ -752,7 +753,7 @@ func TestInstaller_InstallSplitPackage(t *testing.T) {
cmdBuilder.Runner = mockRunner cmdBuilder.Runner = mockRunner
installer := NewInstaller(mockDB, cmdBuilder, &vcs.Mock{}, parser.ModeAny, installer := NewInstaller(mockDB, cmdBuilder, &vcs.Mock{}, parser.ModeAny,
parser.RebuildModeNo, false, NewTestLogger()) parser.RebuildModeNo, false, newTestLogger())
cmdArgs := parser.MakeArguments() cmdArgs := parser.MakeArguments()
cmdArgs.AddTarget("jellyfin") cmdArgs.AddTarget("jellyfin")
@@ -891,7 +892,7 @@ func TestInstaller_InstallDownloadOnly(t *testing.T) {
cmdBuilder.Runner = mockRunner cmdBuilder.Runner = mockRunner
installer := NewInstaller(mockDB, cmdBuilder, &vcs.Mock{}, parser.ModeAny, installer := NewInstaller(mockDB, cmdBuilder, &vcs.Mock{}, parser.ModeAny,
parser.RebuildModeNo, true, NewTestLogger()) parser.RebuildModeNo, true, newTestLogger())
cmdArgs := parser.MakeArguments() cmdArgs := parser.MakeArguments()
cmdArgs.AddTarget("yay") cmdArgs.AddTarget("yay")
@@ -995,7 +996,7 @@ func TestInstaller_InstallGroup(t *testing.T) {
cmdBuilder.Runner = mockRunner cmdBuilder.Runner = mockRunner
installer := NewInstaller(mockDB, cmdBuilder, &vcs.Mock{}, parser.ModeAny, installer := NewInstaller(mockDB, cmdBuilder, &vcs.Mock{}, parser.ModeAny,
parser.RebuildModeNo, true, NewTestLogger()) parser.RebuildModeNo, true, newTestLogger())
cmdArgs := parser.MakeArguments() cmdArgs := parser.MakeArguments()
cmdArgs.AddTarget("kubernetes-tools") cmdArgs.AddTarget("kubernetes-tools")
@@ -1213,7 +1214,7 @@ func TestInstaller_InstallRebuild(t *testing.T) {
cmdBuilder.Runner = mockRunner cmdBuilder.Runner = mockRunner
installer := NewInstaller(mockDB, cmdBuilder, &vcs.Mock{}, parser.ModeAny, installer := NewInstaller(mockDB, cmdBuilder, &vcs.Mock{}, parser.ModeAny,
tc.rebuildOption, false, NewTestLogger()) tc.rebuildOption, false, newTestLogger())
cmdArgs := parser.MakeArguments() cmdArgs := parser.MakeArguments()
cmdArgs.AddTarget("yay") cmdArgs.AddTarget("yay")
@@ -1298,7 +1299,7 @@ func TestInstaller_InstallUpgrade(t *testing.T) {
} }
installer := NewInstaller(mockDB, cmdBuilder, &vcs.Mock{}, tc.targetMode, installer := NewInstaller(mockDB, cmdBuilder, &vcs.Mock{}, tc.targetMode,
parser.RebuildModeNo, false, NewTestLogger()) parser.RebuildModeNo, false, newTestLogger())
cmdArgs := parser.MakeArguments() cmdArgs := parser.MakeArguments()
cmdArgs.AddArg("u", "upgrades") // Make sure both args are removed cmdArgs.AddArg("u", "upgrades") // Make sure both args are removed

View File

@@ -1,4 +1,4 @@
package main package build
import ( import (
"context" "context"
@@ -16,164 +16,6 @@ import (
"github.com/Jguer/yay/v12/pkg/vcs" "github.com/Jguer/yay/v12/pkg/vcs"
) )
func setPkgReason(ctx context.Context,
cmdBuilder exe.ICmdBuilder,
mode parser.TargetMode,
cmdArgs *parser.Arguments, pkgs []string, exp bool,
) error {
if len(pkgs) == 0 {
return nil
}
cmdArgs = cmdArgs.CopyGlobal()
if exp {
if err := cmdArgs.AddArg("q", "D", "asexplicit"); err != nil {
return err
}
} else {
if err := cmdArgs.AddArg("q", "D", "asdeps"); err != nil {
return err
}
}
for _, compositePkgName := range pkgs {
pkgSplit := strings.Split(compositePkgName, "/")
pkgName := pkgSplit[0]
if len(pkgSplit) > 1 {
pkgName = pkgSplit[1]
}
cmdArgs.AddTarget(pkgName)
}
if err := cmdBuilder.Show(cmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, mode, settings.NoConfirm)); err != nil {
return &SetPkgReasonError{exp: exp}
}
return nil
}
func asdeps(ctx context.Context,
cmdBuilder exe.ICmdBuilder,
mode parser.TargetMode, cmdArgs *parser.Arguments, pkgs []string,
) error {
return setPkgReason(ctx, cmdBuilder, mode, cmdArgs, pkgs, false)
}
func asexp(ctx context.Context,
cmdBuilder exe.ICmdBuilder,
mode parser.TargetMode, cmdArgs *parser.Arguments, pkgs []string,
) error {
return setPkgReason(ctx, cmdBuilder, mode, cmdArgs, pkgs, true)
}
func removeMake(ctx context.Context, config *settings.Configuration,
cmdBuilder exe.ICmdBuilder, makeDeps []string, cmdArgs *parser.Arguments,
) error {
removeArguments := cmdArgs.CopyGlobal()
err := removeArguments.AddArg("R", "s", "u")
if err != nil {
return err
}
for _, pkg := range makeDeps {
removeArguments.AddTarget(pkg)
}
oldValue := settings.NoConfirm
settings.NoConfirm = true
err = cmdBuilder.Show(cmdBuilder.BuildPacmanCmd(ctx,
removeArguments, config.Mode, settings.NoConfirm))
settings.NoConfirm = oldValue
return err
}
func earlyRefresh(ctx context.Context, cfg *settings.Configuration, cmdBuilder exe.ICmdBuilder, cmdArgs *parser.Arguments) error {
arguments := cmdArgs.Copy()
if cfg.CombinedUpgrade {
arguments.DelArg("u", "sysupgrade")
}
arguments.DelArg("s", "search")
arguments.DelArg("i", "info")
arguments.DelArg("l", "list")
arguments.ClearTargets()
return cmdBuilder.Show(cmdBuilder.BuildPacmanCmd(ctx,
arguments, cfg.Mode, settings.NoConfirm))
}
func parsePackageList(ctx context.Context, cmdBuilder exe.ICmdBuilder,
dir string,
) (pkgdests map[string]string, pkgVersion string, err error) {
stdout, stderr, err := cmdBuilder.Capture(
cmdBuilder.BuildMakepkgCmd(ctx, dir, "--packagelist"))
if err != nil {
return nil, "", fmt.Errorf("%s %w", stderr, err)
}
lines := strings.Split(stdout, "\n")
pkgdests = make(map[string]string)
for _, line := range lines {
if line == "" {
continue
}
fileName := filepath.Base(line)
split := strings.Split(fileName, "-")
if len(split) < 4 {
return nil, "", errors.New(gotext.Get("cannot find package name: %v", split))
}
// pkgname-pkgver-pkgrel-arch.pkgext
// This assumes 3 dashes after the pkgname, Will cause an error
// if the PKGEXT contains a dash. Please no one do that.
pkgName := strings.Join(split[:len(split)-3], "-")
pkgVersion = strings.Join(split[len(split)-3:len(split)-1], "-")
pkgdests[pkgName] = line
}
if len(pkgdests) == 0 {
return nil, "", &NoPkgDestsFoundError{dir}
}
return pkgdests, pkgVersion, nil
}
func gitMerge(ctx context.Context, cmdBuilder exe.ICmdBuilder, dir string) error {
_, stderr, err := cmdBuilder.Capture(
cmdBuilder.BuildGitCmd(ctx,
dir, "reset", "--hard", "HEAD"))
if err != nil {
return errors.New(gotext.Get("error resetting %s: %s", dir, stderr))
}
_, stderr, err = cmdBuilder.Capture(
cmdBuilder.BuildGitCmd(ctx,
dir, "merge", "--no-edit", "--ff"))
if err != nil {
return errors.New(gotext.Get("error merging %s: %s", dir, stderr))
}
return nil
}
func mergePkgbuilds(ctx context.Context, cmdBuilder exe.ICmdBuilder, pkgbuildDirs map[string]string) error {
for _, dir := range pkgbuildDirs {
err := gitMerge(ctx, cmdBuilder, dir)
if err != nil {
return err
}
}
return nil
}
func installPkgArchive(ctx context.Context, func installPkgArchive(ctx context.Context,
cmdBuilder exe.ICmdBuilder, cmdBuilder exe.ICmdBuilder,
mode parser.TargetMode, mode parser.TargetMode,
@@ -228,3 +70,95 @@ func setInstallReason(ctx context.Context,
return asexp(ctx, cmdBuilder, mode, cmdArgs, exps) return asexp(ctx, cmdBuilder, mode, cmdArgs, exps)
} }
func setPkgReason(ctx context.Context,
cmdBuilder exe.ICmdBuilder,
mode parser.TargetMode,
cmdArgs *parser.Arguments, pkgs []string, exp bool,
) error {
if len(pkgs) == 0 {
return nil
}
cmdArgs = cmdArgs.CopyGlobal()
if exp {
if err := cmdArgs.AddArg("q", "D", "asexplicit"); err != nil {
return err
}
} else {
if err := cmdArgs.AddArg("q", "D", "asdeps"); err != nil {
return err
}
}
for _, compositePkgName := range pkgs {
pkgSplit := strings.Split(compositePkgName, "/")
pkgName := pkgSplit[0]
if len(pkgSplit) > 1 {
pkgName = pkgSplit[1]
}
cmdArgs.AddTarget(pkgName)
}
if err := cmdBuilder.Show(cmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, mode, settings.NoConfirm)); err != nil {
return &SetPkgReasonError{exp: exp}
}
return nil
}
func asdeps(ctx context.Context,
cmdBuilder exe.ICmdBuilder,
mode parser.TargetMode, cmdArgs *parser.Arguments, pkgs []string,
) error {
return setPkgReason(ctx, cmdBuilder, mode, cmdArgs, pkgs, false)
}
func asexp(ctx context.Context,
cmdBuilder exe.ICmdBuilder,
mode parser.TargetMode, cmdArgs *parser.Arguments, pkgs []string,
) error {
return setPkgReason(ctx, cmdBuilder, mode, cmdArgs, pkgs, true)
}
func parsePackageList(ctx context.Context, cmdBuilder exe.ICmdBuilder,
dir string,
) (pkgdests map[string]string, pkgVersion string, err error) {
stdout, stderr, err := cmdBuilder.Capture(
cmdBuilder.BuildMakepkgCmd(ctx, dir, "--packagelist"))
if err != nil {
return nil, "", fmt.Errorf("%s %w", stderr, err)
}
lines := strings.Split(stdout, "\n")
pkgdests = make(map[string]string)
for _, line := range lines {
if line == "" {
continue
}
fileName := filepath.Base(line)
split := strings.Split(fileName, "-")
if len(split) < 4 {
return nil, "", errors.New(gotext.Get("cannot find package name: %v", split))
}
// pkgname-pkgver-pkgrel-arch.pkgext
// This assumes 3 dashes after the pkgname, Will cause an error
// if the PKGEXT contains a dash. Please no one do that.
pkgName := strings.Join(split[:len(split)-3], "-")
pkgVersion = strings.Join(split[len(split)-3:len(split)-1], "-")
pkgdests[pkgName] = line
}
if len(pkgdests) == 0 {
return nil, "", &NoPkgDestsFoundError{dir}
}
return pkgdests, pkgVersion, nil
}

View File

@@ -4,8 +4,6 @@ import (
"bytes" "bytes"
"context" "context"
"errors" "errors"
"fmt"
"os"
"os/exec" "os/exec"
"strings" "strings"
@@ -50,7 +48,7 @@ type GPGCmdBuilder interface {
// CheckPgpKeys iterates through the keys listed in the PKGBUILDs and if needed, // CheckPgpKeys iterates through the keys listed in the PKGBUILDs and if needed,
// asks the user whether yay should try to import them. // asks the user whether yay should try to import them.
func CheckPgpKeys(ctx context.Context, pkgbuildDirsByBase map[string]string, srcinfos map[string]*gosrc.Srcinfo, func CheckPgpKeys(ctx context.Context, logger *text.Logger, pkgbuildDirsByBase map[string]string, srcinfos map[string]*gosrc.Srcinfo,
cmdBuilder GPGCmdBuilder, noConfirm bool, cmdBuilder GPGCmdBuilder, noConfirm bool,
) ([]string, error) { ) ([]string, error) {
// Let's check the keys individually, and then we can offer to import // Let's check the keys individually, and then we can offer to import
@@ -80,24 +78,23 @@ func CheckPgpKeys(ctx context.Context, pkgbuildDirsByBase map[string]string, src
return []string{}, nil return []string{}, nil
} }
str, err := formatKeysToImport(problematic) str, err := formatKeysToImport(logger, problematic)
if err != nil { if err != nil {
return nil, err return nil, err
} }
fmt.Println() logger.Println("\n", str)
fmt.Println(str)
if text.ContinueTask(os.Stdin, gotext.Get("Import?"), true, noConfirm) { if logger.ContinueTask(gotext.Get("Import?"), true, noConfirm) {
return problematic.toSlice(), importKeys(ctx, cmdBuilder, problematic.toSlice()) return problematic.toSlice(), importKeys(ctx, logger, cmdBuilder, problematic.toSlice())
} }
return problematic.toSlice(), nil return problematic.toSlice(), nil
} }
// importKeys tries to import the list of keys specified in its argument. // importKeys tries to import the list of keys specified in its argument.
func importKeys(ctx context.Context, cmdBuilder GPGCmdBuilder, keys []string) error { func importKeys(ctx context.Context, logger *text.Logger, cmdBuilder GPGCmdBuilder, keys []string) error {
text.OperationInfoln(gotext.Get("Importing keys with gpg...")) logger.OperationInfoln(gotext.Get("Importing keys with gpg..."))
if err := cmdBuilder.Show(cmdBuilder.BuildGPGCmd(ctx, append([]string{"--recv-keys"}, keys...)...)); err != nil { if err := cmdBuilder.Show(cmdBuilder.BuildGPGCmd(ctx, append([]string{"--recv-keys"}, keys...)...)); err != nil {
return errors.New(gotext.Get("problem importing keys")) return errors.New(gotext.Get("problem importing keys"))
@@ -108,14 +105,14 @@ func importKeys(ctx context.Context, cmdBuilder GPGCmdBuilder, keys []string) er
// formatKeysToImport receives a set of keys and returns a string containing the // formatKeysToImport receives a set of keys and returns a string containing the
// question asking the user wants to import the problematic keys. // question asking the user wants to import the problematic keys.
func formatKeysToImport(keys pgpKeySet) (string, error) { func formatKeysToImport(logger *text.Logger, keys pgpKeySet) (string, error) {
if len(keys) == 0 { if len(keys) == 0 {
return "", errors.New(gotext.Get("no keys to import")) return "", errors.New(gotext.Get("no keys to import"))
} }
var buffer bytes.Buffer var buffer bytes.Buffer
buffer.WriteString(text.SprintOperationInfo(gotext.Get("PGP keys need importing:"))) buffer.WriteString(logger.SprintOperationInfo(gotext.Get("PGP keys need importing:")))
for key, bases := range keys { for key, bases := range keys {
pkglist := "" pkglist := ""
@@ -124,7 +121,7 @@ func formatKeysToImport(keys pgpKeySet) (string, error) {
} }
pkglist = strings.TrimRight(pkglist, " ") pkglist = strings.TrimRight(pkglist, " ")
buffer.WriteString("\n" + text.SprintWarn(gotext.Get("%s, required by: %s", text.Cyan(key), text.Cyan(pkglist)))) buffer.WriteString("\n" + logger.SprintWarn(gotext.Get("%s, required by: %s", text.Cyan(key), text.Cyan(pkglist))))
} }
return buffer.String(), nil return buffer.String(), nil

View File

@@ -6,6 +6,7 @@ package pgp
import ( import (
"context" "context"
"fmt" "fmt"
"io"
"os" "os"
"os/exec" "os/exec"
"sort" "sort"
@@ -17,8 +18,13 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/Jguer/yay/v12/pkg/settings/exe" "github.com/Jguer/yay/v12/pkg/settings/exe"
"github.com/Jguer/yay/v12/pkg/text"
) )
func newTestLogger() *text.Logger {
return text.NewLogger(io.Discard, io.Discard, strings.NewReader(""), true, "test")
}
func makeSrcinfo(pkgbase string, pgpkeys ...string) *gosrc.Srcinfo { func makeSrcinfo(pkgbase string, pgpkeys ...string) *gosrc.Srcinfo {
srcinfo := gosrc.Srcinfo{} srcinfo := gosrc.Srcinfo{}
srcinfo.Pkgbase = pkgbase srcinfo.Pkgbase = pkgbase
@@ -228,7 +234,7 @@ func TestCheckPgpKeys(t *testing.T) {
GPGFlags: []string{"--homedir /tmp"}, GPGFlags: []string{"--homedir /tmp"},
Runner: mockRunner, Runner: mockRunner,
} }
problematic, err := CheckPgpKeys(context.Background(), tt.pkgs, tt.srcinfos, &cmdBuilder, true) problematic, err := CheckPgpKeys(context.Background(), newTestLogger(), tt.pkgs, tt.srcinfos, &cmdBuilder, true)
require.Len(t, mockRunner.ShowCalls, len(tt.wantShow)) require.Len(t, mockRunner.ShowCalls, len(tt.wantShow))
require.Len(t, mockRunner.CaptureCalls, len(tt.wantCapture)) require.Len(t, mockRunner.CaptureCalls, len(tt.wantCapture))

View File

@@ -11,28 +11,28 @@ import (
"github.com/Jguer/yay/v12/pkg/db" "github.com/Jguer/yay/v12/pkg/db"
"github.com/Jguer/yay/v12/pkg/dep" "github.com/Jguer/yay/v12/pkg/dep"
"github.com/Jguer/yay/v12/pkg/pgp"
"github.com/Jguer/yay/v12/pkg/settings" "github.com/Jguer/yay/v12/pkg/settings"
"github.com/Jguer/yay/v12/pkg/settings/exe" "github.com/Jguer/yay/v12/pkg/settings/exe"
"github.com/Jguer/yay/v12/pkg/sync/srcinfo/pgp"
"github.com/Jguer/yay/v12/pkg/text" "github.com/Jguer/yay/v12/pkg/text"
"github.com/Jguer/yay/v12/pkg/vcs" "github.com/Jguer/yay/v12/pkg/vcs"
) )
// TODO: add tests
type Service struct { type Service struct {
dbExecutor db.Executor dbExecutor db.Executor
cfg *settings.Configuration cfg *settings.Configuration
cmdBuilder exe.ICmdBuilder cmdBuilder pgp.GPGCmdBuilder
vcsStore vcs.Store vcsStore vcs.Store
log *text.Logger
pkgBuildDirs map[string]string pkgBuildDirs map[string]string
srcInfos map[string]*gosrc.Srcinfo srcInfos map[string]*gosrc.Srcinfo
} }
func NewService(dbExecutor db.Executor, cfg *settings.Configuration, func NewService(dbExecutor db.Executor, cfg *settings.Configuration, logger *text.Logger,
cmdBuilder exe.ICmdBuilder, vcsStore vcs.Store, pkgBuildDirs map[string]string, cmdBuilder exe.ICmdBuilder, vcsStore vcs.Store, pkgBuildDirs map[string]string,
) (*Service, error) { ) (*Service, error) {
srcinfos, err := ParseSrcinfoFilesByBase(pkgBuildDirs, true) srcinfos, err := ParseSrcinfoFilesByBase(logger, pkgBuildDirs, true)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@@ -43,6 +43,7 @@ func NewService(dbExecutor db.Executor, cfg *settings.Configuration,
vcsStore: vcsStore, vcsStore: vcsStore,
pkgBuildDirs: pkgBuildDirs, pkgBuildDirs: pkgBuildDirs,
srcInfos: srcinfos, srcInfos: srcinfos,
log: logger,
}, nil }, nil
} }
@@ -68,7 +69,7 @@ nextpkg:
} }
func (s *Service) CheckPGPKeys(ctx context.Context) error { func (s *Service) CheckPGPKeys(ctx context.Context) error {
_, errCPK := pgp.CheckPgpKeys(ctx, s.pkgBuildDirs, s.srcInfos, s.cmdBuilder, settings.NoConfirm) _, errCPK := pgp.CheckPgpKeys(ctx, s.log.Child("pgp"), s.pkgBuildDirs, s.srcInfos, s.cmdBuilder, settings.NoConfirm)
return errCPK return errCPK
} }
@@ -83,15 +84,15 @@ func (s *Service) UpdateVCSStore(ctx context.Context, targets []map[string]*dep.
for i := range srcinfo.Packages { for i := range srcinfo.Packages {
for j := range targets { for j := range targets {
if _, ok := targets[j][srcinfo.Packages[i].Pkgname]; !ok { if _, ok := targets[j][srcinfo.Packages[i].Pkgname]; !ok {
text.Debugln("skipping VCS update for", srcinfo.Packages[i].Pkgname, "not in targets") s.log.Debugln("skipping VCS update for", srcinfo.Packages[i].Pkgname, "not in targets")
continue continue
} }
if _, ok := ignore[srcinfo.Packages[i].Pkgname]; ok { if _, ok := ignore[srcinfo.Packages[i].Pkgname]; ok {
text.Debugln("skipping VCS update for", srcinfo.Packages[i].Pkgname, "due to install error") s.log.Debugln("skipping VCS update for", srcinfo.Packages[i].Pkgname, "due to install error")
continue continue
} }
text.Debugln("checking VCS entry for", srcinfo.Packages[i].Pkgname, fmt.Sprintf("source: %v", srcinfo.Source)) s.log.Debugln("checking VCS entry for", srcinfo.Packages[i].Pkgname, fmt.Sprintf("source: %v", srcinfo.Source))
s.vcsStore.Update(ctx, srcinfo.Packages[i].Pkgname, srcinfo.Source) s.vcsStore.Update(ctx, srcinfo.Packages[i].Pkgname, srcinfo.Source)
} }
} }
@@ -100,17 +101,17 @@ func (s *Service) UpdateVCSStore(ctx context.Context, targets []map[string]*dep.
return nil return nil
} }
func ParseSrcinfoFilesByBase(pkgBuildDirs map[string]string, errIsFatal bool) (map[string]*gosrc.Srcinfo, error) { func ParseSrcinfoFilesByBase(logger *text.Logger, pkgBuildDirs map[string]string, errIsFatal bool) (map[string]*gosrc.Srcinfo, error) {
srcinfos := make(map[string]*gosrc.Srcinfo) srcinfos := make(map[string]*gosrc.Srcinfo)
k := 0 k := 0
for base, dir := range pkgBuildDirs { for base, dir := range pkgBuildDirs {
text.OperationInfoln(gotext.Get("(%d/%d) Parsing SRCINFO: %s", k+1, len(pkgBuildDirs), text.Cyan(base))) logger.OperationInfoln(gotext.Get("(%d/%d) Parsing SRCINFO: %s", k+1, len(pkgBuildDirs), text.Cyan(base)))
pkgbuild, err := gosrc.ParseFile(filepath.Join(dir, ".SRCINFO")) pkgbuild, err := gosrc.ParseFile(filepath.Join(dir, ".SRCINFO"))
if err != nil { if err != nil {
if !errIsFatal { if !errIsFatal {
text.Warnln(gotext.Get("failed to parse %s -- skipping: %s", base, err)) logger.Warnln(gotext.Get("failed to parse %s -- skipping: %s", base, err))
continue continue
} }

View File

@@ -0,0 +1,132 @@
package srcinfo
import (
"context"
"io"
"strings"
"testing"
gosrc "github.com/Morganamilo/go-srcinfo"
"github.com/stretchr/testify/assert"
"github.com/Jguer/yay/v12/pkg/db/mock"
"github.com/Jguer/yay/v12/pkg/dep"
"github.com/Jguer/yay/v12/pkg/settings"
"github.com/Jguer/yay/v12/pkg/settings/exe"
"github.com/Jguer/yay/v12/pkg/text"
"github.com/Jguer/yay/v12/pkg/vcs"
)
func newTestLogger() *text.Logger {
return text.NewLogger(io.Discard, io.Discard, strings.NewReader(""), true, "test")
}
func TestNewService(t *testing.T) {
dbExecutor := &mock.DBExecutor{}
cfg := &settings.Configuration{}
cmdBuilder := &exe.MockBuilder{}
vcsStore := &vcs.Mock{}
pkgBuildDirs := map[string]string{
"jellyfin": "../../../testdata/jfin",
"cephbin": "../../../testdata/cephbin",
}
srv, err := NewService(dbExecutor, cfg, newTestLogger(), cmdBuilder, vcsStore, pkgBuildDirs)
assert.NoError(t, err)
assert.NotNil(t, srv)
assert.Equal(t, dbExecutor, srv.dbExecutor)
assert.Equal(t, cfg, srv.cfg)
assert.Equal(t, cmdBuilder, srv.cmdBuilder)
assert.Equal(t, vcsStore, srv.vcsStore)
assert.Equal(t, pkgBuildDirs, srv.pkgBuildDirs)
assert.NotNil(t, srv.srcInfos)
}
func TestService_IncompatiblePkgs(t *testing.T) {
srv := &Service{
dbExecutor: &mock.DBExecutor{AlpmArchitecturesFn: func() ([]string, error) {
return []string{"x86_64"}, nil
}},
srcInfos: map[string]*gosrc.Srcinfo{
"pkg1": {
Package: gosrc.Package{
Arch: []string{"x86_64", "any"},
},
},
"pkg2": {
Package: gosrc.Package{
Arch: []string{"any"},
},
},
"pkg3": {
Package: gosrc.Package{
Arch: []string{"armv7h"},
},
},
"pkg4": {
Package: gosrc.Package{
Arch: []string{"i683", "x86_64"},
},
},
},
}
incompatible, err := srv.IncompatiblePkgs(context.Background())
assert.NoError(t, err)
assert.ElementsMatch(t, []string{"pkg3"}, incompatible)
}
func TestService_CheckPGPKeys(t *testing.T) {
srv := &Service{
log: newTestLogger(),
pkgBuildDirs: map[string]string{
"pkg1": "/path/to/pkg1",
"pkg2": "/path/to/pkg2",
},
srcInfos: map[string]*gosrc.Srcinfo{
"pkg1": {
Packages: []gosrc.Package{
{Pkgname: "pkg1"},
},
},
"pkg2": {
Packages: []gosrc.Package{
{Pkgname: "pkg2"},
},
},
},
}
err := srv.CheckPGPKeys(context.Background())
assert.NoError(t, err)
}
func TestService_UpdateVCSStore(t *testing.T) {
srv := &Service{
srcInfos: map[string]*gosrc.Srcinfo{
"pkg1": {
Packages: []gosrc.Package{
{Pkgname: "pkg1"},
},
},
"pkg2": {
Packages: []gosrc.Package{
{Pkgname: "pkg2"},
},
},
},
vcsStore: &vcs.Mock{},
}
targets := []map[string]*dep.InstallInfo{
{
"pkg1": {},
"pkg2": {},
},
}
ignore := map[string]error{}
err := srv.UpdateVCSStore(context.Background(), targets, ignore)
assert.NoError(t, err)
}

138
pkg/sync/sync.go Normal file
View File

@@ -0,0 +1,138 @@
package sync
import (
"context"
"github.com/Jguer/yay/v12/pkg/completion"
"github.com/Jguer/yay/v12/pkg/db"
"github.com/Jguer/yay/v12/pkg/dep"
"github.com/Jguer/yay/v12/pkg/multierror"
"github.com/Jguer/yay/v12/pkg/runtime"
"github.com/Jguer/yay/v12/pkg/settings"
"github.com/Jguer/yay/v12/pkg/settings/parser"
"github.com/Jguer/yay/v12/pkg/sync/build"
"github.com/Jguer/yay/v12/pkg/sync/srcinfo"
"github.com/Jguer/yay/v12/pkg/sync/workdir"
"github.com/Jguer/yay/v12/pkg/text"
"github.com/leonelquinteros/gotext"
)
type OperationService struct {
ctx context.Context
cfg *settings.Configuration
dbExecutor db.Executor
logger *text.Logger
}
func NewOperationService(ctx context.Context,
dbExecutor db.Executor,
run *runtime.Runtime,
) *OperationService {
return &OperationService{
ctx: ctx,
cfg: run.Cfg,
dbExecutor: dbExecutor,
logger: run.Logger.Child("operation"),
}
}
func (o *OperationService) Run(ctx context.Context, run *runtime.Runtime,
cmdArgs *parser.Arguments,
targets []map[string]*dep.InstallInfo, excluded []string,
) error {
if len(targets) == 0 {
o.logger.Println("", gotext.Get("there is nothing to do"))
return nil
}
preparer := workdir.NewPreparer(o.dbExecutor, run.CmdBuilder, o.cfg, o.logger.Child("workdir"))
installer := build.NewInstaller(o.dbExecutor, run.CmdBuilder,
run.VCSStore, o.cfg.Mode, o.cfg.ReBuild,
cmdArgs.ExistsArg("w", "downloadonly"), run.Logger.Child("installer"))
pkgBuildDirs, errInstall := preparer.Run(ctx, run, targets)
if errInstall != nil {
return errInstall
}
if cleanFunc := preparer.ShouldCleanMakeDeps(run, cmdArgs); cleanFunc != nil {
installer.AddPostInstallHook(cleanFunc)
}
if cleanAURDirsFunc := preparer.ShouldCleanAURDirs(run, pkgBuildDirs); cleanAURDirsFunc != nil {
installer.AddPostInstallHook(cleanAURDirsFunc)
}
go func() {
errComp := completion.Update(ctx, run.HTTPClient, o.dbExecutor,
o.cfg.AURURL, o.cfg.CompletionPath, o.cfg.CompletionInterval, false)
if errComp != nil {
o.logger.Warnln(errComp)
}
}()
srcInfo, errInstall := srcinfo.NewService(o.dbExecutor, o.cfg,
o.logger.Child("srcinfo"), run.CmdBuilder, run.VCSStore, pkgBuildDirs)
if errInstall != nil {
return errInstall
}
incompatible, errInstall := srcInfo.IncompatiblePkgs(ctx)
if errInstall != nil {
return errInstall
}
if errIncompatible := confirmIncompatible(o.logger, incompatible); errIncompatible != nil {
return errIncompatible
}
if errPGP := srcInfo.CheckPGPKeys(ctx); errPGP != nil {
return errPGP
}
if errInstall := installer.Install(ctx, cmdArgs, targets, pkgBuildDirs,
excluded, o.manualConfirmRequired(cmdArgs)); errInstall != nil {
return errInstall
}
var multiErr multierror.MultiError
failedAndIgnored, err := installer.CompileFailedAndIgnored()
if err != nil {
multiErr.Add(err)
}
if !cmdArgs.ExistsArg("w", "downloadonly") {
if err := srcInfo.UpdateVCSStore(ctx, targets, failedAndIgnored); err != nil {
o.logger.Warnln(err)
}
}
if err := installer.RunPostInstallHooks(ctx); err != nil {
multiErr.Add(err)
}
return multiErr.Return()
}
func (o *OperationService) manualConfirmRequired(cmdArgs *parser.Arguments) bool {
return (!cmdArgs.ExistsArg("u", "sysupgrade") && cmdArgs.Op != "Y") || o.cfg.DoubleConfirm
}
func confirmIncompatible(logger *text.Logger, incompatible []string) error {
if len(incompatible) > 0 {
logger.Warnln(gotext.Get("The following packages are not compatible with your architecture:"))
for _, pkg := range incompatible {
logger.Print(" " + text.Cyan(pkg))
}
logger.Println()
if !logger.ContinueTask(gotext.Get("Try to build them anyway?"), true, settings.NoConfirm) {
return &settings.ErrUserAbort{}
}
}
return nil
}

View File

@@ -1,4 +1,4 @@
package main package workdir
import ( import (
"context" "context"

View File

@@ -1,7 +1,7 @@
//go:build !integration //go:build !integration
// +build !integration // +build !integration
package main package workdir
import ( import (
"context" "context"

62
pkg/sync/workdir/clean.go Normal file
View File

@@ -0,0 +1,62 @@
package workdir
import (
"context"
"github.com/leonelquinteros/gotext"
"github.com/Jguer/yay/v12/pkg/runtime"
"github.com/Jguer/yay/v12/pkg/settings"
"github.com/Jguer/yay/v12/pkg/settings/exe"
"github.com/Jguer/yay/v12/pkg/settings/parser"
"github.com/Jguer/yay/v12/pkg/text"
)
func removeMake(ctx context.Context, config *settings.Configuration,
cmdBuilder exe.ICmdBuilder, makeDeps []string, cmdArgs *parser.Arguments,
) error {
removeArguments := cmdArgs.CopyGlobal()
err := removeArguments.AddArg("R", "s", "u")
if err != nil {
return err
}
for _, pkg := range makeDeps {
removeArguments.AddTarget(pkg)
}
oldValue := settings.NoConfirm
settings.NoConfirm = true
err = cmdBuilder.Show(cmdBuilder.BuildPacmanCmd(ctx,
removeArguments, config.Mode, settings.NoConfirm))
settings.NoConfirm = oldValue
return err
}
func cleanAfter(ctx context.Context, run *runtime.Runtime,
cmdBuilder exe.ICmdBuilder, pkgbuildDirs map[string]string,
) {
run.Logger.Println(gotext.Get("removing untracked AUR files from cache..."))
i := 0
for _, dir := range pkgbuildDirs {
run.Logger.OperationInfoln(gotext.Get("Cleaning (%d/%d): %s", i+1, len(pkgbuildDirs), text.Cyan(dir)))
_, stderr, err := cmdBuilder.Capture(
cmdBuilder.BuildGitCmd(
ctx, dir, "reset", "--hard", "HEAD"))
if err != nil {
run.Logger.Errorln(gotext.Get("error resetting %s: %s", dir, stderr))
}
if err := run.CmdBuilder.Show(
run.CmdBuilder.BuildGitCmd(
ctx, dir, "clean", "-fx", "--exclude", "*.pkg.*")); err != nil {
run.Logger.Errorln(err)
}
i++
}
}

39
pkg/sync/workdir/merge.go Normal file
View File

@@ -0,0 +1,39 @@
package workdir
import (
"context"
"errors"
"github.com/leonelquinteros/gotext"
"github.com/Jguer/yay/v12/pkg/settings/exe"
)
func gitMerge(ctx context.Context, cmdBuilder exe.ICmdBuilder, dir string) error {
_, stderr, err := cmdBuilder.Capture(
cmdBuilder.BuildGitCmd(ctx,
dir, "reset", "--hard", "HEAD"))
if err != nil {
return errors.New(gotext.Get("error resetting %s: %s", dir, stderr))
}
_, stderr, err = cmdBuilder.Capture(
cmdBuilder.BuildGitCmd(ctx,
dir, "merge", "--no-edit", "--ff"))
if err != nil {
return errors.New(gotext.Get("error merging %s: %s", dir, stderr))
}
return nil
}
func mergePkgbuilds(ctx context.Context, cmdBuilder exe.ICmdBuilder, pkgbuildDirs map[string]string) error {
for _, dir := range pkgbuildDirs {
err := gitMerge(ctx, cmdBuilder, dir)
if err != nil {
return err
}
}
return nil
}

View File

@@ -1,4 +1,4 @@
package main package workdir
import ( import (
"context" "context"
@@ -12,9 +12,11 @@ import (
"github.com/Jguer/yay/v12/pkg/dep" "github.com/Jguer/yay/v12/pkg/dep"
"github.com/Jguer/yay/v12/pkg/download" "github.com/Jguer/yay/v12/pkg/download"
"github.com/Jguer/yay/v12/pkg/menus" "github.com/Jguer/yay/v12/pkg/menus"
"github.com/Jguer/yay/v12/pkg/runtime"
"github.com/Jguer/yay/v12/pkg/settings" "github.com/Jguer/yay/v12/pkg/settings"
"github.com/Jguer/yay/v12/pkg/settings/exe" "github.com/Jguer/yay/v12/pkg/settings/exe"
"github.com/Jguer/yay/v12/pkg/settings/parser" "github.com/Jguer/yay/v12/pkg/settings/parser"
"github.com/Jguer/yay/v12/pkg/sync/build"
"github.com/Jguer/yay/v12/pkg/text" "github.com/Jguer/yay/v12/pkg/text"
gosrc "github.com/Morganamilo/go-srcinfo" gosrc "github.com/Morganamilo/go-srcinfo"
@@ -29,7 +31,7 @@ const (
PreDownloadSourcesHook HookType = "pre-download-sources" PreDownloadSourcesHook HookType = "pre-download-sources"
) )
type HookFn func(ctx context.Context, config *settings.Configuration, w io.Writer, type HookFn func(ctx context.Context, run *runtime.Runtime, w io.Writer,
pkgbuildDirsByBase map[string]string, installed mapset.Set[string], pkgbuildDirsByBase map[string]string, installed mapset.Set[string],
) error ) error
@@ -45,12 +47,13 @@ type Preparer struct {
cfg *settings.Configuration cfg *settings.Configuration
hooks []Hook hooks []Hook
downloadSources bool downloadSources bool
log *text.Logger
makeDeps []string makeDeps []string
} }
func NewPreparerWithoutHooks(dbExecutor db.Executor, cmdBuilder exe.ICmdBuilder, func NewPreparerWithoutHooks(dbExecutor db.Executor, cmdBuilder exe.ICmdBuilder,
cfg *settings.Configuration, downloadSources bool, cfg *settings.Configuration, logger *text.Logger, downloadSources bool,
) *Preparer { ) *Preparer {
return &Preparer{ return &Preparer{
dbExecutor: dbExecutor, dbExecutor: dbExecutor,
@@ -58,13 +61,14 @@ func NewPreparerWithoutHooks(dbExecutor db.Executor, cmdBuilder exe.ICmdBuilder,
cfg: cfg, cfg: cfg,
hooks: []Hook{}, hooks: []Hook{},
downloadSources: downloadSources, downloadSources: downloadSources,
log: logger,
} }
} }
func NewPreparer(dbExecutor db.Executor, cmdBuilder exe.ICmdBuilder, func NewPreparer(dbExecutor db.Executor, cmdBuilder exe.ICmdBuilder,
cfg *settings.Configuration, cfg *settings.Configuration, logger *text.Logger,
) *Preparer { ) *Preparer {
preper := NewPreparerWithoutHooks(dbExecutor, cmdBuilder, cfg, true) preper := NewPreparerWithoutHooks(dbExecutor, cmdBuilder, cfg, logger, true)
if cfg.CleanMenu { if cfg.CleanMenu {
preper.hooks = append(preper.hooks, Hook{ preper.hooks = append(preper.hooks, Hook{
@@ -93,20 +97,20 @@ func NewPreparer(dbExecutor db.Executor, cmdBuilder exe.ICmdBuilder,
return preper return preper
} }
func (preper *Preparer) ShouldCleanAURDirs(pkgBuildDirs map[string]string) PostInstallHookFunc { func (preper *Preparer) ShouldCleanAURDirs(run *runtime.Runtime, pkgBuildDirs map[string]string) build.PostInstallHookFunc {
if !preper.cfg.CleanAfter || len(pkgBuildDirs) == 0 { if !preper.cfg.CleanAfter || len(pkgBuildDirs) == 0 {
return nil return nil
} }
text.Debugln("added post install hook to clean up AUR dirs", pkgBuildDirs) preper.log.Debugln("added post install hook to clean up AUR dirs", pkgBuildDirs)
return func(ctx context.Context) error { return func(ctx context.Context) error {
cleanAfter(ctx, preper.cfg, preper.cfg.Runtime.CmdBuilder, pkgBuildDirs) cleanAfter(ctx, run, run.CmdBuilder, pkgBuildDirs)
return nil return nil
} }
} }
func (preper *Preparer) ShouldCleanMakeDeps(cmdArgs *parser.Arguments) PostInstallHookFunc { func (preper *Preparer) ShouldCleanMakeDeps(run *runtime.Runtime, cmdArgs *parser.Arguments) build.PostInstallHookFunc {
if len(preper.makeDeps) == 0 { if len(preper.makeDeps) == 0 {
return nil return nil
} }
@@ -118,25 +122,25 @@ func (preper *Preparer) ShouldCleanMakeDeps(cmdArgs *parser.Arguments) PostInsta
return nil return nil
default: default:
isYesDefault := preper.cfg.RemoveMake == "askyes" isYesDefault := preper.cfg.RemoveMake == "askyes"
if !text.ContinueTask(os.Stdin, gotext.Get("Remove make dependencies after install?"), if !preper.log.ContinueTask(gotext.Get("Remove make dependencies after install?"),
isYesDefault, settings.NoConfirm) { isYesDefault, settings.NoConfirm) {
return nil return nil
} }
} }
text.Debugln("added post install hook to clean up AUR makedeps", preper.makeDeps) preper.log.Debugln("added post install hook to clean up AUR makedeps", preper.makeDeps)
return func(ctx context.Context) error { return func(ctx context.Context) error {
return removeMake(ctx, preper.cfg, preper.cfg.Runtime.CmdBuilder, preper.makeDeps, cmdArgs) return removeMake(ctx, preper.cfg, run.CmdBuilder, preper.makeDeps, cmdArgs)
} }
} }
func (preper *Preparer) Run(ctx context.Context, func (preper *Preparer) Run(ctx context.Context, run *runtime.Runtime,
w io.Writer, targets []map[string]*dep.InstallInfo, targets []map[string]*dep.InstallInfo,
) (pkgbuildDirsByBase map[string]string, err error) { ) (pkgbuildDirsByBase map[string]string, err error) {
preper.Present(w, targets) preper.Present(targets)
pkgBuildDirs, err := preper.PrepareWorkspace(ctx, targets) pkgBuildDirs, err := preper.PrepareWorkspace(ctx, run, targets)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -144,7 +148,7 @@ func (preper *Preparer) Run(ctx context.Context,
return pkgBuildDirs, nil return pkgBuildDirs, nil
} }
func (preper *Preparer) Present(w io.Writer, targets []map[string]*dep.InstallInfo) { func (preper *Preparer) Present(targets []map[string]*dep.InstallInfo) {
pkgsBySourceAndReason := map[string]map[string][]string{} pkgsBySourceAndReason := map[string]map[string][]string{}
for _, layer := range targets { for _, layer := range targets {
@@ -173,7 +177,7 @@ func (preper *Preparer) Present(w io.Writer, targets []map[string]*dep.InstallIn
for source, pkgsByReason := range pkgsBySourceAndReason { for source, pkgsByReason := range pkgsBySourceAndReason {
for reason, pkgs := range pkgsByReason { for reason, pkgs := range pkgsByReason {
fmt.Fprintf(w, text.Bold("%s %s (%d):")+" %s\n", preper.log.Printf(text.Bold("%s %s (%d):")+" %s\n",
source, source,
reason, reason,
len(pkgs), len(pkgs),
@@ -182,7 +186,9 @@ func (preper *Preparer) Present(w io.Writer, targets []map[string]*dep.InstallIn
} }
} }
func (preper *Preparer) PrepareWorkspace(ctx context.Context, targets []map[string]*dep.InstallInfo) (map[string]string, error) { func (preper *Preparer) PrepareWorkspace(ctx context.Context,
run *runtime.Runtime, targets []map[string]*dep.InstallInfo,
) (map[string]string, error) {
aurBasesToClone := mapset.NewThreadUnsafeSet[string]() aurBasesToClone := mapset.NewThreadUnsafeSet[string]()
pkgBuildDirsByBase := make(map[string]string, len(targets)) pkgBuildDirsByBase := make(map[string]string, len(targets))
@@ -203,7 +209,7 @@ func (preper *Preparer) PrepareWorkspace(ctx context.Context, targets []map[stri
} }
if _, errA := download.AURPKGBUILDRepos(ctx, if _, errA := download.AURPKGBUILDRepos(ctx,
preper.cmdBuilder, aurBasesToClone.ToSlice(), preper.cmdBuilder, preper.log.Child("download"), aurBasesToClone.ToSlice(),
preper.cfg.AURURL, preper.cfg.BuildDir, false); errA != nil { preper.cfg.AURURL, preper.cfg.BuildDir, false); errA != nil {
return nil, errA return nil, errA
} }
@@ -220,7 +226,7 @@ func (preper *Preparer) PrepareWorkspace(ctx context.Context, targets []map[stri
remoteNamesCache := mapset.NewThreadUnsafeSet(remoteNames...) remoteNamesCache := mapset.NewThreadUnsafeSet(remoteNames...)
for _, hookFn := range preper.hooks { for _, hookFn := range preper.hooks {
if hookFn.Type == PreDownloadSourcesHook { if hookFn.Type == PreDownloadSourcesHook {
if err := hookFn.Hookfn(ctx, preper.cfg, os.Stdout, pkgBuildDirsByBase, remoteNamesCache); err != nil { if err := hookFn.Hookfn(ctx, run, os.Stdout, pkgBuildDirsByBase, remoteNamesCache); err != nil {
return nil, err return nil, err
} }
} }
@@ -228,7 +234,7 @@ func (preper *Preparer) PrepareWorkspace(ctx context.Context, targets []map[stri
if errP := downloadPKGBUILDSourceFanout(ctx, preper.cmdBuilder, if errP := downloadPKGBUILDSourceFanout(ctx, preper.cmdBuilder,
pkgBuildDirsByBase, false, preper.cfg.MaxConcurrentDownloads); errP != nil { pkgBuildDirsByBase, false, preper.cfg.MaxConcurrentDownloads); errP != nil {
text.Errorln(errP) preper.log.Errorln(errP)
} }
return pkgBuildDirsByBase, nil return pkgBuildDirsByBase, nil
@@ -242,7 +248,7 @@ func (preper *Preparer) needToCloneAURBase(installInfo *dep.InstallInfo, pkgbuil
srcinfoFile := filepath.Join(pkgbuildDir, ".SRCINFO") srcinfoFile := filepath.Join(pkgbuildDir, ".SRCINFO")
if pkgbuild, err := gosrc.ParseFile(srcinfoFile); err == nil { if pkgbuild, err := gosrc.ParseFile(srcinfoFile); err == nil {
if db.VerCmp(pkgbuild.Version(), installInfo.Version) >= 0 { if db.VerCmp(pkgbuild.Version(), installInfo.Version) >= 0 {
text.OperationInfoln( preper.log.OperationInfoln(
gotext.Get("PKGBUILD up to date, skipping download: %s", gotext.Get("PKGBUILD up to date, skipping download: %s",
text.Cyan(*installInfo.AURBase))) text.Cyan(*installInfo.AURBase)))
return false return false

View File

@@ -1,16 +1,23 @@
//go:build !integration //go:build !integration
// +build !integration // +build !integration
package main package workdir
import ( import (
"io"
"strings"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/Jguer/yay/v12/pkg/settings" "github.com/Jguer/yay/v12/pkg/settings"
"github.com/Jguer/yay/v12/pkg/text"
) )
func newTestLogger() *text.Logger {
return text.NewLogger(io.Discard, io.Discard, strings.NewReader(""), true, "test")
}
// Test order of pre-download-sources hooks // Test order of pre-download-sources hooks
func TestPreDownloadSourcesHooks(t *testing.T) { func TestPreDownloadSourcesHooks(t *testing.T) {
testCases := []struct { testCases := []struct {
@@ -49,7 +56,7 @@ func TestPreDownloadSourcesHooks(t *testing.T) {
for _, tc := range testCases { for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
preper := NewPreparer(nil, nil, tc.cfg) preper := NewPreparer(nil, nil, tc.cfg, newTestLogger())
assert.Len(t, preper.hooks, len(tc.wantHook)) assert.Len(t, preper.hooks, len(tc.wantHook))

View File

@@ -3,14 +3,18 @@ package text
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"io" "strings"
"unicode"
"unicode/utf8"
"github.com/leonelquinteros/gotext"
) )
func (l *Logger) GetInput(defaultValue string, noConfirm bool) (string, error) { func (l *Logger) GetInput(defaultValue string, noConfirm bool) (string, error) {
Info() l.Info()
if defaultValue != "" || noConfirm { if defaultValue != "" || noConfirm {
fmt.Println(defaultValue) l.Println(defaultValue)
return defaultValue, nil return defaultValue, nil
} }
@@ -28,6 +32,48 @@ func (l *Logger) GetInput(defaultValue string, noConfirm bool) (string, error) {
return string(buf), nil return string(buf), nil
} }
func GetInput(r io.Reader, defaultValue string, noConfirm bool) (string, error) { // ContinueTask prompts if user wants to continue task.
return GlobalLogger.GetInput(defaultValue, noConfirm) // If NoConfirm is set the action will continue without user input.
func (l *Logger) ContinueTask(s string, preset, noConfirm bool) bool {
if noConfirm {
return preset
}
var (
response string
postFix string
n string
y string
yes = gotext.Get("yes")
no = gotext.Get("no")
)
// Only use localized "y" and "n" if they are latin characters.
if nRune, _ := utf8.DecodeRuneInString(no); unicode.Is(unicode.Latin, nRune) {
n = string(nRune)
} else {
n = nDefault
}
if yRune, _ := utf8.DecodeRuneInString(yes); unicode.Is(unicode.Latin, yRune) {
y = string(yRune)
} else {
y = yDefault
}
if preset { // If default behavior is true, use y as default.
postFix = fmt.Sprintf(" [%s/%s] ", strings.ToUpper(y), n)
} else { // If default behavior is anything else, use n as default.
postFix = fmt.Sprintf(" [%s/%s] ", y, strings.ToUpper(n))
}
l.OperationInfo(Bold(s), Bold(postFix))
if _, err := fmt.Fscanln(l.r, &response); err != nil {
return preset
}
return strings.EqualFold(response, yes) ||
strings.EqualFold(response, y) ||
(!strings.EqualFold(yDefault, n) && strings.EqualFold(response, yDefault))
} }

View File

@@ -1,139 +0,0 @@
package text
import (
"fmt"
"os"
"strconv"
"strings"
"syscall"
"unicode"
"github.com/leonelquinteros/gotext"
"golang.org/x/sys/unix"
)
const (
arrow = "==>"
smallArrow = " ->"
opSymbol = "::"
)
var (
cachedColumnCount = -1
GlobalLogger = NewLogger(os.Stdout, os.Stderr, os.Stdin, false, "global")
)
func Debugln(a ...interface{}) {
GlobalLogger.Debugln(a...)
}
func OperationInfoln(a ...interface{}) {
GlobalLogger.OperationInfoln(a...)
}
func OperationInfo(a ...interface{}) {
GlobalLogger.OperationInfo(a...)
}
func SprintOperationInfo(a ...interface{}) string {
return GlobalLogger.SprintOperationInfo(a...)
}
func Info(a ...interface{}) {
GlobalLogger.Info(a...)
}
func Infoln(a ...interface{}) {
GlobalLogger.Infoln(a...)
}
func SprintWarn(a ...interface{}) string {
return GlobalLogger.SprintWarn(a...)
}
func Warn(a ...interface{}) {
GlobalLogger.Warn(a...)
}
func Warnln(a ...interface{}) {
GlobalLogger.Warnln(a...)
}
func SprintError(a ...interface{}) string {
return GlobalLogger.SprintError(a...)
}
func Error(a ...interface{}) {
GlobalLogger.Error(a...)
}
func Errorln(a ...interface{}) {
GlobalLogger.Errorln(a...)
}
func getColumnCount() int {
if cachedColumnCount > 0 {
return cachedColumnCount
}
if count, err := strconv.Atoi(os.Getenv("COLUMNS")); err == nil {
cachedColumnCount = count
return cachedColumnCount
}
if ws, err := unix.IoctlGetWinsize(syscall.Stdout, unix.TIOCGWINSZ); err == nil {
cachedColumnCount = int(ws.Col)
return cachedColumnCount
}
return 80
}
func PrintInfoValue(key string, values ...string) {
const (
keyLength = 32
delimCount = 2
)
specialWordsCount := 0
for _, runeValue := range key {
// CJK handling: the character 'ー' is Katakana
// but if use unicode.Katakana, it will return false
if unicode.IsOneOf([]*unicode.RangeTable{
unicode.Han,
unicode.Hiragana,
unicode.Katakana,
unicode.Hangul,
}, runeValue) || runeValue == 'ー' {
specialWordsCount++
}
}
keyTextCount := specialWordsCount - keyLength + delimCount
str := fmt.Sprintf(Bold("%-*s: "), keyTextCount, key)
if len(values) == 0 || (len(values) == 1 && values[0] == "") {
fmt.Fprintf(os.Stdout, "%s%s\n", str, gotext.Get("None"))
return
}
maxCols := getColumnCount()
cols := keyLength + len(values[0])
str += values[0]
for _, value := range values[1:] {
if maxCols > keyLength && cols+len(value)+delimCount >= maxCols {
cols = keyLength
str += "\n" + strings.Repeat(" ", keyLength)
} else if cols != keyLength {
str += strings.Repeat(" ", delimCount)
cols += delimCount
}
str += value
cols += len(value)
}
fmt.Println(str)
}

View File

@@ -5,6 +5,12 @@ import (
"io" "io"
) )
const (
arrow = "==>"
smallArrow = " ->"
opSymbol = "::"
)
type Logger struct { type Logger struct {
name string name string
Debug bool Debug bool

View File

@@ -1,13 +1,8 @@
package text package text
import ( import (
"fmt"
"io"
"strings" "strings"
"unicode" "unicode"
"unicode/utf8"
"github.com/leonelquinteros/gotext"
) )
const ( const (
@@ -52,49 +47,3 @@ func LessRunes(iRunes, jRunes []rune) bool {
return len(iRunes) < len(jRunes) return len(iRunes) < len(jRunes)
} }
// ContinueTask prompts if user wants to continue task.
// If NoConfirm is set the action will continue without user input.
func ContinueTask(input io.Reader, s string, preset, noConfirm bool) bool {
if noConfirm {
return preset
}
var (
response string
postFix string
n string
y string
yes = gotext.Get("yes")
no = gotext.Get("no")
)
// Only use localized "y" and "n" if they are latin characters.
if nRune, _ := utf8.DecodeRuneInString(no); unicode.Is(unicode.Latin, nRune) {
n = string(nRune)
} else {
n = nDefault
}
if yRune, _ := utf8.DecodeRuneInString(yes); unicode.Is(unicode.Latin, yRune) {
y = string(yRune)
} else {
y = yDefault
}
if preset { // If default behavior is true, use y as default.
postFix = fmt.Sprintf(" [%s/%s] ", strings.ToUpper(y), n)
} else { // If default behavior is anything else, use n as default.
postFix = fmt.Sprintf(" [%s/%s] ", y, strings.ToUpper(n))
}
OperationInfo(Bold(s), Bold(postFix))
if _, err := fmt.Fscanln(input, &response); err != nil {
return preset
}
return strings.EqualFold(response, yes) ||
strings.EqualFold(response, y) ||
(!strings.EqualFold(yDefault, n) && strings.EqualFold(response, yDefault))
}

View File

@@ -4,6 +4,7 @@
package text package text
import ( import (
"io"
"os" "os"
"path" "path"
"strings" "strings"
@@ -74,7 +75,8 @@ func TestContinueTask(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
// create io.Reader with value of input // create io.Reader with value of input
in := strings.NewReader(tt.args.input) in := strings.NewReader(tt.args.input)
got := ContinueTask(in, tt.args.s, tt.args.preset, tt.args.noConfirm) logger := NewLogger(io.Discard, io.Discard, in, false, "test")
got := logger.ContinueTask(tt.args.s, tt.args.preset, tt.args.noConfirm)
require.Equal(t, tt.want, got) require.Equal(t, tt.want, got)
}) })
} }
@@ -120,7 +122,8 @@ msgstr "да"
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
in := strings.NewReader(tt.args.input) in := strings.NewReader(tt.args.input)
got := ContinueTask(in, tt.args.s, tt.args.preset, tt.args.noConfirm) logger := NewLogger(io.Discard, io.Discard, in, false, "test")
got := logger.ContinueTask(tt.args.s, tt.args.preset, tt.args.noConfirm)
require.Equal(t, tt.want, got) require.Equal(t, tt.want, got)
}) })
} }
@@ -168,7 +171,8 @@ msgstr "ja"
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
in := strings.NewReader(tt.args.input) in := strings.NewReader(tt.args.input)
got := ContinueTask(in, tt.args.s, tt.args.preset, tt.args.noConfirm) logger := NewLogger(io.Discard, io.Discard, in, false, "test")
got := logger.ContinueTask(tt.args.s, tt.args.preset, tt.args.noConfirm)
require.Equal(t, tt.want, got) require.Equal(t, tt.want, got)
}) })
} }

View File

@@ -7,7 +7,6 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt"
"io" "io"
"os" "os"
"os/exec" "os/exec"
@@ -24,6 +23,10 @@ import (
"github.com/Jguer/yay/v12/pkg/text" "github.com/Jguer/yay/v12/pkg/text"
) )
func newTestLogger() *text.Logger {
return text.NewLogger(io.Discard, io.Discard, strings.NewReader(""), true, "test")
}
func TestParsing(t *testing.T) { func TestParsing(t *testing.T) {
t.Parallel() t.Parallel()
type source struct { type source struct {
@@ -232,7 +235,7 @@ func TestInfoStoreToUpgrade(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
t.Parallel() t.Parallel()
v := &InfoStore{ v := &InfoStore{
logger: text.GlobalLogger, logger: newTestLogger(),
CmdBuilder: tt.fields.CmdBuilder, CmdBuilder: tt.fields.CmdBuilder,
OriginsByPackage: map[string]OriginInfoByURL{ OriginsByPackage: map[string]OriginInfoByURL{
"yay": tt.args.infos, "yay": tt.args.infos,
@@ -365,7 +368,7 @@ func TestInfoStore_NeedsUpdate(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
t.Parallel() t.Parallel()
v := &InfoStore{ v := &InfoStore{
logger: text.GlobalLogger, logger: newTestLogger(),
CmdBuilder: tt.fields.CmdBuilder, CmdBuilder: tt.fields.CmdBuilder,
} }
got := v.needsUpdate(context.Background(), tt.args.infos) got := v.needsUpdate(context.Background(), tt.args.infos)
@@ -415,7 +418,7 @@ func TestInfoStore_Update(t *testing.T) {
t.Parallel() t.Parallel()
v := &InfoStore{ v := &InfoStore{
OriginsByPackage: tt.fields.OriginsByPackage, OriginsByPackage: tt.fields.OriginsByPackage,
logger: text.GlobalLogger, logger: newTestLogger(),
FilePath: filePath, FilePath: filePath,
CmdBuilder: tt.fields.CmdBuilder, CmdBuilder: tt.fields.CmdBuilder,
} }
@@ -429,7 +432,6 @@ func TestInfoStore_Update(t *testing.T) {
cupaloy.SnapshotT(t, marshalledinfo) cupaloy.SnapshotT(t, marshalledinfo)
v.Load() v.Load()
fmt.Println(v.OriginsByPackage)
assert.Len(t, tt.fields.OriginsByPackage, 1) assert.Len(t, tt.fields.OriginsByPackage, 1)
marshalledinfo, err = json.MarshalIndent(tt.fields.OriginsByPackage, "", "\t") marshalledinfo, err = json.MarshalIndent(tt.fields.OriginsByPackage, "", "\t")
@@ -479,7 +481,7 @@ func TestInfoStore_Remove(t *testing.T) {
t.Parallel() t.Parallel()
v := &InfoStore{ v := &InfoStore{
OriginsByPackage: tt.fields.OriginsByPackage, OriginsByPackage: tt.fields.OriginsByPackage,
logger: text.GlobalLogger, logger: newTestLogger(),
FilePath: filePath, FilePath: filePath,
} }
v.RemovePackages(tt.args.pkgs) v.RemovePackages(tt.args.pkgs)

184
print.go
View File

@@ -6,14 +6,19 @@ import (
"io" "io"
"os" "os"
"strconv" "strconv"
"strings"
"syscall"
"unicode"
aur "github.com/Jguer/aur" aur "github.com/Jguer/aur"
mapset "github.com/deckarep/golang-set/v2" mapset "github.com/deckarep/golang-set/v2"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"golang.org/x/sys/unix"
"github.com/Jguer/yay/v12/pkg/db" "github.com/Jguer/yay/v12/pkg/db"
"github.com/Jguer/yay/v12/pkg/dep" "github.com/Jguer/yay/v12/pkg/dep"
"github.com/Jguer/yay/v12/pkg/query" "github.com/Jguer/yay/v12/pkg/query"
"github.com/Jguer/yay/v12/pkg/runtime"
"github.com/Jguer/yay/v12/pkg/settings" "github.com/Jguer/yay/v12/pkg/settings"
"github.com/Jguer/yay/v12/pkg/settings/parser" "github.com/Jguer/yay/v12/pkg/settings/parser"
"github.com/Jguer/yay/v12/pkg/text" "github.com/Jguer/yay/v12/pkg/text"
@@ -21,47 +26,47 @@ import (
) )
// printInfo prints package info like pacman -Si. // printInfo prints package info like pacman -Si.
func printInfo(config *settings.Configuration, a *aur.Pkg, extendedInfo bool) { func printInfo(logger *text.Logger, config *settings.Configuration, a *aur.Pkg, extendedInfo bool) {
text.PrintInfoValue(gotext.Get("Repository"), "aur") printInfoValue(logger, gotext.Get("Repository"), "aur")
text.PrintInfoValue(gotext.Get("Name"), a.Name) printInfoValue(logger, gotext.Get("Name"), a.Name)
text.PrintInfoValue(gotext.Get("Version"), a.Version) printInfoValue(logger, gotext.Get("Version"), a.Version)
text.PrintInfoValue(gotext.Get("Description"), a.Description) printInfoValue(logger, gotext.Get("Description"), a.Description)
text.PrintInfoValue(gotext.Get("URL"), a.URL) printInfoValue(logger, gotext.Get("URL"), a.URL)
text.PrintInfoValue(gotext.Get("Licenses"), a.License...) printInfoValue(logger, gotext.Get("Licenses"), a.License...)
text.PrintInfoValue(gotext.Get("Groups"), a.Groups...) printInfoValue(logger, gotext.Get("Groups"), a.Groups...)
text.PrintInfoValue(gotext.Get("Provides"), a.Provides...) printInfoValue(logger, gotext.Get("Provides"), a.Provides...)
text.PrintInfoValue(gotext.Get("Depends On"), a.Depends...) printInfoValue(logger, gotext.Get("Depends On"), a.Depends...)
text.PrintInfoValue(gotext.Get("Optional Deps"), a.OptDepends...) printInfoValue(logger, gotext.Get("Optional Deps"), a.OptDepends...)
text.PrintInfoValue(gotext.Get("Make Deps"), a.MakeDepends...) printInfoValue(logger, gotext.Get("Make Deps"), a.MakeDepends...)
text.PrintInfoValue(gotext.Get("Check Deps"), a.CheckDepends...) printInfoValue(logger, gotext.Get("Check Deps"), a.CheckDepends...)
text.PrintInfoValue(gotext.Get("Conflicts With"), a.Conflicts...) printInfoValue(logger, gotext.Get("Conflicts With"), a.Conflicts...)
text.PrintInfoValue(gotext.Get("Replaces"), a.Replaces...) printInfoValue(logger, gotext.Get("Replaces"), a.Replaces...)
text.PrintInfoValue(gotext.Get("AUR URL"), config.AURURL+"/packages/"+a.Name) printInfoValue(logger, gotext.Get("AUR URL"), config.AURURL+"/packages/"+a.Name)
text.PrintInfoValue(gotext.Get("First Submitted"), text.FormatTimeQuery(a.FirstSubmitted)) printInfoValue(logger, gotext.Get("First Submitted"), text.FormatTimeQuery(a.FirstSubmitted))
text.PrintInfoValue(gotext.Get("Keywords"), a.Keywords...) printInfoValue(logger, gotext.Get("Keywords"), a.Keywords...)
text.PrintInfoValue(gotext.Get("Last Modified"), text.FormatTimeQuery(a.LastModified)) printInfoValue(logger, gotext.Get("Last Modified"), text.FormatTimeQuery(a.LastModified))
text.PrintInfoValue(gotext.Get("Maintainer"), a.Maintainer) printInfoValue(logger, gotext.Get("Maintainer"), a.Maintainer)
text.PrintInfoValue(gotext.Get("Popularity"), fmt.Sprintf("%f", a.Popularity)) printInfoValue(logger, gotext.Get("Popularity"), fmt.Sprintf("%f", a.Popularity))
text.PrintInfoValue(gotext.Get("Votes"), fmt.Sprintf("%d", a.NumVotes)) printInfoValue(logger, gotext.Get("Votes"), fmt.Sprintf("%d", a.NumVotes))
if a.OutOfDate != 0 { if a.OutOfDate != 0 {
text.PrintInfoValue(gotext.Get("Out-of-date"), text.FormatTimeQuery(a.OutOfDate)) printInfoValue(logger, gotext.Get("Out-of-date"), text.FormatTimeQuery(a.OutOfDate))
} else { } else {
text.PrintInfoValue(gotext.Get("Out-of-date"), "No") printInfoValue(logger, gotext.Get("Out-of-date"), "No")
} }
if extendedInfo { if extendedInfo {
text.PrintInfoValue("ID", fmt.Sprintf("%d", a.ID)) printInfoValue(logger, "ID", fmt.Sprintf("%d", a.ID))
text.PrintInfoValue(gotext.Get("Package Base ID"), fmt.Sprintf("%d", a.PackageBaseID)) printInfoValue(logger, gotext.Get("Package Base ID"), fmt.Sprintf("%d", a.PackageBaseID))
text.PrintInfoValue(gotext.Get("Package Base"), a.PackageBase) printInfoValue(logger, gotext.Get("Package Base"), a.PackageBase)
text.PrintInfoValue(gotext.Get("Snapshot URL"), config.AURURL+a.URLPath) printInfoValue(logger, gotext.Get("Snapshot URL"), config.AURURL+a.URLPath)
} }
fmt.Println() logger.Println()
} }
// BiggestPackages prints the name of the ten biggest packages in the system. // BiggestPackages prints the name of the ten biggest packages in the system.
func biggestPackages(dbExecutor db.Executor) { func biggestPackages(logger *text.Logger, dbExecutor db.Executor) {
pkgS := dbExecutor.BiggestPackages() pkgS := dbExecutor.BiggestPackages()
if len(pkgS) < 10 { if len(pkgS) < 10 {
@@ -69,34 +74,34 @@ func biggestPackages(dbExecutor db.Executor) {
} }
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
fmt.Printf("%s: %s\n", text.Bold(pkgS[i].Name()), text.Cyan(text.Human(pkgS[i].ISize()))) logger.Printf("%s: %s\n", text.Bold(pkgS[i].Name()), text.Cyan(text.Human(pkgS[i].ISize())))
} }
} }
// localStatistics prints installed packages statistics. // localStatistics prints installed packages statistics.
func localStatistics(ctx context.Context, cfg *settings.Configuration, dbExecutor db.Executor) error { func localStatistics(ctx context.Context, run *runtime.Runtime, dbExecutor db.Executor) error {
info := statistics(cfg, dbExecutor) info := statistics(run, dbExecutor)
remoteNames := dbExecutor.InstalledRemotePackageNames() remoteNames := dbExecutor.InstalledRemotePackageNames()
remote := dbExecutor.InstalledRemotePackages() remote := dbExecutor.InstalledRemotePackages()
text.Infoln(gotext.Get("Yay version v%s", yayVersion)) run.Logger.Infoln(gotext.Get("Yay version v%s", yayVersion))
fmt.Println(text.Bold(text.Cyan("==========================================="))) run.Logger.Println(text.Bold(text.Cyan("===========================================")))
text.Infoln(gotext.Get("Total installed packages: %s", text.Cyan(strconv.Itoa(info.Totaln)))) run.Logger.Infoln(gotext.Get("Total installed packages: %s", text.Cyan(strconv.Itoa(info.Totaln))))
text.Infoln(gotext.Get("Foreign installed packages: %s", text.Cyan(strconv.Itoa(len(remoteNames))))) run.Logger.Infoln(gotext.Get("Foreign installed packages: %s", text.Cyan(strconv.Itoa(len(remoteNames)))))
text.Infoln(gotext.Get("Explicitly installed packages: %s", text.Cyan(strconv.Itoa(info.Expln)))) run.Logger.Infoln(gotext.Get("Explicitly installed packages: %s", text.Cyan(strconv.Itoa(info.Expln))))
text.Infoln(gotext.Get("Total Size occupied by packages: %s", text.Cyan(text.Human(info.TotalSize)))) run.Logger.Infoln(gotext.Get("Total Size occupied by packages: %s", text.Cyan(text.Human(info.TotalSize))))
for path, size := range info.pacmanCaches { for path, size := range info.pacmanCaches {
text.Infoln(gotext.Get("Size of pacman cache %s: %s", path, text.Cyan(text.Human(size)))) run.Logger.Infoln(gotext.Get("Size of pacman cache %s: %s", path, text.Cyan(text.Human(size))))
} }
text.Infoln(gotext.Get("Size of yay cache %s: %s", cfg.BuildDir, text.Cyan(text.Human(info.yayCache)))) run.Logger.Infoln(gotext.Get("Size of yay cache %s: %s", run.Cfg.BuildDir, text.Cyan(text.Human(info.yayCache))))
fmt.Println(text.Bold(text.Cyan("==========================================="))) run.Logger.Println(text.Bold(text.Cyan("===========================================")))
text.Infoln(gotext.Get("Ten biggest packages:")) run.Logger.Infoln(gotext.Get("Ten biggest packages:"))
biggestPackages(dbExecutor) biggestPackages(run.Logger, dbExecutor)
fmt.Println(text.Bold(text.Cyan("==========================================="))) run.Logger.Println(text.Bold(text.Cyan("===========================================")))
aurData, err := cfg.Runtime.AURClient.Get(ctx, &aur.Query{ aurData, err := run.AURClient.Get(ctx, &aur.Query{
Needles: remoteNames, Needles: remoteNames,
By: aur.Name, By: aur.Name,
}) })
@@ -104,7 +109,7 @@ func localStatistics(ctx context.Context, cfg *settings.Configuration, dbExecuto
return err return err
} }
warnings := query.NewWarnings(cfg.Runtime.Logger.Child("print")) warnings := query.NewWarnings(run.Logger.Child("warnings"))
for i := range aurData { for i := range aurData {
warnings.AddToWarnings(remote, &aurData[i]) warnings.AddToWarnings(remote, &aurData[i])
} }
@@ -114,13 +119,13 @@ func localStatistics(ctx context.Context, cfg *settings.Configuration, dbExecuto
return nil return nil
} }
func printUpdateList(ctx context.Context, cfg *settings.Configuration, cmdArgs *parser.Arguments, func printUpdateList(ctx context.Context, run *runtime.Runtime, cmdArgs *parser.Arguments,
dbExecutor db.Executor, enableDowngrade bool, filter upgrade.Filter, dbExecutor db.Executor, enableDowngrade bool, filter upgrade.Filter,
) error { ) error {
quietMode := cmdArgs.ExistsArg("q", "quiet") quietMode := cmdArgs.ExistsArg("q", "quiet")
// TODO: handle quiet mode in a better way // TODO: handle quiet mode in a better way
logger := text.NewLogger(io.Discard, os.Stderr, os.Stdin, cfg.Debug, "update-list") logger := text.NewLogger(io.Discard, os.Stderr, os.Stdin, run.Cfg.Debug, "update-list")
dbExecutor.SetLogger(logger.Child("db")) dbExecutor.SetLogger(logger.Child("db"))
oldNoConfirm := settings.NoConfirm oldNoConfirm := settings.NoConfirm
settings.NoConfirm = true settings.NoConfirm = true
@@ -128,12 +133,12 @@ func printUpdateList(ctx context.Context, cfg *settings.Configuration, cmdArgs *
defer func() { settings.NoConfirm = oldNoConfirm }() defer func() { settings.NoConfirm = oldNoConfirm }()
targets := mapset.NewThreadUnsafeSet(cmdArgs.Targets...) targets := mapset.NewThreadUnsafeSet(cmdArgs.Targets...)
grapher := dep.NewGrapher(dbExecutor, cfg.Runtime.AURClient, false, true, grapher := dep.NewGrapher(dbExecutor, run.AURClient, false, true,
false, false, cmdArgs.ExistsArg("needed"), logger.Child("grapher")) false, false, cmdArgs.ExistsArg("needed"), logger.Child("grapher"))
upService := upgrade.NewUpgradeService( upService := upgrade.NewUpgradeService(
grapher, cfg.Runtime.AURClient, dbExecutor, cfg.Runtime.VCSStore, grapher, run.AURClient, dbExecutor, run.VCSStore,
cfg, true, logger.Child("upgrade")) run.Cfg, true, logger.Child("upgrade"))
graph, errSysUp := upService.GraphUpgrades(ctx, nil, graph, errSysUp := upService.GraphUpgrades(ctx, nil,
enableDowngrade, filter) enableDowngrade, filter)
@@ -163,9 +168,9 @@ func printUpdateList(ctx context.Context, cfg *settings.Configuration, cmdArgs *
} }
if quietMode { if quietMode {
fmt.Printf("%s\n", pkgName) run.Logger.Printf("%s\n", pkgName)
} else { } else {
fmt.Printf("%s %s -> %s\n", text.Bold(pkgName), text.Bold(text.Green(ii.LocalVersion)), run.Logger.Printf("%s %s -> %s\n", text.Bold(pkgName), text.Bold(text.Green(ii.LocalVersion)),
text.Bold(text.Green(ii.Version))) text.Bold(text.Green(ii.Version)))
} }
@@ -179,7 +184,7 @@ func printUpdateList(ctx context.Context, cfg *settings.Configuration, cmdArgs *
missing := false missing := false
targets.Each(func(pkgName string) bool { targets.Each(func(pkgName string) bool {
if dbExecutor.LocalPackage(pkgName) == nil { if dbExecutor.LocalPackage(pkgName) == nil {
cfg.Runtime.Logger.Errorln(gotext.Get("package '%s' was not found", pkgName)) run.Logger.Errorln(gotext.Get("package '%s' was not found", pkgName))
missing = true missing = true
} }
return false return false
@@ -191,3 +196,72 @@ func printUpdateList(ctx context.Context, cfg *settings.Configuration, cmdArgs *
return nil return nil
} }
func printInfoValue(logger *text.Logger, key string, values ...string) {
const (
keyLength = 32
delimCount = 2
)
specialWordsCount := 0
for _, runeValue := range key {
// CJK handling: the character 'ー' is Katakana
// but if use unicode.Katakana, it will return false
if unicode.IsOneOf([]*unicode.RangeTable{
unicode.Han,
unicode.Hiragana,
unicode.Katakana,
unicode.Hangul,
}, runeValue) || runeValue == 'ー' {
specialWordsCount++
}
}
keyTextCount := specialWordsCount - keyLength + delimCount
str := fmt.Sprintf(text.Bold("%-*s: "), keyTextCount, key)
if len(values) == 0 || (len(values) == 1 && values[0] == "") {
logger.Printf("%s%s\n", str, gotext.Get("None"))
return
}
maxCols := getColumnCount()
cols := keyLength + len(values[0])
str += values[0]
for _, value := range values[1:] {
if maxCols > keyLength && cols+len(value)+delimCount >= maxCols {
cols = keyLength
str += "\n" + strings.Repeat(" ", keyLength)
} else if cols != keyLength {
str += strings.Repeat(" ", delimCount)
cols += delimCount
}
str += value
cols += len(value)
}
logger.Println(str)
}
var cachedColumnCount = -1
func getColumnCount() int {
if cachedColumnCount > 0 {
return cachedColumnCount
}
if count, err := strconv.Atoi(os.Getenv("COLUMNS")); err == nil {
cachedColumnCount = count
return cachedColumnCount
}
if ws, err := unix.IoctlGetWinsize(syscall.Stdout, unix.TIOCGWINSZ); err == nil {
cachedColumnCount = int(ws.Col)
return cachedColumnCount
}
return 80
}

View File

@@ -20,6 +20,7 @@ import (
"github.com/Jguer/yay/v12/pkg/db" "github.com/Jguer/yay/v12/pkg/db"
"github.com/Jguer/yay/v12/pkg/db/mock" "github.com/Jguer/yay/v12/pkg/db/mock"
mockaur "github.com/Jguer/yay/v12/pkg/dep/mock" mockaur "github.com/Jguer/yay/v12/pkg/dep/mock"
"github.com/Jguer/yay/v12/pkg/runtime"
"github.com/Jguer/yay/v12/pkg/settings" "github.com/Jguer/yay/v12/pkg/settings"
"github.com/Jguer/yay/v12/pkg/settings/exe" "github.com/Jguer/yay/v12/pkg/settings/exe"
"github.com/Jguer/yay/v12/pkg/settings/parser" "github.com/Jguer/yay/v12/pkg/settings/parser"
@@ -271,29 +272,28 @@ func TestPrintUpdateList(t *testing.T) {
SudoLoopEnabled: false, SudoLoopEnabled: false,
} }
cfg := &settings.Configuration{ r, w, _ := os.Pipe()
RemoveMake: "no",
Runtime: &settings.Runtime{ logger := text.NewLogger(w, io.Discard, strings.NewReader(""), true, "test")
Logger: NewTestLogger(),
CmdBuilder: cmdBuilder, run := &runtime.Runtime{
VCSStore: &vcs.Mock{}, Cfg: &settings.Configuration{
AURClient: tc.mockData.aurCache, RemoveMake: "no",
}, },
Logger: logger,
CmdBuilder: cmdBuilder,
VCSStore: &vcs.Mock{},
AURClient: tc.mockData.aurCache,
} }
cmdArgs := parser.MakeArguments() cmdArgs := parser.MakeArguments()
cmdArgs.AddArg(tc.args...) cmdArgs.AddArg(tc.args...)
cmdArgs.AddTarget(tc.targets...) cmdArgs.AddTarget(tc.targets...)
rescueStdout := os.Stdout err = handleCmd(context.Background(), run, cmdArgs, tc.mockData.db)
r, w, _ := os.Pipe()
os.Stdout = w
err = handleCmd(context.Background(), cfg, cmdArgs, tc.mockData.db)
w.Close() w.Close()
out, _ := io.ReadAll(r) out, _ := io.ReadAll(r)
os.Stdout = rescueStdout
if tc.wantErr { if tc.wantErr {
require.Error(t, err) require.Error(t, err)

View File

@@ -12,6 +12,7 @@ import (
"github.com/Jguer/yay/v12/pkg/db" "github.com/Jguer/yay/v12/pkg/db"
"github.com/Jguer/yay/v12/pkg/query" "github.com/Jguer/yay/v12/pkg/query"
"github.com/Jguer/yay/v12/pkg/runtime"
"github.com/Jguer/yay/v12/pkg/settings" "github.com/Jguer/yay/v12/pkg/settings"
"github.com/Jguer/yay/v12/pkg/settings/parser" "github.com/Jguer/yay/v12/pkg/settings/parser"
"github.com/Jguer/yay/v12/pkg/text" "github.com/Jguer/yay/v12/pkg/text"
@@ -32,7 +33,7 @@ func syncSearch(ctx context.Context, pkgS []string,
} }
// SyncInfo serves as a pacman -Si for repo packages and AUR packages. // SyncInfo serves as a pacman -Si for repo packages and AUR packages.
func syncInfo(ctx context.Context, cfg *settings.Configuration, func syncInfo(ctx context.Context, run *runtime.Runtime,
cmdArgs *parser.Arguments, pkgS []string, dbExecutor db.Executor, cmdArgs *parser.Arguments, pkgS []string, dbExecutor db.Executor,
) error { ) error {
var ( var (
@@ -41,8 +42,8 @@ func syncInfo(ctx context.Context, cfg *settings.Configuration,
missing = false missing = false
) )
pkgS = query.RemoveInvalidTargets(pkgS, cfg.Mode) pkgS = query.RemoveInvalidTargets(run.Logger, pkgS, run.Cfg.Mode)
aurS, repoS := packageSlices(pkgS, cfg, dbExecutor) aurS, repoS := packageSlices(pkgS, run.Cfg, dbExecutor)
if len(aurS) != 0 { if len(aurS) != 0 {
noDB := make([]string, 0, len(aurS)) noDB := make([]string, 0, len(aurS))
@@ -52,14 +53,14 @@ func syncInfo(ctx context.Context, cfg *settings.Configuration,
noDB = append(noDB, name) noDB = append(noDB, name)
} }
info, err = cfg.Runtime.AURClient.Get(ctx, &aur.Query{ info, err = run.AURClient.Get(ctx, &aur.Query{
Needles: noDB, Needles: noDB,
By: aur.Name, By: aur.Name,
}) })
if err != nil { if err != nil {
missing = true missing = true
cfg.Runtime.Logger.Errorln(err) run.Logger.Errorln(err)
} }
} }
@@ -68,8 +69,8 @@ func syncInfo(ctx context.Context, cfg *settings.Configuration,
arguments.ClearTargets() arguments.ClearTargets()
arguments.AddTarget(repoS...) arguments.AddTarget(repoS...)
err = cfg.Runtime.CmdBuilder.Show(cfg.Runtime.CmdBuilder.BuildPacmanCmd(ctx, err = run.CmdBuilder.Show(run.CmdBuilder.BuildPacmanCmd(ctx,
arguments, cfg.Mode, settings.NoConfirm)) arguments, run.Cfg.Mode, settings.NoConfirm))
if err != nil { if err != nil {
return err return err
} }
@@ -81,7 +82,7 @@ func syncInfo(ctx context.Context, cfg *settings.Configuration,
if len(info) != 0 { if len(info) != 0 {
for i := range info { for i := range info {
printInfo(cfg, &info[i], cmdArgs.ExistsDouble("i")) printInfo(run.Logger, run.Cfg, &info[i], cmdArgs.ExistsDouble("i"))
} }
} }
@@ -220,7 +221,7 @@ func getFolderSize(path string) (size int64) {
} }
// Statistics returns statistics about packages installed in system. // Statistics returns statistics about packages installed in system.
func statistics(cfg *settings.Configuration, dbExecutor db.Executor) (res struct { func statistics(run *runtime.Runtime, dbExecutor db.Executor) (res struct {
Totaln int Totaln int
Expln int Expln int
TotalSize int64 TotalSize int64
@@ -238,11 +239,11 @@ func statistics(cfg *settings.Configuration, dbExecutor db.Executor) (res struct
} }
res.pacmanCaches = make(map[string]int64) res.pacmanCaches = make(map[string]int64)
for _, path := range cfg.Runtime.PacmanConf.CacheDir { for _, path := range run.PacmanConf.CacheDir {
res.pacmanCaches[path] = getFolderSize(path) res.pacmanCaches[path] = getFolderSize(path)
} }
res.yayCache = getFolderSize(cfg.BuildDir) res.yayCache = getFolderSize(run.Cfg.BuildDir)
return return
} }

View File

@@ -16,6 +16,7 @@ import (
"github.com/Jguer/yay/v12/pkg/db/mock" "github.com/Jguer/yay/v12/pkg/db/mock"
mockaur "github.com/Jguer/yay/v12/pkg/dep/mock" mockaur "github.com/Jguer/yay/v12/pkg/dep/mock"
"github.com/Jguer/yay/v12/pkg/query" "github.com/Jguer/yay/v12/pkg/query"
"github.com/Jguer/yay/v12/pkg/runtime"
"github.com/Jguer/yay/v12/pkg/settings" "github.com/Jguer/yay/v12/pkg/settings"
"github.com/Jguer/yay/v12/pkg/settings/exe" "github.com/Jguer/yay/v12/pkg/settings/exe"
"github.com/Jguer/yay/v12/pkg/settings/parser" "github.com/Jguer/yay/v12/pkg/settings/parser"
@@ -125,12 +126,12 @@ func TestSyncInfo(t *testing.T) {
Runner: mockRunner, Runner: mockRunner,
SudoLoopEnabled: false, SudoLoopEnabled: false,
} }
cfg := &settings.Configuration{
Runtime: &settings.Runtime{ run := &runtime.Runtime{
CmdBuilder: cmdBuilder, CmdBuilder: cmdBuilder,
AURClient: mockAUR, AURClient: mockAUR,
Logger: NewTestLogger(), Logger: newTestLogger(),
}, Cfg: &settings.Configuration{},
} }
cmdArgs := parser.MakeArguments() cmdArgs := parser.MakeArguments()
@@ -138,7 +139,7 @@ func TestSyncInfo(t *testing.T) {
cmdArgs.AddTarget(tc.targets...) cmdArgs.AddTarget(tc.targets...)
err := handleCmd(context.Background(), err := handleCmd(context.Background(),
cfg, cmdArgs, dbExc, run, cmdArgs, dbExc,
) )
if tc.wantErr { if tc.wantErr {
@@ -266,14 +267,14 @@ func TestSyncSearchAURDB(t *testing.T) {
Runner: mockRunner, Runner: mockRunner,
SudoLoopEnabled: false, SudoLoopEnabled: false,
} }
cfg := &settings.Configuration{
Runtime: &settings.Runtime{ run := &runtime.Runtime{
CmdBuilder: cmdBuilder, CmdBuilder: cmdBuilder,
AURClient: mockAUR, AURClient: mockAUR,
QueryBuilder: query.NewSourceQueryBuilder(mockAUR, NewTestLogger(), "votes", parser.ModeAny, "name", QueryBuilder: query.NewSourceQueryBuilder(mockAUR, newTestLogger(), "votes", parser.ModeAny, "name",
tc.bottomUp, tc.singleLine, tc.mixed), tc.bottomUp, tc.singleLine, tc.mixed),
Logger: NewTestLogger(), Logger: newTestLogger(),
}, Cfg: &settings.Configuration{},
} }
cmdArgs := parser.MakeArguments() cmdArgs := parser.MakeArguments()
@@ -281,7 +282,7 @@ func TestSyncSearchAURDB(t *testing.T) {
cmdArgs.AddTarget(tc.targets...) cmdArgs.AddTarget(tc.targets...)
err := handleCmd(context.Background(), err := handleCmd(context.Background(),
cfg, cmdArgs, dbExc, run, cmdArgs, dbExc,
) )
if tc.wantErr { if tc.wantErr {

155
sync.go
View File

@@ -3,37 +3,36 @@ package main
import ( import (
"context" "context"
"fmt" "fmt"
"os"
"strings" "strings"
"github.com/Jguer/yay/v12/pkg/completion" "github.com/leonelquinteros/gotext"
"github.com/Jguer/yay/v12/pkg/db" "github.com/Jguer/yay/v12/pkg/db"
"github.com/Jguer/yay/v12/pkg/dep" "github.com/Jguer/yay/v12/pkg/dep"
"github.com/Jguer/yay/v12/pkg/multierror" "github.com/Jguer/yay/v12/pkg/multierror"
"github.com/Jguer/yay/v12/pkg/runtime"
"github.com/Jguer/yay/v12/pkg/settings" "github.com/Jguer/yay/v12/pkg/settings"
"github.com/Jguer/yay/v12/pkg/settings/exe"
"github.com/Jguer/yay/v12/pkg/settings/parser" "github.com/Jguer/yay/v12/pkg/settings/parser"
"github.com/Jguer/yay/v12/pkg/srcinfo" "github.com/Jguer/yay/v12/pkg/sync"
"github.com/Jguer/yay/v12/pkg/text"
"github.com/Jguer/yay/v12/pkg/upgrade" "github.com/Jguer/yay/v12/pkg/upgrade"
"github.com/leonelquinteros/gotext"
) )
func syncInstall(ctx context.Context, func syncInstall(ctx context.Context,
cfg *settings.Configuration, run *runtime.Runtime,
cmdArgs *parser.Arguments, cmdArgs *parser.Arguments,
dbExecutor db.Executor, dbExecutor db.Executor,
) error { ) error {
aurCache := cfg.Runtime.AURClient aurCache := run.AURClient
refreshArg := cmdArgs.ExistsArg("y", "refresh") refreshArg := cmdArgs.ExistsArg("y", "refresh")
noDeps := cmdArgs.ExistsArg("d", "nodeps") noDeps := cmdArgs.ExistsArg("d", "nodeps")
noCheck := strings.Contains(cfg.MFlags, "--nocheck") noCheck := strings.Contains(run.Cfg.MFlags, "--nocheck")
if noDeps { if noDeps {
cfg.Runtime.CmdBuilder.AddMakepkgFlag("-d") run.CmdBuilder.AddMakepkgFlag("-d")
} }
if refreshArg && cfg.Mode.AtLeastRepo() { if refreshArg && run.Cfg.Mode.AtLeastRepo() {
if errR := earlyRefresh(ctx, cfg, cfg.Runtime.CmdBuilder, cmdArgs); errR != nil { if errR := earlyRefresh(ctx, run.Cfg, run.CmdBuilder, cmdArgs); errR != nil {
return fmt.Errorf("%s - %w", gotext.Get("error refreshing databases"), errR) return fmt.Errorf("%s - %w", gotext.Get("error refreshing databases"), errR)
} }
@@ -45,7 +44,7 @@ func syncInstall(ctx context.Context,
} }
grapher := dep.NewGrapher(dbExecutor, aurCache, false, settings.NoConfirm, grapher := dep.NewGrapher(dbExecutor, aurCache, false, settings.NoConfirm,
noDeps, noCheck, cmdArgs.ExistsArg("needed"), cfg.Runtime.Logger.Child("grapher")) noDeps, noCheck, cmdArgs.ExistsArg("needed"), run.Logger.Child("grapher"))
graph, err := grapher.GraphFromTargets(ctx, nil, cmdArgs.Targets) graph, err := grapher.GraphFromTargets(ctx, nil, cmdArgs.Targets)
if err != nil { if err != nil {
@@ -57,8 +56,8 @@ func syncInstall(ctx context.Context,
var errSysUp error var errSysUp error
upService := upgrade.NewUpgradeService( upService := upgrade.NewUpgradeService(
grapher, aurCache, dbExecutor, cfg.Runtime.VCSStore, grapher, aurCache, dbExecutor, run.VCSStore,
cfg, settings.NoConfirm, cfg.Runtime.Logger.Child("upgrade")) run.Cfg, settings.NoConfirm, run.Logger.Child("upgrade"))
graph, errSysUp = upService.GraphUpgrades(ctx, graph, errSysUp = upService.GraphUpgrades(ctx,
graph, cmdArgs.ExistsDouble("u", "sysupgrade"), graph, cmdArgs.ExistsDouble("u", "sysupgrade"),
@@ -75,7 +74,7 @@ func syncInstall(ctx context.Context,
} }
} }
opService := NewOperationService(ctx, cfg, dbExecutor) opService := sync.NewOperationService(ctx, dbExecutor, run)
multiErr := &multierror.MultiError{} multiErr := &multierror.MultiError{}
targets := graph.TopoSortedLayerMap(func(s string, ii *dep.InstallInfo) error { targets := graph.TopoSortedLayerMap(func(s string, ii *dep.InstallInfo) error {
if ii.Source == dep.Missing { if ii.Source == dep.Missing {
@@ -88,117 +87,19 @@ func syncInstall(ctx context.Context,
return err return err
} }
return opService.Run(ctx, cmdArgs, targets, excluded) return opService.Run(ctx, run, cmdArgs, targets, excluded)
} }
type OperationService struct { func earlyRefresh(ctx context.Context, cfg *settings.Configuration, cmdBuilder exe.ICmdBuilder, cmdArgs *parser.Arguments) error {
ctx context.Context arguments := cmdArgs.Copy()
cfg *settings.Configuration if cfg.CombinedUpgrade {
dbExecutor db.Executor arguments.DelArg("u", "sysupgrade")
} }
arguments.DelArg("s", "search")
func NewOperationService(ctx context.Context, cfg *settings.Configuration, dbExecutor db.Executor) *OperationService { arguments.DelArg("i", "info")
return &OperationService{ arguments.DelArg("l", "list")
ctx: ctx, arguments.ClearTargets()
cfg: cfg,
dbExecutor: dbExecutor, return cmdBuilder.Show(cmdBuilder.BuildPacmanCmd(ctx,
} arguments, cfg.Mode, settings.NoConfirm))
}
func (o *OperationService) Run(ctx context.Context,
cmdArgs *parser.Arguments,
targets []map[string]*dep.InstallInfo, excluded []string,
) error {
if len(targets) == 0 {
fmt.Fprintln(os.Stdout, "", gotext.Get("there is nothing to do"))
return nil
}
preparer := NewPreparer(o.dbExecutor, o.cfg.Runtime.CmdBuilder, o.cfg)
installer := NewInstaller(o.dbExecutor, o.cfg.Runtime.CmdBuilder,
o.cfg.Runtime.VCSStore, o.cfg.Mode, o.cfg.ReBuild,
cmdArgs.ExistsArg("w", "downloadonly"), o.cfg.Runtime.Logger.Child("installer"))
pkgBuildDirs, errInstall := preparer.Run(ctx, os.Stdout, targets)
if errInstall != nil {
return errInstall
}
if cleanFunc := preparer.ShouldCleanMakeDeps(cmdArgs); cleanFunc != nil {
installer.AddPostInstallHook(cleanFunc)
}
if cleanAURDirsFunc := preparer.ShouldCleanAURDirs(pkgBuildDirs); cleanAURDirsFunc != nil {
installer.AddPostInstallHook(cleanAURDirsFunc)
}
go func() {
errComp := completion.Update(ctx, o.cfg.Runtime.HTTPClient, o.dbExecutor,
o.cfg.AURURL, o.cfg.CompletionPath, o.cfg.CompletionInterval, false)
if errComp != nil {
text.Warnln(errComp)
}
}()
srcInfo, errInstall := srcinfo.NewService(o.dbExecutor, o.cfg, o.cfg.Runtime.CmdBuilder, o.cfg.Runtime.VCSStore, pkgBuildDirs)
if errInstall != nil {
return errInstall
}
incompatible, errInstall := srcInfo.IncompatiblePkgs(ctx)
if errInstall != nil {
return errInstall
}
if errIncompatible := confirmIncompatible(incompatible); errIncompatible != nil {
return errIncompatible
}
if errPGP := srcInfo.CheckPGPKeys(ctx); errPGP != nil {
return errPGP
}
if errInstall := installer.Install(ctx, cmdArgs, targets, pkgBuildDirs,
excluded, o.manualConfirmRequired(cmdArgs)); errInstall != nil {
return errInstall
}
var multiErr multierror.MultiError
if err := installer.CompileFailedAndIgnored(); err != nil {
multiErr.Add(err)
}
if !cmdArgs.ExistsArg("w", "downloadonly") {
if err := srcInfo.UpdateVCSStore(ctx, targets, installer.failedAndIgnored); err != nil {
text.Warnln(err)
}
}
if err := installer.RunPostInstallHooks(ctx); err != nil {
multiErr.Add(err)
}
return multiErr.Return()
}
func (o *OperationService) manualConfirmRequired(cmdArgs *parser.Arguments) bool {
return (!cmdArgs.ExistsArg("u", "sysupgrade") && cmdArgs.Op != "Y") || o.cfg.DoubleConfirm
}
func confirmIncompatible(incompatible []string) error {
if len(incompatible) > 0 {
text.Warnln(gotext.Get("The following packages are not compatible with your architecture:"))
for _, pkg := range incompatible {
fmt.Print(" " + text.Cyan(pkg))
}
fmt.Println()
if !text.ContinueTask(os.Stdin, gotext.Get("Try to build them anyway?"), true, settings.NoConfirm) {
return &settings.ErrUserAbort{}
}
}
return nil
} }

View File

@@ -23,6 +23,7 @@ import (
"github.com/Jguer/yay/v12/pkg/db" "github.com/Jguer/yay/v12/pkg/db"
"github.com/Jguer/yay/v12/pkg/db/mock" "github.com/Jguer/yay/v12/pkg/db/mock"
mockaur "github.com/Jguer/yay/v12/pkg/dep/mock" mockaur "github.com/Jguer/yay/v12/pkg/dep/mock"
"github.com/Jguer/yay/v12/pkg/runtime"
"github.com/Jguer/yay/v12/pkg/settings" "github.com/Jguer/yay/v12/pkg/settings"
"github.com/Jguer/yay/v12/pkg/settings/exe" "github.com/Jguer/yay/v12/pkg/settings/exe"
"github.com/Jguer/yay/v12/pkg/settings/parser" "github.com/Jguer/yay/v12/pkg/settings/parser"
@@ -106,21 +107,20 @@ func TestSyncUpgrade(t *testing.T) {
}, },
} }
cfg := &settings.Configuration{ run := &runtime.Runtime{
RemoveMake: "no", Cfg: &settings.Configuration{
Runtime: &settings.Runtime{ RemoveMake: "no",
Logger: text.NewLogger(io.Discard, os.Stderr, strings.NewReader("\n"), true, "test"), },
CmdBuilder: cmdBuilder, Logger: text.NewLogger(io.Discard, os.Stderr, strings.NewReader("\n"), true, "test"),
VCSStore: &vcs.Mock{}, CmdBuilder: cmdBuilder,
AURClient: &mockaur.MockAUR{ VCSStore: &vcs.Mock{},
GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) { AURClient: &mockaur.MockAUR{
return []aur.Pkg{}, nil GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
}, return []aur.Pkg{}, nil
}, },
}, },
} }
err = handleCmd(context.Background(), run, cmdArgs, db)
err = handleCmd(context.Background(), cfg, cmdArgs, db)
require.NoError(t, err) require.NoError(t, err)
wantCapture := []string{} wantCapture := []string{}
@@ -219,21 +219,20 @@ func TestSyncUpgrade_IgnoreAll(t *testing.T) {
}, },
} }
cfg := &settings.Configuration{ run := &runtime.Runtime{
RemoveMake: "no", Cfg: &settings.Configuration{
Runtime: &settings.Runtime{ RemoveMake: "no",
Logger: text.NewLogger(io.Discard, os.Stderr, strings.NewReader("1\n"), true, "test"), },
CmdBuilder: cmdBuilder, Logger: text.NewLogger(io.Discard, os.Stderr, strings.NewReader("1\n"), true, "test"),
VCSStore: &vcs.Mock{}, CmdBuilder: cmdBuilder,
AURClient: &mockaur.MockAUR{ VCSStore: &vcs.Mock{},
GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) { AURClient: &mockaur.MockAUR{
return []aur.Pkg{}, nil GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
}, return []aur.Pkg{}, nil
}, },
}, },
} }
err = handleCmd(context.Background(), run, cmdArgs, db)
err = handleCmd(context.Background(), cfg, cmdArgs, db)
require.NoError(t, err) require.NoError(t, err)
wantCapture := []string{} wantCapture := []string{}
@@ -349,21 +348,21 @@ func TestSyncUpgrade_IgnoreOne(t *testing.T) {
}, },
} }
cfg := &settings.Configuration{ run := &runtime.Runtime{
RemoveMake: "no", Cfg: &settings.Configuration{
Runtime: &settings.Runtime{ RemoveMake: "no",
Logger: text.NewLogger(io.Discard, os.Stderr, strings.NewReader("1\n"), true, "test"), },
CmdBuilder: cmdBuilder, Logger: text.NewLogger(io.Discard, os.Stderr, strings.NewReader("1\n"), true, "test"),
VCSStore: &vcs.Mock{}, CmdBuilder: cmdBuilder,
AURClient: &mockaur.MockAUR{ VCSStore: &vcs.Mock{},
GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) { AURClient: &mockaur.MockAUR{
return []aur.Pkg{}, nil GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
}, return []aur.Pkg{}, nil
}, },
}, },
} }
err = handleCmd(context.Background(), cfg, cmdArgs, db) err = handleCmd(context.Background(), run, cmdArgs, db)
require.NoError(t, err) require.NoError(t, err)
wantCapture := []string{} wantCapture := []string{}
@@ -512,37 +511,37 @@ pkgname = python-vosk
}, },
} }
cfg := &settings.Configuration{ run := &runtime.Runtime{
DoubleConfirm: true, Cfg: &settings.Configuration{
RemoveMake: "no", DoubleConfirm: true,
BuildDir: tmpDir, RemoveMake: "no",
Runtime: &settings.Runtime{ BuildDir: tmpDir,
Logger: text.NewLogger(io.Discard, os.Stderr, strings.NewReader("\n\n\n\n"), true, "test"), },
CmdBuilder: cmdBuilder, Logger: text.NewLogger(io.Discard, os.Stderr, strings.NewReader("\n\n\n\n"), true, "test"),
VCSStore: &vcs.Mock{}, CmdBuilder: cmdBuilder,
AURClient: &mockaur.MockAUR{ VCSStore: &vcs.Mock{},
GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) { AURClient: &mockaur.MockAUR{
return []aur.Pkg{ GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
{ return []aur.Pkg{
Name: "vosk-api", {
PackageBase: "vosk-api", Name: "vosk-api",
Version: "0.3.45-1", PackageBase: "vosk-api",
Version: "0.3.45-1",
},
{
Name: "python-vosk",
PackageBase: "vosk-api",
Version: "0.3.45-1",
Depends: []string{
"vosk-api=0.3.45",
}, },
{ },
Name: "python-vosk", }, nil
PackageBase: "vosk-api",
Version: "0.3.45-1",
Depends: []string{
"vosk-api=0.3.45",
},
},
}, nil
},
}, },
}, },
} }
err = handleCmd(context.Background(), cfg, cmdArgs, db) err = handleCmd(context.Background(), run, cmdArgs, db)
require.NoError(t, err) require.NoError(t, err)
wantCapture := []string{ wantCapture := []string{
@@ -697,22 +696,22 @@ func TestSyncUpgrade_NoCombinedUpgrade(t *testing.T) {
}, },
} }
cfg := &settings.Configuration{ run := &runtime.Runtime{
RemoveMake: "no", Cfg: &settings.Configuration{
CombinedUpgrade: false, RemoveMake: "no",
Runtime: &settings.Runtime{ CombinedUpgrade: false,
Logger: text.NewLogger(io.Discard, os.Stderr, strings.NewReader("1\n"), true, "test"), },
CmdBuilder: cmdBuilder, Logger: text.NewLogger(io.Discard, os.Stderr, strings.NewReader("1\n"), true, "test"),
VCSStore: &vcs.Mock{}, CmdBuilder: cmdBuilder,
AURClient: &mockaur.MockAUR{ VCSStore: &vcs.Mock{},
GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) { AURClient: &mockaur.MockAUR{
return []aur.Pkg{}, nil GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
}, return []aur.Pkg{}, nil
}, },
}, },
} }
err = handleCmd(context.Background(), cfg, cmdArgs, db) err = handleCmd(context.Background(), run, cmdArgs, db)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, mockRunner.ShowCalls, len(tc.want)) require.Len(t, mockRunner.ShowCalls, len(tc.want))

23
vcs.go
View File

@@ -2,7 +2,6 @@ package main
import ( import (
"context" "context"
"os"
"sync" "sync"
"github.com/Jguer/aur" "github.com/Jguer/aur"
@@ -10,9 +9,9 @@ import (
"github.com/Jguer/yay/v12/pkg/db" "github.com/Jguer/yay/v12/pkg/db"
"github.com/Jguer/yay/v12/pkg/dep" "github.com/Jguer/yay/v12/pkg/dep"
"github.com/Jguer/yay/v12/pkg/settings" "github.com/Jguer/yay/v12/pkg/runtime"
"github.com/Jguer/yay/v12/pkg/srcinfo" "github.com/Jguer/yay/v12/pkg/sync/srcinfo"
"github.com/Jguer/yay/v12/pkg/text" "github.com/Jguer/yay/v12/pkg/sync/workdir"
) )
func infoToInstallInfo(info []aur.Pkg) []map[string]*dep.InstallInfo { func infoToInstallInfo(info []aur.Pkg) []map[string]*dep.InstallInfo {
@@ -31,11 +30,11 @@ func infoToInstallInfo(info []aur.Pkg) []map[string]*dep.InstallInfo {
} }
// createDevelDB forces yay to create a DB of the existing development packages. // createDevelDB forces yay to create a DB of the existing development packages.
func createDevelDB(ctx context.Context, cfg *settings.Configuration, dbExecutor db.Executor) error { func createDevelDB(ctx context.Context, run *runtime.Runtime, dbExecutor db.Executor) error {
remoteNames := dbExecutor.InstalledRemotePackageNames() remoteNames := dbExecutor.InstalledRemotePackageNames()
cfg.Runtime.QueryBuilder.Execute(ctx, dbExecutor, remoteNames) run.QueryBuilder.Execute(ctx, dbExecutor, remoteNames)
info, err := cfg.Runtime.AURClient.Get(ctx, &aur.Query{ info, err := run.AURClient.Get(ctx, &aur.Query{
Needles: remoteNames, Needles: remoteNames,
By: aur.Name, By: aur.Name,
Contains: false, Contains: false,
@@ -44,15 +43,15 @@ func createDevelDB(ctx context.Context, cfg *settings.Configuration, dbExecutor
return err return err
} }
preper := NewPreparerWithoutHooks(dbExecutor, cfg.Runtime.CmdBuilder, cfg, false) preper := workdir.NewPreparerWithoutHooks(dbExecutor, run.CmdBuilder, run.Cfg, run.Logger.Child("workdir"), false)
mapInfo := infoToInstallInfo(info) mapInfo := infoToInstallInfo(info)
pkgBuildDirsByBase, err := preper.Run(ctx, os.Stdout, mapInfo) pkgBuildDirsByBase, err := preper.Run(ctx, run, mapInfo)
if err != nil { if err != nil {
return err return err
} }
srcinfos, err := srcinfo.ParseSrcinfoFilesByBase(pkgBuildDirsByBase, false) srcinfos, err := srcinfo.ParseSrcinfoFilesByBase(run.Logger.Child("srcinfo"), pkgBuildDirsByBase, false)
if err != nil { if err != nil {
return err return err
} }
@@ -63,14 +62,14 @@ func createDevelDB(ctx context.Context, cfg *settings.Configuration, dbExecutor
wg.Add(1) wg.Add(1)
go func(i string, iP int) { go func(i string, iP int) {
cfg.Runtime.VCSStore.Update(ctx, srcinfos[i].Packages[iP].Pkgname, srcinfos[i].Source) run.VCSStore.Update(ctx, srcinfos[i].Packages[iP].Pkgname, srcinfos[i].Source)
wg.Done() wg.Done()
}(i, iP) }(i, iP)
} }
} }
wg.Wait() wg.Wait()
text.OperationInfoln(gotext.Get("GenDB finished. No packages were installed")) run.Logger.OperationInfoln(gotext.Get("GenDB finished. No packages were installed"))
return err return err
} }

View File

@@ -3,11 +3,12 @@ package main
import ( import (
"context" "context"
"errors" "errors"
"fmt"
"github.com/Jguer/aur" "github.com/Jguer/aur"
"github.com/Jguer/votar/pkg/vote" "github.com/Jguer/votar/pkg/vote"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/Jguer/yay/v12/pkg/text"
) )
type ErrAURVote struct { type ErrAURVote struct {
@@ -20,7 +21,7 @@ func (e *ErrAURVote) Error() string {
} }
func handlePackageVote(ctx context.Context, func handlePackageVote(ctx context.Context,
targets []string, aurClient aur.QueryClient, targets []string, aurClient aur.QueryClient, logger *text.Logger,
voteClient *vote.Client, upvote bool, voteClient *vote.Client, upvote bool,
) error { ) error {
infos, err := aurClient.Get(ctx, &aur.Query{ infos, err := aurClient.Get(ctx, &aur.Query{
@@ -32,7 +33,7 @@ func handlePackageVote(ctx context.Context,
} }
if len(infos) == 0 { if len(infos) == 0 {
fmt.Println(gotext.Get(" there is nothing to do")) logger.Println(gotext.Get(" there is nothing to do"))
return nil return nil
} }