yay/print.go
morganamilo 55bfd619dc
Improve printing
Add ( and ) to "installed" to match groups and out of date
Show popularity as well as voted in yogurt mode
Show download and install size in yogurt mode
Remove printing of white and black
Fix incorrect message on number menu
Yellow is now almost never used
Use `v` instead of `r` when printing version
show when a page was marked out of date on search and info
2018-03-02 20:32:33 +00:00

379 lines
8.9 KiB
Go

package main
import (
"fmt"
"os"
"strconv"
"strings"
"time"
alpm "github.com/jguer/go-alpm"
rpc "github.com/mikkeloscar/aur"
)
const arrow = "==>"
// Human returns results in Human readable format.
func human(size int64) string {
floatsize := float32(size)
units := [...]string{"", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi"}
for _, unit := range units {
if floatsize < 1024 {
return fmt.Sprintf("%.1f %sB", floatsize, unit)
}
floatsize /= 1024
}
return fmt.Sprintf("%d%s", size, "B")
}
// PrintSearch handles printing search results in a given format
func (q aurQuery) printSearch(start int) {
localDb, _ := alpmHandle.LocalDb()
for i, res := range q {
var toprint string
if config.SearchMode == NumberMenu {
if config.SortMode == BottomUp {
toprint += magenta(strconv.Itoa(len(q)+start-i-1) + " ")
} else {
toprint += magenta(strconv.Itoa(start+i) + " ")
}
} else if config.SearchMode == Minimal {
fmt.Println(res.Name)
continue
}
toprint += bold(colourHash("aur")) + "/" + bold(res.Name) +
" " + cyan(res.Version) +
bold(" (+"+strconv.Itoa(res.NumVotes)) +
" " + bold(strconv.FormatFloat(res.Popularity, 'f', 2, 64)+"%) ")
if res.Maintainer == "" {
toprint += bold(red("(Orphaned)")) + " "
}
if res.OutOfDate != 0 {
toprint += bold(red("(Out-of-date "+formatTime(res.OutOfDate)+")")) + " "
}
if _, err := localDb.PkgByName(res.Name); err == nil {
toprint += bold(green("(Installed)"))
}
toprint += "\n " + res.Description
fmt.Println(toprint)
}
}
//PrintSearch receives a RepoSearch type and outputs pretty text.
func (s repoQuery) printSearch() {
for i, res := range s {
var toprint string
if config.SearchMode == NumberMenu {
if config.SortMode == BottomUp {
toprint += magenta(strconv.Itoa(len(s)-i) + " ")
} else {
toprint += magenta(strconv.Itoa(i+1) + " ")
}
} else if config.SearchMode == Minimal {
fmt.Println(res.Name())
continue
}
toprint += bold(colourHash(res.DB().Name())) + "/" + bold(res.Name()) +
" " + cyan(res.Version()) +
bold(" ("+human(res.Size())+
" "+human(res.ISize())+") ")
if len(res.Groups().Slice()) != 0 {
toprint += fmt.Sprint(res.Groups().Slice(), " ")
}
localDb, err := alpmHandle.LocalDb()
if err == nil {
if _, err = localDb.PkgByName(res.Name()); err == nil {
toprint += bold(green("(Installed)"))
}
}
toprint += "\n " + res.Description()
fmt.Println(toprint)
}
}
func formatPkgbase(pkg *rpc.Pkg, bases map[string][]*rpc.Pkg) string {
str := pkg.PackageBase
if len(bases[pkg.PackageBase]) > 1 || pkg.PackageBase != pkg.Name {
str2 := " ("
for _, split := range bases[pkg.PackageBase] {
str2 += split.Name + " "
}
str2 = str2[:len(str2)-1] + ")"
str += str2
}
return str
}
// printDownloadsFromRepo prints repository packages to be downloaded
func printDepCatagories(dc *depCatagories) {
repo := ""
repoMake := ""
aur := ""
aurMake := ""
repoLen := 0
repoMakeLen := 0
aurLen := 0
aurMakeLen := 0
for _, pkg := range dc.Repo {
if dc.MakeOnly.get(pkg.Name()) {
repoMake += " " + pkg.Name()
repoMakeLen++
} else {
repo += " " + pkg.Name()
repoLen++
}
}
for _, pkg := range dc.Aur {
pkgStr := " " + pkg.PackageBase
pkgStrMake := pkgStr
push := false
pushMake := false
if len(dc.Bases[pkg.PackageBase]) > 1 || pkg.PackageBase != pkg.Name {
pkgStr += " ("
pkgStrMake += " ("
for _, split := range dc.Bases[pkg.PackageBase] {
if dc.MakeOnly.get(split.Name) {
pkgStrMake += split.Name + " "
aurMakeLen++
pushMake = true
} else {
pkgStr += split.Name + " "
aurLen++
push = true
}
}
pkgStr = pkgStr[:len(pkgStr)-1] + ")"
pkgStrMake = pkgStrMake[:len(pkgStrMake)-1] + ")"
} else if dc.MakeOnly.get(pkg.Name) {
aurMakeLen++
pushMake = true
} else {
aurLen++
push = true
}
if push {
aur += pkgStr
}
if pushMake {
aurMake += pkgStrMake
}
}
printDownloads("Repo", repoLen, repo)
printDownloads("Repo Make", repoMakeLen, repoMake)
printDownloads("Aur", aurLen, aur)
printDownloads("Aur Make", aurMakeLen, aurMake)
}
func printDownloads(repoName string, length int, packages string) {
if length < 1 {
return
}
repoInfo := bold(blue(
"[" + repoName + ": " + strconv.Itoa(length) + "]"))
fmt.Println(repoInfo + magenta(packages))
}
// PrintInfo prints package info like pacman -Si.
func PrintInfo(a *rpc.Pkg) {
fmt.Println(bold("Repository :"), "aur")
fmt.Println(bold("Name :"), a.Name)
fmt.Println(bold("Version :"), a.Version)
fmt.Println(bold("Description :"), a.Description)
fmt.Println(bold("URL :"), a.URL)
fmt.Println(bold("Licenses :"), strings.Join(a.License, " "))
fmt.Println(bold("Depends On :"), strings.Join(a.Depends, " "))
fmt.Println(bold("Make Deps :"), strings.Join(a.MakeDepends, " "))
fmt.Println(bold("Check Deps :"), strings.Join(a.CheckDepends, " "))
fmt.Println(bold("Optional Deps :"), strings.Join(a.OptDepends, " "))
fmt.Println(bold("Conflicts With :"), strings.Join(a.Conflicts, " "))
fmt.Println(bold("Maintainer :"), a.Maintainer)
fmt.Println(bold("Votes :"), a.NumVotes)
fmt.Println(bold("Popularity :"), a.Popularity)
if a.OutOfDate != 0 {
fmt.Println(bold("Out-of-date :"), "Yes", "["+formatTime(a.OutOfDate)+"]")
}
fmt.Println()
}
// BiggestPackages prints the name of the ten biggest packages in the system.
func biggestPackages() {
localDb, err := alpmHandle.LocalDb()
if err != nil {
return
}
pkgCache := localDb.PkgCache()
pkgS := pkgCache.SortBySize().Slice()
if len(pkgS) < 10 {
return
}
for i := 0; i < 10; i++ {
fmt.Println(bold(pkgS[i].Name()) + ": " + cyan(human(pkgS[i].ISize())))
}
// Could implement size here as well, but we just want the general idea
}
// localStatistics prints installed packages statistics.
func localStatistics() error {
info, err := statistics()
if err != nil {
return err
}
_, _, _, remoteNames, err := filterPackages()
if err != nil {
return err
}
fmt.Printf(bold("Yay version v%s\n"), version)
fmt.Println(bold(cyan("===========================================")))
fmt.Println(bold(green("Total installed packages: ")) + magenta(strconv.Itoa(info.Totaln)))
fmt.Println(bold(green("Total foreign installed packages: ")) + magenta(strconv.Itoa(len(remoteNames))))
fmt.Println(bold(green("Explicitly installed packages: ")) + magenta(strconv.Itoa(info.Expln)))
fmt.Println(bold(green("Total Size occupied by packages: ")) + magenta(human(info.TotalSize)))
fmt.Println(bold(cyan("===========================================")))
fmt.Println(bold(green("Ten biggest packages:")))
biggestPackages()
fmt.Println(bold(cyan("===========================================")))
aurInfo(remoteNames)
return nil
}
//todo make it less hacky
func printNumberOfUpdates() error {
//todo
old := os.Stdout // keep backup of the real stdout
os.Stdout = nil
_, _, localNames, remoteNames, err := filterPackages()
dt, _ := getDepTree(append(localNames, remoteNames...))
aurUp, repoUp, err := upList(dt)
os.Stdout = old // restoring the real stdout
if err != nil {
return err
}
fmt.Println(len(aurUp) + len(repoUp))
return nil
}
//todo make it less hacky
func printUpdateList() error {
old := os.Stdout // keep backup of the real stdout
os.Stdout = nil
_, _, localNames, remoteNames, err := filterPackages()
dt, _ := getDepTree(append(localNames, remoteNames...))
aurUp, repoUp, err := upList(dt)
os.Stdout = old // restoring the real stdout
if err != nil {
return err
}
for _, pkg := range repoUp {
fmt.Println(pkg.Name)
}
for _, pkg := range aurUp {
fmt.Println(pkg.Name)
}
return nil
}
func formatTime(i int) string {
t := time.Unix(int64(i), 0)
return fmt.Sprintf("%d/%d/%d", t.Year(), int(t.Month()), t.Day())
}
func red(in string) string {
if alpmConf.Options&alpm.ConfColor > 0 {
return "\x1b[31m" + in + "\x1b[0m"
}
return in
}
func green(in string) string {
if alpmConf.Options&alpm.ConfColor > 0 {
return "\x1b[32m" + in + "\x1b[0m"
}
return in
}
func yellow(in string) string {
if alpmConf.Options&alpm.ConfColor > 0 {
return "\x1b[33m" + in + "\x1b[0m"
}
return in
}
func blue(in string) string {
if alpmConf.Options&alpm.ConfColor > 0 {
return "\x1b[34m" + in + "\x1b[0m"
}
return in
}
func cyan(in string) string {
if alpmConf.Options&alpm.ConfColor > 0 {
return "\x1b[36m" + in + "\x1b[0m"
}
return in
}
func magenta(in string) string {
if alpmConf.Options&alpm.ConfColor > 0 {
return "\x1b[35m" + in + "\x1b[0m"
}
return in
}
func bold(in string) string {
if alpmConf.Options&alpm.ConfColor > 0 {
return "\x1b[1m" + in + "\x1b[0m"
}
return in
}
func colourHash(name string) (output string) {
if alpmConf.Options&alpm.ConfColor == 0 {
return name
}
var hash = 5381
for i := 0; i < len(name); i++ {
hash = int(name[i]) + ((hash << 5) + (hash))
}
return fmt.Sprintf("\x1b[%dm%s\x1b[0m", hash%6+31, name)
}