pacman.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. package pacman
  2. import (
  3. "fmt"
  4. "os"
  5. "os/exec"
  6. "strings"
  7. "github.com/demizer/go-alpm"
  8. )
  9. // RepoSearch describes a Repository search.
  10. type RepoSearch struct {
  11. Results []Result
  12. }
  13. // Result describes a pkg.
  14. type Result struct {
  15. Name string
  16. Repository string
  17. Version string
  18. Description string
  19. Installed bool
  20. }
  21. // SearchMode is search without numbers.
  22. const SearchMode int = -1
  23. // PacmanConf describes the default pacman config file
  24. const PacmanConf string = "/etc/pacman.conf"
  25. var conf alpm.PacmanConfig
  26. func init() {
  27. conf, _ = readConfig(PacmanConf)
  28. }
  29. func readConfig(pacmanconf string) (conf alpm.PacmanConfig, err error) {
  30. file, err := os.Open(pacmanconf)
  31. if err != nil {
  32. return
  33. }
  34. conf, err = alpm.ParseConfig(file)
  35. if err != nil {
  36. return
  37. }
  38. return
  39. }
  40. // UpdatePackages handles cache update and upgrade
  41. func UpdatePackages(flags []string) error {
  42. var cmd *exec.Cmd
  43. var args []string
  44. args = append(args, "pacman", "-Syu")
  45. args = append(args, flags...)
  46. cmd = exec.Command("sudo", args...)
  47. cmd.Stdout = os.Stdout
  48. cmd.Stdin = os.Stdin
  49. cmd.Stderr = os.Stderr
  50. err := cmd.Run()
  51. return err
  52. }
  53. // SearchRepos searches and prints packages in repo
  54. func SearchRepos(pkgName string, mode int) (err error) {
  55. h, err := conf.CreateHandle()
  56. defer h.Release()
  57. if err != nil {
  58. }
  59. dbList, _ := h.SyncDbs()
  60. localdb, _ := h.LocalDb()
  61. var installed bool
  62. var i int
  63. for _, db := range dbList.Slice() {
  64. for _, pkg := range db.PkgCache().Slice() {
  65. if strings.Contains(pkg.Name(), pkgName) {
  66. if r, _ := localdb.PkgByName(pkg.Name()); r != nil {
  67. installed = true
  68. } else {
  69. installed = false
  70. }
  71. switch {
  72. case mode != SearchMode && !installed:
  73. fmt.Printf("%d \x1b[1m%s/\x1b[33m%s \x1b[36m%s \x1b[32;40mInstalled\x1b[0m\n%s\n",
  74. i, db.Name(), pkg.Name(), pkg.Version(), pkg.Description())
  75. case mode != SearchMode && !installed:
  76. fmt.Printf("%d \x1b[1m%s/\x1b[33m%s \x1b[36m%s\x1b[0m\n%s\n",
  77. i, db.Name(), pkg.Name(), pkg.Version(), pkg.Description())
  78. case mode == SearchMode && !installed:
  79. fmt.Printf("\x1b[1m%s/\x1b[33m%s \x1b[36m%s \x1b[32;40mInstalled\x1b[0m\n%s\n",
  80. db.Name(), pkg.Name(), pkg.Version(), pkg.Description())
  81. case mode == SearchMode && !installed:
  82. fmt.Printf("\x1b[1m%s/\x1b[33m%s \x1b[36m%s\x1b[0m\n%s\n",
  83. db.Name(), pkg.Name(), pkg.Version(), pkg.Description())
  84. }
  85. i++
  86. }
  87. }
  88. }
  89. return
  90. }
  91. // SearchPackages handles repo searches. Creates a RepoSearch struct.
  92. func SearchPackages(pkgName string) (s RepoSearch, err error) {
  93. h, err := conf.CreateHandle()
  94. defer h.Release()
  95. if err != nil {
  96. }
  97. dbList, _ := h.SyncDbs()
  98. localdb, _ := h.LocalDb()
  99. var installed bool
  100. for _, db := range dbList.Slice() {
  101. for _, pkg := range db.PkgCache().Slice() {
  102. if strings.Contains(pkg.Name(), pkgName) {
  103. if r, _ := localdb.PkgByName(pkg.Name()); r != nil {
  104. installed = true
  105. } else {
  106. installed = false
  107. }
  108. s.Results = append(s.Results, Result{
  109. Name: pkg.Name(),
  110. Description: pkg.Description(),
  111. Version: pkg.Version(),
  112. Repository: db.Name(),
  113. Installed: installed,
  114. })
  115. }
  116. }
  117. }
  118. return
  119. }
  120. //PrintSearch receives a RepoSearch type and outputs pretty text.
  121. func (s *RepoSearch) PrintSearch(mode int) {
  122. for i, pkg := range s.Results {
  123. switch {
  124. case mode != SearchMode && pkg.Installed:
  125. fmt.Printf("%d \033[1m%s/\x1B[33m%s \x1B[36m%s \x1B[32;40mInstalled\033[0m\n%s\n",
  126. i, pkg.Repository, pkg.Name, pkg.Version, pkg.Description)
  127. case mode != SearchMode && !pkg.Installed:
  128. fmt.Printf("%d \033[1m%s/\x1B[33m%s \x1B[36m%s\033[0m\n%s\n",
  129. i, pkg.Repository, pkg.Name, pkg.Version, pkg.Description)
  130. case mode == SearchMode && pkg.Installed:
  131. fmt.Printf("\033[1m%s/\x1B[33m%s \x1B[36m%s \x1B[32;40mInstalled\033[0m\n%s\n",
  132. pkg.Repository, pkg.Name, pkg.Version, pkg.Description)
  133. case mode == SearchMode && !pkg.Installed:
  134. fmt.Printf("\033[1m%s/\x1B[33m%s \x1B[36m%s\033[0m\n%s\n",
  135. pkg.Repository, pkg.Name, pkg.Version, pkg.Description)
  136. }
  137. }
  138. }
  139. // PassToPacman outsorces execution to pacman binary without modifications.
  140. func PassToPacman(op string, pkgs []string, flags []string) error {
  141. var cmd *exec.Cmd
  142. var args []string
  143. args = append(args, op)
  144. if len(pkgs) != 0 {
  145. args = append(args, pkgs...)
  146. }
  147. if len(flags) != 0 {
  148. args = append(args, flags...)
  149. }
  150. if strings.Contains(op, "-Q") {
  151. cmd = exec.Command("pacman", args...)
  152. } else {
  153. args = append([]string{"pacman"}, args...)
  154. cmd = exec.Command("sudo", args...)
  155. }
  156. cmd.Stdout = os.Stdout
  157. cmd.Stdin = os.Stdin
  158. cmd.Stderr = os.Stderr
  159. err := cmd.Run()
  160. return err
  161. }
  162. // OutofRepo returns a list of packages not installed and not resolvable
  163. // Accepts inputs like 'gtk2', 'java-environment=8', 'linux >= 4.20'
  164. func OutofRepo(toCheck []string) (aur []string, repo []string, err error) {
  165. h, err := conf.CreateHandle()
  166. defer h.Release()
  167. if err != nil {
  168. return
  169. }
  170. localDb, err := h.LocalDb()
  171. if err != nil {
  172. return
  173. }
  174. dbList, err := h.SyncDbs()
  175. if err != nil {
  176. return
  177. }
  178. f := func(c rune) bool {
  179. return c == '>' || c == '<' || c == '=' || c == ' '
  180. }
  181. // First, Check if they're provided by package name.
  182. for _, dep := range toCheck {
  183. field := strings.FieldsFunc(dep, f)
  184. // Check if dep is installed
  185. _, err = localDb.PkgByName(field[0])
  186. if err == nil {
  187. continue
  188. }
  189. found := false
  190. Loop:
  191. for _, db := range dbList.Slice() {
  192. _, err = db.PkgByName(field[0])
  193. if err == nil {
  194. found = true
  195. repo = append(repo, field[0])
  196. break Loop
  197. }
  198. for _, pkg := range db.PkgCache().Slice() {
  199. for _, p := range pkg.Provides().Slice() {
  200. if p.String() == dep {
  201. found = true
  202. repo = append(repo, pkg.Name())
  203. break Loop
  204. }
  205. }
  206. }
  207. }
  208. if !found {
  209. aur = append(aur, field[0])
  210. }
  211. }
  212. return
  213. }
  214. // ForeignPackages returns a map of foreign packages, with their version and date as values.
  215. func ForeignPackages() (foreign map[string]*struct {
  216. Version string
  217. Date int64
  218. }, n int, err error) {
  219. h, err := conf.CreateHandle()
  220. defer h.Release()
  221. if err != nil {
  222. return
  223. }
  224. localDb, err := h.LocalDb()
  225. if err != nil {
  226. return
  227. }
  228. dbList, err := h.SyncDbs()
  229. if err != nil {
  230. return
  231. }
  232. foreign = make(map[string]*struct {
  233. Version string
  234. Date int64
  235. })
  236. // Find foreign packages in system
  237. for _, pkg := range localDb.PkgCache().Slice() {
  238. // Change to more effective method
  239. found := false
  240. for _, db := range dbList.Slice() {
  241. _, err = db.PkgByName(pkg.Name())
  242. if err == nil {
  243. found = true
  244. break
  245. }
  246. }
  247. if !found {
  248. foreign[pkg.Name()] = &struct {
  249. Version string
  250. Date int64
  251. }{pkg.Version(), pkg.InstallDate().Unix()}
  252. n++
  253. }
  254. }
  255. return
  256. }