diff --git a/dep.go b/dep.go index d37aee44..b3fae560 100644 --- a/dep.go +++ b/dep.go @@ -8,11 +8,6 @@ import ( rpc "github.com/mikkeloscar/aur" ) -type missing struct { - Good stringSet - Missing map[string][][]string -} - type providers struct { lookfor string Pkgs []*rpc.Pkg @@ -45,74 +40,6 @@ func (q providers) Swap(i, j int) { q.Pkgs[i], q.Pkgs[j] = q.Pkgs[j], q.Pkgs[i] } -type Base []*rpc.Pkg - -func (b Base) Pkgbase() string { - return b[0].PackageBase -} - -func (b Base) Version() string { - return b[0].Version -} - -func (b Base) URLPath() string { - return b[0].URLPath -} - -func baseAppend(bases []Base, pkg *rpc.Pkg) []Base { - for i, base := range bases { - if base.Pkgbase() == pkg.PackageBase { - bases[i] = append(bases[i], pkg) - return bases - } - } - - return append(bases, Base{pkg}) -} - -func baseFind(bases []Base, name string) *rpc.Pkg { - for _, base := range bases { - for _, pkg := range base { - if pkg.Name == name { - return pkg - } - } - } - - return nil -} - -type target struct { - Db string - Name string - Mod string - Version string -} - -func toTarget(pkg string) target { - db, dep := splitDbFromName(pkg) - name, mod, version := splitDep(dep) - - return target{ - db, - name, - mod, - version, - } -} - -func (t target) DepString() string { - return t.Name + t.Mod + t.Version -} - -func (t target) String() string { - if t.Db != "" { - return t.Db + "/" + t.DepString() - } - - return t.DepString() -} - func splitDep(dep string) (string, string, string) { mod := "" diff --git a/depCheck.go b/depCheck.go index 08548a81..96d41b75 100644 --- a/depCheck.go +++ b/depCheck.go @@ -7,105 +7,41 @@ import ( "sync" alpm "github.com/jguer/go-alpm" - rpc "github.com/mikkeloscar/aur" ) -func (ds *depSolver) _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 := ds.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 := ds.LocalDb.PkgCache().FindSatisfier(aurDep); err == nil { - missing.Good.set(aurDep) - continue - } - - ds._checkMissing(aurDep, append(stack, aurPkg.Name), missing) - } +func (dp *depPool) checkInnerConflict(name string, conflict string, conflicts mapStringSet) { + for _, pkg := range dp.Aur { + if pkg.Name == name { + continue } - return + if satisfiesAur(conflict, pkg) { + conflicts.Add(name, pkg.Name) + } } - repoPkg := ds.findSatisfierRepo(dep) - if repoPkg != nil { - missing.Good.set(dep) - repoPkg.Depends().ForEach(func(repoDep alpm.Depend) error { - if _, err := ds.LocalDb.PkgCache().FindSatisfier(repoDep.String()); err == nil { - missing.Good.set(repoDep.String()) - return nil - } + for _, pkg := range dp.Repo { + if pkg.Name() == name { + continue + } - ds._checkMissing(repoDep.String(), append(stack, repoPkg.Name()), missing) - return nil - }) - - return + if satisfiesRepo(conflict, pkg) { + conflicts.Add(name, pkg.Name()) + } } - - missing.Missing[dep] = [][]string{stack} } -func (ds *depSolver) CheckMissing() error { - missing := &missing{ - make(stringSet), - make(map[string][][]string), - } - - for _, target := range ds.Targets { - ds._checkMissing(target.DepString(), make([]string, 0), missing) - } - - if len(missing.Missing) == 0 { - return nil - } - - fmt.Fprintln(os.Stderr, bold(red(arrow+" Error: "))+"Could not find all required packages:") - for dep, trees := range missing.Missing { - for _, tree := range trees { - - fmt.Fprint(os.Stderr, " ", cyan(dep)) - - if len(tree) == 0 { - fmt.Fprint(os.Stderr, " (Target") - } else { - fmt.Fprint(os.Stderr, " (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("") -} - -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()) { +func (dp *depPool) checkForwardConflict(name string, conflict string, conflicts 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) } @@ -113,55 +49,74 @@ func (ds *depSolver) checkForwardConflict(name string, conflict string, conflict }) } -func (ds *depSolver) checkReverseConflict(name string, conflict string, conflicts mapStringSet) { - for _, base := range ds.Aur { - for _, pkg := range base { - if pkg.Name == name { - continue +func (dp *depPool) checkReverseConflict(name string, conflict string, conflicts mapStringSet) { + for _, pkg := range dp.Aur { + if pkg.Name == name { + continue + } + + if satisfiesAur(conflict, pkg) { + if name != conflict { + name += " (" + conflict + ")" } - if satisfiesAur(conflict, pkg) { - conflicts.Add(pkg.Name, name) - } + conflicts.Add(pkg.Name, name) } } - for _, pkg := range ds.Repo { + 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 (ds *depSolver) checkForwardConflicts(conflicts mapStringSet) { - for _, base := range ds.Aur { - for _, pkg := range base { - for _, conflict := range pkg.Conflicts { - ds.checkForwardConflict(pkg.Name, conflict, conflicts) - } +func (dp *depPool) checkInnerConflicts(conflicts mapStringSet) { + for _, pkg := range dp.Aur { + for _, conflict := range pkg.Conflicts { + dp.checkInnerConflict(pkg.Name, conflict, conflicts) } } - for _, pkg := range ds.Repo { + for _, pkg := range dp.Repo { pkg.Conflicts().ForEach(func(conflict alpm.Depend) error { - ds.checkForwardConflict(pkg.Name(), conflict.String(), conflicts) + dp.checkInnerConflict(pkg.Name(), conflict.String(), conflicts) return nil }) } } -func (ds *depSolver) checkReverseConflicts(conflicts mapStringSet) { - ds.LocalDb.PkgCache().ForEach(func(pkg alpm.Package) error { - if ds.hasPackage(pkg.Name()) { +func (dp *depPool) checkForwardConflicts(conflicts 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 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 { - ds.checkReverseConflict(pkg.Name(), conflict.String(), conflicts) + dp.checkReverseConflict(pkg.Name(), conflict.String(), conflicts) return nil }) @@ -169,147 +124,66 @@ 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) { +func (dp *depPool) CheckConflicts() (mapStringSet, error) { var wg sync.WaitGroup innerConflicts := make(mapStringSet) conflicts := make(mapStringSet) - repoConflicts := make(mapStringSet) - wg.Add(3) + wg.Add(2) fmt.Println(bold(cyan("::") + bold(" Checking for conflicts..."))) go func() { - ds.checkForwardConflicts(conflicts) - ds.checkReverseConflicts(conflicts) + dp.checkForwardConflicts(conflicts) + dp.checkReverseConflicts(conflicts) wg.Done() }() fmt.Println(bold(cyan("::") + bold(" Checking for inner conflicts..."))) go func() { - ds.checkInnerConflicts(innerConflicts) - wg.Done() - }() - go func() { - ds.checkInnerRepoConflicts(repoConflicts) + dp.checkInnerConflicts(innerConflicts) wg.Done() }() wg.Wait() - formatConflicts := func(conflicts mapStringSet, inner bool, s string) { - if len(conflicts) != 0 { - fmt.Fprintln(os.Stderr) - if inner { - fmt.Fprintln(os.Stderr, bold(red(arrow)), bold("Inner conflicts found:")) - } else { - fmt.Fprintln(os.Stderr, bold(red(arrow)), bold("Package conflicts found:")) - } + if len(innerConflicts) != 0 { + fmt.Println() + fmt.Println(bold(red(arrow)), bold("Inner conflicts found:")) - printConflict := func(name string, pkgs stringSet) { - str := fmt.Sprintf(s, cyan(name)) - for pkg := range pkgs { - str += " " + cyan(pkg) + "," - } - str = strings.TrimSuffix(str, ",") + for name, pkgs := range innerConflicts { + str := red(bold(smallArrow)) + " " + name + ":" + for pkg := range pkgs { + str += " " + cyan(pkg) + "," + } + str = strings.TrimSuffix(str, ",") - fmt.Fprintln(os.Stderr, str) - } - - for _, pkg := range ds.Repo { - if pkgs, ok := conflicts[pkg.Name()]; ok { - printConflict(pkg.Name(), pkgs) - } - } - for _, base := range ds.Aur { - for _, pkg := range base { - if pkgs, ok := conflicts[pkg.Name]; ok { - printConflict(pkg.Name, pkgs) - } - } - } + fmt.Println(str) } + } - repoStr := red(bold(smallArrow)) + " %s Conflicts with:" - formatConflicts(repoConflicts, true, repoStr) + 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) + "," + } + str = strings.TrimSuffix(str, ",") + + fmt.Println(str) + } - if len(repoConflicts) > 0 { - return nil, fmt.Errorf("Unavoidable conflicts, aborting") } - 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) + // 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) } } @@ -327,3 +201,96 @@ func (ds *depSolver) CheckConflicts() (mapStringSet, error) { return conflicts, nil } + +type missing struct { + Good 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), + make(map[string][][]string), + } + + for _, target := range dp.Targets { + dp._checkMissing(target.DepString(), make([]string, 0), missing) + } + + if len(missing.Missing) == 0 { + return nil + } + + fmt.Println(bold(red(arrow+" Error: ")) + "Could not find all required packages:") + for dep, trees := range missing.Missing { + for _, tree := range trees { + + fmt.Print(" ", cyan(dep)) + + if len(tree) == 0 { + fmt.Print(" (Target") + } else { + fmt.Print(" (Wanted by: ") + for n := 0; n < len(tree)-1; n++ { + fmt.Print(cyan(tree[n]), " -> ") + } + fmt.Print(cyan(tree[len(tree)-1])) + } + + fmt.Println(")") + } + } + + return fmt.Errorf("") +} diff --git a/depOrder.go b/depOrder.go new file mode 100644 index 00000000..e2d3f9a1 --- /dev/null +++ b/depOrder.go @@ -0,0 +1,135 @@ +package main + +import ( + alpm "github.com/jguer/go-alpm" + rpc "github.com/mikkeloscar/aur" +) + +type Base []*rpc.Pkg + +func (b Base) Pkgbase() string { + return b[0].PackageBase +} + +func (b Base) Version() string { + return b[0].Version +} + +func (b Base) URLPath() string { + return b[0].URLPath +} + +type depOrder struct { + Aur []Base + Repo []*alpm.Package + Runtime stringSet +} + +func makeDepOrder() *depOrder { + return &depOrder{ + make([]Base, 0), + make([]*alpm.Package, 0), + make(stringSet), + } +} + +func getDepOrder(dp *depPool) *depOrder { + do := makeDepOrder() + + for _, target := range dp.Targets { + dep := target.DepString() + aurPkg := dp.Aur[dep] + if aurPkg != nil && pkgSatisfies(aurPkg.Name, aurPkg.Version, dep) { + do.orderPkgAur(aurPkg, dp, true) + } + + aurPkg = dp.findSatisfierAur(dep) + if aurPkg != nil { + do.orderPkgAur(aurPkg, dp, true) + } + + repoPkg := dp.findSatisfierRepo(dep) + if repoPkg != nil { + do.orderPkgRepo(repoPkg, dp, true) + } + } + + return do +} + +func (do *depOrder) orderPkgAur(pkg *rpc.Pkg, dp *depPool, runtime bool) { + if runtime { + do.Runtime.set(pkg.Name) + } + delete(dp.Aur, pkg.Name) + + for i, deps := range [3][]string{pkg.Depends, pkg.MakeDepends, pkg.CheckDepends} { + for _, dep := range deps { + aurPkg := dp.findSatisfierAur(dep) + if aurPkg != nil { + do.orderPkgAur(aurPkg, dp, runtime && i == 0) + } + + repoPkg := dp.findSatisfierRepo(dep) + if repoPkg != nil { + do.orderPkgRepo(repoPkg, dp, runtime && i == 0) + } + } + } + + for i, base := range do.Aur { + if base.Pkgbase() == pkg.PackageBase { + do.Aur[i] = append(base, pkg) + return + } + } + + do.Aur = append(do.Aur, Base{pkg}) +} + +func (do *depOrder) orderPkgRepo(pkg *alpm.Package, dp *depPool, runtime bool) { + if runtime { + do.Runtime.set(pkg.Name()) + } + delete(dp.Repo, pkg.Name()) + + pkg.Depends().ForEach(func(dep alpm.Depend) (err error) { + repoPkg := dp.findSatisfierRepo(dep.String()) + if repoPkg != nil { + do.orderPkgRepo(repoPkg, dp, runtime) + } + + return nil + }) + + do.Repo = append(do.Repo, pkg) +} + +func (do *depOrder) HasMake() bool { + lenAur := 0 + for _, base := range do.Aur { + lenAur += len(base) + } + + return len(do.Runtime) != lenAur+len(do.Repo) +} + +func (do *depOrder) getMake() []string { + makeOnly := make([]string, 0, len(do.Aur)+len(do.Repo)-len(do.Runtime)) + + for _, base := range do.Aur { + for _, pkg := range base { + if !do.Runtime.get(pkg.Name) { + makeOnly = append(makeOnly, pkg.Name) + } + } + } + + for _, pkg := range do.Repo { + if !do.Runtime.get(pkg.Name()) { + makeOnly = append(makeOnly, pkg.Name()) + } + } + + return makeOnly +} diff --git a/depPool.go b/depPool.go new file mode 100644 index 00000000..5c614959 --- /dev/null +++ b/depPool.go @@ -0,0 +1,477 @@ +package main + +import ( + "sort" + "strings" + "sync" + + alpm "github.com/jguer/go-alpm" + rpc "github.com/mikkeloscar/aur" +) + +type target struct { + Db string + Name string + Mod string + Version string +} + +func toTarget(pkg string) target { + db, dep := splitDbFromName(pkg) + name, mod, version := splitDep(dep) + + return target{ + db, + name, + mod, + version, + } +} + +func (t target) DepString() string { + return t.Name + t.Mod + t.Version +} + +func (t target) String() string { + if t.Db != "" { + return t.Db + "/" + t.DepString() + } + + return t.DepString() +} + +type depPool struct { + Targets []target + Explicit stringSet + Repo map[string]*alpm.Package + Aur map[string]*rpc.Pkg + AurCache map[string]*rpc.Pkg + Groups []string + LocalDb *alpm.Db + SyncDb alpm.DbList + Warnings *aurWarnings +} + +func makeDepPool() (*depPool, error) { + localDb, err := alpmHandle.LocalDb() + if err != nil { + return nil, err + } + syncDb, err := alpmHandle.SyncDbs() + if err != nil { + return nil, err + } + + dp := &depPool{ + make([]target, 0), + make(stringSet), + make(map[string]*alpm.Package), + make(map[string]*rpc.Pkg), + make(map[string]*rpc.Pkg), + make([]string, 0), + localDb, + syncDb, + nil, + } + + return dp, nil +} + +// Includes db/ prefixes and group installs +func (dp *depPool) ResolveTargets(pkgs []string) error { + // RPC requests are slow + // Combine as many AUR package requests as possible into a single RPC + // call + aurTargets := make(stringSet) + + pkgs = removeInvalidTargets(pkgs) + + for _, pkg := range pkgs { + var err error + target := toTarget(pkg) + + // skip targets already satisfied + // even if the user enters db/pkg and aur/pkg the latter will + // still get skipped even if it's from a different database to + // the one specified + // this is how pacman behaves + if dp.hasPackage(target.DepString()) { + continue + } + + var foundPkg *alpm.Package + var singleDb *alpm.Db + + // aur/ prefix means we only check the aur + if target.Db == "aur" || mode == modeAUR { + dp.Targets = append(dp.Targets, target) + aurTargets.set(target.DepString()) + continue + } + + // If there'ss a different priefix only look in that repo + if target.Db != "" { + singleDb, err = alpmHandle.SyncDbByName(target.Db) + if err != nil { + return err + } + foundPkg, err = singleDb.PkgCache().FindSatisfier(target.DepString()) + //otherwise find it in any repo + } else { + foundPkg, err = dp.SyncDb.FindSatisfier(target.DepString()) + } + + if err == nil { + dp.Targets = append(dp.Targets, target) + dp.Explicit.set(foundPkg.Name()) + dp.ResolveRepoDependency(foundPkg) + continue + } else { + //check for groups + //currently we don't resolve the packages in a group + //only check if the group exists + //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 + group, err := dp.SyncDb.PkgCachebyGroup(target.Name) + if err == nil { + dp.Groups = append(dp.Groups, target.String()) + group.ForEach(func(pkg alpm.Package) error { + dp.Explicit.set(pkg.Name()) + return nil + }) + continue + } + } + + //if there was no db prefix check the aur + if target.Db == "" { + aurTargets.set(target.DepString()) + } + + dp.Targets = append(dp.Targets, target) + } + + if len(aurTargets) > 0 && (mode == modeAny || mode == modeAUR) { + return dp.resolveAURPackages(aurTargets, true) + } + + return nil +} + +// Pseudo provides finder. +// Try to find provides by performing a search of the package name +// This effectively performs -Ss on each package +// then runs -Si on each result to cache the information. +// +// For example if you were to -S yay then yay -Ss would give: +// yay-git yay-bin yay realyog pacui pacui-git ruby-yard +// These packages will all be added to the cache in case they are needed later +// Ofcouse only the first three packages provide yay, the rest are just false +// positives. +// +// This method increases dependency resolve time +func (dp *depPool) findProvides(pkgs stringSet) error { + var mux sync.Mutex + var wg sync.WaitGroup + + doSearch := func(pkg string) { + defer wg.Done() + var err error + var results []rpc.Pkg + + // Hack for a bigger search result, if the user wants + // java-envronment we can search for just java instead and get + // more hits. + words := strings.Split(pkg, "-") + + for i := range words { + results, err = rpc.SearchByNameDesc(strings.Join(words[:i+1], "-")) + if err == nil { + break + } + } + + if err != nil { + return + } + + for _, result := range results { + mux.Lock() + if _, ok := dp.AurCache[result.Name]; !ok { + pkgs.set(result.Name) + } + mux.Unlock() + } + } + + for pkg := range pkgs { + if _, err := dp.LocalDb.PkgByName(pkg); err == nil { + continue + } + wg.Add(1) + go doSearch(pkg) + } + + wg.Wait() + + return nil +} + +func (dp *depPool) cacheAURPackages(_pkgs stringSet) error { + pkgs := _pkgs.copy() + query := make([]string, 0) + + for pkg := range pkgs { + if _, ok := dp.AurCache[pkg]; ok { + pkgs.remove(pkg) + } + } + + if len(pkgs) == 0 { + return nil + } + + if config.Provides { + err := dp.findProvides(pkgs) + if err != nil { + return err + } + } + + for pkg := range pkgs { + if _, ok := dp.AurCache[pkg]; !ok { + name, _, _ := splitDep(pkg) + query = append(query, name) + } + } + + info, err := aurInfo(query, dp.Warnings) + if err != nil { + return err + } + + for _, pkg := range info { + // Dump everything in cache just in case we need it later + dp.AurCache[pkg.Name] = pkg + } + + return nil +} + +func (dp *depPool) resolveAURPackages(pkgs stringSet, explicit bool) error { + newPackages := make(stringSet) + newAURPackages := make(stringSet) + + err := dp.cacheAURPackages(pkgs) + if err != nil { + return err + } + + if len(pkgs) == 0 { + return nil + } + + for name := range pkgs { + _, ok := dp.Aur[name] + if ok { + continue + } + + pkg := dp.findSatisfierAurCache(name) + if pkg == nil { + continue + } + + if explicit { + dp.Explicit.set(pkg.Name) + } + dp.Aur[pkg.Name] = pkg + + for _, deps := range [3][]string{pkg.Depends, pkg.MakeDepends, pkg.CheckDepends} { + for _, dep := range deps { + newPackages.set(dep) + } + } + } + + for dep := range newPackages { + if dp.hasSatisfier(dep) { + continue + } + + _, isInstalled := dp.LocalDb.PkgCache().FindSatisfier(dep) //has satisfier installed: skip + hm := hideMenus + hideMenus = isInstalled == nil + repoPkg, inRepos := dp.SyncDb.FindSatisfier(dep) //has satisfier in repo: fetch it + hideMenus = hm + if isInstalled == nil && (config.ReBuild != "tree" || inRepos == nil) { + continue + } + + if inRepos == nil { + dp.ResolveRepoDependency(repoPkg) + continue + } + + //assume it's in the aur + //ditch the versioning because the RPC can't handle it + newAURPackages.set(dep) + + } + + err = dp.resolveAURPackages(newAURPackages, false) + return err +} + +func (dp *depPool) ResolveRepoDependency(pkg *alpm.Package) { + dp.Repo[pkg.Name()] = pkg + + pkg.Depends().ForEach(func(dep alpm.Depend) (err error) { + //have satisfier in dep tree: skip + if dp.hasSatisfier(dep.String()) { + return + } + + //has satisfier installed: skip + _, isInstalled := dp.LocalDb.PkgCache().FindSatisfier(dep.String()) + if isInstalled == nil { + return + } + + //has satisfier in repo: fetch it + repoPkg, inRepos := dp.SyncDb.FindSatisfier(dep.String()) + if inRepos != nil { + return + } + + dp.ResolveRepoDependency(repoPkg) + + return nil + }) +} + +func getDepPool(pkgs []string, warnings *aurWarnings) (*depPool, error) { + dp, err := makeDepPool() + if err != nil { + return nil, err + } + + dp.Warnings = warnings + err = dp.ResolveTargets(pkgs) + + return dp, err +} + +func (dp *depPool) findSatisfierAur(dep string) *rpc.Pkg { + for _, pkg := range dp.Aur { + if satisfiesAur(dep, pkg) { + return pkg + } + } + + return nil +} + +// This is mostly used to promote packages from the cache +// to the Install list +// Provide a pacman style provider menu if there's more than one candidate +// This acts slightly differently from Pacman, It will give +// a menu even if a package with a matching name exists. I believe this +// method is better because most of the time you are choosing between +// foo and foo-git. +// Using Pacman's ways trying to install foo would never give you +// a menu. +// TODO: maybe intermix repo providers in the menu +func (dp *depPool) findSatisfierAurCache(dep string) *rpc.Pkg { + depName, _, _ := splitDep(dep) + seen := make(stringSet) + providers := makeProviders(depName) + + if _, err := dp.LocalDb.PkgByName(depName); err == nil { + if pkg, ok := dp.AurCache[dep]; ok && pkgSatisfies(pkg.Name, pkg.Version, dep) { + return pkg + } + + } + + if cmdArgs.op == "Y" || cmdArgs.op == "yay" { + for _, pkg := range dp.AurCache { + if pkgSatisfies(pkg.Name, pkg.Version, dep) { + for _, target := range dp.Targets { + if target.Name == pkg.Name { + return pkg + } + } + } + } + } + + for _, pkg := range dp.AurCache { + if seen.get(pkg.Name) { + continue + } + + if pkgSatisfies(pkg.Name, pkg.Version, dep) { + providers.Pkgs = append(providers.Pkgs, pkg) + seen.set(pkg.Name) + continue + } + + for _, provide := range pkg.Provides { + if provideSatisfies(provide, dep) { + providers.Pkgs = append(providers.Pkgs, pkg) + seen.set(pkg.Name) + continue + } + } + } + + if providers.Len() == 1 { + return providers.Pkgs[0] + } + + if providers.Len() > 1 { + sort.Sort(providers) + return providerMenu(dep, providers) + } + + return nil +} + +func (dp *depPool) findSatisfierRepo(dep string) *alpm.Package { + for _, pkg := range dp.Repo { + if satisfiesRepo(dep, pkg) { + return pkg + } + } + + return nil +} + +func (dp *depPool) hasSatisfier(dep string) bool { + return dp.findSatisfierRepo(dep) != nil || dp.findSatisfierAur(dep) != nil +} + +func (dp *depPool) hasPackage(name string) bool { + for _, pkg := range dp.Repo { + if pkg.Name() == name { + return true + } + } + + for _, pkg := range dp.Aur { + if pkg.Name == name { + return true + } + } + + for _, pkg := range dp.Groups { + if pkg == name { + return true + } + } + + return false +} diff --git a/depSolver.go b/depSolver.go deleted file mode 100644 index ecb9fd48..00000000 --- a/depSolver.go +++ /dev/null @@ -1,631 +0,0 @@ -package main - -import ( - "sort" - "strings" - "sync" - - alpm "github.com/jguer/go-alpm" - rpc "github.com/mikkeloscar/aur" -) - -type depSolver struct { - Aur []Base - Repo []*alpm.Package - Runtime stringSet - Targets []target - Explicit stringSet - AurCache map[string]*rpc.Pkg - Groups []string - LocalDb *alpm.Db - SyncDb alpm.DbList - Seen stringSet - Warnings *aurWarnings -} - -func makeDepSolver() (*depSolver, error) { - localDb, err := alpmHandle.LocalDb() - if err != nil { - return nil, err - } - syncDb, err := alpmHandle.SyncDbs() - if err != nil { - return nil, err - } - - return &depSolver{ - make([]Base, 0), - make([]*alpm.Package, 0), - make(stringSet), - make([]target, 0), - make(stringSet), - make(map[string]*rpc.Pkg), - make([]string, 0), - localDb, - syncDb, - make(stringSet), - nil, - }, nil -} - -func getDepSolver(pkgs []string, warnings *aurWarnings) (*depSolver, error) { - ds, err := makeDepSolver() - if err != nil { - return nil, err - } - - ds.Warnings = warnings - err = ds.resolveTargets(pkgs) - if err != nil { - return nil, err - } - - ds.resolveRuntime() - return ds, err -} - -// Includes db/ prefixes and group installs -func (ds *depSolver) resolveTargets(pkgs []string) error { - // RPC requests are slow - // Combine as many AUR package requests as possible into a single RPC - // call - aurTargets := make([]string, 0) - pkgs = removeInvalidTargets(pkgs) - - for _, pkg := range pkgs { - var err error - target := toTarget(pkg) - - // skip targets already satisfied - // even if the user enters db/pkg and aur/pkg the latter will - // still get skipped even if it's from a different database to - // the one specified - // this is how pacman behaves - if ds.hasPackage(target.DepString()) { - continue - } - - var foundPkg *alpm.Package - var singleDb *alpm.Db - - // aur/ prefix means we only check the aur - if target.Db == "aur" || mode == modeAUR { - ds.Targets = append(ds.Targets, target) - aurTargets = append(aurTargets, target.DepString()) - continue - } - - // If there'ss a different priefix only look in that repo - if target.Db != "" { - singleDb, err = alpmHandle.SyncDbByName(target.Db) - if err != nil { - return err - } - foundPkg, err = singleDb.PkgCache().FindSatisfier(target.DepString()) - //otherwise find it in any repo - } else { - foundPkg, err = ds.SyncDb.FindSatisfier(target.DepString()) - } - - if err == nil { - ds.Targets = append(ds.Targets, target) - ds.Explicit.set(foundPkg.Name()) - ds.ResolveRepoDependency(foundPkg) - continue - } else { - //check for groups - //currently we don't resolve the packages in a group - //only check if the group exists - //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 - group, err := ds.SyncDb.PkgCachebyGroup(target.Name) - if err == nil { - ds.Groups = append(ds.Groups, target.String()) - group.ForEach(func(pkg alpm.Package) error { - ds.Explicit.set(pkg.Name()) - return nil - }) - continue - } - } - - //if there was no db prefix check the aur - if target.Db == "" { - aurTargets = append(aurTargets, target.DepString()) - } - - ds.Targets = append(ds.Targets, target) - } - - if len(aurTargets) > 0 && (mode == modeAny || mode == modeAUR) { - return ds.resolveAURPackages(aurTargets, true) - } - - return nil -} - -func (ds *depSolver) hasPackage(name string) bool { - for _, pkg := range ds.Repo { - if pkg.Name() == name { - return true - } - } - - for _, base := range ds.Aur { - for _, pkg := range base { - if pkg.Name == name { - return true - } - } - } - - for _, pkg := range ds.Groups { - if pkg == name { - return true - } - } - - return false -} - -func (ds *depSolver) findSatisfierAur(dep string) *rpc.Pkg { - for _, base := range ds.Aur { - for _, pkg := range base { - if satisfiesAur(dep, pkg) { - return pkg - } - } - } - - return nil -} - -func (ds *depSolver) findSatisfierRepo(dep string) *alpm.Package { - for _, pkg := range ds.Repo { - if satisfiesRepo(dep, pkg) { - return pkg - } - } - - return nil -} - -func (ds *depSolver) hasSatisfier(dep string) bool { - return ds.findSatisfierRepo(dep) != nil || ds.findSatisfierAur(dep) != nil -} - -func (ds *depSolver) ResolveRepoDependency(pkg *alpm.Package) { - if ds.Seen.get(pkg.Name()) { - return - } - ds.Repo = append(ds.Repo, pkg) - ds.Seen.set(pkg.Name()) - - pkg.Depends().ForEach(func(dep alpm.Depend) (err error) { - //have satisfier in dep tree: skip - if ds.hasSatisfier(dep.String()) { - return - } - - //has satisfier installed: skip - _, isInstalled := ds.LocalDb.PkgCache().FindSatisfier(dep.String()) - if isInstalled == nil { - return - } - - //has satisfier in repo: fetch it - repoPkg, inRepos := ds.SyncDb.FindSatisfier(dep.String()) - if inRepos != nil { - return - } - - ds.ResolveRepoDependency(repoPkg) - return nil - }) -} - -// This is mostly used to promote packages from the cache -// to the Install list -// Provide a pacman style provider menu if there's more than one candidate -// This acts slightly differently from Pacman, It will give -// a menu even if a package with a matching name exists. I believe this -// method is better because most of the time you are choosing between -// foo and foo-git. -// Using Pacman's ways trying to install foo would never give you -// a menu. -// TODO: maybe intermix repo providers in the menu -func (ds *depSolver) findSatisfierAurCache(dep string) *rpc.Pkg { - depName, _, _ := splitDep(dep) - seen := make(stringSet) - providers := makeProviders(depName) - - if _, err := ds.LocalDb.PkgByName(depName); err == nil { - if pkg, ok := ds.AurCache[dep]; ok && pkgSatisfies(pkg.Name, pkg.Version, dep) { - return pkg - } - - } - - if cmdArgs.op == "Y" || cmdArgs.op == "yay" { - for _, pkg := range ds.AurCache { - if pkgSatisfies(pkg.Name, pkg.Version, dep) { - for _, target := range ds.Targets { - if target.Name == pkg.Name { - return pkg - } - } - } - } - } - - for _, pkg := range ds.AurCache { - if seen.get(pkg.Name) { - continue - } - - if pkgSatisfies(pkg.Name, pkg.Version, dep) { - providers.Pkgs = append(providers.Pkgs, pkg) - seen.set(pkg.Name) - continue - } - - for _, provide := range pkg.Provides { - if provideSatisfies(provide, dep) { - providers.Pkgs = append(providers.Pkgs, pkg) - seen.set(pkg.Name) - continue - } - } - } - - if !config.Provides && providers.Len() >= 1 { - return providers.Pkgs[0] - } - - if providers.Len() == 1 { - return providers.Pkgs[0] - } - - if providers.Len() > 1 { - sort.Sort(providers) - return providerMenu(dep, providers) - } - - return nil -} - -func (ds *depSolver) cacheAURPackages(_pkgs []string) error { - pkgs := sliceToStringSet(_pkgs) - query := make([]string, 0) - - for pkg := range pkgs { - if _, ok := ds.AurCache[pkg]; ok { - pkgs.remove(pkg) - } - } - - if len(pkgs) == 0 { - return nil - } - - if config.Provides { - err := ds.findProvides(pkgs) - if err != nil { - return err - } - } - - for pkg := range pkgs { - if _, ok := ds.AurCache[pkg]; !ok { - name, _, _ := splitDep(pkg) - query = append(query, name) - } - } - - info, err := aurInfo(query, ds.Warnings) - if err != nil { - return err - } - - for _, pkg := range info { - // Dump everything in cache just in case we need it later - ds.AurCache[pkg.Name] = pkg - } - - return nil -} - -// Pseudo provides finder. -// Try to find provides by performing a search of the package name -// This effectively performs -Ss on each package -// then runs -Si on each result to cache the information. -// -// For example if you were to -S yay then yay -Ss would give: -// yay-git yay-bin yay realyog pacui pacui-git ruby-yard -// These packages will all be added to the cache in case they are needed later -// Ofcouse only the first three packages provide yay, the rest are just false -// positives. -// -// This method increases dependency resolve time -func (ds *depSolver) findProvides(pkgs stringSet) error { - var mux sync.Mutex - var wg sync.WaitGroup - - doSearch := func(pkg string) { - defer wg.Done() - var err error - var results []rpc.Pkg - - // Hack for a bigger search result, if the user wants - // java-envronment we can search for just java instead and get - // more hits. - words := strings.Split(pkg, "-") - - for i := range words { - results, err = rpc.SearchByNameDesc(strings.Join(words[:i+1], "-")) - if err == nil { - break - } - } - - if err != nil { - return - } - - for _, result := range results { - mux.Lock() - if _, ok := ds.AurCache[result.Name]; !ok { - pkgs.set(result.Name) - } - mux.Unlock() - } - } - - for pkg := range pkgs { - if _, err := ds.LocalDb.PkgByName(pkg); err == nil { - continue - } - wg.Add(1) - go doSearch(pkg) - } - - wg.Wait() - - return nil -} - -func (ds *depSolver) resolveAURPackages(pkgs []string, explicit bool) error { - newPackages := make(stringSet) - newAURPackages := make([]string, 0) - toAdd := make([]*rpc.Pkg, 0) - - if len(pkgs) == 0 { - return nil - } - - err := ds.cacheAURPackages(pkgs) - if err != nil { - return err - } - - for _, name := range pkgs { - if ds.Seen.get(name) { - continue - } - - pkg := ds.findSatisfierAurCache(name) - if pkg == nil { - continue - } - - if explicit { - ds.Explicit.set(pkg.Name) - } - - ds.Seen.set(pkg.Name) - toAdd = append(toAdd, pkg) - - for _, deps := range [3][]string{pkg.Depends, pkg.MakeDepends, pkg.CheckDepends} { - for _, dep := range deps { - newPackages.set(dep) - } - } - } - - for dep := range newPackages { - if ds.hasSatisfier(dep) { - continue - } - - _, isInstalled := ds.LocalDb.PkgCache().FindSatisfier(dep) //has satisfier installed: skip - hm := hideMenus - hideMenus = isInstalled == nil - repoPkg, inRepos := ds.SyncDb.FindSatisfier(dep) //has satisfier in repo: fetch it - hideMenus = hm - if isInstalled == nil && (config.ReBuild != "tree" || inRepos == nil) { - continue - } - - if inRepos == nil { - ds.ResolveRepoDependency(repoPkg) - continue - } - - //assume it's in the aur - //ditch the versioning because the RPC can't handle it - newAURPackages = append(newAURPackages, dep) - - } - - err = ds.resolveAURPackages(newAURPackages, false) - - for _, pkg := range toAdd { - if !ds.hasPackage(pkg.Name) { - ds.Aur = baseAppend(ds.Aur, pkg) - } - } - - return err -} - -func (ds *depSolver) Print() { - repo := "" - repoMake := "" - aur := "" - aurMake := "" - - repoLen := 0 - repoMakeLen := 0 - aurLen := 0 - aurMakeLen := 0 - - for _, pkg := range ds.Repo { - if ds.Runtime.get(pkg.Name()) { - repo += " " + pkg.Name() + "-" + pkg.Version() - repoLen++ - } else { - repoMake += " " + pkg.Name() + "-" + pkg.Version() - repoMakeLen++ - } - } - - for _, base := range ds.Aur { - pkg := base.Pkgbase() - pkgStr := " " + pkg + "-" + base[0].Version - pkgStrMake := pkgStr - - push := false - pushMake := false - - if len(base) > 1 || pkg != base[0].Name { - pkgStr += " (" - pkgStrMake += " (" - - for _, split := range base { - if ds.Runtime.get(split.Name) { - pkgStr += split.Name + " " - aurLen++ - push = true - } else { - pkgStrMake += split.Name + " " - aurMakeLen++ - pushMake = true - } - } - - pkgStr = pkgStr[:len(pkgStr)-1] + ")" - pkgStrMake = pkgStrMake[:len(pkgStrMake)-1] + ")" - } else if ds.Runtime.get(base[0].Name) { - aurLen++ - push = true - } else { - aurMakeLen++ - pushMake = true - } - - if push { - aur += pkgStr - } - if pushMake { - aurMake += pkgStrMake - } - } - - printDownloads("Repo", repoLen, repo) - printDownloads("Repo Make", repoMakeLen, repoMake) - printDownloads("Aur", aurLen, aur) - printDownloads("Aur Make", aurMakeLen, aurMake) -} - -func (ds *depSolver) resolveRuntime() { - for _, pkg := range ds.Repo { - if ds.Explicit.get(pkg.Name()) { - ds.Runtime.set(pkg.Name()) - ds.resolveRuntimeRepo(pkg) - } - } - - for _, base := range ds.Aur { - for _, pkg := range base { - if ds.Explicit.get(pkg.Name) { - ds.Runtime.set(pkg.Name) - ds.resolveRuntimeAur(pkg) - } - } - } -} - -func (ds *depSolver) resolveRuntimeRepo(pkg *alpm.Package) { - pkg.Depends().ForEach(func(dep alpm.Depend) (err error) { - for _, pkg := range ds.Repo { - if ds.Runtime.get(pkg.Name()) { - continue - } - - if satisfiesRepo(dep.String(), pkg) { - ds.Runtime.set(pkg.Name()) - ds.resolveRuntimeRepo(pkg) - } - } - return nil - }) -} - -func (ds *depSolver) resolveRuntimeAur(pkg *rpc.Pkg) { - for _, dep := range pkg.Depends { - for _, pkg := range ds.Repo { - if ds.Runtime.get(pkg.Name()) { - continue - } - - if satisfiesRepo(dep, pkg) { - ds.Runtime.set(pkg.Name()) - ds.resolveRuntimeRepo(pkg) - } - } - - for _, base := range ds.Aur { - for _, pkg := range base { - if ds.Runtime.get(pkg.Name) { - continue - } - - if satisfiesAur(dep, pkg) { - ds.Runtime.set(pkg.Name) - ds.resolveRuntimeAur(pkg) - } - } - } - } -} - -func (ds *depSolver) HasMake() bool { - lenAur := 0 - for _, base := range ds.Aur { - lenAur += len(base) - } - - return len(ds.Runtime) != lenAur+len(ds.Repo) -} - -func (ds *depSolver) getMake() []string { - makeOnly := make([]string, 0, len(ds.Aur)+len(ds.Repo)-len(ds.Runtime)) - - for _, base := range ds.Aur { - for _, pkg := range base { - if !ds.Runtime.get(pkg.Name) { - makeOnly = append(makeOnly, pkg.Name) - } - } - } - - for _, pkg := range ds.Repo { - if !ds.Runtime.get(pkg.Name()) { - makeOnly = append(makeOnly, pkg.Name()) - } - } - - return makeOnly -} diff --git a/install.go b/install.go index 453bd617..57c18940 100644 --- a/install.go +++ b/install.go @@ -17,6 +17,7 @@ import ( func install(parser *arguments) error { var err error var incompatible stringSet + var do *depOrder var aurUp upSlice var repoUp upSlice @@ -109,17 +110,17 @@ func install(parser *arguments) error { targets := sliceToStringSet(parser.targets) - ds, err := getDepSolver(requestTargets, warnings) + dp, err := getDepPool(requestTargets, warnings) if err != nil { return err } - err = ds.CheckMissing() + err = dp.CheckMissing() if err != nil { return err } - if len(ds.Aur) == 0 { + if len(dp.Aur) == 0 { if !config.CombinedUpgrade { if parser.existsArg("u", "sysupgrade") { fmt.Println(" there is nothing to do") @@ -133,32 +134,37 @@ func install(parser *arguments) error { return show(passToPacman(parser)) } - if len(ds.Aur) > 0 && 0 == os.Geteuid() { + if len(dp.Aur) > 0 && 0 == os.Geteuid() { return fmt.Errorf(bold(red(arrow)) + " Refusing to install AUR Packages as root, Aborting.") } - conflicts, err := ds.CheckConflicts() + conflicts, err := dp.CheckConflicts() if err != nil { return err } - for _, pkg := range ds.Repo { + do = getDepOrder(dp) + if err != nil { + return err + } + + for _, pkg := range do.Repo { arguments.addTarget(pkg.DB().Name() + "/" + pkg.Name()) } - for _, pkg := range ds.Groups { + for _, pkg := range dp.Groups { arguments.addTarget(pkg) } - if len(ds.Aur) == 0 && len(arguments.targets) == 0 && (!parser.existsArg("u", "sysupgrade") || mode == modeAUR) { + if len(do.Aur) == 0 && len(arguments.targets) == 0 && (!parser.existsArg("u", "sysupgrade") || mode == modeAUR) { fmt.Println(" there is nothing to do") return nil } - ds.Print() + do.Print() fmt.Println() - if ds.HasMake() { + if do.HasMake() { if config.RemoveMake == "yes" { removeMake = true } else if config.RemoveMake == "no" { @@ -169,9 +175,9 @@ func install(parser *arguments) error { } if config.CleanMenu { - if anyExistInCache(ds.Aur) { - askClean := pkgbuildNumberMenu(ds.Aur, remoteNamesCache) - toClean, err := cleanNumberMenu(ds.Aur, remoteNamesCache, askClean) + if anyExistInCache(do.Aur) { + askClean := pkgbuildNumberMenu(do.Aur, remoteNamesCache) + toClean, err := cleanNumberMenu(do.Aur, remoteNamesCache, askClean) if err != nil { return err } @@ -180,8 +186,8 @@ func install(parser *arguments) error { } } - toSkip := pkgbuildsToSkip(ds.Aur, targets) - cloned, err := downloadPkgbuilds(ds.Aur, toSkip, config.BuildDir) + toSkip := pkgbuildsToSkip(do.Aur, targets) + cloned, err := downloadPkgbuilds(do.Aur, toSkip, config.BuildDir) if err != nil { return err } @@ -190,8 +196,8 @@ func install(parser *arguments) error { var toEdit []Base if config.DiffMenu { - pkgbuildNumberMenu(ds.Aur, remoteNamesCache) - toDiff, err = diffNumberMenu(ds.Aur, remoteNamesCache) + pkgbuildNumberMenu(do.Aur, remoteNamesCache) + toDiff, err = diffNumberMenu(do.Aur, remoteNamesCache) if err != nil { return err } @@ -214,19 +220,19 @@ func install(parser *arguments) error { config.NoConfirm = oldValue } - err = mergePkgbuilds(ds.Aur) + err = mergePkgbuilds(do.Aur) if err != nil { return err } - srcinfos, err = parseSrcinfoFiles(ds.Aur, true) + srcinfos, err = parseSrcinfoFiles(do.Aur, true) if err != nil { return err } if config.EditMenu { - pkgbuildNumberMenu(ds.Aur, remoteNamesCache) - toEdit, err = editNumberMenu(ds.Aur, remoteNamesCache) + pkgbuildNumberMenu(do.Aur, remoteNamesCache) + toEdit, err = editNumberMenu(do.Aur, remoteNamesCache) if err != nil { return err } @@ -249,13 +255,13 @@ func install(parser *arguments) error { config.NoConfirm = oldValue } - incompatible, err = getIncompatible(ds.Aur, srcinfos) + incompatible, err = getIncompatible(do.Aur, srcinfos) if err != nil { return err } if config.PGPFetch { - err = checkPgpKeys(ds.Aur, srcinfos) + err = checkPgpKeys(do.Aur, srcinfos) if err != nil { return err } @@ -276,15 +282,15 @@ func install(parser *arguments) error { expArguments := makeArguments() expArguments.addArg("D", "asexplicit") - for _, pkg := range ds.Repo { - if !ds.Explicit.get(pkg.Name()) && !localNamesCache.get(pkg.Name()) && !remoteNamesCache.get(pkg.Name()) { + for _, pkg := range do.Repo { + if !dp.Explicit.get(pkg.Name()) && !localNamesCache.get(pkg.Name()) && !remoteNamesCache.get(pkg.Name()) { depArguments.addTarget(pkg.Name()) continue } - if parser.existsArg("asdeps", "asdep") && ds.Explicit.get(pkg.Name()) { + if parser.existsArg("asdeps", "asdep") && dp.Explicit.get(pkg.Name()) { depArguments.addTarget(pkg.Name()) - } else if parser.existsArg("asexp", "asexplicit") && ds.Explicit.get(pkg.Name()) { + } else if parser.existsArg("asexp", "asexplicit") && dp.Explicit.get(pkg.Name()) { expArguments.addTarget(pkg.Name()) } } @@ -306,12 +312,12 @@ func install(parser *arguments) error { go updateCompletion(false) - err = downloadPkgbuildsSources(ds.Aur, incompatible) + err = downloadPkgbuildsSources(do.Aur, incompatible) if err != nil { return err } - err = buildInstallPkgbuilds(ds, srcinfos, parser, incompatible, conflicts) + err = buildInstallPkgbuilds(dp, do, srcinfos, parser, incompatible, conflicts) if err != nil { return err } @@ -320,7 +326,7 @@ func install(parser *arguments) error { removeArguments := makeArguments() removeArguments.addArg("R", "u") - for _, pkg := range ds.getMake() { + for _, pkg := range do.getMake() { removeArguments.addTarget(pkg) } @@ -335,7 +341,7 @@ func install(parser *arguments) error { } if config.CleanAfter { - cleanAfter(ds.Aur) + cleanAfter(do.Aur) } return nil @@ -894,8 +900,8 @@ func downloadPkgbuildsSources(bases []Base, incompatible stringSet) (err error) return } -func buildInstallPkgbuilds(ds *depSolver, srcinfos map[string]*gosrc.Srcinfo, parser *arguments, incompatible stringSet, conflicts mapStringSet) error { - for _, base := range ds.Aur { +func buildInstallPkgbuilds(dp *depPool, do *depOrder, srcinfos map[string]*gosrc.Srcinfo, parser *arguments, incompatible stringSet, conflicts mapStringSet) error { + for _, base := range do.Aur { pkg := base.Pkgbase() dir := filepath.Join(config.BuildDir, pkg) built := true @@ -921,7 +927,7 @@ func buildInstallPkgbuilds(ds *depSolver, srcinfos map[string]*gosrc.Srcinfo, pa isExplicit := false for _, b := range base { - isExplicit = isExplicit || ds.Explicit.get(b.Name) + isExplicit = isExplicit || dp.Explicit.get(b.Name) } if config.ReBuild == "no" || (config.ReBuild == "yes" && !isExplicit) { for _, split := range base { @@ -944,7 +950,7 @@ func buildInstallPkgbuilds(ds *depSolver, srcinfos map[string]*gosrc.Srcinfo, pa if cmdArgs.existsArg("needed") { installed := true for _, split := range base { - if alpmpkg, err := ds.LocalDb.PkgByName(split.Name); err != nil || alpmpkg.Version() != version { + if alpmpkg, err := dp.LocalDb.PkgByName(split.Name); err != nil || alpmpkg.Version() != version { installed = false } } @@ -1028,11 +1034,11 @@ func buildInstallPkgbuilds(ds *depSolver, srcinfos map[string]*gosrc.Srcinfo, pa } arguments.addTarget(pkgdest) - if !ds.Explicit.get(split.Name) && !localNamesCache.get(split.Name) && !remoteNamesCache.get(split.Name) { + if !dp.Explicit.get(split.Name) && !localNamesCache.get(split.Name) && !remoteNamesCache.get(split.Name) { depArguments.addTarget(split.Name) } - if ds.Explicit.get(split.Name) { + if dp.Explicit.get(split.Name) { if parser.existsArg("asdeps", "asdep") { depArguments.addTarget(split.Name) } else if parser.existsArg("asexplicit", "asexp") { diff --git a/print.go b/print.go index c63ac41b..8f2e8c5e 100644 --- a/print.go +++ b/print.go @@ -189,6 +189,76 @@ func (u upSlice) print() { } } +// printDownloadsFromRepo prints repository packages to be downloaded +func (do *depOrder) Print() { + repo := "" + repoMake := "" + aur := "" + aurMake := "" + + repoLen := 0 + repoMakeLen := 0 + aurLen := 0 + aurMakeLen := 0 + + for _, pkg := range do.Repo { + if do.Runtime.get(pkg.Name()) { + repo += " " + pkg.Name() + "-" + pkg.Version() + repoLen++ + } else { + repoMake += " " + pkg.Name() + "-" + pkg.Version() + repoMakeLen++ + } + } + + for _, base := range do.Aur { + pkg := base.Pkgbase() + pkgStr := " " + pkg + "-" + base[0].Version + pkgStrMake := pkgStr + + push := false + pushMake := false + + if len(base) > 1 || pkg != base[0].Name { + pkgStr += " (" + pkgStrMake += " (" + + for _, split := range base { + if do.Runtime.get(split.Name) { + pkgStr += split.Name + " " + aurLen++ + push = true + } else { + pkgStrMake += split.Name + " " + aurMakeLen++ + pushMake = true + } + } + + pkgStr = pkgStr[:len(pkgStr)-1] + ")" + pkgStrMake = pkgStrMake[:len(pkgStrMake)-1] + ")" + } else if do.Runtime.get(base[0].Name) { + aurLen++ + push = true + } else { + aurMakeLen++ + pushMake = true + } + + if push { + aur += pkgStr + } + if pushMake { + aurMake += pkgStrMake + } + } + + printDownloads("Repo", repoLen, repo) + printDownloads("Repo Make", repoMakeLen, repoMake) + printDownloads("Aur", aurLen, aur) + printDownloads("Aur Make", aurMakeLen, aurMake) +} + func printDownloads(repoName string, length int, packages string) { if length < 1 { return