config.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. package config
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io"
  6. "net/http"
  7. "os"
  8. "os/exec"
  9. "os/user"
  10. "strings"
  11. alpm "github.com/jguer/go-alpm"
  12. )
  13. // Verbosity settings for search
  14. const (
  15. NumberMenu = iota
  16. Detailed
  17. Minimal
  18. )
  19. // Describes Sorting method for numberdisplay
  20. const (
  21. BottomUp = iota
  22. TopDown
  23. )
  24. // Configuration stores yay's config.
  25. type Configuration struct {
  26. BuildDir string `json:"buildDir"`
  27. Editor string `json:"editor"`
  28. MakepkgBin string `json:"makepkgbin"`
  29. Shell string `json:"-"`
  30. NoConfirm bool `json:"noconfirm"`
  31. Devel bool `json:"devel"`
  32. PacmanBin string `json:"pacmanbin"`
  33. PacmanConf string `json:"pacmanconf"`
  34. RequestSplitN int `json:"requestsplitn"`
  35. SearchMode int `json:"-"`
  36. SortMode int `json:"sortmode"`
  37. TarBin string `json:"tarbin"`
  38. TimeUpdate bool `json:"timeupdate"`
  39. }
  40. // YayConf holds the current config values for yay.
  41. var YayConf Configuration
  42. // AlpmConf holds the current config values for pacman.
  43. var AlpmConf alpm.PacmanConfig
  44. // AlpmHandle is the alpm handle used by yay.
  45. var AlpmHandle *alpm.Handle
  46. func init() {
  47. defaultSettings(&YayConf)
  48. var err error
  49. configfile := os.Getenv("HOME") + "/.config/yay/config.json"
  50. if _, err = os.Stat(configfile); os.IsNotExist(err) {
  51. _ = os.MkdirAll(os.Getenv("HOME")+"/.config/yay", 0755)
  52. // Save the default config if nothing is found
  53. SaveConfig()
  54. } else {
  55. file, err := os.Open(configfile)
  56. if err != nil {
  57. fmt.Println("Error reading config:", err)
  58. } else {
  59. decoder := json.NewDecoder(file)
  60. err = decoder.Decode(&YayConf)
  61. if err != nil {
  62. fmt.Println("Loading default Settings\nError reading config:", err)
  63. defaultSettings(&YayConf)
  64. }
  65. }
  66. }
  67. AlpmConf, err = readAlpmConfig(YayConf.PacmanConf)
  68. if err != nil {
  69. fmt.Println("Unable to read Pacman conf", err)
  70. os.Exit(1)
  71. }
  72. AlpmHandle, err = AlpmConf.CreateHandle()
  73. if err != nil {
  74. fmt.Println("Unable to CreateHandle", err)
  75. os.Exit(1)
  76. }
  77. }
  78. func readAlpmConfig(pacmanconf string) (conf alpm.PacmanConfig, err error) {
  79. file, err := os.Open(pacmanconf)
  80. if err != nil {
  81. return
  82. }
  83. conf, err = alpm.ParseConfig(file)
  84. if err != nil {
  85. return
  86. }
  87. return
  88. }
  89. // SaveConfig writes yay config to file.
  90. func SaveConfig() error {
  91. YayConf.NoConfirm = false
  92. configfile := os.Getenv("HOME") + "/.config/yay/config.json"
  93. marshalledinfo, _ := json.MarshalIndent(YayConf, "", "\t")
  94. in, err := os.OpenFile(configfile, os.O_RDWR|os.O_CREATE, 0755)
  95. if err != nil {
  96. return err
  97. }
  98. defer in.Close()
  99. _, err = in.Write(marshalledinfo)
  100. if err != nil {
  101. return err
  102. }
  103. err = in.Sync()
  104. return err
  105. }
  106. func defaultSettings(config *Configuration) {
  107. u, err := user.Current()
  108. if err != nil {
  109. panic(err)
  110. }
  111. config.BuildDir = fmt.Sprintf("/tmp/yaytmp-%s/", u.Uid)
  112. config.Editor = ""
  113. config.Devel = false
  114. config.MakepkgBin = "/usr/bin/makepkg"
  115. config.NoConfirm = false
  116. config.PacmanBin = "/usr/bin/pacman"
  117. config.PacmanConf = "/etc/pacman.conf"
  118. config.SortMode = BottomUp
  119. config.TarBin = "/usr/bin/bsdtar"
  120. config.TimeUpdate = false
  121. config.RequestSplitN = 150
  122. }
  123. // Editor returns the preferred system editor.
  124. func Editor() string {
  125. switch {
  126. case YayConf.Editor != "":
  127. editor, err := exec.LookPath(YayConf.Editor)
  128. if err != nil {
  129. fmt.Println(err)
  130. } else {
  131. return editor
  132. }
  133. fallthrough
  134. case os.Getenv("EDITOR") != "":
  135. editor, err := exec.LookPath(os.Getenv("EDITOR"))
  136. if err != nil {
  137. fmt.Println(err)
  138. } else {
  139. return editor
  140. }
  141. fallthrough
  142. case os.Getenv("VISUAL") != "":
  143. editor, err := exec.LookPath(os.Getenv("VISUAL"))
  144. if err != nil {
  145. fmt.Println(err)
  146. } else {
  147. return editor
  148. }
  149. fallthrough
  150. default:
  151. fmt.Printf("\x1b[1;31;40mWarning: \x1B[1;33;40m$EDITOR\x1b[0;37;40m is not set.\x1b[0m\nPlease add $EDITOR or to your environment variables.\n")
  152. editorLoop:
  153. fmt.Printf("\x1b[32m%s\x1b[0m ", "Edit PKGBUILD with:")
  154. var editorInput string
  155. _, err := fmt.Scanln(&editorInput)
  156. if err != nil {
  157. fmt.Println(err)
  158. goto editorLoop
  159. }
  160. editor, err := exec.LookPath(editorInput)
  161. if err != nil {
  162. fmt.Println(err)
  163. goto editorLoop
  164. }
  165. return editor
  166. }
  167. }
  168. // ContinueTask prompts if user wants to continue task.
  169. //If NoConfirm is set the action will continue without user input.
  170. func ContinueTask(s string, def string) (cont bool) {
  171. if YayConf.NoConfirm {
  172. return true
  173. }
  174. var postFix string
  175. if def == "nN" {
  176. postFix = "[Y/n] "
  177. } else {
  178. postFix = "[y/N] "
  179. }
  180. var response string
  181. fmt.Printf("\x1b[1;32m==> %s\x1b[1;37m %s\x1b[0m", s, postFix)
  182. n, err := fmt.Scanln(&response)
  183. if err != nil || n == 0 {
  184. return true
  185. }
  186. if response == string(def[0]) || response == string(def[1]) {
  187. return false
  188. }
  189. return true
  190. }
  191. func downloadFile(path string, url string) (err error) {
  192. // Create the file
  193. out, err := os.Create(path)
  194. if err != nil {
  195. return err
  196. }
  197. defer out.Close()
  198. // Get the data
  199. resp, err := http.Get(url)
  200. if err != nil {
  201. return err
  202. }
  203. defer resp.Body.Close()
  204. // Writer the body to file
  205. _, err = io.Copy(out, resp.Body)
  206. return err
  207. }
  208. // DownloadAndUnpack downloads url tgz and extracts to path.
  209. func DownloadAndUnpack(url string, path string, trim bool) (err error) {
  210. err = os.MkdirAll(path, 0755)
  211. if err != nil {
  212. return
  213. }
  214. tokens := strings.Split(url, "/")
  215. fileName := tokens[len(tokens)-1]
  216. tarLocation := path + fileName
  217. defer os.Remove(tarLocation)
  218. err = downloadFile(tarLocation, url)
  219. if err != nil {
  220. return
  221. }
  222. if trim {
  223. err = exec.Command("/bin/sh", "-c",
  224. YayConf.TarBin+" --strip-components 2 --include='*/"+fileName[:len(fileName)-7]+"/trunk/' -xf "+tarLocation+" -C "+path).Run()
  225. os.Rename(path+"trunk", path+fileName[:len(fileName)-7]) // kurwa
  226. } else {
  227. err = exec.Command(YayConf.TarBin, "-xf", tarLocation, "-C", path).Run()
  228. }
  229. if err != nil {
  230. return
  231. }
  232. return
  233. }
  234. // PassToPacman outsorces execution to pacman binary without modifications.
  235. func PassToPacman(op string, pkgs []string, flags []string) error {
  236. var cmd *exec.Cmd
  237. var args []string
  238. args = append(args, op)
  239. if len(pkgs) != 0 {
  240. args = append(args, pkgs...)
  241. }
  242. if len(flags) != 0 {
  243. args = append(args, flags...)
  244. }
  245. if strings.Contains(op, "-Q") || op == "Si" {
  246. cmd = exec.Command(YayConf.PacmanBin, args...)
  247. } else {
  248. args = append([]string{YayConf.PacmanBin}, args...)
  249. cmd = exec.Command("sudo", args...)
  250. }
  251. cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
  252. err := cmd.Run()
  253. return err
  254. }
  255. // Human returns results in Human readable format.
  256. func Human(size int64) string {
  257. floatsize := float32(size)
  258. units := [...]string{"", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi"}
  259. for _, unit := range units {
  260. if floatsize < 1024 {
  261. return fmt.Sprintf("%.1f %sB", floatsize, unit)
  262. }
  263. floatsize /= 1024
  264. }
  265. return fmt.Sprintf("%d%s", size, "B")
  266. }