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
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
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
disable-all: true
enable:
- forbidigo
- bodyclose
- dogsled
- dupl
@ -80,8 +81,12 @@ linters:
- whitespace
run:
go: "1.18"
go: "1.20"
timeout: "10m"
forbidigo:
forbid:
- p: ^fmt\.Print.*$
msg: Do not commit print statements.
issues:
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`
(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?**
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} --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
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.
- **What settings do you use?**
```sh
yay -Y --devel --combinedupgrade --batchinstall --save
```
Pacman conf options:
```conf
UseSyslog
Color
CheckSpace
VerbosePkgLists
```
## Support
All support related to Yay should be requested via GitHub issues. Since Yay is not

View File

@ -2,7 +2,6 @@ package main
import (
"context"
"fmt"
"os"
"path/filepath"
@ -11,10 +10,10 @@ import (
"github.com/leonelquinteros/gotext"
"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/exe"
"github.com/Jguer/yay/v12/pkg/settings/parser"
"github.com/Jguer/yay/v12/pkg/text"
)
// CleanDependencies removes all dangling dependencies in system.
@ -49,13 +48,13 @@ func cleanRemove(ctx context.Context, cfg *settings.Configuration,
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
keepCurrent := false
_, removeAll, _ := cmdArgs.GetArg("c", "clean")
for _, v := range cfg.Runtime.PacmanConf.CleanMethod {
for _, v := range run.PacmanConf.CleanMethod {
if v == "KeepInstalled" {
keepInstalled = true
} else if v == "KeepCurrent" {
@ -63,14 +62,14 @@ func syncClean(ctx context.Context, cfg *settings.Configuration, cmdArgs *parser
}
}
if cfg.Mode.AtLeastRepo() {
if err := cfg.Runtime.CmdBuilder.Show(cfg.Runtime.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, cfg.Mode, settings.NoConfirm)); err != nil {
if run.Cfg.Mode.AtLeastRepo() {
if err := run.CmdBuilder.Show(run.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, run.Cfg.Mode, settings.NoConfirm)); err != nil {
return err
}
}
if !cfg.Mode.AtLeastAUR() {
if !run.Cfg.Mode.AtLeastAUR() {
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?")
}
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 err := cleanAUR(ctx, cfg, keepInstalled, keepCurrent, removeAll, dbExecutor); err != nil {
if run.Logger.ContinueTask(question, true, settings.NoConfirm) {
if err := cleanAUR(ctx, run, keepInstalled, keepCurrent, removeAll, dbExecutor); err != nil {
return err
}
}
@ -93,24 +92,24 @@ func syncClean(ctx context.Context, cfg *settings.Configuration, cmdArgs *parser
return nil
}
if text.ContinueTask(os.Stdin, gotext.Get("Do you want to remove ALL untracked AUR files?"), true, settings.NoConfirm) {
return cleanUntracked(ctx, cfg)
if run.Logger.ContinueTask(gotext.Get("Do you want to remove ALL untracked AUR files?"), true, settings.NoConfirm) {
return cleanUntracked(ctx, run)
}
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,
) 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]()
inAURBases := mapset.NewThreadUnsafeSet[string]()
remotePackages := dbExecutor.InstalledRemotePackages()
files, err := os.ReadDir(cfg.BuildDir)
files, err := os.ReadDir(run.Cfg.BuildDir)
if err != nil {
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
// don't need to.
if keepCurrent {
info, errInfo := cfg.Runtime.AURClient.Get(ctx, &aur.Query{
info, errInfo := run.AURClient.Get(ctx, &aur.Query{
Needles: cachedPackages,
})
if errInfo != nil {
@ -165,20 +164,20 @@ func cleanAUR(ctx context.Context, cfg *settings.Configuration,
}
}
dir := filepath.Join(cfg.BuildDir, file.Name())
cfg.Runtime.Logger.Debugln("removing", dir)
dir := filepath.Join(run.Cfg.BuildDir, file.Name())
run.Logger.Debugln("removing", dir)
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
}
func cleanUntracked(ctx context.Context, cfg *settings.Configuration) error {
cfg.Runtime.Logger.Println(gotext.Get("removing untracked AUR files from cache..."))
func cleanUntracked(ctx context.Context, run *runtime.Runtime) error {
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 {
return err
}
@ -188,12 +187,11 @@ func cleanUntracked(ctx context.Context, cfg *settings.Configuration) error {
continue
}
dir := filepath.Join(cfg.BuildDir, file.Name())
cfg.Runtime.Logger.Debugln("cleaning", dir)
dir := filepath.Join(run.Cfg.BuildDir, file.Name())
run.Logger.Debugln("cleaning", dir)
if isGitRepository(dir) {
if err := cfg.Runtime.CmdBuilder.Show(cfg.Runtime.CmdBuilder.BuildGitCmd(ctx, dir, "clean", "-fx")); err != nil {
cfg.Runtime.Logger.Warnln(gotext.Get("Unable to clean:"), dir)
if err := run.CmdBuilder.Show(run.CmdBuilder.BuildGitCmd(ctx, dir, "clean", "-fx")); err != nil {
run.Logger.Warnln(gotext.Get("Unable to clean:"), dir)
return err
}
}
@ -206,29 +204,3 @@ func isGitRepository(dir string) bool {
_, err := os.Stat(filepath.Join(dir, ".git"))
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/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/exe"
"github.com/Jguer/yay/v12/pkg/settings/parser"
@ -90,15 +91,13 @@ func TestCleanHanging(t *testing.T) {
Runner: mockRunner,
SudoLoopEnabled: false,
}
cfg := &settings.Configuration{
Runtime: &settings.Runtime{CmdBuilder: cmdBuilder},
}
run := &runtime.Runtime{CmdBuilder: cmdBuilder, Cfg: &settings.Configuration{}}
cmdArgs := parser.MakeArguments()
cmdArgs.AddArg(tc.args...)
err := handleCmd(context.Background(),
cfg, cmdArgs, dbExc,
run, cmdArgs, dbExc,
)
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/news"
"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/exe"
"github.com/Jguer/yay/v12/pkg/settings/parser"
@ -25,8 +26,8 @@ import (
"github.com/Jguer/yay/v12/pkg/vcs"
)
func usage() {
fmt.Println(`Usage:
func usage(logger *text.Logger) {
logger.Println(`Usage:
yay
yay <operation> [...]
yay <package(s)>
@ -146,50 +147,49 @@ getpkgbuild specific options:
-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,
) error {
if cmdArgs.ExistsArg("h", "help") {
return handleHelp(ctx, cfg, cmdArgs)
return handleHelp(ctx, run, cmdArgs)
}
if cfg.SudoLoop && cmdArgs.NeedRoot(cfg.Mode) {
cfg.Runtime.CmdBuilder.SudoLoop()
if run.Cfg.SudoLoop && cmdArgs.NeedRoot(run.Cfg.Mode) {
run.CmdBuilder.SudoLoop()
}
switch cmdArgs.Op {
case "V", "version":
handleVersion()
handleVersion(run.Logger)
return nil
case "D", "database":
return cfg.Runtime.CmdBuilder.Show(cfg.Runtime.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, cfg.Mode, settings.NoConfirm))
return run.CmdBuilder.Show(run.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, run.Cfg.Mode, settings.NoConfirm))
case "F", "files":
return cfg.Runtime.CmdBuilder.Show(cfg.Runtime.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, cfg.Mode, settings.NoConfirm))
return run.CmdBuilder.Show(run.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, run.Cfg.Mode, settings.NoConfirm))
case "Q", "query":
return handleQuery(ctx, cfg, cmdArgs, dbExecutor)
return handleQuery(ctx, run, cmdArgs, dbExecutor)
case "R", "remove":
return handleRemove(ctx, cfg, cmdArgs, cfg.Runtime.VCSStore)
return handleRemove(ctx, run, cmdArgs, run.VCSStore)
case "S", "sync":
return handleSync(ctx, cfg, cmdArgs, dbExecutor)
return handleSync(ctx, run, cmdArgs, dbExecutor)
case "T", "deptest":
return cfg.Runtime.CmdBuilder.Show(cfg.Runtime.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, cfg.Mode, settings.NoConfirm))
return run.CmdBuilder.Show(run.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, run.Cfg.Mode, settings.NoConfirm))
case "U", "upgrade":
return handleUpgrade(ctx, cfg, cmdArgs)
return handleUpgrade(ctx, run, cmdArgs)
case "B", "build":
return handleBuild(ctx, cfg, dbExecutor, cmdArgs)
return handleBuild(ctx, run, dbExecutor, cmdArgs)
case "G", "getpkgbuild":
return handleGetpkgbuild(ctx, cfg, cmdArgs, dbExecutor)
return handleGetpkgbuild(ctx, run, cmdArgs, dbExecutor)
case "P", "show":
return handlePrint(ctx, cfg, cmdArgs, dbExecutor)
return handlePrint(ctx, run, cmdArgs, dbExecutor)
case "Y", "yay":
return handleYay(ctx, cfg, cmdArgs, cfg.Runtime.CmdBuilder,
dbExecutor, cfg.Runtime.QueryBuilder)
return handleYay(ctx, run, cmdArgs, run.CmdBuilder,
dbExecutor, run.QueryBuilder)
case "W", "web":
return handleWeb(ctx, cfg, cmdArgs)
return handleWeb(ctx, run, cmdArgs)
}
return errors.New(gotext.Get("unhandled operation"))
@ -219,19 +219,19 @@ func getFilter(cmdArgs *parser.Arguments) (upgrade.Filter, error) {
}, 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") {
filter, err := getFilter(cmdArgs)
if err != nil {
return err
}
return printUpdateList(ctx, cfg, cmdArgs, dbExecutor,
return printUpdateList(ctx, run, cmdArgs, dbExecutor,
cmdArgs.ExistsDouble("u", "sysupgrade"), filter)
}
if err := cfg.Runtime.CmdBuilder.Show(cfg.Runtime.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, cfg.Mode, settings.NoConfirm)); err != nil {
if err := run.CmdBuilder.Show(run.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, run.Cfg.Mode, settings.NoConfirm)); err != nil {
if str := err.Error(); strings.Contains(str, "exit status") {
// yay -Qdt should not output anything in case of error
return fmt.Errorf("")
@ -243,138 +243,139 @@ func handleQuery(ctx context.Context, cfg *settings.Configuration, cmdArgs *pars
return nil
}
func handleHelp(ctx context.Context, cfg *settings.Configuration, cmdArgs *parser.Arguments) error {
usage()
func handleHelp(ctx context.Context, run *runtime.Runtime, cmdArgs *parser.Arguments) error {
usage(run.Logger)
switch cmdArgs.Op {
case "Y", "yay", "G", "getpkgbuild", "P", "show", "W", "web", "B", "build":
return nil
}
cfg.Runtime.Logger.Println("\npacman operation specific options:")
return cfg.Runtime.CmdBuilder.Show(cfg.Runtime.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, cfg.Mode, settings.NoConfirm))
run.Logger.Println("\npacman operation specific options:")
return run.CmdBuilder.Show(run.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, run.Cfg.Mode, settings.NoConfirm))
}
func handleVersion() {
fmt.Printf("yay v%s - libalpm v%s\n", yayVersion, alpm.Version())
func handleVersion(logger *text.Logger) {
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 {
case cmdArgs.ExistsArg("d", "defaultconfig"):
tmpConfig := settings.DefaultConfig(yayVersion)
fmt.Printf("%v", tmpConfig)
run.Logger.Printf("%v", tmpConfig)
return nil
case cmdArgs.ExistsArg("g", "currentconfig"):
fmt.Printf("%v", cfg)
run.Logger.Printf("%v", run.Cfg)
return nil
case cmdArgs.ExistsArg("w", "news"):
double := cmdArgs.ExistsDouble("w", "news")
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"):
return completion.Show(ctx, cfg.Runtime.HTTPClient, dbExecutor,
cfg.AURURL, cfg.CompletionPath, cfg.CompletionInterval, cmdArgs.ExistsDouble("c", "complete"))
return completion.Show(ctx, run.HTTPClient, dbExecutor,
run.Cfg.AURURL, run.Cfg.CompletionPath, run.Cfg.CompletionInterval, cmdArgs.ExistsDouble("c", "complete"))
case cmdArgs.ExistsArg("s", "stats"):
return localStatistics(ctx, cfg, dbExecutor)
return localStatistics(ctx, run, dbExecutor)
}
return nil
}
func handleYay(ctx context.Context, cfg *settings.Configuration,
func handleYay(ctx context.Context, run *runtime.Runtime,
cmdArgs *parser.Arguments, cmdBuilder exe.ICmdBuilder,
dbExecutor db.Executor, queryBuilder query.Builder,
) error {
switch {
case cmdArgs.ExistsArg("gendb"):
return createDevelDB(ctx, cfg, dbExecutor)
return createDevelDB(ctx, run, dbExecutor)
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"):
return cleanDependencies(ctx, cfg, cmdBuilder, cmdArgs, dbExecutor, false)
return cleanDependencies(ctx, run.Cfg, cmdBuilder, cmdArgs, dbExecutor, false)
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
}
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 {
case cmdArgs.ExistsArg("v", "vote"):
return handlePackageVote(ctx, cmdArgs.Targets, cfg.Runtime.AURClient,
cfg.Runtime.VoteClient, true)
return handlePackageVote(ctx, cmdArgs.Targets, run.AURClient, run.Logger,
run.VoteClient, true)
case cmdArgs.ExistsArg("u", "unvote"):
return handlePackageVote(ctx, cmdArgs.Targets, cfg.Runtime.AURClient,
cfg.Runtime.VoteClient, false)
return handlePackageVote(ctx, cmdArgs.Targets, run.AURClient, run.Logger,
run.VoteClient, false)
}
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") {
return printPkgbuilds(dbExecutor, cfg.Runtime.AURClient,
cfg.Runtime.HTTPClient, cmdArgs.Targets, cfg.Mode, cfg.AURURL)
return printPkgbuilds(dbExecutor, run.AURClient,
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"))
}
func handleUpgrade(ctx context.Context,
config *settings.Configuration, cmdArgs *parser.Arguments,
run *runtime.Runtime, cmdArgs *parser.Arguments,
) error {
return config.Runtime.CmdBuilder.Show(config.Runtime.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, config.Mode, settings.NoConfirm))
return run.CmdBuilder.Show(run.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, run.Cfg.Mode, settings.NoConfirm))
}
// -B* options
func handleBuild(ctx context.Context,
config *settings.Configuration, dbExecutor db.Executor, cmdArgs *parser.Arguments,
run *runtime.Runtime, dbExecutor db.Executor, cmdArgs *parser.Arguments,
) error {
if cmdArgs.ExistsArg("i", "install") {
return installLocalPKGBUILD(ctx, config, cmdArgs, dbExecutor)
return installLocalPKGBUILD(ctx, run, cmdArgs, dbExecutor)
}
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
switch {
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"):
return cfg.Runtime.CmdBuilder.Show(cfg.Runtime.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, cfg.Mode, settings.NoConfirm))
return run.CmdBuilder.Show(run.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, run.Cfg.Mode, settings.NoConfirm))
case cmdArgs.ExistsArg("c", "clean"):
return syncClean(ctx, cfg, cmdArgs, dbExecutor)
return syncClean(ctx, run, cmdArgs, dbExecutor)
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"):
return cfg.Runtime.CmdBuilder.Show(cfg.Runtime.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, cfg.Mode, settings.NoConfirm))
return run.CmdBuilder.Show(run.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, run.Cfg.Mode, settings.NoConfirm))
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:
return syncInstall(ctx, cfg, cmdArgs, dbExecutor)
return syncInstall(ctx, run, cmdArgs, dbExecutor)
case cmdArgs.ExistsArg("y", "refresh"):
return cfg.Runtime.CmdBuilder.Show(cfg.Runtime.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, cfg.Mode, settings.NoConfirm))
return run.CmdBuilder.Show(run.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, run.Cfg.Mode, settings.NoConfirm))
}
return nil
}
func handleRemove(ctx context.Context, cfg *settings.Configuration, cmdArgs *parser.Arguments, localCache vcs.Store) error {
err := cfg.Runtime.CmdBuilder.Show(cfg.Runtime.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, cfg.Mode, settings.NoConfirm))
func handleRemove(ctx context.Context, run *runtime.Runtime, cmdArgs *parser.Arguments, localCache vcs.Store) error {
err := run.CmdBuilder.Show(run.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, run.Cfg.Mode, settings.NoConfirm))
if err == nil {
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.
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,
) error {
queryBuilder.Execute(ctx, dbExecutor, pkgS)
@ -397,9 +398,9 @@ func displayNumberMenu(ctx context.Context, cfg *settings.Configuration, pkgS []
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 {
return err
}
@ -415,27 +416,27 @@ func displayNumberMenu(ctx context.Context, cfg *settings.Configuration, pkgS []
cmdArgs.Targets = targets
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 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,
) error {
aur := false
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:]...)
aur = true
}
}
if cfg.Mode.AtLeastAUR() && (len(cmdArgs.Targets) == 0 || aur) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, cfg.AURURL+"/packages.gz", http.NoBody)
if run.Cfg.Mode.AtLeastAUR() && (len(cmdArgs.Targets) == 0 || aur) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, run.Cfg.AURURL+"/packages.gz", http.NoBody)
if err != nil {
return err
}
@ -453,22 +454,22 @@ func syncList(ctx context.Context, cfg *settings.Configuration,
for scanner.Scan() {
name := scanner.Text()
if cmdArgs.ExistsArg("q", "quiet") {
fmt.Println(name)
run.Logger.Println(name)
} 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 {
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) {
return cfg.Runtime.CmdBuilder.Show(cfg.Runtime.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, cfg.Mode, settings.NoConfirm))
if run.Cfg.Mode.AtLeastRepo() && (len(cmdArgs.Targets) != 0 || !aur) {
return run.CmdBuilder.Show(run.CmdBuilder.BuildPacmanCmd(ctx,
cmdArgs, run.Cfg.Mode, settings.NoConfirm))
}
return nil

View File

@ -19,6 +19,7 @@ import (
"github.com/Jguer/yay/v12/pkg/db/mock"
mockaur "github.com/Jguer/yay/v12/pkg/dep/mock"
"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/exe"
"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")
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)
wantCapture := []string{}

View File

@ -7,56 +7,3 @@ import (
)
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/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/text"
)
// 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,
) 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 {
text.Errorln(err)
logger.Errorln(err)
}
if len(pkgbuilds) != 0 {
for target, pkgbuild := range pkgbuilds {
fmt.Printf("\n\n# %s\n\n", target)
fmt.Print(string(pkgbuild))
logger.Printf("\n\n# %s\n\n%s", target, 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("")
}
@ -51,7 +51,7 @@ func printPkgbuilds(dbExecutor download.DBSearcher, aurClient aur.QueryClient, h
// yay -G.
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 {
wd, err := os.Getwd()
if err != nil {
@ -59,9 +59,9 @@ func getPkgbuilds(ctx context.Context, dbExecutor download.DBSearcher, 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 {
text.Errorln(errD)
run.Logger.Errorln(errD)
}
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("")
}

View File

@ -12,19 +12,18 @@ import (
"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/exe"
"github.com/Jguer/yay/v12/pkg/settings/parser"
"github.com/Jguer/yay/v12/pkg/sync"
gosrc "github.com/Morganamilo/go-srcinfo"
"github.com/leonelquinteros/gotext"
"github.com/pkg/errors"
)
var (
ErrInstallRepoPkgs = errors.New(gotext.Get("error installing repo packages"))
ErrNoBuildFiles = errors.New(gotext.Get("cannot find PKGBUILD and .SRCINFO in directory"))
)
var ErrNoBuildFiles = errors.New(gotext.Get("cannot find PKGBUILD and .SRCINFO in directory"))
func srcinfoExists(ctx context.Context,
cmdBuilder exe.ICmdBuilder, targetDir string,
@ -56,12 +55,12 @@ func srcinfoExists(ctx context.Context,
func installLocalPKGBUILD(
ctx context.Context,
config *settings.Configuration,
run *runtime.Runtime,
cmdArgs *parser.Arguments,
dbExecutor db.Executor,
) error {
aurCache := config.Runtime.AURClient
noCheck := strings.Contains(config.MFlags, "--nocheck")
aurCache := run.AURClient
noCheck := strings.Contains(run.Cfg.MFlags, "--nocheck")
if len(cmdArgs.Targets) < 1 {
return errors.New(gotext.Get("no target directories specified"))
@ -69,7 +68,7 @@ func installLocalPKGBUILD(
srcInfos := map[string]*gosrc.Srcinfo{}
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
}
@ -83,13 +82,13 @@ func installLocalPKGBUILD(
grapher := dep.NewGrapher(dbExecutor, aurCache, false, settings.NoConfirm,
cmdArgs.ExistsDouble("d", "nodeps"), noCheck, cmdArgs.ExistsArg("needed"),
config.Runtime.Logger.Child("grapher"))
run.Logger.Child("grapher"))
graph, err := grapher.GraphFromSrcInfos(ctx, nil, srcInfos)
if err != nil {
return err
}
opService := NewOperationService(ctx, config, dbExecutor)
opService := sync.NewOperationService(ctx, dbExecutor, run)
multiErr := &multierror.MultiError{}
targets := graph.TopoSortedLayerMap(func(name string, ii *dep.InstallInfo) error {
if ii.Source == dep.Missing {
@ -101,5 +100,5 @@ func installLocalPKGBUILD(
if err := multiErr.Return(); err != nil {
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 (
"context"
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
@ -19,12 +20,18 @@ import (
"github.com/Jguer/yay/v12/pkg/db/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/exe"
"github.com/Jguer/yay/v12/pkg/settings/parser"
"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 TestIntegrationLocalInstall(t *testing.T) {
makepkgBin := t.TempDir() + "/makepkg"
pacmanBin := t.TempDir() + "/pacman"
@ -142,21 +149,21 @@ func TestIntegrationLocalInstall(t *testing.T) {
InstalledRemotePackageNamesFn: func() []string { return []string{} },
}
config := &settings.Configuration{
RemoveMake: "no",
Runtime: &settings.Runtime{
Logger: NewTestLogger(),
CmdBuilder: cmdBuilder,
VCSStore: &vcs.Mock{},
AURClient: &mockaur.MockAUR{
GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
return []aur.Pkg{}, nil
},
run := &runtime.Runtime{
Cfg: &settings.Configuration{
RemoveMake: "no",
},
Logger: newTestLogger(),
CmdBuilder: cmdBuilder,
VCSStore: &vcs.Mock{},
AURClient: &mockaur.MockAUR{
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.Len(t, mockRunner.ShowCalls, len(wantShow))
@ -263,20 +270,19 @@ func TestIntegrationLocalInstallMissingDep(t *testing.T) {
LocalPackageFn: func(string) mock.IPackage { return nil },
}
config := &settings.Configuration{
Runtime: &settings.Runtime{
Logger: NewTestLogger(),
CmdBuilder: cmdBuilder,
VCSStore: &vcs.Mock{},
AURClient: &mockaur.MockAUR{
GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
return []aur.Pkg{}, nil
},
run := &runtime.Runtime{
Cfg: &settings.Configuration{},
Logger: newTestLogger(),
CmdBuilder: cmdBuilder,
VCSStore: &vcs.Mock{},
AURClient: &mockaur.MockAUR{
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.ErrorContains(t, err, wantErr.Error())
require.Len(t, mockRunner.ShowCalls, len(wantShow))
@ -421,21 +427,21 @@ func TestIntegrationLocalInstallNeeded(t *testing.T) {
InstalledRemotePackageNamesFn: func() []string { return []string{} },
}
config := &settings.Configuration{
RemoveMake: "no",
Runtime: &settings.Runtime{
Logger: NewTestLogger(),
CmdBuilder: cmdBuilder,
VCSStore: &vcs.Mock{},
AURClient: &mockaur.MockAUR{
GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
return []aur.Pkg{}, nil
},
run := &runtime.Runtime{
Cfg: &settings.Configuration{
RemoveMake: "no",
},
Logger: newTestLogger(),
CmdBuilder: cmdBuilder,
VCSStore: &vcs.Mock{},
AURClient: &mockaur.MockAUR{
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.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{} },
}
config := &settings.Configuration{
RemoveMake: "no",
Debug: false,
Runtime: &settings.Runtime{
Logger: NewTestLogger(),
CmdBuilder: cmdBuilder,
VCSStore: &vcs.Mock{},
AURClient: &mockaur.MockAUR{
GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
return []aur.Pkg{}, nil
},
run := &runtime.Runtime{
Cfg: &settings.Configuration{
RemoveMake: "no",
Debug: false,
},
Logger: newTestLogger(),
CmdBuilder: cmdBuilder,
VCSStore: &vcs.Mock{},
AURClient: &mockaur.MockAUR{
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.Len(t, mockRunner.ShowCalls, len(wantShow))
@ -651,7 +657,6 @@ func TestIntegrationLocalInstallMissingFiles(t *testing.T) {
wantCapture := []string{}
captureOverride := func(cmd *exec.Cmd) (stdout string, stderr string, err error) {
fmt.Println(cmd.Args)
if cmd.Args[1] == "--printsrcinfo" {
return string(srcinfo), "", nil
}
@ -722,16 +727,17 @@ func TestIntegrationLocalInstallMissingFiles(t *testing.T) {
},
}
config := &settings.Configuration{
RemoveMake: "no",
Runtime: &settings.Runtime{
Logger: NewTestLogger(),
CmdBuilder: cmdBuilder,
VCSStore: &vcs.Mock{},
AURClient: &mockaur.MockAUR{
GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
return []aur.Pkg{}, nil
},
config := &runtime.Runtime{
Cfg: &settings.Configuration{
RemoveMake: "no",
Debug: false,
},
Logger: newTestLogger(),
CmdBuilder: cmdBuilder,
VCSStore: &vcs.Mock{},
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{} },
}
config := &settings.Configuration{
RemoveMake: "no",
Runtime: &settings.Runtime{
Logger: NewTestLogger(),
CmdBuilder: cmdBuilder,
VCSStore: &vcs.Mock{},
AURClient: &mockaur.MockAUR{
GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
return []aur.Pkg{}, nil
},
config := &runtime.Runtime{
Cfg: &settings.Configuration{
RemoveMake: "no",
},
Logger: newTestLogger(),
CmdBuilder: cmdBuilder,
VCSStore: &vcs.Mock{},
AURClient: &mockaur.MockAUR{
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{} },
}
config := &settings.Configuration{
RemoveMake: "no",
Runtime: &settings.Runtime{
Logger: NewTestLogger(),
CmdBuilder: cmdBuilder,
VCSStore: &vcs.Mock{},
AURClient: &mockaur.MockAUR{
GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
return []aur.Pkg{}, nil
},
run := &runtime.Runtime{
Cfg: &settings.Configuration{
RemoveMake: "no",
},
Logger: newTestLogger(),
CmdBuilder: cmdBuilder,
VCSStore: &vcs.Mock{},
AURClient: &mockaur.MockAUR{
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.Len(t, mockRunner.ShowCalls, len(wantShow))

68
main.go
View File

@ -9,9 +9,8 @@ import (
"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/query"
"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/text"
@ -39,6 +38,7 @@ func initGotext() {
}
func main() {
fallbackLog := text.NewLogger(os.Stdout, os.Stderr, os.Stdin, false, "fallback")
var (
err error
ctx = context.Background()
@ -47,7 +47,7 @@ func main() {
defer func() {
if rec := recover(); rec != nil {
text.Errorln(rec)
fallbackLog.Errorln(rec)
debug.PrintStack()
}
@ -57,15 +57,15 @@ func main() {
initGotext()
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()
// Parse config
cfg, err := settings.NewConfig(configPath, yayVersion)
cfg, err := settings.NewConfig(fallbackLog, configPath, yayVersion)
if err != nil {
if str := err.Error(); str != "" {
text.Errorln(str)
fallbackLog.Errorln(str)
}
ret = 1
@ -73,13 +73,9 @@ func main() {
return
}
if cfg.Debug {
text.GlobalLogger.Debug = true
}
if errS := cfg.RunMigrations(
if errS := cfg.RunMigrations(fallbackLog,
settings.DefaultMigrations(), configPath, yayVersion); errS != nil {
text.Errorln(errS)
fallbackLog.Errorln(errS)
}
cmdArgs := parser.MakeArguments()
@ -87,7 +83,7 @@ func main() {
// Parse command line
if err = cfg.ParseCommandLine(cmdArgs); err != nil {
if str := err.Error(); str != "" {
text.Errorln(str)
fallbackLog.Errorln(str)
}
ret = 1
@ -97,15 +93,15 @@ func main() {
if cfg.SaveConfig {
if errS := cfg.Save(configPath, yayVersion); errS != nil {
text.Errorln(errS)
fallbackLog.Errorln(errS)
}
}
// Build runtime
runtime, err := settings.BuildRuntime(cfg, cmdArgs, yayVersion)
// Build run
run, err := runtime.NewRuntime(cfg, cmdArgs, yayVersion)
if err != nil {
if str := err.Error(); str != "" {
text.Errorln(str)
fallbackLog.Errorln(str)
}
ret = 1
@ -113,35 +109,10 @@ func main() {
return
}
cfg.Runtime = runtime
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)
dbExecutor, err := ialpm.NewExecutor(run.PacmanConf, run.Logger.Child("db"))
if err != nil {
if str := err.Error(); str != "" {
text.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)
fallbackLog.Errorln(str)
}
ret = 1
@ -151,19 +122,18 @@ func main() {
defer func() {
if rec := recover(); rec != nil {
text.Errorln(rec)
debug.PrintStack()
fallbackLog.Errorln(rec, string(debug.Stack()))
}
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 != "" {
text.Errorln(str)
fallbackLog.Errorln(str)
if cmdArgs.ExistsArg("c") && cmdArgs.ExistsArg("y") && cmdArgs.Op == "S" {
// 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/dep"
"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/text"
@ -17,44 +18,45 @@ import (
"github.com/pkg/errors"
)
func handleCmd() error {
config, err := settings.NewConfig(settings.GetConfigPath(), "")
func handleCmd(logger *text.Logger) error {
cfg, err := settings.NewConfig(logger, settings.GetConfigPath(), "")
if err != nil {
return err
}
cmdArgs := parser.MakeArguments()
if errP := config.ParseCommandLine(cmdArgs); errP != nil {
if errP := cfg.ParseCommandLine(cmdArgs); errP != nil {
return errP
}
pacmanConf, _, err := settings.RetrievePacmanConfig(cmdArgs, config.PacmanConf)
run, err := runtime.NewRuntime(cfg, cmdArgs, "1.0.0")
if err != nil {
return err
}
dbExecutor, err := ialpm.NewExecutor(pacmanConf, text.GlobalLogger)
dbExecutor, err := ialpm.NewExecutor(run.PacmanConf, logger)
if err != nil {
return err
}
aurCache, err := metadata.New(
metadata.WithCacheFilePath(
filepath.Join(config.BuildDir, "aur.json")))
filepath.Join(cfg.BuildDir, "aur.json")))
if err != nil {
return errors.Wrap(err, gotext.Get("failed to retrieve aur Cache"))
}
grapher := dep.NewGrapher(dbExecutor, aurCache, true, settings.NoConfirm,
cmdArgs.ExistsDouble("d", "nodeps"), false, false,
config.Runtime.Logger.Child("grapher"))
run.Logger.Child("grapher"))
return graphPackage(context.Background(), grapher, cmdArgs.Targets)
}
func main() {
if err := handleCmd(); err != nil {
text.Errorln(err)
fallbackLog := text.NewLogger(os.Stdout, os.Stderr, os.Stdin, false, "fallback")
if err := handleCmd(fallbackLog); err != nil {
fallbackLog.Errorln(err)
os.Exit(1)
}
}

View File

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

View File

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

View File

@ -158,7 +158,7 @@ func TestAURPKGBUILDRepos(t *testing.T) {
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.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
}
func PKGBUILDs(dbExecutor DBSearcher, aurClient aur.QueryClient, httpClient *http.Client, targets []string,
aurURL string, mode parser.TargetMode,
func PKGBUILDs(dbExecutor DBSearcher, aurClient aur.QueryClient, httpClient *http.Client,
logger *text.Logger, targets []string, aurURL string, mode parser.TargetMode,
) (map[string][]byte, error) {
pkgbuilds := make(map[string][]byte, len(targets))
@ -96,7 +96,7 @@ func PKGBUILDs(dbExecutor DBSearcher, aurClient aur.QueryClient, httpClient *htt
for _, target := range targets {
// 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 {
continue
}
@ -136,7 +136,7 @@ func PKGBUILDs(dbExecutor DBSearcher, aurClient aur.QueryClient, httpClient *htt
}
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,
) (map[string]bool, error) {
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 {
// 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 {
continue
}
@ -184,11 +184,11 @@ func PKGBUILDRepos(ctx context.Context, dbExecutor DBSearcher, aurClient aur.Que
}
if aur {
text.OperationInfoln(
logger.OperationInfoln(
gotext.Get("(%d/%d) Downloaded PKGBUILD: %s",
progress, len(targets), text.Cyan(pkgName)))
} else {
text.OperationInfoln(
logger.OperationInfoln(
gotext.Get("(%d/%d) Downloaded PKGBUILD from ABS: %s",
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.
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, name := text.SplitDBFromName(target)
if dbName != "aur" && mode.AtLeastRepo() {
@ -239,7 +239,7 @@ func getPackageUsableName(dbExecutor DBSearcher, aurClient aur.QueryClient,
Needles: []string{name},
})
if err != nil {
text.Warnln(err)
logger.Warnln(err)
return dbName, name, true, true
}

View File

@ -5,6 +5,7 @@ package download
import (
"context"
"io"
"net/http"
"os"
"path/filepath"
@ -22,6 +23,10 @@ import (
"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 package in repo is already present
// WHEN defining package db as a target
@ -56,7 +61,7 @@ func TestPKGBUILDReposDefinedDBPull(t *testing.T) {
absPackagesDB: map[string]string{"yay": "core"},
}
cloned, err := PKGBUILDRepos(context.Background(), searcher, mockClient,
cmdBuilder,
cmdBuilder, newTestLogger(),
targets, parser.ModeAny, "https://aur.archlinux.org", dir, false)
assert.NoError(t, err)
@ -90,7 +95,7 @@ func TestPKGBUILDReposDefinedDBClone(t *testing.T) {
absPackagesDB: map[string]string{"yay": "core"},
}
cloned, err := PKGBUILDRepos(context.Background(), searcher, mockClient,
cmdBuilder,
cmdBuilder, newTestLogger(),
targets, parser.ModeAny, "https://aur.archlinux.org", dir, false)
assert.NoError(t, err)
@ -124,7 +129,7 @@ func TestPKGBUILDReposClone(t *testing.T) {
absPackagesDB: map[string]string{"yay": "core"},
}
cloned, err := PKGBUILDRepos(context.Background(), searcher, mockClient,
cmdBuilder,
cmdBuilder, newTestLogger(),
targets, parser.ModeAny, "https://aur.archlinux.org", dir, false)
assert.NoError(t, err)
@ -158,7 +163,7 @@ func TestPKGBUILDReposNotFound(t *testing.T) {
absPackagesDB: map[string]string{"yay": "core"},
}
cloned, err := PKGBUILDRepos(context.Background(), searcher, mockClient,
cmdBuilder,
cmdBuilder, newTestLogger(),
targets, parser.ModeAny, "https://aur.archlinux.org", dir, false)
assert.NoError(t, err)
@ -192,7 +197,7 @@ func TestPKGBUILDReposRepoMode(t *testing.T) {
absPackagesDB: map[string]string{"yay": "core"},
}
cloned, err := PKGBUILDRepos(context.Background(), searcher, mockClient,
cmdBuilder,
cmdBuilder, newTestLogger(),
targets, parser.ModeRepo, "https://aur.archlinux.org", dir, false)
assert.NoError(t, err)
@ -230,7 +235,7 @@ func TestPKGBUILDFull(t *testing.T) {
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)
assert.NoError(t, err)
@ -268,7 +273,7 @@ func TestPKGBUILDReposMissingAUR(t *testing.T) {
absPackagesDB: map[string]string{"yay": "core"},
}
cloned, err := PKGBUILDRepos(context.Background(), searcher, mockClient,
cmdBuilder,
cmdBuilder, newTestLogger(),
targets, parser.ModeAny, "https://aur.archlinux.org", dir, false)
assert.NoError(t, err)

View File

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

View File

@ -5,13 +5,13 @@ import (
"context"
"fmt"
"io"
"os"
"strings"
mapset "github.com/deckarep/golang-set/v2"
"github.com/leonelquinteros/gotext"
"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/exe"
"github.com/Jguer/yay/v12/pkg/text"
@ -22,7 +22,7 @@ const (
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,
) error {
var errMulti multierror.MultiError
@ -46,7 +46,7 @@ func showPkgbuildDiffs(ctx context.Context, cmdBuilder exe.ICmdBuilder,
}
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
}
@ -145,7 +145,7 @@ func updatePkgbuildSeenRef(ctx context.Context, cmdBuilder exe.ICmdBuilder, pkgb
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],
) error {
if len(pkgbuildDirsByBase) == 0 {
@ -157,23 +157,23 @@ func DiffFn(ctx context.Context, config *settings.Configuration, w io.Writer,
bases = append(bases, base)
}
toDiff, errMenu := selectionMenu(w, pkgbuildDirsByBase, bases, installed, gotext.Get("Diffs to show?"),
settings.NoConfirm, config.AnswerDiff, nil)
toDiff, errMenu := selectionMenu(run.Logger, pkgbuildDirsByBase, bases, installed, gotext.Get("Diffs to show?"),
settings.NoConfirm, run.Cfg.AnswerDiff, nil)
if errMenu != nil || len(toDiff) == 0 {
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
}
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{}
}
if errUpd := updatePkgbuildSeenRef(ctx, config.Runtime.CmdBuilder, pkgbuildDirsByBase, toDiff); errUpd != nil {
if errUpd := updatePkgbuildSeenRef(ctx, run.CmdBuilder, pkgbuildDirsByBase, toDiff); errUpd != nil {
return errUpd
}

View File

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

View File

@ -2,7 +2,6 @@ package menus
import (
"fmt"
"io"
"os"
"github.com/leonelquinteros/gotext"
@ -14,7 +13,9 @@ import (
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 := ""
for n, pkgBase := range bases {
@ -34,20 +35,20 @@ func pkgbuildNumberMenu(w io.Writer, pkgbuildDirs map[string]string, bases []str
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,
) ([]string, error) {
selected := make([]string, 0)
pkgbuildNumberMenu(w, pkgbuildDirs, bases, installed)
pkgbuildNumberMenu(logger, pkgbuildDirs, bases, installed)
text.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(message)
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 {
return nil, err
}

View File

@ -4,11 +4,9 @@ import (
"bytes"
"context"
"encoding/xml"
"fmt"
"html"
"io"
"net/http"
"os"
"strings"
"time"
@ -23,13 +21,13 @@ type item struct {
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
date, err := time.Parse(time.RFC1123Z, item.PubDate)
if err != nil {
fmt.Fprintln(os.Stderr, err)
logger.Errorln(err)
} else {
fd = text.FormatTime(int(date.Unix()))
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 {
desc := strings.TrimSpace(parseNews(item.Description))
fmt.Println(desc)
logger.Println(desc)
}
}
@ -60,7 +58,9 @@ type rss struct {
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)
if err != nil {
return err
@ -87,11 +87,11 @@ func PrintNewsFeed(ctx context.Context, client *http.Client, cutOffDate time.Tim
if bottomUp {
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 {
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"
"net/http"
"os"
"strings"
"testing"
"time"
"github.com/bradleyjkemp/cupaloy"
"github.com/stretchr/testify/assert"
"gopkg.in/h2non/gock.v1"
"github.com/Jguer/yay/v12/pkg/text"
)
const lastNews = `
@ -135,17 +138,16 @@ func TestPrintNewsFeed(t *testing.T) {
defer gock.Off()
rescueStdout := os.Stdout
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)
w.Close()
out, _ := io.ReadAll(r)
cupaloy.SnapshotT(t, out)
os.Stdout = rescueStdout
})
}
}
@ -164,15 +166,14 @@ func TestPrintNewsFeedSameDay(t *testing.T) {
defer gock.Off()
rescueStdout := os.Stdout
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)
w.Close()
out, _ := io.ReadAll(r)
cupaloy.SnapshotT(t, out)
os.Stdout = rescueStdout
}

