1
0
mirror of https://github.com/Jguer/yay.git synced 2025-08-19 13:41:18 +02:00
yay/dependencies.go
morganamilo e01c4b3969
Fix duplicate packages when printing dependencies
The depTree holds info on all packages by name ready for the
depCatagories to catagorize and order them. To make things easier when
a repo package was added to the deptree it was also aliased to all of
its provides. So to find a package in the deptree you could search for
its provides instead of it's name and still find it.

The depCatagories is meant to filter out unneeded packages such as the
aliases but as it turns out if a package depends on a package and
something it provides then that alias is no longer unneeded and will end
up in the depCatagories.

Because these are just alias provieds still points to the original
package so you end up with the package name displaed to the user twice
when printing dependencies.

This commit just comments out the aliasing. It should have no effect
on package finding because where it used to seach by alias to find the
package it should instead fail then try to preform a lookup itself using
findSatisfyer and find the package.

This is probably a little less efficient than before but the database is
already on disk so there should be no real perfomance difference.
2018-02-27 19:03:52 +00:00

325 lines
6.8 KiB
Go

package main
import (
alpm "github.com/jguer/go-alpm"
rpc "github.com/mikkeloscar/aur"
"strings"
)
type depTree struct {
ToProcess stringSet
Repo map[string]*alpm.Package
Aur map[string]*rpc.Pkg
Missing stringSet
}
type depCatagories struct {
Repo []*alpm.Package
Aur []*rpc.Pkg
MakeOnly stringSet
Bases map[string][]*rpc.Pkg
}
func makeDepTree() *depTree {
dt := depTree{
make(stringSet),
make(map[string]*alpm.Package),
make(map[string]*rpc.Pkg),
make(stringSet),
}
return &dt
}
func makeDependCatagories() *depCatagories {
dc := depCatagories{
make([]*alpm.Package, 0),
make([]*rpc.Pkg, 0),
make(stringSet),
make(map[string][]*rpc.Pkg),
}
return &dc
}
func getNameFromDep(dep string) string {
return strings.FieldsFunc(dep, func(c rune) bool {
return c == '>' || c == '<' || c == '='
})[0]
}
func getDepCatagories(pkgs []string, dt *depTree) (*depCatagories, error) {
dc := makeDependCatagories()
seen := make(stringSet)
for _, pkg := range pkgs {
dep := getNameFromDep(pkg)
alpmpkg, exists := dt.Repo[dep]
if exists {
repoDepCatagoriesRecursive(alpmpkg, dc, dt, false)
dc.Repo = append(dc.Repo, alpmpkg)
delete(dt.Repo, dep)
}
aurpkg, exists := dt.Aur[dep]
if exists {
depCatagoriesRecursive(aurpkg, dc, dt, false, seen)
if !seen.get(aurpkg.PackageBase) {
dc.Aur = append(dc.Aur, aurpkg)
seen.set(aurpkg.PackageBase)
}
_, ok := dc.Bases[aurpkg.PackageBase]
if !ok {
dc.Bases[aurpkg.PackageBase] = make([]*rpc.Pkg, 0)
}
dc.Bases[aurpkg.PackageBase] = append(dc.Bases[aurpkg.PackageBase], aurpkg)
delete(dt.Aur, dep)
}
}
for _, base := range dc.Bases {
for _, pkg := range base {
for _, dep := range pkg.Depends {
dc.MakeOnly.remove(dep)
}
}
}
for _, pkg := range dc.Repo {
pkg.Depends().ForEach(func(_dep alpm.Depend) error {
dep := _dep.Name
dc.MakeOnly.remove(dep)
return nil
})
}
return dc, nil
}
func repoDepCatagoriesRecursive(pkg *alpm.Package, dc *depCatagories, dt *depTree, isMake bool) {
pkg.Depends().ForEach(func(_dep alpm.Depend) error {
dep := _dep.Name
alpmpkg, exists := dt.Repo[dep]
if exists {
delete(dt.Repo, dep)
repoDepCatagoriesRecursive(alpmpkg, dc, dt, isMake)
if isMake {
dc.MakeOnly.set(alpmpkg.Name())
}
dc.Repo = append(dc.Repo, alpmpkg)
}
return nil
})
}
func depCatagoriesRecursive(pkg *rpc.Pkg, dc *depCatagories, dt *depTree, isMake bool, seen stringSet) {
for _, deps := range [3][]string{pkg.Depends, pkg.MakeDepends, pkg.CheckDepends} {
for _, _dep := range deps {
dep := getNameFromDep(_dep)
aurpkg, exists := dt.Aur[dep]
if exists {
_, ok := dc.Bases[aurpkg.PackageBase]
if !ok {
dc.Bases[aurpkg.PackageBase] = make([]*rpc.Pkg, 0)
}
dc.Bases[aurpkg.PackageBase] = append(dc.Bases[aurpkg.PackageBase], aurpkg)
delete(dt.Aur, dep)
depCatagoriesRecursive(aurpkg, dc, dt, isMake, seen)
if !seen.get(aurpkg.PackageBase) {
dc.Aur = append(dc.Aur, aurpkg)
seen.set(aurpkg.PackageBase)
}
if isMake {
dc.MakeOnly.set(aurpkg.Name)
}
}
alpmpkg, exists := dt.Repo[dep]
if exists {
delete(dt.Repo, dep)
repoDepCatagoriesRecursive(alpmpkg, dc, dt, isMake)
if isMake {
dc.MakeOnly.set(alpmpkg.Name())
}
dc.Repo = append(dc.Repo, alpmpkg)
}
}
isMake = true
}
}
func getDepTree(pkgs []string) (*depTree, error) {
dt := makeDepTree()
localDb, err := alpmHandle.LocalDb()
if err != nil {
return dt, err
}
syncDb, err := alpmHandle.SyncDbs()
if err != nil {
return dt, err
}
for _, pkg := range pkgs {
//if they explicitly asked for it still look for installed pkgs
/*installedPkg, isInstalled := localDb.PkgCache().FindSatisfier(pkg)
if isInstalled == nil {
dt.Repo[installedPkg.Name()] = installedPkg
continue
}//*/
//check the repos for a matching dep
repoPkg, inRepos := syncDb.FindSatisfier(pkg)
if inRepos == nil {
repoTreeRecursive(repoPkg, dt, localDb, syncDb)
continue
}
dt.ToProcess.set(pkg)
}
err = depTreeRecursive(dt, localDb, syncDb, false)
return dt, err
}
//takes a repo package
//gives all of the non installed deps
//does again on each sub dep
func repoTreeRecursive(pkg *alpm.Package, dt *depTree, localDb *alpm.Db, syncDb alpm.DbList) (err error) {
_, exists := dt.Repo[pkg.Name()]
if exists {
return
}
dt.Repo[pkg.Name()] = pkg
/*(*pkg).Provides().ForEach(func(dep alpm.Depend) (err error) {
dt.Repo[dep.Name] = pkg
return nil
})*/
(*pkg).Depends().ForEach(func(dep alpm.Depend) (err error) {
_, exists := dt.Repo[dep.Name]
if exists {
return
}
_, isInstalled := localDb.PkgCache().FindSatisfier(dep.String())
if isInstalled == nil {
return
}
repoPkg, inRepos := syncDb.FindSatisfier(dep.String())
if inRepos == nil {
repoTreeRecursive(repoPkg, dt, localDb, syncDb)
return
}
dt.Missing.set(dep.String())
return
})
return
}
func depTreeRecursive(dt *depTree, localDb *alpm.Db, syncDb alpm.DbList, isMake bool) (err error) {
if len(dt.ToProcess) == 0 {
return
}
nextProcess := make(stringSet)
currentProcess := make(stringSet)
//strip version conditions
for dep := range dt.ToProcess {
currentProcess.set(getNameFromDep(dep))
}
//assume toprocess only contains aur stuff we have not seen
info, err := aurInfo(currentProcess.toSlice())
if err != nil {
return
}
//cache the results
for _, pkg := range info {
//copying to p fixes a bug
//would rather not copy but cant find another way to fix
p := pkg
dt.Aur[pkg.Name] = &p
}
//loop through to process and check if we now have
//each packaged cached
//if its not cached we assume its missing
for pkgName := range currentProcess {
pkg, exists := dt.Aur[pkgName]
//did not get it in the request
if !exists {
dt.Missing.set(pkgName)
continue
}
//for each dep and makedep
for _, deps := range [3][]string{pkg.Depends, pkg.MakeDepends, pkg.CheckDepends} {
for _, versionedDep := range deps {
dep := getNameFromDep(versionedDep)
_, exists = dt.Aur[dep]
//we have it cached so skip
if exists {
continue
}
_, exists = dt.Repo[dep]
//we have it cached so skip
if exists {
continue
}
_, exists = dt.Missing[dep]
//we know it does not resolve so skip
if exists {
continue
}
//check if already installed
_, isInstalled := localDb.PkgCache().FindSatisfier(versionedDep)
if isInstalled == nil {
continue
}
//check the repos for a matching dep
repoPkg, inRepos := syncDb.FindSatisfier(versionedDep)
if inRepos == nil {
repoTreeRecursive(repoPkg, dt, localDb, syncDb)
continue
}
//if all else fails add it to next search
nextProcess.set(versionedDep)
}
}
}
dt.ToProcess = nextProcess
depTreeRecursive(dt, localDb, syncDb, true)
return
}