pacman.go 11 KB

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