yay/depCheck.go
morganamilo 6e990e4dc5
Don't conflict with pkgs that are in the depPool
When upgrading multiple packages that are already installed we should
not conflict with already installed packages that are in the depPool.

This is because the version in the depTree is going to replace the
currently installed version of the package and may have different
conflicts.

If there is a conflict between stuff in the depPool these should be
handled by the innerConflicts check anyway.
2018-05-29 13:15:45 +01:00

274 lines
5.7 KiB
Go

package main
import (
"fmt"
"strings"
"sync"
alpm "github.com/jguer/go-alpm"
// gopkg "github.com/mikkeloscar/gopkgbuild"
)
func (dp *depPool) checkInnerConflict(name string, conflict string, conflicts mapStringSet) {
for _, pkg := range dp.Aur {
if pkg.Name == name {
continue
}
if satisfiesAur(conflict, pkg) {
conflicts.Add(name, pkg.Name)
}
}
for _, pkg := range dp.Repo {
if pkg.Name() == name {
continue
}
if satisfiesRepo(conflict, pkg) {
conflicts.Add(name, pkg.Name())
}
}
}
func (dp *depPool) checkForwardConflict(name string, conflict string, conflicts mapStringSet) {
dp.LocalDb.PkgCache().ForEach(func(pkg alpm.Package) error {
if pkg.Name() == name || dp.hasPackage(pkg.Name()) {
return nil
}
if satisfiesRepo(conflict, &pkg) {
n := pkg.Name()
if n != conflict {
n += " (" + conflict + ")"
}
conflicts.Add(name, n)
}
return nil
})
}
func (dp *depPool) checkReverseConflict(name string, conflict string, conflicts mapStringSet) {
for _, pkg := range dp.Aur {
if pkg.Name == name {
continue
}
if satisfiesAur(conflict, pkg) {
if name != conflict {
name += " (" + conflict + ")"
}
conflicts.Add(pkg.Name, name)
}
}
for _, pkg := range dp.Repo {
if pkg.Name() == name {
continue
}
if satisfiesRepo(conflict, pkg) {
if name != conflict {
name += " (" + conflict + ")"
}
conflicts.Add(pkg.Name(), name)
}
}
}
func (dp *depPool) checkInnerConflicts(conflicts mapStringSet) {
for _, pkg := range dp.Aur {
for _, conflict := range pkg.Conflicts {
dp.checkInnerConflict(pkg.Name, conflict, conflicts)
}
}
for _, pkg := range dp.Repo {
pkg.Conflicts().ForEach(func(conflict alpm.Depend) error {
dp.checkInnerConflict(pkg.Name(), conflict.String(), conflicts)
return nil
})
}
}
func (dp *depPool) checkForwardConflicts(conflicts mapStringSet) {
for _, pkg := range dp.Aur {
for _, conflict := range pkg.Conflicts {
dp.checkForwardConflict(pkg.Name, conflict, conflicts)
}
}
for _, pkg := range dp.Repo {
pkg.Conflicts().ForEach(func(conflict alpm.Depend) error {
dp.checkForwardConflict(pkg.Name(), conflict.String(), conflicts)
return nil
})
}
}
func (dp *depPool) checkReverseConflicts(conflicts mapStringSet) {
dp.LocalDb.PkgCache().ForEach(func(pkg alpm.Package) error {
if dp.hasPackage(pkg.Name()) {
return nil
}
pkg.Conflicts().ForEach(func(conflict alpm.Depend) error {
dp.checkReverseConflict(pkg.Name(), conflict.String(), conflicts)
return nil
})
return nil
})
}
func (dp *depPool) CheckConflicts() error {
var wg sync.WaitGroup
innerConflicts := make(mapStringSet)
conflicts := make(mapStringSet)
wg.Add(2)
fmt.Println(bold(cyan("::") + bold(" Checking for conflicts...")))
go func() {
dp.checkForwardConflicts(conflicts)
dp.checkReverseConflicts(conflicts)
wg.Done()
}()
fmt.Println(bold(cyan("::") + bold(" Checking for inner conflicts...")))
go func() {
dp.checkInnerConflicts(innerConflicts)
wg.Done()
}()
wg.Wait()
if len(innerConflicts) != 0 {
fmt.Println()
fmt.Println(bold(red(arrow)), bold("Inner conflicts found:"))
for name, pkgs := range innerConflicts {
str := red(bold(smallArrow)) + " " + name + ":"
for pkg := range pkgs {
str += " " + cyan(pkg) + ","
}
str = strings.TrimSuffix(str, ",")
fmt.Println(str)
}
return fmt.Errorf("Unresolvable package conflicts, aborting")
}
if len(conflicts) != 0 {
fmt.Println()
fmt.Println(bold(red(arrow)), bold("Package conflicts found:"))
for name, pkgs := range conflicts {
str := red(bold(smallArrow)) + " Installing " + cyan(name) + " will remove:"
for pkg := range pkgs {
str += " " + cyan(pkg) + ","
}
str = strings.TrimSuffix(str, ",")
fmt.Println(str)
}
fmt.Println()
}
return nil
}
type missing struct {
Good stringSet
Missing map[string][][]string
}
func (dp *depPool) _checkMissing(dep string, stack []string, missing *missing) {
if missing.Good.get(dep) {
return
}
if trees, ok := missing.Missing[dep]; ok {
for _, tree := range trees {
if stringSliceEqual(tree, stack) {
return
}
}
missing.Missing[dep] = append(missing.Missing[dep], stack)
return
}
aurPkg := dp.findSatisfierAur(dep)
if aurPkg != nil {
missing.Good.set(dep)
for _, deps := range [3][]string{aurPkg.Depends, aurPkg.MakeDepends, aurPkg.CheckDepends} {
for _, aurDep := range deps {
if _, err := dp.LocalDb.PkgCache().FindSatisfier(aurDep); err == nil {
missing.Good.set(aurDep)
continue
}
dp._checkMissing(aurDep, append(stack, aurPkg.Name), missing)
}
}
return
}
repoPkg := dp.findSatisfierRepo(dep)
if repoPkg != nil {
missing.Good.set(dep)
repoPkg.Depends().ForEach(func(repoDep alpm.Depend) error {
if _, err := dp.LocalDb.PkgCache().FindSatisfier(repoDep.String()); err == nil {
missing.Good.set(repoDep.String())
return nil
}
dp._checkMissing(repoDep.String(), append(stack, repoPkg.Name()), missing)
return nil
})
return
}
missing.Missing[dep] = [][]string{stack}
}
func (dp *depPool) CheckMissing() error {
missing := &missing{
make(stringSet),
make(map[string][][]string),
}
for _, target := range dp.Targets {
dp._checkMissing(target.DepString(), make([]string, 0), missing)
}
if len(missing.Missing) == 0 {
return nil
}
fmt.Println(bold(red(arrow+" Error: ")) + "Could not find all required packages:")
for dep, trees := range missing.Missing {
for _, tree := range trees {
fmt.Print(" "+cyan(dep), " (Tree: ")
if len(tree) == 0 {
fmt.Print(cyan("Target "))
} else {
for _, pkg := range tree {
fmt.Print(cyan(pkg), " -> ")
}
}
fmt.Println(")")
}
}
return fmt.Errorf("")
}