unified.go 5.2 KB

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