config.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "os"
  6. "os/exec"
  7. "strings"
  8. alpm "github.com/Jguer/go-alpm"
  9. pacmanconf "github.com/Morganamilo/go-pacmanconf"
  10. "github.com/leonelquinteros/gotext"
  11. "github.com/Jguer/yay/v10/pkg/settings"
  12. "github.com/Jguer/yay/v10/pkg/text"
  13. )
  14. // Verbosity settings for search
  15. const (
  16. numberMenu = iota
  17. detailed
  18. minimal
  19. )
  20. const (
  21. modeAUR targetMode = iota
  22. modeRepo
  23. modeAny
  24. )
  25. type targetMode int
  26. var yayVersion = "10.0.0"
  27. var localePath = "/usr/share/locale"
  28. // configFileName holds the name of the config file.
  29. const configFileName string = "config.json"
  30. // vcsFileName holds the name of the vcs file.
  31. const vcsFileName string = "vcs.json"
  32. // configHome handles config directory home
  33. var configHome string
  34. // cacheHome handles cache home
  35. var cacheHome string
  36. // savedInfo holds the current vcs info
  37. var savedInfo vcsInfo
  38. // configfile holds yay config file path.
  39. var configFile string
  40. // vcsfile holds yay vcs info file path.
  41. var vcsFile string
  42. // shouldSaveConfig holds whether or not the config should be saved
  43. var shouldSaveConfig bool
  44. // YayConf holds the current config values for yay.
  45. var config *settings.Configuration
  46. // AlpmConf holds the current config values for pacman.
  47. var pacmanConf *pacmanconf.Config
  48. // AlpmHandle is the alpm handle used by yay.
  49. var alpmHandle *alpm.Handle
  50. // Mode is used to restrict yay to AUR or repo only modes
  51. var mode = modeAny
  52. var hideMenus = false
  53. func defaultSettings() *settings.Configuration {
  54. newConfig := &settings.Configuration{
  55. AURURL: "https://aur.archlinux.org",
  56. BuildDir: "$HOME/.cache/yay",
  57. ABSDir: "$HOME/.cache/yay/abs",
  58. CleanAfter: false,
  59. Editor: "",
  60. EditorFlags: "",
  61. Devel: false,
  62. MakepkgBin: "makepkg",
  63. MakepkgConf: "",
  64. NoConfirm: false,
  65. PacmanBin: "pacman",
  66. PGPFetch: true,
  67. PacmanConf: "/etc/pacman.conf",
  68. GpgFlags: "",
  69. MFlags: "",
  70. GitFlags: "",
  71. SortMode: settings.BottomUp,
  72. CompletionInterval: 7,
  73. SortBy: "votes",
  74. SearchBy: "name-desc",
  75. SudoLoop: false,
  76. GitBin: "git",
  77. GpgBin: "gpg",
  78. SudoBin: "sudo",
  79. SudoFlags: "",
  80. TimeUpdate: false,
  81. RequestSplitN: 150,
  82. ReDownload: "no",
  83. ReBuild: "no",
  84. BatchInstall: false,
  85. AnswerClean: "",
  86. AnswerDiff: "",
  87. AnswerEdit: "",
  88. AnswerUpgrade: "",
  89. RemoveMake: "ask",
  90. Provides: true,
  91. UpgradeMenu: true,
  92. CleanMenu: true,
  93. DiffMenu: true,
  94. EditMenu: false,
  95. UseAsk: false,
  96. CombinedUpgrade: false,
  97. }
  98. if os.Getenv("XDG_CACHE_HOME") != "" {
  99. newConfig.BuildDir = "$XDG_CACHE_HOME/yay"
  100. }
  101. return newConfig
  102. }
  103. // Editor returns the preferred system editor.
  104. func editor() (editor string, args []string) {
  105. switch {
  106. case config.Editor != "":
  107. editor, err := exec.LookPath(config.Editor)
  108. if err != nil {
  109. fmt.Fprintln(os.Stderr, err)
  110. } else {
  111. return editor, strings.Fields(config.EditorFlags)
  112. }
  113. fallthrough
  114. case os.Getenv("EDITOR") != "":
  115. if editorArgs := strings.Fields(os.Getenv("EDITOR")); len(editorArgs) != 0 {
  116. editor, err := exec.LookPath(editorArgs[0])
  117. if err != nil {
  118. fmt.Fprintln(os.Stderr, err)
  119. } else {
  120. return editor, editorArgs[1:]
  121. }
  122. }
  123. fallthrough
  124. case os.Getenv("VISUAL") != "":
  125. if editorArgs := strings.Fields(os.Getenv("VISUAL")); len(editorArgs) != 0 {
  126. editor, err := exec.LookPath(editorArgs[0])
  127. if err != nil {
  128. fmt.Fprintln(os.Stderr, err)
  129. } else {
  130. return editor, editorArgs[1:]
  131. }
  132. }
  133. fallthrough
  134. default:
  135. fmt.Fprintln(os.Stderr)
  136. text.Errorln(gotext.Get("%s is not set", bold(cyan("$EDITOR"))))
  137. text.Warnln(gotext.Get("Add %s or %s to your environment variables", bold(cyan("$EDITOR")), bold(cyan("$VISUAL"))))
  138. for {
  139. text.Infoln(gotext.Get("Edit PKGBUILD with?"))
  140. editorInput, err := getInput("")
  141. if err != nil {
  142. fmt.Fprintln(os.Stderr, err)
  143. continue
  144. }
  145. editorArgs := strings.Fields(editorInput)
  146. if len(editorArgs) == 0 {
  147. continue
  148. }
  149. editor, err := exec.LookPath(editorArgs[0])
  150. if err != nil {
  151. fmt.Fprintln(os.Stderr, err)
  152. continue
  153. }
  154. return editor, editorArgs[1:]
  155. }
  156. }
  157. }
  158. // ContinueTask prompts if user wants to continue task.
  159. // If NoConfirm is set the action will continue without user input.
  160. func continueTask(s string, cont bool) bool {
  161. if config.NoConfirm {
  162. return cont
  163. }
  164. var response string
  165. var postFix string
  166. yes := gotext.Get("yes")
  167. no := gotext.Get("no")
  168. y := string([]rune(yes)[0])
  169. n := string([]rune(no)[0])
  170. if cont {
  171. postFix = fmt.Sprintf(" [%s/%s] ", strings.ToUpper(y), n)
  172. } else {
  173. postFix = fmt.Sprintf(" [%s/%s] ", y, strings.ToUpper(n))
  174. }
  175. text.Info(bold(s), bold(postFix))
  176. if _, err := fmt.Scanln(&response); err != nil {
  177. return cont
  178. }
  179. response = strings.ToLower(response)
  180. return response == yes || response == y
  181. }
  182. func getInput(defaultValue string) (string, error) {
  183. text.Info()
  184. if defaultValue != "" || config.NoConfirm {
  185. fmt.Println(defaultValue)
  186. return defaultValue, nil
  187. }
  188. reader := bufio.NewReader(os.Stdin)
  189. buf, overflow, err := reader.ReadLine()
  190. if err != nil {
  191. return "", err
  192. }
  193. if overflow {
  194. return "", fmt.Errorf(gotext.Get("input too long"))
  195. }
  196. return string(buf), nil
  197. }
  198. func toUsage(usages []string) alpm.Usage {
  199. if len(usages) == 0 {
  200. return alpm.UsageAll
  201. }
  202. var ret alpm.Usage
  203. for _, usage := range usages {
  204. switch usage {
  205. case "Sync":
  206. ret |= alpm.UsageSync
  207. case "Search":
  208. ret |= alpm.UsageSearch
  209. case "Install":
  210. ret |= alpm.UsageInstall
  211. case "Upgrade":
  212. ret |= alpm.UsageUpgrade
  213. case "All":
  214. ret |= alpm.UsageAll
  215. }
  216. }
  217. return ret
  218. }
  219. func configureAlpm() error {
  220. // TODO: set SigLevel
  221. // sigLevel := alpm.SigPackage | alpm.SigPackageOptional | alpm.SigDatabase | alpm.SigDatabaseOptional
  222. // localFileSigLevel := alpm.SigUseDefault
  223. // remoteFileSigLevel := alpm.SigUseDefault
  224. for _, repo := range pacmanConf.Repos {
  225. // TODO: set SigLevel
  226. db, err := alpmHandle.RegisterSyncDB(repo.Name, 0)
  227. if err != nil {
  228. return err
  229. }
  230. db.SetServers(repo.Servers)
  231. db.SetUsage(toUsage(repo.Usage))
  232. }
  233. if err := alpmHandle.SetCacheDirs(pacmanConf.CacheDir); err != nil {
  234. return err
  235. }
  236. // add hook directories 1-by-1 to avoid overwriting the system directory
  237. for _, dir := range pacmanConf.HookDir {
  238. if err := alpmHandle.AddHookDir(dir); err != nil {
  239. return err
  240. }
  241. }
  242. if err := alpmHandle.SetGPGDir(pacmanConf.GPGDir); err != nil {
  243. return err
  244. }
  245. if err := alpmHandle.SetLogFile(pacmanConf.LogFile); err != nil {
  246. return err
  247. }
  248. if err := alpmHandle.SetIgnorePkgs(pacmanConf.IgnorePkg); err != nil {
  249. return err
  250. }
  251. if err := alpmHandle.SetIgnoreGroups(pacmanConf.IgnoreGroup); err != nil {
  252. return err
  253. }
  254. if err := alpmHandle.SetArch(pacmanConf.Architecture); err != nil {
  255. return err
  256. }
  257. if err := alpmHandle.SetNoUpgrades(pacmanConf.NoUpgrade); err != nil {
  258. return err
  259. }
  260. if err := alpmHandle.SetNoExtracts(pacmanConf.NoExtract); err != nil {
  261. return err
  262. }
  263. /*if err := alpmHandle.SetDefaultSigLevel(sigLevel); err != nil {
  264. return err
  265. }
  266. if err := alpmHandle.SetLocalFileSigLevel(localFileSigLevel); err != nil {
  267. return err
  268. }
  269. if err := alpmHandle.SetRemoteFileSigLevel(remoteFileSigLevel); err != nil {
  270. return err
  271. }*/
  272. if err := alpmHandle.SetUseSyslog(pacmanConf.UseSyslog); err != nil {
  273. return err
  274. }
  275. return alpmHandle.SetCheckSpace(pacmanConf.CheckSpace)
  276. }