Merge pull request #1048 from Jguer/module-types

Module types
This commit is contained in:
J Guerreiro 2019-10-07 12:10:40 +01:00 committed by GitHub
commit 6e2a4def99
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 637 additions and 489 deletions

View file

@ -5,6 +5,8 @@ import (
"io/ioutil"
"os"
"path/filepath"
"github.com/Jguer/yay/v9/pkg/types"
)
// GetPkgbuild gets the pkgbuild of the package 'pkg' trying the ABS first and then the AUR trying the ABS first and then the AUR.
@ -104,8 +106,8 @@ func syncClean(parser *arguments) error {
func cleanAUR(keepInstalled, keepCurrent, removeAll bool) error {
fmt.Println("removing AUR packages from cache...")
installedBases := make(stringSet)
inAURBases := make(stringSet)
installedBases := make(types.StringSet)
inAURBases := make(types.StringSet)
_, remotePackages, _, _, err := filterPackages()
if err != nil {
@ -137,15 +139,15 @@ func cleanAUR(keepInstalled, keepCurrent, removeAll bool) error {
}
for _, pkg := range info {
inAURBases.set(pkg.PackageBase)
inAURBases.Set(pkg.PackageBase)
}
}
for _, pkg := range remotePackages {
if pkg.Base() != "" {
installedBases.set(pkg.Base())
installedBases.Set(pkg.Base())
} else {
installedBases.set(pkg.Name())
installedBases.Set(pkg.Name())
}
}
@ -155,11 +157,11 @@ func cleanAUR(keepInstalled, keepCurrent, removeAll bool) error {
}
if !removeAll {
if keepInstalled && installedBases.get(file.Name()) {
if keepInstalled && installedBases.Get(file.Name()) {
continue
}
if keepCurrent && inAURBases.get(file.Name()) {
if keepCurrent && inAURBases.Get(file.Name()) {
continue
}
}

7
cmd.go
View file

@ -8,6 +8,7 @@ import (
alpm "github.com/Jguer/go-alpm"
"github.com/Jguer/yay/v9/pkg/completion"
"github.com/Jguer/yay/v9/pkg/types"
)
var cmdArgs = makeArguments()
@ -354,7 +355,7 @@ func displayNumberMenu(pkgS []string) (err error) {
return fmt.Errorf("Input too long")
}
include, exclude, _, otherExclude := parseNumberMenu(string(numberBuf))
include, exclude, _, otherExclude := types.ParseNumberMenu(string(numberBuf))
arguments := makeArguments()
isInclude := len(exclude) == 0 && len(otherExclude) == 0
@ -370,7 +371,7 @@ func displayNumberMenu(pkgS []string) (err error) {
return fmt.Errorf("Invalid Sort Mode. Fix with yay -Y --bottomup --save")
}
if (isInclude && include.get(target)) || (!isInclude && !exclude.get(target)) {
if (isInclude && include.Get(target)) || (!isInclude && !exclude.Get(target)) {
arguments.addTarget(pkg.DB().Name() + "/" + pkg.Name())
}
}
@ -387,7 +388,7 @@ func displayNumberMenu(pkgS []string) (err error) {
return fmt.Errorf("Invalid Sort Mode. Fix with yay -Y --bottomup --save")
}
if (isInclude && include.get(target)) || (!isInclude && !exclude.get(target)) {
if (isInclude && include.Get(target)) || (!isInclude && !exclude.Get(target)) {
arguments.addTarget("aur/" + pkg.Name)
}
}

3
dep.go
View file

@ -5,6 +5,7 @@ import (
"strings"
alpm "github.com/Jguer/go-alpm"
"github.com/Jguer/yay/v9/pkg/types"
rpc "github.com/mikkeloscar/aur"
)
@ -33,7 +34,7 @@ func (q providers) Less(i, j int) bool {
return false
}
return lessRunes([]rune(q.Pkgs[i].Name), []rune(q.Pkgs[j].Name))
return types.LessRunes([]rune(q.Pkgs[i].Name), []rune(q.Pkgs[j].Name))
}
func (q providers) Swap(i, j int) {

View file

@ -7,9 +7,10 @@ import (
"sync"
alpm "github.com/Jguer/go-alpm"
"github.com/Jguer/yay/v9/pkg/types"
)
func (dp *depPool) checkInnerConflict(name string, conflict string, conflicts mapStringSet) {
func (dp *depPool) checkInnerConflict(name string, conflict string, conflicts types.MapStringSet) {
for _, pkg := range dp.Aur {
if pkg.Name == name {
continue
@ -31,7 +32,7 @@ func (dp *depPool) checkInnerConflict(name string, conflict string, conflicts ma
}
}
func (dp *depPool) checkForwardConflict(name string, conflict string, conflicts mapStringSet) {
func (dp *depPool) checkForwardConflict(name string, conflict string, conflicts types.MapStringSet) {
dp.LocalDB.PkgCache().ForEach(func(pkg alpm.Package) error {
if pkg.Name() == name || dp.hasPackage(pkg.Name()) {
return nil
@ -49,7 +50,7 @@ func (dp *depPool) checkForwardConflict(name string, conflict string, conflicts
})
}
func (dp *depPool) checkReverseConflict(name string, conflict string, conflicts mapStringSet) {
func (dp *depPool) checkReverseConflict(name string, conflict string, conflicts types.MapStringSet) {
for _, pkg := range dp.Aur {
if pkg.Name == name {
continue
@ -79,7 +80,7 @@ func (dp *depPool) checkReverseConflict(name string, conflict string, conflicts
}
}
func (dp *depPool) checkInnerConflicts(conflicts mapStringSet) {
func (dp *depPool) checkInnerConflicts(conflicts types.MapStringSet) {
for _, pkg := range dp.Aur {
for _, conflict := range pkg.Conflicts {
dp.checkInnerConflict(pkg.Name, conflict, conflicts)
@ -94,7 +95,7 @@ func (dp *depPool) checkInnerConflicts(conflicts mapStringSet) {
}
}
func (dp *depPool) checkForwardConflicts(conflicts mapStringSet) {
func (dp *depPool) checkForwardConflicts(conflicts types.MapStringSet) {
for _, pkg := range dp.Aur {
for _, conflict := range pkg.Conflicts {
dp.checkForwardConflict(pkg.Name, conflict, conflicts)
@ -109,7 +110,7 @@ func (dp *depPool) checkForwardConflicts(conflicts mapStringSet) {
}
}
func (dp *depPool) checkReverseConflicts(conflicts mapStringSet) {
func (dp *depPool) checkReverseConflicts(conflicts types.MapStringSet) {
dp.LocalDB.PkgCache().ForEach(func(pkg alpm.Package) error {
if dp.hasPackage(pkg.Name()) {
return nil
@ -124,10 +125,10 @@ func (dp *depPool) checkReverseConflicts(conflicts mapStringSet) {
})
}
func (dp *depPool) CheckConflicts() (mapStringSet, error) {
func (dp *depPool) CheckConflicts() (types.MapStringSet, error) {
var wg sync.WaitGroup
innerConflicts := make(mapStringSet)
conflicts := make(mapStringSet)
innerConflicts := make(types.MapStringSet)
conflicts := make(types.MapStringSet)
wg.Add(2)
fmt.Println(bold(cyan("::") + bold(" Checking for conflicts...")))
@ -181,9 +182,9 @@ func (dp *depPool) CheckConflicts() (mapStringSet, error) {
// 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)
conflicts[name] = make(types.StringSet)
for pkg := range pkgs {
conflicts[pkg] = make(stringSet)
conflicts[pkg] = make(types.StringSet)
}
}
@ -203,12 +204,12 @@ func (dp *depPool) CheckConflicts() (mapStringSet, error) {
}
type missing struct {
Good stringSet
Good types.StringSet
Missing map[string][][]string
}
func (dp *depPool) _checkMissing(dep string, stack []string, missing *missing) {
if missing.Good.get(dep) {
if missing.Good.Get(dep) {
return
}
@ -224,11 +225,11 @@ func (dp *depPool) _checkMissing(dep string, stack []string, missing *missing) {
aurPkg := dp.findSatisfierAur(dep)
if aurPkg != nil {
missing.Good.set(dep)
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)
missing.Good.Set(aurDep)
continue
}
@ -241,10 +242,10 @@ func (dp *depPool) _checkMissing(dep string, stack []string, missing *missing) {
repoPkg := dp.findSatisfierRepo(dep)
if repoPkg != nil {
missing.Good.set(dep)
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())
missing.Good.Set(repoDep.String())
return nil
}
@ -260,7 +261,7 @@ func (dp *depPool) _checkMissing(dep string, stack []string, missing *missing) {
func (dp *depPool) CheckMissing() error {
missing := &missing{
make(stringSet),
make(types.StringSet),
make(map[string][][]string),
}

View file

@ -2,6 +2,7 @@ package main
import (
alpm "github.com/Jguer/go-alpm"
"github.com/Jguer/yay/v9/pkg/types"
rpc "github.com/mikkeloscar/aur"
)
@ -22,14 +23,14 @@ func (b Base) URLPath() string {
type depOrder struct {
Aur []Base
Repo []*alpm.Package
Runtime stringSet
Runtime types.StringSet
}
func makeDepOrder() *depOrder {
return &depOrder{
make([]Base, 0),
make([]*alpm.Package, 0),
make(stringSet),
make(types.StringSet),
}
}
@ -59,7 +60,7 @@ func getDepOrder(dp *depPool) *depOrder {
func (do *depOrder) orderPkgAur(pkg *rpc.Pkg, dp *depPool, runtime bool) {
if runtime {
do.Runtime.set(pkg.Name)
do.Runtime.Set(pkg.Name)
}
delete(dp.Aur, pkg.Name)
@ -89,7 +90,7 @@ func (do *depOrder) orderPkgAur(pkg *rpc.Pkg, dp *depPool, runtime bool) {
func (do *depOrder) orderPkgRepo(pkg *alpm.Package, dp *depPool, runtime bool) {
if runtime {
do.Runtime.set(pkg.Name())
do.Runtime.Set(pkg.Name())
}
delete(dp.Repo, pkg.Name())
@ -119,14 +120,14 @@ func (do *depOrder) getMake() []string {
for _, base := range do.Aur {
for _, pkg := range base {
if !do.Runtime.get(pkg.Name) {
if !do.Runtime.Get(pkg.Name) {
makeOnly = append(makeOnly, pkg.Name)
}
}
}
for _, pkg := range do.Repo {
if !do.Runtime.get(pkg.Name()) {
if !do.Runtime.Get(pkg.Name()) {
makeOnly = append(makeOnly, pkg.Name())
}
}

View file

@ -6,6 +6,7 @@ import (
"sync"
alpm "github.com/Jguer/go-alpm"
"github.com/Jguer/yay/v9/pkg/types"
rpc "github.com/mikkeloscar/aur"
)
@ -42,7 +43,7 @@ func (t target) String() string {
type depPool struct {
Targets []target
Explicit stringSet
Explicit types.StringSet
Repo map[string]*alpm.Package
Aur map[string]*rpc.Pkg
AurCache map[string]*rpc.Pkg
@ -64,7 +65,7 @@ func makeDepPool() (*depPool, error) {
dp := &depPool{
make([]target, 0),
make(stringSet),
make(types.StringSet),
make(map[string]*alpm.Package),
make(map[string]*rpc.Pkg),
make(map[string]*rpc.Pkg),
@ -82,7 +83,7 @@ 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)
aurTargets := make(types.StringSet)
pkgs = removeInvalidTargets(pkgs)
@ -105,7 +106,7 @@ func (dp *depPool) ResolveTargets(pkgs []string) error {
// aur/ prefix means we only check the aur
if target.DB == "aur" || mode == modeAUR {
dp.Targets = append(dp.Targets, target)
aurTargets.set(target.DepString())
aurTargets.Set(target.DepString())
continue
}
@ -123,7 +124,7 @@ func (dp *depPool) ResolveTargets(pkgs []string) error {
if err == nil {
dp.Targets = append(dp.Targets, target)
dp.Explicit.set(foundPkg.Name())
dp.Explicit.Set(foundPkg.Name())
dp.ResolveRepoDependency(foundPkg)
continue
} else {
@ -138,7 +139,7 @@ func (dp *depPool) ResolveTargets(pkgs []string) error {
if !group.Empty() {
dp.Groups = append(dp.Groups, target.String())
group.ForEach(func(pkg alpm.Package) error {
dp.Explicit.set(pkg.Name())
dp.Explicit.Set(pkg.Name())
return nil
})
continue
@ -147,7 +148,7 @@ func (dp *depPool) ResolveTargets(pkgs []string) error {
//if there was no db prefix check the aur
if target.DB == "" {
aurTargets.set(target.DepString())
aurTargets.Set(target.DepString())
}
dp.Targets = append(dp.Targets, target)
@ -172,7 +173,7 @@ func (dp *depPool) ResolveTargets(pkgs []string) error {
// positives.
//
// This method increases dependency resolve time
func (dp *depPool) findProvides(pkgs stringSet) error {
func (dp *depPool) findProvides(pkgs types.StringSet) error {
var mux sync.Mutex
var wg sync.WaitGroup
@ -200,7 +201,7 @@ func (dp *depPool) findProvides(pkgs stringSet) error {
for _, result := range results {
mux.Lock()
if _, ok := dp.AurCache[result.Name]; !ok {
pkgs.set(result.Name)
pkgs.Set(result.Name)
}
mux.Unlock()
}
@ -219,13 +220,13 @@ func (dp *depPool) findProvides(pkgs stringSet) error {
return nil
}
func (dp *depPool) cacheAURPackages(_pkgs stringSet) error {
pkgs := _pkgs.copy()
func (dp *depPool) cacheAURPackages(_pkgs types.StringSet) error {
pkgs := _pkgs.Copy()
query := make([]string, 0)
for pkg := range pkgs {
if _, ok := dp.AurCache[pkg]; ok {
pkgs.remove(pkg)
pkgs.Remove(pkg)
}
}
@ -260,9 +261,9 @@ func (dp *depPool) cacheAURPackages(_pkgs stringSet) error {
return nil
}
func (dp *depPool) resolveAURPackages(pkgs stringSet, explicit bool) error {
newPackages := make(stringSet)
newAURPackages := make(stringSet)
func (dp *depPool) resolveAURPackages(pkgs types.StringSet, explicit bool) error {
newPackages := make(types.StringSet)
newAURPackages := make(types.StringSet)
err := dp.cacheAURPackages(pkgs)
if err != nil {
@ -285,13 +286,13 @@ func (dp *depPool) resolveAURPackages(pkgs stringSet, explicit bool) error {
}
if explicit {
dp.Explicit.set(pkg.Name)
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)
newPackages.Set(dep)
}
}
}
@ -317,7 +318,7 @@ func (dp *depPool) resolveAURPackages(pkgs stringSet, explicit bool) error {
//assume it's in the aur
//ditch the versioning because the RPC can't handle it
newAURPackages.set(dep)
newAURPackages.Set(dep)
}
@ -386,7 +387,7 @@ func (dp *depPool) findSatisfierAur(dep string) *rpc.Pkg {
// TODO: maybe intermix repo providers in the menu
func (dp *depPool) findSatisfierAurCache(dep string) *rpc.Pkg {
depName, _, _ := splitDep(dep)
seen := make(stringSet)
seen := make(types.StringSet)
providers := makeProviders(depName)
if dp.LocalDB.Pkg(depName) != nil {
@ -409,20 +410,20 @@ func (dp *depPool) findSatisfierAurCache(dep string) *rpc.Pkg {
}
for _, pkg := range dp.AurCache {
if seen.get(pkg.Name) {
if seen.Get(pkg.Name) {
continue
}
if pkgSatisfies(pkg.Name, pkg.Version, dep) {
providers.Pkgs = append(providers.Pkgs, pkg)
seen.set(pkg.Name)
seen.Set(pkg.Name)
continue
}
for _, provide := range pkg.Provides {
if provideSatisfies(provide, dep) {
providers.Pkgs = append(providers.Pkgs, pkg)
seen.set(pkg.Name)
seen.Set(pkg.Name)
continue
}
}

View file

@ -11,6 +11,7 @@ import (
"sync"
alpm "github.com/Jguer/go-alpm"
"github.com/Jguer/yay/v9/pkg/types"
)
// Decide what download method to use:
@ -224,7 +225,7 @@ func getPkgbuilds(pkgs []string) error {
func getPkgbuildsfromABS(pkgs []string, path string) (bool, error) {
var wg sync.WaitGroup
var mux sync.Mutex
var errs MultiError
var errs types.MultiError
names := make(map[string]string)
missing := make([]string, 0)
downloaded := 0

View file

@ -11,12 +11,13 @@ import (
alpm "github.com/Jguer/go-alpm"
"github.com/Jguer/yay/v9/pkg/completion"
"github.com/Jguer/yay/v9/pkg/types"
gosrc "github.com/Morganamilo/go-srcinfo"
)
// Install handles package installs
func install(parser *arguments) (err error) {
var incompatible stringSet
var incompatible types.StringSet
var do *depOrder
var aurUp upSlice
@ -54,8 +55,8 @@ func install(parser *arguments) (err error) {
return err
}
remoteNamesCache := sliceToStringSet(remoteNames)
localNamesCache := sliceToStringSet(localNames)
remoteNamesCache := types.SliceToStringSet(remoteNames)
localNamesCache := types.SliceToStringSet(localNames)
requestTargets := parser.copy().targets
@ -85,7 +86,7 @@ func install(parser *arguments) (err error) {
}
for _, up := range repoUp {
if !ignore.get(up.Name) {
if !ignore.Get(up.Name) {
requestTargets = append(requestTargets, up.Name)
parser.addTarget(up.Name)
}
@ -99,7 +100,7 @@ func install(parser *arguments) (err error) {
value, _, exists := cmdArgs.getArg("ignore")
if len(ignore) > 0 {
ignoreStr := strings.Join(ignore.toSlice(), ",")
ignoreStr := strings.Join(ignore.ToSlice(), ",")
if exists {
ignoreStr += "," + value
}
@ -107,7 +108,7 @@ func install(parser *arguments) (err error) {
}
}
targets := sliceToStringSet(parser.targets)
targets := types.SliceToStringSet(parser.targets)
dp, err := getDepPool(requestTargets, warnings)
if err != nil {
@ -289,14 +290,14 @@ func install(parser *arguments) (err error) {
expArguments.addArg("D", "asexplicit")
for _, pkg := range do.Repo {
if !dp.Explicit.get(pkg.Name()) && !localNamesCache.get(pkg.Name()) && !remoteNamesCache.get(pkg.Name()) {
if !dp.Explicit.Get(pkg.Name()) && !localNamesCache.Get(pkg.Name()) && !remoteNamesCache.Get(pkg.Name()) {
depArguments.addTarget(pkg.Name())
continue
}
if parser.existsArg("asdeps", "asdep") && dp.Explicit.get(pkg.Name()) {
if parser.existsArg("asdeps", "asdep") && dp.Explicit.Get(pkg.Name()) {
depArguments.addTarget(pkg.Name())
} else if parser.existsArg("asexp", "asexplicit") && dp.Explicit.get(pkg.Name()) {
} else if parser.existsArg("asexp", "asexplicit") && dp.Explicit.Get(pkg.Name()) {
expArguments.addTarget(pkg.Name())
}
}
@ -411,8 +412,8 @@ func earlyRefresh(parser *arguments) error {
return show(passToPacman(arguments))
}
func getIncompatible(bases []Base, srcinfos map[string]*gosrc.Srcinfo) (stringSet, error) {
incompatible := make(stringSet)
func getIncompatible(bases []Base, srcinfos map[string]*gosrc.Srcinfo) (types.StringSet, error) {
incompatible := make(types.StringSet)
basesMap := make(map[string]Base)
alpmArch, err := alpmHandle.Arch()
if err != nil {
@ -427,7 +428,7 @@ nextpkg:
}
}
incompatible.set(base.Pkgbase())
incompatible.Set(base.Pkgbase())
basesMap[base.Pkgbase()] = base
}
@ -495,7 +496,7 @@ func anyExistInCache(bases []Base) bool {
return false
}
func pkgbuildNumberMenu(bases []Base, installed stringSet) bool {
func pkgbuildNumberMenu(bases []Base, installed types.StringSet) bool {
toPrint := ""
askClean := false
@ -508,7 +509,7 @@ func pkgbuildNumberMenu(bases []Base, installed stringSet) bool {
anyInstalled := false
for _, b := range base {
anyInstalled = anyInstalled || installed.get(b.Name)
anyInstalled = anyInstalled || installed.Get(b.Name)
}
if anyInstalled {
@ -528,7 +529,7 @@ func pkgbuildNumberMenu(bases []Base, installed stringSet) bool {
return askClean
}
func cleanNumberMenu(bases []Base, installed stringSet, hasClean bool) ([]Base, error) {
func cleanNumberMenu(bases []Base, installed types.StringSet, hasClean bool) ([]Base, error) {
toClean := make([]Base, 0)
if !hasClean {
@ -543,19 +544,19 @@ func cleanNumberMenu(bases []Base, installed stringSet, hasClean bool) ([]Base,
return nil, err
}
cInclude, cExclude, cOtherInclude, cOtherExclude := parseNumberMenu(cleanInput)
cInclude, cExclude, cOtherInclude, cOtherExclude := types.ParseNumberMenu(cleanInput)
cIsInclude := len(cExclude) == 0 && len(cOtherExclude) == 0
if cOtherInclude.get("abort") || cOtherInclude.get("ab") {
if cOtherInclude.Get("abort") || cOtherInclude.Get("ab") {
return nil, fmt.Errorf("Aborting due to user")
}
if !cOtherInclude.get("n") && !cOtherInclude.get("none") {
if !cOtherInclude.Get("n") && !cOtherInclude.Get("none") {
for i, base := range bases {
pkg := base.Pkgbase()
anyInstalled := false
for _, b := range base {
anyInstalled = anyInstalled || installed.get(b.Name)
anyInstalled = anyInstalled || installed.Get(b.Name)
}
dir := filepath.Join(config.BuildDir, pkg)
@ -563,31 +564,31 @@ func cleanNumberMenu(bases []Base, installed stringSet, hasClean bool) ([]Base,
continue
}
if !cIsInclude && cExclude.get(len(bases)-i) {
if !cIsInclude && cExclude.Get(len(bases)-i) {
continue
}
if anyInstalled && (cOtherInclude.get("i") || cOtherInclude.get("installed")) {
if anyInstalled && (cOtherInclude.Get("i") || cOtherInclude.Get("installed")) {
toClean = append(toClean, base)
continue
}
if !anyInstalled && (cOtherInclude.get("no") || cOtherInclude.get("notinstalled")) {
if !anyInstalled && (cOtherInclude.Get("no") || cOtherInclude.Get("notinstalled")) {
toClean = append(toClean, base)
continue
}
if cOtherInclude.get("a") || cOtherInclude.get("all") {
if cOtherInclude.Get("a") || cOtherInclude.Get("all") {
toClean = append(toClean, base)
continue
}
if cIsInclude && (cInclude.get(len(bases)-i) || cOtherInclude.get(pkg)) {
if cIsInclude && (cInclude.Get(len(bases)-i) || cOtherInclude.Get(pkg)) {
toClean = append(toClean, base)
continue
}
if !cIsInclude && (!cExclude.get(len(bases)-i) && !cOtherExclude.get(pkg)) {
if !cIsInclude && (!cExclude.Get(len(bases)-i) && !cOtherExclude.Get(pkg)) {
toClean = append(toClean, base)
continue
}
@ -597,15 +598,15 @@ func cleanNumberMenu(bases []Base, installed stringSet, hasClean bool) ([]Base,
return toClean, nil
}
func editNumberMenu(bases []Base, installed stringSet) ([]Base, error) {
func editNumberMenu(bases []Base, installed types.StringSet) ([]Base, error) {
return editDiffNumberMenu(bases, installed, false)
}
func diffNumberMenu(bases []Base, installed stringSet) ([]Base, error) {
func diffNumberMenu(bases []Base, installed types.StringSet) ([]Base, error) {
return editDiffNumberMenu(bases, installed, true)
}
func editDiffNumberMenu(bases []Base, installed stringSet, diff bool) ([]Base, error) {
func editDiffNumberMenu(bases []Base, installed types.StringSet, diff bool) ([]Base, error) {
toEdit := make([]Base, 0)
var editInput string
var err error
@ -628,45 +629,45 @@ func editDiffNumberMenu(bases []Base, installed stringSet, diff bool) ([]Base, e
}
}
eInclude, eExclude, eOtherInclude, eOtherExclude := parseNumberMenu(editInput)
eInclude, eExclude, eOtherInclude, eOtherExclude := types.ParseNumberMenu(editInput)
eIsInclude := len(eExclude) == 0 && len(eOtherExclude) == 0
if eOtherInclude.get("abort") || eOtherInclude.get("ab") {
if eOtherInclude.Get("abort") || eOtherInclude.Get("ab") {
return nil, fmt.Errorf("Aborting due to user")
}
if !eOtherInclude.get("n") && !eOtherInclude.get("none") {
if !eOtherInclude.Get("n") && !eOtherInclude.Get("none") {
for i, base := range bases {
pkg := base.Pkgbase()
anyInstalled := false
for _, b := range base {
anyInstalled = anyInstalled || installed.get(b.Name)
anyInstalled = anyInstalled || installed.Get(b.Name)
}
if !eIsInclude && eExclude.get(len(bases)-i) {
if !eIsInclude && eExclude.Get(len(bases)-i) {
continue
}
if anyInstalled && (eOtherInclude.get("i") || eOtherInclude.get("installed")) {
if anyInstalled && (eOtherInclude.Get("i") || eOtherInclude.Get("installed")) {
toEdit = append(toEdit, base)
continue
}
if !anyInstalled && (eOtherInclude.get("no") || eOtherInclude.get("notinstalled")) {
if !anyInstalled && (eOtherInclude.Get("no") || eOtherInclude.Get("notinstalled")) {
toEdit = append(toEdit, base)
continue
}
if eOtherInclude.get("a") || eOtherInclude.get("all") {
if eOtherInclude.Get("a") || eOtherInclude.Get("all") {
toEdit = append(toEdit, base)
continue
}
if eIsInclude && (eInclude.get(len(bases)-i) || eOtherInclude.get(pkg)) {
if eIsInclude && (eInclude.Get(len(bases)-i) || eOtherInclude.Get(pkg)) {
toEdit = append(toEdit, base)
}
if !eIsInclude && (!eExclude.get(len(bases)-i) && !eOtherExclude.get(pkg)) {
if !eIsInclude && (!eExclude.Get(len(bases)-i) && !eOtherExclude.Get(pkg)) {
toEdit = append(toEdit, base)
}
}
@ -675,14 +676,14 @@ func editDiffNumberMenu(bases []Base, installed stringSet, diff bool) ([]Base, e
return toEdit, nil
}
func showPkgbuildDiffs(bases []Base, cloned stringSet) error {
func showPkgbuildDiffs(bases []Base, cloned types.StringSet) error {
for _, base := range bases {
pkg := base.Pkgbase()
dir := filepath.Join(config.BuildDir, pkg)
if shouldUseGit(dir) {
start := "HEAD"
if cloned.get(pkg) {
if cloned.Get(pkg) {
start = gitEmptyTree
} else {
hasDiff, err := gitHasDiff(config.BuildDir, pkg)
@ -774,13 +775,13 @@ func parseSrcinfoFiles(bases []Base, errIsFatal bool) (map[string]*gosrc.Srcinfo
return srcinfos, nil
}
func pkgbuildsToSkip(bases []Base, targets stringSet) stringSet {
toSkip := make(stringSet)
func pkgbuildsToSkip(bases []Base, targets types.StringSet) types.StringSet {
toSkip := make(types.StringSet)
for _, base := range bases {
isTarget := false
for _, pkg := range base {
isTarget = isTarget || targets.get(pkg.Name)
isTarget = isTarget || targets.Get(pkg.Name)
}
if (config.ReDownload == "yes" && isTarget) || config.ReDownload == "all" {
@ -792,7 +793,7 @@ func pkgbuildsToSkip(bases []Base, targets stringSet) stringSet {
if err == nil {
if alpm.VerCmp(pkgbuild.Version(), base.Version()) >= 0 {
toSkip.set(base.Pkgbase())
toSkip.Set(base.Pkgbase())
}
}
}
@ -813,18 +814,18 @@ func mergePkgbuilds(bases []Base) error {
return nil
}
func downloadPkgbuilds(bases []Base, toSkip stringSet, buildDir string) (stringSet, error) {
cloned := make(stringSet)
func downloadPkgbuilds(bases []Base, toSkip types.StringSet, buildDir string) (types.StringSet, error) {
cloned := make(types.StringSet)
downloaded := 0
var wg sync.WaitGroup
var mux sync.Mutex
var errs MultiError
var errs types.MultiError
download := func(k int, base Base) {
defer wg.Done()
pkg := base.Pkgbase()
if toSkip.get(pkg) {
if toSkip.Get(pkg) {
mux.Lock()
downloaded++
str := bold(cyan("::") + " PKGBUILD up to date, Skipping (%d/%d): %s\n")
@ -841,7 +842,7 @@ func downloadPkgbuilds(bases []Base, toSkip stringSet, buildDir string) (stringS
}
if clone {
mux.Lock()
cloned.set(pkg)
cloned.Set(pkg)
mux.Unlock()
}
} else {
@ -874,13 +875,13 @@ func downloadPkgbuilds(bases []Base, toSkip stringSet, buildDir string) (stringS
return cloned, errs.Return()
}
func downloadPkgbuildsSources(bases []Base, incompatible stringSet) (err error) {
func downloadPkgbuildsSources(bases []Base, incompatible types.StringSet) (err error) {
for _, base := range bases {
pkg := base.Pkgbase()
dir := filepath.Join(config.BuildDir, pkg)
args := []string{"--verifysource", "-Ccf"}
if incompatible.get(pkg) {
if incompatible.Get(pkg) {
args = append(args, "--ignorearch")
}
@ -893,7 +894,7 @@ func downloadPkgbuildsSources(bases []Base, incompatible stringSet) (err error)
return
}
func buildInstallPkgbuilds(dp *depPool, do *depOrder, srcinfos map[string]*gosrc.Srcinfo, parser *arguments, incompatible stringSet, conflicts mapStringSet) error {
func buildInstallPkgbuilds(dp *depPool, do *depOrder, srcinfos map[string]*gosrc.Srcinfo, parser *arguments, incompatible types.StringSet, conflicts types.MapStringSet) error {
for _, base := range do.Aur {
pkg := base.Pkgbase()
dir := filepath.Join(config.BuildDir, pkg)
@ -903,7 +904,7 @@ func buildInstallPkgbuilds(dp *depPool, do *depOrder, srcinfos map[string]*gosrc
args := []string{"--nobuild", "-fC"}
if incompatible.get(pkg) {
if incompatible.Get(pkg) {
args = append(args, "--ignorearch")
}
@ -920,7 +921,7 @@ func buildInstallPkgbuilds(dp *depPool, do *depOrder, srcinfos map[string]*gosrc
isExplicit := false
for _, b := range base {
isExplicit = isExplicit || dp.Explicit.get(b.Name)
isExplicit = isExplicit || dp.Explicit.Get(b.Name)
}
if config.ReBuild == "no" || (config.ReBuild == "yes" && !isExplicit) {
for _, split := range base {
@ -962,7 +963,7 @@ func buildInstallPkgbuilds(dp *depPool, do *depOrder, srcinfos map[string]*gosrc
} else {
args := []string{"-cf", "--noconfirm", "--noextract", "--noprepare", "--holdver"}
if incompatible.get(pkg) {
if incompatible.Get(pkg) {
args = append(args, "--ignorearch")
}
@ -1017,8 +1018,8 @@ func buildInstallPkgbuilds(dp *depPool, do *depOrder, srcinfos map[string]*gosrc
//cache as a stringset. maybe make it return a string set in the first
//place
remoteNamesCache := sliceToStringSet(remoteNames)
localNamesCache := sliceToStringSet(localNames)
remoteNamesCache := types.SliceToStringSet(remoteNames)
localNamesCache := types.SliceToStringSet(localNames)
for _, split := range base {
pkgdest, ok := pkgdests[split.Name]
@ -1027,11 +1028,11 @@ func buildInstallPkgbuilds(dp *depPool, do *depOrder, srcinfos map[string]*gosrc
}
arguments.addTarget(pkgdest)
if !dp.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 dp.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") {

125
parser.go
View file

@ -8,73 +8,18 @@ import (
"os"
"strconv"
"strings"
"unicode"
"github.com/Jguer/yay/v9/pkg/types"
rpc "github.com/mikkeloscar/aur"
)
// A basic set implementation for strings.
// This is used a lot so it deserves its own type.
// Other types of sets are used throughout the code but do not have
// their own typedef.
// String sets and <type>sets should be used throughout the code when applicable,
// they are a lot more flexible than slices and provide easy lookup.
type stringSet map[string]struct{}
func (set stringSet) set(v string) {
set[v] = struct{}{}
}
func (set stringSet) get(v string) bool {
_, exists := set[v]
return exists
}
func (set stringSet) remove(v string) {
delete(set, v)
}
func (set stringSet) toSlice() []string {
slice := make([]string, 0, len(set))
for v := range set {
slice = append(slice, v)
}
return slice
}
func (set stringSet) copy() stringSet {
newSet := make(stringSet)
for str := range set {
newSet.set(str)
}
return newSet
}
func sliceToStringSet(in []string) stringSet {
set := make(stringSet)
for _, v := range in {
set.set(v)
}
return set
}
func makeStringSet(in ...string) stringSet {
return sliceToStringSet(in)
}
// Parses command line arguments in a way we can interact with programmatically but
// also in a way that can easily be passed to pacman later on.
type arguments struct {
op string
options map[string]string
globals map[string]string
doubles stringSet // Tracks args passed twice such as -yy and -dd
doubles types.StringSet // Tracks args passed twice such as -yy and -dd
targets []string
}
@ -83,7 +28,7 @@ func makeArguments() *arguments {
"",
make(map[string]string),
make(map[string]string),
make(stringSet),
make(types.StringSet),
make([]string, 0),
}
}
@ -886,70 +831,6 @@ func (parser *arguments) extractYayOptions() {
config.AURURL = strings.TrimRight(config.AURURL, "/")
}
//parses input for number menus split by spaces or commas
//supports individual selection: 1 2 3 4
//supports range selections: 1-4 10-20
//supports negation: ^1 ^1-4
//
//include and excule holds numbers that should be added and should not be added
//respectively. other holds anything that can't be parsed as an int. This is
//intended to allow words inside of number menus. e.g. 'all' 'none' 'abort'
//of course the implementation is up to the caller, this function mearley parses
//the input and organizes it
func parseNumberMenu(input string) (intRanges, intRanges, stringSet, stringSet) {
include := make(intRanges, 0)
exclude := make(intRanges, 0)
otherInclude := make(stringSet)
otherExclude := make(stringSet)
words := strings.FieldsFunc(input, func(c rune) bool {
return unicode.IsSpace(c) || c == ','
})
for _, word := range words {
var num1 int
var num2 int
var err error
invert := false
other := otherInclude
if word[0] == '^' {
invert = true
other = otherExclude
word = word[1:]
}
ranges := strings.SplitN(word, "-", 2)
num1, err = strconv.Atoi(ranges[0])
if err != nil {
other.set(strings.ToLower(word))
continue
}
if len(ranges) == 2 {
num2, err = strconv.Atoi(ranges[1])
if err != nil {
other.set(strings.ToLower(word))
continue
}
} else {
num2 = num1
}
mi := min(num1, num2)
ma := max(num1, num2)
if !invert {
include = append(include, makeIntRange(mi, ma))
} else {
exclude = append(exclude, makeIntRange(mi, ma))
}
}
return include, exclude, otherInclude, otherExclude
}
// Crude html parsing, good enough for the arch news
// This is only displayed in the terminal so there should be no security
// concerns

View file

@ -1,101 +0,0 @@
package main
import "testing"
func intRangesEqual(a, b intRanges) bool {
if a == nil && b == nil {
return true
}
if a == nil || b == nil {
return false
}
if len(a) != len(b) {
return false
}
for n := range a {
r1 := a[n]
r2 := b[n]
if r1.min != r2.min || r1.max != r2.max {
return false
}
}
return true
}
func stringSetEqual(a, b stringSet) bool {
if a == nil && b == nil {
return true
}
if a == nil || b == nil {
return false
}
if len(a) != len(b) {
return false
}
for n := range a {
if !b.get(n) {
return false
}
}
return true
}
func TestParseNumberMenu(t *testing.T) {
type result struct {
Include intRanges
Exclude intRanges
OtherInclude stringSet
OtherExclude stringSet
}
inputs := []string{
"1 2 3 4 5",
"1-10 5-15",
"10-5 90-85",
"1 ^2 ^10-5 99 ^40-38 ^123 60-62",
"abort all none",
"a-b ^a-b ^abort",
"1\t2 3 4\t\t \t 5",
"1 2,3, 4, 5,6 ,7 ,8",
"",
" \t ",
"A B C D E",
}
expected := []result{
{intRanges{makeIntRange(1, 1), makeIntRange(2, 2), makeIntRange(3, 3), makeIntRange(4, 4), makeIntRange(5, 5)}, intRanges{}, make(stringSet), make(stringSet)},
{intRanges{makeIntRange(1, 10), makeIntRange(5, 15)}, intRanges{}, make(stringSet), make(stringSet)},
{intRanges{makeIntRange(5, 10), makeIntRange(85, 90)}, intRanges{}, make(stringSet), make(stringSet)},
{intRanges{makeIntRange(1, 1), makeIntRange(99, 99), makeIntRange(60, 62)}, intRanges{makeIntRange(2, 2), makeIntRange(5, 10), makeIntRange(38, 40), makeIntRange(123, 123)}, make(stringSet), make(stringSet)},
{intRanges{}, intRanges{}, makeStringSet("abort", "all", "none"), make(stringSet)},
{intRanges{}, intRanges{}, makeStringSet("a-b"), makeStringSet("abort", "a-b")},
{intRanges{makeIntRange(1, 1), makeIntRange(2, 2), makeIntRange(3, 3), makeIntRange(4, 4), makeIntRange(5, 5)}, intRanges{}, make(stringSet), make(stringSet)},
{intRanges{makeIntRange(1, 1), makeIntRange(2, 2), makeIntRange(3, 3), makeIntRange(4, 4), makeIntRange(5, 5), makeIntRange(6, 6), makeIntRange(7, 7), makeIntRange(8, 8)}, intRanges{}, make(stringSet), make(stringSet)},
{intRanges{}, intRanges{}, make(stringSet), make(stringSet)},
{intRanges{}, intRanges{}, make(stringSet), make(stringSet)},
{intRanges{}, intRanges{}, makeStringSet("a", "b", "c", "d", "e"), make(stringSet)},
}
for n, in := range inputs {
res := expected[n]
include, exclude, otherInclude, otherExclude := parseNumberMenu(in)
if !intRangesEqual(include, res.Include) ||
!intRangesEqual(exclude, res.Exclude) ||
!stringSetEqual(otherInclude, res.OtherInclude) ||
!stringSetEqual(otherExclude, res.OtherExclude) {
t.Fatalf("Test %d Failed: Expected: include=%+v exclude=%+v otherInclude=%+v otherExclude=%+v got include=%+v excluive=%+v otherInclude=%+v otherExclude=%+v",
n+1, res.Include, res.Exclude, res.OtherInclude, res.OtherExclude, include, exclude, otherInclude, otherExclude)
}
}
}

121
pkg/types/intrange.go Normal file
View file

@ -0,0 +1,121 @@
package types
import (
"strconv"
"strings"
"unicode"
)
// IntRange stores a max and min amount for range
type IntRange struct {
min int
max int
}
// IntRanges is a slice of IntRange
type IntRanges []IntRange
func makeIntRange(min, max int) IntRange {
return IntRange{
min,
max,
}
}
// Get returns true if the argument n is included in the closed range
// between min and max
func (r IntRange) Get(n int) bool {
return n >= r.min && n <= r.max
}
// Get returns true if the argument n is included in the closed range
// between min and max of any of the provided IntRanges
func (rs IntRanges) Get(n int) bool {
for _, r := range rs {
if r.Get(n) {
return true
}
}
return false
}
// Min returns min value between a and b
func Min(a, b int) int {
if a < b {
return a
}
return b
}
// Max returns max value between a and b
func Max(a, b int) int {
if a < b {
return b
}
return a
}
// ParseNumberMenu parses input for number menus split by spaces or commas
//supports individual selection: 1 2 3 4
//supports range selections: 1-4 10-20
//supports negation: ^1 ^1-4
//
//include and excule holds numbers that should be added and should not be added
//respectively. other holds anything that can't be parsed as an int. This is
//intended to allow words inside of number menus. e.g. 'all' 'none' 'abort'
//of course the implementation is up to the caller, this function mearley parses
//the input and organizes it
func ParseNumberMenu(input string) (IntRanges, IntRanges, StringSet, StringSet) {
include := make(IntRanges, 0)
exclude := make(IntRanges, 0)
otherInclude := make(StringSet)
otherExclude := make(StringSet)
words := strings.FieldsFunc(input, func(c rune) bool {
return unicode.IsSpace(c) || c == ','
})
for _, word := range words {
var num1 int
var num2 int
var err error
invert := false
other := otherInclude
if word[0] == '^' {
invert = true
other = otherExclude
word = word[1:]
}
ranges := strings.SplitN(word, "-", 2)
num1, err = strconv.Atoi(ranges[0])
if err != nil {
other.Set(strings.ToLower(word))
continue
}
if len(ranges) == 2 {
num2, err = strconv.Atoi(ranges[1])
if err != nil {
other.Set(strings.ToLower(word))
continue
}
} else {
num2 = num1
}
mi := Min(num1, num2)
ma := Max(num1, num2)
if !invert {
include = append(include, makeIntRange(mi, ma))
} else {
exclude = append(exclude, makeIntRange(mi, ma))
}
}
return include, exclude, otherInclude, otherExclude
}

145
pkg/types/intrange_test.go Normal file
View file

@ -0,0 +1,145 @@
package types
import (
"testing"
)
func TestParseNumberMenu(t *testing.T) {
type result struct {
Include IntRanges
Exclude IntRanges
OtherInclude StringSet
OtherExclude StringSet
}
inputs := []string{
"1 2 3 4 5",
"1-10 5-15",
"10-5 90-85",
"1 ^2 ^10-5 99 ^40-38 ^123 60-62",
"abort all none",
"a-b ^a-b ^abort",
"-9223372036854775809-9223372036854775809",
"1\t2 3 4\t\t \t 5",
"1 2,3, 4, 5,6 ,7 ,8",
"",
" \t ",
"A B C D E",
}
expected := []result{
{IntRanges{makeIntRange(1, 1), makeIntRange(2, 2), makeIntRange(3, 3), makeIntRange(4, 4), makeIntRange(5, 5)}, IntRanges{}, make(StringSet), make(StringSet)},
{IntRanges{makeIntRange(1, 10), makeIntRange(5, 15)}, IntRanges{}, make(StringSet), make(StringSet)},
{IntRanges{makeIntRange(5, 10), makeIntRange(85, 90)}, IntRanges{}, make(StringSet), make(StringSet)},
{IntRanges{makeIntRange(1, 1), makeIntRange(99, 99), makeIntRange(60, 62)}, IntRanges{makeIntRange(2, 2), makeIntRange(5, 10), makeIntRange(38, 40), makeIntRange(123, 123)}, make(StringSet), make(StringSet)},
{IntRanges{}, IntRanges{}, MakeStringSet("abort", "all", "none"), make(StringSet)},
{IntRanges{}, IntRanges{}, MakeStringSet("a-b"), MakeStringSet("abort", "a-b")},
{IntRanges{}, IntRanges{}, MakeStringSet("-9223372036854775809-9223372036854775809"), make(StringSet)},
{IntRanges{makeIntRange(1, 1), makeIntRange(2, 2), makeIntRange(3, 3), makeIntRange(4, 4), makeIntRange(5, 5)}, IntRanges{}, make(StringSet), make(StringSet)},
{IntRanges{makeIntRange(1, 1), makeIntRange(2, 2), makeIntRange(3, 3), makeIntRange(4, 4), makeIntRange(5, 5), makeIntRange(6, 6), makeIntRange(7, 7), makeIntRange(8, 8)}, IntRanges{}, make(StringSet), make(StringSet)},
{IntRanges{}, IntRanges{}, make(StringSet), make(StringSet)},
{IntRanges{}, IntRanges{}, make(StringSet), make(StringSet)},
{IntRanges{}, IntRanges{}, MakeStringSet("a", "b", "c", "d", "e"), make(StringSet)},
}
for n, in := range inputs {
res := expected[n]
include, exclude, otherInclude, otherExclude := ParseNumberMenu(in)
if !intRangesEqual(include, res.Include) ||
!intRangesEqual(exclude, res.Exclude) ||
!StringSetEqual(otherInclude, res.OtherInclude) ||
!StringSetEqual(otherExclude, res.OtherExclude) {
t.Fatalf("Test %d Failed: Expected: include=%+v exclude=%+v otherInclude=%+v otherExclude=%+v got include=%+v excluive=%+v otherInclude=%+v otherExclude=%+v",
n+1, res.Include, res.Exclude, res.OtherInclude, res.OtherExclude, include, exclude, otherInclude, otherExclude)
}
}
}
func TestIntRange_Get(t *testing.T) {
type fields struct {
min int
max int
}
type args struct {
n int
}
tests := []struct {
name string
fields fields
args args
want bool
}{
{name: "normal range true", fields: fields{0, 10}, args: args{5}, want: true},
{name: "normal start range true", fields: fields{0, 10}, args: args{0}, want: true},
{name: "normal end range true", fields: fields{0, 10}, args: args{10}, want: true},
{name: "small range true", fields: fields{1, 1}, args: args{1}, want: true},
{name: "normal start range false", fields: fields{1, 2}, args: args{0}, want: false},
{name: "normal end range false", fields: fields{1, 2}, args: args{3}, want: false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := IntRange{
min: tt.fields.min,
max: tt.fields.max,
}
if got := r.Get(tt.args.n); got != tt.want {
t.Errorf("IntRange.Get() = %v, want %v", got, tt.want)
}
})
}
}
func intRangesEqual(a, b IntRanges) bool {
if a == nil && b == nil {
return true
}
if a == nil || b == nil {
return false
}
if len(a) != len(b) {
return false
}
for n := range a {
r1 := a[n]
r2 := b[n]
if r1.min != r2.min || r1.max != r2.max {
return false
}
}
return true
}
func TestIntRanges_Get(t *testing.T) {
type args struct {
n int
}
tests := []struct {
name string
rs IntRanges
args args
want bool
}{
{name: "normal range true", rs: IntRanges{{0, 10}}, args: args{5}, want: true},
{name: "normal ranges inbetween true", rs: IntRanges{{0, 4}, {5, 10}}, args: args{5}, want: true},
{name: "normal ranges inbetween false", rs: IntRanges{{0, 4}, {6, 10}}, args: args{5}, want: false},
{name: "normal start range true", rs: IntRanges{{0, 10}}, args: args{0}, want: true},
{name: "normal end range true", rs: IntRanges{{0, 10}}, args: args{10}, want: true},
{name: "small range true", rs: IntRanges{{1, 1}, {3, 3}}, args: args{1}, want: true},
{name: "normal start range false", rs: IntRanges{{1, 2}}, args: args{0}, want: false},
{name: "normal end range false", rs: IntRanges{{1, 2}}, args: args{3}, want: false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.rs.Get(tt.args.n); got != tt.want {
t.Errorf("IntRanges.Get() = %v, want %v", got, tt.want)
}
})
}
}

41
pkg/types/multierror.go Normal file
View file

@ -0,0 +1,41 @@
package types
import "sync"
// MultiError type handles error accumulation from goroutines
type MultiError struct {
Errors []error
mux sync.Mutex
}
// Error turns the MultiError structure into a string
func (err *MultiError) Error() string {
str := ""
for _, e := range err.Errors {
str += e.Error() + "\n"
}
return str[:len(str)-1]
}
// Add adds an error to the Multierror structure
func (err *MultiError) Add(e error) {
if e == nil {
return
}
err.mux.Lock()
err.Errors = append(err.Errors, e)
err.mux.Unlock()
}
// Return is used as a wrapper on return on wether to return the
// MultiError Structure if errors exist or nil instead of delivering an empty structure
func (err *MultiError) Return() error {
if len(err.Errors) > 0 {
return err
}
return nil
}

30
pkg/types/runes.go Normal file
View file

@ -0,0 +1,30 @@
package types
import "unicode"
// LessRunes compares two rune values, and returns true if the first argument is lexicographicaly smaller.
func LessRunes(iRunes, jRunes []rune) bool {
max := len(iRunes)
if max > len(jRunes) {
max = len(jRunes)
}
for idx := 0; idx < max; idx++ {
ir := iRunes[idx]
jr := jRunes[idx]
lir := unicode.ToLower(ir)
ljr := unicode.ToLower(jr)
if lir != ljr {
return lir < ljr
}
// the lowercase runes are the same, so compare the original
if ir != jr {
return ir < jr
}
}
return len(iRunes) < len(jRunes)
}

33
pkg/types/runes_test.go Normal file
View file

@ -0,0 +1,33 @@
package types
import "testing"
func TestLessRunes(t *testing.T) {
t.Parallel()
type args struct {
iRunes []rune
jRunes []rune
}
tests := []struct {
name string
args args
want bool
}{
{name: "nilslices", args: args{iRunes: nil, jRunes: nil}, want: false},
{name: "emptyslices", args: args{iRunes: []rune{}, jRunes: []rune{}}, want: false},
{name: "simpleslice a,b", args: args{iRunes: []rune{'a'}, jRunes: []rune{'b'}}, want: true},
{name: "simpleslice b,a", args: args{iRunes: []rune{'b'}, jRunes: []rune{'a'}}, want: false},
{name: "equalslice", args: args{iRunes: []rune{'a', 'a', 'a'}, jRunes: []rune{'a', 'a', 'a'}}, want: false},
{name: "uppercase", args: args{iRunes: []rune{'a'}, jRunes: []rune{'A'}}, want: false},
{name: "longerFirstArg", args: args{iRunes: []rune{'a', 'b'}, jRunes: []rune{'a'}}, want: false},
{name: "longerSecondArg", args: args{iRunes: []rune{'a'}, jRunes: []rune{'a', 'b'}}, want: true},
{name: "utf8 less", args: args{iRunes: []rune{'世', '2', '0'}, jRunes: []rune{'世', '界', '3'}}, want: true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := LessRunes(tt.args.iRunes, tt.args.jRunes); got != tt.want {
t.Errorf("LessRunes() = %v, want %v", got, tt.want)
}
})
}
}

98
pkg/types/stringset.go Normal file
View file

@ -0,0 +1,98 @@
package types
// StringSet is a basic set implementation for strings.
// This is used a lot so it deserves its own type.
// Other types of sets are used throughout the code but do not have
// their own typedef.
// String sets and <type>sets should be used throughout the code when applicable,
// they are a lot more flexible than slices and provide easy lookup.
type StringSet map[string]struct{}
// MapStringSet is a Map of StringSets.
type MapStringSet map[string]StringSet
// Add adds a new value to the Map.
func (mss MapStringSet) Add(n string, v string) {
_, ok := mss[n]
if !ok {
mss[n] = make(StringSet)
}
mss[n].Set(v)
}
// Set sets key in StringSet.
func (set StringSet) Set(v string) {
set[v] = struct{}{}
}
// Get returns true if the key exists in the set.
func (set StringSet) Get(v string) bool {
_, exists := set[v]
return exists
}
// Remove deletes a key from the set.
func (set StringSet) Remove(v string) {
delete(set, v)
}
// ToSlice turns all keys into a string slice.
func (set StringSet) ToSlice() []string {
slice := make([]string, 0, len(set))
for v := range set {
slice = append(slice, v)
}
return slice
}
// Copy copies a StringSet into a new structure of the same type.
func (set StringSet) Copy() StringSet {
newSet := make(StringSet)
for str := range set {
newSet.Set(str)
}
return newSet
}
// SliceToStringSet creates a new StringSet from an input slice
func SliceToStringSet(in []string) StringSet {
set := make(StringSet)
for _, v := range in {
set.Set(v)
}
return set
}
// MakeStringSet creates a new StringSet from a set of arguments
func MakeStringSet(in ...string) StringSet {
return SliceToStringSet(in)
}
// StringSetEqual compares if two StringSets have the same values
func StringSetEqual(a, b StringSet) bool {
if a == nil && b == nil {
return true
}
if a == nil || b == nil {
return false
}
if len(a) != len(b) {
return false
}
for n := range a {
if !b.Get(n) {
return false
}
}
return true
}

View file

@ -12,6 +12,7 @@ import (
"strings"
"time"
"github.com/Jguer/yay/v9/pkg/types"
rpc "github.com/mikkeloscar/aur"
)
@ -176,8 +177,8 @@ func (u upSlice) print() {
packNameLen := len(pack.StylizedNameWithRepository())
version, _ := getVersionDiff(pack.LocalVersion, pack.RemoteVersion)
packVersionLen := len(version)
longestName = max(packNameLen, longestName)
longestVersion = max(packVersionLen, longestVersion)
longestName = types.Max(packNameLen, longestName)
longestVersion = types.Max(packVersionLen, longestVersion)
}
namePadding := fmt.Sprintf("%%-%ds ", longestName)
@ -208,7 +209,7 @@ func (do *depOrder) Print() {
aurMakeLen := 0
for _, pkg := range do.Repo {
if do.Runtime.get(pkg.Name()) {
if do.Runtime.Get(pkg.Name()) {
repo += " " + pkg.Name() + "-" + pkg.Version()
repoLen++
} else {
@ -231,7 +232,7 @@ func (do *depOrder) Print() {
pkgStrMake += " ("
for _, split := range base {
if do.Runtime.get(split.Name) {
if do.Runtime.Get(split.Name) {
pkgStr += split.Name + " "
aurLen++
push = true
@ -244,7 +245,7 @@ func (do *depOrder) Print() {
pkgStr = pkgStr[:len(pkgStr)-1] + ")"
pkgStrMake = pkgStrMake[:len(pkgStrMake)-1] + ")"
case do.Runtime.get(base[0].Name):
case do.Runtime.Get(base[0].Name):
aurLen++
push = true
default:
@ -389,7 +390,7 @@ func printNumberOfUpdates() error {
//TODO: Make it less hacky
func printUpdateList(parser *arguments) error {
targets := sliceToStringSet(parser.targets)
targets := types.SliceToStringSet(parser.targets)
warnings := &aurWarnings{}
old := os.Stdout // keep backup of the real stdout
os.Stdout = nil
@ -408,7 +409,7 @@ func printUpdateList(parser *arguments) error {
if !parser.existsArg("m", "foreign") {
for _, pkg := range repoUp {
if noTargets || targets.get(pkg.Name) {
if noTargets || targets.Get(pkg.Name) {
if parser.existsArg("q", "quiet") {
fmt.Printf("%s\n", pkg.Name)
} else {
@ -421,7 +422,7 @@ func printUpdateList(parser *arguments) error {
if !parser.existsArg("n", "native") {
for _, pkg := range aurUp {
if noTargets || targets.get(pkg.Name) {
if noTargets || targets.Get(pkg.Name) {
if parser.existsArg("q", "quiet") {
fmt.Printf("%s\n", pkg.Name)
} else {

View file

@ -9,6 +9,7 @@ import (
"time"
alpm "github.com/Jguer/go-alpm"
"github.com/Jguer/yay/v9/pkg/types"
rpc "github.com/mikkeloscar/aur"
)
@ -37,9 +38,9 @@ func (q aurQuery) Less(i, j int) bool {
case "popularity":
result = q[i].Popularity > q[j].Popularity
case "name":
result = lessRunes([]rune(q[i].Name), []rune(q[j].Name))
result = types.LessRunes([]rune(q[i].Name), []rune(q[j].Name))
case "base":
result = lessRunes([]rune(q[i].PackageBase), []rune(q[j].PackageBase))
result = types.LessRunes([]rune(q[i].PackageBase), []rune(q[j].PackageBase))
case "submitted":
result = q[i].FirstSubmitted < q[j].FirstSubmitted
case "modified":
@ -341,7 +342,7 @@ func hangingPackages(removeOptional bool) (hanging []string, err error) {
// State = 2 - Keep package and have iterated over dependencies
safePackages := make(map[string]uint8)
// provides stores a mapping from the provides name back to the original package name
provides := make(mapStringSet)
provides := make(types.MapStringSet)
packages := localDB.PkgCache()
// Mark explicit dependencies and enumerate the provides list
@ -478,7 +479,7 @@ func aurInfo(names []string, warnings *aurWarnings) ([]*rpc.Pkg, error) {
seen := make(map[string]int)
var mux sync.Mutex
var wg sync.WaitGroup
var errs MultiError
var errs types.MultiError
makeRequest := func(n, max int) {
defer wg.Done()
@ -496,7 +497,7 @@ func aurInfo(names []string, warnings *aurWarnings) ([]*rpc.Pkg, error) {
}
for n := 0; n < len(names); n += config.RequestSplitN {
max := min(len(names), n+config.RequestSplitN)
max := types.Min(len(names), n+config.RequestSplitN)
wg.Add(1)
go makeRequest(n, max)
}

View file

@ -7,6 +7,7 @@ import (
"unicode"
alpm "github.com/Jguer/go-alpm"
"github.com/Jguer/yay/v9/pkg/types"
rpc "github.com/mikkeloscar/aur"
)
@ -28,14 +29,14 @@ func (u upSlice) Less(i, j int) bool {
if u[i].Repository == u[j].Repository {
iRunes := []rune(u[i].Name)
jRunes := []rune(u[j].Name)
return lessRunes(iRunes, jRunes)
return types.LessRunes(iRunes, jRunes)
}
syncDB, err := alpmHandle.SyncDBs()
if err != nil {
iRunes := []rune(u[i].Repository)
jRunes := []rune(u[j].Repository)
return lessRunes(iRunes, jRunes)
return types.LessRunes(iRunes, jRunes)
}
less := false
@ -58,7 +59,7 @@ func (u upSlice) Less(i, j int) bool {
iRunes := []rune(u[i].Repository)
jRunes := []rune(u[j].Repository)
return lessRunes(iRunes, jRunes)
return types.LessRunes(iRunes, jRunes)
}
@ -120,7 +121,7 @@ func upList(warnings *aurWarnings) (upSlice, upSlice, error) {
var repoUp upSlice
var aurUp upSlice
var errs MultiError
var errs types.MultiError
aurdata := make(map[string]*rpc.Pkg)
@ -168,12 +169,12 @@ func upList(warnings *aurWarnings) (upSlice, upSlice, error) {
printLocalNewerThanAUR(remote, aurdata)
if develUp != nil {
names := make(stringSet)
names := make(types.StringSet)
for _, up := range develUp {
names.set(up.Name)
names.Set(up.Name)
}
for _, up := range aurUp {
if !names.get(up.Name) {
if !names.Get(up.Name) {
develUp = append(develUp, up)
}
}
@ -324,9 +325,9 @@ func upRepo(local []alpm.Package) (upSlice, error) {
}
// upgradePkgs handles updating the cache and installing updates.
func upgradePkgs(aurUp, repoUp upSlice) (stringSet, stringSet, error) {
ignore := make(stringSet)
aurNames := make(stringSet)
func upgradePkgs(aurUp, repoUp upSlice) (types.StringSet, types.StringSet, error) {
ignore := make(types.StringSet)
aurNames := make(types.StringSet)
allUpLen := len(repoUp) + len(aurUp)
if allUpLen == 0 {
@ -335,7 +336,7 @@ func upgradePkgs(aurUp, repoUp upSlice) (stringSet, stringSet, error) {
if !config.UpgradeMenu {
for _, pkg := range aurUp {
aurNames.set(pkg.Name)
aurNames.Set(pkg.Name)
}
return ignore, aurNames, nil
@ -358,37 +359,37 @@ func upgradePkgs(aurUp, repoUp upSlice) (stringSet, stringSet, error) {
//upgrade menu asks you which packages to NOT upgrade so in this case
//include and exclude are kind of swapped
//include, exclude, other := parseNumberMenu(string(numberBuf))
include, exclude, otherInclude, otherExclude := parseNumberMenu(numbers)
include, exclude, otherInclude, otherExclude := types.ParseNumberMenu(numbers)
isInclude := len(exclude) == 0 && len(otherExclude) == 0
for i, pkg := range repoUp {
if isInclude && otherInclude.get(pkg.Repository) {
ignore.set(pkg.Name)
if isInclude && otherInclude.Get(pkg.Repository) {
ignore.Set(pkg.Name)
}
if isInclude && !include.get(len(repoUp)-i+len(aurUp)) {
if isInclude && !include.Get(len(repoUp)-i+len(aurUp)) {
continue
}
if !isInclude && (exclude.get(len(repoUp)-i+len(aurUp)) || otherExclude.get(pkg.Repository)) {
if !isInclude && (exclude.Get(len(repoUp)-i+len(aurUp)) || otherExclude.Get(pkg.Repository)) {
continue
}
ignore.set(pkg.Name)
ignore.Set(pkg.Name)
}
for i, pkg := range aurUp {
if isInclude && otherInclude.get(pkg.Repository) {
if isInclude && otherInclude.Get(pkg.Repository) {
continue
}
if isInclude && !include.get(len(aurUp)-i) {
aurNames.set(pkg.Name)
if isInclude && !include.Get(len(aurUp)-i) {
aurNames.Set(pkg.Name)
}
if !isInclude && (exclude.get(len(aurUp)-i) || otherExclude.get(pkg.Repository)) {
aurNames.set(pkg.Name)
if !isInclude && (exclude.Get(len(aurUp)-i) || otherExclude.Get(pkg.Repository)) {
aurNames.Set(pkg.Name)
}
}

113
utils.go
View file

@ -2,90 +2,10 @@ package main
import (
"fmt"
"sync"
"unicode"
)
const gitEmptyTree = "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
type mapStringSet map[string]stringSet
type intRange struct {
min int
max int
}
func makeIntRange(min, max int) intRange {
return intRange{
min,
max,
}
}
func (r intRange) get(n int) bool {
return n >= r.min && n <= r.max
}
type intRanges []intRange
func (rs intRanges) get(n int) bool {
for _, r := range rs {
if r.get(n) {
return true
}
}
return false
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func max(a, b int) int {
if a < b {
return b
}
return a
}
func (mss mapStringSet) Add(n string, v string) {
_, ok := mss[n]
if !ok {
mss[n] = make(stringSet)
}
mss[n].set(v)
}
func lessRunes(iRunes, jRunes []rune) bool {
max := len(iRunes)
if max > len(jRunes) {
max = len(jRunes)
}
for idx := 0; idx < max; idx++ {
ir := iRunes[idx]
jr := jRunes[idx]
lir := unicode.ToLower(ir)
ljr := unicode.ToLower(jr)
if lir != ljr {
return lir < ljr
}
// the lowercase runes are the same, so compare the original
if ir != jr {
return ir < jr
}
}
return len(iRunes) < len(jRunes)
}
func stringSliceEqual(a, b []string) bool {
if a == nil && b == nil {
return true
@ -129,36 +49,3 @@ func removeInvalidTargets(targets []string) []string {
return filteredTargets
}
type MultiError struct {
Errors []error
mux sync.Mutex
}
func (err *MultiError) Error() string {
str := ""
for _, e := range err.Errors {
str += e.Error() + "\n"
}
return str[:len(str)-1]
}
func (err *MultiError) Add(e error) {
if e == nil {
return
}
err.mux.Lock()
err.Errors = append(err.Errors, e)
err.mux.Unlock()
}
func (err *MultiError) Return() error {
if len(err.Errors) > 0 {
return err
}
return nil
}

3
vcs.go
View file

@ -9,6 +9,7 @@ import (
"sync"
"time"
"github.com/Jguer/yay/v9/pkg/types"
gosrc "github.com/Morganamilo/go-srcinfo"
)
@ -37,7 +38,7 @@ func createDevelDB() error {
}
bases := getBases(info)
toSkip := pkgbuildsToSkip(bases, sliceToStringSet(remoteNames))
toSkip := pkgbuildsToSkip(bases, types.SliceToStringSet(remoteNames))
downloadPkgbuilds(bases, toSkip, config.BuildDir)
srcinfos, _ := parseSrcinfoFiles(bases, false)