config.go 6.6 KB

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