pacman.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. package pacman
  2. import (
  3. "fmt"
  4. "os"
  5. "os/exec"
  6. "strings"
  7. "github.com/jguer/go-alpm"
  8. )
  9. // RepoSearch describes a Repository search.
  10. type RepoSearch []Result
  11. // Result describes a pkg.
  12. type Result struct {
  13. Name string
  14. Repository string
  15. Version string
  16. Description string
  17. Group string
  18. Installed bool
  19. }
  20. // PacmanConf describes the default pacman config file
  21. const PacmanConf string = "/etc/pacman.conf"
  22. // SortMode NumberMenu and Search
  23. var SortMode = DownTop
  24. // Determines NumberMenu and Search Order
  25. const (
  26. DownTop = iota
  27. TopDown
  28. )
  29. var conf alpm.PacmanConfig
  30. func init() {
  31. conf, _ = readConfig(PacmanConf)
  32. }
  33. func readConfig(pacmanconf string) (conf alpm.PacmanConfig, err error) {
  34. file, err := os.Open(pacmanconf)
  35. if err != nil {
  36. return
  37. }
  38. conf, err = alpm.ParseConfig(file)
  39. if err != nil {
  40. return
  41. }
  42. return
  43. }
  44. // UpdatePackages handles cache update and upgrade
  45. func UpdatePackages(flags []string) error {
  46. var cmd *exec.Cmd
  47. var args []string
  48. args = append(args, "pacman", "-Syu")
  49. args = append(args, flags...)
  50. cmd = exec.Command("sudo", args...)
  51. cmd.Stdout = os.Stdout
  52. cmd.Stdin = os.Stdin
  53. cmd.Stderr = os.Stderr
  54. err := cmd.Run()
  55. return err
  56. }
  57. // Search handles repo searches. Creates a RepoSearch struct.
  58. func Search(pkgName string) (s RepoSearch, n int, err error) {
  59. h, err := conf.CreateHandle()
  60. defer h.Release()
  61. if err != nil {
  62. }
  63. localDb, err := h.LocalDb()
  64. if err != nil {
  65. return
  66. }
  67. dbList, err := h.SyncDbs()
  68. if err != nil {
  69. return
  70. }
  71. var installed bool
  72. dbS := dbList.Slice()
  73. var f int
  74. if SortMode == DownTop {
  75. f = len(dbS) - 1
  76. } else {
  77. f = 0
  78. }
  79. for {
  80. pkgS := dbS[f].PkgCache().Slice()
  81. var i int
  82. if SortMode == DownTop {
  83. i = len(pkgS) - 1
  84. } else {
  85. i = 0
  86. }
  87. for {
  88. if strings.Contains(pkgS[i].Name(), pkgName) {
  89. if r, _ := localDb.PkgByName(pkgS[i].Name()); r != nil {
  90. installed = true
  91. } else {
  92. installed = false
  93. }
  94. s = append(s, Result{
  95. Name: pkgS[i].Name(),
  96. Description: pkgS[i].Description(),
  97. Version: pkgS[i].Version(),
  98. Repository: dbS[f].Name(),
  99. Group: strings.Join(pkgS[i].Groups().Slice(), ","),
  100. Installed: installed,
  101. })
  102. n++
  103. }
  104. if SortMode == DownTop {
  105. if i > 0 {
  106. i--
  107. } else {
  108. break
  109. }
  110. } else {
  111. if i < len(pkgS)-1 {
  112. i++
  113. } else {
  114. break
  115. }
  116. }
  117. }
  118. if SortMode == DownTop {
  119. if f > 0 {
  120. f--
  121. } else {
  122. break
  123. }
  124. } else {
  125. if f < len(dbS)-1 {
  126. f++
  127. } else {
  128. break
  129. }
  130. }
  131. }
  132. return
  133. }
  134. //PrintSearch receives a RepoSearch type and outputs pretty text.
  135. func (s RepoSearch) PrintSearch(mode int) {
  136. for i, res := range s {
  137. var toprint string
  138. if mode != -1 {
  139. if mode == 0 {
  140. toprint += fmt.Sprintf("%d ", len(s)-i-1)
  141. } else {
  142. toprint += fmt.Sprintf("%d ", i)
  143. }
  144. }
  145. toprint += fmt.Sprintf("\x1b[1m%s/\x1b[33m%s \x1b[36m%s \x1b[0m",
  146. res.Repository, res.Name, res.Version)
  147. if len(res.Group) != 0 {
  148. toprint += fmt.Sprintf("(%s) ", res.Group)
  149. }
  150. if res.Installed == true {
  151. toprint += fmt.Sprintf("\x1b[32;40mInstalled\x1b[0m")
  152. }
  153. toprint += "\n" + res.Description
  154. fmt.Println(toprint)
  155. }
  156. }
  157. // PFactory execute an action over a series of packages without reopening the handle everytime.
  158. // Everybody told me it wouln't work. It does. It's just not pretty.
  159. // When it worked: https://youtu.be/a4Z5BdEL0Ag?t=1m11s
  160. func PFactory(action func(interface{})) func(name string, object interface{}, rel bool) {
  161. h, _ := conf.CreateHandle()
  162. localDb, _ := h.LocalDb()
  163. return func(name string, object interface{}, rel bool) {
  164. _, err := localDb.PkgByName(name)
  165. if err == nil {
  166. action(object)
  167. }
  168. if rel {
  169. h.Release()
  170. }
  171. }
  172. }
  173. // PackageSlices separates an input slice into aur and repo slices
  174. func PackageSlices(toCheck []string) (aur []string, repo []string, err error) {
  175. h, err := conf.CreateHandle()
  176. defer h.Release()
  177. if err != nil {
  178. return
  179. }
  180. dbList, err := h.SyncDbs()
  181. if err != nil {
  182. return
  183. }
  184. for _, pkg := range toCheck {
  185. // Check if dep is installed
  186. found := false
  187. for _, db := range dbList.Slice() {
  188. _, err = db.PkgByName(pkg)
  189. if err == nil {
  190. found = true
  191. repo = append(repo, pkg)
  192. break
  193. }
  194. }
  195. if !found {
  196. aur = append(aur, pkg)
  197. }
  198. }
  199. return
  200. }
  201. // OutofRepo returns a list of packages not installed and not resolvable
  202. // Accepts inputs like 'gtk2', 'java-environment=8', 'linux >= 4.20'
  203. func OutofRepo(toCheck []string) (aur []string, repo []string, err error) {
  204. h, err := conf.CreateHandle()
  205. defer h.Release()
  206. if err != nil {
  207. return
  208. }
  209. localDb, err := h.LocalDb()
  210. if err != nil {
  211. return
  212. }
  213. dbList, err := h.SyncDbs()
  214. if err != nil {
  215. return
  216. }
  217. f := func(c rune) bool {
  218. return c == '>' || c == '<' || c == '=' || c == ' '
  219. }
  220. // First, Check if they're provided by package name.
  221. for _, dep := range toCheck {
  222. field := strings.FieldsFunc(dep, f)
  223. // Check if dep is installed
  224. _, err = localDb.PkgByName(field[0])
  225. if err == nil {
  226. continue
  227. }
  228. found := false
  229. Loop:
  230. for _, db := range dbList.Slice() {
  231. _, err = db.PkgByName(field[0])
  232. if err == nil {
  233. found = true
  234. repo = append(repo, field[0])
  235. break Loop
  236. }
  237. for _, pkg := range db.PkgCache().Slice() {
  238. for _, p := range pkg.Provides().Slice() {
  239. if p.String() == dep {
  240. found = true
  241. repo = append(repo, pkg.Name())
  242. break Loop
  243. }
  244. }
  245. }
  246. }
  247. if !found {
  248. aur = append(aur, field[0])
  249. }
  250. }
  251. return
  252. }
  253. // Install sends an install command to pacman with the pkgName slice
  254. func Install(pkgName []string, flags []string) (err error) {
  255. if len(pkgName) == 0 {
  256. return nil
  257. }
  258. var cmd *exec.Cmd
  259. var args []string
  260. args = append(args, "pacman")
  261. args = append(args, "-S")
  262. args = append(args, pkgName...)
  263. args = append(args, flags...)
  264. cmd = exec.Command("sudo", args...)
  265. cmd.Stdout = os.Stdout
  266. cmd.Stdin = os.Stdin
  267. cmd.Stderr = os.Stderr
  268. cmd.Run()
  269. return nil
  270. }
  271. // ForeignPackages returns a map of foreign packages, with their version and date as values.
  272. func ForeignPackages() (foreign map[string]*struct {
  273. Version string
  274. Date int64
  275. }, n int, err error) {
  276. h, err := conf.CreateHandle()
  277. defer h.Release()
  278. if err != nil {
  279. return
  280. }
  281. localDb, err := h.LocalDb()
  282. if err != nil {
  283. return
  284. }
  285. dbList, err := h.SyncDbs()
  286. if err != nil {
  287. return
  288. }
  289. foreign = make(map[string]*struct {
  290. Version string
  291. Date int64
  292. })
  293. // Find foreign packages in system
  294. for _, pkg := range localDb.PkgCache().Slice() {
  295. // Change to more effective method
  296. found := false
  297. for _, db := range dbList.Slice() {
  298. _, err = db.PkgByName(pkg.Name())
  299. if err == nil {
  300. found = true
  301. break
  302. }
  303. }
  304. if !found {
  305. foreign[pkg.Name()] = &struct {
  306. Version string
  307. Date int64
  308. }{pkg.Version(), pkg.InstallDate().Unix()}
  309. n++
  310. }
  311. }
  312. return
  313. }
  314. // Statistics returns statistics about packages installed in system
  315. func Statistics() (packages map[string]int64, info struct {
  316. Totaln int
  317. Expln int
  318. TotalSize int64
  319. }, err error) {
  320. var pkgs [10]alpm.Package
  321. var tS int64 // TotalSize
  322. var nPkg int
  323. var ePkg int
  324. h, err := conf.CreateHandle()
  325. defer h.Release()
  326. if err != nil {
  327. return
  328. }
  329. localDb, err := h.LocalDb()
  330. if err != nil {
  331. return
  332. }
  333. var k int
  334. for e, pkg := range localDb.PkgCache().Slice() {
  335. tS += pkg.ISize()
  336. k = -1
  337. nPkg++
  338. if pkg.Reason() == 0 {
  339. ePkg++
  340. }
  341. if e < 10 {
  342. pkgs[e] = pkg
  343. continue
  344. }
  345. for i, pkw := range pkgs {
  346. if k == -1 {
  347. if pkw.ISize() < pkg.ISize() {
  348. k = i
  349. }
  350. } else {
  351. if pkw.ISize() < pkgs[k].ISize() && pkw.ISize() < pkg.ISize() {
  352. k = i
  353. }
  354. }
  355. }
  356. if k != -1 {
  357. pkgs[k] = pkg
  358. }
  359. }
  360. packages = make(map[string]int64)
  361. for _, pkg := range pkgs {
  362. packages[pkg.Name()] = pkg.ISize()
  363. }
  364. info = struct {
  365. Totaln int
  366. Expln int
  367. TotalSize int64
  368. }{
  369. nPkg, ePkg, tS,
  370. }
  371. return
  372. }