mirror of
https://github.com/Jguer/yay
synced 2024-09-06 08:33:20 +00:00
294 lines
6.5 KiB
Go
294 lines
6.5 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"sync"
|
|
|
|
alpm "github.com/Jguer/go-alpm"
|
|
"github.com/leonelquinteros/gotext"
|
|
|
|
"github.com/Jguer/yay/v9/pkg/stringset"
|
|
"github.com/Jguer/yay/v9/pkg/text"
|
|
)
|
|
|
|
func (dp *depPool) checkInnerConflict(name, conflict string, conflicts stringset.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, conflict string, conflicts stringset.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, conflict string, conflicts stringset.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 stringset.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 stringset.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 stringset.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() (stringset.MapStringSet, error) {
|
|
var wg sync.WaitGroup
|
|
innerConflicts := make(stringset.MapStringSet)
|
|
conflicts := make(stringset.MapStringSet)
|
|
wg.Add(2)
|
|
|
|
text.OperationInfoln(gotext.Get("Checking for conflicts..."))
|
|
go func() {
|
|
dp.checkForwardConflicts(conflicts)
|
|
dp.checkReverseConflicts(conflicts)
|
|
wg.Done()
|
|
}()
|
|
|
|
text.OperationInfoln(gotext.Get("Checking for inner conflicts..."))
|
|
go func() {
|
|
dp.checkInnerConflicts(innerConflicts)
|
|
wg.Done()
|
|
}()
|
|
|
|
wg.Wait()
|
|
|
|
if len(innerConflicts) != 0 {
|
|
text.Errorln(gotext.Get("\nInner 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)
|
|
}
|
|
}
|
|
|
|
if len(conflicts) != 0 {
|
|
text.Errorln(gotext.Get("\nPackage conflicts found:"))
|
|
|
|
for name, pkgs := range conflicts {
|
|
str := gotext.Get("%s Installing %s will remove:", red(bold(smallArrow)), cyan(name))
|
|
for pkg := range pkgs {
|
|
str += " " + cyan(pkg) + ","
|
|
}
|
|
str = strings.TrimSuffix(str, ",")
|
|
|
|
fmt.Println(str)
|
|
}
|
|
}
|
|
|
|
// Add the inner conflicts to the conflicts
|
|
// These are used to decide what to pass --ask to (if set) or don't pass --noconfirm to
|
|
// As we have no idea what the order is yet we add every inner conflict to the slice
|
|
for name, pkgs := range innerConflicts {
|
|
conflicts[name] = make(stringset.StringSet)
|
|
for pkg := range pkgs {
|
|
conflicts[pkg] = make(stringset.StringSet)
|
|
}
|
|
}
|
|
|
|
if len(conflicts) > 0 {
|
|
if !config.UseAsk {
|
|
if config.NoConfirm {
|
|
return nil, fmt.Errorf(gotext.Get("package conflicts can not be resolved with noconfirm, aborting"))
|
|
}
|
|
|
|
text.Errorln(gotext.Get("Conflicting packages will have to be confirmed manually"))
|
|
}
|
|
}
|
|
|
|
return conflicts, nil
|
|
}
|
|
|
|
type missing struct {
|
|
Good stringset.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.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
|
|
}
|
|
|
|
text.Errorln(gotext.Get("Could not find all required packages:"))
|
|
for dep, trees := range missing.Missing {
|
|
for _, tree := range trees {
|
|
fmt.Fprintf(os.Stderr, "\t%s", cyan(dep))
|
|
|
|
if len(tree) == 0 {
|
|
fmt.Fprint(os.Stderr, gotext.Get(" (Target"))
|
|
} else {
|
|
fmt.Fprint(os.Stderr, gotext.Get(" (Wanted by: "))
|
|
for n := 0; n < len(tree)-1; n++ {
|
|
fmt.Fprint(os.Stderr, cyan(tree[n]), " -> ")
|
|
}
|
|
fmt.Fprint(os.Stderr, cyan(tree[len(tree)-1]))
|
|
}
|
|
|
|
fmt.Fprintln(os.Stderr, ")")
|
|
}
|
|
}
|
|
|
|
return fmt.Errorf("")
|
|
}
|