unified.go 5.3 KB

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