2017-08-02 17:24:03 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
2018-03-28 14:52:20 +00:00
|
|
|
"path/filepath"
|
2018-05-31 19:31:45 +00:00
|
|
|
"strings"
|
2018-08-18 05:41:16 +00:00
|
|
|
"sync"
|
2018-08-18 03:06:27 +00:00
|
|
|
|
2020-05-04 07:24:32 +00:00
|
|
|
"github.com/leonelquinteros/gotext"
|
|
|
|
"github.com/pkg/errors"
|
2020-05-02 14:17:20 +00:00
|
|
|
|
2020-08-08 16:36:44 +00:00
|
|
|
"github.com/Jguer/yay/v10/pkg/db"
|
2020-07-10 00:36:45 +00:00
|
|
|
"github.com/Jguer/yay/v10/pkg/dep"
|
2020-06-13 17:29:50 +00:00
|
|
|
"github.com/Jguer/yay/v10/pkg/multierror"
|
2020-07-10 00:36:45 +00:00
|
|
|
"github.com/Jguer/yay/v10/pkg/query"
|
2020-06-13 17:29:50 +00:00
|
|
|
"github.com/Jguer/yay/v10/pkg/text"
|
2017-08-02 17:24:03 +00:00
|
|
|
)
|
|
|
|
|
2019-10-15 08:02:10 +00:00
|
|
|
const gitDiffRefName = "AUR_SEEN"
|
2019-10-14 08:56:33 +00:00
|
|
|
|
2019-10-07 10:24:19 +00:00
|
|
|
// Update the YAY_DIFF_REVIEW ref to HEAD. We use this ref to determine which diff were
|
|
|
|
// reviewed by the user
|
2020-05-02 14:17:20 +00:00
|
|
|
func gitUpdateSeenRef(path, name string) error {
|
2019-10-14 08:56:33 +00:00
|
|
|
_, stderr, err := capture(passToGit(filepath.Join(path, name), "update-ref", gitDiffRefName, "HEAD"))
|
2018-05-31 19:31:45 +00:00
|
|
|
if err != nil {
|
2020-05-04 07:24:32 +00:00
|
|
|
return fmt.Errorf("%s %s", stderr, err)
|
2019-10-07 10:24:19 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return wether or not we have reviewed a diff yet. It checks for the existence of
|
|
|
|
// YAY_DIFF_REVIEW in the git ref-list
|
2020-05-02 14:17:20 +00:00
|
|
|
func gitHasLastSeenRef(path, name string) bool {
|
2019-10-14 08:56:33 +00:00
|
|
|
_, _, err := capture(passToGit(filepath.Join(path, name), "rev-parse", "--quiet", "--verify", gitDiffRefName))
|
2019-10-07 10:24:19 +00:00
|
|
|
return err == nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the last reviewed hash. If YAY_DIFF_REVIEW exists it will return this hash.
|
|
|
|
// If it does not it will return empty tree as no diff have been reviewed yet.
|
2020-05-02 14:17:20 +00:00
|
|
|
func getLastSeenHash(path, name string) (string, error) {
|
2019-10-07 10:24:19 +00:00
|
|
|
if gitHasLastSeenRef(path, name) {
|
2019-10-14 08:56:33 +00:00
|
|
|
stdout, stderr, err := capture(passToGit(filepath.Join(path, name), "rev-parse", gitDiffRefName))
|
2019-10-07 10:24:19 +00:00
|
|
|
if err != nil {
|
2020-05-04 07:24:32 +00:00
|
|
|
return "", fmt.Errorf("%s %s", stderr, err)
|
2019-10-07 10:24:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
lines := strings.Split(stdout, "\n")
|
|
|
|
return lines[0], nil
|
2018-05-31 19:31:45 +00:00
|
|
|
}
|
2019-10-07 10:24:19 +00:00
|
|
|
return gitEmptyTree, nil
|
|
|
|
}
|
2018-05-31 19:31:45 +00:00
|
|
|
|
2019-10-07 10:24:19 +00:00
|
|
|
// Check whether or not a diff exists between the last reviewed diff and
|
|
|
|
// HEAD@{upstream}
|
2020-05-02 14:17:20 +00:00
|
|
|
func gitHasDiff(path, name string) (bool, error) {
|
2019-10-07 10:24:19 +00:00
|
|
|
if gitHasLastSeenRef(path, name) {
|
2019-10-14 08:56:33 +00:00
|
|
|
stdout, stderr, err := capture(passToGit(filepath.Join(path, name), "rev-parse", gitDiffRefName, "HEAD@{upstream}"))
|
2019-10-07 10:24:19 +00:00
|
|
|
if err != nil {
|
|
|
|
return false, fmt.Errorf("%s%s", stderr, err)
|
|
|
|
}
|
2018-06-10 00:57:17 +00:00
|
|
|
|
2019-10-07 10:24:19 +00:00
|
|
|
lines := strings.Split(stdout, "\n")
|
|
|
|
lastseen := lines[0]
|
|
|
|
upstream := lines[1]
|
|
|
|
return lastseen != upstream, nil
|
|
|
|
}
|
|
|
|
// If YAY_DIFF_REVIEW does not exists, we have never reviewed a diff for this package
|
|
|
|
// and should display it.
|
|
|
|
return true, nil
|
2018-05-31 19:31:45 +00:00
|
|
|
}
|
|
|
|
|
2019-09-20 17:18:53 +00:00
|
|
|
// TODO: yay-next passes args through the header, use that to unify ABS and AUR
|
2020-05-02 14:17:20 +00:00
|
|
|
func gitDownloadABS(url, path, name string) (bool, error) {
|
2020-07-08 01:40:50 +00:00
|
|
|
if err := os.MkdirAll(path, 0o755); err != nil {
|
2019-10-18 07:39:37 +00:00
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
|
2020-05-02 14:17:20 +00:00
|
|
|
if _, errExist := os.Stat(filepath.Join(path, name)); os.IsNotExist(errExist) {
|
2019-09-20 17:18:53 +00:00
|
|
|
cmd := passToGit(path, "clone", "--no-progress", "--single-branch",
|
|
|
|
"-b", "packages/"+name, url, name)
|
|
|
|
cmd.Env = append(os.Environ(), "GIT_TERMINAL_PROMPT=0")
|
|
|
|
_, stderr, err := capture(cmd)
|
|
|
|
if err != nil {
|
2020-05-04 07:24:32 +00:00
|
|
|
return false, fmt.Errorf(gotext.Get("error cloning %s: %s", name, stderr))
|
2019-09-20 17:18:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true, nil
|
2020-05-02 14:17:20 +00:00
|
|
|
} else if errExist != nil {
|
2020-05-04 07:24:32 +00:00
|
|
|
return false, fmt.Errorf(gotext.Get("error reading %s", filepath.Join(path, name, ".git")))
|
2019-09-20 17:18:53 +00:00
|
|
|
}
|
|
|
|
|
2019-12-23 20:59:37 +00:00
|
|
|
cmd := passToGit(filepath.Join(path, name), "pull", "--ff-only")
|
2019-09-20 17:18:53 +00:00
|
|
|
cmd.Env = append(os.Environ(), "GIT_TERMINAL_PROMPT=0")
|
|
|
|
_, stderr, err := capture(cmd)
|
|
|
|
if err != nil {
|
2020-05-04 07:24:32 +00:00
|
|
|
return false, fmt.Errorf(gotext.Get("error fetching %s: %s", name, stderr))
|
2019-09-20 17:18:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
2020-05-02 14:17:20 +00:00
|
|
|
func gitDownload(url, path, name string) (bool, error) {
|
2018-03-28 14:52:20 +00:00
|
|
|
_, err := os.Stat(filepath.Join(path, name, ".git"))
|
|
|
|
if os.IsNotExist(err) {
|
2018-08-02 22:07:36 +00:00
|
|
|
cmd := passToGit(path, "clone", "--no-progress", url, name)
|
|
|
|
cmd.Env = append(os.Environ(), "GIT_TERMINAL_PROMPT=0")
|
2020-05-02 14:17:20 +00:00
|
|
|
_, stderr, errCapture := capture(cmd)
|
|
|
|
if errCapture != nil {
|
2020-05-04 07:24:32 +00:00
|
|
|
return false, fmt.Errorf(gotext.Get("error cloning %s: %s", name, stderr))
|
2018-03-28 14:52:20 +00:00
|
|
|
}
|
|
|
|
|
2018-06-10 02:41:25 +00:00
|
|
|
return true, nil
|
2018-03-28 14:52:20 +00:00
|
|
|
} else if err != nil {
|
2020-05-04 07:24:32 +00:00
|
|
|
return false, fmt.Errorf(gotext.Get("error reading %s", filepath.Join(path, name, ".git")))
|
2018-03-28 14:52:20 +00:00
|
|
|
}
|
|
|
|
|
2018-08-02 22:07:36 +00:00
|
|
|
cmd := passToGit(filepath.Join(path, name), "fetch")
|
|
|
|
cmd.Env = append(os.Environ(), "GIT_TERMINAL_PROMPT=0")
|
|
|
|
_, stderr, err := capture(cmd)
|
2018-03-28 14:52:20 +00:00
|
|
|
if err != nil {
|
2020-05-04 07:24:32 +00:00
|
|
|
return false, fmt.Errorf(gotext.Get("error fetching %s: %s", name, stderr))
|
2018-03-28 14:52:20 +00:00
|
|
|
}
|
|
|
|
|
2018-06-10 02:41:25 +00:00
|
|
|
return false, nil
|
2018-06-09 23:42:58 +00:00
|
|
|
}
|
|
|
|
|
2020-05-02 14:17:20 +00:00
|
|
|
func gitMerge(path, name string) error {
|
2018-08-02 15:11:37 +00:00
|
|
|
_, stderr, err := capture(passToGit(filepath.Join(path, name), "reset", "--hard", "HEAD"))
|
2018-03-28 14:52:20 +00:00
|
|
|
if err != nil {
|
2020-05-04 07:24:32 +00:00
|
|
|
return fmt.Errorf(gotext.Get("error resetting %s: %s", name, stderr))
|
2018-03-28 14:52:20 +00:00
|
|
|
}
|
|
|
|
|
2018-08-02 15:11:37 +00:00
|
|
|
_, stderr, err = capture(passToGit(filepath.Join(path, name), "merge", "--no-edit", "--ff"))
|
2018-03-28 14:52:20 +00:00
|
|
|
if err != nil {
|
2020-05-04 07:24:32 +00:00
|
|
|
return fmt.Errorf(gotext.Get("error merging %s: %s", name, stderr))
|
2018-03-28 14:52:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-08-16 21:41:38 +00:00
|
|
|
func getPkgbuilds(pkgs []string, dbExecutor db.Executor, force bool) error {
|
2018-06-01 04:04:15 +00:00
|
|
|
missing := false
|
2017-08-02 17:24:03 +00:00
|
|
|
wd, err := os.Getwd()
|
|
|
|
if err != nil {
|
2018-02-17 17:44:30 +00:00
|
|
|
return err
|
2017-08-02 17:24:03 +00:00
|
|
|
}
|
|
|
|
|
2020-07-10 00:36:45 +00:00
|
|
|
pkgs = query.RemoveInvalidTargets(pkgs, config.Runtime.Mode)
|
2020-08-08 16:36:44 +00:00
|
|
|
aur, repo := packageSlices(pkgs, dbExecutor)
|
2019-04-23 16:03:09 +00:00
|
|
|
|
2018-08-18 03:06:27 +00:00
|
|
|
for n := range aur {
|
2020-07-10 00:36:45 +00:00
|
|
|
_, pkg := text.SplitDBFromName(aur[n])
|
2018-08-18 03:06:27 +00:00
|
|
|
aur[n] = pkg
|
|
|
|
}
|
|
|
|
|
2020-07-10 00:36:45 +00:00
|
|
|
info, err := query.AURInfoPrint(aur, config.RequestSplitN)
|
2018-08-17 23:16:04 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-06-01 04:04:15 +00:00
|
|
|
|
|
|
|
if len(repo) > 0 {
|
2020-08-08 16:36:44 +00:00
|
|
|
missing, err = getPkgbuildsfromABS(repo, wd, dbExecutor, force)
|
2018-06-01 04:04:15 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(aur) > 0 {
|
2020-07-10 00:36:45 +00:00
|
|
|
allBases := dep.GetBases(info)
|
|
|
|
bases := make([]dep.Base, 0)
|
2018-08-30 14:30:52 +00:00
|
|
|
|
|
|
|
for _, base := range allBases {
|
|
|
|
name := base.Pkgbase()
|
2020-07-05 12:06:31 +00:00
|
|
|
pkgDest := filepath.Join(wd, name)
|
|
|
|
_, err = os.Stat(pkgDest)
|
2020-07-10 01:02:34 +00:00
|
|
|
if os.IsNotExist(err) {
|
|
|
|
bases = append(bases, base)
|
|
|
|
} else if err != nil {
|
2020-05-04 07:24:32 +00:00
|
|
|
text.Errorln(err)
|
2018-08-30 14:30:52 +00:00
|
|
|
continue
|
2020-07-10 01:02:34 +00:00
|
|
|
} else {
|
2020-07-08 01:22:01 +00:00
|
|
|
if force {
|
2020-07-05 12:06:31 +00:00
|
|
|
if err = os.RemoveAll(pkgDest); err != nil {
|
|
|
|
text.Errorln(err)
|
|
|
|
continue
|
|
|
|
}
|
2020-07-10 01:02:34 +00:00
|
|
|
bases = append(bases, base)
|
2020-07-05 12:06:31 +00:00
|
|
|
} else {
|
|
|
|
text.Warnln(gotext.Get("%s already exists. Use -f/--force to overwrite", pkgDest))
|
2018-08-30 14:30:52 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, err = downloadPkgbuilds(bases, nil, wd); err != nil {
|
2018-06-01 04:04:15 +00:00
|
|
|
return err
|
|
|
|
}
|
2018-08-17 23:16:04 +00:00
|
|
|
|
|
|
|
missing = missing || len(aur) != len(info)
|
2018-06-01 04:04:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if missing {
|
|
|
|
err = fmt.Errorf("")
|
2017-08-02 17:24:03 +00:00
|
|
|
}
|
|
|
|
|
2018-02-17 17:44:30 +00:00
|
|
|
return err
|
2017-08-02 17:24:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetPkgbuild downloads pkgbuild from the ABS.
|
2020-08-16 21:41:38 +00:00
|
|
|
func getPkgbuildsfromABS(pkgs []string, path string, dbExecutor db.Executor, force bool) (bool, error) {
|
2018-08-18 05:41:16 +00:00
|
|
|
var wg sync.WaitGroup
|
|
|
|
var mux sync.Mutex
|
2019-10-16 21:38:54 +00:00
|
|
|
var errs multierror.MultiError
|
2018-08-18 05:41:16 +00:00
|
|
|
names := make(map[string]string)
|
|
|
|
missing := make([]string, 0)
|
|
|
|
downloaded := 0
|
|
|
|
|
|
|
|
for _, pkgN := range pkgs {
|
2020-08-08 16:36:44 +00:00
|
|
|
var pkg db.RepoPackage
|
2018-08-18 03:06:27 +00:00
|
|
|
var err error
|
|
|
|
var url string
|
2020-07-10 00:36:45 +00:00
|
|
|
pkgDB, name := text.SplitDBFromName(pkgN)
|
2018-06-01 04:04:15 +00:00
|
|
|
|
2019-02-04 16:56:02 +00:00
|
|
|
if pkgDB != "" {
|
2020-08-08 16:36:44 +00:00
|
|
|
pkg = dbExecutor.PackageFromDB(name, pkgDB)
|
2018-08-18 03:06:27 +00:00
|
|
|
} else {
|
2020-08-08 16:36:44 +00:00
|
|
|
pkg = dbExecutor.SyncSatisfier(name)
|
2018-08-18 03:06:27 +00:00
|
|
|
}
|
2018-05-14 17:33:48 +00:00
|
|
|
|
2018-08-18 03:06:27 +00:00
|
|
|
if pkg == nil {
|
2018-08-18 05:41:16 +00:00
|
|
|
missing = append(missing, name)
|
2018-08-18 03:06:27 +00:00
|
|
|
continue
|
|
|
|
}
|
2018-02-17 17:44:30 +00:00
|
|
|
|
2018-08-18 03:06:27 +00:00
|
|
|
name = pkg.Base()
|
|
|
|
if name == "" {
|
|
|
|
name = pkg.Name()
|
|
|
|
}
|
2018-05-14 17:33:48 +00:00
|
|
|
|
2019-09-20 17:18:53 +00:00
|
|
|
// TODO: Check existence with ls-remote
|
|
|
|
// https://git.archlinux.org/svntogit/packages.git
|
2018-08-18 03:06:27 +00:00
|
|
|
switch pkg.DB().Name() {
|
|
|
|
case "core", "extra", "testing":
|
2019-09-20 17:18:53 +00:00
|
|
|
url = "https://git.archlinux.org/svntogit/packages.git"
|
2018-08-18 03:06:27 +00:00
|
|
|
case "community", "multilib", "community-testing", "multilib-testing":
|
2019-09-20 17:18:53 +00:00
|
|
|
url = "https://git.archlinux.org/svntogit/community.git"
|
2018-08-18 03:06:27 +00:00
|
|
|
default:
|
2018-08-18 05:41:16 +00:00
|
|
|
missing = append(missing, name)
|
2018-08-18 03:06:27 +00:00
|
|
|
continue
|
2017-08-02 17:24:03 +00:00
|
|
|
}
|
2018-02-17 17:44:30 +00:00
|
|
|
|
2018-08-30 14:30:52 +00:00
|
|
|
_, err = os.Stat(filepath.Join(path, name))
|
2019-03-07 20:02:44 +00:00
|
|
|
switch {
|
|
|
|
case err != nil && !os.IsNotExist(err):
|
2020-07-10 22:48:30 +00:00
|
|
|
text.Errorln(err)
|
2018-08-18 05:41:16 +00:00
|
|
|
continue
|
2020-07-08 01:22:01 +00:00
|
|
|
case os.IsNotExist(err), force:
|
2018-08-30 14:30:52 +00:00
|
|
|
if err = os.RemoveAll(filepath.Join(path, name)); err != nil {
|
2020-07-10 22:48:30 +00:00
|
|
|
text.Errorln(err)
|
2018-08-30 14:30:52 +00:00
|
|
|
continue
|
|
|
|
}
|
2019-03-07 20:02:44 +00:00
|
|
|
default:
|
2020-08-16 22:09:43 +00:00
|
|
|
text.Warn(gotext.Get("%s already downloaded -- use -f to overwrite", text.Cyan(name)))
|
2018-08-30 14:30:52 +00:00
|
|
|
continue
|
2018-08-18 05:41:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
names[name] = url
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(missing) != 0 {
|
2020-05-04 07:24:32 +00:00
|
|
|
text.Warnln(gotext.Get("Missing ABS packages:"),
|
2020-08-16 22:09:43 +00:00
|
|
|
text.Cyan(strings.Join(missing, ", ")))
|
2018-08-18 05:41:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
download := func(pkg string, url string) {
|
|
|
|
defer wg.Done()
|
2019-10-18 07:39:37 +00:00
|
|
|
if _, err := gitDownloadABS(url, config.ABSDir, pkg); err != nil {
|
2020-08-16 22:09:43 +00:00
|
|
|
errs.Add(errors.New(gotext.Get("failed to get pkgbuild: %s: %s", text.Cyan(pkg), err.Error())))
|
2018-08-18 05:41:16 +00:00
|
|
|
return
|
2018-08-18 03:06:27 +00:00
|
|
|
}
|
2018-02-17 17:44:30 +00:00
|
|
|
|
2019-10-23 11:31:29 +00:00
|
|
|
_, stderr, err := capture(exec.Command("cp", "-r", filepath.Join(config.ABSDir, pkg, "trunk"), filepath.Join(path, pkg)))
|
2018-08-18 05:41:16 +00:00
|
|
|
mux.Lock()
|
|
|
|
downloaded++
|
2018-08-18 03:06:27 +00:00
|
|
|
if err != nil {
|
2020-08-16 22:09:43 +00:00
|
|
|
errs.Add(errors.New(gotext.Get("failed to link %s: %s", text.Cyan(pkg), stderr)))
|
2018-08-18 03:06:27 +00:00
|
|
|
} else {
|
2020-08-16 22:09:43 +00:00
|
|
|
fmt.Fprintln(os.Stdout, gotext.Get("(%d/%d) Downloaded PKGBUILD from ABS: %s", downloaded, len(names), text.Cyan(pkg)))
|
2018-08-18 03:06:27 +00:00
|
|
|
}
|
2018-08-18 05:41:16 +00:00
|
|
|
mux.Unlock()
|
|
|
|
}
|
|
|
|
|
2018-09-04 17:28:36 +00:00
|
|
|
count := 0
|
2018-08-18 05:41:16 +00:00
|
|
|
for name, url := range names {
|
|
|
|
wg.Add(1)
|
|
|
|
go download(name, url)
|
2018-09-04 17:28:36 +00:00
|
|
|
count++
|
|
|
|
if count%25 == 0 {
|
|
|
|
wg.Wait()
|
|
|
|
}
|
2018-05-14 17:33:48 +00:00
|
|
|
}
|
|
|
|
|
2018-08-18 05:41:16 +00:00
|
|
|
wg.Wait()
|
2020-07-08 01:40:50 +00:00
|
|
|
|
2018-08-18 05:41:16 +00:00
|
|
|
return len(missing) != 0, errs.Return()
|
2017-08-02 17:24:03 +00:00
|
|
|
}
|