yay/query.go
morganamilo 96f499ff44
Reimplement all previously existing operations
This reimplemens all operations yay previously supported:
	'-S' 'Syu' 'Si' ect.

Currently the argument objects are not fully implemented with the code.
Theres alot of funky conversion from
	argument object -> pkg, flags -> argument object
This is to just get back to the functionally we had before (almost).

I have not looked into it yet but alot of the time pacman flags get
passed to makepkg. this cases an error for most commands now because the
new system Passes all flags:
	`yay -Syu` -> flags = '-S' '-y' '-u'
while the old system would have done:
	`yay -Syu` -> op = '-Suy', flags = ''

So extra flags are no longer passed at all currently.

This means:
	'yay -S aic94xx-firmware --noconfirm -b /tmp/pacutilesu2q6hw/tmp-pacman -d'
will no longer error and 'aic94xx-firmware' will be installed but the
database path change will not apply and the dep checking will not be
skipped.
2018-01-04 08:32:50 +00:00

358 lines
6.7 KiB
Go

package main
import (
"fmt"
"sort"
"strings"
alpm "github.com/jguer/go-alpm"
rpc "github.com/mikkeloscar/aur"
)
// Query is a collection of Results
type aurQuery []rpc.Pkg
// Query holds the results of a repository search.
type repoQuery []alpm.Package
func (q aurQuery) Len() int {
return len(q)
}
func (q aurQuery) Less(i, j int) bool {
if config.SortMode == BottomUp {
return q[i].NumVotes < q[j].NumVotes
}
return q[i].NumVotes > q[j].NumVotes
}
func (q aurQuery) Swap(i, j int) {
q[i], q[j] = q[j], q[i]
}
// FilterPackages filters packages based on source and type from local repository.
func filterPackages() (local []alpm.Package, remote []alpm.Package,
localNames []string, remoteNames []string, err error) {
localDb, err := alpmHandle.LocalDb()
if err != nil {
return
}
dbList, err := alpmHandle.SyncDbs()
if err != nil {
return
}
f := func(k alpm.Package) error {
found := false
// For each DB search for our secret package.
_ = dbList.ForEach(func(d alpm.Db) error {
if found {
return nil
}
_, err := d.PkgByName(k.Name())
if err == nil {
found = true
local = append(local, k)
localNames = append(localNames, k.Name())
}
return nil
})
if !found {
remote = append(remote, k)
remoteNames = append(remoteNames, k.Name())
}
return nil
}
err = localDb.PkgCache().ForEach(f)
return
}
// MissingPackage warns if the Query was unable to find a package
func (q aurQuery) missingPackage(pkgS []string) {
for _, depName := range pkgS {
found := false
for _, dep := range q {
if dep.Name == depName {
found = true
break
}
}
if !found {
fmt.Println("\x1b[31mUnable to find", depName, "in AUR\x1b[0m")
}
}
}
// NarrowSearch searches AUR and narrows based on subarguments
func narrowSearch(pkgS []string, sortS bool) (aurQuery, error) {
if len(pkgS) == 0 {
return nil, nil
}
r, err := rpc.Search(pkgS[0])
if err != nil {
return nil, err
}
if len(pkgS) == 1 {
if sortS {
sort.Sort(aurQuery(r))
}
return r, err
}
var aq aurQuery
var n int
for _, res := range r {
match := true
for _, pkgN := range pkgS[1:] {
if !(strings.Contains(res.Name, pkgN) || strings.Contains(strings.ToLower(res.Description), pkgN)) {
match = false
break
}
}
if match {
n++
aq = append(aq, res)
}
}
if sortS {
sort.Sort(aq)
}
return aq, err
}
// SyncSearch presents a query to the local repos and to the AUR.
func syncSearch(pkgS []string) (err error) {
aq, err := narrowSearch(pkgS, true)
if err != nil {
return err
}
pq, _, err := queryRepo(pkgS)
if err != nil {
return err
}
if config.SortMode == BottomUp {
aq.printSearch(0)
pq.printSearch()
} else {
pq.printSearch()
aq.printSearch(0)
}
return nil
}
// SyncInfo serves as a pacman -Si for repo packages and AUR packages.
func syncInfo(pkgS []string, flags []string) (err error) {
aurS, repoS, err := packageSlices(pkgS)
if err != nil {
return
}
if len(aurS) != 0 {
q, err := rpc.Info(aurS)
if err != nil {
fmt.Println(err)
}
for _, aurP := range q {
PrintInfo(&aurP)
}
}
if len(repoS) != 0 {
arguments := makeArguments()
arguments.addArg("S", "i")
//arguments.addArg(flags...)
arguments.addTarget(repoS...)
err = passToPacman(arguments)
}
return
}
// Search handles repo searches. Creates a RepoSearch struct.
func queryRepo(pkgInputN []string) (s repoQuery, n int, err error) {
dbList, err := alpmHandle.SyncDbs()
if err != nil {
return
}
// BottomUp functions
initL := func(len int) int {
if config.SortMode == TopDown {
return 0
}
return len - 1
}
compL := func(len int, i int) bool {
if config.SortMode == TopDown {
return i < len
}
return i > -1
}
finalL := func(i int) int {
if config.SortMode == TopDown {
return i + 1
}
return i - 1
}
dbS := dbList.Slice()
lenDbs := len(dbS)
for f := initL(lenDbs); compL(lenDbs, f); f = finalL(f) {
pkgS := dbS[f].PkgCache().Slice()
lenPkgs := len(pkgS)
for i := initL(lenPkgs); compL(lenPkgs, i); i = finalL(i) {
match := true
for _, pkgN := range pkgInputN {
if !(strings.Contains(pkgS[i].Name(), pkgN) || strings.Contains(strings.ToLower(pkgS[i].Description()), pkgN)) {
match = false
break
}
}
if match {
n++
s = append(s, pkgS[i])
}
}
}
return
}
// PackageSlices separates an input slice into aur and repo slices
func packageSlices(toCheck []string) (aur []string, repo []string, err error) {
dbList, err := alpmHandle.SyncDbs()
if err != nil {
return
}
for _, pkg := range toCheck {
found := false
_ = dbList.ForEach(func(db alpm.Db) error {
if found {
return nil
}
_, err = db.PkgByName(pkg)
if err == nil {
found = true
repo = append(repo, pkg)
}
return nil
})
if !found {
if _, errdb := dbList.PkgCachebyGroup(pkg); errdb == nil {
repo = append(repo, pkg)
} else {
aur = append(aur, pkg)
}
}
}
err = nil
return
}
// HangingPackages returns a list of packages installed as deps
// and unneeded by the system
func hangingPackages() (hanging []string, err error) {
localDb, err := alpmHandle.LocalDb()
if err != nil {
return
}
f := func(pkg alpm.Package) error {
if pkg.Reason() != alpm.PkgReasonDepend {
return nil
}
requiredby := pkg.ComputeRequiredBy()
if len(requiredby) == 0 {
hanging = append(hanging, pkg.Name())
fmt.Printf("%s: \x1B[0;33m%s\x1B[0m\n", pkg.Name(), human(pkg.ISize()))
}
return nil
}
err = localDb.PkgCache().ForEach(f)
return
}
// Statistics returns statistics about packages installed in system
func statistics() (info struct {
Totaln int
Expln int
TotalSize int64
}, err error) {
var tS int64 // TotalSize
var nPkg int
var ePkg int
localDb, err := alpmHandle.LocalDb()
if err != nil {
return
}
for _, pkg := range localDb.PkgCache().Slice() {
tS += pkg.ISize()
nPkg++
if pkg.Reason() == 0 {
ePkg++
}
}
info = struct {
Totaln int
Expln int
TotalSize int64
}{
nPkg, ePkg, tS,
}
return
}
// SliceHangingPackages returns a list of packages installed as deps
// and unneeded by the system from a provided list of package names.
func sliceHangingPackages(pkgS []string) (hanging []string) {
localDb, err := alpmHandle.LocalDb()
if err != nil {
return
}
big:
for _, pkgName := range pkgS {
for _, hangN := range hanging {
if hangN == pkgName {
continue big
}
}
pkg, err := localDb.PkgByName(pkgName)
if err == nil {
if pkg.Reason() != alpm.PkgReasonDepend {
continue
}
requiredby := pkg.ComputeRequiredBy()
if len(requiredby) == 0 {
hanging = append(hanging, pkgName)
fmt.Printf("%s: \x1B[0;33m%s\x1B[0m\n", pkg.Name(), human(pkg.ISize()))
}
}
}
return
}