diff --git a/conflicts.go b/conflicts.go deleted file mode 100644 index 9f03b94..0000000 --- a/conflicts.go +++ /dev/null @@ -1,354 +0,0 @@ -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 mapStringSet, 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) { - conflicts.Add(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) { - conflicts.Add(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) { - conflicts.Add(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 { - conflicts.Add(name, pkg.Name()) - return fmt.Errorf("") - } - - version, err := gopkg.NewCompleteVersion(provide.Version) - if err != nil { - return nil - } - - if version.Satisfies(dep) { - conflicts.Add(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) mapStringSet { - conflicts := make(mapStringSet) - - 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 mapStringSet) 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 - conflicts.Add(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 mapStringSet) 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) { - conflicts.Add(name, pkg.Name()) - return nil - } - - pkg.Provides().ForEach(func(provide alpm.Depend) error { - if dep.Name != provide.Name { - return nil - } - - // Provides aren't 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 { - conflicts.Add(name, pkg.Name()+" ("+provide.Name+")") - return fmt.Errorf("") - } - - version, err := gopkg.NewCompleteVersion(provide.Version) - if err != nil { - return nil - } - - if version.Satisfies(dep) { - conflicts.Add(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) (mapStringSet, error) { - conflicts := make(mapStringSet) - - 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 mapStringSet - var innerConflicts mapStringSet - 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 -} diff --git a/dep.go b/dep.go index 2958ef7..e604c3f 100644 --- a/dep.go +++ b/dep.go @@ -102,3 +102,28 @@ func satisfiesRepo(dep string, pkg *alpm.Package) bool { return false } + +//split apart db/package to db and package +func splitDbFromName(pkg string) (string, string) { + split := strings.SplitN(pkg, "/", 2) + + if len(split) == 2 { + return split[0], split[1] + } + return "", split[0] +} + +func getBases(pkgs map[string]*rpc.Pkg) map[string][]*rpc.Pkg { + bases := make(map[string][]*rpc.Pkg) + + for _, pkg := range pkgs { + _, ok := bases[pkg.PackageBase] + if !ok { + bases[pkg.PackageBase] = make([]*rpc.Pkg, 0) + } + bases[pkg.PackageBase] = append(bases[pkg.PackageBase], pkg) + } + + return bases +} + diff --git a/dependencies.go b/dependencies.go deleted file mode 100644 index b795673..0000000 --- a/dependencies.go +++ /dev/null @@ -1,650 +0,0 @@ -package main - -import ( - "fmt" - "strings" - - alpm "github.com/jguer/go-alpm" - rpc "github.com/mikkeloscar/aur" - gopkg "github.com/mikkeloscar/gopkgbuild" -) - -type depTree struct { - ToProcess stringSet - Repo map[string]*alpm.Package - Aur map[string]*rpc.Pkg - Missing stringSet - Groups stringSet - Provides map[string]string - Warnings *aurWarnings -} - -type depCatagories struct { - Repo []*alpm.Package - Aur []*rpc.Pkg - MakeOnly stringSet - Bases map[string][]*rpc.Pkg -} - -func makeDepTree() *depTree { - dt := depTree{ - make(stringSet), - make(map[string]*alpm.Package), - make(map[string]*rpc.Pkg), - make(stringSet), - make(stringSet), - make(map[string]string), - &aurWarnings{}, - } - - return &dt -} - -func makeDependCatagories() *depCatagories { - dc := depCatagories{ - make([]*alpm.Package, 0), - make([]*rpc.Pkg, 0), - make(stringSet), - make(map[string][]*rpc.Pkg), - } - - return &dc -} - -// Cut the version requirement from a dependency leaving just the name. -func splitNameFromDep(dep string) (string, string) { - split := strings.FieldsFunc(dep, func(c rune) bool { - return c == '>' || c == '<' || c == '=' - }) - - if len(split) == 1 { - return split[0], "" - } - - return split[0], split[1] -} - -//split apart db/package to db and package -func splitDbFromName(pkg string) (string, string) { - split := strings.SplitN(pkg, "/", 2) - - if len(split) == 2 { - return split[0], split[1] - } - return "", split[0] -} - -func isDevelName(name string) bool { - for _, suffix := range []string{"git", "svn", "hg", "bzr", "nightly"} { - if strings.HasSuffix(name, suffix) { - return true - } - } - - return strings.Contains(name, "-always-") -} - -func getBases(pkgs map[string]*rpc.Pkg) map[string][]*rpc.Pkg { - bases := make(map[string][]*rpc.Pkg) - -nextpkg: - for _, pkg := range pkgs { - for _, base := range bases[pkg.PackageBase] { - if base == pkg { - continue nextpkg - } - } - - _, ok := bases[pkg.PackageBase] - if !ok { - bases[pkg.PackageBase] = make([]*rpc.Pkg, 0) - } - bases[pkg.PackageBase] = append(bases[pkg.PackageBase], pkg) - } - - return bases -} - -func aurFindProvider(name string, dt *depTree) (string, *rpc.Pkg) { - dep, _ := splitNameFromDep(name) - aurpkg, exists := dt.Aur[dep] - - if exists { - return dep, aurpkg - } - - dep, exists = dt.Provides[dep] - if exists { - aurpkg, exists = dt.Aur[dep] - if exists { - return dep, aurpkg - } - } - - return "", nil - -} - -func repoFindProvider(name string, dt *depTree) (string, *alpm.Package) { - dep, _ := splitNameFromDep(name) - alpmpkg, exists := dt.Repo[dep] - - if exists { - return dep, alpmpkg - } - - dep, exists = dt.Provides[dep] - if exists { - alpmpkg, exists = dt.Repo[dep] - if exists { - return dep, alpmpkg - } - } - - return "", nil - -} - -// Step two of dependency resolving. We already have all the information on the -// packages we need, now it's just about ordering them correctly. -// pkgs is a list of targets, the packages we want to install. Dependencies are -// not included. -// For each package we want we iterate down the tree until we hit the bottom. -// This is done recursively for each branch. -// The start of the tree is defined as the package we want. -// When we hit the bottom of the branch we know thats the first package -// we need to install so we add it to the start of the to install -// list (dc.Aur and dc.Repo). -// We work our way up until there is another branch to go down and do it all -// again. -// -// Here is a visual example: -// -// a -// / \ -// b c -// / \ -// d e -// -// We see a and it needs b and c -// We see b and it needs d and e -// We see d - it needs nothing so we add d to our list and move up -// We see e - it needs nothing so we add e to our list and move up -// We see c - it needs nothing so we add c to our list and move up -// -// The final install order would come out as debca -// -// There is a little more to this, handling provides, multiple packages wanting the -// same dependencies, etc. This is just the basic premise. -func getDepCatagories(pkgs []string, dt *depTree) (*depCatagories, error) { - dc := makeDependCatagories() - seen := make(stringSet) - - dc.Bases = getBases(dt.Aur) - - for _, pkg := range pkgs { - dep, alpmpkg := repoFindProvider(pkg, dt) - if alpmpkg != nil { - repoDepCatagoriesRecursive(alpmpkg, dc, dt, false) - dc.Repo = append(dc.Repo, alpmpkg) - delete(dt.Repo, dep) - } - - dep, aurpkg := aurFindProvider(pkg, dt) - if aurpkg != nil { - depCatagoriesRecursive(aurpkg, dc, dt, false, seen) - if !seen.get(aurpkg.PackageBase) { - dc.Aur = append(dc.Aur, aurpkg) - seen.set(aurpkg.PackageBase) - } - - delete(dt.Aur, dep) - } - } - - for _, base := range dc.Bases { - for _, pkg := range base { - for _, dep := range pkg.Depends { - dc.MakeOnly.remove(dep) - } - } - } - - for _, pkg := range dc.Repo { - pkg.Depends().ForEach(func(_dep alpm.Depend) error { - dep := _dep.Name - dc.MakeOnly.remove(dep) - - return nil - }) - } - - for _, pkg := range pkgs { - dc.MakeOnly.remove(pkg) - } - - dupes := make(map[*alpm.Package]struct{}) - filteredRepo := make([]*alpm.Package, 0) - - for _, pkg := range dc.Repo { - _, ok := dupes[pkg] - if ok { - continue - } - dupes[pkg] = struct{}{} - filteredRepo = append(filteredRepo, pkg) - } - - dc.Repo = filteredRepo - - return dc, nil -} - -func repoDepCatagoriesRecursive(pkg *alpm.Package, dc *depCatagories, dt *depTree, isMake bool) { - pkg.Depends().ForEach(func(_dep alpm.Depend) error { - dep, alpmpkg := repoFindProvider(_dep.Name, dt) - if alpmpkg != nil { - delete(dt.Repo, dep) - repoDepCatagoriesRecursive(alpmpkg, dc, dt, isMake) - - if isMake { - dc.MakeOnly.set(alpmpkg.Name()) - } - - dc.Repo = append(dc.Repo, alpmpkg) - } - - return nil - }) -} - -func depCatagoriesRecursive(_pkg *rpc.Pkg, dc *depCatagories, dt *depTree, isMake bool, seen stringSet) { - for _, pkg := range dc.Bases[_pkg.PackageBase] { - for _, deps := range [3][]string{pkg.Depends, pkg.MakeDepends, pkg.CheckDepends} { - for _, pkg := range deps { - dep, aurpkg := aurFindProvider(pkg, dt) - if aurpkg != nil { - delete(dt.Aur, dep) - depCatagoriesRecursive(aurpkg, dc, dt, isMake, seen) - - if !seen.get(aurpkg.PackageBase) { - dc.Aur = append(dc.Aur, aurpkg) - seen.set(aurpkg.PackageBase) - } - - if isMake { - dc.MakeOnly.set(aurpkg.Name) - } - } - - dep, alpmpkg := repoFindProvider(pkg, dt) - if alpmpkg != nil { - delete(dt.Repo, dep) - repoDepCatagoriesRecursive(alpmpkg, dc, dt, isMake) - - if isMake { - dc.MakeOnly.set(alpmpkg.Name()) - } - - dc.Repo = append(dc.Repo, alpmpkg) - } - - } - isMake = true - } - } -} - -// This is step one for dependency resolving. pkgs is a slice of the packages you -// want to resolve the dependencies for. They can be a mix of aur and repo -// dependencies. All unmet dependencies will be resolved. -// -// For Aur dependencies depends, makedepends and checkdepends are resolved but -// for repo packages only depends are resolved as they are prebuilt. -// The return will be split into three categories: Repo, Aur and Missing. -// The return is in no way ordered. This step is is just aimed at gathering the -// packages we need. -// -// This has been designed to make the least amount of rpc requests as possible. -// Web requests are probably going to be the bottleneck here so minimizing them -// provides a nice speed boost. -// -// Here is a visual expample of the request system. -// Remember only unsatisfied packages are requested, if a package is already -// installed we don't bother. -// -// a -// / \ -// b c -// / \ -// d e -// -// We see a so we send a request for a -// We see a wants b and c so we send a request for b and c -// We see d and e so we send a request for d and e -// -// That's 5 packages in 3 requests. The amount of requests needed should always be -// the same as the height of the tree. -// The example does not really do this justice, In the real world where packages -// have 10+ dependencies each this is a very nice optimization. -func getDepTree(pkgs []string, warnings *aurWarnings) (*depTree, error) { - dt := makeDepTree() - dt.Warnings = warnings - - localDb, err := alpmHandle.LocalDb() - if err != nil { - return dt, err - } - syncDb, err := alpmHandle.SyncDbs() - if err != nil { - return dt, err - } - - for _, pkg := range pkgs { - db, name := splitDbFromName(pkg) - var foundPkg *alpm.Package - var singleDb *alpm.Db - - if db == "aur" { - dt.ToProcess.set(name) - continue - } - - // Check the repos for a matching dep - if db != "" { - singleDb, err = alpmHandle.SyncDbByName(db) - if err != nil { - return dt, err - } - foundPkg, err = singleDb.PkgCache().FindSatisfier(name) - } else { - foundPkg, err = syncDb.FindSatisfier(name) - } - - if err == nil { - repoTreeRecursive(foundPkg, dt, localDb, syncDb) - continue - } else { - //would be better to check the groups from singleDb if - //the user specified a db but there's no easy way to do - //it without making alpm_lists so don't bother for now - //db/group is probably a rare use case - _, err := syncDb.PkgCachebyGroup(name) - - if err == nil { - dt.Groups.set(pkg) - continue - } - } - - if db == "" { - dt.ToProcess.set(name) - } else { - dt.Missing.set(pkg) - } - } - - if len(dt.ToProcess) > 0 { - fmt.Println(bold(cyan("::") + bold(" Querying AUR..."))) - } - - err = depTreeRecursive(dt, localDb, syncDb, false) - if err != nil { - return dt, err - } - - if !cmdArgs.existsArg("d", "nodeps") { - err = checkVersions(dt) - } - - dt.Warnings.print() - - return dt, err -} - -// Takes a repo package, -// gives all of the non installed deps, -// repeats on each sub dep. -func repoTreeRecursive(pkg *alpm.Package, dt *depTree, localDb *alpm.Db, syncDb alpm.DbList) (err error) { - _, exists := dt.Repo[pkg.Name()] - if exists { - return - } - - _, exists = dt.Provides[pkg.Name()] - if exists { - return - } - - dt.Repo[pkg.Name()] = pkg - (*pkg).Provides().ForEach(func(dep alpm.Depend) (err error) { - dt.Provides[dep.Name] = pkg.Name() - return nil - }) - - (*pkg).Depends().ForEach(func(dep alpm.Depend) (err error) { - _, exists := dt.Repo[dep.Name] - if exists { - return - } - - _, isInstalled := localDb.PkgCache().FindSatisfier(dep.String()) - if isInstalled == nil { - return - } - - repoPkg, inRepos := syncDb.FindSatisfier(dep.String()) - if inRepos == nil { - repoTreeRecursive(repoPkg, dt, localDb, syncDb) - return - } - - dt.Missing.set(dep.String()) - - return - }) - - return -} - -func depTreeRecursive(dt *depTree, localDb *alpm.Db, syncDb alpm.DbList, isMake bool) (err error) { - if len(dt.ToProcess) == 0 { - return - } - - nextProcess := make(stringSet) - currentProcess := make(stringSet) - // Strip version conditions - for _dep := range dt.ToProcess { - dep, _ := splitNameFromDep(_dep) - currentProcess.set(dep) - } - - // Assume toprocess only contains aur stuff we have not seen - info, err := aurInfo(currentProcess.toSlice(), dt.Warnings) - - if err != nil { - return - } - - // Cache the results - for _, pkg := range info { - dt.Aur[pkg.Name] = pkg - - for _, provide := range pkg.Provides { - name, _ := splitNameFromDep(provide) - dt.Provides[name] = pkg.Name - } - } - - // Loop through to process and check if we now have - // each packaged cached. - // If not cached, we assume it is missing. - for pkgName := range currentProcess { - pkg, exists := dt.Aur[pkgName] - - // Did not get it in the request. - if !exists { - dt.Missing.set(pkgName) - continue - } - - // for each dep and makedep - for _, deps := range [3][]string{pkg.Depends, pkg.MakeDepends, pkg.CheckDepends} { - for _, versionedDep := range deps { - dep, _ := splitNameFromDep(versionedDep) - - _, exists = dt.Aur[dep] - // We have it cached so skip. - if exists { - continue - } - - _, exists = dt.Provides[dep] - // We have it cached so skip. - if exists { - continue - } - - _, exists = dt.Repo[dep] - // We have it cached so skip. - if exists { - continue - } - - _, exists = dt.Missing[dep] - // We know it does not resolve so skip. - if exists { - continue - } - - // Check if already installed. - _, isInstalled := localDb.PkgCache().FindSatisfier(versionedDep) - if isInstalled == nil && config.ReBuild != "tree" { - continue - } - - // Check the repos for a matching dep. - repoPkg, inRepos := syncDb.FindSatisfier(versionedDep) - if inRepos == nil { - if isInstalled == nil && config.ReBuild == "tree" { - continue - } - - repoTreeRecursive(repoPkg, dt, localDb, syncDb) - continue - } - - // If all else fails add it to next search. - nextProcess.set(versionedDep) - } - } - } - - dt.ToProcess = nextProcess - depTreeRecursive(dt, localDb, syncDb, true) - - return -} - -func checkVersions(dt *depTree) error { - has := make(mapStringSlice) - allDeps := make([]*gopkg.Dependency, 0) - - localDb, err := alpmHandle.LocalDb() - if err != nil { - return err - } - - for _, pkg := range dt.Aur { - for _, deps := range [3][]string{pkg.Depends, pkg.MakeDepends, pkg.CheckDepends} { - for _, dep := range deps { - _, _dep := splitNameFromDep(dep) - if _dep != "" { - deps, _ := gopkg.ParseDeps([]string{dep}) - if deps[0] != nil { - allDeps = append(allDeps, deps[0]) - } - } - } - } - - has.Add(pkg.Name, pkg.Version) - - if !isDevelName(pkg.Name) { - for _, name := range pkg.Provides { - _name, _ver := splitNameFromDep(name) - if _ver != "" { - has.Add(_name, _ver) - } else { - delete(has, _name) - } - } - } - } - - for _, pkg := range dt.Repo { - pkg.Depends().ForEach(func(dep alpm.Depend) error { - if dep.Mod != alpm.DepModAny { - deps, _ := gopkg.ParseDeps([]string{dep.String()}) - if deps[0] != nil { - allDeps = append(allDeps, deps[0]) - } - } - return nil - }) - - has.Add(pkg.Name(), pkg.Version()) - - pkg.Provides().ForEach(func(dep alpm.Depend) error { - if dep.Mod != alpm.DepModAny { - has.Add(dep.Name, dep.Version) - } else { - delete(has, dep.Name) - } - - return nil - }) - - } - - localDb.PkgCache().ForEach(func(pkg alpm.Package) error { - pkg.Provides().ForEach(func(dep alpm.Depend) error { - if dep.Mod != alpm.DepModAny { - has.Add(dep.Name, dep.Version) - } else { - delete(has, dep.Name) - } - - return nil - }) - - return nil - }) - - for _, dep := range allDeps { - satisfied := false - verStrs, ok := has[dep.Name] - if !ok { - continue - } - - for _, verStr := range verStrs { - version, err := gopkg.NewCompleteVersion(verStr) - if err != nil { - return err - } - - if version.Satisfies(dep) { - satisfied = true - break - } - } - - if !satisfied { - dt.Missing.set(dep.String()) - } - } - - return nil -}