View File

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

View File

@ -7,19 +7,19 @@ import (
"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)
for _, target := range targets {
dbName, _ := text.SplitDBFromName(target)
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
}
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
}

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) {
var aurErr error
pkgS = RemoveInvalidTargets(pkgS, s.targetMode)
pkgS = RemoveInvalidTargets(s.logger, pkgS, s.targetMode)
metric := &metrics.Hamming{
CaseSensitive: false,

View File

@ -1,4 +1,4 @@
package settings
package runtime
import (
"fmt"
@ -10,7 +10,7 @@ import (
"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 := "/"
if value, _, exists := cmdArgs.GetArg("root", "r"); exists {
root = value

View File

@ -1,7 +1,7 @@
//go:build !integration
// +build !integration
package settings
package runtime
import (
"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.NotNil(t, pacmanConf)
assert.Equal(t, color, false)

View File

@ -1,4 +1,4 @@
package settings
package runtime
import (
"context"
@ -9,8 +9,8 @@ import (
"github.com/leonelquinteros/gotext"
"github.com/Jguer/yay/v12/pkg/db"
"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/parser"
"github.com/Jguer/yay/v12/pkg/text"
@ -24,6 +24,7 @@ import (
)
type Runtime struct {
Cfg *settings.Configuration
QueryBuilder query.Builder
PacmanConf *pacmanconf.Config
VCSStore vcs.Store
@ -31,13 +32,12 @@ type Runtime struct {
HTTPClient *http.Client
VoteClient *vote.Client
AURClient aur.QueryClient
DBExecutor db.Executor
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")
cmdBuilder := cfg.CmdBuilder(nil)
runner := exe.NewOSRunner(logger.Child("runner"))
httpClient := &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
@ -86,6 +86,16 @@ func BuildRuntime(cfg *Configuration, cmdArgs *parser.Arguments, version string)
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(
cfg.VCSFilePath, cmdBuilder,
logger.Child("vcs"))
@ -94,17 +104,23 @@ func BuildRuntime(cfg *Configuration, cmdArgs *parser.Arguments, version string)
return nil, err
}
runtime := &Runtime{
QueryBuilder: nil,
PacmanConf: nil,
queryBuilder := query.NewSourceQueryBuilder(
aurClient,
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,
CmdBuilder: cmdBuilder,
HTTPClient: &http.Client{},
VoteClient: voteClient,
AURClient: aurCache,
DBExecutor: nil,
Logger: text.NewLogger(os.Stdout, os.Stderr, os.Stdin, cfg.Debug, "runtime"),
Logger: logger,
}
return runtime, nil
return run, nil
}

View File

@ -1,16 +1,17 @@
//go:build !integration
// +build !integration
package settings_test
package runtime_test
import (
"testing"
"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/parser"
"github.com/Jguer/yay/v12/pkg/text"
)
func TestBuildRuntime(t *testing.T) {
@ -23,24 +24,23 @@ func TestBuildRuntime(t *testing.T) {
AURRPCURL: "https://aur.archlinux.org/rpc",
BuildDir: "/tmp",
VCSFilePath: "",
Runtime: &settings.Runtime{Logger: text.NewLogger(nil, nil, nil, false, "")},
PacmanConf: "../../testdata/pacman.conf",
}
cmdArgs := parser.MakeArguments()
version := "1.0.0"
// 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.NotNil(t, runtime)
assert.Nil(t, err)
assert.Nil(t, runtime.QueryBuilder)
assert.Nil(t, runtime.PacmanConf)
assert.NotNil(t, runtime.VCSStore)
assert.NotNil(t, runtime.CmdBuilder)
assert.NotNil(t, runtime.HTTPClient)
assert.NotNil(t, runtime.VoteClient)
assert.NotNil(t, runtime.AURClient)
assert.Nil(t, runtime.DBExecutor)
assert.NotNil(t, runtime.Logger)
assert.NotNil(t, run)
assert.NotNil(t, run.QueryBuilder)
assert.NotNil(t, run.PacmanConf)
assert.NotNil(t, run.VCSStore)
assert.NotNil(t, run.CmdBuilder)
assert.NotNil(t, run.HTTPClient)
assert.NotNil(t, run.VoteClient)
assert.NotNil(t, run.AURClient)
assert.NotNil(t, run.Logger)
}

View File

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

View File

@ -9,7 +9,6 @@ import (
"path/filepath"
"strings"
"github.com/Jguer/yay/v12/pkg/settings/exe"
"github.com/Jguer/yay/v12/pkg/settings/parser"
"github.com/Jguer/yay/v12/pkg/text"
@ -24,53 +23,52 @@ var NoConfirm = false
// Configuration stores yay's config.
type Configuration struct {
Runtime *Runtime `json:"-"`
AURURL string `json:"aururl"`
AURRPCURL string `json:"aurrpcurl"`
BuildDir string `json:"buildDir"`
Editor string `json:"editor"`
EditorFlags string `json:"editorflags"`
MakepkgBin string `json:"makepkgbin"`
MakepkgConf string `json:"makepkgconf"`
PacmanBin string `json:"pacmanbin"`
PacmanConf string `json:"pacmanconf"`
ReDownload string `json:"redownload"`
AnswerClean string `json:"answerclean"`
AnswerDiff string `json:"answerdiff"`
AnswerEdit string `json:"answeredit"`
AnswerUpgrade string `json:"answerupgrade"`
GitBin string `json:"gitbin"`
GpgBin string `json:"gpgbin"`
GpgFlags string `json:"gpgflags"`
MFlags string `json:"mflags"`
SortBy string `json:"sortby"`
SearchBy string `json:"searchby"`
GitFlags string `json:"gitflags"`
RemoveMake string `json:"removemake"`
SudoBin string `json:"sudobin"`
SudoFlags string `json:"sudoflags"`
Version string `json:"version"`
RequestSplitN int `json:"requestsplitn"`
CompletionInterval int `json:"completionrefreshtime"`
MaxConcurrentDownloads int `json:"maxconcurrentdownloads"`
BottomUp bool `json:"bottomup"`
SudoLoop bool `json:"sudoloop"`
TimeUpdate bool `json:"timeupdate"`
Devel bool `json:"devel"`
CleanAfter bool `json:"cleanAfter"`
Provides bool `json:"provides"`
PGPFetch bool `json:"pgpfetch"`
CleanMenu bool `json:"cleanmenu"`
DiffMenu bool `json:"diffmenu"`
EditMenu bool `json:"editmenu"`
CombinedUpgrade bool `json:"combinedupgrade"`
UseAsk bool `json:"useask"`
BatchInstall bool `json:"batchinstall"`
SingleLineResults bool `json:"singlelineresults"`
SeparateSources bool `json:"separatesources"`
Debug bool `json:"debug"`
UseRPC bool `json:"rpc"`
DoubleConfirm bool `json:"doubleconfirm"` // confirm install before and after build
AURURL string `json:"aururl"`
AURRPCURL string `json:"aurrpcurl"`
BuildDir string `json:"buildDir"`
Editor string `json:"editor"`
EditorFlags string `json:"editorflags"`
MakepkgBin string `json:"makepkgbin"`
MakepkgConf string `json:"makepkgconf"`
PacmanBin string `json:"pacmanbin"`
PacmanConf string `json:"pacmanconf"`
ReDownload string `json:"redownload"`
AnswerClean string `json:"answerclean"`
AnswerDiff string `json:"answerdiff"`
AnswerEdit string `json:"answeredit"`
AnswerUpgrade string `json:"answerupgrade"`
GitBin string `json:"gitbin"`
GpgBin string `json:"gpgbin"`
GpgFlags string `json:"gpgflags"`
MFlags string `json:"mflags"`
SortBy string `json:"sortby"`
SearchBy string `json:"searchby"`
GitFlags string `json:"gitflags"`
RemoveMake string `json:"removemake"`
SudoBin string `json:"sudobin"`
SudoFlags string `json:"sudoflags"`
Version string `json:"version"`
RequestSplitN int `json:"requestsplitn"`
CompletionInterval int `json:"completionrefreshtime"`
MaxConcurrentDownloads int `json:"maxconcurrentdownloads"`
BottomUp bool `json:"bottomup"`
SudoLoop bool `json:"sudoloop"`
TimeUpdate bool `json:"timeupdate"`
Devel bool `json:"devel"`
CleanAfter bool `json:"cleanAfter"`
Provides bool `json:"provides"`
PGPFetch bool `json:"pgpfetch"`
CleanMenu bool `json:"cleanmenu"`
DiffMenu bool `json:"diffmenu"`
EditMenu bool `json:"editmenu"`
CombinedUpgrade bool `json:"combinedupgrade"`
UseAsk bool `json:"useask"`
BatchInstall bool `json:"batchinstall"`
SingleLineResults bool `json:"singlelineresults"`
SeparateSources bool `json:"separatesources"`
Debug bool `json:"debug"`
UseRPC bool `json:"rpc"`
DoubleConfirm bool `json:"doubleconfirm"` // confirm install before and after build
CompletionPath string `json:"-"`
VCSFilePath string `json:"-"`
@ -237,19 +235,16 @@ func DefaultConfig(version string) *Configuration {
Debug: false,
UseRPC: true,
DoubleConfirm: true,
Runtime: &Runtime{
Logger: text.GlobalLogger,
},
Mode: parser.ModeAny,
Mode: parser.ModeAny,
}
}
func NewConfig(configPath, version string) (*Configuration, error) {
func NewConfig(logger *text.Logger, configPath, version string) (*Configuration, error) {
newConfig := DefaultConfig(version)
cacheHome, errCache := getCacheHome()
if errCache != nil {
text.Errorln(errCache)
if errCache != nil && logger != nil {
logger.Errorln(errCache)
}
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))
assert.NoError(t, err)
newConfig, err := NewConfig(GetConfigPath(), "v1.0.0")
newConfig, err := NewConfig(nil, GetConfigPath(), "v1.0.0")
assert.NoError(t, err)
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))
assert.NoError(t, err)
newConfig, err := NewConfig(GetConfigPath(), "v1.0.0")
newConfig, err := NewConfig(nil, GetConfigPath(), "v1.0.0")
assert.NoError(t, err)
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))
assert.NoError(t, err)
newConfig, err := NewConfig(GetConfigPath(), "v1.0.0")
newConfig, err := NewConfig(nil, GetConfigPath(), "v1.0.0")
assert.NoError(t, err)
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"
"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/text"
)
@ -38,7 +39,6 @@ type ICmdBuilder interface {
BuildMakepkgCmd(ctx context.Context, dir string, extraArgs ...string) *exec.Cmd
BuildPacmanCmd(ctx context.Context, args *parser.Arguments, mode parser.TargetMode, noConfirm bool) *exec.Cmd
AddMakepkgFlag(string)
SetPacmanDBPath(string)
SudoLoop()
}
@ -60,6 +60,26 @@ type CmdBuilder struct {
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 {
args := make([]string, len(c.GPGFlags), len(c.GPGFlags)+len(extraArgs))
copy(args, c.GPGFlags)
@ -135,10 +155,6 @@ func (c *CmdBuilder) BuildMakepkgCmd(ctx context.Context, dir string, extraArgs
return cmd
}
func (c *CmdBuilder) SetPacmanDBPath(dbPath string) {
c.PacmanDBPath = dbPath
}
// deElevateCommand, `systemd-run` code based on pikaur.
func (c *CmdBuilder) deElevateCommand(ctx context.Context, cmd *exec.Cmd) *exec.Cmd {
if os.Geteuid() != 0 {
@ -242,7 +258,7 @@ func (c *CmdBuilder) waitLock(dbPath string) {
time.Sleep(3 * time.Second)
if _, err := os.Stat(lockDBPath); err != nil {
fmt.Println()
c.Log.Println()
return
}

View File

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

View File

@ -36,6 +36,10 @@ type MockRunner struct {
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 {
var res *exec.Cmd
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,
) error {
saveConfig := false
@ -53,7 +53,7 @@ func (c *Configuration) RunMigrations(migrations []configMigration,
for _, migration := range migrations {
if db.VerCmp(migration.TargetVersion(), c.Version) > 0 {
if migration.Do(c) {
text.Infoln("Config migration executed (",
logger.Infoln("Config migration executed (",
migration.TargetVersion(), "):", migration)
saveConfig = true

View File

@ -16,6 +16,10 @@ import (
"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) {
t.Parallel()
// Create temporary file for config
@ -28,13 +32,10 @@ func TestMigrationNothingToDo(t *testing.T) {
config := Configuration{
Version: "99.0.0",
// Create runtime with runtimeVersion
Runtime: &Runtime{
Logger: text.NewLogger(io.Discard, io.Discard, strings.NewReader(""), false, "test"),
},
}
// Run Migration
err = config.RunMigrations(DefaultMigrations(), testFilePath, "20.0.0")
err = config.RunMigrations(newTestLogger(), DefaultMigrations(), testFilePath, "20.0.0")
require.NoError(t, err)
// Check file contents if wantSave otherwise check file empty
@ -53,9 +54,6 @@ func TestProvidesMigrationDo(t *testing.T) {
migration := &configProviderMigration{}
config := Configuration{
Provides: true,
Runtime: &Runtime{
Logger: text.NewLogger(io.Discard, io.Discard, strings.NewReader(""), false, "test"),
},
}
assert.True(t, migration.Do(&config))
@ -135,13 +133,10 @@ func TestProvidesMigration(t *testing.T) {
Version: tc.testConfig.Version,
Provides: tc.testConfig.Provides,
// Create runtime with runtimeVersion
Runtime: &Runtime{
Logger: text.NewLogger(io.Discard, io.Discard, strings.NewReader(""), false, "test"),
},
}
// Run Migration
err = tcConfig.RunMigrations(
err = tcConfig.RunMigrations(newTestLogger(),
[]configMigration{&configProviderMigration{}},
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 (
"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 {
return nil
return installer.failedAndIgnored, nil
}
return &FailedIgnoredPkgError{
return installer.failedAndIgnored, &FailedIgnoredPkgError{
pkgErrors: installer.failedAndIgnored,
}
}
@ -234,12 +234,12 @@ func (installer *Installer) installAURPackages(ctx context.Context,
}
installer.failedAndIgnored[name] = errMake
text.Errorln(gotext.Get("error making: %s", base), "-", errMake)
installer.log.Errorln(gotext.Get("error making: %s", base), "-", errMake)
continue
}
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
}
@ -298,10 +298,10 @@ func (installer *Installer) buildPkg(ctx context.Context,
case needed && installer.pkgsAreAlreadyInstalled(pkgdests, pkgVersion) || installer.downloadOnly:
args = []string{"-c", "--nobuild", "--noextract", "--ignorearch"}
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):
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:
args = []string{"-cf", "--noconfirm", "--noextract", "--noprepare", "--holdver"}
if installIncompatible {
@ -333,10 +333,10 @@ func (installer *Installer) pkgsAreAlreadyInstalled(pkgdests map[string]string,
return true
}
func pkgsAreBuilt(pkgdests map[string]string) bool {
func pkgsAreBuilt(logger *text.Logger, pkgdests map[string]string) bool {
for _, pkgdest := range pkgdests {
if _, err := os.Stat(pkgdest); err != nil {
text.Debugln("pkgIsBuilt:", pkgdest, "does not exist")
logger.Debugln("pkgIsBuilt:", pkgdest, "does not exist")
return false
}
}
@ -347,14 +347,14 @@ func pkgsAreBuilt(pkgdests map[string]string) bool {
func (installer *Installer) skipAlreadyBuiltPkg(isTarget bool, pkgdests map[string]string) bool {
switch installer.rebuildMode {
case parser.RebuildModeNo:
return pkgsAreBuilt(pkgdests)
return pkgsAreBuilt(installer.log, pkgdests)
case parser.RebuildModeYes:
return !isTarget && pkgsAreBuilt(pkgdests)
return !isTarget && pkgsAreBuilt(installer.log, pkgdests)
// case parser.RebuildModeTree: // TODO
// case parser.RebuildModeAll: // TODO
default:
// same as RebuildModeNo
return pkgsAreBuilt(pkgdests)
return pkgsAreBuilt(installer.log, pkgdests)
}
}

View File

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

View File

@ -1,4 +1,4 @@
package main
package build
import (
"context"
@ -16,164 +16,6 @@ import (
"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,
cmdBuilder exe.ICmdBuilder,
mode parser.TargetMode,
@ -228,3 +70,95 @@ func setInstallReason(ctx context.Context,
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"
"context"
"errors"
"fmt"
"os"
"os/exec"
"strings"
@ -50,7 +48,7 @@ type GPGCmdBuilder interface {
// CheckPgpKeys iterates through the keys listed in the PKGBUILDs and if needed,
// 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,
) ([]string, error) {
// 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
}
str, err := formatKeysToImport(problematic)
str, err := formatKeysToImport(logger, problematic)
if err != nil {
return nil, err
}
fmt.Println()
fmt.Println(str)
logger.Println("\n", str)
if text.ContinueTask(os.Stdin, gotext.Get("Import?"), true, noConfirm) {
return problematic.toSlice(), importKeys(ctx, cmdBuilder, problematic.toSlice())
if logger.ContinueTask(gotext.Get("Import?"), true, noConfirm) {
return problematic.toSlice(), importKeys(ctx, logger, cmdBuilder, problematic.toSlice())
}
return problematic.toSlice(), nil
}
// importKeys tries to import the list of keys specified in its argument.
func importKeys(ctx context.Context, cmdBuilder GPGCmdBuilder, keys []string) error {
text.OperationInfoln(gotext.Get("Importing keys with gpg..."))
func importKeys(ctx context.Context, logger *text.Logger, cmdBuilder GPGCmdBuilder, keys []string) error {
logger.OperationInfoln(gotext.Get("Importing keys with gpg..."))
if err := cmdBuilder.Show(cmdBuilder.BuildGPGCmd(ctx, append([]string{"--recv-keys"}, keys...)...)); err != nil {
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
// 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 {
return "", errors.New(gotext.Get("no keys to import"))
}
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 {
pkglist := ""
@ -124,7 +121,7 @@ func formatKeysToImport(keys pgpKeySet) (string, error) {
}
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

View File

@ -6,6 +6,7 @@ package pgp
import (
"context"
"fmt"
"io"
"os"
"os/exec"
"sort"
@ -17,8 +18,13 @@ import (
"github.com/stretchr/testify/require"
"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 {
srcinfo := gosrc.Srcinfo{}
srcinfo.Pkgbase = pkgbase
@ -228,7 +234,7 @@ func TestCheckPgpKeys(t *testing.T) {
GPGFlags: []string{"--homedir /tmp"},
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.CaptureCalls, len(tt.wantCapture))

View File

@ -11,28 +11,28 @@ import (
"github.com/Jguer/yay/v12/pkg/db"
"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/exe"
"github.com/Jguer/yay/v12/pkg/sync/srcinfo/pgp"
"github.com/Jguer/yay/v12/pkg/text"
"github.com/Jguer/yay/v12/pkg/vcs"
)
// TODO: add tests
type Service struct {
dbExecutor db.Executor
cfg *settings.Configuration
cmdBuilder exe.ICmdBuilder
cmdBuilder pgp.GPGCmdBuilder
vcsStore vcs.Store
log *text.Logger
pkgBuildDirs map[string]string
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,
) (*Service, error) {
srcinfos, err := ParseSrcinfoFilesByBase(pkgBuildDirs, true)
srcinfos, err := ParseSrcinfoFilesByBase(logger, pkgBuildDirs, true)
if err != nil {
panic(err)
}
@ -43,6 +43,7 @@ func NewService(dbExecutor db.Executor, cfg *settings.Configuration,
vcsStore: vcsStore,
pkgBuildDirs: pkgBuildDirs,
srcInfos: srcinfos,
log: logger,
}, nil
}
@ -68,7 +69,7 @@ nextpkg:
}
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
}
@ -83,15 +84,15 @@ func (s *Service) UpdateVCSStore(ctx context.Context, targets []map[string]*dep.
for i := range srcinfo.Packages {
for j := range targets {
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
}
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
}
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)
}
}
@ -100,17 +101,17 @@ func (s *Service) UpdateVCSStore(ctx context.Context, targets []map[string]*dep.
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)
k := 0
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"))
if err != nil {
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
}

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 (
"context"

View File

@ -1,7 +1,7 @@
//go:build !integration
// +build !integration
package main
package workdir
import (
"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 (
"context"
@ -12,9 +12,11 @@ import (
"github.com/Jguer/yay/v12/pkg/dep"
"github.com/Jguer/yay/v12/pkg/download"
"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/exe"
"github.com/Jguer/yay/v12/pkg/settings/parser"
"github.com/Jguer/yay/v12/pkg/sync/build"
"github.com/Jguer/yay/v12/pkg/text"
gosrc "github.com/Morganamilo/go-srcinfo"
@ -29,7 +31,7 @@ const (
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],
) error
@ -45,12 +47,13 @@ type Preparer struct {
cfg *settings.Configuration
hooks []Hook
downloadSources bool
log *text.Logger
makeDeps []string
}
func NewPreparerWithoutHooks(dbExecutor db.Executor, cmdBuilder exe.ICmdBuilder,
cfg *settings.Configuration, downloadSources bool,
cfg *settings.Configuration, logger *text.Logger, downloadSources bool,
) *Preparer {
return &Preparer{
dbExecutor: dbExecutor,
@ -58,13 +61,14 @@ func NewPreparerWithoutHooks(dbExecutor db.Executor, cmdBuilder exe.ICmdBuilder,
cfg: cfg,
hooks: []Hook{},
downloadSources: downloadSources,
log: logger,
}
}
func NewPreparer(dbExecutor db.Executor, cmdBuilder exe.ICmdBuilder,
cfg *settings.Configuration,
cfg *settings.Configuration, logger *text.Logger,
) *Preparer {
preper := NewPreparerWithoutHooks(dbExecutor, cmdBuilder, cfg, true)
preper := NewPreparerWithoutHooks(dbExecutor, cmdBuilder, cfg, logger, true)
if cfg.CleanMenu {
preper.hooks = append(preper.hooks, Hook{
@ -93,20 +97,20 @@ func NewPreparer(dbExecutor db.Executor, cmdBuilder exe.ICmdBuilder,
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 {
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 {
cleanAfter(ctx, preper.cfg, preper.cfg.Runtime.CmdBuilder, pkgBuildDirs)
cleanAfter(ctx, run, run.CmdBuilder, pkgBuildDirs)
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 {
return nil
}
@ -118,25 +122,25 @@ func (preper *Preparer) ShouldCleanMakeDeps(cmdArgs *parser.Arguments) PostInsta
return nil
default:
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) {
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 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,
w io.Writer, targets []map[string]*dep.InstallInfo,
func (preper *Preparer) Run(ctx context.Context, run *runtime.Runtime,
targets []map[string]*dep.InstallInfo,
) (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 {
return nil, err
}
@ -144,7 +148,7 @@ func (preper *Preparer) Run(ctx context.Context,
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{}
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 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,
reason,
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]()
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,
preper.cmdBuilder, aurBasesToClone.ToSlice(),
preper.cmdBuilder, preper.log.Child("download"), aurBasesToClone.ToSlice(),
preper.cfg.AURURL, preper.cfg.BuildDir, false); errA != nil {
return nil, errA
}
@ -220,7 +226,7 @@ func (preper *Preparer) PrepareWorkspace(ctx context.Context, targets []map[stri
remoteNamesCache := mapset.NewThreadUnsafeSet(remoteNames...)
for _, hookFn := range preper.hooks {
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
}
}
@ -228,7 +234,7 @@ func (preper *Preparer) PrepareWorkspace(ctx context.Context, targets []map[stri
if errP := downloadPKGBUILDSourceFanout(ctx, preper.cmdBuilder,
pkgBuildDirsByBase, false, preper.cfg.MaxConcurrentDownloads); errP != nil {
text.Errorln(errP)
preper.log.Errorln(errP)
}
return pkgBuildDirsByBase, nil
@ -242,7 +248,7 @@ func (preper *Preparer) needToCloneAURBase(installInfo *dep.InstallInfo, pkgbuil
srcinfoFile := filepath.Join(pkgbuildDir, ".SRCINFO")
if pkgbuild, err := gosrc.ParseFile(srcinfoFile); err == nil {
if db.VerCmp(pkgbuild.Version(), installInfo.Version) >= 0 {
text.OperationInfoln(
preper.log.OperationInfoln(
gotext.Get("PKGBUILD up to date, skipping download: %s",
text.Cyan(*installInfo.AURBase)))
return false

View File

@ -1,16 +1,23 @@
//go:build !integration
// +build !integration
package main
package workdir
import (
"io"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"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
func TestPreDownloadSourcesHooks(t *testing.T) {
testCases := []struct {
@ -49,7 +56,7 @@ func TestPreDownloadSourcesHooks(t *testing.T) {
for _, tc := range testCases {
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))

View File

@ -3,14 +3,18 @@ package text
import (
"bufio"
"fmt"
"io"
"strings"
"unicode"
"unicode/utf8"
"github.com/leonelquinteros/gotext"
)
func (l *Logger) GetInput(defaultValue string, noConfirm bool) (string, error) {
Info()
l.Info()
if defaultValue != "" || noConfirm {
fmt.Println(defaultValue)
l.Println(defaultValue)
return defaultValue, nil
}
@ -28,6 +32,48 @@ func (l *Logger) GetInput(defaultValue string, noConfirm bool) (string, error) {
return string(buf), nil
}
func GetInput(r io.Reader, defaultValue string, noConfirm bool) (string, error) {
return GlobalLogger.GetInput(defaultValue, noConfirm)
// ContinueTask prompts if user wants to continue task.
// 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"
)
const (
arrow = "==>"
smallArrow = " ->"
opSymbol = "::"
)
type Logger struct {
name string
Debug bool

View File

@ -1,13 +1,8 @@
package text
import (
"fmt"
"io"
"strings"
"unicode"
"unicode/utf8"
"github.com/leonelquinteros/gotext"
)
const (
@ -52,49 +47,3 @@ func LessRunes(iRunes, jRunes []rune) bool {
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
import (
"io"
"os"
"path"
"strings"
@ -74,7 +75,8 @@ func TestContinueTask(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
// create io.Reader with value of 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)
})
}
@ -120,7 +122,8 @@ msgstr "да"
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
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)
})
}
@ -168,7 +171,8 @@ msgstr "ja"
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
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)
})
}

View File

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

184
print.go
View File

@ -6,14 +6,19 @@ import (
"io"
"os"
"strconv"
"strings"
"syscall"
"unicode"
aur "github.com/Jguer/aur"
mapset "github.com/deckarep/golang-set/v2"
"github.com/leonelquinteros/gotext"
"golang.org/x/sys/unix"
"github.com/Jguer/yay/v12/pkg/db"
"github.com/Jguer/yay/v12/pkg/dep"
"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/parser"
"github.com/Jguer/yay/v12/pkg/text"
@ -21,47 +26,47 @@ import (
)
// printInfo prints package info like pacman -Si.
func printInfo(config *settings.Configuration, a *aur.Pkg, extendedInfo bool) {
text.PrintInfoValue(gotext.Get("Repository"), "aur")
text.PrintInfoValue(gotext.Get("Name"), a.Name)
text.PrintInfoValue(gotext.Get("Version"), a.Version)
text.PrintInfoValue(gotext.Get("Description"), a.Description)
text.PrintInfoValue(gotext.Get("URL"), a.URL)
text.PrintInfoValue(gotext.Get("Licenses"), a.License...)
text.PrintInfoValue(gotext.Get("Groups"), a.Groups...)
text.PrintInfoValue(gotext.Get("Provides"), a.Provides...)
text.PrintInfoValue(gotext.Get("Depends On"), a.Depends...)
text.PrintInfoValue(gotext.Get("Optional Deps"), a.OptDepends...)
text.PrintInfoValue(gotext.Get("Make Deps"), a.MakeDepends...)
text.PrintInfoValue(gotext.Get("Check Deps"), a.CheckDepends...)
text.PrintInfoValue(gotext.Get("Conflicts With"), a.Conflicts...)
text.PrintInfoValue(gotext.Get("Replaces"), a.Replaces...)
text.PrintInfoValue(gotext.Get("AUR URL"), config.AURURL+"/packages/"+a.Name)
text.PrintInfoValue(gotext.Get("First Submitted"), text.FormatTimeQuery(a.FirstSubmitted))
text.PrintInfoValue(gotext.Get("Keywords"), a.Keywords...)
text.PrintInfoValue(gotext.Get("Last Modified"), text.FormatTimeQuery(a.LastModified))
text.PrintInfoValue(gotext.Get("Maintainer"), a.Maintainer)
text.PrintInfoValue(gotext.Get("Popularity"), fmt.Sprintf("%f", a.Popularity))
text.PrintInfoValue(gotext.Get("Votes"), fmt.Sprintf("%d", a.NumVotes))
func printInfo(logger *text.Logger, config *settings.Configuration, a *aur.Pkg, extendedInfo bool) {
printInfoValue(logger, gotext.Get("Repository"), "aur")
printInfoValue(logger, gotext.Get("Name"), a.Name)
printInfoValue(logger, gotext.Get("Version"), a.Version)
printInfoValue(logger, gotext.Get("Description"), a.Description)
printInfoValue(logger, gotext.Get("URL"), a.URL)
printInfoValue(logger, gotext.Get("Licenses"), a.License...)
printInfoValue(logger, gotext.Get("Groups"), a.Groups...)
printInfoValue(logger, gotext.Get("Provides"), a.Provides...)
printInfoValue(logger, gotext.Get("Depends On"), a.Depends...)
printInfoValue(logger, gotext.Get("Optional Deps"), a.OptDepends...)
printInfoValue(logger, gotext.Get("Make Deps"), a.MakeDepends...)
printInfoValue(logger, gotext.Get("Check Deps"), a.CheckDepends...)
printInfoValue(logger, gotext.Get("Conflicts With"), a.Conflicts...)
printInfoValue(logger, gotext.Get("Replaces"), a.Replaces...)
printInfoValue(logger, gotext.Get("AUR URL"), config.AURURL+"/packages/"+a.Name)
printInfoValue(logger, gotext.Get("First Submitted"), text.FormatTimeQuery(a.FirstSubmitted))
printInfoValue(logger, gotext.Get("Keywords"), a.Keywords...)
printInfoValue(logger, gotext.Get("Last Modified"), text.FormatTimeQuery(a.LastModified))
printInfoValue(logger, gotext.Get("Maintainer"), a.Maintainer)
printInfoValue(logger, gotext.Get("Popularity"), fmt.Sprintf("%f", a.Popularity))
printInfoValue(logger, gotext.Get("Votes"), fmt.Sprintf("%d", a.NumVotes))
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 {
text.PrintInfoValue(gotext.Get("Out-of-date"), "No")
printInfoValue(logger, gotext.Get("Out-of-date"), "No")
}
if extendedInfo {
text.PrintInfoValue("ID", fmt.Sprintf("%d", a.ID))
text.PrintInfoValue(gotext.Get("Package Base ID"), fmt.Sprintf("%d", a.PackageBaseID))
text.PrintInfoValue(gotext.Get("Package Base"), a.PackageBase)
text.PrintInfoValue(gotext.Get("Snapshot URL"), config.AURURL+a.URLPath)
printInfoValue(logger, "ID", fmt.Sprintf("%d", a.ID))
printInfoValue(logger, gotext.Get("Package Base ID"), fmt.Sprintf("%d", a.PackageBaseID))
printInfoValue(logger, gotext.Get("Package Base"), a.PackageBase)
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.
func biggestPackages(dbExecutor db.Executor) {
func biggestPackages(logger *text.Logger, dbExecutor db.Executor) {
pkgS := dbExecutor.BiggestPackages()
if len(pkgS) < 10 {
@ -69,34 +74,34 @@ func biggestPackages(dbExecutor db.Executor) {
}
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.
func localStatistics(ctx context.Context, cfg *settings.Configuration, dbExecutor db.Executor) error {
info := statistics(cfg, dbExecutor)
func localStatistics(ctx context.Context, run *runtime.Runtime, dbExecutor db.Executor) error {
info := statistics(run, dbExecutor)
remoteNames := dbExecutor.InstalledRemotePackageNames()
remote := dbExecutor.InstalledRemotePackages()
text.Infoln(gotext.Get("Yay version v%s", yayVersion))
fmt.Println(text.Bold(text.Cyan("===========================================")))
text.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)))))
text.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("Yay version v%s", yayVersion))
run.Logger.Println(text.Bold(text.Cyan("===========================================")))
run.Logger.Infoln(gotext.Get("Total installed packages: %s", text.Cyan(strconv.Itoa(info.Totaln))))
run.Logger.Infoln(gotext.Get("Foreign installed packages: %s", text.Cyan(strconv.Itoa(len(remoteNames)))))
run.Logger.Infoln(gotext.Get("Explicitly installed packages: %s", text.Cyan(strconv.Itoa(info.Expln))))
run.Logger.Infoln(gotext.Get("Total Size occupied by packages: %s", text.Cyan(text.Human(info.TotalSize))))
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))))
fmt.Println(text.Bold(text.Cyan("===========================================")))
text.Infoln(gotext.Get("Ten biggest packages:"))
biggestPackages(dbExecutor)
fmt.Println(text.Bold(text.Cyan("===========================================")))
run.Logger.Infoln(gotext.Get("Size of yay cache %s: %s", run.Cfg.BuildDir, text.Cyan(text.Human(info.yayCache))))
run.Logger.Println(text.Bold(text.Cyan("===========================================")))
run.Logger.Infoln(gotext.Get("Ten biggest packages:"))
biggestPackages(run.Logger, dbExecutor)
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,
By: aur.Name,
})
@ -104,7 +109,7 @@ func localStatistics(ctx context.Context, cfg *settings.Configuration, dbExecuto
return err
}
warnings := query.NewWarnings(cfg.Runtime.Logger.Child("print"))
warnings := query.NewWarnings(run.Logger.Child("warnings"))
for i := range aurData {
warnings.AddToWarnings(remote, &aurData[i])
}
@ -114,13 +119,13 @@ func localStatistics(ctx context.Context, cfg *settings.Configuration, dbExecuto
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,
) error {
quietMode := cmdArgs.ExistsArg("q", "quiet")
// 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"))
oldNoConfirm := settings.NoConfirm
settings.NoConfirm = true
@ -128,12 +133,12 @@ func printUpdateList(ctx context.Context, cfg *settings.Configuration, cmdArgs *
defer func() { settings.NoConfirm = oldNoConfirm }()
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"))
upService := upgrade.NewUpgradeService(
grapher, cfg.Runtime.AURClient, dbExecutor, cfg.Runtime.VCSStore,
cfg, true, logger.Child("upgrade"))
grapher, run.AURClient, dbExecutor, run.VCSStore,
run.Cfg, true, logger.Child("upgrade"))
graph, errSysUp := upService.GraphUpgrades(ctx, nil,
enableDowngrade, filter)
@ -163,9 +168,9 @@ func printUpdateList(ctx context.Context, cfg *settings.Configuration, cmdArgs *
}
if quietMode {
fmt.Printf("%s\n", pkgName)
run.Logger.Printf("%s\n", pkgName)
} 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)))
}
@ -179,7 +184,7 @@ func printUpdateList(ctx context.Context, cfg *settings.Configuration, cmdArgs *
missing := false
targets.Each(func(pkgName string) bool {
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
}
return false
@ -191,3 +196,72 @@ func printUpdateList(ctx context.Context, cfg *settings.Configuration, cmdArgs *
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/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/exe"
"github.com/Jguer/yay/v12/pkg/settings/parser"
@ -271,29 +272,28 @@ func TestPrintUpdateList(t *testing.T) {
SudoLoopEnabled: false,
}
cfg := &settings.Configuration{
RemoveMake: "no",
Runtime: &settings.Runtime{
Logger: NewTestLogger(),
CmdBuilder: cmdBuilder,
VCSStore: &vcs.Mock{},
AURClient: tc.mockData.aurCache,
r, w, _ := os.Pipe()
logger := text.NewLogger(w, io.Discard, strings.NewReader(""), true, "test")
run := &runtime.Runtime{
Cfg: &settings.Configuration{
RemoveMake: "no",
},
Logger: logger,
CmdBuilder: cmdBuilder,
VCSStore: &vcs.Mock{},
AURClient: tc.mockData.aurCache,
}
cmdArgs := parser.MakeArguments()
cmdArgs.AddArg(tc.args...)
cmdArgs.AddTarget(tc.targets...)
rescueStdout := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w
err = handleCmd(context.Background(), cfg, cmdArgs, tc.mockData.db)
err = handleCmd(context.Background(), run, cmdArgs, tc.mockData.db)
w.Close()
out, _ := io.ReadAll(r)
os.Stdout = rescueStdout
if tc.wantErr {
require.Error(t, err)

View File

@ -12,6 +12,7 @@ import (
"github.com/Jguer/yay/v12/pkg/db"
"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/parser"
"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.
func syncInfo(ctx context.Context, cfg *settings.Configuration,
func syncInfo(ctx context.Context, run *runtime.Runtime,
cmdArgs *parser.Arguments, pkgS []string, dbExecutor db.Executor,
) error {
var (
@ -41,8 +42,8 @@ func syncInfo(ctx context.Context, cfg *settings.Configuration,
missing = false
)
pkgS = query.RemoveInvalidTargets(pkgS, cfg.Mode)
aurS, repoS := packageSlices(pkgS, cfg, dbExecutor)
pkgS = query.RemoveInvalidTargets(run.Logger, pkgS, run.Cfg.Mode)
aurS, repoS := packageSlices(pkgS, run.Cfg, dbExecutor)
if len(aurS) != 0 {
noDB := make([]string, 0, len(aurS))
@ -52,14 +53,14 @@ func syncInfo(ctx context.Context, cfg *settings.Configuration,
noDB = append(noDB, name)
}
info, err = cfg.Runtime.AURClient.Get(ctx, &aur.Query{
info, err = run.AURClient.Get(ctx, &aur.Query{
Needles: noDB,
By: aur.Name,
})
if err != nil {
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.AddTarget(repoS...)
err = cfg.Runtime.CmdBuilder.Show(cfg.Runtime.CmdBuilder.BuildPacmanCmd(ctx,
arguments, cfg.Mode, settings.NoConfirm))
err = run.CmdBuilder.Show(run.CmdBuilder.BuildPacmanCmd(ctx,
arguments, run.Cfg.Mode, settings.NoConfirm))
if err != nil {
return err
}
@ -81,7 +82,7 @@ func syncInfo(ctx context.Context, cfg *settings.Configuration,
if len(info) != 0 {
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.
func statistics(cfg *settings.Configuration, dbExecutor db.Executor) (res struct {
func statistics(run *runtime.Runtime, dbExecutor db.Executor) (res struct {
Totaln int
Expln int
TotalSize int64
@ -238,11 +239,11 @@ func statistics(cfg *settings.Configuration, dbExecutor db.Executor) (res struct
}
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.yayCache = getFolderSize(cfg.BuildDir)
res.yayCache = getFolderSize(run.Cfg.BuildDir)
return
}

View File

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

155
sync.go
View File

@ -3,37 +3,36 @@ package main
import (
"context"
"fmt"
"os"
"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/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/exe"
"github.com/Jguer/yay/v12/pkg/settings/parser"
"github.com/Jguer/yay/v12/pkg/srcinfo"
"github.com/Jguer/yay/v12/pkg/text"
"github.com/Jguer/yay/v12/pkg/sync"
"github.com/Jguer/yay/v12/pkg/upgrade"
"github.com/leonelquinteros/gotext"
)
func syncInstall(ctx context.Context,
cfg *settings.Configuration,
run *runtime.Runtime,
cmdArgs *parser.Arguments,
dbExecutor db.Executor,
) error {
aurCache := cfg.Runtime.AURClient
aurCache := run.AURClient
refreshArg := cmdArgs.ExistsArg("y", "refresh")
noDeps := cmdArgs.ExistsArg("d", "nodeps")
noCheck := strings.Contains(cfg.MFlags, "--nocheck")
noCheck := strings.Contains(run.Cfg.MFlags, "--nocheck")
if noDeps {
cfg.Runtime.CmdBuilder.AddMakepkgFlag("-d")
run.CmdBuilder.AddMakepkgFlag("-d")
}
if refreshArg && cfg.Mode.AtLeastRepo() {
if errR := earlyRefresh(ctx, cfg, cfg.Runtime.CmdBuilder, cmdArgs); errR != nil {
if refreshArg && run.Cfg.Mode.AtLeastRepo() {
if errR := earlyRefresh(ctx, run.Cfg, run.CmdBuilder, cmdArgs); errR != nil {
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,
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)
if err != nil {
@ -57,8 +56,8 @@ func syncInstall(ctx context.Context,
var errSysUp error
upService := upgrade.NewUpgradeService(
grapher, aurCache, dbExecutor, cfg.Runtime.VCSStore,
cfg, settings.NoConfirm, cfg.Runtime.Logger.Child("upgrade"))
grapher, aurCache, dbExecutor, run.VCSStore,
run.Cfg, settings.NoConfirm, run.Logger.Child("upgrade"))
graph, errSysUp = upService.GraphUpgrades(ctx,
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{}
targets := graph.TopoSortedLayerMap(func(s string, ii *dep.InstallInfo) error {
if ii.Source == dep.Missing {
@ -88,117 +87,19 @@ func syncInstall(ctx context.Context,
return err
}
return opService.Run(ctx, cmdArgs, targets, excluded)
return opService.Run(ctx, run, cmdArgs, targets, excluded)
}
type OperationService struct {
ctx context.Context
cfg *settings.Configuration
dbExecutor db.Executor
}
func NewOperationService(ctx context.Context, cfg *settings.Configuration, dbExecutor db.Executor) *OperationService {
return &OperationService{
ctx: ctx,
cfg: cfg,
dbExecutor: dbExecutor,
}
}
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
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))
}

View File

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

23
vcs.go
View File

@ -2,7 +2,6 @@ package main
import (
"context"
"os"
"sync"
"github.com/Jguer/aur"
@ -10,9 +9,9 @@ import (
"github.com/Jguer/yay/v12/pkg/db"
"github.com/Jguer/yay/v12/pkg/dep"
"github.com/Jguer/yay/v12/pkg/settings"
"github.com/Jguer/yay/v12/pkg/srcinfo"
"github.com/Jguer/yay/v12/pkg/text"
"github.com/Jguer/yay/v12/pkg/runtime"
"github.com/Jguer/yay/v12/pkg/sync/srcinfo"
"github.com/Jguer/yay/v12/pkg/sync/workdir"
)
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.
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()
cfg.Runtime.QueryBuilder.Execute(ctx, dbExecutor, remoteNames)
info, err := cfg.Runtime.AURClient.Get(ctx, &aur.Query{
run.QueryBuilder.Execute(ctx, dbExecutor, remoteNames)
info, err := run.AURClient.Get(ctx, &aur.Query{
Needles: remoteNames,
By: aur.Name,
Contains: false,
@ -44,15 +43,15 @@ func createDevelDB(ctx context.Context, cfg *settings.Configuration, dbExecutor
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)
pkgBuildDirsByBase, err := preper.Run(ctx, os.Stdout, mapInfo)
pkgBuildDirsByBase, err := preper.Run(ctx, run, mapInfo)
if err != nil {
return err
}
srcinfos, err := srcinfo.ParseSrcinfoFilesByBase(pkgBuildDirsByBase, false)
srcinfos, err := srcinfo.ParseSrcinfoFilesByBase(run.Logger.Child("srcinfo"), pkgBuildDirsByBase, false)
if err != nil {
return err
}
@ -63,14 +62,14 @@ func createDevelDB(ctx context.Context, cfg *settings.Configuration, dbExecutor
wg.Add(1)
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()
}(i, iP)
}
}
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
}

View File

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