yay/main.go

264 lines
5.3 KiB
Go
Raw Normal View History

2018-03-22 15:46:48 +00:00
package main
import (
2018-03-22 16:39:27 +00:00
"encoding/json"
"fmt"
2018-03-22 15:46:48 +00:00
"os"
"path/filepath"
"strings"
alpm "github.com/jguer/go-alpm"
)
func setPaths() error {
if _configHome, set := os.LookupEnv("XDG_CONFIG_HOME"); set {
if _configHome == "" {
return fmt.Errorf("XDG_CONFIG_HOME set but empty")
}
2018-06-05 13:14:49 +00:00
configHome = filepath.Join(_configHome, "yay")
} else if _configHome, set := os.LookupEnv("HOME"); set {
if _configHome == "" {
return fmt.Errorf("HOME set but empty")
}
2018-06-05 13:14:49 +00:00
configHome = filepath.Join(_configHome, ".config/yay")
2018-03-22 15:46:48 +00:00
} else {
return fmt.Errorf("XDG_CONFIG_HOME and HOME unset")
2018-03-22 15:46:48 +00:00
}
if _cacheHome, set := os.LookupEnv("XDG_CACHE_HOME"); set {
if _cacheHome == "" {
return fmt.Errorf("XDG_CACHE_HOME set but empty")
}
cacheHome = filepath.Join(_cacheHome, "yay")
} else if _cacheHome, set := os.LookupEnv("HOME"); set {
if _cacheHome == "" {
return fmt.Errorf("XDG_CACHE_HOME set but empty")
}
cacheHome = filepath.Join(_cacheHome, ".cache/yay")
2018-03-22 15:46:48 +00:00
} else {
return fmt.Errorf("XDG_CACHE_HOME and HOME unset")
2018-03-22 15:46:48 +00:00
}
configFile = filepath.Join(configHome, configFileName)
vcsFile = filepath.Join(cacheHome, vcsFileName)
return nil
2018-03-22 15:46:48 +00:00
}
func initConfig() (err error) {
defaultSettings(&config)
if _, err = os.Stat(configFile); os.IsNotExist(err) {
err = os.MkdirAll(filepath.Dir(configFile), 0755)
if err != nil {
err = fmt.Errorf("Unable to create config directory:\n%s\n"+
"The error was:\n%s", filepath.Dir(configFile), err)
return
}
// Save the default config if nothing is found
config.saveConfig()
} else {
cfile, errf := os.OpenFile(configFile, os.O_RDWR|os.O_CREATE, 0644)
if errf != nil {
fmt.Printf("Error reading config: %s\n", err)
} else {
defer cfile.Close()
decoder := json.NewDecoder(cfile)
err = decoder.Decode(&config)
if err != nil {
fmt.Println("Loading default Settings.\nError reading config:",
err)
defaultSettings(&config)
}
if _, err = os.Stat(config.BuildDir); os.IsNotExist(err) {
err = os.MkdirAll(config.BuildDir, 0755)
if err != nil {
err = fmt.Errorf("Unable to create BuildDir directory:\n%s\n"+
"The error was:\n%s", config.BuildDir, err)
return
}
}
2018-03-22 15:46:48 +00:00
}
}
return
}
func initVCS() (err error) {
if _, err = os.Stat(vcsFile); os.IsNotExist(err) {
err = os.MkdirAll(filepath.Dir(vcsFile), 0755)
if err != nil {
err = fmt.Errorf("Unable to create vcs directory:\n%s\n"+
"The error was:\n%s", filepath.Dir(configFile), err)
return
}
} else {
vfile, err := os.OpenFile(vcsFile, os.O_RDONLY|os.O_CREATE, 0644)
if err == nil {
defer vfile.Close()
decoder := json.NewDecoder(vfile)
_ = decoder.Decode(&savedInfo)
}
}
return
}
func initAlpm() (err error) {
var value string
var exists bool
//var double bool
alpmConf, err = readAlpmConfig(config.PacmanConf)
if err != nil {
err = fmt.Errorf("Unable to read Pacman conf: %s", err)
return
}
value, _, exists = cmdArgs.getArg("dbpath", "b")
if exists {
alpmConf.DBPath = value
}
value, _, exists = cmdArgs.getArg("root", "r")
if exists {
alpmConf.RootDir = value
}
value, _, exists = cmdArgs.getArg("arch")
if exists {
alpmConf.Architecture = value
}
value, _, exists = cmdArgs.getArg("ignore")
if exists {
alpmConf.IgnorePkg = append(alpmConf.IgnorePkg, strings.Split(value, ",")...)
}
value, _, exists = cmdArgs.getArg("ignoregroup")
if exists {
alpmConf.IgnoreGroup = append(alpmConf.IgnoreGroup, strings.Split(value, ",")...)
}
//TODO
//current system does not allow duplicate arguments
//but pacman allows multiple cachdirs to be passed
//for now only handle one cache dir
value, _, exists = cmdArgs.getArg("cachdir")
if exists {
alpmConf.CacheDir = []string{value}
}
value, _, exists = cmdArgs.getArg("gpgdir")
if exists {
alpmConf.GPGDir = value
}
Separate Pacman upgrade and AUR Upgrade by default Currently When performing a system upgrade, Yay will first refresh the database then perform the repo and AUR upgrade. This allows Yay to add some features such as better batch interaction, showing potential dependency problems before the upgrade starts and combined menus showing AUR and repo upgrades together. There has been discussion that this approach is a bad idea. The main issue people have is that the separation of the database refresh and the upgrade could lead to a partial upgrade if Yay fails between the two stages. Personally I do not like this argument, there are valid reasons to Yay to fail between these points. For example there may be dependency or conflict issues during the AUR upgrade. Yay can detect these before any installing actually starts and exit, just like how pacman will when there are dependency problems. If Yay does fail between these points, for the previously mentioned reasons or even a crash then a simple refresh will not cause a partial upgrade by itself. It is then the user's responsibility to either resolve these issues or instead perform an upgrade using pacman directly. My opinions aside, The discussions on the Arch wiki has reached a decision, this method is not recommended. So to follow the decided best practises this behaviour has been disabled by default. This behaviour can be toggled using the --[no]combinedupgrade flag It should be noted that Yay's upgrade menu will not show repo packages unless --combinedupgrade is used.
2018-06-22 13:44:38 +00:00
err = initAlpmHandle()
2018-03-22 15:46:48 +00:00
if err != nil {
return
}
value, _, _ = cmdArgs.getArg("color")
2018-03-22 15:46:48 +00:00
if value == "always" || value == "auto" {
useColor = true
} else if value == "never" {
useColor = false
} else {
useColor = alpmConf.Options&alpm.ConfColor > 0
}
Separate Pacman upgrade and AUR Upgrade by default Currently When performing a system upgrade, Yay will first refresh the database then perform the repo and AUR upgrade. This allows Yay to add some features such as better batch interaction, showing potential dependency problems before the upgrade starts and combined menus showing AUR and repo upgrades together. There has been discussion that this approach is a bad idea. The main issue people have is that the separation of the database refresh and the upgrade could lead to a partial upgrade if Yay fails between the two stages. Personally I do not like this argument, there are valid reasons to Yay to fail between these points. For example there may be dependency or conflict issues during the AUR upgrade. Yay can detect these before any installing actually starts and exit, just like how pacman will when there are dependency problems. If Yay does fail between these points, for the previously mentioned reasons or even a crash then a simple refresh will not cause a partial upgrade by itself. It is then the user's responsibility to either resolve these issues or instead perform an upgrade using pacman directly. My opinions aside, The discussions on the Arch wiki has reached a decision, this method is not recommended. So to follow the decided best practises this behaviour has been disabled by default. This behaviour can be toggled using the --[no]combinedupgrade flag It should be noted that Yay's upgrade menu will not show repo packages unless --combinedupgrade is used.
2018-06-22 13:44:38 +00:00
return
}
func initAlpmHandle() (err error) {
if alpmHandle != nil {
err = alpmHandle.Release()
if err != nil {
return err
}
}
2018-03-22 15:46:48 +00:00
Separate Pacman upgrade and AUR Upgrade by default Currently When performing a system upgrade, Yay will first refresh the database then perform the repo and AUR upgrade. This allows Yay to add some features such as better batch interaction, showing potential dependency problems before the upgrade starts and combined menus showing AUR and repo upgrades together. There has been discussion that this approach is a bad idea. The main issue people have is that the separation of the database refresh and the upgrade could lead to a partial upgrade if Yay fails between the two stages. Personally I do not like this argument, there are valid reasons to Yay to fail between these points. For example there may be dependency or conflict issues during the AUR upgrade. Yay can detect these before any installing actually starts and exit, just like how pacman will when there are dependency problems. If Yay does fail between these points, for the previously mentioned reasons or even a crash then a simple refresh will not cause a partial upgrade by itself. It is then the user's responsibility to either resolve these issues or instead perform an upgrade using pacman directly. My opinions aside, The discussions on the Arch wiki has reached a decision, this method is not recommended. So to follow the decided best practises this behaviour has been disabled by default. This behaviour can be toggled using the --[no]combinedupgrade flag It should be noted that Yay's upgrade menu will not show repo packages unless --combinedupgrade is used.
2018-06-22 13:44:38 +00:00
alpmHandle, err = alpmConf.CreateHandle()
if err != nil {
err = fmt.Errorf("Unable to CreateHandle: %s", err)
return
}
alpmHandle.SetQuestionCallback(questionCallback)
2018-03-22 15:46:48 +00:00
return
}
func main() {
var status int
var err error
if 0 == os.Geteuid() {
fmt.Println("Please avoid running yay as root/sudo.")
}
err = cmdArgs.parseCommandLine()
if err != nil {
fmt.Println(err)
status = 1
goto cleanup
}
err = setPaths()
if err != nil {
fmt.Println(err)
status = 1
goto cleanup
}
2018-03-22 15:46:48 +00:00
err = initConfig()
if err != nil {
fmt.Println(err)
status = 1
goto cleanup
}
cmdArgs.extractYayOptions()
2018-03-22 15:46:48 +00:00
err = initVCS()
if err != nil {
fmt.Println(err)
status = 1
goto cleanup
}
err = initAlpm()
if err != nil {
fmt.Println(err)
status = 1
goto cleanup
}
err = handleCmd()
if err != nil {
if err.Error() != "" {
fmt.Println(err)
}
2018-03-22 15:46:48 +00:00
status = 1
goto cleanup
}
cleanup:
//cleanup
2018-05-12 16:16:48 +00:00
//from here on out don't exit if an error occurs
2018-03-22 15:46:48 +00:00
//if we fail to save the configuration
//at least continue on and try clean up other parts
if alpmHandle != nil {
err = alpmHandle.Release()
if err != nil {
fmt.Println(err)
status = 1
}
}
os.Exit(status)
}