123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479 |
- package ialpm
- import (
- "bufio"
- "errors"
- "fmt"
- "os"
- "strconv"
- "time"
- alpm "github.com/Jguer/go-alpm/v2"
- pacmanconf "github.com/Morganamilo/go-pacmanconf"
- "github.com/leonelquinteros/gotext"
- "github.com/Jguer/yay/v10/pkg/settings"
- "github.com/Jguer/yay/v10/pkg/text"
- "github.com/Jguer/yay/v10/pkg/upgrade"
- )
- type AlpmExecutor struct {
- handle *alpm.Handle
- localDB alpm.IDB
- syncDB alpm.IDBList
- syncDBsCache []alpm.IDB
- conf *pacmanconf.Config
- }
- func NewExecutor(pacmanConf *pacmanconf.Config) (*AlpmExecutor, error) {
- ae := &AlpmExecutor{conf: pacmanConf}
- err := ae.RefreshHandle()
- if err != nil {
- return nil, err
- }
- ae.localDB, err = ae.handle.LocalDB()
- if err != nil {
- return nil, err
- }
- ae.syncDB, err = ae.handle.SyncDBs()
- if err != nil {
- return nil, err
- }
- return ae, nil
- }
- func toUsage(usages []string) alpm.Usage {
- if len(usages) == 0 {
- return alpm.UsageAll
- }
- var ret alpm.Usage
- for _, usage := range usages {
- switch usage {
- case "Sync":
- ret |= alpm.UsageSync
- case "Search":
- ret |= alpm.UsageSearch
- case "Install":
- ret |= alpm.UsageInstall
- case "Upgrade":
- ret |= alpm.UsageUpgrade
- case "All":
- ret |= alpm.UsageAll
- }
- }
- return ret
- }
- func configureAlpm(pacmanConf *pacmanconf.Config, alpmHandle *alpm.Handle) error {
- // TODO: set SigLevel
- // sigLevel := alpm.SigPackage | alpm.SigPackageOptional | alpm.SigDatabase | alpm.SigDatabaseOptional
- // localFileSigLevel := alpm.SigUseDefault
- // remoteFileSigLevel := alpm.SigUseDefault
- for _, repo := range pacmanConf.Repos {
- // TODO: set SigLevel
- alpmDB, err := alpmHandle.RegisterSyncDB(repo.Name, 0)
- if err != nil {
- return err
- }
- alpmDB.SetServers(repo.Servers)
- alpmDB.SetUsage(toUsage(repo.Usage))
- }
- if err := alpmHandle.SetCacheDirs(pacmanConf.CacheDir); err != nil {
- return err
- }
- // add hook directories 1-by-1 to avoid overwriting the system directory
- for _, dir := range pacmanConf.HookDir {
- if err := alpmHandle.AddHookDir(dir); err != nil {
- return err
- }
- }
- if err := alpmHandle.SetGPGDir(pacmanConf.GPGDir); err != nil {
- return err
- }
- if err := alpmHandle.SetLogFile(pacmanConf.LogFile); err != nil {
- return err
- }
- if err := alpmHandle.SetIgnorePkgs(pacmanConf.IgnorePkg); err != nil {
- return err
- }
- if err := alpmHandle.SetIgnoreGroups(pacmanConf.IgnoreGroup); err != nil {
- return err
- }
- if err := alpmHandle.SetArch(pacmanConf.Architecture); err != nil {
- return err
- }
- if err := alpmHandle.SetNoUpgrades(pacmanConf.NoUpgrade); err != nil {
- return err
- }
- if err := alpmHandle.SetNoExtracts(pacmanConf.NoExtract); err != nil {
- return err
- }
- /*if err := alpmHandle.SetDefaultSigLevel(sigLevel); err != nil {
- return err
- }
- if err := alpmHandle.SetLocalFileSigLevel(localFileSigLevel); err != nil {
- return err
- }
- if err := alpmHandle.SetRemoteFileSigLevel(remoteFileSigLevel); err != nil {
- return err
- }*/
- if err := alpmHandle.SetUseSyslog(pacmanConf.UseSyslog); err != nil {
- return err
- }
- return alpmHandle.SetCheckSpace(pacmanConf.CheckSpace)
- }
- func logCallback(level alpm.LogLevel, str string) {
- switch level {
- case alpm.LogWarning:
- text.Warn(str)
- case alpm.LogError:
- text.Error(str)
- }
- }
- func (ae *AlpmExecutor) questionCallback() func(question alpm.QuestionAny) {
- return func(question alpm.QuestionAny) {
- if qi, err := question.QuestionInstallIgnorepkg(); err == nil {
- qi.SetInstall(true)
- }
- qp, err := question.QuestionSelectProvider()
- if err != nil {
- return
- }
- if settings.HideMenus {
- return
- }
- size := 0
- _ = qp.Providers(ae.handle).ForEach(func(pkg alpm.IPackage) error {
- size++
- return nil
- })
- str := text.Bold(gotext.Get("There are %d providers available for %s:\n", size, qp.Dep()))
- size = 1
- var dbName string
- _ = qp.Providers(ae.handle).ForEach(func(pkg alpm.IPackage) error {
- thisDB := pkg.DB().Name()
- if dbName != thisDB {
- dbName = thisDB
- str += text.SprintOperationInfo(gotext.Get("Repository"), dbName, "\n ")
- }
- str += fmt.Sprintf("%d) %s ", size, pkg.Name())
- size++
- return nil
- })
- text.OperationInfoln(str)
- for {
- fmt.Print(gotext.Get("\nEnter a number (default=1): "))
- // TODO: reenable noconfirm
- if settings.NoConfirm {
- fmt.Println()
- break
- }
- reader := bufio.NewReader(os.Stdin)
- numberBuf, overflow, err := reader.ReadLine()
- if err != nil {
- text.Errorln(err)
- break
- }
- if overflow {
- text.Errorln(gotext.Get(" Input too long"))
- continue
- }
- if string(numberBuf) == "" {
- break
- }
- num, err := strconv.Atoi(string(numberBuf))
- if err != nil {
- text.Errorln(gotext.Get("invalid number: %s", string(numberBuf)))
- continue
- }
- if num < 1 || num > size {
- text.Errorln(gotext.Get("invalid value: %d is not between %d and %d", num, 1, size))
- continue
- }
- qp.SetUseIndex(num - 1)
- break
- }
- }
- }
- func (ae *AlpmExecutor) RefreshHandle() error {
- if ae.handle != nil {
- if errRelease := ae.handle.Release(); errRelease != nil {
- return errRelease
- }
- }
- alpmHandle, err := alpm.Initialize(ae.conf.RootDir, ae.conf.DBPath)
- if err != nil {
- return errors.New(gotext.Get("unable to CreateHandle: %s", err))
- }
- if errConf := configureAlpm(ae.conf, alpmHandle); errConf != nil {
- return errConf
- }
- alpmHandle.SetQuestionCallback(ae.questionCallback())
- alpmHandle.SetLogCallback(logCallback)
- ae.handle = alpmHandle
- ae.syncDBsCache = nil
- ae.syncDB, err = alpmHandle.SyncDBs()
- if err != nil {
- return err
- }
- ae.localDB, err = alpmHandle.LocalDB()
- return err
- }
- func (ae *AlpmExecutor) LocalSatisfierExists(pkgName string) bool {
- if _, err := ae.localDB.PkgCache().FindSatisfier(pkgName); err != nil {
- return false
- }
- return true
- }
- func (ae *AlpmExecutor) SyncSatisfierExists(pkgName string) bool {
- if _, err := ae.syncDB.FindSatisfier(pkgName); err != nil {
- return false
- }
- return true
- }
- func (ae *AlpmExecutor) IsCorrectVersionInstalled(pkgName, versionRequired string) bool {
- alpmPackage := ae.localDB.Pkg(pkgName)
- if alpmPackage == nil {
- return false
- }
- return alpmPackage.Version() == versionRequired
- }
- func (ae *AlpmExecutor) SyncSatisfier(pkgName string) alpm.IPackage {
- foundPkg, err := ae.syncDB.FindSatisfier(pkgName)
- if err != nil {
- return nil
- }
- return foundPkg
- }
- func (ae *AlpmExecutor) PackagesFromGroup(groupName string) []alpm.IPackage {
- groupPackages := []alpm.IPackage{}
- _ = ae.syncDB.FindGroupPkgs(groupName).ForEach(func(pkg alpm.IPackage) error {
- groupPackages = append(groupPackages, pkg)
- return nil
- })
- return groupPackages
- }
- func (ae *AlpmExecutor) LocalPackages() []alpm.IPackage {
- localPackages := []alpm.IPackage{}
- _ = ae.localDB.PkgCache().ForEach(func(pkg alpm.IPackage) error {
- localPackages = append(localPackages, pkg)
- return nil
- })
- return localPackages
- }
- // SyncPackages searches SyncDB for packages or returns all packages if no search param is given
- func (ae *AlpmExecutor) SyncPackages(pkgNames ...string) []alpm.IPackage {
- repoPackages := []alpm.IPackage{}
- _ = ae.syncDB.ForEach(func(alpmDB alpm.IDB) error {
- if len(pkgNames) == 0 {
- _ = alpmDB.PkgCache().ForEach(func(pkg alpm.IPackage) error {
- repoPackages = append(repoPackages, pkg)
- return nil
- })
- } else {
- _ = alpmDB.Search(pkgNames).ForEach(func(pkg alpm.IPackage) error {
- repoPackages = append(repoPackages, pkg)
- return nil
- })
- }
- return nil
- })
- return repoPackages
- }
- func (ae *AlpmExecutor) LocalPackage(pkgName string) alpm.IPackage {
- pkg := ae.localDB.Pkg(pkgName)
- if pkg == nil {
- return nil
- }
- return pkg
- }
- func (ae *AlpmExecutor) syncDBs() []alpm.IDB {
- if ae.syncDBsCache == nil {
- ae.syncDBsCache = ae.syncDB.Slice()
- }
- return ae.syncDBsCache
- }
- func (ae *AlpmExecutor) SyncPackage(pkgName string) alpm.IPackage {
- for _, db := range ae.syncDBs() {
- if dbPkg := db.Pkg(pkgName); dbPkg != nil {
- return dbPkg
- }
- }
- return nil
- }
- func (ae *AlpmExecutor) SatisfierFromDB(pkgName, dbName string) alpm.IPackage {
- singleDB, err := ae.handle.SyncDBByName(dbName)
- if err != nil {
- return nil
- }
- foundPkg, err := singleDB.PkgCache().FindSatisfier(pkgName)
- if err != nil {
- return nil
- }
- return foundPkg
- }
- func (ae *AlpmExecutor) PackageDepends(pkg alpm.IPackage) []alpm.Depend {
- alpmPackage := pkg.(*alpm.Package)
- return alpmPackage.Depends().Slice()
- }
- func (ae *AlpmExecutor) PackageOptionalDepends(pkg alpm.IPackage) []alpm.Depend {
- alpmPackage := pkg.(*alpm.Package)
- return alpmPackage.OptionalDepends().Slice()
- }
- func (ae *AlpmExecutor) PackageProvides(pkg alpm.IPackage) []alpm.Depend {
- alpmPackage := pkg.(*alpm.Package)
- return alpmPackage.Provides().Slice()
- }
- func (ae *AlpmExecutor) PackageConflicts(pkg alpm.IPackage) []alpm.Depend {
- alpmPackage := pkg.(*alpm.Package)
- return alpmPackage.Conflicts().Slice()
- }
- func (ae *AlpmExecutor) PackageGroups(pkg alpm.IPackage) []string {
- alpmPackage := pkg.(*alpm.Package)
- return alpmPackage.Groups().Slice()
- }
- // upRepo gathers local packages and checks if they have new versions.
- // Output: Upgrade type package list.
- func (ae *AlpmExecutor) RepoUpgrades(enableDowngrade bool) (upgrade.UpSlice, error) {
- slice := upgrade.UpSlice{}
- localDB, err := ae.handle.LocalDB()
- if err != nil {
- return slice, err
- }
- err = ae.handle.TransInit(alpm.TransFlagNoLock)
- if err != nil {
- return slice, err
- }
- defer func() {
- err = ae.handle.TransRelease()
- }()
- err = ae.handle.SyncSysupgrade(enableDowngrade)
- if err != nil {
- return slice, err
- }
- _ = ae.handle.TransGetAdd().ForEach(func(pkg alpm.IPackage) error {
- localVer := "-"
- reason := alpm.PkgReasonExplicit
- if localPkg := localDB.Pkg(pkg.Name()); localPkg != nil {
- localVer = localPkg.Version()
- reason = localPkg.Reason()
- }
- slice = append(slice, upgrade.Upgrade{
- Name: pkg.Name(),
- Repository: pkg.DB().Name(),
- LocalVersion: localVer,
- RemoteVersion: pkg.Version(),
- Reason: reason,
- })
- return nil
- })
- return slice, nil
- }
- func (ae *AlpmExecutor) AlpmArch() (string, error) {
- return ae.handle.Arch()
- }
- func (ae *AlpmExecutor) BiggestPackages() []alpm.IPackage {
- localPackages := []alpm.IPackage{}
- _ = ae.localDB.PkgCache().SortBySize().ForEach(func(pkg alpm.IPackage) error {
- localPackages = append(localPackages, pkg)
- return nil
- })
- return localPackages
- }
- func (ae *AlpmExecutor) LastBuildTime() time.Time {
- var lastTime time.Time
- _ = ae.syncDB.ForEach(func(db alpm.IDB) error {
- _ = db.PkgCache().ForEach(func(pkg alpm.IPackage) error {
- thisTime := pkg.BuildDate()
- if thisTime.After(lastTime) {
- lastTime = thisTime
- }
- return nil
- })
- return nil
- })
- return lastTime
- }
- func (ae *AlpmExecutor) Cleanup() {
- if ae.handle != nil {
- if err := ae.handle.Release(); err != nil {
- fmt.Fprintln(os.Stderr, err)
- }
- }
- }
|