mirror of
https://github.com/Jguer/yay.git
synced 2025-10-05 00:08:30 -04:00
chore(query): unify search in number menu selection and normal search
This commit is contained in:
parent
44cf54795d
commit
9eb73899fe
109
cmd.go
109
cmd.go
@ -5,7 +5,6 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
alpm "github.com/Jguer/go-alpm/v2"
|
||||
@ -310,7 +309,6 @@ func handleGetpkgbuild(ctx context.Context, cmdArgs *parser.Arguments, dbExecuto
|
||||
}
|
||||
|
||||
func handleYogurt(ctx context.Context, cmdArgs *parser.Arguments, dbExecutor db.Executor) error {
|
||||
config.SearchMode = numberMenu
|
||||
return displayNumberMenu(ctx, cmdArgs.Targets, dbExecutor, cmdArgs)
|
||||
}
|
||||
|
||||
@ -319,13 +317,7 @@ func handleSync(ctx context.Context, cmdArgs *parser.Arguments, dbExecutor db.Ex
|
||||
|
||||
switch {
|
||||
case cmdArgs.ExistsArg("s", "search"):
|
||||
if cmdArgs.ExistsArg("q", "quiet") {
|
||||
config.SearchMode = minimal
|
||||
} else {
|
||||
config.SearchMode = detailed
|
||||
}
|
||||
|
||||
return syncSearch(ctx, targets, config.Runtime.AURClient, dbExecutor)
|
||||
return syncSearch(ctx, targets, config.Runtime.AURClient, dbExecutor, !cmdArgs.ExistsArg("q", "quiet"))
|
||||
case cmdArgs.ExistsArg("p", "print", "print-format"):
|
||||
return config.Runtime.CmdBuilder.Show(config.Runtime.CmdBuilder.BuildPacmanCmd(ctx,
|
||||
cmdArgs, config.Runtime.Mode, settings.NoConfirm))
|
||||
@ -362,107 +354,30 @@ func handleRemove(ctx context.Context, cmdArgs *parser.Arguments, localCache *vc
|
||||
|
||||
// NumberMenu presents a CLI for selecting packages to install.
|
||||
func displayNumberMenu(ctx context.Context, pkgS []string, dbExecutor db.Executor, cmdArgs *parser.Arguments) error {
|
||||
var (
|
||||
aurErr error
|
||||
aq aurQuery
|
||||
pq repoQuery
|
||||
lenaq, lenpq int
|
||||
)
|
||||
queryBuilder := query.NewSourceQueryBuilder(config.SortMode, config.SortBy, config.Runtime.Mode, config.SearchBy)
|
||||
|
||||
pkgS = query.RemoveInvalidTargets(pkgS, config.Runtime.Mode)
|
||||
queryBuilder.Execute(ctx, dbExecutor, config.Runtime.AURClient, pkgS)
|
||||
|
||||
if config.Runtime.Mode.AtLeastAUR() {
|
||||
aq, aurErr = narrowSearch(ctx, config.Runtime.AURClient, pkgS, true)
|
||||
lenaq = len(aq)
|
||||
}
|
||||
|
||||
if config.Runtime.Mode.AtLeastRepo() {
|
||||
pq = queryRepo(pkgS, dbExecutor)
|
||||
lenpq = len(pq)
|
||||
}
|
||||
|
||||
if aurErr != nil {
|
||||
text.Errorln(gotext.Get("Error during AUR search: %s\n", aurErr))
|
||||
text.Warnln(gotext.Get("Showing repo packages only"))
|
||||
}
|
||||
|
||||
if lenpq == 0 && lenaq == 0 {
|
||||
return fmt.Errorf(gotext.Get("no packages match search"))
|
||||
}
|
||||
|
||||
switch config.SortMode {
|
||||
case settings.TopDown:
|
||||
if config.Runtime.Mode.AtLeastRepo() {
|
||||
pq.printSearch(dbExecutor)
|
||||
}
|
||||
|
||||
if config.Runtime.Mode.AtLeastAUR() {
|
||||
aq.printSearch(lenpq+1, dbExecutor)
|
||||
}
|
||||
case settings.BottomUp:
|
||||
if config.Runtime.Mode.AtLeastAUR() {
|
||||
aq.printSearch(lenpq+1, dbExecutor)
|
||||
}
|
||||
|
||||
if config.Runtime.Mode.AtLeastRepo() {
|
||||
pq.printSearch(dbExecutor)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf(gotext.Get("invalid sort mode. Fix with yay -Y --bottomup --save"))
|
||||
if err := queryBuilder.Results(dbExecutor, query.NumberMenu); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
text.Infoln(gotext.Get("Packages to install (eg: 1 2 3, 1-3 or ^4)"))
|
||||
text.Info()
|
||||
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
|
||||
numberBuf, overflow, err := reader.ReadLine()
|
||||
numberBuf, err := text.GetInput("", false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if overflow {
|
||||
return fmt.Errorf(gotext.Get("input too long"))
|
||||
include, exclude, _, otherExclude := intrange.ParseNumberMenu(numberBuf)
|
||||
|
||||
targets, err := queryBuilder.GetTargets(include, exclude, otherExclude)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
include, exclude, _, otherExclude := intrange.ParseNumberMenu(string(numberBuf))
|
||||
arguments := cmdArgs.CopyGlobal()
|
||||
|
||||
isInclude := len(exclude) == 0 && len(otherExclude) == 0
|
||||
|
||||
for i, pkg := range pq {
|
||||
var target int
|
||||
|
||||
switch config.SortMode {
|
||||
case settings.TopDown:
|
||||
target = i + 1
|
||||
case settings.BottomUp:
|
||||
target = len(pq) - i
|
||||
default:
|
||||
return fmt.Errorf(gotext.Get("invalid sort mode. Fix with yay -Y --bottomup --save"))
|
||||
}
|
||||
|
||||
if (isInclude && include.Get(target)) || (!isInclude && !exclude.Get(target)) {
|
||||
arguments.AddTarget(pkg.DB().Name() + "/" + pkg.Name())
|
||||
}
|
||||
}
|
||||
|
||||
for i := range aq {
|
||||
var target int
|
||||
|
||||
switch config.SortMode {
|
||||
case settings.TopDown:
|
||||
target = i + 1 + len(pq)
|
||||
case settings.BottomUp:
|
||||
target = len(aq) - i + len(pq)
|
||||
default:
|
||||
return fmt.Errorf(gotext.Get("invalid sort mode. Fix with yay -Y --bottomup --save"))
|
||||
}
|
||||
|
||||
if (isInclude && include.Get(target)) || (!isInclude && !exclude.Get(target)) {
|
||||
arguments.AddTarget("aur/" + aq[i].Name)
|
||||
}
|
||||
}
|
||||
arguments.AddTarget(targets...)
|
||||
|
||||
if len(arguments.Targets) == 0 {
|
||||
fmt.Println(gotext.Get(" there is nothing to do"))
|
||||
|
@ -2,13 +2,6 @@ package main
|
||||
|
||||
import "github.com/Jguer/yay/v11/pkg/settings"
|
||||
|
||||
// Verbosity settings for search.
|
||||
const (
|
||||
numberMenu = iota
|
||||
detailed
|
||||
minimal
|
||||
)
|
||||
|
||||
var (
|
||||
yayVersion = "11.0.1" // To be set by compiler.
|
||||
localePath = "/usr/share/locale" // To be set by compiler.
|
||||
|
28
pkg/query/errors.go
Normal file
28
pkg/query/errors.go
Normal file
@ -0,0 +1,28 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"github.com/leonelquinteros/gotext"
|
||||
)
|
||||
|
||||
// ErrAURSearch means that it was not possible to connect to the AUR.
|
||||
type ErrAURSearch struct {
|
||||
inner error
|
||||
}
|
||||
|
||||
func (e ErrAURSearch) Error() string {
|
||||
return gotext.Get("Error during AUR search: %s\n", e.inner.Error())
|
||||
}
|
||||
|
||||
// ErrInvalidSortMode means that the sort mode provided was not valid.
|
||||
type ErrInvalidSortMode struct{}
|
||||
|
||||
func (e ErrInvalidSortMode) Error() string {
|
||||
return gotext.Get("invalid sort mode. Fix with yay -Y --bottomup --save")
|
||||
}
|
||||
|
||||
// ErrNoQuery means that query was not executed.
|
||||
type ErrNoQuery struct{}
|
||||
|
||||
func (e ErrNoQuery) Error() string {
|
||||
return gotext.Get("no query was executed")
|
||||
}
|
223
pkg/query/source.go
Normal file
223
pkg/query/source.go
Normal file
@ -0,0 +1,223 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/Jguer/aur"
|
||||
"github.com/leonelquinteros/gotext"
|
||||
|
||||
"github.com/Jguer/yay/v11/pkg/db"
|
||||
"github.com/Jguer/yay/v11/pkg/intrange"
|
||||
"github.com/Jguer/yay/v11/pkg/settings"
|
||||
"github.com/Jguer/yay/v11/pkg/settings/parser"
|
||||
"github.com/Jguer/yay/v11/pkg/stringset"
|
||||
"github.com/Jguer/yay/v11/pkg/text"
|
||||
)
|
||||
|
||||
type SearchVerbosity int
|
||||
|
||||
// Verbosity settings for search.
|
||||
const (
|
||||
NumberMenu SearchVerbosity = iota
|
||||
Detailed
|
||||
Minimal
|
||||
)
|
||||
|
||||
type SourceQueryBuilder struct {
|
||||
repoQuery
|
||||
aurQuery
|
||||
sortMode int
|
||||
sortBy string
|
||||
targetMode parser.TargetMode
|
||||
searchBy string
|
||||
}
|
||||
|
||||
func NewSourceQueryBuilder(sortMode int, sortBy string, targetMode parser.TargetMode, searchBy string) *SourceQueryBuilder {
|
||||
return &SourceQueryBuilder{
|
||||
sortMode: sortMode,
|
||||
sortBy: sortBy,
|
||||
targetMode: targetMode,
|
||||
searchBy: searchBy,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SourceQueryBuilder) Execute(ctx context.Context, dbExecutor db.Executor, aurClient *aur.Client, pkgS []string) {
|
||||
var aurErr error
|
||||
|
||||
pkgS = RemoveInvalidTargets(pkgS, s.targetMode)
|
||||
|
||||
if s.targetMode.AtLeastAUR() {
|
||||
s.aurQuery, aurErr = queryAUR(ctx, aurClient, pkgS, s.searchBy, s.sortMode, s.sortBy)
|
||||
}
|
||||
|
||||
if s.targetMode.AtLeastRepo() {
|
||||
s.repoQuery = queryRepo(pkgS, dbExecutor, s.sortMode)
|
||||
}
|
||||
|
||||
if aurErr != nil && len(s.repoQuery) != 0 {
|
||||
text.Errorln(ErrAURSearch{inner: aurErr})
|
||||
text.Warnln(gotext.Get("Showing repo packages only"))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SourceQueryBuilder) Results(dbExecutor db.Executor, verboseSearch SearchVerbosity) error {
|
||||
if s.aurQuery == nil && s.repoQuery == nil {
|
||||
return ErrNoQuery{}
|
||||
}
|
||||
|
||||
switch s.sortMode {
|
||||
case settings.TopDown:
|
||||
if s.targetMode.AtLeastRepo() {
|
||||
s.repoQuery.printSearch(dbExecutor, verboseSearch, s.sortMode)
|
||||
}
|
||||
|
||||
if s.targetMode.AtLeastAUR() {
|
||||
s.aurQuery.printSearch(1, dbExecutor, verboseSearch, s.sortMode)
|
||||
}
|
||||
case settings.BottomUp:
|
||||
if s.targetMode.AtLeastAUR() {
|
||||
s.aurQuery.printSearch(1, dbExecutor, verboseSearch, s.sortMode)
|
||||
}
|
||||
|
||||
if s.targetMode.AtLeastRepo() {
|
||||
s.repoQuery.printSearch(dbExecutor, verboseSearch, s.sortMode)
|
||||
}
|
||||
default:
|
||||
return ErrInvalidSortMode{}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SourceQueryBuilder) GetTargets(include, exclude intrange.IntRanges,
|
||||
otherExclude stringset.StringSet) ([]string, error) {
|
||||
isInclude := len(exclude) == 0 && len(otherExclude) == 0
|
||||
|
||||
var targets []string
|
||||
|
||||
for i, pkg := range s.repoQuery {
|
||||
var target int
|
||||
|
||||
switch s.sortMode {
|
||||
case settings.TopDown:
|
||||
target = i + 1
|
||||
case settings.BottomUp:
|
||||
target = len(s.repoQuery) - i
|
||||
default:
|
||||
return targets, ErrInvalidSortMode{}
|
||||
}
|
||||
|
||||
if (isInclude && include.Get(target)) || (!isInclude && !exclude.Get(target)) {
|
||||
targets = append(targets, pkg.DB().Name()+"/"+pkg.Name())
|
||||
}
|
||||
}
|
||||
|
||||
for i := range s.aurQuery {
|
||||
var target int
|
||||
|
||||
switch s.sortMode {
|
||||
case settings.TopDown:
|
||||
target = i + 1 + len(s.repoQuery)
|
||||
case settings.BottomUp:
|
||||
target = len(s.aurQuery) - i + len(s.repoQuery)
|
||||
default:
|
||||
return targets, ErrInvalidSortMode{}
|
||||
}
|
||||
|
||||
if (isInclude && include.Get(target)) || (!isInclude && !exclude.Get(target)) {
|
||||
targets = append(targets, "aur/"+s.aurQuery[i].Name)
|
||||
}
|
||||
}
|
||||
|
||||
return targets, nil
|
||||
}
|
||||
|
||||
// queryRepo handles repo searches. Creates a RepoSearch struct.
|
||||
func queryRepo(pkgInputN []string, dbExecutor db.Executor, sortMode int) repoQuery {
|
||||
s := repoQuery(dbExecutor.SyncPackages(pkgInputN...))
|
||||
|
||||
if sortMode == settings.BottomUp {
|
||||
s = sort.Reverse(s).(repoQuery)
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// queryAUR searches AUR and narrows based on subarguments.
|
||||
func queryAUR(ctx context.Context, aurClient *aur.Client, pkgS []string, searchBy string, sortMode int, sortBy string) (aurQuery, error) {
|
||||
var (
|
||||
r []aur.Pkg
|
||||
err error
|
||||
usedIndex int
|
||||
)
|
||||
|
||||
by := getSearchBy(searchBy)
|
||||
|
||||
if len(pkgS) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
for i, word := range pkgS {
|
||||
r, err = aurClient.Search(ctx, word, by)
|
||||
if err == nil {
|
||||
usedIndex = i
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(pkgS) == 1 {
|
||||
sort.Sort(aurSortable{
|
||||
aurQuery: r,
|
||||
sortBy: sortBy,
|
||||
sortMode: sortMode,
|
||||
})
|
||||
|
||||
return r, err
|
||||
}
|
||||
|
||||
var (
|
||||
aq aurQuery
|
||||
n int
|
||||
)
|
||||
|
||||
for i := range r {
|
||||
match := true
|
||||
|
||||
for j, pkgN := range pkgS {
|
||||
if usedIndex == j {
|
||||
continue
|
||||
}
|
||||
|
||||
name := strings.ToLower(r[i].Name)
|
||||
desc := strings.ToLower(r[i].Description)
|
||||
targ := strings.ToLower(pkgN)
|
||||
|
||||
if !(strings.Contains(name, targ) || strings.Contains(desc, targ)) {
|
||||
match = false
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if match {
|
||||
n++
|
||||
|
||||
aq = append(aq, r[i])
|
||||
}
|
||||
}
|
||||
|
||||
sort.Sort(aurSortable{
|
||||
aurQuery: aq,
|
||||
sortBy: sortBy,
|
||||
sortMode: sortMode,
|
||||
})
|
||||
|
||||
return aq, err
|
||||
}
|
180
pkg/query/types.go
Normal file
180
pkg/query/types.go
Normal file
@ -0,0 +1,180 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/Jguer/aur"
|
||||
"github.com/Jguer/go-alpm/v2"
|
||||
"github.com/leonelquinteros/gotext"
|
||||
|
||||
"github.com/Jguer/yay/v11/pkg/db"
|
||||
"github.com/Jguer/yay/v11/pkg/settings"
|
||||
"github.com/Jguer/yay/v11/pkg/text"
|
||||
)
|
||||
|
||||
type (
|
||||
aurQuery []aur.Pkg // Query is a collection of Results.
|
||||
repoQuery []alpm.IPackage // Query holds the results of a repository search.
|
||||
)
|
||||
|
||||
type aurSortable struct {
|
||||
aurQuery
|
||||
sortBy string
|
||||
sortMode int
|
||||
}
|
||||
|
||||
func (r repoQuery) Len() int {
|
||||
return len(r)
|
||||
}
|
||||
|
||||
func (r repoQuery) Swap(i, j int) {
|
||||
r[i], r[j] = r[j], r[i]
|
||||
}
|
||||
|
||||
func (r repoQuery) Less(i, j int) bool {
|
||||
return text.LessRunes([]rune(r[i].Name()), []rune(r[j].Name()))
|
||||
}
|
||||
|
||||
func (q aurSortable) Len() int {
|
||||
return len(q.aurQuery)
|
||||
}
|
||||
|
||||
func (q aurSortable) Less(i, j int) bool {
|
||||
var result bool
|
||||
|
||||
switch q.sortBy {
|
||||
case "votes":
|
||||
result = q.aurQuery[i].NumVotes > q.aurQuery[j].NumVotes
|
||||
case "popularity":
|
||||
result = q.aurQuery[i].Popularity > q.aurQuery[j].Popularity
|
||||
case "name":
|
||||
result = text.LessRunes([]rune(q.aurQuery[i].Name), []rune(q.aurQuery[j].Name))
|
||||
case "base":
|
||||
result = text.LessRunes([]rune(q.aurQuery[i].PackageBase), []rune(q.aurQuery[j].PackageBase))
|
||||
case "submitted":
|
||||
result = q.aurQuery[i].FirstSubmitted < q.aurQuery[j].FirstSubmitted
|
||||
case "modified":
|
||||
result = q.aurQuery[i].LastModified < q.aurQuery[j].LastModified
|
||||
case "id":
|
||||
result = q.aurQuery[i].ID < q.aurQuery[j].ID
|
||||
case "baseid":
|
||||
result = q.aurQuery[i].PackageBaseID < q.aurQuery[j].PackageBaseID
|
||||
}
|
||||
|
||||
if q.sortMode == settings.BottomUp {
|
||||
return !result
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (q aurSortable) Swap(i, j int) {
|
||||
q.aurQuery[i], q.aurQuery[j] = q.aurQuery[j], q.aurQuery[i]
|
||||
}
|
||||
|
||||
func getSearchBy(value string) aur.By {
|
||||
switch value {
|
||||
case "name":
|
||||
return aur.Name
|
||||
case "maintainer":
|
||||
return aur.Maintainer
|
||||
case "depends":
|
||||
return aur.Depends
|
||||
case "makedepends":
|
||||
return aur.MakeDepends
|
||||
case "optdepends":
|
||||
return aur.OptDepends
|
||||
case "checkdepends":
|
||||
return aur.CheckDepends
|
||||
default:
|
||||
return aur.NameDesc
|
||||
}
|
||||
}
|
||||
|
||||
// PrintSearch handles printing search results in a given format.
|
||||
func (q aurQuery) printSearch(start int, dbExecutor db.Executor, searchMode SearchVerbosity, sortMode int) {
|
||||
for i := range q {
|
||||
var toprint string
|
||||
|
||||
if searchMode == NumberMenu {
|
||||
switch sortMode {
|
||||
case settings.TopDown:
|
||||
toprint += text.Magenta(strconv.Itoa(start+i) + " ")
|
||||
case settings.BottomUp:
|
||||
toprint += text.Magenta(strconv.Itoa(len(q)+start-i-1) + " ")
|
||||
default:
|
||||
text.Warnln(gotext.Get("invalid sort mode. Fix with yay -Y --bottomup --save"))
|
||||
}
|
||||
} else if searchMode == Minimal {
|
||||
fmt.Println(q[i].Name)
|
||||
continue
|
||||
}
|
||||
|
||||
toprint += text.Bold(text.ColorHash("aur")) + "/" + text.Bold(q[i].Name) +
|
||||
" " + text.Cyan(q[i].Version) +
|
||||
text.Bold(" (+"+strconv.Itoa(q[i].NumVotes)) +
|
||||
" " + text.Bold(strconv.FormatFloat(q[i].Popularity, 'f', 2, 64)+") ")
|
||||
|
||||
if q[i].Maintainer == "" {
|
||||
toprint += text.Bold(text.Red(gotext.Get("(Orphaned)"))) + " "
|
||||
}
|
||||
|
||||
if q[i].OutOfDate != 0 {
|
||||
toprint += text.Bold(text.Red(gotext.Get("(Out-of-date: %s)", text.FormatTime(q[i].OutOfDate)))) + " "
|
||||
}
|
||||
|
||||
if pkg := dbExecutor.LocalPackage(q[i].Name); pkg != nil {
|
||||
if pkg.Version() != q[i].Version {
|
||||
toprint += text.Bold(text.Green(gotext.Get("(Installed: %s)", pkg.Version())))
|
||||
} else {
|
||||
toprint += text.Bold(text.Green(gotext.Get("(Installed)")))
|
||||
}
|
||||
}
|
||||
|
||||
toprint += "\n " + q[i].Description
|
||||
fmt.Println(toprint)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintSearch receives a RepoSearch type and outputs pretty text.
|
||||
func (r repoQuery) printSearch(dbExecutor db.Executor, searchMode SearchVerbosity, sortMode int) {
|
||||
for i, res := range r {
|
||||
var toprint string
|
||||
|
||||
if searchMode == NumberMenu {
|
||||
switch sortMode {
|
||||
case settings.TopDown:
|
||||
toprint += text.Magenta(strconv.Itoa(i+1) + " ")
|
||||
case settings.BottomUp:
|
||||
toprint += text.Magenta(strconv.Itoa(len(r)-i) + " ")
|
||||
default:
|
||||
text.Warnln(gotext.Get("invalid sort mode. Fix with yay -Y --bottomup --save"))
|
||||
}
|
||||
} else if searchMode == Minimal {
|
||||
fmt.Println(res.Name())
|
||||
continue
|
||||
}
|
||||
|
||||
toprint += text.Bold(text.ColorHash(res.DB().Name())) + "/" + text.Bold(res.Name()) +
|
||||
" " + text.Cyan(res.Version()) +
|
||||
text.Bold(" ("+text.Human(res.Size())+
|
||||
" "+text.Human(res.ISize())+") ")
|
||||
|
||||
packageGroups := dbExecutor.PackageGroups(res)
|
||||
if len(packageGroups) != 0 {
|
||||
toprint += fmt.Sprint(packageGroups, " ")
|
||||
}
|
||||
|
||||
if pkg := dbExecutor.LocalPackage(res.Name()); pkg != nil {
|
||||
if pkg.Version() != res.Version() {
|
||||
toprint += text.Bold(text.Green(gotext.Get("(Installed: %s)", pkg.Version())))
|
||||
} else {
|
||||
toprint += text.Bold(text.Green(gotext.Get("(Installed)")))
|
||||
}
|
||||
}
|
||||
|
||||
toprint += "\n " + res.Description()
|
||||
fmt.Println(toprint)
|
||||
}
|
||||
}
|
@ -60,7 +60,6 @@ type Configuration struct {
|
||||
SudoBin string `json:"sudobin"`
|
||||
SudoFlags string `json:"sudoflags"`
|
||||
RequestSplitN int `json:"requestsplitn"`
|
||||
SearchMode int `json:"-"`
|
||||
SortMode int `json:"sortmode"`
|
||||
CompletionInterval int `json:"completionrefreshtime"`
|
||||
SudoLoop bool `json:"sudoloop"`
|
||||
|
90
print.go
90
print.go
@ -11,102 +11,12 @@ import (
|
||||
|
||||
"github.com/Jguer/yay/v11/pkg/db"
|
||||
"github.com/Jguer/yay/v11/pkg/query"
|
||||
"github.com/Jguer/yay/v11/pkg/settings"
|
||||
"github.com/Jguer/yay/v11/pkg/settings/parser"
|
||||
"github.com/Jguer/yay/v11/pkg/stringset"
|
||||
"github.com/Jguer/yay/v11/pkg/text"
|
||||
"github.com/Jguer/yay/v11/pkg/upgrade"
|
||||
)
|
||||
|
||||
// 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:
|
||||
toprint += text.Magenta(strconv.Itoa(start+i) + " ")
|
||||
case settings.BottomUp:
|
||||
toprint += text.Magenta(strconv.Itoa(len(q)+start-i-1) + " ")
|
||||
default:
|
||||
text.Warnln(gotext.Get("invalid sort mode. Fix with yay -Y --bottomup --save"))
|
||||
}
|
||||
} else if config.SearchMode == minimal {
|
||||
fmt.Println(q[i].Name)
|
||||
continue
|
||||
}
|
||||
|
||||
toprint += text.Bold(text.ColorHash("aur")) + "/" + text.Bold(q[i].Name) +
|
||||
" " + text.Cyan(q[i].Version) +
|
||||
text.Bold(" (+"+strconv.Itoa(q[i].NumVotes)) +
|
||||
" " + text.Bold(strconv.FormatFloat(q[i].Popularity, 'f', 2, 64)+") ")
|
||||
|
||||
if q[i].Maintainer == "" {
|
||||
toprint += text.Bold(text.Red(gotext.Get("(Orphaned)"))) + " "
|
||||
}
|
||||
|
||||
if q[i].OutOfDate != 0 {
|
||||
toprint += text.Bold(text.Red(gotext.Get("(Out-of-date: %s)", text.FormatTime(q[i].OutOfDate)))) + " "
|
||||
}
|
||||
|
||||
if pkg := dbExecutor.LocalPackage(q[i].Name); pkg != nil {
|
||||
if pkg.Version() != q[i].Version {
|
||||
toprint += text.Bold(text.Green(gotext.Get("(Installed: %s)", pkg.Version())))
|
||||
} else {
|
||||
toprint += text.Bold(text.Green(gotext.Get("(Installed)")))
|
||||
}
|
||||
}
|
||||
|
||||
toprint += "\n " + q[i].Description
|
||||
fmt.Println(toprint)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintSearch receives a RepoSearch type and outputs pretty text.
|
||||
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:
|
||||
toprint += text.Magenta(strconv.Itoa(i+1) + " ")
|
||||
case settings.BottomUp:
|
||||
toprint += text.Magenta(strconv.Itoa(len(s)-i) + " ")
|
||||
default:
|
||||
text.Warnln(gotext.Get("invalid sort mode. Fix with yay -Y --bottomup --save"))
|
||||
}
|
||||
} else if config.SearchMode == minimal {
|
||||
fmt.Println(res.Name())
|
||||
continue
|
||||
}
|
||||
|
||||
toprint += text.Bold(text.ColorHash(res.DB().Name())) + "/" + text.Bold(res.Name()) +
|
||||
" " + text.Cyan(res.Version()) +
|
||||
text.Bold(" ("+text.Human(res.Size())+
|
||||
" "+text.Human(res.ISize())+") ")
|
||||
|
||||
packageGroups := dbExecutor.PackageGroups(res)
|
||||
if len(packageGroups) != 0 {
|
||||
toprint += fmt.Sprint(packageGroups, " ")
|
||||
}
|
||||
|
||||
if pkg := dbExecutor.LocalPackage(res.Name()); pkg != nil {
|
||||
if pkg.Version() != res.Version() {
|
||||
toprint += text.Bold(text.Green(gotext.Get("(Installed: %s)", pkg.Version())))
|
||||
} else {
|
||||
toprint += text.Bold(text.Green(gotext.Get("(Installed)")))
|
||||
}
|
||||
}
|
||||
|
||||
toprint += "\n " + res.Description()
|
||||
fmt.Println(toprint)
|
||||
}
|
||||
}
|
||||
|
||||
// Pretty print a set of packages from the same package base.
|
||||
|
||||
// PrintInfo prints package info like pacman -Si.
|
||||
func PrintInfo(a *aur.Pkg, extendedInfo bool) {
|
||||
text.PrintInfoValue(gotext.Get("Repository"), "aur")
|
||||
|
203
query.go
203
query.go
@ -2,15 +2,11 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
aur "github.com/Jguer/aur"
|
||||
alpm "github.com/Jguer/go-alpm/v2"
|
||||
"github.com/leonelquinteros/gotext"
|
||||
|
||||
"github.com/Jguer/yay/v11/pkg/db"
|
||||
"github.com/Jguer/yay/v11/pkg/query"
|
||||
@ -20,192 +16,18 @@ import (
|
||||
"github.com/Jguer/yay/v11/pkg/text"
|
||||
)
|
||||
|
||||
// Query is a collection of Results.
|
||||
type aurQuery []aur.Pkg
|
||||
|
||||
// Query holds the results of a repository search.
|
||||
type repoQuery []alpm.IPackage
|
||||
|
||||
func (s repoQuery) Reverse() {
|
||||
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
}
|
||||
|
||||
func (q aurQuery) Len() int {
|
||||
return len(q)
|
||||
}
|
||||
|
||||
func (q aurQuery) Less(i, j int) bool {
|
||||
var result bool
|
||||
|
||||
switch config.SortBy {
|
||||
case "votes":
|
||||
result = q[i].NumVotes > q[j].NumVotes
|
||||
case "popularity":
|
||||
result = q[i].Popularity > q[j].Popularity
|
||||
case "name":
|
||||
result = text.LessRunes([]rune(q[i].Name), []rune(q[j].Name))
|
||||
case "base":
|
||||
result = text.LessRunes([]rune(q[i].PackageBase), []rune(q[j].PackageBase))
|
||||
case "submitted":
|
||||
result = q[i].FirstSubmitted < q[j].FirstSubmitted
|
||||
case "modified":
|
||||
result = q[i].LastModified < q[j].LastModified
|
||||
case "id":
|
||||
result = q[i].ID < q[j].ID
|
||||
case "baseid":
|
||||
result = q[i].PackageBaseID < q[j].PackageBaseID
|
||||
}
|
||||
|
||||
if config.SortMode == settings.BottomUp {
|
||||
return !result
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (q aurQuery) Swap(i, j int) {
|
||||
q[i], q[j] = q[j], q[i]
|
||||
}
|
||||
|
||||
func getSearchBy(value string) aur.By {
|
||||
switch value {
|
||||
case "name":
|
||||
return aur.Name
|
||||
case "maintainer":
|
||||
return aur.Maintainer
|
||||
case "depends":
|
||||
return aur.Depends
|
||||
case "makedepends":
|
||||
return aur.MakeDepends
|
||||
case "optdepends":
|
||||
return aur.OptDepends
|
||||
case "checkdepends":
|
||||
return aur.CheckDepends
|
||||
default:
|
||||
return aur.NameDesc
|
||||
}
|
||||
}
|
||||
|
||||
// NarrowSearch searches AUR and narrows based on subarguments.
|
||||
func narrowSearch(ctx context.Context, aurClient *aur.Client, pkgS []string, sortS bool) (aurQuery, error) {
|
||||
var (
|
||||
r []aur.Pkg
|
||||
err error
|
||||
usedIndex int
|
||||
)
|
||||
|
||||
by := getSearchBy(config.SearchBy)
|
||||
|
||||
if len(pkgS) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
for i, word := range pkgS {
|
||||
r, err = aurClient.Search(ctx, word, by)
|
||||
if err == nil {
|
||||
usedIndex = i
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(pkgS) == 1 {
|
||||
if sortS {
|
||||
sort.Sort(aurQuery(r))
|
||||
}
|
||||
|
||||
return r, err
|
||||
}
|
||||
|
||||
var (
|
||||
aq aurQuery
|
||||
n int
|
||||
)
|
||||
|
||||
for i := range r {
|
||||
match := true
|
||||
|
||||
for j, pkgN := range pkgS {
|
||||
if usedIndex == j {
|
||||
continue
|
||||
}
|
||||
|
||||
name := strings.ToLower(r[i].Name)
|
||||
desc := strings.ToLower(r[i].Description)
|
||||
targ := strings.ToLower(pkgN)
|
||||
|
||||
if !(strings.Contains(name, targ) || strings.Contains(desc, targ)) {
|
||||
match = false
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if match {
|
||||
n++
|
||||
|
||||
aq = append(aq, r[i])
|
||||
}
|
||||
}
|
||||
|
||||
if sortS {
|
||||
sort.Sort(aq)
|
||||
}
|
||||
|
||||
return aq, err
|
||||
}
|
||||
|
||||
// SyncSearch presents a query to the local repos and to the AUR.
|
||||
func syncSearch(ctx context.Context, pkgS []string, aurClient *aur.Client, dbExecutor db.Executor) (err error) {
|
||||
pkgS = query.RemoveInvalidTargets(pkgS, config.Runtime.Mode)
|
||||
func syncSearch(ctx context.Context, pkgS []string, aurClient *aur.Client, dbExecutor db.Executor, verbose bool) error {
|
||||
queryBuilder := query.NewSourceQueryBuilder(config.SortMode, config.SortBy, config.Runtime.Mode, config.SearchBy)
|
||||
|
||||
var (
|
||||
aurErr error
|
||||
aq aurQuery
|
||||
pq repoQuery
|
||||
)
|
||||
queryBuilder.Execute(ctx, dbExecutor, aurClient, pkgS)
|
||||
|
||||
if config.Runtime.Mode.AtLeastAUR() {
|
||||
aq, aurErr = narrowSearch(ctx, aurClient, pkgS, true)
|
||||
searchMode := query.Minimal
|
||||
if verbose {
|
||||
searchMode = query.Detailed
|
||||
}
|
||||
|
||||
if config.Runtime.Mode.AtLeastRepo() {
|
||||
pq = queryRepo(pkgS, dbExecutor)
|
||||
}
|
||||
|
||||
switch config.SortMode {
|
||||
case settings.TopDown:
|
||||
if config.Runtime.Mode.AtLeastRepo() {
|
||||
pq.printSearch(dbExecutor)
|
||||
}
|
||||
|
||||
if config.Runtime.Mode.AtLeastAUR() {
|
||||
aq.printSearch(1, dbExecutor)
|
||||
}
|
||||
case settings.BottomUp:
|
||||
if config.Runtime.Mode.AtLeastAUR() {
|
||||
aq.printSearch(1, dbExecutor)
|
||||
}
|
||||
|
||||
if config.Runtime.Mode.AtLeastRepo() {
|
||||
pq.printSearch(dbExecutor)
|
||||
}
|
||||
default:
|
||||
return errors.New(gotext.Get("invalid sort mode. Fix with yay -Y --bottomup --save"))
|
||||
}
|
||||
|
||||
if aurErr != nil {
|
||||
text.Errorln(gotext.Get("error during AUR search: %s", aurErr))
|
||||
text.Warnln(gotext.Get("Showing repo packages only"))
|
||||
}
|
||||
|
||||
return nil
|
||||
return queryBuilder.Results(dbExecutor, searchMode)
|
||||
}
|
||||
|
||||
// SyncInfo serves as a pacman -Si for repo packages and AUR packages.
|
||||
@ -265,17 +87,6 @@ func syncInfo(ctx context.Context, cmdArgs *parser.Arguments, pkgS []string, dbE
|
||||
return err
|
||||
}
|
||||
|
||||
// Search handles repo searches. Creates a RepoSearch struct.
|
||||
func queryRepo(pkgInputN []string, dbExecutor db.Executor) repoQuery {
|
||||
s := repoQuery(dbExecutor.SyncPackages(pkgInputN...))
|
||||
|
||||
if config.SortMode == settings.BottomUp {
|
||||
s.Reverse()
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// PackageSlices separates an input slice into aur and repo slices.
|
||||
func packageSlices(toCheck []string, dbExecutor db.Executor) (aurNames, repoNames []string) {
|
||||
for _, _pkg := range toCheck {
|
||||
|
Loading…
x
Reference in New Issue
Block a user