alpm.go 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. package db
  2. import (
  3. "errors"
  4. "fmt"
  5. "os"
  6. "time"
  7. alpm "github.com/Jguer/go-alpm"
  8. pacmanconf "github.com/Morganamilo/go-pacmanconf"
  9. "github.com/leonelquinteros/gotext"
  10. "github.com/Jguer/yay/v10/pkg/text"
  11. "github.com/Jguer/yay/v10/pkg/upgrade"
  12. )
  13. type AlpmExecutor struct {
  14. handle *alpm.Handle
  15. localDB *alpm.DB
  16. syncDB alpm.DBList
  17. conf *pacmanconf.Config
  18. questionCallback func(question alpm.QuestionAny)
  19. }
  20. func NewExecutor(pacamnConf *pacmanconf.Config,
  21. questionCallback func(question alpm.QuestionAny)) (*AlpmExecutor, error) {
  22. ae := &AlpmExecutor{conf: pacamnConf, questionCallback: questionCallback}
  23. err := ae.RefreshHandle()
  24. if err != nil {
  25. return nil, err
  26. }
  27. ae.localDB, err = ae.handle.LocalDB()
  28. if err != nil {
  29. return nil, err
  30. }
  31. ae.syncDB, err = ae.handle.SyncDBs()
  32. if err != nil {
  33. return nil, err
  34. }
  35. return ae, nil
  36. }
  37. func toUsage(usages []string) alpm.Usage {
  38. if len(usages) == 0 {
  39. return alpm.UsageAll
  40. }
  41. var ret alpm.Usage
  42. for _, usage := range usages {
  43. switch usage {
  44. case "Sync":
  45. ret |= alpm.UsageSync
  46. case "Search":
  47. ret |= alpm.UsageSearch
  48. case "Install":
  49. ret |= alpm.UsageInstall
  50. case "Upgrade":
  51. ret |= alpm.UsageUpgrade
  52. case "All":
  53. ret |= alpm.UsageAll
  54. }
  55. }
  56. return ret
  57. }
  58. func configureAlpm(pacmanConf *pacmanconf.Config, alpmHandle *alpm.Handle) error {
  59. // TODO: set SigLevel
  60. // sigLevel := alpm.SigPackage | alpm.SigPackageOptional | alpm.SigDatabase | alpm.SigDatabaseOptional
  61. // localFileSigLevel := alpm.SigUseDefault
  62. // remoteFileSigLevel := alpm.SigUseDefault
  63. for _, repo := range pacmanConf.Repos {
  64. // TODO: set SigLevel
  65. db, err := alpmHandle.RegisterSyncDB(repo.Name, 0)
  66. if err != nil {
  67. return err
  68. }
  69. db.SetServers(repo.Servers)
  70. db.SetUsage(toUsage(repo.Usage))
  71. }
  72. if err := alpmHandle.SetCacheDirs(pacmanConf.CacheDir); err != nil {
  73. return err
  74. }
  75. // add hook directories 1-by-1 to avoid overwriting the system directory
  76. for _, dir := range pacmanConf.HookDir {
  77. if err := alpmHandle.AddHookDir(dir); err != nil {
  78. return err
  79. }
  80. }
  81. if err := alpmHandle.SetGPGDir(pacmanConf.GPGDir); err != nil {
  82. return err
  83. }
  84. if err := alpmHandle.SetLogFile(pacmanConf.LogFile); err != nil {
  85. return err
  86. }
  87. if err := alpmHandle.SetIgnorePkgs(pacmanConf.IgnorePkg); err != nil {
  88. return err
  89. }
  90. if err := alpmHandle.SetIgnoreGroups(pacmanConf.IgnoreGroup); err != nil {
  91. return err
  92. }
  93. if err := alpmHandle.SetArch(pacmanConf.Architecture); err != nil {
  94. return err
  95. }
  96. if err := alpmHandle.SetNoUpgrades(pacmanConf.NoUpgrade); err != nil {
  97. return err
  98. }
  99. if err := alpmHandle.SetNoExtracts(pacmanConf.NoExtract); err != nil {
  100. return err
  101. }
  102. /*if err := alpmHandle.SetDefaultSigLevel(sigLevel); err != nil {
  103. return err
  104. }
  105. if err := alpmHandle.SetLocalFileSigLevel(localFileSigLevel); err != nil {
  106. return err
  107. }
  108. if err := alpmHandle.SetRemoteFileSigLevel(remoteFileSigLevel); err != nil {
  109. return err
  110. }*/
  111. if err := alpmHandle.SetUseSyslog(pacmanConf.UseSyslog); err != nil {
  112. return err
  113. }
  114. return alpmHandle.SetCheckSpace(pacmanConf.CheckSpace)
  115. }
  116. func logCallback(level alpm.LogLevel, str string) {
  117. switch level {
  118. case alpm.LogWarning:
  119. text.Warn(str)
  120. case alpm.LogError:
  121. text.Error(str)
  122. }
  123. }
  124. func (ae *AlpmExecutor) RefreshHandle() error {
  125. if ae.handle != nil {
  126. if errRelease := ae.handle.Release(); errRelease != nil {
  127. return errRelease
  128. }
  129. }
  130. alpmHandle, err := alpm.Initialize(ae.conf.RootDir, ae.conf.DBPath)
  131. if err != nil {
  132. return errors.New(gotext.Get("unable to CreateHandle: %s", err))
  133. }
  134. if errConf := configureAlpm(ae.conf, alpmHandle); errConf != nil {
  135. return errConf
  136. }
  137. alpmHandle.SetQuestionCallback(ae.questionCallback)
  138. alpmHandle.SetLogCallback(logCallback)
  139. ae.handle = alpmHandle
  140. ae.syncDB, err = alpmHandle.SyncDBs()
  141. if err != nil {
  142. return err
  143. }
  144. ae.localDB, err = alpmHandle.LocalDB()
  145. return err
  146. }
  147. func (ae *AlpmExecutor) LocalSatisfierExists(pkgName string) bool {
  148. if _, err := ae.localDB.PkgCache().FindSatisfier(pkgName); err != nil {
  149. return false
  150. }
  151. return true
  152. }
  153. func (ae *AlpmExecutor) SyncSatisfierExists(pkgName string) bool {
  154. if _, err := ae.syncDB.FindSatisfier(pkgName); err != nil {
  155. return false
  156. }
  157. return true
  158. }
  159. func (ae *AlpmExecutor) IsCorrectVersionInstalled(pkgName, versionRequired string) bool {
  160. alpmPackage := ae.localDB.Pkg(pkgName)
  161. if alpmPackage == nil {
  162. return false
  163. }
  164. return alpmPackage.Version() == versionRequired
  165. }
  166. func (ae *AlpmExecutor) SyncSatisfier(pkgName string) RepoPackage {
  167. foundPkg, err := ae.syncDB.FindSatisfier(pkgName)
  168. if err != nil {
  169. return nil
  170. }
  171. return foundPkg
  172. }
  173. func (ae *AlpmExecutor) PackagesFromGroup(groupName string) []RepoPackage {
  174. groupPackages := []RepoPackage{}
  175. _ = ae.syncDB.FindGroupPkgs(groupName).ForEach(func(pkg alpm.Package) error {
  176. groupPackages = append(groupPackages, &pkg)
  177. return nil
  178. })
  179. return groupPackages
  180. }
  181. func (ae *AlpmExecutor) LocalPackages() []RepoPackage {
  182. localPackages := []RepoPackage{}
  183. _ = ae.localDB.PkgCache().ForEach(func(pkg alpm.Package) error {
  184. localPackages = append(localPackages, RepoPackage(&pkg))
  185. return nil
  186. })
  187. return localPackages
  188. }
  189. // SyncPackages searches SyncDB for packages or returns all packages if no search param is given
  190. func (ae *AlpmExecutor) SyncPackages(pkgNames ...string) []RepoPackage {
  191. repoPackages := []RepoPackage{}
  192. _ = ae.syncDB.ForEach(func(db alpm.DB) error {
  193. if len(pkgNames) == 0 {
  194. _ = db.PkgCache().ForEach(func(pkg alpm.Package) error {
  195. repoPackages = append(repoPackages, RepoPackage(&pkg))
  196. return nil
  197. })
  198. } else {
  199. _ = db.Search(pkgNames).ForEach(func(pkg alpm.Package) error {
  200. repoPackages = append(repoPackages, RepoPackage(&pkg))
  201. return nil
  202. })
  203. }
  204. return nil
  205. })
  206. return repoPackages
  207. }
  208. func (ae *AlpmExecutor) LocalPackage(pkgName string) RepoPackage {
  209. pkg := ae.localDB.Pkg(pkgName)
  210. if pkg == nil {
  211. return nil
  212. }
  213. return pkg
  214. }
  215. func (ae *AlpmExecutor) PackageFromDB(pkgName, dbName string) RepoPackage {
  216. singleDB, err := ae.handle.SyncDBByName(dbName)
  217. if err != nil {
  218. return nil
  219. }
  220. foundPkg, err := singleDB.PkgCache().FindSatisfier(pkgName)
  221. if err != nil {
  222. return nil
  223. }
  224. return foundPkg
  225. }
  226. func (ae *AlpmExecutor) PackageDepends(pkg RepoPackage) []alpm.Depend {
  227. alpmPackage := pkg.(*alpm.Package)
  228. return alpmPackage.Depends().Slice()
  229. }
  230. func (ae *AlpmExecutor) PackageOptionalDepends(pkg RepoPackage) []alpm.Depend {
  231. alpmPackage := pkg.(*alpm.Package)
  232. return alpmPackage.OptionalDepends().Slice()
  233. }
  234. func (ae *AlpmExecutor) PackageProvides(pkg RepoPackage) []alpm.Depend {
  235. alpmPackage := pkg.(*alpm.Package)
  236. return alpmPackage.Provides().Slice()
  237. }
  238. func (ae *AlpmExecutor) PackageConflicts(pkg RepoPackage) []alpm.Depend {
  239. alpmPackage := pkg.(*alpm.Package)
  240. return alpmPackage.Conflicts().Slice()
  241. }
  242. func (ae *AlpmExecutor) PackageGroups(pkg RepoPackage) []string {
  243. alpmPackage := pkg.(*alpm.Package)
  244. return alpmPackage.Groups().Slice()
  245. }
  246. // upRepo gathers local packages and checks if they have new versions.
  247. // Output: Upgrade type package list.
  248. func (ae *AlpmExecutor) RepoUpgrades(enableDowngrade bool) (upgrade.UpSlice, error) {
  249. slice := upgrade.UpSlice{}
  250. localDB, err := ae.handle.LocalDB()
  251. if err != nil {
  252. return slice, err
  253. }
  254. err = ae.handle.TransInit(alpm.TransFlagNoLock)
  255. if err != nil {
  256. return slice, err
  257. }
  258. defer func() {
  259. err = ae.handle.TransRelease()
  260. }()
  261. err = ae.handle.SyncSysupgrade(enableDowngrade)
  262. if err != nil {
  263. return slice, err
  264. }
  265. _ = ae.handle.TransGetAdd().ForEach(func(pkg alpm.Package) error {
  266. localVer := "-"
  267. if localPkg := localDB.Pkg(pkg.Name()); localPkg != nil {
  268. localVer = localPkg.Version()
  269. }
  270. slice = append(slice, upgrade.Upgrade{
  271. Name: pkg.Name(),
  272. Repository: pkg.DB().Name(),
  273. LocalVersion: localVer,
  274. RemoteVersion: pkg.Version(),
  275. })
  276. return nil
  277. })
  278. return slice, nil
  279. }
  280. func (ae *AlpmExecutor) AlpmArch() (string, error) {
  281. return ae.handle.Arch()
  282. }
  283. func (ae *AlpmExecutor) BiggestPackages() []RepoPackage {
  284. localPackages := []RepoPackage{}
  285. _ = ae.localDB.PkgCache().SortBySize().ForEach(func(pkg alpm.Package) error {
  286. localPackages = append(localPackages, RepoPackage(&pkg))
  287. return nil
  288. })
  289. return localPackages
  290. }
  291. func (ae *AlpmExecutor) LastBuildTime() time.Time {
  292. var lastTime time.Time
  293. _ = ae.syncDB.ForEach(func(db alpm.DB) error {
  294. _ = db.PkgCache().ForEach(func(pkg alpm.Package) error {
  295. thisTime := pkg.BuildDate()
  296. if thisTime.After(lastTime) {
  297. lastTime = thisTime
  298. }
  299. return nil
  300. })
  301. return nil
  302. })
  303. return lastTime
  304. }
  305. func (ae *AlpmExecutor) Cleanup() {
  306. if ae.handle != nil {
  307. if err := ae.handle.Release(); err != nil {
  308. fmt.Fprintln(os.Stderr, err)
  309. }
  310. }
  311. }