unified.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. package download
  2. import (
  3. "net/http"
  4. "os"
  5. "path/filepath"
  6. "sync"
  7. "github.com/leonelquinteros/gotext"
  8. "github.com/Jguer/go-alpm/v2"
  9. "github.com/Jguer/yay/v10/pkg/db"
  10. "github.com/Jguer/yay/v10/pkg/multierror"
  11. "github.com/Jguer/yay/v10/pkg/settings"
  12. "github.com/Jguer/yay/v10/pkg/settings/exe"
  13. "github.com/Jguer/yay/v10/pkg/text"
  14. )
  15. type DBSearcher interface {
  16. SyncPackage(string) db.IPackage
  17. SatisfierFromDB(string, string) db.IPackage
  18. }
  19. func downloadGitRepo(cmdRunner exe.Runner,
  20. cmdBuilder exe.GitCmdBuilder, pkgURL, pkgName, dest string, force bool, gitArgs ...string) error {
  21. finalDir := filepath.Join(dest, pkgName)
  22. if _, err := os.Stat(filepath.Join(finalDir, ".git")); os.IsNotExist(err) || (err == nil && force) {
  23. if _, errD := os.Stat(finalDir); force && errD == nil {
  24. if errR := os.RemoveAll(finalDir); errR != nil {
  25. return ErrGetPKGBUILDRepo{inner: errR, pkgName: pkgName, errOut: ""}
  26. }
  27. }
  28. gitArgs = append(gitArgs, pkgURL, pkgName)
  29. cloneArgs := make([]string, 0, len(gitArgs)+4)
  30. cloneArgs = append(cloneArgs, "clone", "--no-progress")
  31. cloneArgs = append(cloneArgs, gitArgs...)
  32. cmd := cmdBuilder.BuildGitCmd(dest, cloneArgs...)
  33. _, stderr, errCapture := cmdRunner.Capture(cmd, 0)
  34. if errCapture != nil {
  35. return ErrGetPKGBUILDRepo{inner: errCapture, pkgName: pkgName, errOut: stderr}
  36. }
  37. } else if err != nil {
  38. return ErrGetPKGBUILDRepo{
  39. inner: err,
  40. pkgName: pkgName,
  41. errOut: gotext.Get("error reading %s", filepath.Join(dest, pkgName, ".git")),
  42. }
  43. } else {
  44. cmd := cmdBuilder.BuildGitCmd(filepath.Join(dest, pkgName), "pull", "--ff-only")
  45. _, stderr, errCmd := cmdRunner.Capture(cmd, 0)
  46. if errCmd != nil {
  47. return ErrGetPKGBUILDRepo{inner: errCmd, pkgName: pkgName, errOut: stderr}
  48. }
  49. }
  50. return nil
  51. }
  52. func getURLName(pkg db.IPackage) string {
  53. name := pkg.Base()
  54. if name == "" {
  55. name = pkg.Name()
  56. }
  57. return name
  58. }
  59. func PKGBUILDs(dbExecutor DBSearcher, httpClient *http.Client, targets []string, mode settings.TargetMode) (map[string][]byte, error) {
  60. pkgbuilds := make(map[string][]byte, len(targets))
  61. var (
  62. mux sync.Mutex
  63. errs multierror.MultiError
  64. wg sync.WaitGroup
  65. )
  66. sem := make(chan uint8, MaxConcurrentFetch)
  67. for _, target := range targets {
  68. // Probably replaceable by something in query.
  69. dbName, name, aur, toSkip := getPackageUsableName(dbExecutor, target, mode)
  70. if toSkip {
  71. continue
  72. }
  73. sem <- 1
  74. wg.Add(1)
  75. go func(target, dbName, pkgName string, aur bool) {
  76. var (
  77. err error
  78. pkgbuild []byte
  79. )
  80. if aur {
  81. pkgbuild, err = AURPKGBUILD(httpClient, pkgName)
  82. } else {
  83. pkgbuild, err = ABSPKGBUILD(httpClient, dbName, pkgName)
  84. }
  85. if err == nil {
  86. mux.Lock()
  87. pkgbuilds[target] = pkgbuild
  88. mux.Unlock()
  89. } else {
  90. errs.Add(err)
  91. }
  92. <-sem
  93. wg.Done()
  94. }(target, dbName, name, aur)
  95. }
  96. wg.Wait()
  97. return pkgbuilds, errs.Return()
  98. }
  99. func PKGBUILDRepos(dbExecutor DBSearcher,
  100. cmdRunner exe.Runner,
  101. cmdBuilder exe.GitCmdBuilder,
  102. targets []string, mode settings.TargetMode, aurURL, dest string, force bool) (map[string]bool, error) {
  103. cloned := make(map[string]bool, len(targets))
  104. var (
  105. mux sync.Mutex
  106. errs multierror.MultiError
  107. wg sync.WaitGroup
  108. )
  109. sem := make(chan uint8, MaxConcurrentFetch)
  110. for _, target := range targets {
  111. // Probably replaceable by something in query.
  112. dbName, name, aur, toSkip := getPackageUsableName(dbExecutor, target, mode)
  113. if toSkip {
  114. continue
  115. }
  116. sem <- 1
  117. wg.Add(1)
  118. go func(target, dbName, pkgName string, aur bool) {
  119. var err error
  120. if aur {
  121. err = AURPKGBUILDRepo(cmdRunner, cmdBuilder, aurURL, pkgName, dest, force)
  122. } else {
  123. err = ABSPKGBUILDRepo(cmdRunner, cmdBuilder, dbName, pkgName, dest, force)
  124. }
  125. success := err == nil
  126. if success {
  127. mux.Lock()
  128. cloned[target] = success
  129. mux.Unlock()
  130. } else {
  131. errs.Add(err)
  132. }
  133. if aur {
  134. text.OperationInfoln(
  135. gotext.Get("(%d/%d) Downloaded PKGBUILD: %s",
  136. len(cloned), len(targets), text.Cyan(pkgName)))
  137. } else {
  138. text.OperationInfoln(
  139. gotext.Get("(%d/%d) Downloaded PKGBUILD from ABS: %s",
  140. len(cloned), len(targets), text.Cyan(pkgName)))
  141. }
  142. <-sem
  143. wg.Done()
  144. }(target, dbName, name, aur)
  145. }
  146. wg.Wait()
  147. return cloned, errs.Return()
  148. }
  149. func getPackageUsableName(dbExecutor DBSearcher, target string, mode settings.TargetMode) (dbname, pkgname string, aur, toSkip bool) {
  150. aur = true
  151. dbName, name := text.SplitDBFromName(target)
  152. if dbName != "aur" && (mode == settings.ModeAny || mode == settings.ModeRepo) {
  153. var pkg alpm.IPackage
  154. if dbName != "" {
  155. pkg = dbExecutor.SatisfierFromDB(name, dbName)
  156. if pkg == nil {
  157. // if the user precised a db but the package is not in the db
  158. // then it is missing
  159. // Mode does not allow AUR packages
  160. return dbName, name, aur, true
  161. }
  162. } else {
  163. pkg = dbExecutor.SyncPackage(name)
  164. }
  165. if pkg != nil {
  166. aur = false
  167. name = getURLName(pkg)
  168. dbName = pkg.DB().Name()
  169. }
  170. }
  171. if aur && mode == settings.ModeRepo {
  172. return dbName, name, aur, true
  173. }
  174. return dbName, name, aur, false
  175. }