pacman.go 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. package pacman
  2. import (
  3. "fmt"
  4. "os"
  5. "strings"
  6. "github.com/jguer/go-alpm"
  7. "github.com/jguer/yay/config"
  8. )
  9. // Query holds the results of a repository search.
  10. type Query []alpm.Package
  11. // Search handles repo searches. Creates a RepoSearch struct.
  12. func Search(pkgInputN []string) (s Query, n int, err error) {
  13. dbList, err := config.AlpmHandle.SyncDbs()
  14. if err != nil {
  15. return
  16. }
  17. // BottomUp functions
  18. initL := func(len int) int {
  19. if config.YayConf.SortMode == config.TopDown {
  20. return 0
  21. } else {
  22. return len - 1
  23. }
  24. }
  25. compL := func(len int, i int) bool {
  26. if config.YayConf.SortMode == config.TopDown {
  27. return i < len
  28. } else {
  29. return i > -1
  30. }
  31. }
  32. finalL := func(i int) int {
  33. if config.YayConf.SortMode == config.TopDown {
  34. return i + 1
  35. } else {
  36. return i - 1
  37. }
  38. }
  39. dbS := dbList.Slice()
  40. lenDbs := len(dbS)
  41. for f := initL(lenDbs); compL(lenDbs, f); f = finalL(f) {
  42. pkgS := dbS[f].PkgCache().Slice()
  43. lenPkgs := len(pkgS)
  44. for i := initL(lenPkgs); compL(lenPkgs, i); i = finalL(i) {
  45. match := true
  46. for _, pkgN := range pkgInputN {
  47. if !(strings.Contains(pkgS[i].Name(), pkgN) || strings.Contains(strings.ToLower(pkgS[i].Description()), pkgN)) {
  48. match = false
  49. break
  50. }
  51. }
  52. if match {
  53. n++
  54. s = append(s, pkgS[i])
  55. }
  56. }
  57. }
  58. return
  59. }
  60. //PrintSearch receives a RepoSearch type and outputs pretty text.
  61. func (s Query) PrintSearch() {
  62. for i, res := range s {
  63. var toprint string
  64. if config.YayConf.SearchMode == config.NumberMenu {
  65. if config.YayConf.SortMode == config.BottomUp {
  66. toprint += fmt.Sprintf("\x1b[33m%d\x1b[0m ", len(s)-i-1)
  67. } else {
  68. toprint += fmt.Sprintf("\x1b[33m%d\x1b[0m ", i)
  69. }
  70. } else if config.YayConf.SearchMode == config.Minimal {
  71. fmt.Println(res.Name())
  72. continue
  73. }
  74. toprint += fmt.Sprintf("\x1b[1m%s/\x1b[33m%s \x1b[36m%s \x1b[0m",
  75. res.DB().Name(), res.Name(), res.Version())
  76. if len(res.Groups().Slice()) != 0 {
  77. toprint += fmt.Sprint(res.Groups().Slice(), " ")
  78. }
  79. localDb, err := config.AlpmHandle.LocalDb()
  80. if err == nil {
  81. if _, err = localDb.PkgByName(res.Name()); err == nil {
  82. toprint += fmt.Sprintf("\x1b[32;40mInstalled\x1b[0m")
  83. }
  84. }
  85. toprint += "\n " + res.Description()
  86. fmt.Println(toprint)
  87. }
  88. }
  89. // PackageSlices separates an input slice into aur and repo slices
  90. func PackageSlices(toCheck []string) (aur []string, repo []string, err error) {
  91. dbList, err := config.AlpmHandle.SyncDbs()
  92. if err != nil {
  93. return
  94. }
  95. for _, pkg := range toCheck {
  96. found := false
  97. _ = dbList.ForEach(func(db alpm.Db) error {
  98. if found {
  99. return nil
  100. }
  101. _, err = db.PkgByName(pkg)
  102. if err == nil {
  103. found = true
  104. repo = append(repo, pkg)
  105. }
  106. return nil
  107. })
  108. if !found {
  109. if _, errdb := dbList.PkgCachebyGroup(pkg); errdb == nil {
  110. repo = append(repo, pkg)
  111. } else {
  112. aur = append(aur, pkg)
  113. }
  114. }
  115. }
  116. err = nil
  117. return
  118. }
  119. // BuildDependencies finds packages, on the second run
  120. // compares with a baselist and avoids searching those
  121. func BuildDependencies(baselist []string) func(toCheck []string, isBaseList bool, last bool) (repo []string, notFound []string) {
  122. localDb, _ := config.AlpmHandle.LocalDb()
  123. dbList, _ := config.AlpmHandle.SyncDbs()
  124. f := func(c rune) bool {
  125. return c == '>' || c == '<' || c == '=' || c == ' '
  126. }
  127. return func(toCheck []string, isBaseList bool, close bool) (repo []string, notFound []string) {
  128. if close {
  129. return
  130. }
  131. Loop:
  132. for _, dep := range toCheck {
  133. if !isBaseList {
  134. for _, base := range baselist {
  135. if base == dep {
  136. continue Loop
  137. }
  138. }
  139. }
  140. if _, erp := localDb.PkgCache().FindSatisfier(dep); erp == nil {
  141. continue
  142. } else if pkg, erp := dbList.FindSatisfier(dep); erp == nil {
  143. repo = append(repo, pkg.Name())
  144. } else {
  145. field := strings.FieldsFunc(dep, f)
  146. notFound = append(notFound, field[0])
  147. }
  148. }
  149. return
  150. }
  151. }
  152. // DepSatisfier receives a string slice, returns a slice of packages found in
  153. // repos and one of packages not found in repos. Leaves out installed packages.
  154. func DepSatisfier(toCheck []string) (repo []string, notFound []string, err error) {
  155. localDb, err := config.AlpmHandle.LocalDb()
  156. if err != nil {
  157. return
  158. }
  159. dbList, err := config.AlpmHandle.SyncDbs()
  160. if err != nil {
  161. return
  162. }
  163. f := func(c rune) bool {
  164. return c == '>' || c == '<' || c == '=' || c == ' '
  165. }
  166. for _, dep := range toCheck {
  167. if _, erp := localDb.PkgCache().FindSatisfier(dep); erp == nil {
  168. continue
  169. } else if pkg, erp := dbList.FindSatisfier(dep); erp == nil {
  170. repo = append(repo, pkg.Name())
  171. } else {
  172. field := strings.FieldsFunc(dep, f)
  173. notFound = append(notFound, field[0])
  174. }
  175. }
  176. err = nil
  177. return
  178. }
  179. // PkgNameSlice returns a slice of package names
  180. // func (s Query) PkgNameSlice() (pkgNames []string) {
  181. // for _, e := range s {
  182. // pkgNames = append(pkgNames, e.Name())
  183. // }
  184. // return
  185. // }
  186. // CleanRemove sends a full removal command to pacman with the pkgName slice
  187. func CleanRemove(pkgName []string) (err error) {
  188. if len(pkgName) == 0 {
  189. return nil
  190. }
  191. err = config.PassToPacman("-Rsnc", pkgName, []string{"--noutil.Conf.rm"})
  192. return err
  193. }
  194. // ForeignPackages returns a map of foreign packages, with their version and date as values.
  195. func ForeignPackages() (foreign map[string]alpm.Package, err error) {
  196. localDb, err := config.AlpmHandle.LocalDb()
  197. if err != nil {
  198. return
  199. }
  200. dbList, err := config.AlpmHandle.SyncDbs()
  201. if err != nil {
  202. return
  203. }
  204. foreign = make(map[string]alpm.Package)
  205. f := func(k alpm.Package) error {
  206. found := false
  207. _ = dbList.ForEach(func(d alpm.Db) error {
  208. if found {
  209. return nil
  210. }
  211. _, err = d.PkgByName(k.Name())
  212. if err == nil {
  213. found = true
  214. }
  215. return nil
  216. })
  217. if !found {
  218. foreign[k.Name()] = k
  219. }
  220. return nil
  221. }
  222. err = localDb.PkgCache().ForEach(f)
  223. return
  224. }
  225. // Statistics returns statistics about packages installed in system
  226. func Statistics() (info struct {
  227. Totaln int
  228. Expln int
  229. TotalSize int64
  230. }, err error) {
  231. var tS int64 // TotalSize
  232. var nPkg int
  233. var ePkg int
  234. localDb, err := config.AlpmHandle.LocalDb()
  235. if err != nil {
  236. return
  237. }
  238. for _, pkg := range localDb.PkgCache().Slice() {
  239. tS += pkg.ISize()
  240. nPkg++
  241. if pkg.Reason() == 0 {
  242. ePkg++
  243. }
  244. }
  245. info = struct {
  246. Totaln int
  247. Expln int
  248. TotalSize int64
  249. }{
  250. nPkg, ePkg, tS,
  251. }
  252. return
  253. }
  254. // BiggestPackages prints the name of the ten biggest packages in the system.
  255. func BiggestPackages() {
  256. localDb, err := config.AlpmHandle.LocalDb()
  257. if err != nil {
  258. return
  259. }
  260. pkgCache := localDb.PkgCache()
  261. pkgS := pkgCache.SortBySize().Slice()
  262. if len(pkgS) < 10 {
  263. return
  264. }
  265. for i := 0; i < 10; i++ {
  266. fmt.Printf("%s: \x1B[0;33m%dMB\x1B[0m\n", pkgS[i].Name(), pkgS[i].ISize()/(1024*1024))
  267. }
  268. // Could implement size here as well, but we just want the general idea
  269. }
  270. // HangingPackages returns a list of packages installed as deps
  271. // and unneeded by the system
  272. func HangingPackages() (hanging []string, err error) {
  273. localDb, err := config.AlpmHandle.LocalDb()
  274. if err != nil {
  275. return
  276. }
  277. f := func(pkg alpm.Package) error {
  278. if pkg.Reason() != alpm.PkgReasonDepend {
  279. return nil
  280. }
  281. requiredby := pkg.ComputeRequiredBy()
  282. if len(requiredby) == 0 {
  283. hanging = append(hanging, pkg.Name())
  284. fmt.Printf("%s: \x1B[0;33m%dMB\x1B[0m\n", pkg.Name(), pkg.ISize()/(1024*1024))
  285. }
  286. return nil
  287. }
  288. err = localDb.PkgCache().ForEach(f)
  289. return
  290. }
  291. // SliceHangingPackages returns a list of packages installed as deps
  292. // and unneeded by the system from a provided list of package names.
  293. func SliceHangingPackages(pkgS []string) (hanging []string) {
  294. localDb, err := config.AlpmHandle.LocalDb()
  295. if err != nil {
  296. return
  297. }
  298. big:
  299. for _, pkgName := range pkgS {
  300. for _, hangN := range hanging {
  301. if hangN == pkgName {
  302. continue big
  303. }
  304. }
  305. pkg, err := localDb.PkgByName(pkgName)
  306. if err == nil {
  307. if pkg.Reason() != alpm.PkgReasonDepend {
  308. continue
  309. }
  310. requiredby := pkg.ComputeRequiredBy()
  311. if len(requiredby) == 0 {
  312. hanging = append(hanging, pkgName)
  313. fmt.Printf("%s: \x1B[0;33m%dMB\x1B[0m\n", pkg.Name(), pkg.ISize()/(1024*1024))
  314. }
  315. }
  316. }
  317. return
  318. }
  319. // GetPkgbuild downloads pkgbuild from the ABS.
  320. func GetPkgbuild(pkgN string, path string) (err error) {
  321. dbList, err := config.AlpmHandle.SyncDbs()
  322. if err != nil {
  323. return
  324. }
  325. for _, db := range dbList.Slice() {
  326. pkg, err := db.PkgByName(pkgN)
  327. if err == nil {
  328. var url string
  329. if db.Name() == "core" || db.Name() == "extra" {
  330. url = "https://projects.archlinux.org/svntogit/packages.git/snapshot/packages/" + pkg.Name() + ".tar.gz"
  331. } else if db.Name() == "community" {
  332. url = "https://projects.archlinux.org/svntogit/community.git/snapshot/community-packages/" + pkg.Name() + ".tar.gz"
  333. } else {
  334. return fmt.Errorf("Not in standard repositories")
  335. }
  336. fmt.Printf("\x1b[1;32m==>\x1b[1;33m %s \x1b[1;32mfound in ABS.\x1b[0m\n", pkgN)
  337. errD := config.DownloadAndUnpack(url, path, true)
  338. return errD
  339. }
  340. }
  341. return fmt.Errorf("package not found")
  342. }
  343. //CreatePackageList appends Repo packages to completion cache
  344. func CreatePackageList(out *os.File) (err error) {
  345. dbList, err := config.AlpmHandle.SyncDbs()
  346. if err != nil {
  347. return
  348. }
  349. _ = dbList.ForEach(func(db alpm.Db) error {
  350. _ = db.PkgCache().ForEach(func(pkg alpm.Package) error {
  351. fmt.Print(pkg.Name())
  352. out.WriteString(pkg.Name())
  353. if config.YayConf.Shell == "fish" {
  354. fmt.Print("\t" + pkg.DB().Name() + "\n")
  355. out.WriteString("\t" + pkg.DB().Name() + "\n")
  356. } else {
  357. fmt.Print("\n")
  358. out.WriteString("\n")
  359. }
  360. return nil
  361. })
  362. return nil
  363. })
  364. return nil
  365. }