123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354 |
- package main
- import (
- "fmt"
- "strings"
- "sync"
- alpm "github.com/jguer/go-alpm"
- gopkg "github.com/mikkeloscar/gopkgbuild"
- )
- // Checks a single conflict against every other to be installed package's
- // name and its provides.
- func checkInnerConflict(name string, conflict string, conflicts map[string]stringSet, dc *depCatagories) {
- deps, err := gopkg.ParseDeps([]string{conflict})
- if err != nil {
- return
- }
- dep := deps[0]
- for _, pkg := range dc.Aur {
- if name == pkg.Name {
- continue
- }
- version, err := gopkg.NewCompleteVersion(pkg.Version)
- if err != nil {
- return
- }
- if dep.Name == pkg.Name && version.Satisfies(dep) {
- addMapStringSet(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
- }
- }
- if version != nil && version.Satisfies(dep) {
- addMapStringSet(conflicts, name, pkg.Name)
- break
- }
- }
- }
- for _, pkg := range dc.Repo {
- if name == pkg.Name() {
- continue
- }
- version, err := gopkg.NewCompleteVersion(pkg.Version())
- if err != nil {
- return
- }
- if dep.Name == pkg.Name() && version.Satisfies(dep) {
- addMapStringSet(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 {
- addMapStringSet(conflicts, name, pkg.Name())
- return fmt.Errorf("")
- }
- version, err := gopkg.NewCompleteVersion(provide.Version)
- if err != nil {
- return nil
- }
- if version.Satisfies(dep) {
- addMapStringSet(conflicts, name, pkg.Name())
- return fmt.Errorf("")
- }
- return nil
- })
- }
- }
- // Checks every to be installed package's conflicts against every other to be
- // installed package and its provides.
- 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
- }
- // Checks a provide or packagename from a to be installed package
- // against every already installed package's conflicts
- func checkReverseConflict(name string, provide string, conflicts map[string]stringSet) error {
- var version *gopkg.CompleteVersion
- var err error
- 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
- addMapStringSet(conflicts, name, pkg.Name()+" ("+provide+")")
- return fmt.Errorf("")
- }
- return nil
- })
- return nil
- })
- return nil
- }
- // Checks the conflict of a to be installed package against the package name and
- // provides of every installed package.
- func checkConflict(name string, conflict string, conflicts map[string]stringSet) error {
- 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) {
- addMapStringSet(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 {
- addMapStringSet(conflicts, name, pkg.Name()+" ("+provide.Name+")")
- return fmt.Errorf("")
- }
- version, err := gopkg.NewCompleteVersion(provide.Version)
- if err != nil {
- return nil
- }
- if version.Satisfies(dep) {
- addMapStringSet(conflicts, name, pkg.Name()+" ("+provide.Name+")")
- return fmt.Errorf("")
- }
- return nil
- })
- return nil
- })
- return nil
- }
- // Checks every to be installed package's conflicts against the names and
- // provides of every already installed package and checks every to be installed
- // package's name and provides against every already installed package.
- 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
- }
- // Combiles checkForConflicts() and checkForInnerConflicts() in parallel and
- // does some printing.
- 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("::") + bold(" Checking for conflicts...")))
- go func() {
- conflicts, err = checkForConflicts(dc)
- wg.Done()
- }()
- fmt.Println(bold(cyan("::") + bold(" Checking for inner conflicts...")))
- go func() {
- innerConflicts = checkForInnerConflicts(dc)
- wg.Done()
- }()
- wg.Wait()
- if err != nil {
- return err
- }
- 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)
- }
- 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)
- }
- fmt.Println(str)
- }
- fmt.Println()
- }
- return nil
- }
|