fix(news): package news and begin settings

This commit is contained in:
jguer 2020-07-05 02:01:08 +02:00
parent fff9d74764
commit cb8a988701
No known key found for this signature in database
GPG Key ID: 6D6CC9BEA8556B35
17 changed files with 418 additions and 382 deletions

View File

@ -8,6 +8,7 @@ import (
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/Jguer/yay/v10/pkg/query"
"github.com/Jguer/yay/v10/pkg/stringset" "github.com/Jguer/yay/v10/pkg/stringset"
"github.com/Jguer/yay/v10/pkg/text" "github.com/Jguer/yay/v10/pkg/text"
) )
@ -116,7 +117,7 @@ func cleanAUR(keepInstalled, keepCurrent, removeAll bool) error {
installedBases := make(stringset.StringSet) installedBases := make(stringset.StringSet)
inAURBases := make(stringset.StringSet) inAURBases := make(stringset.StringSet)
_, remotePackages, _, _, err := filterPackages() _, remotePackages, _, _, err := query.FilterPackages(alpmHandle)
if err != nil { if err != nil {
return err return err
} }

20
cmd.go
View File

@ -11,6 +11,8 @@ import (
"github.com/Jguer/yay/v10/pkg/completion" "github.com/Jguer/yay/v10/pkg/completion"
"github.com/Jguer/yay/v10/pkg/intrange" "github.com/Jguer/yay/v10/pkg/intrange"
"github.com/Jguer/yay/v10/pkg/news"
"github.com/Jguer/yay/v10/pkg/settings"
"github.com/Jguer/yay/v10/pkg/text" "github.com/Jguer/yay/v10/pkg/text"
) )
@ -198,7 +200,7 @@ func handlePrint() (err error) {
switch { switch {
case cmdArgs.existsArg("d", "defaultconfig"): case cmdArgs.existsArg("d", "defaultconfig"):
tmpConfig := defaultSettings() tmpConfig := defaultSettings()
tmpConfig.expandEnv() tmpConfig.ExpandEnv()
fmt.Printf("%v", tmpConfig) fmt.Printf("%v", tmpConfig)
case cmdArgs.existsArg("g", "currentconfig"): case cmdArgs.existsArg("g", "currentconfig"):
fmt.Printf("%v", config) fmt.Printf("%v", config)
@ -207,7 +209,9 @@ func handlePrint() (err error) {
case cmdArgs.existsArg("u", "upgrades"): case cmdArgs.existsArg("u", "upgrades"):
err = printUpdateList(cmdArgs) err = printUpdateList(cmdArgs)
case cmdArgs.existsArg("w", "news"): case cmdArgs.existsArg("w", "news"):
err = printNewsFeed() _, double, _ := cmdArgs.getArg("news", "w")
quiet := cmdArgs.existsArg("q", "quiet")
err = news.PrintNewsFeed(alpmHandle, config.SortMode, double, quiet)
case cmdArgs.existsDouble("c", "complete"): case cmdArgs.existsDouble("c", "complete"):
err = completion.Show(alpmHandle, config.AURURL, cacheHome, config.CompletionInterval, true) err = completion.Show(alpmHandle, config.AURURL, cacheHome, config.CompletionInterval, true)
case cmdArgs.existsArg("c", "complete"): case cmdArgs.existsArg("c", "complete"):
@ -320,14 +324,14 @@ func displayNumberMenu(pkgS []string) error {
} }
switch config.SortMode { switch config.SortMode {
case topDown: case settings.TopDown:
if mode == modeRepo || mode == modeAny { if mode == modeRepo || mode == modeAny {
pq.printSearch() pq.printSearch()
} }
if mode == modeAUR || mode == modeAny { if mode == modeAUR || mode == modeAny {
aq.printSearch(lenpq + 1) aq.printSearch(lenpq + 1)
} }
case bottomUp: case settings.BottomUp:
if mode == modeAUR || mode == modeAny { if mode == modeAUR || mode == modeAny {
aq.printSearch(lenpq + 1) aq.printSearch(lenpq + 1)
} }
@ -364,9 +368,9 @@ func displayNumberMenu(pkgS []string) error {
for i, pkg := range pq { for i, pkg := range pq {
var target int var target int
switch config.SortMode { switch config.SortMode {
case topDown: case settings.TopDown:
target = i + 1 target = i + 1
case bottomUp: case settings.BottomUp:
target = len(pq) - i target = len(pq) - i
default: default:
return fmt.Errorf(gotext.Get("invalid sort mode. Fix with yay -Y --bottomup --save")) return fmt.Errorf(gotext.Get("invalid sort mode. Fix with yay -Y --bottomup --save"))
@ -381,9 +385,9 @@ func displayNumberMenu(pkgS []string) error {
var target int var target int
switch config.SortMode { switch config.SortMode {
case topDown: case settings.TopDown:
target = i + 1 + len(pq) target = i + 1 + len(pq)
case bottomUp: case settings.BottomUp:
target = len(aq) - i + len(pq) target = len(aq) - i + len(pq)
default: default:
return fmt.Errorf(gotext.Get("invalid sort mode. Fix with yay -Y --bottomup --save")) return fmt.Errorf(gotext.Get("invalid sort mode. Fix with yay -Y --bottomup --save"))

119
config.go
View File

@ -2,8 +2,6 @@ package main
import ( import (
"bufio" "bufio"
"bytes"
"encoding/json"
"fmt" "fmt"
"os" "os"
"os/exec" "os/exec"
@ -13,6 +11,7 @@ import (
pacmanconf "github.com/Morganamilo/go-pacmanconf" pacmanconf "github.com/Morganamilo/go-pacmanconf"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/Jguer/yay/v10/pkg/settings"
"github.com/Jguer/yay/v10/pkg/text" "github.com/Jguer/yay/v10/pkg/text"
) )
@ -23,12 +22,6 @@ const (
minimal minimal
) )
const (
// Describes Sorting method for numberdisplay
bottomUp = iota
topDown
)
const ( const (
modeAUR targetMode = iota modeAUR targetMode = iota
modeRepo modeRepo
@ -37,53 +30,6 @@ const (
type targetMode int type targetMode int
// Configuration stores yay's config.
type Configuration struct {
AURURL string `json:"aururl"`
BuildDir string `json:"buildDir"`
ABSDir string `json:"absdir"`
Editor string `json:"editor"`
EditorFlags string `json:"editorflags"`
MakepkgBin string `json:"makepkgbin"`
MakepkgConf string `json:"makepkgconf"`
PacmanBin string `json:"pacmanbin"`
PacmanConf string `json:"pacmanconf"`
ReDownload string `json:"redownload"`
ReBuild string `json:"rebuild"`
AnswerClean string `json:"answerclean"`
AnswerDiff string `json:"answerdiff"`
AnswerEdit string `json:"answeredit"`
AnswerUpgrade string `json:"answerupgrade"`
GitBin string `json:"gitbin"`
GpgBin string `json:"gpgbin"`
GpgFlags string `json:"gpgflags"`
MFlags string `json:"mflags"`
SortBy string `json:"sortby"`
SearchBy string `json:"searchby"`
GitFlags string `json:"gitflags"`
RemoveMake string `json:"removemake"`
SudoBin string `json:"sudobin"`
SudoFlags string `json:"sudoflags"`
RequestSplitN int `json:"requestsplitn"`
SearchMode int `json:"-"`
SortMode int `json:"sortmode"`
CompletionInterval int `json:"completionrefreshtime"`
SudoLoop bool `json:"sudoloop"`
TimeUpdate bool `json:"timeupdate"`
NoConfirm bool `json:"-"`
Devel bool `json:"devel"`
CleanAfter bool `json:"cleanAfter"`
Provides bool `json:"provides"`
PGPFetch bool `json:"pgpfetch"`
UpgradeMenu bool `json:"upgrademenu"`
CleanMenu bool `json:"cleanmenu"`
DiffMenu bool `json:"diffmenu"`
EditMenu bool `json:"editmenu"`
CombinedUpgrade bool `json:"combinedupgrade"`
UseAsk bool `json:"useask"`
BatchInstall bool `json:"batchinstall"`
}
var yayVersion = "10.0.0" var yayVersion = "10.0.0"
var localePath = "/usr/share/locale" var localePath = "/usr/share/locale"
@ -113,7 +59,7 @@ var vcsFile string
var shouldSaveConfig bool var shouldSaveConfig bool
// YayConf holds the current config values for yay. // YayConf holds the current config values for yay.
var config *Configuration var config *settings.Configuration
// AlpmConf holds the current config values for pacman. // AlpmConf holds the current config values for pacman.
var pacmanConf *pacmanconf.Config var pacmanConf *pacmanconf.Config
@ -126,25 +72,8 @@ var mode = modeAny
var hideMenus = false var hideMenus = false
// SaveConfig writes yay config to file. func defaultSettings() *settings.Configuration {
func (config *Configuration) saveConfig() error { newConfig := &settings.Configuration{
marshalledinfo, err := json.MarshalIndent(config, "", "\t")
if err != nil {
return err
}
in, err := os.OpenFile(configFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
return err
}
defer in.Close()
if _, err = in.Write(marshalledinfo); err != nil {
return err
}
return in.Sync()
}
func defaultSettings() *Configuration {
newConfig := &Configuration{
AURURL: "https://aur.archlinux.org", AURURL: "https://aur.archlinux.org",
BuildDir: "$HOME/.cache/yay", BuildDir: "$HOME/.cache/yay",
ABSDir: "$HOME/.cache/yay/abs", ABSDir: "$HOME/.cache/yay/abs",
@ -161,7 +90,7 @@ func defaultSettings() *Configuration {
GpgFlags: "", GpgFlags: "",
MFlags: "", MFlags: "",
GitFlags: "", GitFlags: "",
SortMode: bottomUp, SortMode: settings.BottomUp,
CompletionInterval: 7, CompletionInterval: 7,
SortBy: "votes", SortBy: "votes",
SearchBy: "name-desc", SearchBy: "name-desc",
@ -196,34 +125,6 @@ func defaultSettings() *Configuration {
return newConfig return newConfig
} }
func (config *Configuration) expandEnv() {
config.AURURL = os.ExpandEnv(config.AURURL)
config.ABSDir = os.ExpandEnv(config.ABSDir)
config.BuildDir = os.ExpandEnv(config.BuildDir)
config.Editor = os.ExpandEnv(config.Editor)
config.EditorFlags = os.ExpandEnv(config.EditorFlags)
config.MakepkgBin = os.ExpandEnv(config.MakepkgBin)
config.MakepkgConf = os.ExpandEnv(config.MakepkgConf)
config.PacmanBin = os.ExpandEnv(config.PacmanBin)
config.PacmanConf = os.ExpandEnv(config.PacmanConf)
config.GpgFlags = os.ExpandEnv(config.GpgFlags)
config.MFlags = os.ExpandEnv(config.MFlags)
config.GitFlags = os.ExpandEnv(config.GitFlags)
config.SortBy = os.ExpandEnv(config.SortBy)
config.SearchBy = os.ExpandEnv(config.SearchBy)
config.GitBin = os.ExpandEnv(config.GitBin)
config.GpgBin = os.ExpandEnv(config.GpgBin)
config.SudoBin = os.ExpandEnv(config.SudoBin)
config.SudoFlags = os.ExpandEnv(config.SudoFlags)
config.ReDownload = os.ExpandEnv(config.ReDownload)
config.ReBuild = os.ExpandEnv(config.ReBuild)
config.AnswerClean = os.ExpandEnv(config.AnswerClean)
config.AnswerDiff = os.ExpandEnv(config.AnswerDiff)
config.AnswerEdit = os.ExpandEnv(config.AnswerEdit)
config.AnswerUpgrade = os.ExpandEnv(config.AnswerUpgrade)
config.RemoveMake = os.ExpandEnv(config.RemoveMake)
}
// Editor returns the preferred system editor. // Editor returns the preferred system editor.
func editor() (editor string, args []string) { func editor() (editor string, args []string) {
switch { switch {
@ -334,16 +235,6 @@ func getInput(defaultValue string) (string, error) {
return string(buf), nil return string(buf), nil
} }
func (config *Configuration) String() string {
var buf bytes.Buffer
enc := json.NewEncoder(&buf)
enc.SetIndent("", "\t")
if err := enc.Encode(config); err != nil {
fmt.Fprintln(os.Stderr, err)
}
return buf.String()
}
func toUsage(usages []string) alpm.Usage { func toUsage(usages []string) alpm.Usage {
if len(usages) == 0 { if len(usages) == 0 {
return alpm.UsageAll return alpm.UsageAll

View File

@ -13,11 +13,8 @@ func expect(t *testing.T, field string, a interface{}, b interface{}, err error)
} }
} }
func TestConfig(t *testing.T) { func TestAlpmConfig(t *testing.T) {
config = &Configuration{} err := initAlpm("testdata/pacman.conf")
config.PacmanConf = "./testdata/pacman.conf"
err := initAlpm()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -17,6 +17,7 @@ import (
"github.com/Jguer/yay/v10/pkg/completion" "github.com/Jguer/yay/v10/pkg/completion"
"github.com/Jguer/yay/v10/pkg/intrange" "github.com/Jguer/yay/v10/pkg/intrange"
"github.com/Jguer/yay/v10/pkg/multierror" "github.com/Jguer/yay/v10/pkg/multierror"
"github.com/Jguer/yay/v10/pkg/query"
"github.com/Jguer/yay/v10/pkg/stringset" "github.com/Jguer/yay/v10/pkg/stringset"
"github.com/Jguer/yay/v10/pkg/text" "github.com/Jguer/yay/v10/pkg/text"
) )
@ -88,7 +89,7 @@ func install(parser *arguments) (err error) {
return err return err
} }
_, _, localNames, remoteNames, err := filterPackages() _, _, localNames, remoteNames, err := query.FilterPackages(alpmHandle)
if err != nil { if err != nil {
return err return err
} }
@ -951,7 +952,7 @@ func buildInstallPkgbuilds(
config.NoConfirm = true config.NoConfirm = true
//remotenames: names of all non repo packages on the system //remotenames: names of all non repo packages on the system
_, _, localNames, remoteNames, err := filterPackages() _, _, localNames, remoteNames, err := query.FilterPackages(alpmHandle)
if err != nil { if err != nil {
return err return err
} }

View File

@ -72,6 +72,7 @@ func TestImportKeys(t *testing.T) {
} }
defer os.RemoveAll(keyringDir) defer os.RemoveAll(keyringDir)
config = defaultSettings()
config.GpgBin = "gpg" config.GpgBin = "gpg"
config.GpgFlags = fmt.Sprintf("--homedir %s --keyserver 127.0.0.1", keyringDir) config.GpgFlags = fmt.Sprintf("--homedir %s --keyserver 127.0.0.1", keyringDir)

10
main.go
View File

@ -117,7 +117,7 @@ func initBuildDir() error {
return nil return nil
} }
func initAlpm() error { func initAlpm(pacmanConfigPath string) error {
var err error var err error
var stderr string var stderr string
@ -126,7 +126,7 @@ func initAlpm() error {
root = value root = value
} }
pacmanConf, stderr, err = pacmanconf.PacmanConf("--config", config.PacmanConf, "--root", root) pacmanConf, stderr, err = pacmanconf.PacmanConf("--config", pacmanConfigPath, "--root", root)
if err != nil { if err != nil {
return fmt.Errorf("%s", stderr) return fmt.Errorf("%s", stderr)
} }
@ -231,15 +231,15 @@ func main() {
exitOnError(initConfig()) exitOnError(initConfig())
exitOnError(cmdArgs.parseCommandLine()) exitOnError(cmdArgs.parseCommandLine())
if shouldSaveConfig { if shouldSaveConfig {
err := config.saveConfig() err := config.SaveConfig(configFile)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, err) fmt.Fprintln(os.Stderr, err)
} }
} }
config.expandEnv() config.ExpandEnv()
exitOnError(initBuildDir()) exitOnError(initBuildDir())
exitOnError(initVCS()) exitOnError(initVCS())
exitOnError(initAlpm()) exitOnError(initAlpm(config.PacmanConf))
exitOnError(handleCmd()) exitOnError(handleCmd())
os.Exit(cleanup()) os.Exit(cleanup())
} }

View File

@ -2,8 +2,6 @@ package main
import ( import (
"bufio" "bufio"
"bytes"
"html"
"os" "os"
"strconv" "strconv"
"strings" "strings"
@ -12,6 +10,7 @@ import (
rpc "github.com/mikkeloscar/aur" rpc "github.com/mikkeloscar/aur"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/Jguer/yay/v10/pkg/settings"
"github.com/Jguer/yay/v10/pkg/stringset" "github.com/Jguer/yay/v10/pkg/stringset"
) )
@ -474,9 +473,9 @@ func handleConfig(option, value string) bool {
case "notimeupdate": case "notimeupdate":
config.TimeUpdate = false config.TimeUpdate = false
case "topdown": case "topdown":
config.SortMode = topDown config.SortMode = settings.TopDown
case "bottomup": case "bottomup":
config.SortMode = bottomUp config.SortMode = settings.BottomUp
case "completioninterval": case "completioninterval":
n, err := strconv.Atoi(value) n, err := strconv.Atoi(value)
if err == nil { if err == nil {
@ -849,66 +848,3 @@ func (parser *arguments) extractYayOptions() {
rpc.AURURL = strings.TrimRight(config.AURURL, "/") + "/rpc.php?" rpc.AURURL = strings.TrimRight(config.AURURL, "/") + "/rpc.php?"
config.AURURL = strings.TrimRight(config.AURURL, "/") config.AURURL = strings.TrimRight(config.AURURL, "/")
} }
// Crude html parsing, good enough for the arch news
// This is only displayed in the terminal so there should be no security
// concerns
func parseNews(str string) string {
var buffer bytes.Buffer
var tagBuffer bytes.Buffer
var escapeBuffer bytes.Buffer
inTag := false
inEscape := false
for _, char := range str {
if inTag {
if char == '>' {
inTag = false
switch tagBuffer.String() {
case "code":
buffer.WriteString(cyanCode)
case "/code":
buffer.WriteString(resetCode)
case "/p":
buffer.WriteRune('\n')
}
continue
}
tagBuffer.WriteRune(char)
continue
}
if inEscape {
if char == ';' {
inEscape = false
escapeBuffer.WriteRune(char)
s := html.UnescapeString(escapeBuffer.String())
buffer.WriteString(s)
continue
}
escapeBuffer.WriteRune(char)
continue
}
if char == '<' {
inTag = true
tagBuffer.Reset()
continue
}
if char == '&' {
inEscape = true
escapeBuffer.Reset()
escapeBuffer.WriteRune(char)
continue
}
buffer.WriteRune(char)
}
buffer.WriteString(resetCode)
return buffer.String()
}

182
pkg/news/news.go Normal file
View File

@ -0,0 +1,182 @@
package news
import (
"bytes"
"encoding/xml"
"fmt"
"html"
"io/ioutil"
"net/http"
"os"
"strings"
"time"
"github.com/Jguer/go-alpm"
"github.com/Jguer/yay/v10/pkg/query"
"github.com/Jguer/yay/v10/pkg/settings"
"github.com/Jguer/yay/v10/pkg/text"
)
type item struct {
Title string `xml:"title"`
Link string `xml:"link"`
Description string `xml:"description"`
PubDate string `xml:"pubDate"`
Creator string `xml:"dc:creator"`
}
func (item *item) print(buildTime time.Time, double, quiet bool) {
var fd string
date, err := time.Parse(time.RFC1123Z, item.PubDate)
if err != nil {
fmt.Fprintln(os.Stderr, err)
} else {
fd = text.FormatTime(int(date.Unix()))
if !double && !buildTime.IsZero() {
if buildTime.After(date) {
return
}
}
}
fmt.Println(text.Bold(text.Magenta(fd)), text.Bold(strings.TrimSpace(item.Title)))
if !quiet {
desc := strings.TrimSpace(parseNews(item.Description))
fmt.Println(desc)
}
}
type channel struct {
Title string `xml:"title"`
Link string `xml:"link"`
Description string `xml:"description"`
Language string `xml:"language"`
Lastbuilddate string `xml:"lastbuilddate"`
Items []item `xml:"item"`
}
type rss struct {
Channel channel `xml:"channel"`
}
func PrintNewsFeed(alpmHandle *alpm.Handle, sortMode int, double, quiet bool) error {
resp, err := http.Get("https://archlinux.org/feeds/news")
if err != nil {
return err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
rssGot := rss{}
d := xml.NewDecoder(bytes.NewReader(body))
err = d.Decode(&rssGot)
if err != nil {
return err
}
buildTime, err := lastBuildTime(alpmHandle)
if err != nil {
return err
}
if sortMode == settings.BottomUp {
for i := len(rssGot.Channel.Items) - 1; i >= 0; i-- {
rssGot.Channel.Items[i].print(buildTime, double, quiet)
}
} else {
for i := 0; i < len(rssGot.Channel.Items); i++ {
rssGot.Channel.Items[i].print(buildTime, double, quiet)
}
}
return nil
}
func lastBuildTime(alpmHandle *alpm.Handle) (time.Time, error) {
var lastTime time.Time
pkgs, _, _, _, err := query.FilterPackages(alpmHandle)
if err != nil {
return lastTime, err
}
for _, pkg := range pkgs {
thisTime := pkg.BuildDate()
if thisTime.After(lastTime) {
lastTime = thisTime
}
}
return lastTime, nil
}
// Crude html parsing, good enough for the arch news
// This is only displayed in the terminal so there should be no security
// concerns
func parseNews(str string) string {
var buffer bytes.Buffer
var tagBuffer bytes.Buffer
var escapeBuffer bytes.Buffer
inTag := false
inEscape := false
for _, char := range str {
if inTag {
if char == '>' {
inTag = false
switch tagBuffer.String() {
case "code":
buffer.WriteString(text.CyanCode)
case "/code":
buffer.WriteString(text.ResetCode)
case "/p":
buffer.WriteRune('\n')
}
continue
}
tagBuffer.WriteRune(char)
continue
}
if inEscape {
if char == ';' {
inEscape = false
escapeBuffer.WriteRune(char)
s := html.UnescapeString(escapeBuffer.String())
buffer.WriteString(s)
continue
}
escapeBuffer.WriteRune(char)
continue
}
if char == '<' {
inTag = true
tagBuffer.Reset()
continue
}
if char == '&' {
inEscape = true
escapeBuffer.Reset()
escapeBuffer.WriteRune(char)
continue
}
buffer.WriteRune(char)
}
buffer.WriteString(text.ResetCode)
return buffer.String()
}

44
pkg/query/filter.go Normal file
View File

@ -0,0 +1,44 @@
package query
import "github.com/Jguer/go-alpm"
// FilterPackages filters packages based on source and type from local repository.
func FilterPackages(alpmHandle *alpm.Handle) (
local, remote []alpm.Package,
localNames, remoteNames []string,
err error) {
localDB, err := alpmHandle.LocalDB()
if err != nil {
return
}
dbList, err := alpmHandle.SyncDBs()
if err != nil {
return
}
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
}
if d.Pkg(k.Name()) != nil {
found = true
local = append(local, k)
localNames = append(localNames, k.Name())
}
return nil
})
if !found {
remote = append(remote, k)
remoteNames = append(remoteNames, k.Name())
}
return nil
}
err = localDB.PkgCache().ForEach(f)
return local, remote, localNames, remoteNames, err
}

116
pkg/settings/config.go Normal file
View File

@ -0,0 +1,116 @@
package settings
import (
"bytes"
"encoding/json"
"fmt"
"os"
)
const (
// Describes Sorting method for numberdisplay
BottomUp = iota
TopDown
)
// Configuration stores yay's config.
type Configuration struct {
AURURL string `json:"aururl"`
BuildDir string `json:"buildDir"`
ABSDir string `json:"absdir"`
Editor string `json:"editor"`
EditorFlags string `json:"editorflags"`
MakepkgBin string `json:"makepkgbin"`
MakepkgConf string `json:"makepkgconf"`
PacmanBin string `json:"pacmanbin"`
PacmanConf string `json:"pacmanconf"`
ReDownload string `json:"redownload"`
ReBuild string `json:"rebuild"`
AnswerClean string `json:"answerclean"`
AnswerDiff string `json:"answerdiff"`
AnswerEdit string `json:"answeredit"`
AnswerUpgrade string `json:"answerupgrade"`
GitBin string `json:"gitbin"`
GpgBin string `json:"gpgbin"`
GpgFlags string `json:"gpgflags"`
MFlags string `json:"mflags"`
SortBy string `json:"sortby"`
SearchBy string `json:"searchby"`
GitFlags string `json:"gitflags"`
RemoveMake string `json:"removemake"`
SudoBin string `json:"sudobin"`
SudoFlags string `json:"sudoflags"`
RequestSplitN int `json:"requestsplitn"`
SearchMode int `json:"-"`
SortMode int `json:"sortmode"`
CompletionInterval int `json:"completionrefreshtime"`
SudoLoop bool `json:"sudoloop"`
TimeUpdate bool `json:"timeupdate"`
NoConfirm bool `json:"-"`
Devel bool `json:"devel"`
CleanAfter bool `json:"cleanAfter"`
Provides bool `json:"provides"`
PGPFetch bool `json:"pgpfetch"`
UpgradeMenu bool `json:"upgrademenu"`
CleanMenu bool `json:"cleanmenu"`
DiffMenu bool `json:"diffmenu"`
EditMenu bool `json:"editmenu"`
CombinedUpgrade bool `json:"combinedupgrade"`
UseAsk bool `json:"useask"`
BatchInstall bool `json:"batchinstall"`
}
// SaveConfig writes yay config to file.
func (config *Configuration) SaveConfig(configPath string) error {
marshalledinfo, err := json.MarshalIndent(config, "", "\t")
if err != nil {
return err
}
in, err := os.OpenFile(configPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
return err
}
defer in.Close()
if _, err = in.Write(marshalledinfo); err != nil {
return err
}
return in.Sync()
}
func (config *Configuration) ExpandEnv() {
config.AURURL = os.ExpandEnv(config.AURURL)
config.ABSDir = os.ExpandEnv(config.ABSDir)
config.BuildDir = os.ExpandEnv(config.BuildDir)
config.Editor = os.ExpandEnv(config.Editor)
config.EditorFlags = os.ExpandEnv(config.EditorFlags)
config.MakepkgBin = os.ExpandEnv(config.MakepkgBin)
config.MakepkgConf = os.ExpandEnv(config.MakepkgConf)
config.PacmanBin = os.ExpandEnv(config.PacmanBin)
config.PacmanConf = os.ExpandEnv(config.PacmanConf)
config.GpgFlags = os.ExpandEnv(config.GpgFlags)
config.MFlags = os.ExpandEnv(config.MFlags)
config.GitFlags = os.ExpandEnv(config.GitFlags)
config.SortBy = os.ExpandEnv(config.SortBy)
config.SearchBy = os.ExpandEnv(config.SearchBy)
config.GitBin = os.ExpandEnv(config.GitBin)
config.GpgBin = os.ExpandEnv(config.GpgBin)
config.SudoBin = os.ExpandEnv(config.SudoBin)
config.SudoFlags = os.ExpandEnv(config.SudoFlags)
config.ReDownload = os.ExpandEnv(config.ReDownload)
config.ReBuild = os.ExpandEnv(config.ReBuild)
config.AnswerClean = os.ExpandEnv(config.AnswerClean)
config.AnswerDiff = os.ExpandEnv(config.AnswerDiff)
config.AnswerEdit = os.ExpandEnv(config.AnswerEdit)
config.AnswerUpgrade = os.ExpandEnv(config.AnswerUpgrade)
config.RemoveMake = os.ExpandEnv(config.RemoveMake)
}
func (config *Configuration) String() string {
var buf bytes.Buffer
enc := json.NewEncoder(&buf)
enc.SetIndent("", "\t")
if err := enc.Encode(config); err != nil {
fmt.Fprintln(os.Stderr, err)
}
return buf.String()
}

View File

@ -6,10 +6,11 @@ const (
redCode = "\x1b[31m" redCode = "\x1b[31m"
greenCode = "\x1b[32m" greenCode = "\x1b[32m"
yellowCode = "\x1b[33m" yellowCode = "\x1b[33m"
cyanCode = "\x1b[36m" magentaCode = "\x1b[35m"
CyanCode = "\x1b[36m"
boldCode = "\x1b[1m" boldCode = "\x1b[1m"
resetCode = "\x1b[0m" ResetCode = "\x1b[0m"
) )
// UseColor determines if package will emit colors // UseColor determines if package will emit colors
@ -17,7 +18,7 @@ var UseColor = true
func stylize(startCode, in string) string { func stylize(startCode, in string) string {
if UseColor { if UseColor {
return startCode + in + resetCode return startCode + in + ResetCode
} }
return in return in
@ -36,10 +37,14 @@ func yellow(in string) string {
} }
func cyan(in string) string { func cyan(in string) string {
return stylize(cyanCode, in) return stylize(CyanCode, in)
} }
func bold(in string) string { func Magenta(in string) string {
return stylize(magentaCode, in)
}
func Bold(in string) string {
return stylize(boldCode, in) return stylize(boldCode, in)
} }

View File

@ -9,40 +9,40 @@ import (
const arrow = "==>" const arrow = "==>"
const smallArrow = " ->" const smallArrow = " ->"
const opSymbol = ":: " const opSymbol = "::"
func OperationInfoln(a ...interface{}) { func OperationInfoln(a ...interface{}) {
fmt.Fprint(os.Stdout, append([]interface{}{boldCode, cyan(opSymbol), boldCode}, a...)...) fmt.Fprint(os.Stdout, append([]interface{}{Bold(cyan(opSymbol + " ")), boldCode}, a...)...)
fmt.Fprintln(os.Stdout, resetCode) fmt.Fprintln(os.Stdout, ResetCode)
} }
func OperationInfo(a ...interface{}) { func OperationInfo(a ...interface{}) {
fmt.Fprint(os.Stdout, append([]interface{}{boldCode, cyan(opSymbol), boldCode}, a...)...) fmt.Fprint(os.Stdout, append([]interface{}{Bold(cyan(opSymbol + " ")), boldCode}, a...)...)
fmt.Fprint(os.Stdout, resetCode+" ") fmt.Fprint(os.Stdout, ResetCode+" ")
} }
func Info(a ...interface{}) { 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{}) { 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 Warn(a ...interface{}) { func Warn(a ...interface{}) {
fmt.Fprint(os.Stdout, append([]interface{}{bold(yellow(smallArrow + " "))}, a...)...) fmt.Fprint(os.Stdout, append([]interface{}{Bold(yellow(smallArrow + " "))}, a...)...)
} }
func Warnln(a ...interface{}) { func Warnln(a ...interface{}) {
fmt.Fprintln(os.Stdout, append([]interface{}{bold(yellow(smallArrow))}, a...)...) fmt.Fprintln(os.Stdout, append([]interface{}{Bold(yellow(smallArrow))}, a...)...)
} }
func Error(a ...interface{}) { func Error(a ...interface{}) {
fmt.Fprint(os.Stderr, append([]interface{}{bold(red(smallArrow + " "))}, a...)...) fmt.Fprint(os.Stderr, append([]interface{}{Bold(red(smallArrow + " "))}, a...)...)
} }
func Errorln(a ...interface{}) { func Errorln(a ...interface{}) {
fmt.Fprintln(os.Stderr, append([]interface{}{bold(red(smallArrow))}, a...)...) fmt.Fprintln(os.Stderr, append([]interface{}{Bold(red(smallArrow))}, a...)...)
} }
func PrintInfoValue(str, value string) { func PrintInfoValue(str, value string) {
@ -50,5 +50,5 @@ func PrintInfoValue(str, value string) {
value = gotext.Get("None") value = gotext.Get("None")
} }
fmt.Fprintf(os.Stdout, bold("%-16s%s")+" %s\n", str, ":", value) fmt.Fprintf(os.Stdout, Bold("%-16s%s")+" %s\n", str, ":", value)
} }

101
print.go
View File

@ -2,20 +2,17 @@ package main
import ( import (
"bufio" "bufio"
"bytes"
"encoding/xml"
"fmt" "fmt"
"io/ioutil"
"net/http"
"os" "os"
"strconv" "strconv"
"strings" "strings"
"time"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
rpc "github.com/mikkeloscar/aur" rpc "github.com/mikkeloscar/aur"
"github.com/Jguer/yay/v10/pkg/intrange" "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" "github.com/Jguer/yay/v10/pkg/stringset"
"github.com/Jguer/yay/v10/pkg/text" "github.com/Jguer/yay/v10/pkg/text"
) )
@ -57,9 +54,9 @@ func (q aurQuery) printSearch(start int) {
var toprint string var toprint string
if config.SearchMode == numberMenu { if config.SearchMode == numberMenu {
switch config.SortMode { switch config.SortMode {
case topDown: case settings.TopDown:
toprint += magenta(strconv.Itoa(start+i) + " ") toprint += magenta(strconv.Itoa(start+i) + " ")
case bottomUp: case settings.BottomUp:
toprint += magenta(strconv.Itoa(len(q)+start-i-1) + " ") toprint += magenta(strconv.Itoa(len(q)+start-i-1) + " ")
default: default:
text.Warnln(gotext.Get("invalid sort mode. Fix with yay -Y --bottomup --save")) text.Warnln(gotext.Get("invalid sort mode. Fix with yay -Y --bottomup --save"))
@ -100,9 +97,9 @@ func (s repoQuery) printSearch() {
var toprint string var toprint string
if config.SearchMode == numberMenu { if config.SearchMode == numberMenu {
switch config.SortMode { switch config.SortMode {
case topDown: case settings.TopDown:
toprint += magenta(strconv.Itoa(i+1) + " ") toprint += magenta(strconv.Itoa(i+1) + " ")
case bottomUp: case settings.BottomUp:
toprint += magenta(strconv.Itoa(len(s)-i) + " ") toprint += magenta(strconv.Itoa(len(s)-i) + " ")
default: default:
text.Warnln(gotext.Get("invalid sort mode. Fix with yay -Y --bottomup --save")) text.Warnln(gotext.Get("invalid sort mode. Fix with yay -Y --bottomup --save"))
@ -333,7 +330,7 @@ func localStatistics() error {
return err return err
} }
_, _, _, remoteNames, err := filterPackages() _, _, _, remoteNames, err := query.FilterPackages(alpmHandle)
if err != nil { if err != nil {
return err return err
} }
@ -375,7 +372,7 @@ func printUpdateList(parser *arguments) error {
warnings := makeWarnings() warnings := makeWarnings()
old := os.Stdout // keep backup of the real stdout old := os.Stdout // keep backup of the real stdout
os.Stdout = nil os.Stdout = nil
_, _, localNames, remoteNames, err := filterPackages() _, _, localNames, remoteNames, err := query.FilterPackages(alpmHandle)
if err != nil { if err != nil {
return err return err
} }
@ -441,88 +438,6 @@ outer:
return nil return nil
} }
type item struct {
Title string `xml:"title"`
Link string `xml:"link"`
Description string `xml:"description"`
PubDate string `xml:"pubDate"`
Creator string `xml:"dc:creator"`
}
func (item *item) print(buildTime time.Time) {
var fd string
date, err := time.Parse(time.RFC1123Z, item.PubDate)
if err != nil {
fmt.Fprintln(os.Stderr, err)
} else {
fd = text.FormatTime(int(date.Unix()))
if _, double, _ := cmdArgs.getArg("news", "w"); !double && !buildTime.IsZero() {
if buildTime.After(date) {
return
}
}
}
fmt.Println(bold(magenta(fd)), bold(strings.TrimSpace(item.Title)))
if !cmdArgs.existsArg("q", "quiet") {
desc := strings.TrimSpace(parseNews(item.Description))
fmt.Println(desc)
}
}
type channel struct {
Title string `xml:"title"`
Link string `xml:"link"`
Description string `xml:"description"`
Language string `xml:"language"`
Lastbuilddate string `xml:"lastbuilddate"`
Items []item `xml:"item"`
}
type rss struct {
Channel channel `xml:"channel"`
}
func printNewsFeed() error {
resp, err := http.Get("https://archlinux.org/feeds/news")
if err != nil {
return err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
rssGot := rss{}
d := xml.NewDecoder(bytes.NewReader(body))
err = d.Decode(&rssGot)
if err != nil {
return err
}
buildTime, err := lastBuildTime()
if err != nil {
return err
}
if config.SortMode == bottomUp {
for i := len(rssGot.Channel.Items) - 1; i >= 0; i-- {
rssGot.Channel.Items[i].print(buildTime)
}
} else {
for i := 0; i < len(rssGot.Channel.Items); i++ {
rssGot.Channel.Items[i].print(buildTime)
}
}
return nil
}
const ( const (
redCode = "\x1b[31m" redCode = "\x1b[31m"
greenCode = "\x1b[32m" greenCode = "\x1b[32m"

View File

@ -7,7 +7,6 @@ import (
"sort" "sort"
"strings" "strings"
"sync" "sync"
"time"
alpm "github.com/Jguer/go-alpm" alpm "github.com/Jguer/go-alpm"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
@ -15,6 +14,7 @@ import (
"github.com/Jguer/yay/v10/pkg/intrange" "github.com/Jguer/yay/v10/pkg/intrange"
"github.com/Jguer/yay/v10/pkg/multierror" "github.com/Jguer/yay/v10/pkg/multierror"
"github.com/Jguer/yay/v10/pkg/settings"
"github.com/Jguer/yay/v10/pkg/stringset" "github.com/Jguer/yay/v10/pkg/stringset"
"github.com/Jguer/yay/v10/pkg/text" "github.com/Jguer/yay/v10/pkg/text"
) )
@ -62,7 +62,7 @@ func (q aurQuery) Less(i, j int) bool {
result = q[i].PackageBaseID < q[j].PackageBaseID result = q[i].PackageBaseID < q[j].PackageBaseID
} }
if config.SortMode == bottomUp { if config.SortMode == settings.BottomUp {
return !result return !result
} }
@ -73,47 +73,6 @@ func (q aurQuery) Swap(i, j int) {
q[i], q[j] = q[j], q[i] q[i], q[j] = q[j], q[i]
} }
// FilterPackages filters packages based on source and type from local repository.
func filterPackages() (
local, remote []alpm.Package,
localNames, remoteNames []string,
err error) {
localDB, err := alpmHandle.LocalDB()
if err != nil {
return
}
dbList, err := alpmHandle.SyncDBs()
if err != nil {
return
}
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
}
if d.Pkg(k.Name()) != nil {
found = true
local = append(local, k)
localNames = append(localNames, k.Name())
}
return nil
})
if !found {
remote = append(remote, k)
remoteNames = append(remoteNames, k.Name())
}
return nil
}
err = localDB.PkgCache().ForEach(f)
return local, remote, localNames, remoteNames, err
}
func getSearchBy(value string) rpc.By { func getSearchBy(value string) rpc.By {
switch value { switch value {
case "name": case "name":
@ -212,14 +171,14 @@ func syncSearch(pkgS []string) (err error) {
} }
switch config.SortMode { switch config.SortMode {
case topDown: case settings.TopDown:
if mode == modeRepo || mode == modeAny { if mode == modeRepo || mode == modeAny {
pq.printSearch() pq.printSearch()
} }
if mode == modeAUR || mode == modeAny { if mode == modeAUR || mode == modeAny {
aq.printSearch(1) aq.printSearch(1)
} }
case bottomUp: case settings.BottomUp:
if mode == modeAUR || mode == modeAny { if mode == modeAUR || mode == modeAny {
aq.printSearch(1) aq.printSearch(1)
} }
@ -310,7 +269,7 @@ func queryRepo(pkgInputN []string) (s repoQuery, err error) {
return nil return nil
}) })
if config.SortMode == bottomUp { if config.SortMode == settings.BottomUp {
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 { for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i] s[i], s[j] = s[j], s[i]
} }
@ -450,24 +409,6 @@ func hangingPackages(removeOptional bool) (hanging []string, err error) {
return hanging, err return hanging, err
} }
func lastBuildTime() (time.Time, error) {
var lastTime time.Time
pkgs, _, _, _, err := filterPackages()
if err != nil {
return lastTime, err
}
for _, pkg := range pkgs {
thisTime := pkg.BuildDate()
if thisTime.After(lastTime) {
lastTime = thisTime
}
}
return lastTime, nil
}
// Statistics returns statistics about packages installed in system // Statistics returns statistics about packages installed in system
func statistics() (*struct { func statistics() (*struct {
Totaln int Totaln int

View File

@ -10,6 +10,7 @@ import (
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/Jguer/yay/v10/pkg/intrange" "github.com/Jguer/yay/v10/pkg/intrange"
"github.com/Jguer/yay/v10/pkg/query"
"github.com/Jguer/yay/v10/pkg/text" "github.com/Jguer/yay/v10/pkg/text"
rpc "github.com/mikkeloscar/aur" rpc "github.com/mikkeloscar/aur"
@ -117,7 +118,7 @@ func getVersionDiff(oldVersion, newVersion string) (left, right string) {
// upList returns lists of packages to upgrade from each source. // upList returns lists of packages to upgrade from each source.
func upList(warnings *aurWarnings) (aurUp, repoUp upSlice, err error) { func upList(warnings *aurWarnings) (aurUp, repoUp upSlice, err error) {
_, remote, _, remoteNames, err := filterPackages() _, remote, _, remoteNames, err := query.FilterPackages(alpmHandle)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }

3
vcs.go
View File

@ -12,6 +12,7 @@ import (
gosrc "github.com/Morganamilo/go-srcinfo" gosrc "github.com/Morganamilo/go-srcinfo"
"github.com/leonelquinteros/gotext" "github.com/leonelquinteros/gotext"
"github.com/Jguer/yay/v10/pkg/query"
"github.com/Jguer/yay/v10/pkg/stringset" "github.com/Jguer/yay/v10/pkg/stringset"
"github.com/Jguer/yay/v10/pkg/text" "github.com/Jguer/yay/v10/pkg/text"
) )
@ -30,7 +31,7 @@ func createDevelDB() error {
var mux sync.Mutex var mux sync.Mutex
var wg sync.WaitGroup var wg sync.WaitGroup
_, _, _, remoteNames, err := filterPackages() _, _, _, remoteNames, err := query.FilterPackages(alpmHandle)
if err != nil { if err != nil {
return err return err
} }