yay/pkg/settings/config.go

341 lines
9.4 KiB
Go
Raw Normal View History

package settings
import (
"bytes"
2021-05-13 07:27:24 +02:00
"context"
"encoding/json"
"fmt"
2021-01-30 12:52:50 +01:00
"net/http"
"os"
"os/exec"
"path/filepath"
2020-08-22 01:24:52 +02:00
"strings"
"github.com/leonelquinteros/gotext"
2021-05-13 07:27:24 +02:00
"github.com/Jguer/aur"
"github.com/Jguer/votar/pkg/vote"
2021-05-13 07:27:24 +02:00
2021-09-08 22:28:08 +02:00
"github.com/Jguer/yay/v11/pkg/settings/exe"
"github.com/Jguer/yay/v11/pkg/settings/parser"
"github.com/Jguer/yay/v11/pkg/text"
2021-09-08 22:28:08 +02:00
"github.com/Jguer/yay/v11/pkg/vcs"
)
2021-08-11 20:13:28 +02:00
// HideMenus indicates if pacman's provider menus must be hidden.
2020-07-10 02:36:45 +02:00
var HideMenus = false
2021-08-11 20:13:28 +02:00
// NoConfirm indicates if user input should be skipped.
var NoConfirm = false
// Configuration stores yay's config.
type Configuration struct {
AURURL string `json:"aururl"`
BuildDir string `json:"buildDir"`
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"`
CompletionInterval int `json:"completionrefreshtime"`
BottomUp bool `json:"bottomup"`
SudoLoop bool `json:"sudoloop"`
TimeUpdate bool `json:"timeupdate"`
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"`
SingleLineResults bool `json:"singlelineresults"`
SeparateSources bool `json:"separatesources"`
Runtime *Runtime `json:"-"`
Version string `json:"version"`
}
// SaveConfig writes yay config to file.
func (c *Configuration) Save(configPath string) error {
c.Version = c.Runtime.Version
marshalledinfo, err := json.MarshalIndent(c, "", "\t")
if err != nil {
return err
}
2020-08-07 23:59:55 +02:00
// https://github.com/Jguer/yay/issues/1325
marshalledinfo = append(marshalledinfo, '\n')
parent 55a6767b44a4aa8093dff6ff30058b985939a4e0 author lwlf <wuhaojie_2011@sina.com> 1603706823 +0800 committer jguer <me@jguer.space> 1604217613 +0100 gpgsig -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEP4pAozwhlAIAKURxbWzJvqhVazUFAl+eaw0ACgkQbWzJvqhV azU8Dg//XEcgshJ3DqS54kGDOhOXvp3RGWDW6EGYS9UG22ul6af2Yxgt+sNksQY2 oaTBV2TiQ979AWikJ70waTLQEkkqqkbG1eKz0AWniQQuHPmpTu/9CA6e5hX5f+nh AdeUdvz8UcxRd2n80YCVYv7KEs2QkR1ZU4gE+42BG/ohdWSoAxfd1S/skDJ2uYjx VUu/ZVYh1qsgLhoIqLpnKzv0jPDVvbpzQ0il+1Zyl2P7qC8QKDTHkfajO6FQV46t 74anbsk1HrwJSK2G8Z25h/vzi+6Vz36koS7A8mQCLz4jpQZho0Ax7wkhPwLhYSNf 8CRTK8uoyczTLECOBXnwwrQoDl21N4EgqzZWDBso6DEozBZMteSd74liye3FAXff vWmN12pf6nh8uUN5kUGaj/Jq6XWij0cdU4vM0CpRzlzAw3OV4Z0RTwVHqAy6qU6J M73cIwVjzVEmPAjWlD2y1ZbTNFUsbWNZ4iqxWXcvc2IOuR4Ywjv+T45NcFXB6RcZ PoEivscWy/nEkmihtn9bAIhZXze/UMgIktOV8FyrYFizlVNmZ3HuFPlu6tXRFIZK RdGbTeLunPGMLg8iw5C9rKe8/vvsVlUpLUiguyr7w3vUS9QpxLPd8mHlsUETp3p2 OKxz3zD4/BRaRmuL6Gef7KeroCvJYZGnVpTHPHoOENkSzGxqHCk= =D+N6 -----END PGP SIGNATURE----- unsaved config when yay's config path does not exist unsaved config when yay's config path does not exist unsaved config when yay's config path does not exist unsaved config when yay's config path does not exist unsaved config when yay's config path does not exist fix: unsaved config when yay's config path does not exist fix: unsaved config when yay's config path does not exist fix: unsaved config when yay's config path does not exist fix: unsaved config when yay's config path does not exist fix: unsaved config when yay's config path does not exist
2020-10-26 11:07:03 +01:00
// https://github.com/Jguer/yay/issues/1399
2020-11-01 09:09:38 +01:00
if _, err = os.Stat(filepath.Dir(configPath)); os.IsNotExist(err) && err != nil {
if mkErr := os.MkdirAll(filepath.Dir(configPath), 0o755); mkErr != nil {
parent 55a6767b44a4aa8093dff6ff30058b985939a4e0 author lwlf <wuhaojie_2011@sina.com> 1603706823 +0800 committer jguer <me@jguer.space> 1604217613 +0100 gpgsig -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEP4pAozwhlAIAKURxbWzJvqhVazUFAl+eaw0ACgkQbWzJvqhV azU8Dg//XEcgshJ3DqS54kGDOhOXvp3RGWDW6EGYS9UG22ul6af2Yxgt+sNksQY2 oaTBV2TiQ979AWikJ70waTLQEkkqqkbG1eKz0AWniQQuHPmpTu/9CA6e5hX5f+nh AdeUdvz8UcxRd2n80YCVYv7KEs2QkR1ZU4gE+42BG/ohdWSoAxfd1S/skDJ2uYjx VUu/ZVYh1qsgLhoIqLpnKzv0jPDVvbpzQ0il+1Zyl2P7qC8QKDTHkfajO6FQV46t 74anbsk1HrwJSK2G8Z25h/vzi+6Vz36koS7A8mQCLz4jpQZho0Ax7wkhPwLhYSNf 8CRTK8uoyczTLECOBXnwwrQoDl21N4EgqzZWDBso6DEozBZMteSd74liye3FAXff vWmN12pf6nh8uUN5kUGaj/Jq6XWij0cdU4vM0CpRzlzAw3OV4Z0RTwVHqAy6qU6J M73cIwVjzVEmPAjWlD2y1ZbTNFUsbWNZ4iqxWXcvc2IOuR4Ywjv+T45NcFXB6RcZ PoEivscWy/nEkmihtn9bAIhZXze/UMgIktOV8FyrYFizlVNmZ3HuFPlu6tXRFIZK RdGbTeLunPGMLg8iw5C9rKe8/vvsVlUpLUiguyr7w3vUS9QpxLPd8mHlsUETp3p2 OKxz3zD4/BRaRmuL6Gef7KeroCvJYZGnVpTHPHoOENkSzGxqHCk= =D+N6 -----END PGP SIGNATURE----- unsaved config when yay's config path does not exist unsaved config when yay's config path does not exist unsaved config when yay's config path does not exist unsaved config when yay's config path does not exist unsaved config when yay's config path does not exist fix: unsaved config when yay's config path does not exist fix: unsaved config when yay's config path does not exist fix: unsaved config when yay's config path does not exist fix: unsaved config when yay's config path does not exist fix: unsaved config when yay's config path does not exist
2020-10-26 11:07:03 +01:00
return mkErr
}
}
2021-08-11 20:13:28 +02:00
in, err := os.OpenFile(configPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o644)
if err != nil {
return err
}
defer in.Close()
2021-08-11 20:13:28 +02:00
if _, err = in.Write(marshalledinfo); err != nil {
return err
}
2021-08-11 20:13:28 +02:00
return in.Sync()
}
func (c *Configuration) expandEnv() {
c.AURURL = os.ExpandEnv(c.AURURL)
c.BuildDir = os.ExpandEnv(c.BuildDir)
c.Editor = os.ExpandEnv(c.Editor)
c.EditorFlags = os.ExpandEnv(c.EditorFlags)
c.MakepkgBin = os.ExpandEnv(c.MakepkgBin)
c.MakepkgConf = os.ExpandEnv(c.MakepkgConf)
c.PacmanBin = os.ExpandEnv(c.PacmanBin)
c.PacmanConf = os.ExpandEnv(c.PacmanConf)
c.GpgFlags = os.ExpandEnv(c.GpgFlags)
c.MFlags = os.ExpandEnv(c.MFlags)
c.GitFlags = os.ExpandEnv(c.GitFlags)
c.SortBy = os.ExpandEnv(c.SortBy)
c.SearchBy = os.ExpandEnv(c.SearchBy)
c.GitBin = os.ExpandEnv(c.GitBin)
c.GpgBin = os.ExpandEnv(c.GpgBin)
c.SudoBin = os.ExpandEnv(c.SudoBin)
c.SudoFlags = os.ExpandEnv(c.SudoFlags)
c.ReDownload = os.ExpandEnv(c.ReDownload)
c.ReBuild = os.ExpandEnv(c.ReBuild)
c.AnswerClean = os.ExpandEnv(c.AnswerClean)
c.AnswerDiff = os.ExpandEnv(c.AnswerDiff)
c.AnswerEdit = os.ExpandEnv(c.AnswerEdit)
c.AnswerUpgrade = os.ExpandEnv(c.AnswerUpgrade)
c.RemoveMake = os.ExpandEnv(c.RemoveMake)
}
func (c *Configuration) String() string {
var buf bytes.Buffer
enc := json.NewEncoder(&buf)
enc.SetIndent("", "\t")
2021-08-11 20:13:28 +02:00
if err := enc.Encode(c); err != nil {
fmt.Fprintln(os.Stderr, err)
}
2021-08-11 20:13:28 +02:00
return buf.String()
}
// check privilege elevator exists otherwise try to find another one.
func (c *Configuration) setPrivilegeElevator() error {
if auth := os.Getenv("PACMAN_AUTH"); auth != "" {
c.SudoBin = auth
if auth != "sudo" {
c.SudoFlags = ""
c.SudoLoop = false
}
}
for _, bin := range [...]string{c.SudoBin, "sudo"} {
if _, err := exec.LookPath(bin); err == nil {
c.SudoBin = bin
return nil // wrapper or sudo command existing. Retrocompatiblity
}
}
c.SudoFlags = ""
c.SudoLoop = false
for _, bin := range [...]string{"doas", "pkexec", "su"} {
if _, err := exec.LookPath(bin); err == nil {
c.SudoBin = bin
return nil // command existing
}
}
return &ErrPrivilegeElevatorNotFound{confValue: c.SudoBin}
}
func DefaultConfig(version string) *Configuration {
return &Configuration{
AURURL: "https://aur.archlinux.org",
BuildDir: os.ExpandEnv("$HOME/.cache/yay"),
CleanAfter: false,
Editor: "",
EditorFlags: "",
Devel: false,
MakepkgBin: "makepkg",
MakepkgConf: "",
PacmanBin: "pacman",
PGPFetch: true,
PacmanConf: "/etc/pacman.conf",
GpgFlags: "",
MFlags: "",
GitFlags: "",
BottomUp: true,
CompletionInterval: 7,
SortBy: "votes",
SearchBy: "name-desc",
SudoLoop: false,
GitBin: "git",
GpgBin: "gpg",
SudoBin: "sudo",
SudoFlags: "",
TimeUpdate: false,
RequestSplitN: 150,
ReDownload: "no",
ReBuild: "no",
BatchInstall: false,
AnswerClean: "",
AnswerDiff: "",
AnswerEdit: "",
AnswerUpgrade: "",
RemoveMake: "ask",
Provides: true,
UpgradeMenu: true,
CleanMenu: true,
DiffMenu: true,
EditMenu: false,
UseAsk: false,
CombinedUpgrade: false,
2022-06-10 18:31:21 +02:00
SeparateSources: true,
Version: version,
}
}
2021-05-13 07:27:24 +02:00
func NewConfig(version string) (*Configuration, error) {
newConfig := DefaultConfig(version)
cacheHome, errCache := getCacheHome()
if errCache != nil {
text.Errorln(errCache)
}
newConfig.BuildDir = cacheHome
configPath := getConfigPath()
newConfig.load(configPath)
if aurdest := os.Getenv("AURDEST"); aurdest != "" {
newConfig.BuildDir = aurdest
}
newConfig.expandEnv()
if newConfig.BuildDir != systemdCache {
errBuildDir := initDir(newConfig.BuildDir)
if errBuildDir != nil {
return nil, errBuildDir
}
}
2021-09-06 23:51:07 +02:00
if errPE := newConfig.setPrivilegeElevator(); errPE != nil {
return nil, errPE
}
userAgent := fmt.Sprintf("Yay/%s", version)
voteClient, errVote := vote.NewClient(vote.WithUserAgent(userAgent))
if errVote != nil {
return nil, errVote
}
voteClient.SetCredentials(
os.Getenv("AUR_USERNAME"),
os.Getenv("AUR_PASSWORD"))
newConfig.Runtime = &Runtime{
2020-09-03 18:26:57 +02:00
ConfigPath: configPath,
Version: version,
Mode: parser.ModeAny,
SaveConfig: false,
CompletionPath: filepath.Join(cacheHome, completionFileName),
CmdBuilder: newConfig.CmdBuilder(nil),
PacmanConf: nil,
VCSStore: nil,
HTTPClient: &http.Client{},
AURClient: nil,
VoteClient: voteClient,
2021-05-13 07:27:24 +02:00
}
var errAUR error
newConfig.Runtime.AURClient, errAUR = aur.NewClient(aur.WithHTTPClient(newConfig.Runtime.HTTPClient),
aur.WithRequestEditorFn(func(ctx context.Context, req *http.Request) error {
req.Header.Set("User-Agent", userAgent)
2021-05-13 07:27:24 +02:00
return nil
}))
if errAUR != nil {
return nil, errAUR
}
newConfig.Runtime.VCSStore = vcs.NewInfoStore(
filepath.Join(cacheHome, vcsFileName), newConfig.Runtime.CmdBuilder)
err := newConfig.Runtime.VCSStore.Load()
return newConfig, err
}
func (c *Configuration) load(configPath string) {
cfile, err := os.Open(configPath)
if !os.IsNotExist(err) && err != nil {
fmt.Fprintln(os.Stderr,
gotext.Get("failed to open config file '%s': %s", configPath, err))
return
}
defer cfile.Close()
2021-08-11 20:13:28 +02:00
if !os.IsNotExist(err) {
decoder := json.NewDecoder(cfile)
if err = decoder.Decode(c); err != nil {
fmt.Fprintln(os.Stderr,
gotext.Get("failed to read config file '%s': %s", configPath, err))
}
}
}
func (c *Configuration) CmdBuilder(runner exe.Runner) exe.ICmdBuilder {
if runner == nil {
runner = &exe.OSRunner{}
}
2021-08-11 20:13:28 +02:00
return &exe.CmdBuilder{
GitBin: c.GitBin,
GitFlags: strings.Fields(c.GitFlags),
MakepkgFlags: strings.Fields(c.MFlags),
MakepkgConfPath: c.MakepkgConf,
MakepkgBin: c.MakepkgBin,
SudoBin: c.SudoBin,
SudoFlags: strings.Fields(c.SudoFlags),
SudoLoopEnabled: c.SudoLoop,
PacmanBin: c.PacmanBin,
PacmanConfigPath: c.PacmanConf,
PacmanDBPath: "",
Runner: runner,
}
}