mirror of
https://github.com/Jguer/yay
synced 2024-09-06 16:43:03 +00:00
![morganamilo](/assets/img/avatar_default.png)
Now that we are using alpm to fetch packages it generates these mesages and we can not control the format. So change out format to match.
407 lines
8.8 KiB
Go
407 lines
8.8 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
"sync"
|
|
"unicode"
|
|
|
|
alpm "github.com/jguer/go-alpm"
|
|
rpc "github.com/mikkeloscar/aur"
|
|
)
|
|
|
|
// 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 lessRunes(iRunes, jRunes)
|
|
}
|
|
|
|
syncDb, err := alpmHandle.SyncDbs()
|
|
if err != nil {
|
|
iRunes := []rune(u[i].Repository)
|
|
jRunes := []rune(u[j].Repository)
|
|
return lessRunes(iRunes, jRunes)
|
|
}
|
|
|
|
less := false
|
|
found := syncDb.ForEach(func(db alpm.Db) error {
|
|
if db.Name() == u[i].Repository {
|
|
less = true
|
|
} else if db.Name() == u[j].Repository {
|
|
less = false
|
|
} else {
|
|
return nil
|
|
}
|
|
|
|
return fmt.Errorf("")
|
|
})
|
|
|
|
if found != nil {
|
|
return less
|
|
}
|
|
|
|
iRunes := []rune(u[i].Repository)
|
|
jRunes := []rune(u[j].Repository)
|
|
return lessRunes(iRunes, jRunes)
|
|
|
|
}
|
|
|
|
func getVersionDiff(oldVersion, newVersion string) (left, right string) {
|
|
if oldVersion == newVersion {
|
|
return oldVersion, newVersion
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
// upList returns lists of packages to upgrade from each source.
|
|
func upList(warnings *aurWarnings) (aurUp upSlice, repoUp upSlice, err error) {
|
|
local, remote, _, remoteNames, err := filterPackages()
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
var wg sync.WaitGroup
|
|
var develUp upSlice
|
|
|
|
var repoErr error
|
|
var aurErr error
|
|
var develErr error
|
|
|
|
pkgdata := make(map[string]*rpc.Pkg)
|
|
|
|
if mode == ModeAny || mode == ModeRepo {
|
|
fmt.Println(bold(cyan("::") + bold(" Searching databases for updates...")))
|
|
wg.Add(1)
|
|
go func() {
|
|
repoUp, repoErr = upRepo(local)
|
|
wg.Done()
|
|
}()
|
|
}
|
|
|
|
if mode == ModeAny || mode == ModeAUR {
|
|
fmt.Println(bold(cyan("::") + bold(" Searching AUR for updates...")))
|
|
wg.Add(1)
|
|
go func() {
|
|
aurUp, aurErr = upAUR(remote, remoteNames, pkgdata, warnings)
|
|
wg.Done()
|
|
}()
|
|
|
|
if config.Devel {
|
|
fmt.Println(bold(cyan("::") + bold(" Checking development packages...")))
|
|
wg.Add(1)
|
|
go func() {
|
|
develUp, develErr = upDevel(remote)
|
|
wg.Done()
|
|
}()
|
|
}
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
printLocalNewerThanAUR(remote, pkgdata)
|
|
|
|
errs := make([]string, 0)
|
|
for _, e := range []error{repoErr, aurErr, develErr} {
|
|
if e != nil {
|
|
errs = append(errs, e.Error())
|
|
}
|
|
}
|
|
|
|
if len(errs) > 0 {
|
|
err = fmt.Errorf("%s", strings.Join(errs, "\n"))
|
|
return nil, nil, err
|
|
}
|
|
|
|
if develUp != nil {
|
|
names := make(stringSet)
|
|
for _, up := range develUp {
|
|
names.set(up.Name)
|
|
}
|
|
for _, up := range aurUp {
|
|
if !names.get(up.Name) {
|
|
develUp = append(develUp, up)
|
|
}
|
|
}
|
|
|
|
aurUp = develUp
|
|
}
|
|
|
|
return aurUp, repoUp, err
|
|
}
|
|
|
|
func upDevel(remote []alpm.Package) (toUpgrade upSlice, err error) {
|
|
toUpdate := make([]alpm.Package, 0)
|
|
toRemove := make([]string, 0)
|
|
|
|
var mux1 sync.Mutex
|
|
var mux2 sync.Mutex
|
|
var wg sync.WaitGroup
|
|
|
|
checkUpdate := func(vcsName string, e shaInfos) {
|
|
defer wg.Done()
|
|
|
|
if e.needsUpdate() {
|
|
for _, pkg := range remote {
|
|
if pkg.Name() == vcsName {
|
|
mux1.Lock()
|
|
toUpdate = append(toUpdate, pkg)
|
|
mux1.Unlock()
|
|
return
|
|
}
|
|
}
|
|
|
|
mux2.Lock()
|
|
toRemove = append(toRemove, vcsName)
|
|
mux2.Unlock()
|
|
}
|
|
}
|
|
|
|
for vcsName, e := range savedInfo {
|
|
wg.Add(1)
|
|
go checkUpdate(vcsName, e)
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
for _, pkg := range toUpdate {
|
|
if pkg.ShouldIgnore() {
|
|
printIgnoringPackage(pkg, "latest-commit")
|
|
} else {
|
|
toUpgrade = append(toUpgrade, upgrade{pkg.Name(), "devel", pkg.Version(), "latest-commit"})
|
|
}
|
|
}
|
|
|
|
removeVCSPackage(toRemove)
|
|
return
|
|
}
|
|
|
|
// upAUR gathers foreign packages and checks if they have new versions.
|
|
// Output: Upgrade type package list.
|
|
func upAUR(
|
|
remote []alpm.Package, remoteNames []string,
|
|
pkgdata map[string]*rpc.Pkg, warnings *aurWarnings) (upSlice, error) {
|
|
|
|
toUpgrade := make(upSlice, 0)
|
|
_pkgdata, err := aurInfo(remoteNames, warnings)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, pkg := range _pkgdata {
|
|
pkgdata[pkg.Name] = pkg
|
|
}
|
|
|
|
for _, pkg := range remote {
|
|
aurPkg, ok := pkgdata[pkg.Name()]
|
|
if !ok {
|
|
continue
|
|
}
|
|
|
|
if (config.TimeUpdate && (int64(aurPkg.LastModified) > pkg.BuildDate().Unix())) ||
|
|
(alpm.VerCmp(pkg.Version(), aurPkg.Version) < 0) {
|
|
if pkg.ShouldIgnore() {
|
|
printIgnoringPackage(pkg, aurPkg.Version)
|
|
} else {
|
|
toUpgrade = append(toUpgrade, upgrade{aurPkg.Name, "aur", pkg.Version(), aurPkg.Version})
|
|
}
|
|
}
|
|
}
|
|
|
|
return toUpgrade, nil
|
|
}
|
|
|
|
func printIgnoringPackage(pkg alpm.Package, newPkgVersion string) {
|
|
left, right := getVersionDiff(pkg.Version(), newPkgVersion)
|
|
|
|
fmt.Printf("%s %s: ignoring package upgrade (%s => %s)\n",
|
|
yellow(bold(smallArrow)),
|
|
cyan(pkg.Name()),
|
|
left, right,
|
|
)
|
|
}
|
|
|
|
func printLocalNewerThanAUR(
|
|
remote []alpm.Package, pkgdata map[string]*rpc.Pkg) {
|
|
for _, pkg := range remote {
|
|
aurPkg, ok := pkgdata[pkg.Name()]
|
|
if !ok {
|
|
continue
|
|
}
|
|
|
|
left, right := getVersionDiff(pkg.Version(), aurPkg.Version)
|
|
|
|
if !isDevelName(pkg.Name()) && alpm.VerCmp(pkg.Version(), aurPkg.Version) > 0 {
|
|
fmt.Printf("%s %s: local (%s) is newer than AUR (%s)\n",
|
|
yellow(bold(smallArrow)),
|
|
cyan(pkg.Name()),
|
|
left, right,
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
// upRepo gathers local packages and checks if they have new versions.
|
|
// Output: Upgrade type package list.
|
|
func upRepo(local []alpm.Package) (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 alpmHandle.TransRelease()
|
|
|
|
alpmHandle.SyncSysupgrade(cmdArgs.existsDouble("u", "sysupgrade"))
|
|
alpmHandle.TransGetAdd().ForEach(func(pkg alpm.Package) error {
|
|
localPkg, err := localDB.PkgByName(pkg.Name())
|
|
localVer := "-"
|
|
|
|
if err == 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) (stringSet, stringSet, error) {
|
|
ignore := make(stringSet)
|
|
aurNames := make(stringSet)
|
|
|
|
allUpLen := len(repoUp) + len(aurUp)
|
|
if allUpLen == 0 {
|
|
return ignore, aurNames, nil
|
|
}
|
|
|
|
if !config.UpgradeMenu {
|
|
for _, pkg := range aurUp {
|
|
aurNames.set(pkg.Name)
|
|
}
|
|
|
|
return ignore, aurNames, nil
|
|
}
|
|
|
|
sort.Sort(repoUp)
|
|
sort.Sort(aurUp)
|
|
allUp := append(repoUp, aurUp...)
|
|
fmt.Printf("%s"+bold(" %d ")+"%s\n", bold(cyan("::")), allUpLen, bold("Packages to upgrade."))
|
|
allUp.print()
|
|
|
|
fmt.Println(bold(green(arrow + " Packages to not upgrade: (eg: 1 2 3, 1-3, ^4 or repo name)")))
|
|
fmt.Print(bold(green(arrow + " ")))
|
|
|
|
numbers, err := getInput(config.AnswerUpgrade)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
//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)
|
|
|
|
isInclude := len(exclude) == 0 && len(otherExclude) == 0
|
|
|
|
for i, pkg := range repoUp {
|
|
if isInclude && otherInclude.get(pkg.Repository) {
|
|
ignore.set(pkg.Name)
|
|
}
|
|
|
|
if isInclude && !include.get(len(repoUp)-i+len(aurUp)) {
|
|
continue
|
|
}
|
|
|
|
if !isInclude && (exclude.get(len(repoUp)-i+len(aurUp)) || otherExclude.get(pkg.Repository)) {
|
|
continue
|
|
}
|
|
|
|
ignore.set(pkg.Name)
|
|
}
|
|
|
|
for i, pkg := range aurUp {
|
|
if isInclude && otherInclude.get(pkg.Repository) {
|
|
continue
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|
|
|
|
return ignore, aurNames, err
|
|
}
|