123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 |
- package download
- import (
- "context"
- "net/http"
- "os"
- "path/filepath"
- "sync"
- "github.com/leonelquinteros/gotext"
- "github.com/Jguer/aur"
- "github.com/Jguer/yay/v12/pkg/db"
- "github.com/Jguer/yay/v12/pkg/multierror"
- "github.com/Jguer/yay/v12/pkg/settings/exe"
- "github.com/Jguer/yay/v12/pkg/settings/parser"
- "github.com/Jguer/yay/v12/pkg/text"
- )
- type httpRequestDoer interface {
- Get(string) (*http.Response, error)
- }
- type DBSearcher interface {
- SyncPackage(string) db.IPackage
- SatisfierFromDB(string, string) db.IPackage
- }
- func downloadGitRepo(ctx context.Context, cmdBuilder exe.GitCmdBuilder,
- pkgURL, pkgName, dest string, force bool, gitArgs ...string,
- ) (bool, error) {
- finalDir := filepath.Join(dest, pkgName)
- newClone := true
- switch _, err := os.Stat(filepath.Join(finalDir, ".git")); {
- case os.IsNotExist(err) || (err == nil && force):
- if _, errD := os.Stat(finalDir); force && errD == nil {
- if errR := os.RemoveAll(finalDir); errR != nil {
- return false, ErrGetPKGBUILDRepo{inner: errR, pkgName: pkgName, errOut: ""}
- }
- }
- gitArgs = append(gitArgs, pkgURL, pkgName)
- cloneArgs := make([]string, 0, len(gitArgs)+4)
- cloneArgs = append(cloneArgs, "clone", "--no-progress")
- cloneArgs = append(cloneArgs, gitArgs...)
- cmd := cmdBuilder.BuildGitCmd(ctx, dest, cloneArgs...)
- _, stderr, errCapture := cmdBuilder.Capture(cmd)
- if errCapture != nil {
- return false, ErrGetPKGBUILDRepo{inner: errCapture, pkgName: pkgName, errOut: stderr}
- }
- case err != nil:
- return false, ErrGetPKGBUILDRepo{
- inner: err,
- pkgName: pkgName,
- errOut: gotext.Get("error reading %s", filepath.Join(dest, pkgName, ".git")),
- }
- default:
- cmd := cmdBuilder.BuildGitCmd(ctx, filepath.Join(dest, pkgName), "pull", "--rebase", "--autostash")
- _, stderr, errCmd := cmdBuilder.Capture(cmd)
- if errCmd != nil {
- return false, ErrGetPKGBUILDRepo{inner: errCmd, pkgName: pkgName, errOut: stderr}
- }
- newClone = false
- }
- return newClone, nil
- }
- func getURLName(pkg db.IPackage) string {
- name := pkg.Base()
- if name == "" {
- name = pkg.Name()
- }
- return name
- }
- func PKGBUILDs(dbExecutor DBSearcher, aurClient aur.QueryClient, httpClient *http.Client, targets []string,
- aurURL string, mode parser.TargetMode,
- ) (map[string][]byte, error) {
- pkgbuilds := make(map[string][]byte, len(targets))
- var (
- mux sync.Mutex
- errs multierror.MultiError
- wg sync.WaitGroup
- )
- sem := make(chan uint8, MaxConcurrentFetch)
- for _, target := range targets {
- // Probably replaceable by something in query.
- dbName, name, isAUR, toSkip := getPackageUsableName(dbExecutor, aurClient, target, mode)
- if toSkip {
- continue
- }
- sem <- 1
- wg.Add(1)
- go func(target, dbName, pkgName string, aur bool) {
- var (
- err error
- pkgbuild []byte
- )
- if aur {
- pkgbuild, err = AURPKGBUILD(httpClient, pkgName, aurURL)
- } else {
- pkgbuild, err = ABSPKGBUILD(httpClient, dbName, pkgName)
- }
- if err == nil {
- mux.Lock()
- pkgbuilds[target] = pkgbuild
- mux.Unlock()
- } else {
- errs.Add(err)
- }
- <-sem
- wg.Done()
- }(target, dbName, name, isAUR)
- }
- wg.Wait()
- return pkgbuilds, errs.Return()
- }
- func PKGBUILDRepos(ctx context.Context, dbExecutor DBSearcher, aurClient aur.QueryClient,
- cmdBuilder exe.GitCmdBuilder,
- targets []string, mode parser.TargetMode, aurURL, dest string, force bool,
- ) (map[string]bool, error) {
- cloned := make(map[string]bool, len(targets))
- var (
- mux sync.Mutex
- errs multierror.MultiError
- wg sync.WaitGroup
- )
- sem := make(chan uint8, MaxConcurrentFetch)
- for _, target := range targets {
- // Probably replaceable by something in query.
- dbName, name, isAUR, toSkip := getPackageUsableName(dbExecutor, aurClient, target, mode)
- if toSkip {
- continue
- }
- sem <- 1
- wg.Add(1)
- go func(target, dbName, pkgName string, aur bool) {
- var (
- err error
- newClone bool
- )
- if aur {
- newClone, err = AURPKGBUILDRepo(ctx, cmdBuilder, aurURL, pkgName, dest, force)
- } else {
- newClone, err = ABSPKGBUILDRepo(ctx, cmdBuilder, dbName, pkgName, dest, force)
- }
- progress := 0
- if err != nil {
- errs.Add(err)
- } else {
- mux.Lock()
- cloned[target] = newClone
- progress = len(cloned)
- mux.Unlock()
- }
- if aur {
- text.OperationInfoln(
- gotext.Get("(%d/%d) Downloaded PKGBUILD: %s",
- progress, len(targets), text.Cyan(pkgName)))
- } else {
- text.OperationInfoln(
- gotext.Get("(%d/%d) Downloaded PKGBUILD from ABS: %s",
- progress, len(targets), text.Cyan(pkgName)))
- }
- <-sem
- wg.Done()
- }(target, dbName, name, isAUR)
- }
- wg.Wait()
- return cloned, errs.Return()
- }
- // TODO: replace with dep.ResolveTargets.
- func getPackageUsableName(dbExecutor DBSearcher, aurClient aur.QueryClient,
- target string, mode parser.TargetMode,
- ) (dbname, pkgname string, isAUR, toSkip bool) {
- dbName, name := text.SplitDBFromName(target)
- if dbName != "aur" && mode.AtLeastRepo() {
- var pkg db.IPackage
- if dbName != "" {
- pkg = dbExecutor.SatisfierFromDB(name, dbName)
- } else {
- pkg = dbExecutor.SyncPackage(name)
- }
- if pkg != nil {
- name = getURLName(pkg)
- dbName = pkg.DB().Name()
- return dbName, name, false, false
- }
- // If the package is not found in the database and it was expected to be
- if pkg == nil && dbName != "" {
- return dbName, name, true, true
- }
- }
- if mode == parser.ModeRepo {
- return dbName, name, true, true
- }
- pkgs, err := aurClient.Get(context.Background(), &aur.Query{
- By: aur.Name,
- Contains: false,
- Needles: []string{name},
- })
- if err != nil {
- text.Warnln(err)
- return dbName, name, true, true
- }
- if len(pkgs) == 0 {
- return dbName, name, true, true
- }
- return "aur", name, true, false
- }
|