|
@@ -8,6 +8,7 @@ import (
|
|
|
"os/exec"
|
|
|
"strconv"
|
|
|
"strings"
|
|
|
+ "sync"
|
|
|
|
|
|
alpm "github.com/jguer/go-alpm"
|
|
|
rpc "github.com/mikkeloscar/aur"
|
|
@@ -126,7 +127,7 @@ func install(parser *arguments) error {
|
|
|
fmt.Println()
|
|
|
|
|
|
if !parser.existsArg("gendb") {
|
|
|
- err = checkForConflicts(dc)
|
|
|
+ err = checkForAllConflicts(dc)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
@@ -460,43 +461,346 @@ func cleanBuilds(pkgs []*rpc.Pkg) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-func checkForConflicts(dc *depCatagories) error {
|
|
|
- localDb, err := alpmHandle.LocalDb()
|
|
|
+func checkInnerConflict(name string, conflict string, conflicts map[string]stringSet, dc *depCatagories) {
|
|
|
+ add := func(h map[string]stringSet, n string, v string) {
|
|
|
+ _, ok := h[n]
|
|
|
+ if !ok {
|
|
|
+ h[n] = make(stringSet)
|
|
|
+ }
|
|
|
+ h[n].set(v)
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ deps, err := gopkg.ParseDeps([]string{conflict})
|
|
|
if err != nil {
|
|
|
- return err
|
|
|
+ return
|
|
|
}
|
|
|
- toRemove := make(map[string]stringSet)
|
|
|
+ dep := deps[0]
|
|
|
|
|
|
for _, pkg := range dc.Aur {
|
|
|
- for _, cpkg := range pkg.Conflicts {
|
|
|
- if _, err := localDb.PkgByName(cpkg); err == nil {
|
|
|
- _, ok := toRemove[pkg.Name]
|
|
|
- if !ok {
|
|
|
- toRemove[pkg.Name] = make(stringSet)
|
|
|
+ if name == pkg.Name {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ version, err := gopkg.NewCompleteVersion(pkg.Version)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if dep.Name == pkg.Name && version.Satisfies(dep) {
|
|
|
+ add(conflicts, name, pkg.Name)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, provide := range pkg.Provides {
|
|
|
+ // Provides are not versioned unless explicitly defined as
|
|
|
+ // such. If a conflict is versioned but a provide is
|
|
|
+ // not it can not conflict.
|
|
|
+ if (dep.MaxVer != nil || dep.MinVer != nil) && !strings.ContainsAny(provide, "><=") {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ var version *gopkg.CompleteVersion
|
|
|
+ var err error
|
|
|
+
|
|
|
+ pname, pversion := splitNameFromDep(provide)
|
|
|
+
|
|
|
+ if dep.Name != pname {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ if pversion != "" {
|
|
|
+ version, err = gopkg.NewCompleteVersion(provide)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
}
|
|
|
- toRemove[pkg.Name].set(cpkg)
|
|
|
}
|
|
|
+
|
|
|
+ if version != nil && version.Satisfies(dep) {
|
|
|
+ add(conflicts, name, pkg.Name)
|
|
|
+ break
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
}
|
|
|
|
|
|
for _, pkg := range dc.Repo {
|
|
|
- pkg.Conflicts().ForEach(func(conf alpm.Depend) error {
|
|
|
- if _, err := localDb.PkgByName(conf.Name); err == nil {
|
|
|
- _, ok := toRemove[pkg.Name()]
|
|
|
- if !ok {
|
|
|
- toRemove[pkg.Name()] = make(stringSet)
|
|
|
- }
|
|
|
- toRemove[pkg.Name()].set(conf.Name)
|
|
|
+ if name == pkg.Name() {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ version, err := gopkg.NewCompleteVersion(pkg.Version())
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if dep.Name == pkg.Name() && version.Satisfies(dep) {
|
|
|
+ add(conflicts, name, pkg.Name())
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ pkg.Provides().ForEach(func(provide alpm.Depend) error {
|
|
|
+ // Provides are not versioned unless explicitly defined as
|
|
|
+ // such. If a conflict is versioned but a provide is
|
|
|
+ // not it can not conflict.
|
|
|
+ if (dep.MaxVer != nil || dep.MinVer != nil) && provide.Mod == alpm.DepModAny {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ if dep.Name != pkg.Name() {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ if provide.Mod == alpm.DepModAny {
|
|
|
+ add(conflicts, name, pkg.Name())
|
|
|
+ return fmt.Errorf("")
|
|
|
+ }
|
|
|
+
|
|
|
+ version, err := gopkg.NewCompleteVersion(provide.Version)
|
|
|
+ if err != nil {
|
|
|
+ return nil
|
|
|
}
|
|
|
+
|
|
|
+ if version.Satisfies(dep) {
|
|
|
+ add(conflicts, name, pkg.Name())
|
|
|
+ return fmt.Errorf("")
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func checkForInnerConflicts(dc *depCatagories) (map[string]stringSet) {
|
|
|
+ conflicts := make(map[string]stringSet)
|
|
|
+
|
|
|
+ for _, pkg := range dc.Aur {
|
|
|
+ for _, cpkg := range pkg.Conflicts {
|
|
|
+ checkInnerConflict(pkg.Name, cpkg, conflicts, dc)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, pkg := range dc.Repo {
|
|
|
+ pkg.Conflicts().ForEach(func(conflict alpm.Depend) error {
|
|
|
+ checkInnerConflict(pkg.Name(), conflict.String(), conflicts, dc)
|
|
|
return nil
|
|
|
})
|
|
|
}
|
|
|
+
|
|
|
+ return conflicts
|
|
|
+}
|
|
|
+
|
|
|
+func checkReverseConflict(name string, provide string, conflicts map[string]stringSet) error {
|
|
|
+ add := func(h map[string]stringSet, n string, v string) {
|
|
|
+ _, ok := h[n]
|
|
|
+ if !ok {
|
|
|
+ h[n] = make(stringSet)
|
|
|
+ }
|
|
|
+ h[n].set(v)
|
|
|
+ }
|
|
|
+
|
|
|
+ var version *gopkg.CompleteVersion
|
|
|
+ var err error
|
|
|
|
|
|
- if len(toRemove) != 0 {
|
|
|
+ localDb, err := alpmHandle.LocalDb()
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ pname, pversion := splitNameFromDep(provide)
|
|
|
+ if pversion != "" {
|
|
|
+ version, err = gopkg.NewCompleteVersion(pversion)
|
|
|
+ if err != nil {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ localDb.PkgCache().ForEach(func(pkg alpm.Package) error {
|
|
|
+ if name == pkg.Name() {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ pkg.Conflicts().ForEach(func(conflict alpm.Depend) error {
|
|
|
+ deps, err := gopkg.ParseDeps([]string{conflict.String()})
|
|
|
+ if err != nil {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ dep := deps[0]
|
|
|
+ // Provides are not versioned unless explicitly defined as
|
|
|
+ // such. If a conflict is versioned but a provide is
|
|
|
+ // not it can not conflict.
|
|
|
+ if (dep.MaxVer != nil || dep.MinVer != nil) && version == nil {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ if dep.Name != pname {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ if version == nil || version.Satisfies(dep) {
|
|
|
+ // Todo
|
|
|
+ add(conflicts, name, pkg.Name() + " (" + provide + ")")
|
|
|
+ return fmt.Errorf("")
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+ })
|
|
|
+
|
|
|
+ return nil
|
|
|
+ })
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func checkConflict(name string, conflict string, conflicts map[string]stringSet) error {
|
|
|
+ add := func(h map[string]stringSet, n string, v string) {
|
|
|
+ _, ok := h[n]
|
|
|
+ if !ok {
|
|
|
+ h[n] = make(stringSet)
|
|
|
+ }
|
|
|
+ h[n].set(v)
|
|
|
+ }
|
|
|
+
|
|
|
+ localDb, err := alpmHandle.LocalDb()
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ deps, err := gopkg.ParseDeps([]string{conflict})
|
|
|
+ if err != nil {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ dep := deps[0]
|
|
|
+
|
|
|
+ localDb.PkgCache().ForEach(func(pkg alpm.Package) error {
|
|
|
+ if name == pkg.Name() {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ version, err := gopkg.NewCompleteVersion(pkg.Version())
|
|
|
+ if err != nil {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ if dep.Name == pkg.Name() && version.Satisfies(dep) {
|
|
|
+ add(conflicts, name, pkg.Name())
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ pkg.Provides().ForEach(func(provide alpm.Depend) error {
|
|
|
+ if dep.Name != provide.Name {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ // Provides arent version unless explicitly defined as
|
|
|
+ // such. If a conflict is versioned but a provide is
|
|
|
+ // not it can not conflict.
|
|
|
+ if (dep.MaxVer != nil || dep.MinVer != nil) && provide.Mod == alpm.DepModAny {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ if provide.Mod == alpm.DepModAny {
|
|
|
+ add(conflicts, name, pkg.Name() + " (" + provide.Name + ")")
|
|
|
+ return fmt.Errorf("")
|
|
|
+ }
|
|
|
+
|
|
|
+ version, err := gopkg.NewCompleteVersion(provide.Version)
|
|
|
+ if err != nil {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ if version.Satisfies(dep) {
|
|
|
+ add(conflicts, name, pkg.Name() + " (" + provide.Name + ")")
|
|
|
+ return fmt.Errorf("")
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+ })
|
|
|
+
|
|
|
+ return nil
|
|
|
+ })
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+func checkForConflicts(dc *depCatagories) (map[string]stringSet, error) {
|
|
|
+ conflicts := make(map[string]stringSet)
|
|
|
+
|
|
|
+ for _, pkg := range dc.Aur {
|
|
|
+ for _, cpkg := range pkg.Conflicts {
|
|
|
+ checkConflict(pkg.Name, cpkg, conflicts)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, pkg := range dc.Repo {
|
|
|
+ pkg.Conflicts().ForEach(func(conflict alpm.Depend) error {
|
|
|
+ checkConflict(pkg.Name(), conflict.String(), conflicts)
|
|
|
+ return nil
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, pkg := range dc.Aur {
|
|
|
+ checkReverseConflict(pkg.Name, pkg.Name, conflicts)
|
|
|
+ for _, ppkg := range pkg.Provides {
|
|
|
+ checkReverseConflict(pkg.Name, ppkg, conflicts)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, pkg := range dc.Repo {
|
|
|
+ checkReverseConflict(pkg.Name(), pkg.Name(), conflicts)
|
|
|
+ pkg.Provides().ForEach(func(provide alpm.Depend) error {
|
|
|
+ checkReverseConflict(pkg.Name(), provide.String(), conflicts)
|
|
|
+ return nil
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ return conflicts, nil
|
|
|
+}
|
|
|
+
|
|
|
+func checkForAllConflicts(dc *depCatagories) error {
|
|
|
+ var err error
|
|
|
+ var conflicts map[string]stringSet
|
|
|
+ var innerConflicts map[string]stringSet
|
|
|
+ var wg sync.WaitGroup
|
|
|
+ wg.Add(2)
|
|
|
+
|
|
|
+
|
|
|
+ fmt.Println(bold(cyan("::")+ " Checking for conflicts..."))
|
|
|
+ go func() {
|
|
|
+ conflicts, err = checkForConflicts(dc)
|
|
|
+ wg.Done()
|
|
|
+ }()
|
|
|
+
|
|
|
+ fmt.Println(bold(cyan("::")+ " Checking for inner conflicts..."))
|
|
|
+ go func() {
|
|
|
+ innerConflicts = checkForInnerConflicts(dc)
|
|
|
+ wg.Done()
|
|
|
+ }()
|
|
|
+
|
|
|
+ wg.Wait()
|
|
|
+ if len(innerConflicts) != 0 {
|
|
|
fmt.Println(
|
|
|
- red("Package conflicts found:"))
|
|
|
- for name, pkgs := range toRemove {
|
|
|
- str := "\tInstalling " + magenta(name) + " will remove"
|
|
|
+ red("\nInner conflicts found:"))
|
|
|
+ for name, pkgs := range innerConflicts {
|
|
|
+ str := "\t" + name + ":"
|
|
|
+ for pkg := range pkgs {
|
|
|
+ str += " " + magenta(pkg)
|
|
|
+ }
|
|
|
+
|
|
|
+ fmt.Println(str)
|
|
|
+ }
|
|
|
+
|
|
|
+ return fmt.Errorf("Aborting")
|
|
|
+ }
|
|
|
+
|
|
|
+ if len(conflicts) != 0 {
|
|
|
+ fmt.Println(
|
|
|
+ red("\nPackage conflicts found:"))
|
|
|
+ for name, pkgs := range conflicts {
|
|
|
+ str := "\tInstalling " + magenta(name) + " will remove:"
|
|
|
for pkg := range pkgs {
|
|
|
str += " " + magenta(pkg)
|
|
|
}
|
|
@@ -736,6 +1040,7 @@ func clean(pkgs []*rpc.Pkg) {
|
|
|
}
|
|
|
|
|
|
func completeFileName(dir, name string) (string, error) {
|
|
|
+
|
|
|
files, err := ioutil.ReadDir(dir)
|
|
|
if err != nil {
|
|
|
return "", err
|