From cb4b57f6d860c96960d699c374bb2ca72e8e858b Mon Sep 17 00:00:00 2001 From: jguer Date: Wed, 11 Aug 2021 20:13:28 +0200 Subject: [PATCH] chore(golangci): add new linters --- .golangci.yml | 35 ++++------- clean.go | 8 ++- cmd.go | 64 +++++++++++-------- config.go | 8 ++- diff.go | 17 +++++- get.go | 14 +++-- install.go | 81 +++++++++++++++++++------ main.go | 21 ++++++- main_test.go | 2 + pkg/completion/completion.go | 19 ++++-- pkg/completion/completion_test.go | 2 + pkg/db/ialpm/alpm.go | 62 ++++++++++--------- pkg/db/ialpm/alpm_test.go | 1 + pkg/db/mock/repo.go | 6 +- pkg/dep/base.go | 6 +- pkg/dep/depCheck.go | 12 ++++ pkg/dep/depOrder.go | 8 ++- pkg/dep/depPool.go | 34 ++++++++--- pkg/download/abs_test.go | 15 ++++- pkg/download/aur.go | 3 +- pkg/download/aur_test.go | 9 ++- pkg/download/unified.go | 17 ++++-- pkg/download/unified_test.go | 8 ++- pkg/intrange/intrange.go | 25 +++++--- pkg/intrange/intrange_test.go | 11 +++- pkg/multierror/multierror.go | 8 +-- pkg/news/news.go | 29 ++++++--- pkg/news/news_test.go | 7 ++- pkg/pgp/keys.go | 15 +++-- pkg/pgp/keys_test.go | 1 + pkg/query/aur_info.go | 17 ++++-- pkg/query/aur_warnings.go | 1 + pkg/query/filter.go | 4 +- pkg/settings/config.go | 13 +++- pkg/settings/exe/cmd_builder.go | 10 ++- pkg/settings/exe/exec.go | 14 +++-- pkg/settings/parser/parser.go | 56 ++++++++++------- pkg/settings/parser/parser_test.go | 24 ++++++++ pkg/stringset/stringset.go | 12 ++-- pkg/text/color.go | 5 +- pkg/text/convert.go | 3 + pkg/text/print.go | 6 ++ pkg/text/text.go | 18 +++--- pkg/text/{test_text.go => text_test.go} | 5 ++ pkg/text/time.go | 4 +- pkg/upgrade/sources.go | 10 ++- pkg/upgrade/sources_test.go | 8 ++- pkg/upgrade/upgrade.go | 8 ++- pkg/upgrade/upgrade_test.go | 1 + pkg/vcs/vcs.go | 37 +++++++---- pkg/vcs/vcs_test.go | 13 ++++ print.go | 14 +++-- query.go | 69 ++++++++++++++------- upgrade.go | 29 +++++++-- vcs.go | 11 +++- 55 files changed, 670 insertions(+), 270 deletions(-) rename pkg/text/{test_text.go => text_test.go} (97%) diff --git a/.golangci.yml b/.golangci.yml index 8f26ea57..de89ab18 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -14,12 +14,6 @@ linters-settings: - opinionated - performance - style - disabled-checks: - - dupImport # https://github.com/go-critic/go-critic/issues/845 - - ifElseChain - - octalLiteral - - whyNoLint - - wrapperFunc gocyclo: min-complexity: 15 goimports: @@ -72,28 +66,25 @@ linters: - unused - varcheck - whitespace + - wsl + - godot - # disabled want to fix - #- scopelint - #- gomnd - #- goconst - #- gocyclo - #- funlen - #- dogsled - # disabled for now - #- godox +run: issues: - # Excluding configuration per-path, per-linter, per-text and per-source exclude-rules: - path: _test\.go linters: - - gomnd + - lll + - revive + - wsl + - govet + - godot + - errcheck + - stylecheck + - dupl + - gocritic + - gochecknoinits exclude: - - G107 - G204 - - commentedOutCode - -run: - tests: false diff --git a/clean.go b/clean.go index 40d64767..8cab3b96 100644 --- a/clean.go +++ b/clean.go @@ -17,7 +17,7 @@ import ( "github.com/Jguer/yay/v10/pkg/text" ) -// CleanDependencies removes all dangling dependencies in system +// CleanDependencies removes all dangling dependencies in system. func cleanDependencies(cmdArgs *parser.Arguments, dbExecutor db.Executor, removeOptional bool) error { hanging := hangingPackages(removeOptional, dbExecutor) if len(hanging) != 0 { @@ -27,7 +27,7 @@ func cleanDependencies(cmdArgs *parser.Arguments, dbExecutor db.Executor, remove return nil } -// CleanRemove sends a full removal command to pacman with the pkgName slice +// CleanRemove sends a full removal command to pacman with the pkgName slice. func cleanRemove(cmdArgs *parser.Arguments, pkgNames []string) error { if len(pkgNames) == 0 { return nil @@ -107,6 +107,7 @@ func cleanAUR(keepInstalled, keepCurrent, removeAll bool, dbExecutor db.Executor } cachedPackages := make([]string, 0, len(files)) + for _, file := range files { if !file.IsDir() { continue @@ -179,10 +180,12 @@ func cleanUntracked() error { if isGitRepository(dir) { if err := config.Runtime.CmdBuilder.Show(config.Runtime.CmdBuilder.BuildGitCmd(dir, "clean", "-fx")); err != nil { text.Warnln(gotext.Get("Unable to clean:"), dir) + return err } } } + return nil } @@ -217,6 +220,7 @@ func cleanBuilds(bases []dep.Base) { for i, base := range bases { dir := filepath.Join(config.BuildDir, base.Pkgbase()) text.OperationInfoln(gotext.Get("Deleting (%d/%d): %s", i+1, len(bases), text.Cyan(dir))) + if err := os.RemoveAll(dir); err != nil { fmt.Fprintln(os.Stderr, err) } diff --git a/cmd.go b/cmd.go index a86e114e..798a2950 100644 --- a/cmd.go +++ b/cmd.go @@ -12,6 +12,7 @@ import ( "github.com/Jguer/yay/v10/pkg/completion" "github.com/Jguer/yay/v10/pkg/db" + "github.com/Jguer/yay/v10/pkg/download" "github.com/Jguer/yay/v10/pkg/intrange" "github.com/Jguer/yay/v10/pkg/news" "github.com/Jguer/yay/v10/pkg/query" @@ -156,6 +157,7 @@ func handleCmd(cmdArgs *parser.Arguments, dbExecutor db.Executor) error { switch cmdArgs.Op { case "V", "version": handleVersion() + return nil case "D", "database": return config.Runtime.CmdBuilder.Show(config.Runtime.CmdBuilder.BuildPacmanCmd( @@ -191,6 +193,7 @@ func handleCmd(cmdArgs *parser.Arguments, dbExecutor db.Executor) error { // updates or their count. func getFilter(cmdArgs *parser.Arguments) (upgrade.Filter, error) { deps, explicit := cmdArgs.ExistsArg("d", "deps"), cmdArgs.ExistsArg("e", "explicit") + switch { case deps && explicit: return nil, fmt.Errorf(gotext.Get("invalid option: '--deps' and '--explicit' may not be used together")) @@ -203,6 +206,7 @@ func getFilter(cmdArgs *parser.Arguments) (upgrade.Filter, error) { return pkg.Reason == alpm.PkgReasonExplicit }, nil } + return func(pkg upgrade.Upgrade) bool { return true }, nil @@ -214,8 +218,10 @@ func handleQuery(cmdArgs *parser.Arguments, dbExecutor db.Executor) error { if err != nil { return err } + return printUpdateList(cmdArgs, dbExecutor, cmdArgs.ExistsDouble("u", "sysupgrade"), filter) } + return config.Runtime.CmdBuilder.Show(config.Runtime.CmdBuilder.BuildPacmanCmd( cmdArgs, config.Runtime.Mode, settings.NoConfirm)) } @@ -225,6 +231,7 @@ func handleHelp(cmdArgs *parser.Arguments) error { usage() return nil } + return config.Runtime.CmdBuilder.Show(config.Runtime.CmdBuilder.BuildPacmanCmd( cmdArgs, config.Runtime.Mode, settings.NoConfirm)) } @@ -238,19 +245,23 @@ func handlePrint(cmdArgs *parser.Arguments, dbExecutor db.Executor) error { case cmdArgs.ExistsArg("d", "defaultconfig"): tmpConfig := settings.DefaultConfig() fmt.Printf("%v", tmpConfig) + return nil case cmdArgs.ExistsArg("g", "currentconfig"): fmt.Printf("%v", config) + return nil case cmdArgs.ExistsArg("n", "numberupgrades"): filter, err := getFilter(cmdArgs) if err != nil { return err } + return printNumberOfUpdates(dbExecutor, cmdArgs.ExistsDouble("u", "sysupgrade"), filter) case cmdArgs.ExistsArg("w", "news"): double := cmdArgs.ExistsDouble("w", "news") quiet := cmdArgs.ExistsArg("q", "quiet") + return news.PrintNewsFeed(config.Runtime.HTTPClient, dbExecutor.LastBuildTime(), config.SortMode, double, quiet) case cmdArgs.ExistsDouble("c", "complete"): return completion.Show(config.Runtime.HTTPClient, dbExecutor, @@ -261,29 +272,30 @@ func handlePrint(cmdArgs *parser.Arguments, dbExecutor db.Executor) error { case cmdArgs.ExistsArg("s", "stats"): return localStatistics(dbExecutor) } + return nil } func handleYay(cmdArgs *parser.Arguments, dbExecutor db.Executor) error { - if cmdArgs.ExistsArg("gendb") { + switch { + case cmdArgs.ExistsArg("gendb"): return createDevelDB(config, dbExecutor) - } - if cmdArgs.ExistsDouble("c") { + case cmdArgs.ExistsDouble("c"): return cleanDependencies(cmdArgs, dbExecutor, true) - } - if cmdArgs.ExistsArg("c", "clean") { + case cmdArgs.ExistsArg("c", "clean"): return cleanDependencies(cmdArgs, dbExecutor, false) - } - if len(cmdArgs.Targets) > 0 { + case len(cmdArgs.Targets) > 0: return handleYogurt(cmdArgs, dbExecutor) } + return nil } -func handleGetpkgbuild(cmdArgs *parser.Arguments, dbExecutor db.Executor) error { +func handleGetpkgbuild(cmdArgs *parser.Arguments, dbExecutor download.DBSearcher) error { if cmdArgs.ExistsArg("p", "print") { return printPkgbuilds(dbExecutor, config.Runtime.HTTPClient, cmdArgs.Targets, config.Runtime.Mode, config.AURURL) } + return getPkgbuilds(dbExecutor, config, cmdArgs.Targets, cmdArgs.ExistsArg("f", "force")) } @@ -295,41 +307,36 @@ func handleYogurt(cmdArgs *parser.Arguments, dbExecutor db.Executor) error { func handleSync(cmdArgs *parser.Arguments, dbExecutor db.Executor) error { targets := cmdArgs.Targets - if cmdArgs.ExistsArg("s", "search") { + switch { + case cmdArgs.ExistsArg("s", "search"): if cmdArgs.ExistsArg("q", "quiet") { config.SearchMode = minimal } else { config.SearchMode = detailed } + return syncSearch(targets, config.Runtime.AURClient, dbExecutor) - } - if cmdArgs.ExistsArg("p", "print", "print-format") { + case cmdArgs.ExistsArg("p", "print", "print-format"): return config.Runtime.CmdBuilder.Show(config.Runtime.CmdBuilder.BuildPacmanCmd( cmdArgs, config.Runtime.Mode, settings.NoConfirm)) - } - if cmdArgs.ExistsArg("c", "clean") { + case cmdArgs.ExistsArg("c", "clean"): return syncClean(cmdArgs, dbExecutor) - } - if cmdArgs.ExistsArg("l", "list") { + case cmdArgs.ExistsArg("l", "list"): return syncList(config.Runtime.HTTPClient, cmdArgs, dbExecutor) - } - if cmdArgs.ExistsArg("g", "groups") { + case cmdArgs.ExistsArg("g", "groups"): return config.Runtime.CmdBuilder.Show(config.Runtime.CmdBuilder.BuildPacmanCmd( cmdArgs, config.Runtime.Mode, settings.NoConfirm)) - } - if cmdArgs.ExistsArg("i", "info") { + case cmdArgs.ExistsArg("i", "info"): return syncInfo(cmdArgs, targets, dbExecutor) - } - if cmdArgs.ExistsArg("u", "sysupgrade") { + case cmdArgs.ExistsArg("u", "sysupgrade"): return install(cmdArgs, dbExecutor, false) - } - if len(cmdArgs.Targets) > 0 { + case len(cmdArgs.Targets) > 0: return install(cmdArgs, dbExecutor, false) - } - if cmdArgs.ExistsArg("y", "refresh") { + case cmdArgs.ExistsArg("y", "refresh"): return config.Runtime.CmdBuilder.Show(config.Runtime.CmdBuilder.BuildPacmanCmd( cmdArgs, config.Runtime.Mode, settings.NoConfirm)) } + return nil } @@ -358,9 +365,11 @@ func displayNumberMenu(pkgS []string, dbExecutor db.Executor, cmdArgs *parser.Ar aq, aurErr = narrowSearch(config.Runtime.AURClient, pkgS, true) lenaq = len(aq) } + if config.Runtime.Mode.AtLeastRepo() { pq = queryRepo(pkgS, dbExecutor) lenpq = len(pq) + if repoErr != nil { return repoErr } @@ -375,6 +384,7 @@ func displayNumberMenu(pkgS []string, dbExecutor db.Executor, cmdArgs *parser.Ar if config.Runtime.Mode.AtLeastRepo() { pq.printSearch(dbExecutor) } + if config.Runtime.Mode.AtLeastAUR() { aq.printSearch(lenpq+1, dbExecutor) } @@ -382,6 +392,7 @@ func displayNumberMenu(pkgS []string, dbExecutor db.Executor, cmdArgs *parser.Ar if config.Runtime.Mode.AtLeastAUR() { aq.printSearch(lenpq+1, dbExecutor) } + if config.Runtime.Mode.AtLeastRepo() { pq.printSearch(dbExecutor) } @@ -403,6 +414,7 @@ func displayNumberMenu(pkgS []string, dbExecutor db.Executor, cmdArgs *parser.Ar if err != nil { return err } + if overflow { return fmt.Errorf(gotext.Get("input too long")) } @@ -414,6 +426,7 @@ func displayNumberMenu(pkgS []string, dbExecutor db.Executor, cmdArgs *parser.Ar for i, pkg := range pq { var target int + switch config.SortMode { case settings.TopDown: target = i + 1 @@ -478,6 +491,7 @@ func syncList(httpClient *http.Client, cmdArgs *parser.Arguments, dbExecutor db. scanner := bufio.NewScanner(resp.Body) scanner.Scan() + for scanner.Scan() { name := scanner.Text() if cmdArgs.ExistsArg("q", "quiet") { diff --git a/config.go b/config.go index 2cb4e832..fad12f9c 100644 --- a/config.go +++ b/config.go @@ -13,7 +13,7 @@ import ( "github.com/Jguer/yay/v10/pkg/text" ) -// Verbosity settings for search +// Verbosity settings for search. const ( numberMenu = iota detailed @@ -37,6 +37,7 @@ func editor() (editor string, args []string) { } else { return editor, strings.Fields(config.EditorFlags) } + fallthrough case os.Getenv("EDITOR") != "": if editorArgs := strings.Fields(os.Getenv("EDITOR")); len(editorArgs) != 0 { @@ -47,6 +48,7 @@ func editor() (editor string, args []string) { return editor, editorArgs[1:] } } + fallthrough case os.Getenv("VISUAL") != "": if editorArgs := strings.Fields(os.Getenv("VISUAL")); len(editorArgs) != 0 { @@ -57,6 +59,7 @@ func editor() (editor string, args []string) { return editor, editorArgs[1:] } } + fallthrough default: fmt.Fprintln(os.Stderr) @@ -65,6 +68,7 @@ func editor() (editor string, args []string) { for { text.Infoln(gotext.Get("Edit PKGBUILD with?")) + editorInput, err := getInput("") if err != nil { fmt.Fprintln(os.Stderr, err) @@ -81,6 +85,7 @@ func editor() (editor string, args []string) { fmt.Fprintln(os.Stderr, err) continue } + return editor, editorArgs[1:] } } @@ -88,6 +93,7 @@ func editor() (editor string, args []string) { func getInput(defaultValue string) (string, error) { text.Info() + if defaultValue != "" || settings.NoConfirm { fmt.Println(defaultValue) return defaultValue, nil diff --git a/diff.go b/diff.go index df93c3e6..ba0339cf 100644 --- a/diff.go +++ b/diff.go @@ -16,12 +16,15 @@ const gitDiffRefName = "AUR_SEEN" func showPkgbuildDiffs(bases []dep.Base, cloned map[string]bool) error { var errMulti multierror.MultiError + for _, base := range bases { pkg := base.Pkgbase() dir := filepath.Join(config.BuildDir, pkg) + start, err := getLastSeenHash(config.BuildDir, pkg) if err != nil { errMulti.Add(err) + continue } @@ -31,11 +34,13 @@ func showPkgbuildDiffs(bases []dep.Base, cloned map[string]bool) error { hasDiff, err := gitHasDiff(config.BuildDir, pkg) if err != nil { errMulti.Add(err) + continue } if !hasDiff { text.Warnln(gotext.Get("%s: No changes -- skipping", text.Cyan(base.String()))) + continue } } @@ -50,6 +55,7 @@ func showPkgbuildDiffs(bases []dep.Base, cloned map[string]bool) error { } else { args = append(args, "--color=never") } + _ = config.Runtime.CmdBuilder.Show(config.Runtime.CmdBuilder.BuildGitCmd(dir, args...)) } @@ -57,7 +63,7 @@ func showPkgbuildDiffs(bases []dep.Base, cloned map[string]bool) error { } // Check whether or not a diff exists between the last reviewed diff and -// HEAD@{upstream} +// HEAD@{upstream}. func gitHasDiff(path, name string) (bool, error) { if gitHasLastSeenRef(path, name) { stdout, stderr, err := config.Runtime.CmdBuilder.Capture( @@ -69,6 +75,7 @@ func gitHasDiff(path, name string) (bool, error) { lines := strings.Split(stdout, "\n") lastseen := lines[0] upstream := lines[1] + return lastseen != upstream, nil } // If YAY_DIFF_REVIEW does not exists, we have never reviewed a diff for this package @@ -77,11 +84,12 @@ func gitHasDiff(path, name string) (bool, error) { } // Return wether or not we have reviewed a diff yet. It checks for the existence of -// YAY_DIFF_REVIEW in the git ref-list +// YAY_DIFF_REVIEW in the git ref-list. func gitHasLastSeenRef(path, name string) bool { _, _, err := config.Runtime.CmdBuilder.Capture( config.Runtime.CmdBuilder.BuildGitCmd( filepath.Join(path, name), "rev-parse", "--quiet", "--verify", gitDiffRefName), 0) + return err == nil } @@ -97,13 +105,15 @@ func getLastSeenHash(path, name string) (string, error) { } lines := strings.Split(stdout, "\n") + return lines[0], nil } + return gitEmptyTree, nil } // Update the YAY_DIFF_REVIEW ref to HEAD. We use this ref to determine which diff were -// reviewed by the user +// reviewed by the user. func gitUpdateSeenRef(path, name string) error { _, stderr, err := config.Runtime.CmdBuilder.Capture( config.Runtime.CmdBuilder.BuildGitCmd( @@ -111,6 +121,7 @@ func gitUpdateSeenRef(path, name string) error { if err != nil { return fmt.Errorf("%s %s", stderr, err) } + return nil } diff --git a/get.go b/get.go index 27afd209..a529222c 100644 --- a/get.go +++ b/get.go @@ -8,15 +8,14 @@ import ( "github.com/leonelquinteros/gotext" - "github.com/Jguer/yay/v10/pkg/db" "github.com/Jguer/yay/v10/pkg/download" "github.com/Jguer/yay/v10/pkg/settings" "github.com/Jguer/yay/v10/pkg/settings/parser" "github.com/Jguer/yay/v10/pkg/text" ) -// yay -Gp -func printPkgbuilds(dbExecutor db.Executor, httpClient *http.Client, targets []string, +// yay -Gp. +func printPkgbuilds(dbExecutor download.DBSearcher, httpClient *http.Client, targets []string, mode parser.TargetMode, aurURL string) error { pkgbuilds, err := download.PKGBUILDs(dbExecutor, httpClient, targets, aurURL, mode) if err != nil { @@ -32,11 +31,13 @@ func printPkgbuilds(dbExecutor db.Executor, httpClient *http.Client, targets []s if len(pkgbuilds) != len(targets) { missing := []string{} + for _, target := range targets { if _, ok := pkgbuilds[target]; !ok { missing = append(missing, target) } } + text.Warnln(gotext.Get("Unable to find the following packages:"), strings.Join(missing, ", ")) return fmt.Errorf("") @@ -45,13 +46,14 @@ func printPkgbuilds(dbExecutor db.Executor, httpClient *http.Client, targets []s return nil } -// yay -G -func getPkgbuilds(dbExecutor db.Executor, config *settings.Configuration, targets []string, +// yay -G. +func getPkgbuilds(dbExecutor download.DBSearcher, config *settings.Configuration, targets []string, force bool) error { wd, err := os.Getwd() if err != nil { return err } + cloned, errD := download.PKGBUILDRepos(dbExecutor, config.Runtime.CmdBuilder, targets, config.Runtime.Mode, config.AURURL, wd, force) if errD != nil { @@ -60,11 +62,13 @@ func getPkgbuilds(dbExecutor db.Executor, config *settings.Configuration, target if len(targets) != len(cloned) { missing := []string{} + for _, target := range targets { if _, ok := cloned[target]; !ok { missing = append(missing, target) } } + text.Warnln(gotext.Get("Unable to find the following packages:"), strings.Join(missing, ", ")) err = fmt.Errorf("") diff --git a/install.go b/install.go index 1edac0c2..f0638e4a 100644 --- a/install.go +++ b/install.go @@ -38,6 +38,7 @@ func asdeps(cmdArgs *parser.Arguments, pkgs []string) (err error) { cmdArgs = cmdArgs.CopyGlobal() _ = cmdArgs.AddArg("q", "D", "asdeps") cmdArgs.AddTarget(pkgs...) + err = config.Runtime.CmdBuilder.Show(config.Runtime.CmdBuilder.BuildPacmanCmd( cmdArgs, config.Runtime.Mode, settings.NoConfirm)) if err != nil { @@ -55,6 +56,7 @@ func asexp(cmdArgs *parser.Arguments, pkgs []string) (err error) { cmdArgs = cmdArgs.CopyGlobal() _ = cmdArgs.AddArg("q", "D", "asexplicit") cmdArgs.AddTarget(pkgs...) + err = config.Runtime.CmdBuilder.Show(config.Runtime.CmdBuilder.BuildPacmanCmd( cmdArgs, config.Runtime.Mode, settings.NoConfirm)) if err != nil { @@ -64,7 +66,7 @@ func asexp(cmdArgs *parser.Arguments, pkgs []string) (err error) { return nil } -// Install handles package installs +// Install handles package installs. func install(cmdArgs *parser.Arguments, dbExecutor db.Executor, ignoreProviders bool) (err error) { var ( incompatible stringset.StringSet @@ -162,14 +164,17 @@ func install(cmdArgs *parser.Arguments, dbExecutor db.Executor, ignoreProviders if sysupgradeArg { fmt.Println(gotext.Get(" there is nothing to do")) } + return nil } cmdArgs.Op = "S" cmdArgs.DelArg("y", "refresh") + if arguments.ExistsArg("ignore") { cmdArgs.CreateOrAppendOption("ignore", arguments.GetArgs("ignore")...) } + return config.Runtime.CmdBuilder.Show(config.Runtime.CmdBuilder.BuildPacmanCmd( cmdArgs, config.Runtime.Mode, settings.NoConfirm)) } @@ -184,9 +189,6 @@ func install(cmdArgs *parser.Arguments, dbExecutor db.Executor, ignoreProviders } do = dep.GetOrder(dp, noDeps, noCheck) - if err != nil { - return err - } for _, pkg := range do.Repo { arguments.AddTarget(pkg.DB().Name() + "/" + pkg.Name()) @@ -230,6 +232,7 @@ func install(cmdArgs *parser.Arguments, dbExecutor db.Executor, ignoreProviders if config.CleanMenu { if anyExistInCache(do.Aur) { askClean := pkgbuildNumberMenu(do.Aur, remoteNamesCache) + toClean, errClean := cleanNumberMenu(do.Aur, remoteNamesCache, askClean) if errClean != nil { return errClean @@ -241,6 +244,7 @@ func install(cmdArgs *parser.Arguments, dbExecutor db.Executor, ignoreProviders toSkip := pkgbuildsToSkip(do.Aur, targets) toClone := make([]string, 0, len(do.Aur)) + for _, base := range do.Aur { if !toSkip.Get(base.Pkgbase()) { toClone = append(toClone, base.Pkgbase()) @@ -260,11 +264,14 @@ func install(cmdArgs *parser.Arguments, dbExecutor db.Executor, ignoreProviders return err } - var toDiff []dep.Base - var toEdit []dep.Base + var ( + toDiff []dep.Base + toEdit []dep.Base + ) if config.DiffMenu { pkgbuildNumberMenu(do.Aur, remoteNamesCache) + toDiff, err = diffNumberMenu(do.Aur, remoteNamesCache) if err != nil { return err @@ -281,10 +288,13 @@ func install(cmdArgs *parser.Arguments, dbExecutor db.Executor, ignoreProviders if len(toDiff) > 0 { oldValue := settings.NoConfirm settings.NoConfirm = false + fmt.Println() + if !text.ContinueTask(gotext.Get("Proceed with install?"), true, settings.NoConfirm) { return fmt.Errorf(gotext.Get("aborting due to user")) } + err = updatePkgbuildSeenRef(toDiff) if err != nil { text.Errorln(err.Error()) @@ -305,6 +315,7 @@ func install(cmdArgs *parser.Arguments, dbExecutor db.Executor, ignoreProviders if config.EditMenu { pkgbuildNumberMenu(do.Aur, remoteNamesCache) + toEdit, err = editNumberMenu(do.Aur, remoteNamesCache) if err != nil { return err @@ -321,10 +332,13 @@ func install(cmdArgs *parser.Arguments, dbExecutor db.Executor, ignoreProviders if len(toEdit) > 0 { oldValue := settings.NoConfirm settings.NoConfirm = false + fmt.Println() + if !text.ContinueTask(gotext.Get("Proceed with install?"), true, settings.NoConfirm) { return errors.New(gotext.Get("aborting due to user")) } + settings.NoConfirm = oldValue } @@ -356,6 +370,7 @@ func install(cmdArgs *parser.Arguments, dbExecutor db.Executor, ignoreProviders for _, pkg := range do.Repo { if !dp.Explicit.Get(pkg.Name()) && !localNamesCache.Get(pkg.Name()) && !remoteNamesCache.Get(pkg.Name()) { deps = append(deps, pkg.Name()) + continue } @@ -369,6 +384,7 @@ func install(cmdArgs *parser.Arguments, dbExecutor db.Executor, ignoreProviders if errDeps := asdeps(cmdArgs, deps); errDeps != nil { return errDeps } + if errExp := asexp(cmdArgs, exp); errExp != nil { return errExp } @@ -394,6 +410,7 @@ func install(cmdArgs *parser.Arguments, dbExecutor db.Executor, ignoreProviders func removeMake(do *dep.Order) error { removeArguments := parser.MakeArguments() + err := removeArguments.AddArg("R", "u") if err != nil { return err @@ -467,6 +484,7 @@ func earlyRefresh(cmdArgs *parser.Arguments) error { arguments.DelArg("i", "info") arguments.DelArg("l", "list") arguments.ClearTargets() + return config.Runtime.CmdBuilder.Show(config.Runtime.CmdBuilder.BuildPacmanCmd( arguments, config.Runtime.Mode, settings.NoConfirm)) } @@ -488,6 +506,7 @@ func alpmArchIsSupported(alpmArch []string, arch string) bool { func getIncompatible(bases []dep.Base, srcinfos map[string]*gosrc.Srcinfo, dbExecutor db.Executor) (stringset.StringSet, error) { incompatible := make(stringset.StringSet) basesMap := make(map[string]dep.Base) + alpmArch, err := dbExecutor.AlpmArchitectures() if err != nil { return nil, err @@ -507,6 +526,7 @@ nextpkg: 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(basesMap[pkg].String())) } @@ -609,6 +629,7 @@ func cleanNumberMenu(bases []dep.Base, installed stringset.StringSet, hasClean b text.Infoln(gotext.Get("Packages to cleanBuild?")) 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")))) + cleanInput, err := getInput(config.AnswerClean) if err != nil { return nil, err @@ -625,6 +646,7 @@ func cleanNumberMenu(bases []dep.Base, installed stringset.StringSet, hasClean b for i, base := range bases { pkg := base.Pkgbase() anyInstalled := false + for _, b := range base { anyInstalled = anyInstalled || installed.Get(b.Name) } @@ -677,13 +699,16 @@ func diffNumberMenu(bases []dep.Base, installed stringset.StringSet) ([]dep.Base } func editDiffNumberMenu(bases []dep.Base, installed stringset.StringSet, diff bool) ([]dep.Base, error) { - toEdit := make([]dep.Base, 0) - var editInput string - var err error + var ( + toEdit = make([]dep.Base, 0) + editInput string + err error + ) if diff { text.Infoln(gotext.Get("Diffs to show?")) 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")))) + editInput, err = getInput(config.AnswerDiff) if err != nil { return nil, err @@ -708,6 +733,7 @@ func editDiffNumberMenu(bases []dep.Base, installed stringset.StringSet, diff bo for i, base := range bases { pkg := base.Pkgbase() anyInstalled := false + for _, b := range base { anyInstalled = anyInstalled || installed.Get(b.Name) } @@ -746,18 +772,21 @@ func editDiffNumberMenu(bases []dep.Base, installed stringset.StringSet, diff bo func updatePkgbuildSeenRef(bases []dep.Base) error { var errMulti multierror.MultiError + for _, base := range bases { pkg := base.Pkgbase() - err := gitUpdateSeenRef(config.BuildDir, pkg) - if err != nil { + + if err := gitUpdateSeenRef(config.BuildDir, pkg); err != nil { errMulti.Add(err) } } + return errMulti.Return() } func editPkgbuilds(bases []dep.Base, srcinfos map[string]*gosrc.Srcinfo) error { pkgbuilds := make([]string, 0, len(bases)) + for _, base := range bases { pkg := base.Pkgbase() dir := filepath.Join(config.BuildDir, pkg) @@ -775,8 +804,8 @@ func editPkgbuilds(bases []dep.Base, srcinfos map[string]*gosrc.Srcinfo) error { editorArgs = append(editorArgs, pkgbuilds...) editcmd := exec.Command(editor, editorArgs...) editcmd.Stdin, editcmd.Stdout, editcmd.Stderr = os.Stdin, os.Stdout, os.Stderr - err := editcmd.Run() - if err != nil { + + if err := editcmd.Run(); err != nil { return errors.New(gotext.Get("editor did not exit successfully, aborting: %s", err)) } } @@ -786,6 +815,7 @@ func editPkgbuilds(bases []dep.Base, srcinfos map[string]*gosrc.Srcinfo) error { func parseSrcinfoFiles(bases []dep.Base, errIsFatal bool) (map[string]*gosrc.Srcinfo, error) { srcinfos := make(map[string]*gosrc.Srcinfo) + for k, base := range bases { pkg := base.Pkgbase() dir := filepath.Join(config.BuildDir, pkg) @@ -798,6 +828,7 @@ func parseSrcinfoFiles(bases []dep.Base, errIsFatal bool) (map[string]*gosrc.Src text.Warnln(gotext.Get("failed to parse %s -- skipping: %s", base.String(), err)) continue } + return nil, errors.New(gotext.Get("failed to parse %s: %s", base.String(), err)) } @@ -914,6 +945,7 @@ func buildInstallPkgbuilds( if !dp.AlpmExecutor.LocalSatisfierExists(dep) { satisfied = false text.Warnln(gotext.Get("%s not satisfied, flushing install queue", dep)) + break all } } @@ -923,8 +955,10 @@ func buildInstallPkgbuilds( if !satisfied || !config.BatchInstall { err = doInstall(arguments, cmdArgs, deps, exp) arguments.ClearTargets() + deps = make([]string, 0) exp = make([]string, 0) + if err != nil { return err } @@ -953,6 +987,7 @@ func buildInstallPkgbuilds( for _, b := range base { isExplicit = isExplicit || dp.Explicit.Get(b.Name) } + if config.ReBuild == "no" || (config.ReBuild == "yes" && !isExplicit) { for _, split := range base { pkgdest, ok := pkgdests[split.Name] @@ -985,6 +1020,7 @@ func buildInstallPkgbuilds( } fmt.Fprintln(os.Stdout, gotext.Get("%s is up to date -- skipping", text.Cyan(pkg+"-"+pkgVersion))) + continue } } @@ -1021,12 +1057,14 @@ func buildInstallPkgbuilds( for _, split := range base { if _, ok := conflicts[split.Name]; ok { settings.NoConfirm = false + break } } } var errAdd error + for _, split := range base { for _, suffix := range []string{"", "-debug"} { deps, exp, errAdd = doAddTarget(dp, localNamesCache, remoteNamesCache, @@ -1037,10 +1075,14 @@ func buildInstallPkgbuilds( } } - var mux sync.Mutex - var wg sync.WaitGroup + var ( + mux sync.Mutex + wg sync.WaitGroup + ) + for _, pkg := range base { wg.Add(1) + go config.Runtime.VCSStore.Update(pkg.Name, srcinfo.Source, &mux, &wg) } @@ -1049,6 +1091,7 @@ func buildInstallPkgbuilds( err = doInstall(arguments, cmdArgs, deps, exp) settings.NoConfirm = oldConfirm + return err } @@ -1097,11 +1140,13 @@ func doAddTarget(dp *dep.Pool, localNamesCache, remoteNamesCache stringset.Strin } arguments.AddTarget(pkgdest) - if cmdArgs.ExistsArg("asdeps", "asdep") { + + switch { + case cmdArgs.ExistsArg("asdeps", "asdep"): deps = append(deps, name) - } else if cmdArgs.ExistsArg("asexplicit", "asexp") { + case cmdArgs.ExistsArg("asexplicit", "asexp"): exp = append(exp, name) - } else if !dp.Explicit.Get(name) && !localNamesCache.Get(name) && !remoteNamesCache.Get(name) { + case !dp.Explicit.Get(name) && !localNamesCache.Get(name) && !remoteNamesCache.Get(name): deps = append(deps, name) } diff --git a/main.go b/main.go index a7f84167..8863edf8 100644 --- a/main.go +++ b/main.go @@ -41,6 +41,7 @@ func initAlpm(cmdArgs *parser.Arguments, pacmanConfigPath string) (*pacmanconf.C if stderr != "" { cmdErr = fmt.Errorf("%s\n%s", err, stderr) } + return nil, false, cmdErr } @@ -69,6 +70,7 @@ func initAlpm(cmdArgs *parser.Arguments, pacmanConfigPath string) (*pacmanconf.C } useColor := pacmanConf.Color && term.IsTerminal(int(os.Stdout.Fd())) + switch value, _, _ := cmdArgs.GetArg("color"); value { case "always": useColor = true @@ -83,9 +85,13 @@ func initAlpm(cmdArgs *parser.Arguments, pacmanConfigPath string) (*pacmanconf.C func main() { var err error + ret := 0 + defer func() { os.Exit(ret) }() + initGotext() + if os.Geteuid() == 0 { text.Warnln(gotext.Get("Avoid running yay as root/sudo.")) } @@ -95,17 +101,21 @@ func main() { if str := err.Error(); str != "" { fmt.Fprintln(os.Stderr, str) } + ret = 1 + return } cmdArgs := parser.MakeArguments() - err = config.ParseCommandLine(cmdArgs) - if err != nil { + + if err = config.ParseCommandLine(cmdArgs); err != nil { if str := err.Error(); str != "" { fmt.Fprintln(os.Stderr, str) } + ret = 1 + return } @@ -116,14 +126,18 @@ func main() { } var useColor bool + config.Runtime.PacmanConf, useColor, err = initAlpm(cmdArgs, config.PacmanConf) if err != nil { if str := err.Error(); str != "" { fmt.Fprintln(os.Stderr, str) } + ret = 1 + return } + config.Runtime.CmdBuilder.SetPacmanDBPath(config.Runtime.PacmanConf.DBPath) text.UseColor = useColor @@ -133,7 +147,9 @@ func main() { if str := err.Error(); str != "" { fmt.Fprintln(os.Stderr, str) } + ret = 1 + return } @@ -153,6 +169,7 @@ func main() { // fallback ret = 1 + return } } diff --git a/main_test.go b/main_test.go index d32e77c4..1fa76149 100644 --- a/main_test.go +++ b/main_test.go @@ -10,6 +10,8 @@ import ( ) func TestPacmanConf(t *testing.T) { + t.Parallel() + expectedPacmanConf := &pacmanconf.Config{ RootDir: "/", DBPath: "//var/lib/pacman/", diff --git a/pkg/completion/completion.go b/pkg/completion/completion.go index 19f7e88f..d8cf78c9 100644 --- a/pkg/completion/completion.go +++ b/pkg/completion/completion.go @@ -20,7 +20,7 @@ type PkgSynchronizer interface { SyncPackages(...string) []db.IPackage } -// Show provides completion info for shells +// Show provides completion info for shells. func Show(httpClient *http.Client, dbExecutor PkgSynchronizer, aurURL, completionPath string, interval int, force bool) error { err := Update(httpClient, dbExecutor, aurURL, completionPath, interval, force) if err != nil { @@ -34,10 +34,11 @@ func Show(httpClient *http.Client, dbExecutor PkgSynchronizer, aurURL, completio defer in.Close() _, err = io.Copy(os.Stdout, in) + return err } -// Update updates completion cache to be used by Complete +// Update updates completion cache to be used by Complete. func Update(httpClient *http.Client, dbExecutor PkgSynchronizer, aurURL, completionPath string, interval int, force bool) error { info, err := os.Stat(completionPath) @@ -46,6 +47,7 @@ func Update(httpClient *http.Client, dbExecutor PkgSynchronizer, aurURL, complet if errd != nil { return errd } + out, errf := os.Create(completionPath) if errf != nil { return errf @@ -58,18 +60,20 @@ func Update(httpClient *http.Client, dbExecutor PkgSynchronizer, aurURL, complet erra := createRepoList(dbExecutor, out) out.Close() + return erra } return nil } -// CreateAURList creates a new completion file +// CreateAURList creates a new completion file. func createAURList(client *http.Client, aurURL string, out io.Writer) error { u, err := url.Parse(aurURL) if err != nil { return err } + u.Path = path.Join(u.Path, "packages.gz") req, err := http.NewRequestWithContext(context.Background(), "GET", u.String(), nil) @@ -82,6 +86,7 @@ func createAURList(client *http.Client, aurURL string, out io.Writer) error { return err } defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { return fmt.Errorf("invalid status code: %d", resp.StatusCode) } @@ -89,13 +94,14 @@ func createAURList(client *http.Client, aurURL string, out io.Writer) error { scanner := bufio.NewScanner(resp.Body) scanner.Scan() + for scanner.Scan() { text := scanner.Text() if strings.HasPrefix(text, "#") { continue } - _, err = io.WriteString(out, text+"\tAUR\n") - if err != nil { + + if _, err := io.WriteString(out, text+"\tAUR\n"); err != nil { return err } } @@ -103,7 +109,7 @@ func createAURList(client *http.Client, aurURL string, out io.Writer) error { return nil } -// CreatePackageList appends Repo packages to completion cache +// CreatePackageList appends Repo packages to completion cache. func createRepoList(dbExecutor PkgSynchronizer, out io.Writer) error { for _, pkg := range dbExecutor.SyncPackages() { _, err := io.WriteString(out, pkg.Name()+"\t"+pkg.DB().Name()+"\n") @@ -111,5 +117,6 @@ func createRepoList(dbExecutor PkgSynchronizer, out io.Writer) error { return err } } + return nil } diff --git a/pkg/completion/completion_test.go b/pkg/completion/completion_test.go index 36eb3893..83f461b4 100644 --- a/pkg/completion/completion_test.go +++ b/pkg/completion/completion_test.go @@ -39,6 +39,7 @@ func Test_createAURList(t *testing.T) { Get("/packages.gz"). Reply(200). BodyString(samplePackageResp) + out := &bytes.Buffer{} err := createAURList(&http.Client{}, "https://aur.archlinux.org", out) assert.NoError(t, err) @@ -52,6 +53,7 @@ func Test_createAURListHTTPError(t *testing.T) { gock.New("https://aur.archlinux.org"). Get("/packages.gz"). ReplyError(errors.New("Not available")) + out := &bytes.Buffer{} err := createAURList(&http.Client{}, "https://aur.archlinux.org", out) assert.EqualError(t, err, "Get \"https://aur.archlinux.org/packages.gz\": Not available") diff --git a/pkg/db/ialpm/alpm.go b/pkg/db/ialpm/alpm.go index 209c2dd8..ebb36433 100644 --- a/pkg/db/ialpm/alpm.go +++ b/pkg/db/ialpm/alpm.go @@ -53,6 +53,7 @@ func toUsage(usages []string) alpm.Usage { } var ret alpm.Usage + for _, usage := range usages { switch usage { case "Sync": @@ -72,11 +73,6 @@ func toUsage(usages []string) alpm.Usage { } func configureAlpm(pacmanConf *pacmanconf.Config, alpmHandle *alpm.Handle) error { - // TODO: set SigLevel - // sigLevel := alpm.SigPackage | alpm.SigPackageOptional | alpm.SigDatabase | alpm.SigDatabaseOptional - // localFileSigLevel := alpm.SigUseDefault - // remoteFileSigLevel := alpm.SigUseDefault - for _, repo := range pacmanConf.Repos { // TODO: set SigLevel alpmDB, err := alpmHandle.RegisterSyncDB(repo.Name, 0) @@ -127,18 +123,6 @@ func configureAlpm(pacmanConf *pacmanconf.Config, alpmHandle *alpm.Handle) error return err } - /*if err := alpmHandle.SetDefaultSigLevel(sigLevel); err != nil { - return err - } - - if err := alpmHandle.SetLocalFileSigLevel(localFileSigLevel); err != nil { - return err - } - - if err := alpmHandle.SetRemoteFileSigLevel(remoteFileSigLevel); err != nil { - return err - }*/ - if err := alpmHandle.SetUseSyslog(pacmanConf.UseSyslog); err != nil { return err } @@ -180,6 +164,7 @@ func (ae *AlpmExecutor) questionCallback() func(question alpm.QuestionAny) { str := text.Bold(gotext.Get("There are %d providers available for %s:\n", size, qp.Dep())) size = 1 + var dbName string _ = qp.Providers(ae.handle).ForEach(func(pkg alpm.IPackage) error { @@ -202,18 +187,22 @@ func (ae *AlpmExecutor) questionCallback() func(question alpm.QuestionAny) { // TODO: reenable noconfirm if settings.NoConfirm { fmt.Println() + break } reader := bufio.NewReader(os.Stdin) + numberBuf, overflow, err := reader.ReadLine() if err != nil { text.Errorln(err) + break } if overflow { text.Errorln(gotext.Get(" Input too long")) + continue } @@ -233,6 +222,7 @@ func (ae *AlpmExecutor) questionCallback() func(question alpm.QuestionAny) { } qp.SetUseIndex(num - 1) + break } } @@ -258,12 +248,14 @@ func (ae *AlpmExecutor) RefreshHandle() error { alpmSetLogCallback(alpmHandle, logCallback) ae.handle = alpmHandle ae.syncDBsCache = nil + ae.syncDB, err = alpmHandle.SyncDBs() if err != nil { return err } ae.localDB, err = alpmHandle.LocalDB() + return err } @@ -271,6 +263,7 @@ func (ae *AlpmExecutor) LocalSatisfierExists(pkgName string) bool { if _, err := ae.localDB.PkgCache().FindSatisfier(pkgName); err != nil { return false } + return true } @@ -278,6 +271,7 @@ func (ae *AlpmExecutor) SyncSatisfierExists(pkgName string) bool { if _, err := ae.syncDB.FindSatisfier(pkgName); err != nil { return false } + return true } @@ -295,6 +289,7 @@ func (ae *AlpmExecutor) SyncSatisfier(pkgName string) alpm.IPackage { if err != nil { return nil } + return foundPkg } @@ -302,8 +297,10 @@ func (ae *AlpmExecutor) PackagesFromGroup(groupName string) []alpm.IPackage { groupPackages := []alpm.IPackage{} _ = ae.syncDB.FindGroupPkgs(groupName).ForEach(func(pkg alpm.IPackage) error { groupPackages = append(groupPackages, pkg) + return nil }) + return groupPackages } @@ -313,10 +310,11 @@ func (ae *AlpmExecutor) LocalPackages() []alpm.IPackage { localPackages = append(localPackages, pkg) return nil }) + return localPackages } -// SyncPackages searches SyncDB for packages or returns all packages if no search param is given +// SyncPackages searches SyncDB for packages or returns all packages if no search param is given. func (ae *AlpmExecutor) SyncPackages(pkgNames ...string) []alpm.IPackage { repoPackages := []alpm.IPackage{} _ = ae.syncDB.ForEach(func(alpmDB alpm.IDB) error { @@ -333,6 +331,7 @@ func (ae *AlpmExecutor) SyncPackages(pkgNames ...string) []alpm.IPackage { } return nil }) + return repoPackages } @@ -341,6 +340,7 @@ func (ae *AlpmExecutor) LocalPackage(pkgName string) alpm.IPackage { if pkg == nil { return nil } + return pkg } @@ -348,6 +348,7 @@ func (ae *AlpmExecutor) syncDBs() []alpm.IDB { if ae.syncDBsCache == nil { ae.syncDBsCache = ae.syncDB.Slice() } + return ae.syncDBsCache } @@ -357,6 +358,7 @@ func (ae *AlpmExecutor) SyncPackage(pkgName string) alpm.IPackage { return dbPkg } } + return nil } @@ -365,10 +367,12 @@ func (ae *AlpmExecutor) SatisfierFromDB(pkgName, dbName string) alpm.IPackage { if err != nil { return nil } + foundPkg, err := singleDB.PkgCache().FindSatisfier(pkgName) if err != nil { return nil } + return foundPkg } @@ -400,26 +404,27 @@ func (ae *AlpmExecutor) PackageGroups(pkg alpm.IPackage) []string { // upRepo gathers local packages and checks if they have new versions. // Output: Upgrade type package list. func (ae *AlpmExecutor) RepoUpgrades(enableDowngrade bool) ([]db.Upgrade, error) { + var errReturn error + slice := []db.Upgrade{} - localDB, err := ae.handle.LocalDB() - if err != nil { - return slice, err + localDB, errDB := ae.handle.LocalDB() + if errDB != nil { + return slice, errDB } - err = ae.handle.TransInit(alpm.TransFlagNoLock) - if err != nil { + if err := ae.handle.TransInit(alpm.TransFlagNoLock); err != nil { return slice, err } defer func() { - err = ae.handle.TransRelease() + errReturn = ae.handle.TransRelease() }() - err = ae.handle.SyncSysupgrade(enableDowngrade) - if err != nil { + if err := ae.handle.SyncSysupgrade(enableDowngrade); err != nil { return slice, err } + _ = ae.handle.TransGetAdd().ForEach(func(pkg alpm.IPackage) error { localVer := "-" reason := alpm.PkgReasonExplicit @@ -439,7 +444,7 @@ func (ae *AlpmExecutor) RepoUpgrades(enableDowngrade bool) ([]db.Upgrade, error) return nil }) - return slice, nil + return slice, errReturn } func (ae *AlpmExecutor) BiggestPackages() []alpm.IPackage { @@ -448,11 +453,13 @@ func (ae *AlpmExecutor) BiggestPackages() []alpm.IPackage { localPackages = append(localPackages, pkg) return nil }) + return localPackages } func (ae *AlpmExecutor) LastBuildTime() time.Time { var lastTime time.Time + _ = ae.syncDB.ForEach(func(db alpm.IDB) error { _ = db.PkgCache().ForEach(func(pkg alpm.IPackage) error { thisTime := pkg.BuildDate() @@ -480,6 +487,7 @@ func (ae *AlpmExecutor) Repos() (repos []string) { repos = append(repos, db.Name()) return nil }) + return } diff --git a/pkg/db/ialpm/alpm_test.go b/pkg/db/ialpm/alpm_test.go index 3d014be1..9d5822eb 100644 --- a/pkg/db/ialpm/alpm_test.go +++ b/pkg/db/ialpm/alpm_test.go @@ -9,6 +9,7 @@ import ( ) func TestAlpmExecutor(t *testing.T) { + t.Parallel() pacmanConf := &pacmanconf.Config{ RootDir: "/", DBPath: "/var/lib/pacman/", diff --git a/pkg/db/mock/repo.go b/pkg/db/mock/repo.go index 0159cb0f..1afe7deb 100644 --- a/pkg/db/mock/repo.go +++ b/pkg/db/mock/repo.go @@ -111,7 +111,7 @@ func (p *Package) Files() []alpm.File { panic("not implemented") // TODO: Implement } -// ContainsFile checks if the path is in the package filelist +// ContainsFile checks if the path is in the package filelist. func (p *Package) ContainsFile(path string) (alpm.File, error) { panic("not implemented") // TODO: Implement } @@ -166,13 +166,13 @@ func (p *Package) URL() string { panic("not implemented") // TODO: Implement } -// ComputeRequiredBy returns the names of reverse dependencies of a package +// ComputeRequiredBy returns the names of reverse dependencies of a package. func (p *Package) ComputeRequiredBy() []string { panic("not implemented") // TODO: Implement } // ComputeOptionalFor returns the names of packages that optionally -// require the given package +// require the given package. func (p *Package) ComputeOptionalFor() []string { panic("not implemented") // TODO: Implement } diff --git a/pkg/dep/base.go b/pkg/dep/base.go index 0a28f45a..647da6d5 100644 --- a/pkg/dep/base.go +++ b/pkg/dep/base.go @@ -2,7 +2,7 @@ package dep import aur "github.com/Jguer/yay/v10/pkg/query" -// Base is an AUR base package +// Base is an AUR base package. type Base []*aur.Pkg // Pkgbase returns the first base package. @@ -21,15 +21,17 @@ func (b Base) URLPath() string { } // Packages foo and bar from a pkgbase named base would print like so: -// base (foo bar) +// base (foo bar). func (b Base) String() string { pkg := b[0] str := pkg.PackageBase + if len(b) > 1 || pkg.PackageBase != pkg.Name { str2 := " (" for _, split := range b { str2 += split.Name + " " } + str2 = str2[:len(str2)-1] + ")" str += str2 diff --git a/pkg/dep/depCheck.go b/pkg/dep/depCheck.go index 923725cf..1321dc7a 100644 --- a/pkg/dep/depCheck.go +++ b/pkg/dep/depCheck.go @@ -45,6 +45,7 @@ func (dp *Pool) checkForwardConflict(name, conflict string, conflicts stringset. if n != conflict { n += " (" + conflict + ")" } + conflicts.Add(name, n) } } @@ -113,6 +114,7 @@ func (dp *Pool) checkReverseConflicts(conflicts stringset.MapStringSet) { if dp.hasPackage(pkg.Name()) { continue } + for _, conflict := range dp.AlpmExecutor.PackageConflicts(pkg) { dp.checkReverseConflict(pkg.Name(), conflict.String(), conflicts) } @@ -126,10 +128,13 @@ func (dp *Pool) CheckConflicts(useAsk, noConfirm, noDeps bool) (stringset.MapStr } var wg sync.WaitGroup + innerConflicts := make(stringset.MapStringSet) + wg.Add(2) text.OperationInfoln(gotext.Get("Checking for conflicts...")) + go func() { dp.checkForwardConflicts(conflicts) dp.checkReverseConflicts(conflicts) @@ -137,6 +142,7 @@ func (dp *Pool) CheckConflicts(useAsk, noConfirm, noDeps bool) (stringset.MapStr }() text.OperationInfoln(gotext.Get("Checking for inner conflicts...")) + go func() { dp.checkInnerConflicts(innerConflicts) wg.Done() @@ -152,6 +158,7 @@ func (dp *Pool) CheckConflicts(useAsk, noConfirm, noDeps bool) (stringset.MapStr for pkg := range pkgs { str += " " + text.Cyan(pkg) + "," } + str = strings.TrimSuffix(str, ",") fmt.Println(str) @@ -166,6 +173,7 @@ func (dp *Pool) CheckConflicts(useAsk, noConfirm, noDeps bool) (stringset.MapStr for pkg := range pkgs { str += " " + text.Cyan(pkg) + "," } + str = strings.TrimSuffix(str, ",") fmt.Println(str) @@ -211,12 +219,15 @@ func (dp *Pool) _checkMissing(dep string, stack []string, missing *missing, noDe return } } + missing.Missing[dep] = append(missing.Missing[dep], stack) + return } if aurPkg := dp.findSatisfierAur(dep); aurPkg != nil { missing.Good.Set(dep) + combinedDepList := ComputeCombinedDepList(aurPkg, noDeps, noCheckDeps) for _, deps := range combinedDepList { for _, aurDep := range deps { @@ -291,6 +302,7 @@ func (dp *Pool) CheckMissing(noDeps, noCheckDeps bool) error { } text.Errorln(gotext.Get("Could not find all required packages:")) + for dep, trees := range missing.Missing { for _, tree := range trees { fmt.Fprintf(os.Stderr, "\t%s", text.Cyan(dep)) diff --git a/pkg/dep/depOrder.go b/pkg/dep/depOrder.go index bb830502..8ddda9e7 100644 --- a/pkg/dep/depOrder.go +++ b/pkg/dep/depOrder.go @@ -45,6 +45,7 @@ func (do *Order) orderPkgAur(pkg *aur.Pkg, dp *Pool, runtime, noDeps, noCheckDep if runtime { do.Runtime.Set(pkg.Name) } + delete(dp.Aur, pkg.Name) for i, deps := range ComputeCombinedDepList(pkg, noDeps, noCheckDeps) { @@ -73,6 +74,7 @@ func (do *Order) orderPkgRepo(pkg db.IPackage, dp *Pool, runtime bool) { if runtime { do.Runtime.Set(pkg.Name()) } + delete(dp.Repo, pkg.Name()) for _, dep := range dp.AlpmExecutor.PackageDepends(pkg) { @@ -113,7 +115,7 @@ func (do *Order) GetMake() []string { return makeOnly } -// Print prints repository packages to be downloaded +// Print prints repository packages to be downloaded. func (do *Order) Print() { repo := "" repoMake := "" @@ -153,6 +155,7 @@ func (do *Order) Print() { if do.Runtime.Get(split.Name) { pkgStr += split.Name + " " aurLen++ + push = true } else { pkgStrMake += split.Name + " " @@ -165,15 +168,18 @@ func (do *Order) Print() { pkgStrMake = pkgStrMake[:len(pkgStrMake)-1] + ")" case do.Runtime.Get(base[0].Name): aurLen++ + push = true default: aurMakeLen++ + pushMake = true } if push { aurString += pkgStr } + if pushMake { aurMake += pkgStrMake } diff --git a/pkg/dep/depPool.go b/pkg/dep/depPool.go index 70119b46..c0cb3fcb 100644 --- a/pkg/dep/depPool.go +++ b/pkg/dep/depPool.go @@ -81,7 +81,7 @@ func makePool(dbExecutor db.Executor, aurClient *aur.Client) *Pool { return dp } -// Includes db/ prefixes and group installs +// Includes db/ prefixes and group installs. func (dp *Pool) ResolveTargets(pkgs []string, mode parser.TargetMode, ignoreProviders, noConfirm, provides bool, rebuild string, splitN int, noDeps, noCheckDeps bool, assumeInstalled []string) error { @@ -109,6 +109,7 @@ func (dp *Pool) ResolveTargets(pkgs []string, if target.DB == "aur" || mode == parser.ModeAUR { dp.Targets = append(dp.Targets, target) aurTargets.Set(target.DepString()) + continue } @@ -124,6 +125,7 @@ func (dp *Pool) ResolveTargets(pkgs []string, dp.Targets = append(dp.Targets, target) dp.Explicit.Set(foundPkg.Name()) dp.ResolveRepoDependency(foundPkg, noDeps) + continue } else { // check for groups @@ -169,15 +171,20 @@ func (dp *Pool) ResolveTargets(pkgs []string, // Ofcouse only the first three packages provide yay, the rest are just false // positives. // -// This method increases dependency resolve time +// This method increases dependency resolve time. func (dp *Pool) findProvides(pkgs stringset.StringSet) error { - var mux sync.Mutex - var wg sync.WaitGroup + var ( + mux sync.Mutex + wg sync.WaitGroup + ) doSearch := func(pkg string) { defer wg.Done() - var err error - var results []query.Pkg + + var ( + err error + results []query.Pkg + ) // Hack for a bigger search result, if the user wants // java-envronment we can search for just java instead and get @@ -209,7 +216,9 @@ func (dp *Pool) findProvides(pkgs stringset.StringSet) error { if dp.AlpmExecutor.LocalPackage(pkg) != nil { continue } + wg.Add(1) + go doSearch(pkg) } @@ -264,7 +273,7 @@ func (dp *Pool) cacheAURPackages(_pkgs stringset.StringSet, provides bool, split } // Compute dependency lists used in Package dep searching and ordering. -// Order sensitive TOFIX +// Order sensitive TOFIX. func ComputeCombinedDepList(pkg *aur.Pkg, noDeps, noCheckDeps bool) [][]string { combinedDepList := make([][]string, 0, 3) @@ -310,6 +319,7 @@ func (dp *Pool) resolveAURPackages(pkgs stringset.StringSet, if explicit { dp.Explicit.Set(pkg.Name) } + dp.Aur[pkg.Name] = pkg combinedDepList := ComputeCombinedDepList(pkg, noDeps, noCheckDeps) @@ -330,6 +340,7 @@ func (dp *Pool) resolveAURPackages(pkgs stringset.StringSet, settings.HideMenus = isInstalled repoPkg := dp.AlpmExecutor.SyncSatisfier(dep) // has satisfier in repo: fetch it settings.HideMenus = hm + if isInstalled && (rebuild != "tree" || repoPkg != nil) { continue } @@ -345,11 +356,13 @@ func (dp *Pool) resolveAURPackages(pkgs stringset.StringSet, } err = dp.resolveAURPackages(newAURPackages, false, ignoreProviders, noConfirm, provides, rebuild, splitN, noDeps, noCheckDeps) + return err } func (dp *Pool) ResolveRepoDependency(pkg db.IPackage, noDeps bool) { dp.Repo[pkg.Name()] = pkg + if noDeps { return } @@ -405,7 +418,7 @@ func (dp *Pool) findSatisfierAur(dep string) *query.Pkg { // foo and foo-git. // Using Pacman's ways trying to install foo would never give you // a menu. -// TODO: maybe intermix repo providers in the menu +// TODO: maybe intermix repo providers in the menu. func (dp *Pool) findSatisfierAurCache(dep string, ignoreProviders, noConfirm, provides bool) *query.Pkg { depName, _, _ := splitDep(dep) seen := make(stringset.StringSet) @@ -437,6 +450,7 @@ func (dp *Pool) findSatisfierAurCache(dep string, ignoreProviders, noConfirm, pr if pkgSatisfies(pkg.Name, pkg.Version, dep) { providerSlice.Pkgs = append(providerSlice.Pkgs, pkg) seen.Set(pkg.Name) + continue } @@ -444,6 +458,7 @@ func (dp *Pool) findSatisfierAurCache(dep string, ignoreProviders, noConfirm, pr if provideSatisfies(provide, dep, pkg.Version) { providerSlice.Pkgs = append(providerSlice.Pkgs, pkg) seen.Set(pkg.Name) + continue } } @@ -504,6 +519,7 @@ func (dp *Pool) hasPackage(name string) bool { func isInAssumeInstalled(name string, assumeInstalled []string) bool { for _, pkgAndVersion := range assumeInstalled { assumeName, _, _ := splitDep(pkgAndVersion) + depName, _, _ := splitDep(name) if assumeName == depName { return true @@ -537,9 +553,11 @@ func providerMenu(dep string, providers providers, noConfirm bool) *query.Pkg { } reader := bufio.NewReader(os.Stdin) + numberBuf, overflow, err := reader.ReadLine() if err != nil { fmt.Fprintln(os.Stderr, err) + break } diff --git a/pkg/download/abs_test.go b/pkg/download/abs_test.go index 072d5b7f..3aba7c67 100644 --- a/pkg/download/abs_test.go +++ b/pkg/download/abs_test.go @@ -36,6 +36,7 @@ package() { }` func Test_getPackageURL(t *testing.T) { + t.Parallel() type args struct { db string pkgName string @@ -75,7 +76,9 @@ func Test_getPackageURL(t *testing.T) { }, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() got, err := getPackageURL(tt.args.db, tt.args.pkgName) if tt.wantErr { assert.ErrorIs(t, err, ErrInvalidRepository) @@ -86,6 +89,7 @@ func Test_getPackageURL(t *testing.T) { } func TestGetABSPkgbuild(t *testing.T) { + t.Parallel() pkgBuildHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(200) w.Write([]byte(gitExtrasPKGBUILD)) @@ -95,7 +99,6 @@ func TestGetABSPkgbuild(t *testing.T) { w.WriteHeader(404) }) - PKGBuild := httptest.NewServer(pkgBuildHandler) type args struct { handler http.Handler dbName string @@ -129,7 +132,10 @@ func TestGetABSPkgbuild(t *testing.T) { }, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() + PKGBuild := httptest.NewServer(pkgBuildHandler) ABSPackageURL = PKGBuild.URL PKGBuild.Config.Handler = tt.args.handler got, err := ABSPKGBUILD(PKGBuild.Client(), tt.args.dbName, tt.args.pkgName) @@ -145,8 +151,7 @@ func TestGetABSPkgbuild(t *testing.T) { } func Test_getPackageRepoURL(t *testing.T) { - ABSPackageURL = "https://github.com/archlinux/svntogit-packages" - ABSCommunityURL = "https://github.com/archlinux/svntogit-community" + t.Parallel() type args struct { db string @@ -177,7 +182,9 @@ func Test_getPackageRepoURL(t *testing.T) { }, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() got, err := getPackageRepoURL(tt.args.db) if tt.wantErr { assert.ErrorIs(t, err, ErrInvalidRepository) @@ -191,6 +198,7 @@ func Test_getPackageRepoURL(t *testing.T) { // WHEN ABSPKGBUILDRepo is called // THEN a clone command should be formed func TestABSPKGBUILDRepo(t *testing.T) { + t.Parallel() cmdRunner := &testRunner{} cmdBuilder := &testGitBuilder{ index: 0, @@ -211,6 +219,7 @@ func TestABSPKGBUILDRepo(t *testing.T) { // WHEN ABSPKGBUILDRepo is called // THEN a pull command should be formed func TestABSPKGBUILDRepoExistsPerms(t *testing.T) { + t.Parallel() dir, _ := ioutil.TempDir("/tmp/", "yay-test") defer os.RemoveAll(dir) diff --git a/pkg/download/aur.go b/pkg/download/aur.go index ac7aa362..b5ab7e5c 100644 --- a/pkg/download/aur.go +++ b/pkg/download/aur.go @@ -14,8 +14,6 @@ import ( "github.com/Jguer/yay/v10/pkg/text" ) -var AURPackageURL = "https://aur.archlinux.org/cgit/aur.git" - func AURPKGBUILD(httpClient *http.Client, pkgName, aurURL string) ([]byte, error) { values := url.Values{} values.Set("h", pkgName) @@ -69,6 +67,7 @@ func AURPKGBUILDRepos( newClone, err := AURPKGBUILDRepo(cmdBuilder, aurURL, target, dest, force) progress := 0 + if err != nil { errs.Add(err) } else { diff --git a/pkg/download/aur_test.go b/pkg/download/aur_test.go index dcc21745..9f5e219c 100644 --- a/pkg/download/aur_test.go +++ b/pkg/download/aur_test.go @@ -15,6 +15,7 @@ import ( ) func TestGetAURPkgbuild(t *testing.T) { + t.Parallel() pkgBuildHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(200) w.Write([]byte(gitExtrasPKGBUILD)) @@ -24,7 +25,6 @@ func TestGetAURPkgbuild(t *testing.T) { w.WriteHeader(404) }) - PKGBuild := httptest.NewServer(pkgBuildHandler) type args struct { handler http.Handler pkgName string @@ -55,7 +55,10 @@ func TestGetAURPkgbuild(t *testing.T) { }, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() + PKGBuild := httptest.NewServer(pkgBuildHandler) PKGBuild.Config.Handler = tt.args.handler got, err := AURPKGBUILD(PKGBuild.Client(), tt.args.pkgName, PKGBuild.URL) if tt.wantErr { @@ -73,6 +76,7 @@ func TestGetAURPkgbuild(t *testing.T) { // WHEN AURPKGBUILDRepo is called // THEN a clone command should be formed func TestAURPKGBUILDRepo(t *testing.T) { + t.Parallel() cmdRunner := &testRunner{} cmdBuilder := &testGitBuilder{ index: 0, @@ -93,6 +97,7 @@ func TestAURPKGBUILDRepo(t *testing.T) { // WHEN AURPKGBUILDRepo is called // THEN a pull command should be formed func TestAURPKGBUILDRepoExistsPerms(t *testing.T) { + t.Parallel() dir, _ := ioutil.TempDir("/tmp/", "yay-test") defer os.RemoveAll(dir) @@ -114,8 +119,8 @@ func TestAURPKGBUILDRepoExistsPerms(t *testing.T) { assert.Equal(t, false, cloned) } -// GIVEN func TestAURPKGBUILDRepos(t *testing.T) { + t.Parallel() dir, _ := ioutil.TempDir("/tmp/", "yay-test") defer os.RemoveAll(dir) diff --git a/pkg/download/unified.go b/pkg/download/unified.go index 26e3ca39..e2c90089 100644 --- a/pkg/download/unified.go +++ b/pkg/download/unified.go @@ -25,7 +25,8 @@ func downloadGitRepo(cmdBuilder exe.GitCmdBuilder, finalDir := filepath.Join(dest, pkgName) newClone := true - if _, err := os.Stat(filepath.Join(finalDir, ".git")); os.IsNotExist(err) || (err == nil && force) { + switch _, err := os.Stat(filepath.Join(finalDir, ".git")); { + case os.IsNotExist(err) || (err == nil && force): if _, errD := os.Stat(finalDir); force && errD == nil { if errR := os.RemoveAll(finalDir); errR != nil { return false, ErrGetPKGBUILDRepo{inner: errR, pkgName: pkgName, errOut: ""} @@ -43,19 +44,20 @@ func downloadGitRepo(cmdBuilder exe.GitCmdBuilder, if errCapture != nil { return false, ErrGetPKGBUILDRepo{inner: errCapture, pkgName: pkgName, errOut: stderr} } - } else if err != nil { + case err != nil: return false, ErrGetPKGBUILDRepo{ inner: err, pkgName: pkgName, errOut: gotext.Get("error reading %s", filepath.Join(dest, pkgName, ".git")), } - } else { + default: cmd := cmdBuilder.BuildGitCmd(filepath.Join(dest, pkgName), "pull", "--ff-only") _, stderr, errCmd := cmdBuilder.Capture(cmd, 0) if errCmd != nil { return false, ErrGetPKGBUILDRepo{inner: errCmd, pkgName: pkgName, errOut: stderr} } + newClone = false } @@ -149,8 +151,10 @@ func PKGBUILDRepos(dbExecutor DBSearcher, wg.Add(1) go func(target, dbName, pkgName string, aur bool) { - var err error - var newClone bool + var ( + err error + newClone bool + ) if aur { newClone, err = AURPKGBUILDRepo(cmdBuilder, aurURL, pkgName, dest, force) @@ -159,6 +163,7 @@ func PKGBUILDRepos(dbExecutor DBSearcher, } progress := 0 + if err != nil { errs.Add(err) } else { @@ -189,7 +194,7 @@ func PKGBUILDRepos(dbExecutor DBSearcher, return cloned, errs.Return() } -// TODO: replace with dep.ResolveTargets +// TODO: replace with dep.ResolveTargets. func getPackageUsableName(dbExecutor DBSearcher, target string, mode parser.TargetMode) (dbname, pkgname string, aur, toSkip bool) { aur = true diff --git a/pkg/download/unified_test.go b/pkg/download/unified_test.go index bf76f3b4..b29534d7 100644 --- a/pkg/download/unified_test.go +++ b/pkg/download/unified_test.go @@ -19,6 +19,7 @@ import ( // WHEN defining package db as a target // THEN all should be found and cloned, except the repo one func TestPKGBUILDReposDefinedDBPull(t *testing.T) { + t.Parallel() dir, _ := ioutil.TempDir("/tmp/", "yay-test") defer os.RemoveAll(dir) @@ -50,6 +51,7 @@ func TestPKGBUILDReposDefinedDBPull(t *testing.T) { // WHEN defining package db as a target // THEN all should be found and cloned func TestPKGBUILDReposDefinedDBClone(t *testing.T) { + t.Parallel() dir, _ := ioutil.TempDir("/tmp/", "yay-test") defer os.RemoveAll(dir) @@ -79,6 +81,7 @@ func TestPKGBUILDReposDefinedDBClone(t *testing.T) { // WHEN defining as non specified targets // THEN all should be found and cloned func TestPKGBUILDReposClone(t *testing.T) { + t.Parallel() dir, _ := ioutil.TempDir("/tmp/", "yay-test") defer os.RemoveAll(dir) @@ -108,6 +111,7 @@ func TestPKGBUILDReposClone(t *testing.T) { // WHEN defining as non specified targets // THEN all aur be found and cloned func TestPKGBUILDReposNotFound(t *testing.T) { + t.Parallel() dir, _ := ioutil.TempDir("/tmp/", "yay-test") defer os.RemoveAll(dir) @@ -137,6 +141,7 @@ func TestPKGBUILDReposNotFound(t *testing.T) { // WHEN defining as non specified targets in repo mode // THEN only repo should be cloned func TestPKGBUILDReposRepoMode(t *testing.T) { + t.Parallel() dir, _ := ioutil.TempDir("/tmp/", "yay-test") defer os.RemoveAll(dir) @@ -166,7 +171,7 @@ func TestPKGBUILDReposRepoMode(t *testing.T) { // WHEN defining as specified targets // THEN all aur be found and cloned func TestPKGBUILDFull(t *testing.T) { - defer gock.Off() + t.Parallel() gock.New("https://aur.archlinux.org"). Get("/cgit/aur.git/plain/PKGBUILD").MatchParam("h", "yay-git"). @@ -182,6 +187,7 @@ func TestPKGBUILDFull(t *testing.T) { Reply(200). BodyString("example_yay") + defer gock.Off() targets := []string{"core/yay", "aur/yay-bin", "yay-git"} searcher := &testDBSearcher{ absPackagesDB: map[string]string{"yay": "core"}, diff --git a/pkg/intrange/intrange.go b/pkg/intrange/intrange.go index 2a1ad0ed..8ca726a5 100644 --- a/pkg/intrange/intrange.go +++ b/pkg/intrange/intrange.go @@ -8,13 +8,13 @@ import ( "github.com/Jguer/yay/v10/pkg/stringset" ) -// IntRange stores a max and min amount for range +// IntRange stores a max and min amount for range. type IntRange struct { min int max int } -// IntRanges is a slice of IntRange +// IntRanges is a slice of IntRange. type IntRanges []IntRange func makeIntRange(min, max int) IntRange { @@ -25,13 +25,13 @@ func makeIntRange(min, max int) IntRange { } // Get returns true if the argument n is included in the closed range -// between min and max +// between min and max. func (r IntRange) Get(n int) bool { return n >= r.min && n <= r.max } // Get returns true if the argument n is included in the closed range -// between min and max of any of the provided IntRanges +// between min and max of any of the provided IntRanges. func (rs IntRanges) Get(n int) bool { for _, r := range rs { if r.Get(n) { @@ -42,19 +42,21 @@ func (rs IntRanges) Get(n int) bool { return false } -// Min returns min value between a and b +// Min returns min value between a and b. func Min(a, b int) int { if a < b { return a } + return b } -// Max returns max value between a and b +// Max returns max value between a and b. func Max(a, b int) int { if a < b { return b } + return a } @@ -67,7 +69,7 @@ func Max(a, b int) int { // respectively. other holds anything that can't be parsed as an int. This is // intended to allow words inside of number menus. e.g. 'all' 'none' 'abort' // of course the implementation is up to the caller, this function mearley parses -// the input and organizes it +// the input and organizes it. func ParseNumberMenu(input string) (include, exclude IntRanges, otherInclude, otherExclude stringset.StringSet) { include = make(IntRanges, 0) @@ -80,9 +82,12 @@ func ParseNumberMenu(input string) (include, exclude IntRanges, }) for _, word := range words { - var num1 int - var num2 int - var err error + var ( + num1 int + num2 int + err error + ) + invert := false other := otherInclude diff --git a/pkg/intrange/intrange_test.go b/pkg/intrange/intrange_test.go index 78fe1752..c71b38bd 100644 --- a/pkg/intrange/intrange_test.go +++ b/pkg/intrange/intrange_test.go @@ -7,6 +7,7 @@ import ( ) func TestParseNumberMenu(t *testing.T) { + t.Parallel() type result struct { Include IntRanges Exclude IntRanges @@ -99,6 +100,7 @@ func TestParseNumberMenu(t *testing.T) { } func TestIntRange_Get(t *testing.T) { + t.Parallel() type fields struct { min int max int @@ -120,7 +122,9 @@ func TestIntRange_Get(t *testing.T) { {name: "normal end range false", fields: fields{1, 2}, args: args{3}, want: false}, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() r := IntRange{ min: tt.fields.min, max: tt.fields.max, @@ -158,6 +162,7 @@ func intRangesEqual(a, b IntRanges) bool { } func TestIntRanges_Get(t *testing.T) { + t.Parallel() type args struct { n int } @@ -168,8 +173,8 @@ func TestIntRanges_Get(t *testing.T) { want bool }{ {name: "normal range true", rs: IntRanges{{0, 10}}, args: args{5}, want: true}, - {name: "normal ranges inbetween true", rs: IntRanges{{0, 4}, {5, 10}}, args: args{5}, want: true}, - {name: "normal ranges inbetween false", rs: IntRanges{{0, 4}, {6, 10}}, args: args{5}, want: false}, + {name: "normal ranges in between true", rs: IntRanges{{0, 4}, {5, 10}}, args: args{5}, want: true}, + {name: "normal ranges in between false", rs: IntRanges{{0, 4}, {6, 10}}, args: args{5}, want: false}, {name: "normal start range true", rs: IntRanges{{0, 10}}, args: args{0}, want: true}, {name: "normal end range true", rs: IntRanges{{0, 10}}, args: args{10}, want: true}, {name: "small range true", rs: IntRanges{{1, 1}, {3, 3}}, args: args{1}, want: true}, @@ -177,7 +182,9 @@ func TestIntRanges_Get(t *testing.T) { {name: "normal end range false", rs: IntRanges{{1, 2}}, args: args{3}, want: false}, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() if got := tt.rs.Get(tt.args.n); got != tt.want { t.Errorf("IntRanges.Get() = %v, want %v", got, tt.want) } diff --git a/pkg/multierror/multierror.go b/pkg/multierror/multierror.go index 4d2bb4d3..d718afff 100644 --- a/pkg/multierror/multierror.go +++ b/pkg/multierror/multierror.go @@ -2,13 +2,13 @@ package multierror import "sync" -// MultiError type handles error accumulation from goroutines +// MultiError type handles error accumulation from goroutines. type MultiError struct { Errors []error mux sync.Mutex } -// Error turns the MultiError structure into a string +// Error turns the MultiError structure into a string. func (err *MultiError) Error() string { str := "" @@ -19,7 +19,7 @@ func (err *MultiError) Error() string { return str[:len(str)-1] } -// Add adds an error to the Multierror structure +// Add adds an error to the Multierror structure. func (err *MultiError) Add(e error) { if e == nil { return @@ -31,7 +31,7 @@ func (err *MultiError) Add(e error) { } // Return is used as a wrapper on return on whether to return the -// MultiError Structure if errors exist or nil instead of delivering an empty structure +// MultiError Structure if errors exist or nil instead of delivering an empty structure. func (err *MultiError) Return() error { if len(err.Errors) > 0 { return err diff --git a/pkg/news/news.go b/pkg/news/news.go index 0a03b942..9d2d0612 100644 --- a/pkg/news/news.go +++ b/pkg/news/news.go @@ -26,6 +26,7 @@ type item struct { func (item *item) print(buildTime time.Time, all, quiet bool) { var fd string + date, err := time.Parse(time.RFC1123Z, item.PubDate) if err != nil { @@ -72,6 +73,7 @@ func PrintNewsFeed(client *http.Client, cutOffDate time.Time, sortMode int, all, } defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) if err != nil { return err @@ -80,8 +82,7 @@ func PrintNewsFeed(client *http.Client, cutOffDate time.Time, sortMode int, all, rssGot := rss{} d := xml.NewDecoder(bytes.NewReader(body)) - err = d.Decode(&rssGot) - if err != nil { + if err := d.Decode(&rssGot); err != nil { return err } @@ -100,18 +101,21 @@ func PrintNewsFeed(client *http.Client, cutOffDate time.Time, sortMode int, all, // Crude html parsing, good enough for the arch news // This is only displayed in the terminal so there should be no security -// concerns +// concerns. func parseNews(str string) string { - var buffer bytes.Buffer - var tagBuffer bytes.Buffer - var escapeBuffer bytes.Buffer - inTag := false - inEscape := false + var ( + buffer bytes.Buffer + tagBuffer bytes.Buffer + escapeBuffer bytes.Buffer + inTag = false + inEscape = false + ) for _, char := range str { if inTag { if char == '>' { inTag = false + switch tagBuffer.String() { case "code": buffer.WriteString(text.CyanCode) @@ -125,32 +129,40 @@ func parseNews(str string) string { } tagBuffer.WriteRune(char) + continue } if inEscape { if char == ';' { inEscape = false + escapeBuffer.WriteRune(char) s := html.UnescapeString(escapeBuffer.String()) buffer.WriteString(s) + continue } escapeBuffer.WriteRune(char) + continue } if char == '<' { inTag = true + tagBuffer.Reset() + continue } if char == '&' { inEscape = true + escapeBuffer.Reset() escapeBuffer.WriteRune(char) + continue } @@ -158,5 +170,6 @@ func parseNews(str string) string { } buffer.WriteString(text.ResetCode) + return buffer.String() } diff --git a/pkg/news/news_test.go b/pkg/news/news_test.go index 36fc4aaf..a2059c8d 100644 --- a/pkg/news/news_test.go +++ b/pkg/news/news_test.go @@ -79,6 +79,7 @@ intervention when you hit this message:</p> ` func TestPrintNewsFeed(t *testing.T) { + t.Parallel() layout := "2006-01-02" str := "2020-04-13" lastNewsTime, _ := time.Parse(layout, str) @@ -100,13 +101,15 @@ func TestPrintNewsFeed(t *testing.T) { {name: "latest-quiet-topdown", args: args{sortMode: 1, cutOffDate: lastNewsTime, all: false, quiet: true}, wantErr: false}, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { - defer gock.Off() - gock.New("https://archlinux.org"). Get("/feeds/news"). Reply(200). BodyString(sampleNews) + + defer gock.Off() + rescueStdout := os.Stdout r, w, _ := os.Pipe() os.Stdout = w diff --git a/pkg/pgp/keys.go b/pkg/pgp/keys.go index 6423d08f..26ba448b 100644 --- a/pkg/pgp/keys.go +++ b/pkg/pgp/keys.go @@ -24,6 +24,7 @@ func (set pgpKeySet) toSlice() []string { for v := range set { slice = append(slice, v) } + return slice } @@ -37,6 +38,7 @@ func (set pgpKeySet) set(key string, p dep.Base) { func (set pgpKeySet) get(key string) bool { upperKey := strings.ToUpper(key) _, exists := set[upperKey] + return exists } @@ -47,6 +49,7 @@ func CheckPgpKeys(bases []dep.Base, srcinfos map[string]*gosrc.Srcinfo, // Let's check the keys individually, and then we can offer to import // the problematic ones. problematic := make(pgpKeySet) + args := append(strings.Fields(gpgFlags), "--list-keys") // Mapping all the keys. @@ -63,8 +66,7 @@ func CheckPgpKeys(bases []dep.Base, srcinfos map[string]*gosrc.Srcinfo, } cmd := exec.Command(gpgBin, append(args, key)...) - err := cmd.Run() - if err != nil { + if err := cmd.Run(); err != nil { problematic.set(key, base) } } @@ -97,10 +99,11 @@ func importKeys(keys []string, gpgBin, gpgFlags string) error { cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr text.OperationInfoln(gotext.Get("Importing keys with gpg...")) - err := cmd.Run() - if err != nil { + + if err := cmd.Run(); err != nil { return errors.New(gotext.Get("problem importing keys")) } + return nil } @@ -112,14 +115,18 @@ func formatKeysToImport(keys pgpKeySet) (string, error) { } var buffer bytes.Buffer + buffer.WriteString(text.SprintOperationInfo(gotext.Get("PGP keys need importing:"))) + for key, bases := range keys { pkglist := "" for _, base := range bases { pkglist += base.String() + " " } + pkglist = strings.TrimRight(pkglist, " ") buffer.WriteString("\n" + text.SprintWarn(gotext.Get("%s, required by: %s", text.Cyan(key), text.Cyan(pkglist)))) } + return buffer.String(), nil } diff --git a/pkg/pgp/keys_test.go b/pkg/pgp/keys_test.go index 741027cf..9056d610 100644 --- a/pkg/pgp/keys_test.go +++ b/pkg/pgp/keys_test.go @@ -241,6 +241,7 @@ func TestCheckPgpKeys(t *testing.T) { } for _, tt := range casetests { + tt := tt t.Run(tt.name, func(t *testing.T) { rescueStdout := os.Stdout r, w, _ := os.Pipe() diff --git a/pkg/query/aur_info.go b/pkg/query/aur_info.go index 212d4b3d..1c92d5cc 100644 --- a/pkg/query/aur_info.go +++ b/pkg/query/aur_info.go @@ -22,17 +22,22 @@ type Pkg = aur.Pkg func AURInfo(aurClient *aur.Client, names []string, warnings *AURWarnings, splitN int) ([]*Pkg, error) { info := make([]*Pkg, 0, len(names)) seen := make(map[string]int) - var mux sync.Mutex - var wg sync.WaitGroup - var errs multierror.MultiError + + var ( + mux sync.Mutex + wg sync.WaitGroup + errs multierror.MultiError + ) makeRequest := func(n, max int) { defer wg.Done() + tempInfo, requestErr := aurClient.Info(context.Background(), names[n:max]) - errs.Add(requestErr) if requestErr != nil { + errs.Add(requestErr) return } + mux.Lock() for i := range tempInfo { info = append(info, &tempInfo[i]) @@ -42,7 +47,9 @@ func AURInfo(aurClient *aur.Client, names []string, warnings *AURWarnings, split for n := 0; n < len(names); n += splitN { max := intrange.Min(len(names), n+splitN) + wg.Add(1) + go makeRequest(n, max) } @@ -68,6 +75,7 @@ func AURInfo(aurClient *aur.Client, names []string, warnings *AURWarnings, split if pkg.Maintainer == "" && !warnings.Ignore.Get(name) { warnings.Orphans = append(warnings.Orphans, name) } + if pkg.OutOfDate != 0 && !warnings.Ignore.Get(name) { warnings.OutOfDate = append(warnings.OutOfDate, name) } @@ -80,6 +88,7 @@ func AURInfoPrint(aurClient *aur.Client, names []string, splitN int) ([]*Pkg, er text.OperationInfoln(gotext.Get("Querying AUR...")) warnings := &AURWarnings{} + info, err := AURInfo(aurClient, names, warnings, splitN) if err != nil { return info, err diff --git a/pkg/query/aur_warnings.go b/pkg/query/aur_warnings.go index 6c2d251f..ffe2e3f1 100644 --- a/pkg/query/aur_warnings.go +++ b/pkg/query/aur_warnings.go @@ -64,5 +64,6 @@ func printRange(names []string) { for _, name := range names { fmt.Print(" " + text.Cyan(name)) } + fmt.Println() } diff --git a/pkg/query/filter.go b/pkg/query/filter.go index 4a6ec098..617ff113 100644 --- a/pkg/query/filter.go +++ b/pkg/query/filter.go @@ -8,7 +8,7 @@ import ( "github.com/Jguer/yay/v10/pkg/text" ) -// GetPackageNamesBySource returns package names with and without correspondence in SyncDBS respectively +// GetPackageNamesBySource returns package names with and without correspondence in SyncDBS respectively. func GetPackageNamesBySource(dbExecutor db.Executor) (local, remote []string, err error) { for _, localpkg := range dbExecutor.LocalPackages() { pkgName := localpkg.Name() @@ -18,6 +18,7 @@ func GetPackageNamesBySource(dbExecutor db.Executor) (local, remote []string, er remote = append(remote, pkgName) } } + return local, remote, err } @@ -32,6 +33,7 @@ func GetRemotePackages(dbExecutor db.Executor) ( remoteNames = append(remoteNames, pkgName) } } + return remote, remoteNames } diff --git a/pkg/settings/config.go b/pkg/settings/config.go index 74ffeb5e..6d168121 100644 --- a/pkg/settings/config.go +++ b/pkg/settings/config.go @@ -20,15 +20,15 @@ import ( ) const ( - // Describes Sorting method for numberdisplay + // Describes Sorting method for numberdisplay. BottomUp = iota TopDown ) -// HideMenus indicates if pacman's provider menus must be hidden +// HideMenus indicates if pacman's provider menus must be hidden. var HideMenus = false -// NoConfirm indicates if user input should be skipped +// NoConfirm indicates if user input should be skipped. var NoConfirm = false // Configuration stores yay's config. @@ -93,14 +93,17 @@ func (c *Configuration) Save(configPath string) error { return mkErr } } + in, err := os.OpenFile(configPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o644) if err != nil { return err } defer in.Close() + if _, err = in.Write(marshalledinfo); err != nil { return err } + return in.Sync() } @@ -136,9 +139,11 @@ func (c *Configuration) String() string { var buf bytes.Buffer enc := json.NewEncoder(&buf) enc.SetIndent("", "\t") + if err := enc.Encode(c); err != nil { fmt.Fprintln(os.Stderr, err) } + return buf.String() } @@ -249,6 +254,7 @@ func (c *Configuration) load(configPath string) { } defer cfile.Close() + if !os.IsNotExist(err) { decoder := json.NewDecoder(cfile) if err = decoder.Decode(c); err != nil { @@ -262,6 +268,7 @@ func (c *Configuration) CmdBuilder(runner exe.Runner) exe.ICmdBuilder { if runner == nil { runner = &exe.OSRunner{} } + return &exe.CmdBuilder{ GitBin: c.GitBin, GitFlags: strings.Fields(c.GitFlags), diff --git a/pkg/settings/exe/cmd_builder.go b/pkg/settings/exe/cmd_builder.go index 5d635b75..8d77b935 100644 --- a/pkg/settings/exe/cmd_builder.go +++ b/pkg/settings/exe/cmd_builder.go @@ -58,7 +58,9 @@ func (c *CmdBuilder) BuildGitCmd(dir string, extraArgs ...string) *exec.Cmd { } cmd := exec.Command(c.GitBin, args...) + cmd.Env = append(os.Environ(), "GIT_TERMINAL_PROMPT=0") + return cmd } @@ -80,6 +82,7 @@ func (c *CmdBuilder) BuildMakepkgCmd(dir string, extraArgs ...string) *exec.Cmd cmd := exec.Command(c.MakepkgBin, args...) cmd.Dir = dir + return cmd } @@ -99,6 +102,7 @@ func (c *CmdBuilder) BuildPacmanCmd(args *parser.Arguments, mode parser.TargetMo argArr = append(argArr, c.PacmanBin) argArr = append(argArr, args.FormatGlobals()...) argArr = append(argArr, args.FormatArgs()...) + if noConfirm { argArr = append(argArr, "--noconfirm") } @@ -109,10 +113,11 @@ func (c *CmdBuilder) BuildPacmanCmd(args *parser.Arguments, mode parser.TargetMo if needsRoot { waitLock(c.PacmanDBPath) } + return exec.Command(argArr[0], argArr[1:]...) } -// waitLock will lock yay checking the status of db.lck until it does not exist +// waitLock will lock yay checking the status of db.lck until it does not exist. func waitLock(dbPath string) { lockDBPath := filepath.Join(dbPath, "db.lck") if _, err := os.Stat(lockDBPath); err != nil { @@ -124,8 +129,10 @@ func waitLock(dbPath string) { for { time.Sleep(3 * time.Second) + if _, err := os.Stat(lockDBPath); err != nil { fmt.Println() + return } } @@ -133,6 +140,7 @@ func waitLock(dbPath string) { func (c *CmdBuilder) SudoLoop() { c.updateSudo() + go c.sudoLoopBackground() } diff --git a/pkg/settings/exe/exec.go b/pkg/settings/exe/exec.go index 8da7019e..1cf0bcb6 100644 --- a/pkg/settings/exe/exec.go +++ b/pkg/settings/exe/exec.go @@ -17,8 +17,7 @@ type Runner interface { Show(cmd *exec.Cmd) error } -type OSRunner struct { -} +type OSRunner struct{} func (r *OSRunner) Show(cmd *exec.Cmd) error { cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr @@ -26,9 +25,11 @@ func (r *OSRunner) Show(cmd *exec.Cmd) error { } func (r *OSRunner) Capture(cmd *exec.Cmd, timeout int64) (stdout, stderr string, err error) { - var outbuf, errbuf bytes.Buffer - var timer *time.Timer - timedOut := false + var ( + outbuf, errbuf bytes.Buffer + timer *time.Timer + timedOut = false + ) cmd.Stdout = &outbuf cmd.Stderr = &errbuf @@ -38,6 +39,7 @@ func (r *OSRunner) Capture(cmd *exec.Cmd, timeout int64) (stdout, stderr string, if err != nil { stdout = strings.TrimSpace(outbuf.String()) stderr = strings.TrimSpace(errbuf.String()) + return stdout, stderr, err } @@ -52,12 +54,14 @@ func (r *OSRunner) Capture(cmd *exec.Cmd, timeout int64) (stdout, stderr string, } err = cmd.Wait() + if timeout != 0 { timer.Stop() } stdout = strings.TrimSpace(outbuf.String()) stderr = strings.TrimSpace(errbuf.String()) + if err != nil { return stdout, stderr, err } diff --git a/pkg/settings/parser/parser.go b/pkg/settings/parser/parser.go index 74e5d51e..0e61755a 100644 --- a/pkg/settings/parser/parser.go +++ b/pkg/settings/parser/parser.go @@ -20,6 +20,7 @@ func (o *Option) Add(args ...string) { o.Args = args return } + o.Args = append(o.Args, args...) } @@ -27,6 +28,7 @@ func (o *Option) First() string { if o.Args == nil || len(o.Args) == 0 { return "" } + return o.Args[0] } @@ -70,6 +72,7 @@ func MakeArguments() *Arguments { func (a *Arguments) CopyGlobal() *Arguments { cp := MakeArguments() + for k, v := range a.Options { if v.Global { cp.Options[k] = v @@ -110,44 +113,44 @@ func (a *Arguments) NeedRoot(mode TargetMode) bool { if a.ExistsArg("k", "check") { return false } + return true case "F", "files": if a.ExistsArg("y", "refresh") { return true } + return false case "Q", "query": if a.ExistsArg("k", "check") { return true } + return false case "R", "remove": if a.ExistsArg("p", "print", "print-format") { return false } + return true case "S", "sync": - if a.ExistsArg("y", "refresh") { + switch { + case a.ExistsArg("y", "refresh"): return true - } - if a.ExistsArg("p", "print", "print-format") { - return false - } - if a.ExistsArg("s", "search") { - return false - } - if a.ExistsArg("l", "list") { - return false - } - if a.ExistsArg("g", "groups") { - return false - } - if a.ExistsArg("i", "info") { - return false - } - if a.ExistsArg("c", "clean") && mode == ModeAUR { + case a.ExistsArg("p", "print", "print-format"): + return false + case a.ExistsArg("s", "search"): + return false + case a.ExistsArg("l", "list"): + return false + case a.ExistsArg("g", "groups"): + return false + case a.ExistsArg("i", "info"): + return false + case a.ExistsArg("c", "clean") && mode == ModeAUR: return false } + return true case "U", "upgrade": return true @@ -162,6 +165,7 @@ func (a *Arguments) addOP(op string) error { } a.Op = op + return nil } @@ -179,6 +183,7 @@ func (a *Arguments) addParam(option, arg string) error { if isGlobal(option) { a.Options[option].Global = true } + return nil } @@ -189,16 +194,18 @@ func (a *Arguments) AddArg(options ...string) error { return err } } + return nil } -// Multiple args acts as an OR operator +// Multiple args acts as an OR operator. func (a *Arguments) ExistsArg(options ...string) bool { for _, option := range options { if _, exists := a.Options[option]; exists { return true } } + return false } @@ -230,13 +237,14 @@ func (a *Arguments) ClearTargets() { a.Targets = make([]string, 0) } -// Multiple args acts as an OR operator +// Multiple args acts as an OR operator. func (a *Arguments) ExistsDouble(options ...string) bool { for _, option := range options { if value, exists := a.Options[option]; exists { return len(value.Args) >= 2 } } + return false } @@ -258,6 +266,7 @@ func (a *Arguments) FormatArgs() (args []string) { } } } + return args } @@ -266,6 +275,7 @@ func (a *Arguments) FormatGlobals() (args []string) { if !arg.Global { continue } + formattedOption := formatArg(option) for _, value := range arg.Args { @@ -275,6 +285,7 @@ func (a *Arguments) FormatGlobals() (args []string) { } } } + return args } @@ -534,7 +545,7 @@ func hasParam(arg string) bool { } // Parses short hand options such as: -// -Syu -b/some/path - +// -Syu -b/some/path -. func (a *Arguments) parseShortOption(arg, param string) (usedNext bool, err error) { if arg == "-" { err = a.AddArg("-") @@ -568,7 +579,7 @@ func (a *Arguments) parseShortOption(arg, param string) (usedNext bool, err erro } // Parses full length options such as: -// --sync --refresh --sysupgrade --dbpath /some/path -- +// --sync --refresh --sysupgrade --dbpath /some/path --. func (a *Arguments) parseLongOption(arg, param string) (usedNext bool, err error) { if arg == "--" { err = a.AddArg(arg) @@ -648,6 +659,7 @@ func (a *Arguments) Parse() error { if err := a.parseStdin(); err != nil { return err } + a.DelArg("-") file, err := os.Open("/dev/tty") diff --git a/pkg/settings/parser/parser_test.go b/pkg/settings/parser/parser_test.go index 32d33082..013ee9a9 100644 --- a/pkg/settings/parser/parser_test.go +++ b/pkg/settings/parser/parser_test.go @@ -7,6 +7,7 @@ import ( ) func TestOption_Add(t *testing.T) { + t.Parallel() type fields struct { Args []string } @@ -31,7 +32,9 @@ func TestOption_Add(t *testing.T) { }, want: []string{"c"}}, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() o := &Option{ Args: tt.fields.Args, } @@ -42,6 +45,7 @@ func TestOption_Add(t *testing.T) { } func TestOption_Set(t *testing.T) { + t.Parallel() type fields struct { Args []string } @@ -66,7 +70,9 @@ func TestOption_Set(t *testing.T) { }, want: []string{"c"}}, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() o := &Option{ Args: tt.fields.Args, } @@ -77,6 +83,7 @@ func TestOption_Set(t *testing.T) { } func TestOption_First(t *testing.T) { + t.Parallel() type fields struct { Args []string } @@ -93,7 +100,9 @@ func TestOption_First(t *testing.T) { }, want: ""}, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() o := &Option{ Args: tt.fields.Args, } @@ -103,6 +112,7 @@ func TestOption_First(t *testing.T) { } func TestMakeArguments(t *testing.T) { + t.Parallel() args := MakeArguments() assert.NotNil(t, args) assert.Equal(t, "", args.Op) @@ -111,6 +121,7 @@ func TestMakeArguments(t *testing.T) { } func TestArguments_CopyGlobal(t *testing.T) { + t.Parallel() type fields struct { Op string Options map[string]*Option @@ -142,7 +153,9 @@ func TestArguments_CopyGlobal(t *testing.T) { }}, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() cmdArgs := &Arguments{ Op: tt.fields.Op, Options: tt.fields.Options, @@ -158,6 +171,7 @@ func TestArguments_CopyGlobal(t *testing.T) { } func TestArguments_Copy(t *testing.T) { + t.Parallel() type fields struct { Op string Options map[string]*Option @@ -188,7 +202,9 @@ func TestArguments_Copy(t *testing.T) { }}, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() cmdArgs := &Arguments{ Op: tt.fields.Op, Options: tt.fields.Options, @@ -202,6 +218,7 @@ func TestArguments_Copy(t *testing.T) { } func TestArguments_DelArg(t *testing.T) { + t.Parallel() args := MakeArguments() args.addParam("arch", "arg") args.addParam("ask", "arg") @@ -210,6 +227,7 @@ func TestArguments_DelArg(t *testing.T) { } func TestArguments_FormatArgs(t *testing.T) { + t.Parallel() type fields struct { Op string Options map[string]*Option @@ -242,7 +260,9 @@ func TestArguments_FormatArgs(t *testing.T) { }, wantArgs: []string{"-Y", "--overwrite", "/tmp/a", "--overwrite", "/tmp/b", "--overwrite", "/tmp/c", "--needed"}}, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() cmdArgs := &Arguments{ Op: tt.fields.Op, Options: tt.fields.Options, @@ -255,6 +275,7 @@ func TestArguments_FormatArgs(t *testing.T) { } func TestArguments_FormatGlobalArgs(t *testing.T) { + t.Parallel() type fields struct { Op string Options map[string]*Option @@ -287,7 +308,9 @@ func TestArguments_FormatGlobalArgs(t *testing.T) { }, wantArgs: []string(nil)}, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() cmdArgs := &Arguments{ Op: tt.fields.Op, Options: tt.fields.Options, @@ -300,6 +323,7 @@ func TestArguments_FormatGlobalArgs(t *testing.T) { } func Test_isArg(t *testing.T) { + t.Parallel() got := isArg("zorg") assert.False(t, got) diff --git a/pkg/stringset/stringset.go b/pkg/stringset/stringset.go index a820c99c..4be4f5a7 100644 --- a/pkg/stringset/stringset.go +++ b/pkg/stringset/stringset.go @@ -13,12 +13,12 @@ type MapStringSet map[string]StringSet // Add adds a new value to the Map. // If n is already in the map, then v is appended to the StringSet under that key. -// Otherwise a new StringSet is creayed containing v +// Otherwise a new StringSet is creayed containing v. func (mss MapStringSet) Add(n, v string) { - _, ok := mss[n] - if !ok { + if _, ok := mss[n]; !ok { mss[n] = make(StringSet) } + mss[n].Set(v) } @@ -67,7 +67,7 @@ func (set StringSet) Copy() StringSet { return newSet } -// FromSlice creates a new StringSet from an input slice +// FromSlice creates a new StringSet from an input slice. func FromSlice(in []string) StringSet { set := make(StringSet) @@ -78,12 +78,12 @@ func FromSlice(in []string) StringSet { return set } -// Make creates a new StringSet from a set of arguments +// Make creates a new StringSet from a set of arguments. func Make(in ...string) StringSet { return FromSlice(in) } -// Equal compares if two StringSets have the same values +// Equal compares if two StringSets have the same values. func Equal(a, b StringSet) bool { if a == nil && b == nil { return true diff --git a/pkg/text/color.go b/pkg/text/color.go index c1cf253a..d27f9e7c 100644 --- a/pkg/text/color.go +++ b/pkg/text/color.go @@ -14,7 +14,7 @@ const ( ResetCode = "\x1b[0m" ) -// UseColor determines if package will emit colors +// UseColor determines if package will emit colors. var UseColor = true func stylize(startCode, in string) string { @@ -59,9 +59,12 @@ func ColorHash(name string) (output string) { if !UseColor { return name } + var hash uint = 5381 + for i := 0; i < len(name); i++ { hash = uint(name[i]) + ((hash << 5) + (hash)) } + return fmt.Sprintf("\x1b[%dm%s\x1b[0m", hash%6+31, name) } diff --git a/pkg/text/convert.go b/pkg/text/convert.go index 8a8037f7..10e4ef65 100644 --- a/pkg/text/convert.go +++ b/pkg/text/convert.go @@ -7,12 +7,15 @@ import ( // Human method returns results in human readable format. func Human(size int64) string { floatsize := float32(size) + units := [...]string{"", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi"} for _, unit := range units { if floatsize < 1024 { return fmt.Sprintf("%.1f %sB", floatsize, unit) } + floatsize /= 1024 } + return fmt.Sprintf("%d%s", size, "B") } diff --git a/pkg/text/print.go b/pkg/text/print.go index 9e1038dd..edbc73d8 100644 --- a/pkg/text/print.go +++ b/pkg/text/print.go @@ -69,14 +69,17 @@ 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 } @@ -96,6 +99,7 @@ func PrintInfoValue(key string, values ...string) { 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 @@ -104,8 +108,10 @@ func PrintInfoValue(key string, values ...string) { str += strings.Repeat(" ", delimCount) cols += delimCount } + str += value cols += len(value) } + fmt.Println(str) } diff --git a/pkg/text/text.go b/pkg/text/text.go index f9cbb97c..dacc999e 100644 --- a/pkg/text/text.go +++ b/pkg/text/text.go @@ -8,13 +8,14 @@ import ( "github.com/leonelquinteros/gotext" ) -// SplitDBFromName split apart db/package to db and package +// SplitDBFromName split apart db/package to db and package. func SplitDBFromName(pkg string) (db, name string) { split := strings.SplitN(pkg, "/", 2) if len(split) == 2 { return split[0], split[1] } + return "", split[0] } @@ -52,12 +53,14 @@ func ContinueTask(s string, cont, noConfirm bool) bool { return cont } - var response string - var postFix string - yes := gotext.Get("yes") - no := gotext.Get("no") - y := string([]rune(yes)[0]) - n := string([]rune(no)[0]) + var ( + response string + postFix string + yes = gotext.Get("yes") + no = gotext.Get("no") + y = string([]rune(yes)[0]) + n = string([]rune(no)[0]) + ) if cont { postFix = fmt.Sprintf(" [%s/%s] ", strings.ToUpper(y), n) @@ -72,5 +75,6 @@ func ContinueTask(s string, cont, noConfirm bool) bool { } response = strings.ToLower(response) + return response == yes || response == y } diff --git a/pkg/text/test_text.go b/pkg/text/text_test.go similarity index 97% rename from pkg/text/test_text.go rename to pkg/text/text_test.go index cae859c2..cd3694c9 100644 --- a/pkg/text/test_text.go +++ b/pkg/text/text_test.go @@ -8,10 +8,12 @@ import ( func TestLessRunes(t *testing.T) { t.Parallel() + type args struct { iRunes []rune jRunes []rune } + tests := []struct { name string args args @@ -27,8 +29,11 @@ func TestLessRunes(t *testing.T) { {name: "longerSecondArg", args: args{iRunes: []rune{'a'}, jRunes: []rune{'a', 'b'}}, want: true}, {name: "utf8 less", args: args{iRunes: []rune{'世', '2', '0'}, jRunes: []rune{'世', '界', '3'}}, want: true}, } + for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() got := LessRunes(tt.args.iRunes, tt.args.jRunes) assert.Equal(t, tt.want, got) }) diff --git a/pkg/text/time.go b/pkg/text/time.go index 85bce4d5..9f4aa124 100644 --- a/pkg/text/time.go +++ b/pkg/text/time.go @@ -2,13 +2,13 @@ package text import "time" -// Formats a unix timestamp to ISO 8601 date (yyyy-mm-dd) +// Formats a unix timestamp to ISO 8601 date (yyyy-mm-dd). func FormatTime(i int) string { t := time.Unix(int64(i), 0) return t.Format("2006-01-02") } -// Formats a unix timestamp to ISO 8601 date (Mon 02 Jan 2006 03:04:05 PM MST) +// Formats a unix timestamp to ISO 8601 date (Mon 02 Jan 2006 03:04:05 PM MST). func FormatTimeQuery(i int) string { t := time.Unix(int64(i), 0) return t.Format("Mon 02 Jan 2006 03:04:05 PM MST") diff --git a/pkg/upgrade/sources.go b/pkg/upgrade/sources.go index df4f7b01..a2e50a1c 100644 --- a/pkg/upgrade/sources.go +++ b/pkg/upgrade/sources.go @@ -18,8 +18,10 @@ func UpDevel( toUpdate := make([]db.IPackage, 0, len(aurdata)) toRemove := make([]string, 0) - var mux1, mux2 sync.Mutex - var wg sync.WaitGroup + var ( + mux1, mux2 sync.Mutex + wg sync.WaitGroup + ) checkUpdate := func(pkgName string, e vcs.OriginInfoByURL) { defer wg.Done() @@ -31,6 +33,7 @@ func UpDevel( mux1.Lock() toUpdate = append(toUpdate, pkg) mux1.Unlock() + return } } @@ -44,12 +47,14 @@ func UpDevel( for pkgName, e := range localCache.OriginsByPackage { wg.Add(1) + go checkUpdate(pkgName, e) } wg.Wait() toUpgrade := UpSlice{Up: make([]Upgrade, 0), Repos: []string{"devel"}} + for _, pkg := range toUpdate { if pkg.ShouldIgnore() { printIgnoringPackage(pkg, "latest-commit") @@ -65,6 +70,7 @@ func UpDevel( } localCache.RemovePackage(toRemove) + return toUpgrade } diff --git a/pkg/upgrade/sources_test.go b/pkg/upgrade/sources_test.go index cfd61182..896cd63f 100644 --- a/pkg/upgrade/sources_test.go +++ b/pkg/upgrade/sources_test.go @@ -22,6 +22,7 @@ import ( ) func Test_upAUR(t *testing.T) { + t.Parallel() type args struct { remote []alpm.IPackage aurdata map[string]*aur.Pkg @@ -68,7 +69,9 @@ func Test_upAUR(t *testing.T) { }, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() rescueStdout := os.Stdout r, w, _ := os.Pipe() os.Stdout = w @@ -106,6 +109,7 @@ func (r *MockRunner) Capture(cmd *exec.Cmd, timeout int64) (stdout, stderr strin } func Test_upDevel(t *testing.T) { + t.Parallel() var err error config, err := settings.NewConfig("v0") assert.NoError(t, err) @@ -163,7 +167,7 @@ func Test_upDevel(t *testing.T) { SHA: "991c5b4146fd27f4aacf4e3111258a848934aaa1", }, }, - "hello-non-existant": { + "hello-non-existent": { "github.com/Jguer/y.git": vcs.OriginInfo{ Protocols: []string{"https"}, Branch: "0", @@ -263,7 +267,9 @@ func Test_upDevel(t *testing.T) { }, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() config.Runtime.CmdBuilder.(*exe.CmdBuilder).Runner.(*MockRunner).t = t got := UpDevel(tt.args.remote, tt.args.aurdata, &tt.args.cached) assert.ElementsMatch(t, tt.want.Up, got.Up) diff --git a/pkg/upgrade/upgrade.go b/pkg/upgrade/upgrade.go index 45fb3a85..d0ebaac8 100644 --- a/pkg/upgrade/upgrade.go +++ b/pkg/upgrade/upgrade.go @@ -19,7 +19,7 @@ func StylizedNameWithRepository(u Upgrade) string { return text.Bold(text.ColorHash(u.Repository)) + "/" + text.Bold(u.Name) } -// upSlice is a slice of Upgrades +// upSlice is a slice of Upgrades. type UpSlice struct { Up []Upgrade Repos []string @@ -32,6 +32,7 @@ func (u UpSlice) Less(i, j int) bool { if u.Up[i].Repository == u.Up[j].Repository { iRunes := []rune(u.Up[i].Name) jRunes := []rune(u.Up[j].Name) + return text.LessRunes(iRunes, jRunes) } @@ -45,6 +46,7 @@ func (u UpSlice) Less(i, j int) bool { iRunes := []rune(u.Up[i].Repository) jRunes := []rune(u.Up[j].Repository) + return text.LessRunes(iRunes, jRunes) } @@ -58,12 +60,14 @@ func GetVersionDiff(oldVersion, newVersion string) (left, right string) { checkWords := func(str string, index int, words ...string) bool { for _, word := range words { wordLength := len(word) + nextIndex := index + 1 if (index < len(str)-wordLength) && (str[nextIndex:(nextIndex+wordLength)] == word) { return true } } + return false } @@ -74,6 +78,7 @@ func GetVersionDiff(oldVersion, newVersion string) (left, right string) { if charIsSpecial { diffPosition = index } + break } @@ -97,6 +102,7 @@ func GetVersionDiff(oldVersion, newVersion string) (left, right string) { // Print prints the details of the packages to upgrade. func (u UpSlice) Print() { longestName, longestVersion := 0, 0 + for _, pack := range u.Up { packNameLen := len(StylizedNameWithRepository(pack)) packVersion, _ := GetVersionDiff(pack.LocalVersion, pack.RemoteVersion) diff --git a/pkg/upgrade/upgrade_test.go b/pkg/upgrade/upgrade_test.go index cf81f343..dfc2c638 100644 --- a/pkg/upgrade/upgrade_test.go +++ b/pkg/upgrade/upgrade_test.go @@ -7,6 +7,7 @@ import ( ) func TestGetVersionDiff(t *testing.T) { + t.Parallel() text.UseColor = true type versionPair struct { diff --git a/pkg/vcs/vcs.go b/pkg/vcs/vcs.go index 561984fb..1fb9c361 100644 --- a/pkg/vcs/vcs.go +++ b/pkg/vcs/vcs.go @@ -16,14 +16,14 @@ import ( ) // InfoStore is a collection of OriginInfoByURL by Package. -// Containing a map of last commit SHAs of a repo +// Containing a map of last commit SHAs of a repo. type InfoStore struct { OriginsByPackage map[string]OriginInfoByURL FilePath string CmdBuilder exe.GitCmdBuilder } -// OriginInfoByURL stores the OriginInfo of each origin URL provided +// OriginInfoByURL stores the OriginInfo of each origin URL provided. type OriginInfoByURL map[string]OriginInfo // OriginInfo contains the last commit sha of a repo @@ -34,7 +34,7 @@ type OriginInfoByURL map[string]OriginInfo // ], // "branch": "next", // "sha": "c1171d41467c68ffd3c46748182a16366aaaf87b" -// } +// }. type OriginInfo struct { Protocols []string `json:"protocols"` Branch string `json:"branch"` @@ -51,12 +51,13 @@ func NewInfoStore(filePath string, cmdBuilder exe.GitCmdBuilder) *InfoStore { return infoStore } -// GetCommit parses HEAD commit from url and branch +// GetCommit parses HEAD commit from url and branch. func (v *InfoStore) getCommit(url, branch string, protocols []string) string { if len(protocols) > 0 { protocol := protocols[len(protocols)-1] cmd := v.CmdBuilder.BuildGitCmd("", "ls-remote", protocol+"://"+url, branch) + stdout, _, err := v.CmdBuilder.Capture(cmd, 5) if err != nil { if exiterr, ok := err.(*exec.ExitError); ok && exiterr.ExitCode() == 128 { @@ -65,6 +66,7 @@ func (v *InfoStore) getCommit(url, branch string, protocols []string) string { } text.Warnln(err) + return "" } @@ -75,6 +77,7 @@ func (v *InfoStore) getCommit(url, branch string, protocols []string) string { } commit := split[0] + return commit } @@ -87,6 +90,7 @@ func (v *InfoStore) Update(pkgName string, sources []gosrc.ArchString, mux sync. info := make(OriginInfoByURL) checkSource := func(source gosrc.ArchString) { defer wg.Done() + url, branch, protocols := parseSource(source.Value) if url == "" || branch == "" { return @@ -105,6 +109,7 @@ func (v *InfoStore) Update(pkgName string, sources []gosrc.ArchString, mux sync. } v.OriginsByPackage[pkgName] = info + text.Warnln(gotext.Get("Found git repo: %s", text.Cyan(url))) if err := v.Save(); err != nil { @@ -115,11 +120,12 @@ func (v *InfoStore) Update(pkgName string, sources []gosrc.ArchString, mux sync. for _, source := range sources { wg.Add(1) + go checkSource(source) } } -// parseSource returns the git url, default branch and protocols it supports +// parseSource returns the git url, default branch and protocols it supports. func parseSource(source string) (url, branch string, protocols []string) { split := strings.Split(source, "::") source = split[len(split)-1] @@ -128,9 +134,11 @@ func parseSource(source string) (url, branch string, protocols []string) { if len(split) != 2 { return "", "", nil } + protocols = strings.SplitN(split[0], "+", 2) git := false + for _, protocol := range protocols { if protocol == "git" { git = true @@ -197,6 +205,7 @@ func (v *InfoStore) NeedsUpdate(infos OriginInfoByURL) bool { for url, info := range infos { alive++ + go checkHash(url, info) } @@ -218,26 +227,29 @@ func (v *InfoStore) Save() error { if err != nil || string(marshalledinfo) == "null" { return err } + in, err := os.OpenFile(v.FilePath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o644) if err != nil { return err } + defer in.Close() - _, err = in.Write(marshalledinfo) - if err != nil { - return err + + if _, errM := in.Write(marshalledinfo); errM != nil { + return errM } - err = in.Sync() - return err + + return in.Sync() } -// RemovePackage removes package from VCS information +// RemovePackage removes package from VCS information. func (v *InfoStore) RemovePackage(pkgs []string) { updated := false for _, pkgName := range pkgs { if _, ok := v.OriginsByPackage[pkgName]; ok { delete(v.OriginsByPackage, pkgName) + updated = true } } @@ -249,7 +261,7 @@ func (v *InfoStore) RemovePackage(pkgs []string) { } } -// LoadStore reads a json file and populates a InfoStore structure +// LoadStore reads a json file and populates a InfoStore structure. func (v InfoStore) Load() error { vfile, err := os.Open(v.FilePath) if !os.IsNotExist(err) && err != nil { @@ -257,6 +269,7 @@ func (v InfoStore) Load() error { } defer vfile.Close() + if !os.IsNotExist(err) { decoder := json.NewDecoder(vfile) if err = decoder.Decode(&v.OriginsByPackage); err != nil { diff --git a/pkg/vcs/vcs_test.go b/pkg/vcs/vcs_test.go index c6497afd..9ef11146 100644 --- a/pkg/vcs/vcs_test.go +++ b/pkg/vcs/vcs_test.go @@ -18,6 +18,7 @@ import ( ) func TestParsing(t *testing.T) { + t.Parallel() type source struct { URL string Branch string @@ -53,6 +54,7 @@ func TestParsing(t *testing.T) { } func TestNewInfoStore(t *testing.T) { + t.Parallel() type args struct { filePath string cmdBuilder *exe.CmdBuilder @@ -70,7 +72,9 @@ func TestNewInfoStore(t *testing.T) { }, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() got := NewInfoStore(tt.args.filePath, tt.args.cmdBuilder) assert.NotNil(t, got) assert.Equal(t, []string{"--a", "--b"}, got.CmdBuilder.(*exe.CmdBuilder).GitFlags) @@ -98,6 +102,7 @@ func (r *MockRunner) Capture(cmd *exec.Cmd, timeout int64) (stdout, stderr strin } func TestInfoStore_NeedsUpdate(t *testing.T) { + t.Parallel() type fields struct { CmdBuilder *exe.CmdBuilder } @@ -213,7 +218,9 @@ func TestInfoStore_NeedsUpdate(t *testing.T) { }, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() v := &InfoStore{ CmdBuilder: tt.fields.CmdBuilder, } @@ -224,6 +231,7 @@ func TestInfoStore_NeedsUpdate(t *testing.T) { } func TestInfoStore_Update(t *testing.T) { + t.Parallel() type fields struct { OriginsByPackage map[string]OriginInfoByURL CmdBuilder *exe.CmdBuilder @@ -258,7 +266,9 @@ func TestInfoStore_Update(t *testing.T) { defer os.Remove(file.Name()) for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() v := &InfoStore{ OriginsByPackage: tt.fields.OriginsByPackage, FilePath: file.Name(), @@ -289,6 +299,7 @@ func TestInfoStore_Update(t *testing.T) { } func TestInfoStore_Remove(t *testing.T) { + t.Parallel() type fields struct { OriginsByPackage map[string]OriginInfoByURL } @@ -319,7 +330,9 @@ func TestInfoStore_Remove(t *testing.T) { defer os.Remove(file.Name()) for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() v := &InfoStore{ OriginsByPackage: tt.fields.OriginsByPackage, FilePath: file.Name(), diff --git a/print.go b/print.go index b8ead1b4..fa78744b 100644 --- a/print.go +++ b/print.go @@ -17,10 +17,11 @@ import ( "github.com/Jguer/yay/v10/pkg/upgrade" ) -// PrintSearch handles printing search results in a given format +// PrintSearch handles printing search results in a given format. func (q aurQuery) printSearch(start int, dbExecutor db.Executor) { for i := range q { var toprint string + if config.SearchMode == numberMenu { switch config.SortMode { case settings.TopDown: @@ -55,6 +56,7 @@ func (q aurQuery) printSearch(start int, dbExecutor db.Executor) { toprint += text.Bold(text.Green(gotext.Get("(Installed)"))) } } + toprint += "\n " + q[i].Description fmt.Println(toprint) } @@ -64,6 +66,7 @@ func (q aurQuery) printSearch(start int, dbExecutor db.Executor) { func (s repoQuery) printSearch(dbExecutor db.Executor) { for i, res := range s { var toprint string + if config.SearchMode == numberMenu { switch config.SortMode { case settings.TopDown: @@ -153,7 +156,6 @@ 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()))) } - // Could implement size here as well, but we just want the general idea } // localStatistics prints installed packages statistics. @@ -181,27 +183,28 @@ func localStatistics(dbExecutor db.Executor) error { return nil } -// TODO: Make it less hacky func printNumberOfUpdates(dbExecutor db.Executor, enableDowngrade bool, filter upgrade.Filter) error { warnings := query.NewWarnings() old := os.Stdout // keep backup of the real stdout os.Stdout = nil aurUp, repoUp, err := upList(warnings, dbExecutor, enableDowngrade, filter) os.Stdout = old // restoring the real stdout + if err != nil { return err } + fmt.Println(len(aurUp.Up) + len(repoUp.Up)) return nil } -// TODO: Make it less hacky func printUpdateList(cmdArgs *parser.Arguments, dbExecutor db.Executor, enableDowngrade bool, filter upgrade.Filter) error { targets := stringset.FromSlice(cmdArgs.Targets) warnings := query.NewWarnings() old := os.Stdout // keep backup of the real stdout os.Stdout = nil + localNames, remoteNames, err := query.GetPackageNamesBySource(dbExecutor) if err != nil { os.Stdout = old @@ -210,6 +213,7 @@ func printUpdateList(cmdArgs *parser.Arguments, dbExecutor db.Executor, enableDo aurUp, repoUp, err := upList(warnings, dbExecutor, enableDowngrade, filter) os.Stdout = old // restoring the real stdout + if err != nil { return err } @@ -224,6 +228,7 @@ func printUpdateList(cmdArgs *parser.Arguments, dbExecutor db.Executor, enableDo } else { fmt.Printf("%s %s -> %s\n", text.Bold(pkg.Name), text.Green(pkg.LocalVersion), text.Green(pkg.RemoteVersion)) } + delete(targets, pkg.Name) } } @@ -237,6 +242,7 @@ func printUpdateList(cmdArgs *parser.Arguments, dbExecutor db.Executor, enableDo } else { fmt.Printf("%s %s -> %s\n", text.Bold(pkg.Name), text.Green(pkg.LocalVersion), text.Green(pkg.RemoteVersion)) } + delete(targets, pkg.Name) } } diff --git a/query.go b/query.go index c9d3e849..ac135564 100644 --- a/query.go +++ b/query.go @@ -20,7 +20,7 @@ import ( "github.com/Jguer/yay/v10/pkg/text" ) -// Query is a collection of Results +// Query is a collection of Results. type aurQuery []aur.Pkg // Query holds the results of a repository search. @@ -88,11 +88,13 @@ func getSearchBy(value string) aur.By { } } -// NarrowSearch searches AUR and narrows based on subarguments +// NarrowSearch searches AUR and narrows based on subarguments. func narrowSearch(aurClient *aur.Client, pkgS []string, sortS bool) (aurQuery, error) { - var r []aur.Pkg - var err error - var usedIndex int + var ( + r []aur.Pkg + err error + usedIndex int + ) by := getSearchBy(config.SearchBy) @@ -104,6 +106,7 @@ func narrowSearch(aurClient *aur.Client, pkgS []string, sortS bool) (aurQuery, e r, err = aurClient.Search(context.Background(), word, by) if err == nil { usedIndex = i + break } } @@ -116,14 +119,18 @@ func narrowSearch(aurClient *aur.Client, pkgS []string, sortS bool) (aurQuery, e if sortS { sort.Sort(aurQuery(r)) } + return r, err } - var aq aurQuery - var n int + var ( + aq aurQuery + n int + ) for i := range r { match := true + for j, pkgN := range pkgS { if usedIndex == j { continue @@ -131,12 +138,14 @@ func narrowSearch(aurClient *aur.Client, pkgS []string, sortS bool) (aurQuery, e if !(strings.Contains(r[i].Name, pkgN) || strings.Contains(strings.ToLower(r[i].Description), pkgN)) { match = false + break } } if match { n++ + aq = append(aq, r[i]) } } @@ -151,13 +160,17 @@ func narrowSearch(aurClient *aur.Client, pkgS []string, sortS bool) (aurQuery, e // SyncSearch presents a query to the local repos and to the AUR. func syncSearch(pkgS []string, aurClient *aur.Client, dbExecutor db.Executor) (err error) { pkgS = query.RemoveInvalidTargets(pkgS, config.Runtime.Mode) - var aurErr error - var aq aurQuery - var pq repoQuery + + var ( + aurErr error + aq aurQuery + pq repoQuery + ) if config.Runtime.Mode.AtLeastAUR() { aq, aurErr = narrowSearch(aurClient, pkgS, true) } + if config.Runtime.Mode.AtLeastRepo() { pq = queryRepo(pkgS, dbExecutor) } @@ -167,6 +180,7 @@ func syncSearch(pkgS []string, aurClient *aur.Client, dbExecutor db.Executor) (e if config.Runtime.Mode.AtLeastRepo() { pq.printSearch(dbExecutor) } + if config.Runtime.Mode.AtLeastAUR() { aq.printSearch(1, dbExecutor) } @@ -174,6 +188,7 @@ func syncSearch(pkgS []string, aurClient *aur.Client, dbExecutor db.Executor) (e if config.Runtime.Mode.AtLeastAUR() { aq.printSearch(1, dbExecutor) } + if config.Runtime.Mode.AtLeastRepo() { pq.printSearch(dbExecutor) } @@ -191,9 +206,12 @@ func syncSearch(pkgS []string, aurClient *aur.Client, dbExecutor db.Executor) (e // SyncInfo serves as a pacman -Si for repo packages and AUR packages. func syncInfo(cmdArgs *parser.Arguments, pkgS []string, dbExecutor db.Executor) error { - var info []*aur.Pkg - var err error - missing := false + var ( + info []*aur.Pkg + err error + missing = false + ) + pkgS = query.RemoveInvalidTargets(pkgS, config.Runtime.Mode) aurS, repoS := packageSlices(pkgS, dbExecutor) @@ -208,6 +226,7 @@ func syncInfo(cmdArgs *parser.Arguments, pkgS []string, dbExecutor db.Executor) info, err = query.AURInfoPrint(config.Runtime.AURClient, noDB, config.RequestSplitN) if err != nil { missing = true + fmt.Fprintln(os.Stderr, err) } } @@ -217,9 +236,9 @@ func syncInfo(cmdArgs *parser.Arguments, pkgS []string, dbExecutor db.Executor) arguments := cmdArgs.Copy() arguments.ClearTargets() arguments.AddTarget(repoS...) + err = config.Runtime.CmdBuilder.Show(config.Runtime.CmdBuilder.BuildPacmanCmd( cmdArgs, config.Runtime.Mode, settings.NoConfirm)) - if err != nil { return err } @@ -249,10 +268,11 @@ func queryRepo(pkgInputN []string, dbExecutor db.Executor) repoQuery { if config.SortMode == settings.BottomUp { s.Reverse() } + return s } -// PackageSlices separates an input slice into aur and repo slices +// PackageSlices separates an input slice into aur and repo slices. func packageSlices(toCheck []string, dbExecutor db.Executor) (aurNames, repoNames []string) { for _, _pkg := range toCheck { dbName, name := text.SplitDBFromName(_pkg) @@ -278,7 +298,7 @@ func packageSlices(toCheck []string, dbExecutor db.Executor) (aurNames, repoName // HangingPackages returns a list of packages installed as deps // and unneeded by the system -// removeOptional decides whether optional dependencies are counted or not +// removeOptional decides whether optional dependencies are counted or not. func hangingPackages(removeOptional bool, dbExecutor db.Executor) (hanging []string) { // safePackages represents every package in the system in one of 3 states // State = 0 - Remove package from the system @@ -306,6 +326,7 @@ func hangingPackages(removeOptional bool, dbExecutor db.Executor) (hanging []str for iterateAgain { iterateAgain = false + for _, pkg := range packages { if state := safePackages[pkg.Name()]; state == 0 || state == 2 { continue @@ -313,6 +334,7 @@ func hangingPackages(removeOptional bool, dbExecutor db.Executor) (hanging []str safePackages[pkg.Name()] = 2 deps := dbExecutor.PackageDepends(pkg) + if !removeOptional { deps = append(deps, dbExecutor.PackageOptionalDepends(pkg)...) } @@ -331,6 +353,7 @@ func hangingPackages(removeOptional bool, dbExecutor db.Executor) (hanging []str } } } + continue } @@ -352,20 +375,24 @@ func hangingPackages(removeOptional bool, dbExecutor db.Executor) (hanging []str return hanging } -// Statistics returns statistics about packages installed in system +// Statistics returns statistics about packages installed in system. func statistics(dbExecutor db.Executor) *struct { Totaln int Expln int TotalSize int64 } { - var totalSize int64 - localPackages := dbExecutor.LocalPackages() - totalInstalls := 0 - explicitInstalls := 0 + var ( + totalSize int64 + + localPackages = dbExecutor.LocalPackages() + totalInstalls = 0 + explicitInstalls = 0 + ) for _, pkg := range localPackages { totalSize += pkg.ISize() totalInstalls++ + if pkg.Reason() == alpm.PkgReasonExplicit { explicitInstalls++ } diff --git a/upgrade.go b/upgrade.go index 7e34899d..6766464c 100644 --- a/upgrade.go +++ b/upgrade.go @@ -21,11 +21,13 @@ import ( func filterUpdateList(list []db.Upgrade, filter upgrade.Filter) []db.Upgrade { tmp := list[:0] + for _, pkg := range list { if filter(pkg) { tmp = append(tmp, pkg) } } + return tmp } @@ -34,10 +36,12 @@ func upList(warnings *query.AURWarnings, dbExecutor db.Executor, enableDowngrade filter upgrade.Filter) (aurUp, repoUp upgrade.UpSlice, err error) { remote, remoteNames := query.GetRemotePackages(dbExecutor) - var wg sync.WaitGroup - var develUp upgrade.UpSlice - var repoSlice []db.Upgrade - var errs multierror.MultiError + var ( + wg sync.WaitGroup + develUp upgrade.UpSlice + repoSlice []db.Upgrade + errs multierror.MultiError + ) aurdata := make(map[string]*aur.Pkg) @@ -50,6 +54,7 @@ func upList(warnings *query.AURWarnings, dbExecutor db.Executor, enableDowngrade if config.Runtime.Mode.AtLeastRepo() { text.OperationInfoln(gotext.Get("Searching databases for updates...")) wg.Add(1) + go func() { repoSlice, err = dbExecutor.RepoUpgrades(enableDowngrade) errs.Add(err) @@ -63,22 +68,27 @@ func upList(warnings *query.AURWarnings, dbExecutor db.Executor, enableDowngrade var _aurdata []*aur.Pkg _aurdata, err = query.AURInfo(config.Runtime.AURClient, remoteNames, warnings, config.RequestSplitN) errs.Add(err) + if err == nil { for _, pkg := range _aurdata { aurdata[pkg.Name] = pkg } wg.Add(1) + go func() { aurUp = upgrade.UpAUR(remote, aurdata, config.TimeUpdate) + wg.Done() }() if config.Devel { text.OperationInfoln(gotext.Get("Checking development packages...")) wg.Add(1) + go func() { develUp = upgrade.UpDevel(remote, aurdata, config.Runtime.VCSStore) + wg.Done() }() } @@ -88,15 +98,19 @@ func upList(warnings *query.AURWarnings, dbExecutor db.Executor, enableDowngrade wg.Wait() printLocalNewerThanAUR(remote, aurdata) + names := make(stringset.StringSet) + for _, up := range develUp.Up { names.Set(up.Name) } + for _, up := range aurUp.Up { if !names.Get(up.Name) { develUp.Up = append(develUp.Up, up) } } + aurUp = develUp aurUp.Repos = []string{"aur", "devel"} @@ -104,6 +118,7 @@ func upList(warnings *query.AURWarnings, dbExecutor db.Executor, enableDowngrade aurUp.Up = filterUpdateList(aurUp.Up, filter) repoUp.Up = filterUpdateList(repoUp.Up, filter) + return aurUp, repoUp, errs.Return() } @@ -160,7 +175,9 @@ func upgradePkgsMenu(aurUp, repoUp upgrade.UpSlice) (stringset.StringSet, []stri sort.Sort(repoUp) sort.Sort(aurUp) + allUp := upgrade.UpSlice{Up: append(repoUp.Up, aurUp.Up...), Repos: append(repoUp.Repos, aurUp.Repos...)} + fmt.Printf("%s"+text.Bold(" %d ")+"%s\n", text.Bold(text.Cyan("::")), allUpLen, text.Bold(gotext.Get("Packages to upgrade."))) allUp.Print() @@ -212,9 +229,10 @@ func upgradePkgsMenu(aurUp, repoUp upgrade.UpSlice) (stringset.StringSet, []stri return ignore, targets, err } -// Targets for sys upgrade +// Targets for sys upgrade. func sysupgradeTargets(dbExecutor db.Executor, enableDowngrade bool) (stringset.StringSet, []string, error) { warnings := query.NewWarnings() + aurUp, repoUp, err := upList(warnings, dbExecutor, enableDowngrade, func(upgrade.Upgrade) bool { return true }) if err != nil { return nil, nil, err @@ -223,5 +241,6 @@ func sysupgradeTargets(dbExecutor db.Executor, enableDowngrade bool) (stringset. warnings.Print() ignore, targets, errUp := upgradePkgsMenu(aurUp, repoUp) + return ignore, targets, errUp } diff --git a/vcs.go b/vcs.go index 7fdf010b..31fa31c3 100644 --- a/vcs.go +++ b/vcs.go @@ -15,10 +15,12 @@ import ( "github.com/Jguer/yay/v10/pkg/text" ) -// createDevelDB forces yay to create a DB of the existing development packages +// createDevelDB forces yay to create a DB of the existing development packages. func createDevelDB(config *settings.Configuration, dbExecutor db.Executor) error { - var mux sync.Mutex - var wg sync.WaitGroup + var ( + mux sync.Mutex + wg sync.WaitGroup + ) _, remoteNames, err := query.GetPackageNamesBySource(dbExecutor) if err != nil { @@ -34,6 +36,7 @@ func createDevelDB(config *settings.Configuration, dbExecutor db.Executor) error toSkip := pkgbuildsToSkip(bases, stringset.FromSlice(remoteNames)) targets := make([]string, 0, len(bases)) + for _, base := range bases { if !toSkip.Get(base.Pkgbase()) { targets = append(targets, base.Pkgbase()) @@ -60,11 +63,13 @@ func createDevelDB(config *settings.Configuration, dbExecutor db.Executor) error for i := range srcinfos { for iP := range srcinfos[i].Packages { wg.Add(1) + go config.Runtime.VCSStore.Update(srcinfos[i].Packages[iP].Pkgname, srcinfos[i].Source, &mux, &wg) } } wg.Wait() text.OperationInfoln(gotext.Get("GenDB finished. No packages were installed")) + return err }