Browse Source

Rework inner conflicts

Inner conflicts now check against the previously installed aur packages
For example when installing yay, yay-bin and yay-git

yay will be checked the previously insalled packages (nothing)

yay-bin will be checked the previously insalled packages and see that it
conflicts with yay and warn you that yay will be removed

yay-git will be checked the previously insalled packages and see that it
conflicts with yay but see that it has already been removed by yay-bin
so does nothing. Then it will see that it conflicts with yay-bin and
warn you that yay-bin will be removed

This example is unlikley to happen unless the user enters
`yay -S yay yay-bin yay-git`. But where this does happen is packages
which have some sort of bootsrapping process such as ffmpeg-libfdk_aac.

If two repo packages conflict then we abort. This is because they will
be installed at the same time and we never swap repo packages mid AUR
install.
morganamilo 6 years ago
parent
commit
f648697994
1 changed files with 101 additions and 73 deletions
  1. 101 73
      depCheck.go

+ 101 - 73
depCheck.go

@@ -6,6 +6,7 @@ import (
 	"sync"
 
 	alpm "github.com/jguer/go-alpm"
+	rpc "github.com/mikkeloscar/aur"
 )
 
 func (ds *depSolver) _checkMissing(dep string, stack []string, missing *missing) {
@@ -96,30 +97,6 @@ func (ds *depSolver) CheckMissing() error {
 	return fmt.Errorf("")
 }
 
-func (ds *depSolver) checkInnerConflict(name string, conflict string, conflicts mapStringSet) {
-	for _, base := range ds.Aur {
-		for _, pkg := range base {
-			if pkg.Name == name {
-				continue
-			}
-
-			if satisfiesAur(conflict, pkg) {
-				conflicts.Add(name, pkg.Name)
-			}
-		}
-	}
-
-	for _, pkg := range ds.Repo {
-		if pkg.Name() == name {
-			continue
-		}
-
-		if satisfiesRepo(conflict, pkg) {
-			conflicts.Add(name, pkg.Name())
-		}
-	}
-}
-
 func (ds *depSolver) checkForwardConflict(name string, conflict string, conflicts mapStringSet) {
 	ds.LocalDb.PkgCache().ForEach(func(pkg alpm.Package) error {
 		if pkg.Name() == name || ds.hasPackage(pkg.Name()) {
@@ -159,23 +136,6 @@ func (ds *depSolver) checkReverseConflict(name string, conflict string, conflict
 	}
 }
 
-func (ds *depSolver) checkInnerConflicts(conflicts mapStringSet) {
-	for _, base := range ds.Aur {
-		for _, pkg := range base {
-			for _, conflict := range pkg.Conflicts {
-				ds.checkInnerConflict(pkg.Name, conflict, conflicts)
-			}
-		}
-	}
-
-	for _, pkg := range ds.Repo {
-		pkg.Conflicts().ForEach(func(conflict alpm.Depend) error {
-			ds.checkInnerConflict(pkg.Name(), conflict.String(), conflicts)
-			return nil
-		})
-	}
-}
-
 func (ds *depSolver) checkForwardConflicts(conflicts mapStringSet) {
 	for _, base := range ds.Aur {
 		for _, pkg := range base {
@@ -208,11 +168,79 @@ func (ds *depSolver) checkReverseConflicts(conflicts mapStringSet) {
 	})
 }
 
+func (ds *depSolver) checkInnerRepoConflicts(conflicts mapStringSet) {
+	for _, pkg := range ds.Repo {
+		pkg.Conflicts().ForEach(func(conflict alpm.Depend) error {
+			for _, innerpkg := range ds.Repo {
+				if pkg.Name() != innerpkg.Name() && satisfiesRepo(conflict.String(), innerpkg) {
+					conflicts.Add(pkg.Name(), innerpkg.Name())
+				}
+			}
+
+			return nil
+		})
+	}
+}
+
+func (ds *depSolver) checkInnerConflicts(conflicts mapStringSet) {
+	removed := make(stringSet)
+	//ds.checkInnerConflictRepoAur(conflicts)
+
+	for current, currbase := range ds.Aur {
+		for _, pkg := range currbase {
+			ds.checkInnerConflict(pkg, ds.Aur[:current], removed, conflicts)
+		}
+	}
+}
+
+// Check if anything conflicts with currpkg
+// If so add the conflict with currpkg being removed by the conflicting pkg
+func (ds *depSolver) checkInnerConflict(currpkg *rpc.Pkg, aur []Base, removed stringSet, conflicts mapStringSet) {
+	for _, base := range aur {
+		for _, pkg := range base {
+			for _, conflict := range pkg.Conflicts {
+				if !removed.get(pkg.Name) && satisfiesAur(conflict, currpkg) {
+					addInnerConflict(pkg.Name, currpkg.Name, removed, conflicts)
+				}
+			}
+		}
+	}
+	for _, pkg := range ds.Repo {
+		pkg.Conflicts().ForEach(func(conflict alpm.Depend) error {
+			if !removed.get(pkg.Name()) && satisfiesAur(conflict.String(), currpkg) {
+				addInnerConflict(pkg.Name(), currpkg.Name, removed, conflicts)
+			}
+			return nil
+		})
+	}
+
+	for _, conflict := range currpkg.Conflicts {
+		for _, base := range aur {
+			for _, pkg := range base {
+				if !removed.get(pkg.Name) && satisfiesAur(conflict, pkg) {
+					addInnerConflict(pkg.Name, currpkg.Name, removed, conflicts)
+				}
+			}
+		}
+		for _, pkg := range ds.Repo {
+			if !removed.get(pkg.Name()) && satisfiesRepo(conflict, pkg) {
+				addInnerConflict(pkg.Name(), currpkg.Name, removed, conflicts)
+			}
+		}
+	}
+}
+
+func addInnerConflict(toRemove string, removedBy string, removed stringSet, conflicts mapStringSet) {
+	conflicts.Add(removedBy, toRemove)
+	removed.set(toRemove)
+}
+
 func (ds *depSolver) CheckConflicts() (mapStringSet, error) {
 	var wg sync.WaitGroup
 	innerConflicts := make(mapStringSet)
 	conflicts := make(mapStringSet)
-	wg.Add(2)
+	repoConflicts := make(mapStringSet)
+	wg.Add(3)
 
 	fmt.Println(bold(cyan("::") + bold(" Checking for conflicts...")))
 	go func() {
@@ -226,48 +254,48 @@ func (ds *depSolver) CheckConflicts() (mapStringSet, error) {
 		ds.checkInnerConflicts(innerConflicts)
 		wg.Done()
 	}()
+	go func() {
+		ds.checkInnerRepoConflicts(repoConflicts)
+		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) + ","
+	formatConflicts := func(conflicts mapStringSet, inner bool, s string) {
+		if len(conflicts) != 0 {
+			fmt.Println()
+			if inner {
+				fmt.Println(bold(red(arrow)), bold("Inner conflicts found:"))
+			} else {
+				fmt.Println(bold(red(arrow)), bold("Package conflicts found:"))
 			}
-			str = strings.TrimSuffix(str, ",")
-
-			fmt.Println(str)
-		}
-
-	}
 
-	if len(conflicts) != 0 {
-		fmt.Println()
-		fmt.Println(bold(red(arrow)), bold("Package conflicts found:"))
+			for name, pkgs := range conflicts {
+				str := fmt.Sprintf(s, cyan(name))
+				for pkg := range pkgs {
+					str += " " + cyan(pkg) + ","
+				}
+				str = strings.TrimSuffix(str, ",")
 
-		for name, pkgs := range conflicts {
-			str := red(bold(smallArrow)) + " Installing " + cyan(name) + " will remove:"
-			for pkg := range pkgs {
-				str += " " + cyan(pkg) + ","
+				fmt.Println(str)
 			}
-			str = strings.TrimSuffix(str, ",")
-
-			fmt.Println(str)
 		}
+	}
 
+	repoStr := red(bold(smallArrow)) + " %s Conflicts with:"
+	formatConflicts(repoConflicts, true, repoStr)
+
+	if len(repoConflicts) > 0 {
+		return nil, fmt.Errorf("Unavoidable conflicts, aborting")
 	}
 
-	// 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)
-		for pkg := range pkgs {
-			conflicts[pkg] = make(stringSet)
+	str := red(bold(smallArrow)) + " Installing %s will remove:"
+	formatConflicts(conflicts, false, str)
+	formatConflicts(innerConflicts, true, str)
+
+	for name, c := range innerConflicts {
+		for cs, _ := range c {
+			conflicts.Add(name, cs)
 		}
 	}