source.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. package query
  2. import (
  3. "context"
  4. "sort"
  5. "strings"
  6. "github.com/Jguer/aur"
  7. "github.com/leonelquinteros/gotext"
  8. "github.com/Jguer/yay/v11/pkg/db"
  9. "github.com/Jguer/yay/v11/pkg/intrange"
  10. "github.com/Jguer/yay/v11/pkg/settings"
  11. "github.com/Jguer/yay/v11/pkg/settings/parser"
  12. "github.com/Jguer/yay/v11/pkg/stringset"
  13. "github.com/Jguer/yay/v11/pkg/text"
  14. )
  15. type SearchVerbosity int
  16. // Verbosity settings for search.
  17. const (
  18. NumberMenu SearchVerbosity = iota
  19. Detailed
  20. Minimal
  21. )
  22. type SourceQueryBuilder struct {
  23. repoQuery
  24. aurQuery
  25. sortMode int
  26. sortBy string
  27. targetMode parser.TargetMode
  28. searchBy string
  29. }
  30. func NewSourceQueryBuilder(sortMode int, sortBy string, targetMode parser.TargetMode, searchBy string) *SourceQueryBuilder {
  31. return &SourceQueryBuilder{
  32. sortMode: sortMode,
  33. sortBy: sortBy,
  34. targetMode: targetMode,
  35. searchBy: searchBy,
  36. }
  37. }
  38. func (s *SourceQueryBuilder) Execute(ctx context.Context, dbExecutor db.Executor, aurClient *aur.Client, pkgS []string) {
  39. var aurErr error
  40. pkgS = RemoveInvalidTargets(pkgS, s.targetMode)
  41. if s.targetMode.AtLeastAUR() {
  42. s.aurQuery, aurErr = queryAUR(ctx, aurClient, pkgS, s.searchBy, s.sortMode, s.sortBy)
  43. }
  44. if s.targetMode.AtLeastRepo() {
  45. s.repoQuery = queryRepo(pkgS, dbExecutor, s.sortMode)
  46. }
  47. if aurErr != nil && len(s.repoQuery) != 0 {
  48. text.Errorln(ErrAURSearch{inner: aurErr})
  49. text.Warnln(gotext.Get("Showing repo packages only"))
  50. }
  51. }
  52. func (s *SourceQueryBuilder) Results(dbExecutor db.Executor, verboseSearch SearchVerbosity) error {
  53. if s.aurQuery == nil && s.repoQuery == nil {
  54. return ErrNoQuery{}
  55. }
  56. switch s.sortMode {
  57. case settings.TopDown:
  58. if s.targetMode.AtLeastRepo() {
  59. s.repoQuery.printSearch(dbExecutor, verboseSearch, s.sortMode)
  60. }
  61. if s.targetMode.AtLeastAUR() {
  62. s.aurQuery.printSearch(1, dbExecutor, verboseSearch, s.sortMode)
  63. }
  64. case settings.BottomUp:
  65. if s.targetMode.AtLeastAUR() {
  66. s.aurQuery.printSearch(1, dbExecutor, verboseSearch, s.sortMode)
  67. }
  68. if s.targetMode.AtLeastRepo() {
  69. s.repoQuery.printSearch(dbExecutor, verboseSearch, s.sortMode)
  70. }
  71. default:
  72. return ErrInvalidSortMode{}
  73. }
  74. return nil
  75. }
  76. func (s *SourceQueryBuilder) GetTargets(include, exclude intrange.IntRanges,
  77. otherExclude stringset.StringSet) ([]string, error) {
  78. isInclude := len(exclude) == 0 && len(otherExclude) == 0
  79. var targets []string
  80. for i, pkg := range s.repoQuery {
  81. var target int
  82. switch s.sortMode {
  83. case settings.TopDown:
  84. target = i + 1
  85. case settings.BottomUp:
  86. target = len(s.repoQuery) - i
  87. default:
  88. return targets, ErrInvalidSortMode{}
  89. }
  90. if (isInclude && include.Get(target)) || (!isInclude && !exclude.Get(target)) {
  91. targets = append(targets, pkg.DB().Name()+"/"+pkg.Name())
  92. }
  93. }
  94. for i := range s.aurQuery {
  95. var target int
  96. switch s.sortMode {
  97. case settings.TopDown:
  98. target = i + 1 + len(s.repoQuery)
  99. case settings.BottomUp:
  100. target = len(s.aurQuery) - i + len(s.repoQuery)
  101. default:
  102. return targets, ErrInvalidSortMode{}
  103. }
  104. if (isInclude && include.Get(target)) || (!isInclude && !exclude.Get(target)) {
  105. targets = append(targets, "aur/"+s.aurQuery[i].Name)
  106. }
  107. }
  108. return targets, nil
  109. }
  110. // queryRepo handles repo searches. Creates a RepoSearch struct.
  111. func queryRepo(pkgInputN []string, dbExecutor db.Executor, sortMode int) repoQuery {
  112. s := repoQuery(dbExecutor.SyncPackages(pkgInputN...))
  113. if sortMode == settings.BottomUp {
  114. s.Reverse()
  115. }
  116. return s
  117. }
  118. // queryAUR searches AUR and narrows based on subarguments.
  119. func queryAUR(ctx context.Context, aurClient *aur.Client, pkgS []string, searchBy string, sortMode int, sortBy string) (aurQuery, error) {
  120. var (
  121. r []aur.Pkg
  122. err error
  123. usedIndex int
  124. )
  125. by := getSearchBy(searchBy)
  126. if len(pkgS) == 0 {
  127. return nil, nil
  128. }
  129. for i, word := range pkgS {
  130. r, err = aurClient.Search(ctx, word, by)
  131. if err == nil {
  132. usedIndex = i
  133. break
  134. }
  135. }
  136. if err != nil {
  137. return nil, err
  138. }
  139. if len(pkgS) == 1 {
  140. sort.Sort(aurSortable{
  141. aurQuery: r,
  142. sortBy: sortBy,
  143. sortMode: sortMode,
  144. })
  145. return r, err
  146. }
  147. var (
  148. aq aurQuery
  149. n int
  150. )
  151. for i := range r {
  152. match := true
  153. for j, pkgN := range pkgS {
  154. if usedIndex == j {
  155. continue
  156. }
  157. name := strings.ToLower(r[i].Name)
  158. desc := strings.ToLower(r[i].Description)
  159. targ := strings.ToLower(pkgN)
  160. if !(strings.Contains(name, targ) || strings.Contains(desc, targ)) {
  161. match = false
  162. break
  163. }
  164. }
  165. if match {
  166. n++
  167. aq = append(aq, r[i])
  168. }
  169. }
  170. sort.Sort(aurSortable{
  171. aurQuery: aq,
  172. sortBy: sortBy,
  173. sortMode: sortMode,
  174. })
  175. return aq, err
  176. }