From 005b29373d4d1820a567ab8e81fffe62d04ed75b Mon Sep 17 00:00:00 2001 From: jguer Date: Sat, 1 Aug 2020 01:20:00 +0200 Subject: [PATCH] fix(install): remove alpmHandle --- clean.go | 5 +- cmd.go | 15 +-- install.go | 54 ++++------ pkg/completion/completion.go | 27 ++--- pkg/db/alpm.go | 54 ++++++++++ pkg/db/executor.go | 16 ++- pkg/query/filter.go | 83 ++++----------- pkg/text/color.go | 2 +- pkg/text/print.go | 4 +- pkg/upgrade/upgrade.go | 111 +++++++++++++++++++ pkg/upgrade/upgrade_test.go | 67 ++++++++++++ print.go | 39 +------ upgrade.go | 199 ++++++----------------------------- upgrade_test.go | 67 ------------ vcs.go | 2 +- 15 files changed, 346 insertions(+), 399 deletions(-) create mode 100644 pkg/upgrade/upgrade.go create mode 100644 pkg/upgrade/upgrade_test.go delete mode 100644 upgrade_test.go diff --git a/clean.go b/clean.go index 02809230..4ed0b062 100644 --- a/clean.go +++ b/clean.go @@ -121,10 +121,7 @@ func cleanAUR(keepInstalled, keepCurrent, removeAll bool, alpmHandle *alpm.Handl installedBases := make(stringset.StringSet) inAURBases := make(stringset.StringSet) - remotePackages, _, err := query.GetRemotePackages(alpmHandle) - if err != nil { - return err - } + remotePackages, _ := query.GetRemotePackages(config.Runtime.DBExecutor) files, err := ioutil.ReadDir(config.BuildDir) if err != nil { diff --git a/cmd.go b/cmd.go index e83c491e..2d38e5c7 100644 --- a/cmd.go +++ b/cmd.go @@ -11,6 +11,7 @@ import ( "github.com/leonelquinteros/gotext" "github.com/Jguer/yay/v10/pkg/completion" + "github.com/Jguer/yay/v10/pkg/db" "github.com/Jguer/yay/v10/pkg/intrange" "github.com/Jguer/yay/v10/pkg/news" "github.com/Jguer/yay/v10/pkg/query" @@ -169,7 +170,7 @@ func handleCmd(cmdArgs *settings.Arguments, alpmHandle *alpm.Handle) error { case "G", "getpkgbuild": return handleGetpkgbuild(cmdArgs, alpmHandle) case "P", "show": - return handlePrint(cmdArgs, alpmHandle) + return handlePrint(cmdArgs, alpmHandle, config.Runtime.DBExecutor) case "Y", "--yay": return handleYay(cmdArgs, alpmHandle) } @@ -217,7 +218,7 @@ func lastBuildTime(alpmHandle *alpm.Handle) time.Time { return lastTime } -func handlePrint(cmdArgs *settings.Arguments, alpmHandle *alpm.Handle) (err error) { +func handlePrint(cmdArgs *settings.Arguments, alpmHandle *alpm.Handle, dbExecutor *db.AlpmExecutor) (err error) { switch { case cmdArgs.ExistsArg("d", "defaultconfig"): tmpConfig := settings.MakeConfig() @@ -232,9 +233,9 @@ func handlePrint(cmdArgs *settings.Arguments, alpmHandle *alpm.Handle) (err erro quiet := cmdArgs.ExistsArg("q", "quiet") err = news.PrintNewsFeed(lastBuildTime(alpmHandle), config.SortMode, double, quiet) case cmdArgs.ExistsDouble("c", "complete"): - err = completion.Show(alpmHandle, config.AURURL, config.Runtime.CompletionPath, config.CompletionInterval, true) + err = completion.Show(dbExecutor, config.AURURL, config.Runtime.CompletionPath, config.CompletionInterval, true) case cmdArgs.ExistsArg("c", "complete"): - err = completion.Show(alpmHandle, config.AURURL, config.Runtime.CompletionPath, config.CompletionInterval, false) + err = completion.Show(dbExecutor, config.AURURL, config.Runtime.CompletionPath, config.CompletionInterval, false) case cmdArgs.ExistsArg("s", "stats"): err = localStatistics(alpmHandle) default: @@ -295,10 +296,10 @@ func handleSync(cmdArgs *settings.Arguments, alpmHandle *alpm.Handle) error { return syncInfo(cmdArgs, targets, alpmHandle) } if cmdArgs.ExistsArg("u", "sysupgrade") { - return install(cmdArgs, alpmHandle, false) + return install(cmdArgs, config.Runtime.DBExecutor, false) } if len(cmdArgs.Targets) > 0 { - return install(cmdArgs, alpmHandle, false) + return install(cmdArgs, config.Runtime.DBExecutor, false) } if cmdArgs.ExistsArg("y", "refresh") { return show(passToPacman(cmdArgs)) @@ -426,7 +427,7 @@ func displayNumberMenu(pkgS []string, alpmHandle *alpm.Handle, cmdArgs *settings sudoLoopBackground() } - return install(arguments, alpmHandle, true) + return install(arguments, config.Runtime.DBExecutor, true) } func syncList(cmdArgs *settings.Arguments, alpmHandle *alpm.Handle) error { diff --git a/install.go b/install.go index 510aa8dd..45d45cca 100644 --- a/install.go +++ b/install.go @@ -15,6 +15,7 @@ import ( "github.com/leonelquinteros/gotext" "github.com/Jguer/yay/v10/pkg/completion" + "github.com/Jguer/yay/v10/pkg/db" "github.com/Jguer/yay/v10/pkg/dep" "github.com/Jguer/yay/v10/pkg/intrange" "github.com/Jguer/yay/v10/pkg/multierror" @@ -23,6 +24,7 @@ import ( "github.com/Jguer/yay/v10/pkg/settings" "github.com/Jguer/yay/v10/pkg/stringset" "github.com/Jguer/yay/v10/pkg/text" + "github.com/Jguer/yay/v10/pkg/upgrade" ) const gitEmptyTree = "4b825dc642cb6eb9a060e54bf8d69288fbee4904" @@ -60,12 +62,12 @@ func asexp(cmdArgs *settings.Arguments, pkgs []string) error { } // Install handles package installs -func install(cmdArgs *settings.Arguments, alpmHandle *alpm.Handle, ignoreProviders bool) (err error) { +func install(cmdArgs *settings.Arguments, dbExecutor *db.AlpmExecutor, ignoreProviders bool) (err error) { var incompatible stringset.StringSet var do *dep.Order - var aurUp upSlice - var repoUp upSlice + var aurUp upgrade.UpSlice + var repoUp upgrade.UpSlice var srcinfos map[string]*gosrc.Srcinfo @@ -80,7 +82,7 @@ func install(cmdArgs *settings.Arguments, alpmHandle *alpm.Handle, ignoreProvide } } } else if cmdArgs.ExistsArg("y", "refresh") || cmdArgs.ExistsArg("u", "sysupgrade") || len(cmdArgs.Targets) > 0 { - err = earlyPacmanCall(cmdArgs, alpmHandle) + err = earlyPacmanCall(cmdArgs, config.Runtime.DBExecutor) if err != nil { return err } @@ -89,17 +91,12 @@ func install(cmdArgs *settings.Arguments, alpmHandle *alpm.Handle, ignoreProvide // we may have done -Sy, our handle now has an old // database. - alpmHandle, err = initAlpmHandle(config.Runtime.PacmanConf, alpmHandle) - if err != nil { - return err - } - config.Runtime.AlpmHandle = alpmHandle err = config.Runtime.DBExecutor.RefreshHandle() if err != nil { return err } - localNames, remoteNames, err := query.GetPackageNamesBySource(alpmHandle) + localNames, remoteNames, err := query.GetPackageNamesBySource(dbExecutor) if err != nil { return err } @@ -122,7 +119,7 @@ func install(cmdArgs *settings.Arguments, alpmHandle *alpm.Handle, ignoreProvide // if we are doing -u also request all packages needing update if cmdArgs.ExistsArg("u", "sysupgrade") { - aurUp, repoUp, err = upList(warnings, alpmHandle, cmdArgs.ExistsDouble("u", "sysupgrade")) + aurUp, repoUp, err = upList(warnings, dbExecutor, cmdArgs.ExistsDouble("u", "sysupgrade")) if err != nil { return err } @@ -324,7 +321,7 @@ func install(cmdArgs *settings.Arguments, alpmHandle *alpm.Handle, ignoreProvide config.NoConfirm = oldValue } - incompatible, err = getIncompatible(do.Aur, srcinfos, alpmHandle) + incompatible, err = getIncompatible(do.Aur, srcinfos, dbExecutor) if err != nil { return err } @@ -369,14 +366,14 @@ func install(cmdArgs *settings.Arguments, alpmHandle *alpm.Handle, ignoreProvide } } - go exitOnError(completion.Update(alpmHandle, config.AURURL, config.Runtime.CompletionPath, config.CompletionInterval, false)) + go exitOnError(completion.Update(dbExecutor, config.AURURL, config.Runtime.CompletionPath, config.CompletionInterval, false)) err = downloadPkgbuildsSources(do.Aur, incompatible) if err != nil { return err } - err = buildInstallPkgbuilds(cmdArgs, alpmHandle, dp, do, srcinfos, incompatible, conflicts) + err = buildInstallPkgbuilds(cmdArgs, dbExecutor, dp, do, srcinfos, incompatible, conflicts) if err != nil { return err } @@ -403,7 +400,7 @@ func removeMake(do *dep.Order) error { return err } -func inRepos(syncDB alpm.DBList, pkg string) bool { +func inRepos(dbExecutor *db.AlpmExecutor, pkg string) bool { target := dep.ToTarget(pkg) if target.DB == "aur" { @@ -414,33 +411,25 @@ func inRepos(syncDB alpm.DBList, pkg string) bool { previousHideMenus := settings.HideMenus settings.HideMenus = false - _, err := syncDB.FindSatisfier(target.DepString()) + exists := dbExecutor.SyncSatisfierExists(target.DepString()) settings.HideMenus = previousHideMenus - if err == nil { - return true - } - return !syncDB.FindGroupPkgs(target.Name).Empty() + return exists || len(dbExecutor.PackagesFromGroup(target.Name)) > 0 } -func earlyPacmanCall(cmdArgs *settings.Arguments, alpmHandle *alpm.Handle) error { +func earlyPacmanCall(cmdArgs *settings.Arguments, dbExecutor *db.AlpmExecutor) error { arguments := cmdArgs.Copy() arguments.Op = "S" targets := cmdArgs.Targets cmdArgs.ClearTargets() arguments.ClearTargets() - syncDB, err := alpmHandle.SyncDBs() - if err != nil { - return err - } - if config.Runtime.Mode == settings.ModeRepo { arguments.Targets = targets } else { // separate aur and repo targets for _, target := range targets { - if inRepos(syncDB, target) { + if inRepos(dbExecutor, target) { arguments.AddTarget(target) } else { cmdArgs.AddTarget(target) @@ -449,8 +438,7 @@ func earlyPacmanCall(cmdArgs *settings.Arguments, alpmHandle *alpm.Handle) error } if cmdArgs.ExistsArg("y", "refresh") || cmdArgs.ExistsArg("u", "sysupgrade") || len(arguments.Targets) > 0 { - err = show(passToPacman(arguments)) - if err != nil { + if err := show(passToPacman(arguments)); err != nil { return errors.New(gotext.Get("error installing repo packages")) } } @@ -469,10 +457,10 @@ func earlyRefresh(cmdArgs *settings.Arguments) error { return show(passToPacman(arguments)) } -func getIncompatible(bases []dep.Base, srcinfos map[string]*gosrc.Srcinfo, alpmHandle *alpm.Handle) (stringset.StringSet, error) { +func getIncompatible(bases []dep.Base, srcinfos map[string]*gosrc.Srcinfo, dbExecutor *db.AlpmExecutor) (stringset.StringSet, error) { incompatible := make(stringset.StringSet) basesMap := make(map[string]dep.Base) - alpmArch, err := alpmHandle.Arch() + alpmArch, err := dbExecutor.AlpmArch() if err != nil { return nil, err } @@ -943,7 +931,7 @@ func downloadPkgbuildsSources(bases []dep.Base, incompatible stringset.StringSet func buildInstallPkgbuilds( cmdArgs *settings.Arguments, - alpmHandle *alpm.Handle, + dbExecutor *db.AlpmExecutor, dp *dep.Pool, do *dep.Order, srcinfos map[string]*gosrc.Srcinfo, @@ -968,7 +956,7 @@ func buildInstallPkgbuilds( config.NoConfirm = true //remotenames: names of all non repo packages on the system - localNames, remoteNames, err := query.GetPackageNamesBySource(alpmHandle) + localNames, remoteNames, err := query.GetPackageNamesBySource(dbExecutor) if err != nil { return err } diff --git a/pkg/completion/completion.go b/pkg/completion/completion.go index ecc8112e..fc6e79cc 100644 --- a/pkg/completion/completion.go +++ b/pkg/completion/completion.go @@ -12,12 +12,12 @@ import ( "strings" "time" - alpm "github.com/Jguer/go-alpm" + "github.com/Jguer/yay/v10/pkg/db" ) // Show provides completion info for shells -func Show(alpmHandle *alpm.Handle, aurURL, completionPath string, interval int, force bool) error { - err := Update(alpmHandle, aurURL, completionPath, interval, force) +func Show(dbExecutor *db.AlpmExecutor, aurURL, completionPath string, interval int, force bool) error { + err := Update(dbExecutor, aurURL, completionPath, interval, force) if err != nil { return err } @@ -33,7 +33,7 @@ func Show(alpmHandle *alpm.Handle, aurURL, completionPath string, interval int, } // Update updates completion cache to be used by Complete -func Update(alpmHandle *alpm.Handle, aurURL, completionPath string, interval int, force bool) error { +func Update(dbExecutor *db.AlpmExecutor, aurURL, completionPath string, interval int, force bool) error { info, err := os.Stat(completionPath) if os.IsNotExist(err) || (interval != -1 && time.Since(info.ModTime()).Hours() >= float64(interval*24)) || force { @@ -50,11 +50,7 @@ func Update(alpmHandle *alpm.Handle, aurURL, completionPath string, interval int defer os.Remove(completionPath) } - dbList, err := alpmHandle.SyncDBs() - if err != nil { - return err - } - erra := createRepoList(&dbList, out) + erra := createRepoList(dbExecutor, out) out.Close() return erra @@ -97,13 +93,12 @@ func createAURList(aurURL string, out io.Writer) error { } // CreatePackageList appends Repo packages to completion cache -func createRepoList(dbList *alpm.DBList, out io.Writer) error { - _ = dbList.ForEach(func(db alpm.DB) error { - _ = db.PkgCache().ForEach(func(pkg alpm.Package) error { - _, err := io.WriteString(out, pkg.Name()+"\t"+pkg.DB().Name()+"\n") +func createRepoList(dbExecutor *db.AlpmExecutor, out io.Writer) error { + for _, pkg := range dbExecutor.SyncPackages() { + _, err := io.WriteString(out, pkg.Name()+"\t"+pkg.DB().Name()+"\n") + if err != nil { return err - }) - return nil - }) + } + } return nil } diff --git a/pkg/db/alpm.go b/pkg/db/alpm.go index 72826043..1f47e955 100644 --- a/pkg/db/alpm.go +++ b/pkg/db/alpm.go @@ -8,6 +8,7 @@ import ( "github.com/leonelquinteros/gotext" "github.com/Jguer/yay/v10/pkg/text" + "github.com/Jguer/yay/v10/pkg/upgrade" ) type AlpmExecutor struct { @@ -176,6 +177,13 @@ func (ae *AlpmExecutor) LocalSatisfierExists(pkgName string) bool { return true } +func (ae *AlpmExecutor) SyncSatisfierExists(pkgName string) bool { + if _, err := ae.syncDB.FindSatisfier(pkgName); err != nil { + return false + } + return true +} + func (ae *AlpmExecutor) IsCorrectVersionInstalled(pkgName, versionRequired string) bool { alpmPackage := ae.localDB.Pkg(pkgName) if alpmPackage == nil { @@ -266,3 +274,49 @@ func (ae *AlpmExecutor) PackageGroups(pkg RepoPackage) []string { alpmPackage := pkg.(*alpm.Package) return alpmPackage.Groups().Slice() } + +// upRepo gathers local packages and checks if they have new versions. +// Output: Upgrade type package list. +func (ae *AlpmExecutor) RepoUpgrades(enableDowngrade bool) (upgrade.UpSlice, error) { + slice := upgrade.UpSlice{} + + localDB, err := ae.handle.LocalDB() + if err != nil { + return slice, err + } + + err = ae.handle.TransInit(alpm.TransFlagNoLock) + if err != nil { + return slice, err + } + + defer func() { + err = ae.handle.TransRelease() + }() + + err = ae.handle.SyncSysupgrade(enableDowngrade) + if err != nil { + return slice, err + } + _ = ae.handle.TransGetAdd().ForEach(func(pkg alpm.Package) error { + localVer := "-" + + if localPkg := localDB.Pkg(pkg.Name()); localPkg != nil { + localVer = localPkg.Version() + } + + slice = append(slice, upgrade.Upgrade{ + Name: pkg.Name(), + Repository: pkg.DB().Name(), + LocalVersion: localVer, + RemoteVersion: pkg.Version(), + }) + return nil + }) + + return slice, nil +} + +func (ae *AlpmExecutor) AlpmArch() (string, error) { + return ae.handle.Arch() +} diff --git a/pkg/db/executor.go b/pkg/db/executor.go index 0272e797..5002010f 100644 --- a/pkg/db/executor.go +++ b/pkg/db/executor.go @@ -1,13 +1,19 @@ package db -import alpm "github.com/Jguer/go-alpm" +import ( + "time" + + alpm "github.com/Jguer/go-alpm" +) type RepoPackage interface { Base() string - Name() string - Version() string + BuildDate() time.Time DB() *alpm.DB - ISize() int64 - Size() int64 Description() string + ISize() int64 + Name() string + ShouldIgnore() bool + Size() int64 + Version() string } diff --git a/pkg/query/filter.go b/pkg/query/filter.go index e54c786e..3c25d9b6 100644 --- a/pkg/query/filter.go +++ b/pkg/query/filter.go @@ -1,83 +1,46 @@ package query import ( - alpm "github.com/Jguer/go-alpm" "github.com/leonelquinteros/gotext" + "github.com/Jguer/yay/v10/pkg/db" "github.com/Jguer/yay/v10/pkg/settings" "github.com/Jguer/yay/v10/pkg/text" ) // GetPackageNamesBySource returns package names with and without correspondence in SyncDBS respectively -func GetPackageNamesBySource(alpmHandle *alpm.Handle) (local, remote []string, err error) { - localDB, err := alpmHandle.LocalDB() - if err != nil { - return nil, nil, err - } - dbList, err := alpmHandle.SyncDBs() - if err != nil { - return nil, nil, err - } - - err = localDB.PkgCache().ForEach(func(k alpm.Package) error { - found := false - // For each DB search for our secret package. - _ = dbList.ForEach(func(d alpm.DB) error { - if found { - return nil +func GetPackageNamesBySource(dbExecutor *db.AlpmExecutor) (local, remote []string, err error) { +outer: + for _, localpkg := range dbExecutor.LocalPackages() { + for _, syncpkg := range dbExecutor.SyncPackages() { + if localpkg.Name() == syncpkg.Name() { + local = append(local, localpkg.Name()) + continue outer } - - if d.Pkg(k.Name()) != nil { - found = true - local = append(local, k.Name()) - } - return nil - }) - if !found { - remote = append(remote, k.Name()) } - return nil - }) + remote = append(remote, localpkg.Name()) + } return local, remote, err } // GetRemotePackages returns packages with no correspondence in SyncDBS. -func GetRemotePackages(alpmHandle *alpm.Handle) ( - remote []alpm.Package, - remoteNames []string, - err error) { - localDB, err := alpmHandle.LocalDB() - if err != nil { - return - } - dbList, err := alpmHandle.SyncDBs() - if err != nil { - return - } +func GetRemotePackages(dbExecutor *db.AlpmExecutor) ( + []db.RepoPackage, + []string) { + remoteNames := []string{} + remote := []db.RepoPackage{} - f := func(k alpm.Package) error { - found := false - // For each DB search for our secret package. - _ = dbList.ForEach(func(d alpm.DB) error { - if found { - return nil +outer: + for _, localpkg := range dbExecutor.LocalPackages() { + for _, syncpkg := range dbExecutor.SyncPackages() { + if localpkg.Name() == syncpkg.Name() { + continue outer } - - if d.Pkg(k.Name()) != nil { - found = true - } - return nil - }) - - if !found { - remote = append(remote, k) - remoteNames = append(remoteNames, k.Name()) } - return nil + remote = append(remote, localpkg) + remoteNames = append(remoteNames, localpkg.Name()) } - - err = localDB.PkgCache().ForEach(f) - return remote, remoteNames, err + return remote, remoteNames } func RemoveInvalidTargets(targets []string, mode settings.TargetMode) []string { diff --git a/pkg/text/color.go b/pkg/text/color.go index a72085cb..c1cf253a 100644 --- a/pkg/text/color.go +++ b/pkg/text/color.go @@ -29,7 +29,7 @@ func Red(in string) string { return stylize(redCode, in) } -func green(in string) string { +func Green(in string) string { return stylize(greenCode, in) } diff --git a/pkg/text/print.go b/pkg/text/print.go index 0463c8ed..1897b3c3 100644 --- a/pkg/text/print.go +++ b/pkg/text/print.go @@ -28,11 +28,11 @@ func SprintOperationInfo(a ...interface{}) string { } func Info(a ...interface{}) { - fmt.Fprint(os.Stdout, append([]interface{}{Bold(green(arrow + " "))}, a...)...) + fmt.Fprint(os.Stdout, append([]interface{}{Bold(Green(arrow + " "))}, a...)...) } func Infoln(a ...interface{}) { - fmt.Fprintln(os.Stdout, append([]interface{}{Bold(green(arrow))}, a...)...) + fmt.Fprintln(os.Stdout, append([]interface{}{Bold(Green(arrow))}, a...)...) } func SprintWarn(a ...interface{}) string { diff --git a/pkg/upgrade/upgrade.go b/pkg/upgrade/upgrade.go new file mode 100644 index 00000000..a7bb5ae1 --- /dev/null +++ b/pkg/upgrade/upgrade.go @@ -0,0 +1,111 @@ +package upgrade + +import ( + "fmt" + "unicode" + + "github.com/Jguer/yay/v10/pkg/intrange" + "github.com/Jguer/yay/v10/pkg/text" +) + +// Upgrade type describes a system upgrade. +type Upgrade struct { + Name string + Repository string + LocalVersion string + RemoteVersion string +} + +func (u *Upgrade) StylizedNameWithRepository() string { + return text.Bold(text.ColorHash(u.Repository)) + "/" + text.Bold(u.Name) +} + +// upSlice is a slice of Upgrades +type UpSlice []Upgrade + +func (u UpSlice) Len() int { return len(u) } +func (u UpSlice) Swap(i, j int) { u[i], u[j] = u[j], u[i] } + +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 text.LessRunes(iRunes, jRunes) + } + + iRunes := []rune(u[i].Repository) + jRunes := []rune(u[j].Repository) + return text.LessRunes(iRunes, jRunes) +} + +func GetVersionDiff(oldVersion, newVersion string) (left, right string) { + if oldVersion == newVersion { + return oldVersion + text.Red(""), newVersion + text.Green("") + } + + diffPosition := 0 + + checkWords := func(str string, index int, words ...string) bool { + for _, word := range words { + wordLength := len(word) + nextIndex := index + 1 + if (index < len(str)-wordLength) && + (str[nextIndex:(nextIndex+wordLength)] == word) { + return true + } + } + return false + } + + for index, char := range oldVersion { + charIsSpecial := !(unicode.IsLetter(char) || unicode.IsNumber(char)) + + if (index >= len(newVersion)) || (char != rune(newVersion[index])) { + if charIsSpecial { + diffPosition = index + } + break + } + + if charIsSpecial || + (((index == len(oldVersion)-1) || (index == len(newVersion)-1)) && + ((len(oldVersion) != len(newVersion)) || + (oldVersion[index] == newVersion[index]))) || + checkWords(oldVersion, index, "rc", "pre", "alpha", "beta") { + diffPosition = index + 1 + } + } + + samePart := oldVersion[0:diffPosition] + + left = samePart + text.Red(oldVersion[diffPosition:]) + right = samePart + text.Green(newVersion[diffPosition:]) + + return left, right +} + +// Print prints the details of the packages to upgrade. +func (u UpSlice) Print() { + longestName, longestVersion := 0, 0 + for _, pack := range u { + packNameLen := len(pack.StylizedNameWithRepository()) + packVersion, _ := GetVersionDiff(pack.LocalVersion, pack.RemoteVersion) + packVersionLen := len(packVersion) + longestName = intrange.Max(packNameLen, longestName) + longestVersion = intrange.Max(packVersionLen, longestVersion) + } + + namePadding := fmt.Sprintf("%%-%ds ", longestName) + versionPadding := fmt.Sprintf("%%-%ds", longestVersion) + numberPadding := fmt.Sprintf("%%%dd ", len(fmt.Sprintf("%v", len(u)))) + + for k, i := range u { + left, right := GetVersionDiff(i.LocalVersion, i.RemoteVersion) + + fmt.Print(text.Magenta(fmt.Sprintf(numberPadding, len(u)-k))) + + fmt.Printf(namePadding, i.StylizedNameWithRepository()) + + fmt.Printf("%s -> %s\n", fmt.Sprintf(versionPadding, left), right) + } +} diff --git a/pkg/upgrade/upgrade_test.go b/pkg/upgrade/upgrade_test.go new file mode 100644 index 00000000..cf81f343 --- /dev/null +++ b/pkg/upgrade/upgrade_test.go @@ -0,0 +1,67 @@ +package upgrade + +import ( + "testing" + + "github.com/Jguer/yay/v10/pkg/text" +) + +func TestGetVersionDiff(t *testing.T) { + text.UseColor = true + + type versionPair struct { + Old string + New string + } + + in := []versionPair{ + {"1-1", "1-1"}, + {"1-1", "2-1"}, + {"2-1", "1-1"}, + {"1-1", "1-2"}, + {"1-2", "1-1"}, + {"1.2.3-1", "1.2.4-1"}, + {"1.8rc1+6+g0f377f94-1", "1.8rc1+1+g7e949283-1"}, + {"1.8rc1+6+g0f377f94-1", "1.8rc2+1+g7e949283-1"}, + {"1.8rc2", "1.9rc1"}, + {"2.99.917+812+g75795523-1", "2.99.917+823+gd9bf46e4-1"}, + {"1.2.9-1", "1.2.10-1"}, + {"1.2.10-1", "1.2.9-1"}, + {"1.2-1", "1.2.1-1"}, + {"1.2.1-1", "1.2-1"}, + {"0.7-4", "0.7+4+gd8d8c67-1"}, + {"1.0.2_r0-1", "1.0.2_r0-2"}, + {"1.0.2_r0-1", "1.0.2_r1-1"}, + {"1.0.2_r0-1", "1.0.3_r0-1"}, + } + + out := []versionPair{ + {"1-1" + text.Red(""), "1-1" + text.Green("")}, + {text.Red("1-1"), text.Green("2-1")}, + {text.Red("2-1"), text.Green("1-1")}, + {"1-" + text.Red("1"), "1-" + text.Green("2")}, + {"1-" + text.Red("2"), "1-" + text.Green("1")}, + {"1.2." + text.Red("3-1"), "1.2." + text.Green("4-1")}, + {"1.8rc1+" + text.Red("6+g0f377f94-1"), "1.8rc1+" + text.Green("1+g7e949283-1")}, + {"1.8" + text.Red("rc1+6+g0f377f94-1"), "1.8" + text.Green("rc2+1+g7e949283-1")}, + {"1." + text.Red("8rc2"), "1." + text.Green("9rc1")}, + {"2.99.917+" + text.Red("812+g75795523-1"), "2.99.917+" + text.Green("823+gd9bf46e4-1")}, + {"1.2." + text.Red("9-1"), "1.2." + text.Green("10-1")}, + {"1.2." + text.Red("10-1"), "1.2." + text.Green("9-1")}, + {"1.2" + text.Red("-1"), "1.2" + text.Green(".1-1")}, + {"1.2" + text.Red(".1-1"), "1.2" + text.Green("-1")}, + {"0.7" + text.Red("-4"), "0.7" + text.Green("+4+gd8d8c67-1")}, + {"1.0.2_r0-" + text.Red("1"), "1.0.2_r0-" + text.Green("2")}, + {"1.0.2_" + text.Red("r0-1"), "1.0.2_" + text.Green("r1-1")}, + {"1.0." + text.Red("2_r0-1"), "1.0." + text.Green("3_r0-1")}, + } + + for i, pair := range in { + o, n := GetVersionDiff(pair.Old, pair.New) + + if o != out[i].Old || n != out[i].New { + t.Errorf("Test %d failed for update: expected (%s => %s) got (%s => %s) %d %d %d %d", + i+1, in[i].Old, in[i].New, o, n, len(in[i].Old), len(in[i].New), len(o), len(n)) + } + } +} diff --git a/print.go b/print.go index 7a46dd09..0195ff30 100644 --- a/print.go +++ b/print.go @@ -12,7 +12,6 @@ import ( "github.com/Jguer/go-alpm" "github.com/Jguer/yay/v10/pkg/db" - "github.com/Jguer/yay/v10/pkg/intrange" "github.com/Jguer/yay/v10/pkg/query" "github.com/Jguer/yay/v10/pkg/settings" "github.com/Jguer/yay/v10/pkg/stringset" @@ -105,36 +104,6 @@ func (s repoQuery) printSearch(dbExecutor *db.AlpmExecutor) { // Pretty print a set of packages from the same package base. -func (u *upgrade) StylizedNameWithRepository() string { - return bold(text.ColorHash(u.Repository)) + "/" + bold(u.Name) -} - -// Print prints the details of the packages to upgrade. -func (u upSlice) print() { - longestName, longestVersion := 0, 0 - for _, pack := range u { - packNameLen := len(pack.StylizedNameWithRepository()) - packVersion, _ := getVersionDiff(pack.LocalVersion, pack.RemoteVersion) - packVersionLen := len(packVersion) - longestName = intrange.Max(packNameLen, longestName) - longestVersion = intrange.Max(packVersionLen, longestVersion) - } - - namePadding := fmt.Sprintf("%%-%ds ", longestName) - versionPadding := fmt.Sprintf("%%-%ds", longestVersion) - numberPadding := fmt.Sprintf("%%%dd ", len(fmt.Sprintf("%v", len(u)))) - - for k, i := range u { - left, right := getVersionDiff(i.LocalVersion, i.RemoteVersion) - - fmt.Print(magenta(fmt.Sprintf(numberPadding, len(u)-k))) - - fmt.Printf(namePadding, i.StylizedNameWithRepository()) - - fmt.Printf("%s -> %s\n", fmt.Sprintf(versionPadding, left), right) - } -} - // PrintInfo prints package info like pacman -Si. func PrintInfo(a *rpc.Pkg, extendedInfo bool) { text.PrintInfoValue(gotext.Get("Repository"), "aur") @@ -201,7 +170,7 @@ func localStatistics(alpmHandle *alpm.Handle) error { return err } - _, remoteNames, err := query.GetPackageNamesBySource(alpmHandle) + _, remoteNames, err := query.GetPackageNamesBySource(config.Runtime.DBExecutor) if err != nil { return err } @@ -227,7 +196,7 @@ func printNumberOfUpdates(alpmHandle *alpm.Handle, enableDowngrade bool) error { warnings := query.NewWarnings() old := os.Stdout // keep backup of the real stdout os.Stdout = nil - aurUp, repoUp, err := upList(warnings, alpmHandle, enableDowngrade) + aurUp, repoUp, err := upList(warnings, config.Runtime.DBExecutor, enableDowngrade) os.Stdout = old // restoring the real stdout if err != nil { return err @@ -243,12 +212,12 @@ func printUpdateList(cmdArgs *settings.Arguments, alpmHandle *alpm.Handle, enabl warnings := query.NewWarnings() old := os.Stdout // keep backup of the real stdout os.Stdout = nil - localNames, remoteNames, err := query.GetPackageNamesBySource(alpmHandle) + localNames, remoteNames, err := query.GetPackageNamesBySource(config.Runtime.DBExecutor) if err != nil { return err } - aurUp, repoUp, err := upList(warnings, alpmHandle, enableDowngrade) + aurUp, repoUp, err := upList(warnings, config.Runtime.DBExecutor, enableDowngrade) os.Stdout = old // restoring the real stdout if err != nil { return err diff --git a/upgrade.go b/upgrade.go index 4357e8f2..ae7e5a21 100644 --- a/upgrade.go +++ b/upgrade.go @@ -5,15 +5,16 @@ import ( "sort" "strings" "sync" - "unicode" alpm "github.com/Jguer/go-alpm" "github.com/leonelquinteros/gotext" + "github.com/Jguer/yay/v10/pkg/db" "github.com/Jguer/yay/v10/pkg/intrange" "github.com/Jguer/yay/v10/pkg/query" "github.com/Jguer/yay/v10/pkg/settings" "github.com/Jguer/yay/v10/pkg/text" + "github.com/Jguer/yay/v10/pkg/upgrade" rpc "github.com/mikkeloscar/aur" @@ -21,112 +22,12 @@ import ( "github.com/Jguer/yay/v10/pkg/stringset" ) -// upgrade type describes a system upgrade. -type upgrade struct { - Name string - Repository string - LocalVersion string - RemoteVersion string -} - -// upSlice is a slice of Upgrades -type upSlice []upgrade - -func (u upSlice) Len() int { return len(u) } -func (u upSlice) Swap(i, j int) { u[i], u[j] = u[j], u[i] } - -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 text.LessRunes(iRunes, jRunes) - } - - syncDB, err := config.Runtime.AlpmHandle.SyncDBs() - if err != nil { - iRunes := []rune(u[i].Repository) - jRunes := []rune(u[j].Repository) - return text.LessRunes(iRunes, jRunes) - } - - less := false - found := syncDB.ForEach(func(db alpm.DB) error { - switch db.Name() { - case u[i].Repository: - less = true - case u[j].Repository: - less = false - default: - return nil - } - - return fmt.Errorf("") - }) - - if found != nil { - return less - } - - iRunes := []rune(u[i].Repository) - jRunes := []rune(u[j].Repository) - return text.LessRunes(iRunes, jRunes) -} - -func getVersionDiff(oldVersion, newVersion string) (left, right string) { - if oldVersion == newVersion { - return oldVersion + red(""), newVersion + green("") - } - - diffPosition := 0 - - checkWords := func(str string, index int, words ...string) bool { - for _, word := range words { - wordLength := len(word) - nextIndex := index + 1 - if (index < len(str)-wordLength) && - (str[nextIndex:(nextIndex+wordLength)] == word) { - return true - } - } - return false - } - - for index, char := range oldVersion { - charIsSpecial := !(unicode.IsLetter(char) || unicode.IsNumber(char)) - - if (index >= len(newVersion)) || (char != rune(newVersion[index])) { - if charIsSpecial { - diffPosition = index - } - break - } - - if charIsSpecial || - (((index == len(oldVersion)-1) || (index == len(newVersion)-1)) && - ((len(oldVersion) != len(newVersion)) || - (oldVersion[index] == newVersion[index]))) || - checkWords(oldVersion, index, "rc", "pre", "alpha", "beta") { - diffPosition = index + 1 - } - } - - samePart := oldVersion[0:diffPosition] - - left = samePart + red(oldVersion[diffPosition:]) - right = samePart + green(newVersion[diffPosition:]) - - return left, right -} - // upList returns lists of packages to upgrade from each source. -func upList(warnings *query.AURWarnings, alpmHandle *alpm.Handle, enableDowngrade bool) (aurUp, repoUp upSlice, err error) { - remote, remoteNames, err := query.GetRemotePackages(alpmHandle) - if err != nil { - return nil, nil, err - } +func upList(warnings *query.AURWarnings, dbExecutor *db.AlpmExecutor, enableDowngrade bool) (aurUp, repoUp upgrade.UpSlice, err error) { + remote, remoteNames := query.GetRemotePackages(dbExecutor) var wg sync.WaitGroup - var develUp upSlice + var develUp upgrade.UpSlice var errs multierror.MultiError aurdata := make(map[string]*rpc.Pkg) @@ -141,7 +42,7 @@ func upList(warnings *query.AURWarnings, alpmHandle *alpm.Handle, enableDowngrad text.OperationInfoln(gotext.Get("Searching databases for updates...")) wg.Add(1) go func() { - repoUp, err = upRepo(alpmHandle, enableDowngrade) + repoUp, err = dbExecutor.RepoUpgrades(enableDowngrade) errs.Add(err) wg.Done() }() @@ -196,8 +97,8 @@ func upList(warnings *query.AURWarnings, alpmHandle *alpm.Handle, enableDowngrad return aurUp, repoUp, errs.Return() } -func upDevel(remote []alpm.Package, aurdata map[string]*rpc.Pkg) upSlice { - toUpdate := make([]alpm.Package, 0) +func upDevel(remote []db.RepoPackage, aurdata map[string]*rpc.Pkg) upgrade.UpSlice { + toUpdate := make([]db.RepoPackage, 0) toRemove := make([]string, 0) var mux1 sync.Mutex @@ -232,12 +133,16 @@ func upDevel(remote []alpm.Package, aurdata map[string]*rpc.Pkg) upSlice { wg.Wait() - toUpgrade := make(upSlice, 0, len(toUpdate)) + toUpgrade := make(upgrade.UpSlice, 0, len(toUpdate)) for _, pkg := range toUpdate { if pkg.ShouldIgnore() { printIgnoringPackage(pkg, "latest-commit") } else { - toUpgrade = append(toUpgrade, upgrade{pkg.Name(), "devel", pkg.Version(), "latest-commit"}) + toUpgrade = append(toUpgrade, + upgrade.Upgrade{Name: pkg.Name(), + Repository: "devel", + LocalVersion: pkg.Version(), + RemoteVersion: "latest-commit"}) } } @@ -245,10 +150,19 @@ func upDevel(remote []alpm.Package, aurdata map[string]*rpc.Pkg) upSlice { return toUpgrade } +func printIgnoringPackage(pkg db.RepoPackage, newPkgVersion string) { + left, right := upgrade.GetVersionDiff(pkg.Version(), newPkgVersion) + + text.Warnln(gotext.Get("%s: ignoring package upgrade (%s => %s)", + cyan(pkg.Name()), + left, right, + )) +} + // upAUR gathers foreign packages and checks if they have new versions. // Output: Upgrade type package list. -func upAUR(remote []alpm.Package, aurdata map[string]*rpc.Pkg) upSlice { - toUpgrade := make(upSlice, 0) +func upAUR(remote []db.RepoPackage, aurdata map[string]*rpc.Pkg) upgrade.UpSlice { + toUpgrade := make(upgrade.UpSlice, 0) for _, pkg := range remote { aurPkg, ok := aurdata[pkg.Name()] @@ -261,7 +175,7 @@ func upAUR(remote []alpm.Package, aurdata map[string]*rpc.Pkg) upSlice { if pkg.ShouldIgnore() { printIgnoringPackage(pkg, aurPkg.Version) } else { - toUpgrade = append(toUpgrade, upgrade{aurPkg.Name, "aur", pkg.Version(), aurPkg.Version}) + toUpgrade = append(toUpgrade, upgrade.Upgrade{Name: aurPkg.Name, Repository: "aur", LocalVersion: pkg.Version(), RemoteVersion: aurPkg.Version}) } } } @@ -269,24 +183,15 @@ func upAUR(remote []alpm.Package, aurdata map[string]*rpc.Pkg) upSlice { return toUpgrade } -func printIgnoringPackage(pkg alpm.Package, newPkgVersion string) { - left, right := getVersionDiff(pkg.Version(), newPkgVersion) - - text.Warnln(gotext.Get("%s: ignoring package upgrade (%s => %s)", - cyan(pkg.Name()), - left, right, - )) -} - func printLocalNewerThanAUR( - remote []alpm.Package, aurdata map[string]*rpc.Pkg) { + remote []db.RepoPackage, aurdata map[string]*rpc.Pkg) { for _, pkg := range remote { aurPkg, ok := aurdata[pkg.Name()] if !ok { continue } - left, right := getVersionDiff(pkg.Version(), aurPkg.Version) + left, right := upgrade.GetVersionDiff(pkg.Version(), aurPkg.Version) if !isDevelPackage(pkg) && alpm.VerCmp(pkg.Version(), aurPkg.Version) > 0 { text.Warnln(gotext.Get("%s: local (%s) is newer than AUR (%s)", @@ -307,54 +212,12 @@ func isDevelName(name string) bool { return strings.Contains(name, "-always-") } -func isDevelPackage(pkg alpm.Package) bool { +func isDevelPackage(pkg db.RepoPackage) bool { return isDevelName(pkg.Name()) || isDevelName(pkg.Base()) } -// upRepo gathers local packages and checks if they have new versions. -// Output: Upgrade type package list. -func upRepo(alpmHandle *alpm.Handle, enableDowngrade bool) (upSlice, error) { - slice := upSlice{} - - localDB, err := alpmHandle.LocalDB() - if err != nil { - return slice, err - } - - err = alpmHandle.TransInit(alpm.TransFlagNoLock) - if err != nil { - return slice, err - } - - defer func() { - err = alpmHandle.TransRelease() - }() - - err = alpmHandle.SyncSysupgrade(enableDowngrade) - if err != nil { - return slice, err - } - _ = alpmHandle.TransGetAdd().ForEach(func(pkg alpm.Package) error { - localVer := "-" - - if localPkg := localDB.Pkg(pkg.Name()); localPkg != nil { - localVer = localPkg.Version() - } - - slice = append(slice, upgrade{ - pkg.Name(), - pkg.DB().Name(), - localVer, - pkg.Version(), - }) - return nil - }) - - return slice, nil -} - // upgradePkgs handles updating the cache and installing updates. -func upgradePkgs(aurUp, repoUp upSlice) (ignore, aurNames stringset.StringSet, err error) { +func upgradePkgs(aurUp, repoUp upgrade.UpSlice) (ignore, aurNames stringset.StringSet, err error) { ignore = make(stringset.StringSet) aurNames = make(stringset.StringSet) @@ -375,7 +238,7 @@ func upgradePkgs(aurUp, repoUp upSlice) (ignore, aurNames stringset.StringSet, e sort.Sort(aurUp) allUp := append(repoUp, aurUp...) fmt.Printf("%s"+bold(" %d ")+"%s\n", bold(cyan("::")), allUpLen, bold(gotext.Get("Packages to upgrade."))) - allUp.print() + allUp.Print() text.Infoln(gotext.Get("Packages to exclude: (eg: \"1 2 3\", \"1-3\", \"^4\" or repo name)")) diff --git a/upgrade_test.go b/upgrade_test.go deleted file mode 100644 index df9253eb..00000000 --- a/upgrade_test.go +++ /dev/null @@ -1,67 +0,0 @@ -package main - -import ( - "testing" - - "github.com/Jguer/yay/v10/pkg/text" -) - -func TestGetVersionDiff(t *testing.T) { - text.UseColor = true - - type versionPair struct { - Old string - New string - } - - in := []versionPair{ - {"1-1", "1-1"}, - {"1-1", "2-1"}, - {"2-1", "1-1"}, - {"1-1", "1-2"}, - {"1-2", "1-1"}, - {"1.2.3-1", "1.2.4-1"}, - {"1.8rc1+6+g0f377f94-1", "1.8rc1+1+g7e949283-1"}, - {"1.8rc1+6+g0f377f94-1", "1.8rc2+1+g7e949283-1"}, - {"1.8rc2", "1.9rc1"}, - {"2.99.917+812+g75795523-1", "2.99.917+823+gd9bf46e4-1"}, - {"1.2.9-1", "1.2.10-1"}, - {"1.2.10-1", "1.2.9-1"}, - {"1.2-1", "1.2.1-1"}, - {"1.2.1-1", "1.2-1"}, - {"0.7-4", "0.7+4+gd8d8c67-1"}, - {"1.0.2_r0-1", "1.0.2_r0-2"}, - {"1.0.2_r0-1", "1.0.2_r1-1"}, - {"1.0.2_r0-1", "1.0.3_r0-1"}, - } - - out := []versionPair{ - {"1-1" + red(""), "1-1" + green("")}, - {red("1-1"), green("2-1")}, - {red("2-1"), green("1-1")}, - {"1-" + red("1"), "1-" + green("2")}, - {"1-" + red("2"), "1-" + green("1")}, - {"1.2." + red("3-1"), "1.2." + green("4-1")}, - {"1.8rc1+" + red("6+g0f377f94-1"), "1.8rc1+" + green("1+g7e949283-1")}, - {"1.8" + red("rc1+6+g0f377f94-1"), "1.8" + green("rc2+1+g7e949283-1")}, - {"1." + red("8rc2"), "1." + green("9rc1")}, - {"2.99.917+" + red("812+g75795523-1"), "2.99.917+" + green("823+gd9bf46e4-1")}, - {"1.2." + red("9-1"), "1.2." + green("10-1")}, - {"1.2." + red("10-1"), "1.2." + green("9-1")}, - {"1.2" + red("-1"), "1.2" + green(".1-1")}, - {"1.2" + red(".1-1"), "1.2" + green("-1")}, - {"0.7" + red("-4"), "0.7" + green("+4+gd8d8c67-1")}, - {"1.0.2_r0-" + red("1"), "1.0.2_r0-" + green("2")}, - {"1.0.2_" + red("r0-1"), "1.0.2_" + green("r1-1")}, - {"1.0." + red("2_r0-1"), "1.0." + green("3_r0-1")}, - } - - for i, pair := range in { - o, n := getVersionDiff(pair.Old, pair.New) - - if o != out[i].Old || n != out[i].New { - t.Errorf("Test %d failed for update: expected (%s => %s) got (%s => %s) %d %d %d %d", - i+1, in[i].Old, in[i].New, o, n, len(in[i].Old), len(in[i].New), len(o), len(n)) - } - } -} diff --git a/vcs.go b/vcs.go index 189f8009..e1c1c193 100644 --- a/vcs.go +++ b/vcs.go @@ -36,7 +36,7 @@ func createDevelDB(vcsFilePath string, alpmHandle *alpm.Handle) error { var mux sync.Mutex var wg sync.WaitGroup - _, remoteNames, err := query.GetPackageNamesBySource(alpmHandle) + _, remoteNames, err := query.GetPackageNamesBySource(config.Runtime.DBExecutor) if err != nil { return err }