123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- package query
- import (
- "context"
- "io"
- "sort"
- "strings"
- "unicode"
- "github.com/Jguer/aur"
- "github.com/Jguer/go-alpm/v2"
- "github.com/hashicorp/go-multierror"
- "github.com/leonelquinteros/gotext"
- "github.com/Jguer/yay/v12/pkg/db"
- "github.com/Jguer/yay/v12/pkg/intrange"
- "github.com/Jguer/yay/v12/pkg/settings/parser"
- "github.com/Jguer/yay/v12/pkg/stringset"
- "github.com/Jguer/yay/v12/pkg/text"
- )
- type SearchVerbosity int
- // Verbosity settings for search.
- const (
- NumberMenu SearchVerbosity = iota
- Detailed
- Minimal
- )
- type SourceQueryBuilder struct {
- repoQuery
- aurQuery
- sortBy string
- searchBy string
- targetMode parser.TargetMode
- bottomUp bool
- singleLineResults bool
- aurCache aur.QueryClient
- logger *text.Logger
- }
- func NewSourceQueryBuilder(
- aurCache aur.QueryClient,
- logger *text.Logger,
- sortBy string,
- targetMode parser.TargetMode,
- searchBy string,
- bottomUp,
- singleLineResults bool,
- ) *SourceQueryBuilder {
- return &SourceQueryBuilder{
- aurCache: aurCache,
- logger: logger,
- repoQuery: []alpm.IPackage{},
- aurQuery: []aur.Pkg{},
- bottomUp: bottomUp,
- sortBy: sortBy,
- targetMode: targetMode,
- searchBy: searchBy,
- singleLineResults: singleLineResults,
- }
- }
- func (s *SourceQueryBuilder) Execute(ctx context.Context,
- dbExecutor db.Executor,
- pkgS []string,
- ) {
- var aurErr error
- pkgS = RemoveInvalidTargets(pkgS, s.targetMode)
- if s.targetMode.AtLeastAUR() {
- s.aurQuery, aurErr = queryAUR(ctx, s.aurCache, pkgS, s.searchBy)
- s.aurQuery = filterAURResults(pkgS, s.aurQuery)
- sort.Sort(aurSortable{aurQuery: s.aurQuery, sortBy: s.sortBy, bottomUp: s.bottomUp})
- }
- if s.targetMode.AtLeastRepo() {
- s.repoQuery = repoQuery(dbExecutor.SyncPackages(pkgS...))
- if s.bottomUp {
- s.Reverse()
- }
- }
- if aurErr != nil && len(s.repoQuery) != 0 {
- s.logger.Errorln(ErrAURSearch{inner: aurErr})
- s.logger.Warnln(gotext.Get("Showing repo packages only"))
- }
- }
- func (s *SourceQueryBuilder) Results(w io.Writer, dbExecutor db.Executor, verboseSearch SearchVerbosity) error {
- if s.aurQuery == nil || s.repoQuery == nil {
- return ErrNoQuery{}
- }
- if s.bottomUp {
- if s.targetMode.AtLeastAUR() {
- s.aurQuery.printSearch(w, len(s.repoQuery)+1, dbExecutor, verboseSearch, s.bottomUp, s.singleLineResults)
- }
- if s.targetMode.AtLeastRepo() {
- s.repoQuery.printSearch(w, dbExecutor, verboseSearch, s.bottomUp, s.singleLineResults)
- }
- } else {
- if s.targetMode.AtLeastRepo() {
- s.repoQuery.printSearch(w, dbExecutor, verboseSearch, s.bottomUp, s.singleLineResults)
- }
- if s.targetMode.AtLeastAUR() {
- s.aurQuery.printSearch(w, len(s.repoQuery)+1, dbExecutor, verboseSearch, s.bottomUp, s.singleLineResults)
- }
- }
- return nil
- }
- func (s *SourceQueryBuilder) Len() int {
- return len(s.repoQuery) + len(s.aurQuery)
- }
- 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
- if s.bottomUp {
- target = len(s.repoQuery) - i
- } else {
- target = i + 1
- }
- 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
- if s.bottomUp {
- target = len(s.aurQuery) - i + len(s.repoQuery)
- } else {
- target = i + 1 + len(s.repoQuery)
- }
- if (isInclude && include.Get(target)) || (!isInclude && !exclude.Get(target)) {
- targets = append(targets, "aur/"+s.aurQuery[i].Name)
- }
- }
- return targets, nil
- }
- // filter AUR results to remove strings that don't contain all of the search terms.
- func filterAURResults(pkgS []string, results []aur.Pkg) []aur.Pkg {
- aurPkgs := make([]aur.Pkg, 0, len(results))
- matchesSearchTerms := func(pkg *aur.Pkg, terms []string) bool {
- for _, pkgN := range terms {
- if strings.IndexFunc(pkgN, unicode.IsSymbol) != -1 {
- return true
- }
- name := strings.ToLower(pkg.Name)
- desc := strings.ToLower(pkg.Description)
- targ := strings.ToLower(pkgN)
- if !(strings.Contains(name, targ) || strings.Contains(desc, targ)) {
- return false
- }
- }
- return true
- }
- for i := range results {
- if matchesSearchTerms(&results[i], pkgS) {
- aurPkgs = append(aurPkgs, results[i])
- }
- }
- return aurPkgs
- }
- // queryAUR searches AUR and narrows based on subarguments.
- func queryAUR(ctx context.Context,
- aurClient aur.QueryClient,
- pkgS []string, searchBy string,
- ) ([]aur.Pkg, error) {
- var (
- err error
- by = getSearchBy(searchBy)
- )
- for _, word := range pkgS {
- r, errM := aurClient.Get(ctx, &aur.Query{
- Needles: []string{word},
- By: by,
- Contains: true,
- })
- if errM == nil {
- return r, nil
- }
- err = multierror.Append(err, errM)
- }
- return nil, err
- }
|