pacman.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  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. // PackageSlices separates an input slice into aur and repo slices
  163. func PackageSlices(toCheck []string) (aur []string, repo []string, err error) {
  164. h, err := conf.CreateHandle()
  165. defer h.Release()
  166. if err != nil {
  167. return
  168. }
  169. dbList, err := h.SyncDbs()
  170. if err != nil {
  171. return
  172. }
  173. for _, pkg := range toCheck {
  174. // Check if dep is installed
  175. found := false
  176. for _, db := range dbList.Slice() {
  177. _, err = db.PkgByName(pkg)
  178. if err == nil {
  179. found = true
  180. repo = append(repo, pkg)
  181. break
  182. }
  183. }
  184. if !found {
  185. aur = append(aur, pkg)
  186. }
  187. }
  188. return
  189. }
  190. // OutofRepo returns a list of packages not installed and not resolvable
  191. // Accepts inputs like 'gtk2', 'java-environment=8', 'linux >= 4.20'
  192. func OutofRepo(toCheck []string) (aur []string, repo []string, err error) {
  193. h, err := conf.CreateHandle()
  194. defer h.Release()
  195. if err != nil {
  196. return
  197. }
  198. localDb, err := h.LocalDb()
  199. if err != nil {
  200. return
  201. }
  202. dbList, err := h.SyncDbs()
  203. if err != nil {
  204. return
  205. }
  206. f := func(c rune) bool {
  207. return c == '>' || c == '<' || c == '=' || c == ' '
  208. }
  209. // First, Check if they're provided by package name.
  210. for _, dep := range toCheck {
  211. field := strings.FieldsFunc(dep, f)
  212. // Check if dep is installed
  213. _, err = localDb.PkgByName(field[0])
  214. if err == nil {
  215. continue
  216. }
  217. found := false
  218. Loop:
  219. for _, db := range dbList.Slice() {
  220. _, err = db.PkgByName(field[0])
  221. if err == nil {
  222. found = true
  223. repo = append(repo, field[0])
  224. break Loop
  225. }
  226. for _, pkg := range db.PkgCache().Slice() {
  227. for _, p := range pkg.Provides().Slice() {
  228. if p.String() == dep {
  229. found = true
  230. repo = append(repo, pkg.Name())
  231. break Loop
  232. }
  233. }
  234. }
  235. }
  236. if !found {
  237. aur = append(aur, field[0])
  238. }
  239. }
  240. return
  241. }
  242. // ForeignPackages returns a map of foreign packages, with their version and date as values.
  243. func ForeignPackages() (foreign map[string]*struct {
  244. Version string
  245. Date int64
  246. }, n int, err error) {
  247. h, err := conf.CreateHandle()
  248. defer h.Release()
  249. if err != nil {
  250. return
  251. }
  252. localDb, err := h.LocalDb()
  253. if err != nil {
  254. return
  255. }
  256. dbList, err := h.SyncDbs()
  257. if err != nil {
  258. return
  259. }
  260. foreign = make(map[string]*struct {
  261. Version string
  262. Date int64
  263. })
  264. // Find foreign packages in system
  265. for _, pkg := range localDb.PkgCache().Slice() {
  266. // Change to more effective method
  267. found := false
  268. for _, db := range dbList.Slice() {
  269. _, err = db.PkgByName(pkg.Name())
  270. if err == nil {
  271. found = true
  272. break
  273. }
  274. }
  275. if !found {
  276. foreign[pkg.Name()] = &struct {
  277. Version string
  278. Date int64
  279. }{pkg.Version(), pkg.InstallDate().Unix()}
  280. n++
  281. }
  282. }
  283. return
  284. }
  285. // Statistics returns statistics about packages installed in system
  286. func Statistics() (packages map[string]int64, info struct {
  287. Totaln int
  288. Expln int
  289. TotalSize int64
  290. }, err error) {
  291. var pkgs [10]alpm.Package
  292. var tS int64 // TotalSize
  293. var nPkg int
  294. var ePkg int
  295. h, err := conf.CreateHandle()
  296. defer h.Release()
  297. if err != nil {
  298. return
  299. }
  300. localDb, err := h.LocalDb()
  301. if err != nil {
  302. return
  303. }
  304. var k int
  305. for e, pkg := range localDb.PkgCache().Slice() {
  306. tS += pkg.ISize()
  307. k = -1
  308. nPkg++
  309. if pkg.Reason() == 0 {
  310. ePkg++
  311. }
  312. if e < 10 {
  313. pkgs[e] = pkg
  314. continue
  315. }
  316. for i, pkw := range pkgs {
  317. if k == -1 {
  318. if pkw.ISize() < pkg.ISize() {
  319. k = i
  320. }
  321. } else {
  322. if pkw.ISize() < pkgs[k].ISize() && pkw.ISize() < pkg.ISize() {
  323. k = i
  324. }
  325. }
  326. }
  327. if k != -1 {
  328. pkgs[k] = pkg
  329. }
  330. }
  331. for _, pkg := range pkgs {
  332. packages[pkg.Name()] = pkg.ISize()
  333. }
  334. info = struct {
  335. Totaln int
  336. Expln int
  337. TotalSize int64
  338. }{
  339. nPkg, ePkg, tS,
  340. }
  341. return
  342. }