aur_install.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. package main
  2. import (
  3. "context"
  4. "fmt"
  5. "os"
  6. "github.com/Jguer/yay/v11/pkg/db"
  7. "github.com/Jguer/yay/v11/pkg/dep"
  8. "github.com/Jguer/yay/v11/pkg/multierror"
  9. "github.com/Jguer/yay/v11/pkg/settings"
  10. "github.com/Jguer/yay/v11/pkg/settings/parser"
  11. "github.com/Jguer/yay/v11/pkg/text"
  12. "github.com/leonelquinteros/gotext"
  13. mapset "github.com/deckarep/golang-set/v2"
  14. )
  15. type (
  16. PostInstallHookFunc func(ctx context.Context) error
  17. Installer struct {
  18. dbExecutor db.Executor
  19. postInstallHooks []PostInstallHookFunc
  20. }
  21. )
  22. func (installer *Installer) AddPostInstallHook(hook PostInstallHookFunc) {
  23. installer.postInstallHooks = append(installer.postInstallHooks, hook)
  24. }
  25. func (installer *Installer) RunPostInstallHooks(ctx context.Context) error {
  26. var errMulti multierror.MultiError
  27. for _, hook := range installer.postInstallHooks {
  28. if err := hook(ctx); err != nil {
  29. errMulti.Add(err)
  30. }
  31. }
  32. return errMulti.Return()
  33. }
  34. func (installer *Installer) Install(ctx context.Context,
  35. cmdArgs *parser.Arguments,
  36. targets []map[string]*dep.InstallInfo,
  37. pkgBuildDirs map[string]string,
  38. ) error {
  39. // Reorganize targets into layers of dependencies
  40. for i := len(targets) - 1; i >= 0; i-- {
  41. err := installer.handleLayer(ctx, cmdArgs, targets[i], pkgBuildDirs)
  42. if err != nil {
  43. // rollback
  44. return err
  45. }
  46. }
  47. return nil
  48. }
  49. func (installer *Installer) handleLayer(ctx context.Context,
  50. cmdArgs *parser.Arguments, layer map[string]*dep.InstallInfo, pkgBuildDirs map[string]string,
  51. ) error {
  52. // Install layer
  53. nameToBaseMap := make(map[string]string, 0)
  54. syncDeps, syncExp := mapset.NewThreadUnsafeSet[string](), mapset.NewThreadUnsafeSet[string]()
  55. aurDeps, aurExp := mapset.NewThreadUnsafeSet[string](), mapset.NewThreadUnsafeSet[string]()
  56. for name, info := range layer {
  57. switch info.Source {
  58. case dep.AUR, dep.SrcInfo:
  59. nameToBaseMap[name] = *info.AURBase
  60. switch info.Reason {
  61. case dep.Explicit:
  62. if cmdArgs.ExistsArg("asdeps", "asdep") {
  63. aurDeps.Add(name)
  64. } else {
  65. aurExp.Add(name)
  66. }
  67. case dep.Dep, dep.MakeDep, dep.CheckDep:
  68. aurDeps.Add(name)
  69. }
  70. case dep.Sync:
  71. compositePkgName := fmt.Sprintf("%s/%s", *info.SyncDBName, name)
  72. switch info.Reason {
  73. case dep.Explicit:
  74. if cmdArgs.ExistsArg("asdeps", "asdep") {
  75. syncDeps.Add(compositePkgName)
  76. } else {
  77. syncExp.Add(compositePkgName)
  78. }
  79. case dep.Dep, dep.MakeDep, dep.CheckDep:
  80. syncDeps.Add(compositePkgName)
  81. }
  82. }
  83. }
  84. text.Debugln("syncDeps", syncDeps, "SyncExp", syncExp, "aurDeps", aurDeps, "aurExp", aurExp)
  85. errShow := installer.installSyncPackages(ctx, cmdArgs, syncDeps, syncExp)
  86. if errShow != nil {
  87. return ErrInstallRepoPkgs
  88. }
  89. errAur := installer.installAURPackages(ctx, cmdArgs, aurDeps, aurExp, nameToBaseMap, pkgBuildDirs, false)
  90. return errAur
  91. }
  92. func (installer *Installer) installAURPackages(ctx context.Context,
  93. cmdArgs *parser.Arguments,
  94. aurDepNames, aurExpNames mapset.Set[string],
  95. nameToBase, pkgBuildDirsByBase map[string]string,
  96. installIncompatible bool,
  97. ) error {
  98. deps, exps := make([]string, 0, aurDepNames.Cardinality()), make([]string, 0, aurExpNames.Cardinality())
  99. pkgArchives := make([]string, 0, len(exps)+len(deps))
  100. for _, name := range aurDepNames.Union(aurExpNames).ToSlice() {
  101. base := nameToBase[name]
  102. dir := pkgBuildDirsByBase[base]
  103. args := []string{"--nobuild", "-fC"}
  104. if installIncompatible {
  105. args = append(args, "--ignorearch")
  106. }
  107. // pkgver bump
  108. if err := config.Runtime.CmdBuilder.Show(
  109. config.Runtime.CmdBuilder.BuildMakepkgCmd(ctx, dir, args...)); err != nil {
  110. return fmt.Errorf("%s - %w", gotext.Get("error making: %s", base), err)
  111. }
  112. pkgdests, _, errList := parsePackageList(ctx, dir)
  113. if errList != nil {
  114. return errList
  115. }
  116. args = []string{"-cf", "--noconfirm", "--noextract", "--noprepare", "--holdver"}
  117. if installIncompatible {
  118. args = append(args, "--ignorearch")
  119. }
  120. if errMake := config.Runtime.CmdBuilder.Show(
  121. config.Runtime.CmdBuilder.BuildMakepkgCmd(ctx,
  122. dir, args...)); errMake != nil {
  123. return fmt.Errorf("%s - %w", gotext.Get("error making: %s", base), errMake)
  124. }
  125. newPKGArchives, hasDebug, err := installer.getNewTargets(pkgdests, name)
  126. if err != nil {
  127. return err
  128. }
  129. pkgArchives = append(pkgArchives, newPKGArchives...)
  130. if isDep := installer.isDep(cmdArgs, aurExpNames, name); isDep {
  131. deps = append(deps, name)
  132. } else {
  133. exps = append(exps, name)
  134. }
  135. if hasDebug {
  136. deps = append(deps, name+"-debug")
  137. }
  138. }
  139. if err := installPkgArchive(ctx, cmdArgs, pkgArchives); err != nil {
  140. return fmt.Errorf("%s - %w", fmt.Sprintf(gotext.Get("error installing:")+" %v", pkgArchives), err)
  141. }
  142. if err := setInstallReason(ctx, cmdArgs, deps, exps); err != nil {
  143. return fmt.Errorf("%s - %w", fmt.Sprintf(gotext.Get("error installing:")+" %v", pkgArchives), err)
  144. }
  145. return nil
  146. }
  147. func (*Installer) isDep(cmdArgs *parser.Arguments, aurExpNames mapset.Set[string], name string) bool {
  148. switch {
  149. case cmdArgs.ExistsArg("asdeps", "asdep"):
  150. return true
  151. case cmdArgs.ExistsArg("asexplicit", "asexp"):
  152. return false
  153. case aurExpNames.Contains(name):
  154. return false
  155. }
  156. return true
  157. }
  158. func (installer *Installer) getNewTargets(pkgdests map[string]string, name string,
  159. ) ([]string, bool, error) {
  160. pkgdest, ok := pkgdests[name]
  161. if !ok {
  162. return nil, false, &PkgDestNotInListError{name: name}
  163. }
  164. pkgArchives := make([]string, 0, 2)
  165. if _, errStat := os.Stat(pkgdest); os.IsNotExist(errStat) {
  166. return nil, false, &UnableToFindPkgDestError{name: name, pkgDest: pkgdest}
  167. }
  168. pkgArchives = append(pkgArchives, pkgdest)
  169. debugName := pkgdest + "-debug"
  170. pkgdestDebug, ok := pkgdests[debugName]
  171. if ok {
  172. if _, errStat := os.Stat(pkgdestDebug); errStat == nil {
  173. pkgArchives = append(pkgArchives, debugName)
  174. }
  175. }
  176. return pkgArchives, ok, nil
  177. }
  178. func (*Installer) installSyncPackages(ctx context.Context, cmdArgs *parser.Arguments,
  179. syncDeps, // repo targets that are deps
  180. syncExp mapset.Set[string], // repo targets that are exp
  181. ) error {
  182. repoTargets := syncDeps.Union(syncExp).ToSlice()
  183. if len(repoTargets) == 0 {
  184. return nil
  185. }
  186. arguments := cmdArgs.Copy()
  187. arguments.DelArg("asdeps", "asdep")
  188. arguments.DelArg("asexplicit", "asexp")
  189. arguments.DelArg("i", "install")
  190. arguments.Op = "S"
  191. arguments.ClearTargets()
  192. arguments.AddTarget(repoTargets...)
  193. errShow := config.Runtime.CmdBuilder.Show(config.Runtime.CmdBuilder.BuildPacmanCmd(ctx,
  194. arguments, config.Runtime.Mode, settings.NoConfirm))
  195. if errD := asdeps(ctx, cmdArgs, syncDeps.ToSlice()); errD != nil {
  196. return errD
  197. }
  198. if errE := asexp(ctx, cmdArgs, syncExp.ToSlice()); errE != nil {
  199. return errE
  200. }
  201. return errShow
  202. }