unified.go 5.1 KB

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