unified.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  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 DBSearcher interface {
  15. SyncPackage(string) db.IPackage
  16. SatisfierFromDB(string, string) db.IPackage
  17. }
  18. func downloadGitRepo(cmdBuilder exe.GitCmdBuilder,
  19. pkgURL, pkgName, dest string, force bool, gitArgs ...string) (bool, error) {
  20. finalDir := filepath.Join(dest, pkgName)
  21. newClone := true
  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 false, 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 := cmdBuilder.Capture(cmd, 0)
  34. if errCapture != nil {
  35. return false, ErrGetPKGBUILDRepo{inner: errCapture, pkgName: pkgName, errOut: stderr}
  36. }
  37. } else if err != nil {
  38. return false, 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 := cmdBuilder.Capture(cmd, 0)
  46. if errCmd != nil {
  47. return false, ErrGetPKGBUILDRepo{inner: errCmd, pkgName: pkgName, errOut: stderr}
  48. }
  49. newClone = false
  50. }
  51. return newClone, nil
  52. }
  53. func getURLName(pkg db.IPackage) string {
  54. name := pkg.Base()
  55. if name == "" {
  56. name = pkg.Name()
  57. }
  58. return name
  59. }
  60. func PKGBUILDs(dbExecutor DBSearcher, httpClient *http.Client, targets []string,
  61. aurURL string, mode parser.TargetMode) (map[string][]byte, error) {
  62. pkgbuilds := make(map[string][]byte, len(targets))
  63. var (
  64. mux sync.Mutex
  65. errs multierror.MultiError
  66. wg sync.WaitGroup
  67. )
  68. sem := make(chan uint8, MaxConcurrentFetch)
  69. for _, target := range targets {
  70. // Probably replaceable by something in query.
  71. dbName, name, aur, toSkip := getPackageUsableName(dbExecutor, target, mode)
  72. if toSkip {
  73. continue
  74. }
  75. sem <- 1
  76. wg.Add(1)
  77. go func(target, dbName, pkgName string, aur bool) {
  78. var (
  79. err error
  80. pkgbuild []byte
  81. )
  82. if aur {
  83. pkgbuild, err = AURPKGBUILD(httpClient, pkgName, aurURL)
  84. } else {
  85. pkgbuild, err = ABSPKGBUILD(httpClient, dbName, pkgName)
  86. }
  87. if err == nil {
  88. mux.Lock()
  89. pkgbuilds[target] = pkgbuild
  90. mux.Unlock()
  91. } else {
  92. errs.Add(err)
  93. }
  94. <-sem
  95. wg.Done()
  96. }(target, dbName, name, aur)
  97. }
  98. wg.Wait()
  99. return pkgbuilds, errs.Return()
  100. }
  101. func PKGBUILDRepos(dbExecutor DBSearcher,
  102. cmdBuilder exe.GitCmdBuilder,
  103. targets []string, mode parser.TargetMode, aurURL, dest string, force bool) (map[string]bool, error) {
  104. cloned := make(map[string]bool, len(targets))
  105. var (
  106. mux sync.Mutex
  107. errs multierror.MultiError
  108. wg sync.WaitGroup
  109. )
  110. sem := make(chan uint8, MaxConcurrentFetch)
  111. for _, target := range targets {
  112. // Probably replaceable by something in query.
  113. dbName, name, aur, toSkip := getPackageUsableName(dbExecutor, target, mode)
  114. if toSkip {
  115. continue
  116. }
  117. sem <- 1
  118. wg.Add(1)
  119. go func(target, dbName, pkgName string, aur bool) {
  120. var err error
  121. var newClone bool
  122. if aur {
  123. newClone, err = AURPKGBUILDRepo(cmdBuilder, aurURL, pkgName, dest, force)
  124. } else {
  125. newClone, err = ABSPKGBUILDRepo(cmdBuilder, dbName, pkgName, dest, force)
  126. }
  127. progress := 0
  128. if err != nil {
  129. errs.Add(err)
  130. } else {
  131. mux.Lock()
  132. cloned[target] = newClone
  133. progress = len(cloned)
  134. mux.Unlock()
  135. }
  136. if aur {
  137. text.OperationInfoln(
  138. gotext.Get("(%d/%d) Downloaded PKGBUILD: %s",
  139. progress, len(targets), text.Cyan(pkgName)))
  140. } else {
  141. text.OperationInfoln(
  142. gotext.Get("(%d/%d) Downloaded PKGBUILD from ABS: %s",
  143. progress, len(targets), text.Cyan(pkgName)))
  144. }
  145. <-sem
  146. wg.Done()
  147. }(target, dbName, name, aur)
  148. }
  149. wg.Wait()
  150. return cloned, errs.Return()
  151. }
  152. // TODO: replace with dep.ResolveTargets
  153. func getPackageUsableName(dbExecutor DBSearcher, target string, mode parser.TargetMode) (dbname, pkgname string, aur, toSkip bool) {
  154. aur = true
  155. dbName, name := text.SplitDBFromName(target)
  156. if dbName != "aur" && mode.AtLeastRepo() {
  157. var pkg db.IPackage
  158. if dbName != "" {
  159. pkg = dbExecutor.SatisfierFromDB(name, dbName)
  160. if pkg == nil {
  161. // if the user precised a db but the package is not in the db
  162. // then it is missing
  163. // Mode does not allow AUR packages
  164. return dbName, name, aur, true
  165. }
  166. } else {
  167. pkg = dbExecutor.SyncPackage(name)
  168. }
  169. if pkg != nil {
  170. aur = false
  171. name = getURLName(pkg)
  172. dbName = pkg.DB().Name()
  173. }
  174. }
  175. if aur && mode == parser.ModeRepo {
  176. return dbName, name, aur, true
  177. }
  178. return dbName, name, aur, false
  179. }