fix: rework menus to work on both flows (#1830)

* rework menus to work on both flows

* add installed package split

* remove unused field

* Add post install hooks
This commit is contained in:
Jo 2022-11-20 00:51:55 +00:00 committed by GitHub
parent 63f20599cd
commit 6ad63cae10
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 387 additions and 194 deletions

View File

@ -99,7 +99,7 @@ func cleanAUR(ctx context.Context, keepInstalled, keepCurrent, removeAll bool, d
installedBases := make(stringset.StringSet)
inAURBases := make(stringset.StringSet)
remotePackages, _ := query.GetRemotePackages(dbExecutor)
remotePackages := dbExecutor.InstalledRemotePackages()
files, err := os.ReadDir(config.BuildDir)
if err != nil {
@ -194,10 +194,11 @@ func isGitRepository(dir string) bool {
return !os.IsNotExist(err)
}
func cleanAfter(ctx context.Context, cmdBuilder exe.ICmdBuilder, pkgbuildDirs []string) {
func cleanAfter(ctx context.Context, cmdBuilder exe.ICmdBuilder, pkgbuildDirs map[string]string) {
fmt.Println(gotext.Get("removing untracked AUR files from cache..."))
for i, dir := range pkgbuildDirs {
i := 0
for _, dir := range pkgbuildDirs {
text.OperationInfoln(gotext.Get("Cleaning (%d/%d): %s", i+1, len(pkgbuildDirs), text.Cyan(dir)))
_, stderr, err := cmdBuilder.Capture(
@ -212,5 +213,7 @@ func cleanAfter(ctx context.Context, cmdBuilder exe.ICmdBuilder, pkgbuildDirs []
ctx, dir, "clean", "-fx", "--exclude='*.pkg.*'")); err != nil {
fmt.Fprintln(os.Stderr, err)
}
i++
}
}

View File

@ -12,6 +12,7 @@ import (
alpm "github.com/Jguer/go-alpm/v2"
gosrc "github.com/Morganamilo/go-srcinfo"
mapset "github.com/deckarep/golang-set/v2"
"github.com/leonelquinteros/gotext"
"github.com/Jguer/yay/v11/pkg/completion"
@ -109,12 +110,10 @@ func install(ctx context.Context, cmdArgs *parser.Arguments, dbExecutor db.Execu
return errRefresh
}
localNames, remoteNames, err := query.GetPackageNamesBySource(dbExecutor)
if err != nil {
return err
}
remoteNames := dbExecutor.InstalledRemotePackageNames()
localNames := dbExecutor.InstalledSyncPackageNames()
remoteNamesCache := stringset.FromSlice(remoteNames)
remoteNamesCache := mapset.NewThreadUnsafeSet(remoteNames...)
localNamesCache := stringset.FromSlice(localNames)
requestTargets := cmdArgs.Copy().Targets
@ -197,17 +196,17 @@ func install(ctx context.Context, cmdArgs *parser.Arguments, dbExecutor db.Execu
do.Print()
fmt.Println()
pkgbuildDirs := make(map[string]string, len(do.Aur))
for _, base := range do.Aur {
dir := filepath.Join(config.BuildDir, base.Pkgbase())
if isGitRepository(dir) {
pkgbuildDirs[base.Pkgbase()] = dir
}
}
if config.CleanAfter {
defer func() {
pkgbuildDirs := make([]string, 0, len(do.Aur))
for _, base := range do.Aur {
dir := filepath.Join(config.BuildDir, base.Pkgbase())
if isGitRepository(dir) {
pkgbuildDirs = append(pkgbuildDirs, dir)
}
}
cleanAfter(ctx, config.Runtime.CmdBuilder, pkgbuildDirs)
}()
}
@ -230,8 +229,8 @@ func install(ctx context.Context, cmdArgs *parser.Arguments, dbExecutor db.Execu
}
}
if errCleanMenu := menus.Clean(config.CleanMenu,
config.BuildDir, do.Aur,
if errCleanMenu := menus.Clean(os.Stdout, config.CleanMenu,
pkgbuildDirs,
remoteNamesCache, settings.NoConfirm, config.AnswerClean); errCleanMenu != nil {
if errors.As(errCleanMenu, &settings.ErrUserAbort{}) {
return errCleanMenu
@ -261,8 +260,8 @@ func install(ctx context.Context, cmdArgs *parser.Arguments, dbExecutor db.Execu
return errA
}
if errDiffMenu := menus.Diff(ctx, config.Runtime.CmdBuilder, config.BuildDir,
config.DiffMenu, do.Aur, remoteNamesCache,
if errDiffMenu := menus.Diff(ctx, config.Runtime.CmdBuilder, os.Stdout, pkgbuildDirs,
config.DiffMenu, remoteNamesCache,
cloned, settings.NoConfirm, config.AnswerDiff); errDiffMenu != nil {
if errors.As(errDiffMenu, &settings.ErrUserAbort{}) {
return errDiffMenu
@ -280,7 +279,7 @@ func install(ctx context.Context, cmdArgs *parser.Arguments, dbExecutor db.Execu
return err
}
if errEditMenu := menus.Edit(config.EditMenu, config.BuildDir, do.Aur,
if errEditMenu := menus.Edit(os.Stdout, config.EditMenu, pkgbuildDirs,
config.Editor, config.EditorFlags, remoteNamesCache, srcinfos,
settings.NoConfirm, config.AnswerEdit); errEditMenu != nil {
if errors.As(errEditMenu, &settings.ErrUserAbort{}) {
@ -315,7 +314,7 @@ func install(ctx context.Context, cmdArgs *parser.Arguments, dbExecutor db.Execu
exp := make([]string, 0)
for _, pkg := range do.Repo {
if !dp.Explicit.Get(pkg.Name()) && !localNamesCache.Get(pkg.Name()) && !remoteNamesCache.Get(pkg.Name()) {
if !dp.Explicit.Get(pkg.Name()) && !localNamesCache.Get(pkg.Name()) && !remoteNamesCache.Contains(pkg.Name()) {
deps = append(deps, pkg.Name())
continue
@ -630,10 +629,8 @@ func buildInstallPkgbuilds(
settings.NoConfirm = true
// remotenames: names of all non repo packages on the system
localNames, remoteNames, err := query.GetPackageNamesBySource(dbExecutor)
if err != nil {
return err
}
remoteNames := dbExecutor.InstalledRemotePackageNames()
localNames := dbExecutor.InstalledSyncPackageNames()
// cache as a stringset. maybe make it return a string set in the first
// place
@ -688,7 +685,7 @@ func buildInstallPkgbuilds(
}
// pkgver bump
if err = config.Runtime.CmdBuilder.Show(
if err := config.Runtime.CmdBuilder.Show(
config.Runtime.CmdBuilder.BuildMakepkgCmd(ctx, dir, args...)); err != nil {
return errors.New(gotext.Get("error making: %s", base.String()))
}
@ -727,7 +724,7 @@ func buildInstallPkgbuilds(
}
if installed {
err = config.Runtime.CmdBuilder.Show(
err := config.Runtime.CmdBuilder.Show(
config.Runtime.CmdBuilder.BuildMakepkgCmd(ctx,
dir, "-c", "--nobuild", "--noextract", "--ignorearch"))
if err != nil {
@ -741,7 +738,7 @@ func buildInstallPkgbuilds(
}
if built {
err = config.Runtime.CmdBuilder.Show(
err := config.Runtime.CmdBuilder.Show(
config.Runtime.CmdBuilder.BuildMakepkgCmd(ctx,
dir, "-c", "--nobuild", "--noextract", "--ignorearch"))
if err != nil {
@ -816,7 +813,7 @@ func buildInstallPkgbuilds(
settings.NoConfirm = oldConfirm
return err
return nil
}
func installPkgArchive(ctx context.Context, cmdArgs *parser.Arguments, pkgArchives []string) error {

View File

@ -30,6 +30,9 @@ type Executor interface {
AlpmArchitectures() ([]string, error)
BiggestPackages() []IPackage
Cleanup()
InstalledRemotePackageNames() []string
InstalledRemotePackages() []IPackage
InstalledSyncPackageNames() []string
IsCorrectVersionInstalled(string, string) bool
LastBuildTime() time.Time
LocalPackage(string) IPackage

View File

@ -23,16 +23,29 @@ type AlpmExecutor struct {
syncDB alpm.IDBList
syncDBsCache []alpm.IDB
conf *pacmanconf.Config
installedRemotePkgs []alpm.IPackage
installedRemotePkgNames []string
installedSyncPkgNames []string
}
func NewExecutor(pacmanConf *pacmanconf.Config) (*AlpmExecutor, error) {
ae := &AlpmExecutor{conf: pacmanConf}
ae := &AlpmExecutor{
handle: nil,
localDB: nil,
syncDB: nil,
syncDBsCache: []alpm.IDB{},
conf: pacmanConf,
installedRemotePkgs: nil,
installedRemotePkgNames: nil,
installedSyncPkgNames: nil,
}
err := ae.RefreshHandle()
if err != nil {
if err := ae.RefreshHandle(); err != nil {
return nil, err
}
var err error
ae.localDB, err = ae.handle.LocalDB()
if err != nil {
return nil, err

View File

@ -0,0 +1,46 @@
package ialpm
import (
"github.com/Jguer/yay/v11/pkg/db"
"github.com/Jguer/yay/v11/pkg/text"
)
// GetPackageNamesBySource returns package names with and without correspondence in SyncDBS respectively.
func (ae *AlpmExecutor) getPackageNamesBySource() {
for _, localpkg := range ae.LocalPackages() {
pkgName := localpkg.Name()
if ae.SyncPackage(pkgName) != nil {
ae.installedSyncPkgNames = append(ae.installedSyncPkgNames, pkgName)
} else {
ae.installedRemotePkgs = append(ae.installedRemotePkgs, localpkg)
ae.installedRemotePkgNames = append(ae.installedRemotePkgNames, pkgName)
}
}
text.Debugln("populating db executor package caches.",
"sync_len", len(ae.installedSyncPkgNames), "remote_len", len(ae.installedRemotePkgNames))
}
func (ae *AlpmExecutor) InstalledRemotePackages() []db.IPackage {
if ae.installedRemotePkgs == nil {
ae.getPackageNamesBySource()
}
return ae.installedRemotePkgs
}
func (ae *AlpmExecutor) InstalledRemotePackageNames() []string {
if ae.installedRemotePkgNames == nil {
ae.getPackageNamesBySource()
}
return ae.installedRemotePkgNames
}
func (ae *AlpmExecutor) InstalledSyncPackageNames() []string {
if ae.installedSyncPkgNames == nil {
ae.getPackageNamesBySource()
}
return ae.installedSyncPkgNames
}

View File

@ -14,7 +14,9 @@ type (
Upgrade = db.Upgrade
)
type DBExecutor struct{}
type DBExecutor struct {
db.Executor
}
func (t DBExecutor) AlpmArchitectures() ([]string, error) {
panic("implement me")

View File

@ -2,22 +2,20 @@
package menus
import (
"context"
"fmt"
"io"
"os"
"path/filepath"
mapset "github.com/deckarep/golang-set/v2"
"github.com/leonelquinteros/gotext"
"github.com/Jguer/yay/v11/pkg/dep"
"github.com/Jguer/yay/v11/pkg/stringset"
"github.com/Jguer/yay/v11/pkg/settings"
"github.com/Jguer/yay/v11/pkg/text"
)
func anyExistInCache(buildDir string, bases []dep.Base) bool {
for _, base := range bases {
pkg := base.Pkgbase()
dir := filepath.Join(buildDir, pkg)
func anyExistInCache(pkgbuildDirs map[string]string) bool {
for _, dir := range pkgbuildDirs {
if _, err := os.Stat(dir); !os.IsNotExist(err) {
return true
}
@ -26,14 +24,13 @@ func anyExistInCache(buildDir string, bases []dep.Base) bool {
return false
}
func Clean(cleanMenuOption bool, buildDir string, bases []dep.Base,
installed stringset.StringSet, noConfirm bool, answerClean string) error {
if !(cleanMenuOption && anyExistInCache(buildDir, bases)) {
func CleanFn(ctx context.Context, config *settings.Configuration, w io.Writer, pkgbuildDirsByBase map[string]string) error {
if !anyExistInCache(pkgbuildDirsByBase) {
return nil
}
skipFunc := func(pkg string) bool {
dir := filepath.Join(buildDir, pkg)
dir := pkgbuildDirsByBase[pkg]
if _, err := os.Stat(dir); os.IsNotExist(err) {
return true
}
@ -41,14 +38,68 @@ func Clean(cleanMenuOption bool, buildDir string, bases []dep.Base,
return false
}
toClean, errClean := selectionMenu(buildDir, bases, installed, gotext.Get("Packages to cleanBuild?"),
bases := make([]string, 0, len(pkgbuildDirsByBase))
for pkg := range pkgbuildDirsByBase {
bases = append(bases, pkg)
}
// TOFIX: empty installed slice means installed filter is disabled
toClean, errClean := selectionMenu(w, pkgbuildDirsByBase, bases, mapset.NewSet[string](),
gotext.Get("Packages to cleanBuild?"),
settings.NoConfirm, config.AnswerClean, skipFunc)
if errClean != nil {
return errClean
}
for i, base := range toClean {
dir := pkgbuildDirsByBase[base]
text.OperationInfoln(gotext.Get("Deleting (%d/%d): %s", i+1, len(toClean), text.Cyan(dir)))
if err := config.Runtime.CmdBuilder.Show(config.Runtime.CmdBuilder.BuildGitCmd(ctx, dir, "reset", "--hard")); err != nil {
text.Warnln(gotext.Get("Unable to clean:"), dir)
return err
}
if err := config.Runtime.CmdBuilder.Show(config.Runtime.CmdBuilder.BuildGitCmd(ctx, dir, "clean", "-fdx")); err != nil {
text.Warnln(gotext.Get("Unable to clean:"), dir)
return err
}
}
return nil
}
func Clean(w io.Writer, cleanMenuOption bool, pkgbuildDirs map[string]string,
installed mapset.Set[string], noConfirm bool, answerClean string,
) error {
if !(cleanMenuOption && anyExistInCache(pkgbuildDirs)) {
return nil
}
skipFunc := func(pkg string) bool {
dir := pkgbuildDirs[pkg]
if _, err := os.Stat(dir); os.IsNotExist(err) {
return true
}
return false
}
bases := make([]string, 0, len(pkgbuildDirs))
for pkg := range pkgbuildDirs {
bases = append(bases, pkg)
}
toClean, errClean := selectionMenu(w, pkgbuildDirs, bases, installed, gotext.Get("Packages to cleanBuild?"),
noConfirm, answerClean, skipFunc)
if errClean != nil {
return errClean
}
for i, base := range toClean {
dir := filepath.Join(buildDir, base.Pkgbase())
dir := pkgbuildDirs[base]
text.OperationInfoln(gotext.Get("Deleting (%d/%d): %s", i+1, len(toClean), text.Cyan(dir)))
if err := os.RemoveAll(dir); err != nil {

View File

@ -4,17 +4,16 @@ package menus
import (
"context"
"fmt"
"io"
"os"
"path/filepath"
"strings"
mapset "github.com/deckarep/golang-set/v2"
"github.com/leonelquinteros/gotext"
"github.com/Jguer/yay/v11/pkg/dep"
"github.com/Jguer/yay/v11/pkg/multierror"
"github.com/Jguer/yay/v11/pkg/settings"
"github.com/Jguer/yay/v11/pkg/settings/exe"
"github.com/Jguer/yay/v11/pkg/stringset"
"github.com/Jguer/yay/v11/pkg/text"
)
@ -23,24 +22,23 @@ const (
gitDiffRefName = "AUR_SEEN"
)
func showPkgbuildDiffs(ctx context.Context, cmdBuilder exe.ICmdBuilder, buildDir string, bases []dep.Base, cloned map[string]bool) error {
func showPkgbuildDiffs(ctx context.Context, cmdBuilder exe.ICmdBuilder,
pkgbuildDirs map[string]string, bases []string,
) error {
var errMulti multierror.MultiError
for _, base := range bases {
pkg := base.Pkgbase()
dir := filepath.Join(buildDir, pkg)
for _, pkg := range bases {
dir := pkgbuildDirs[pkg]
start, err := getLastSeenHash(ctx, cmdBuilder, buildDir, pkg)
start, err := getLastSeenHash(ctx, cmdBuilder, dir)
if err != nil {
errMulti.Add(err)
continue
}
if cloned[pkg] {
start = gitEmptyTree
} else {
hasDiff, err := gitHasDiff(ctx, cmdBuilder, buildDir, pkg)
if start != gitEmptyTree {
hasDiff, err := gitHasDiff(ctx, cmdBuilder, dir)
if err != nil {
errMulti.Add(err)
@ -48,7 +46,7 @@ func showPkgbuildDiffs(ctx context.Context, cmdBuilder exe.ICmdBuilder, buildDir
}
if !hasDiff {
text.Warnln(gotext.Get("%s: No changes -- skipping", text.Cyan(base.String())))
text.Warnln(gotext.Get("%s: No changes -- skipping", text.Cyan(pkg)))
continue
}
@ -73,10 +71,10 @@ func showPkgbuildDiffs(ctx context.Context, cmdBuilder exe.ICmdBuilder, buildDir
// Check whether or not a diff exists between the last reviewed diff and
// HEAD@{upstream}.
func gitHasDiff(ctx context.Context, cmdBuilder exe.ICmdBuilder, path, name string) (bool, error) {
if gitHasLastSeenRef(ctx, cmdBuilder, path, name) {
func gitHasDiff(ctx context.Context, cmdBuilder exe.ICmdBuilder, dir string) (bool, error) {
if gitHasLastSeenRef(ctx, cmdBuilder, dir) {
stdout, stderr, err := cmdBuilder.Capture(
cmdBuilder.BuildGitCmd(ctx, filepath.Join(path, name), "rev-parse", gitDiffRefName, "HEAD@{upstream}"))
cmdBuilder.BuildGitCmd(ctx, dir, "rev-parse", gitDiffRefName, "HEAD@{upstream}"))
if err != nil {
return false, fmt.Errorf("%s%s", stderr, err)
}
@ -94,21 +92,21 @@ func gitHasDiff(ctx context.Context, cmdBuilder exe.ICmdBuilder, path, name stri
// Return wether or not we have reviewed a diff yet. It checks for the existence of
// YAY_DIFF_REVIEW in the git ref-list.
func gitHasLastSeenRef(ctx context.Context, cmdBuilder exe.ICmdBuilder, path, name string) bool {
func gitHasLastSeenRef(ctx context.Context, cmdBuilder exe.ICmdBuilder, dir string) bool {
_, _, err := cmdBuilder.Capture(
cmdBuilder.BuildGitCmd(ctx,
filepath.Join(path, name), "rev-parse", "--quiet", "--verify", gitDiffRefName))
dir, "rev-parse", "--quiet", "--verify", gitDiffRefName))
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.
func getLastSeenHash(ctx context.Context, cmdBuilder exe.ICmdBuilder, path, name string) (string, error) {
if gitHasLastSeenRef(ctx, cmdBuilder, path, name) {
func getLastSeenHash(ctx context.Context, cmdBuilder exe.ICmdBuilder, dir string) (string, error) {
if gitHasLastSeenRef(ctx, cmdBuilder, dir) {
stdout, stderr, err := cmdBuilder.Capture(
cmdBuilder.BuildGitCmd(ctx,
filepath.Join(path, name), "rev-parse", gitDiffRefName))
dir, "rev-parse", gitDiffRefName))
if err != nil {
return "", fmt.Errorf("%s %s", stderr, err)
}
@ -123,10 +121,10 @@ func getLastSeenHash(ctx context.Context, cmdBuilder exe.ICmdBuilder, path, name
// Update the YAY_DIFF_REVIEW ref to HEAD. We use this ref to determine which diff were
// reviewed by the user.
func gitUpdateSeenRef(ctx context.Context, cmdBuilder exe.ICmdBuilder, path, name string) error {
func gitUpdateSeenRef(ctx context.Context, cmdBuilder exe.ICmdBuilder, dir string) error {
_, stderr, err := cmdBuilder.Capture(
cmdBuilder.BuildGitCmd(ctx,
filepath.Join(path, name), "update-ref", gitDiffRefName, "HEAD"))
dir, "update-ref", gitDiffRefName, "HEAD"))
if err != nil {
return fmt.Errorf("%s %s", stderr, err)
}
@ -134,13 +132,12 @@ func gitUpdateSeenRef(ctx context.Context, cmdBuilder exe.ICmdBuilder, path, nam
return nil
}
func updatePkgbuildSeenRef(ctx context.Context, cmdBuilder exe.ICmdBuilder, buildDir string, bases []dep.Base) error {
func updatePkgbuildSeenRef(ctx context.Context, cmdBuilder exe.ICmdBuilder, pkgbuildDirs map[string]string, bases []string) error {
var errMulti multierror.MultiError
for _, base := range bases {
pkg := base.Pkgbase()
if err := gitUpdateSeenRef(ctx, cmdBuilder, buildDir, pkg); err != nil {
for _, pkg := range bases {
dir := pkgbuildDirs[pkg]
if err := gitUpdateSeenRef(ctx, cmdBuilder, dir); err != nil {
errMulti.Add(err)
}
}
@ -148,21 +145,26 @@ func updatePkgbuildSeenRef(ctx context.Context, cmdBuilder exe.ICmdBuilder, buil
return errMulti.Return()
}
func Diff(ctx context.Context, cmdBuilder exe.ICmdBuilder,
buildDir string, diffMenuOption bool, bases []dep.Base,
installed stringset.StringSet, cloned map[string]bool, noConfirm bool, diffDefaultAnswer string,
func Diff(ctx context.Context, cmdBuilder exe.ICmdBuilder, w io.Writer,
pkgbuildDirs map[string]string, diffMenuOption bool,
installed mapset.Set[string], cloned map[string]bool, noConfirm bool, diffDefaultAnswer string,
) error {
if !diffMenuOption {
return nil
}
toDiff, errMenu := selectionMenu(buildDir, bases, installed, gotext.Get("Diffs to show?"),
bases := make([]string, 0, len(pkgbuildDirs))
for base := range pkgbuildDirs {
bases = append(bases, base)
}
toDiff, errMenu := selectionMenu(w, pkgbuildDirs, bases, installed, gotext.Get("Diffs to show?"),
noConfirm, diffDefaultAnswer, nil)
if errMenu != nil || len(toDiff) == 0 {
return errMenu
}
if errD := showPkgbuildDiffs(ctx, cmdBuilder, buildDir, toDiff, cloned); errD != nil {
if errD := showPkgbuildDiffs(ctx, cmdBuilder, pkgbuildDirs, toDiff); errD != nil {
return errD
}
@ -172,7 +174,36 @@ func Diff(ctx context.Context, cmdBuilder exe.ICmdBuilder,
return settings.ErrUserAbort{}
}
if errUpd := updatePkgbuildSeenRef(ctx, cmdBuilder, buildDir, toDiff); errUpd != nil {
if errUpd := updatePkgbuildSeenRef(ctx, cmdBuilder, pkgbuildDirs, toDiff); errUpd != nil {
return errUpd
}
return nil
}
func DiffFn(ctx context.Context, config *settings.Configuration, w io.Writer, pkgbuildDirsByBase map[string]string) error {
bases := make([]string, 0, len(pkgbuildDirsByBase))
for base := range pkgbuildDirsByBase {
bases = append(bases, base)
}
toDiff, errMenu := selectionMenu(w, pkgbuildDirsByBase, bases, mapset.NewThreadUnsafeSet[string](), gotext.Get("Diffs to show?"),
settings.NoConfirm, config.AnswerDiff, nil)
if errMenu != nil || len(toDiff) == 0 {
return errMenu
}
if errD := showPkgbuildDiffs(ctx, config.Runtime.CmdBuilder, pkgbuildDirsByBase, toDiff); errD != nil {
return errD
}
fmt.Println()
if !text.ContinueTask(os.Stdin, gotext.Get("Proceed with install?"), true, false) {
return settings.ErrUserAbort{}
}
if errUpd := updatePkgbuildSeenRef(ctx, config.Runtime.CmdBuilder, pkgbuildDirsByBase, toDiff); errUpd != nil {
return errUpd
}

View File

@ -2,19 +2,20 @@
package menus
import (
"context"
"errors"
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
"strings"
gosrc "github.com/Morganamilo/go-srcinfo"
mapset "github.com/deckarep/golang-set/v2"
"github.com/leonelquinteros/gotext"
"github.com/Jguer/yay/v11/pkg/dep"
"github.com/Jguer/yay/v11/pkg/settings"
"github.com/Jguer/yay/v11/pkg/stringset"
"github.com/Jguer/yay/v11/pkg/text"
)
@ -82,19 +83,20 @@ func editor(editorConfig, editorFlags string, noConfirm bool) (editor string, ar
}
}
func editPkgbuilds(buildDir string, bases []dep.Base, editorConfig,
func editPkgbuilds(pkgbuildDirs map[string]string, bases []string, editorConfig,
editorFlags string, srcinfos map[string]*gosrc.Srcinfo, noConfirm bool,
) error {
pkgbuilds := make([]string, 0, len(bases))
for _, base := range bases {
pkg := base.Pkgbase()
dir := filepath.Join(buildDir, pkg)
for _, pkg := range bases {
dir := pkgbuildDirs[pkg]
pkgbuilds = append(pkgbuilds, filepath.Join(dir, "PKGBUILD"))
for _, splitPkg := range srcinfos[pkg].SplitPackages() {
if splitPkg.Install != "" {
pkgbuilds = append(pkgbuilds, filepath.Join(dir, splitPkg.Install))
if srcinfos != nil {
for _, splitPkg := range srcinfos[pkg].SplitPackages() {
if splitPkg.Install != "" {
pkgbuilds = append(pkgbuilds, filepath.Join(dir, splitPkg.Install))
}
}
}
}
@ -113,21 +115,56 @@ func editPkgbuilds(buildDir string, bases []dep.Base, editorConfig,
return nil
}
func Edit(editMenuOption bool, buildDir string, bases []dep.Base, editorConfig,
editorFlags string, installed stringset.StringSet, srcinfos map[string]*gosrc.Srcinfo,
func Edit(w io.Writer, editMenuOption bool, pkgbuildDirs map[string]string, editorConfig,
editorFlags string, installed mapset.Set[string], srcinfos map[string]*gosrc.Srcinfo,
noConfirm bool, editDefaultAnswer string,
) error {
if !editMenuOption {
return nil
}
toEdit, errMenu := selectionMenu(buildDir, bases,
bases := make([]string, 0, len(pkgbuildDirs))
for pkg := range pkgbuildDirs {
bases = append(bases, pkg)
}
toEdit, errMenu := selectionMenu(w, pkgbuildDirs, bases,
installed, gotext.Get("PKGBUILDs to edit?"), noConfirm, editDefaultAnswer, nil)
if errMenu != nil || len(toEdit) == 0 {
return errMenu
}
if errEdit := editPkgbuilds(buildDir, toEdit, editorConfig, editorFlags, srcinfos, noConfirm); errEdit != nil {
if errEdit := editPkgbuilds(pkgbuildDirs, toEdit, editorConfig, editorFlags, srcinfos, noConfirm); errEdit != nil {
return errEdit
}
fmt.Println()
if !text.ContinueTask(os.Stdin, gotext.Get("Proceed with install?"), true, false) {
return settings.ErrUserAbort{}
}
return nil
}
func EditFn(ctx context.Context, config *settings.Configuration, w io.Writer,
pkgbuildDirsByBase map[string]string,
) error {
bases := make([]string, 0, len(pkgbuildDirsByBase))
for pkg := range pkgbuildDirsByBase {
bases = append(bases, pkg)
}
toEdit, errMenu := selectionMenu(w, pkgbuildDirsByBase, bases,
mapset.NewThreadUnsafeSet[string](),
gotext.Get("PKGBUILDs to edit?"), settings.NoConfirm, config.AnswerEdit, nil)
if errMenu != nil || len(toEdit) == 0 {
return errMenu
}
// TOFIX: remove or use srcinfo data
if errEdit := editPkgbuilds(pkgbuildDirsByBase,
toEdit, config.Editor, config.EditorFlags, nil, settings.NoConfirm); errEdit != nil {
return errEdit
}

View File

@ -2,29 +2,27 @@ package menus
import (
"fmt"
"io"
"os"
"path/filepath"
"github.com/leonelquinteros/gotext"
"github.com/Jguer/yay/v11/pkg/dep"
"github.com/Jguer/yay/v11/pkg/intrange"
"github.com/Jguer/yay/v11/pkg/settings"
"github.com/Jguer/yay/v11/pkg/stringset"
"github.com/Jguer/yay/v11/pkg/text"
mapset "github.com/deckarep/golang-set/v2"
)
func pkgbuildNumberMenu(buildDir string, bases []dep.Base, installed stringset.StringSet) {
func pkgbuildNumberMenu(w io.Writer, pkgbuildDirs map[string]string, bases []string, installed mapset.Set[string]) {
toPrint := ""
for n, base := range bases {
pkg := base.Pkgbase()
dir := filepath.Join(buildDir, pkg)
for n, pkgBase := range bases {
dir := pkgbuildDirs[pkgBase]
toPrint += fmt.Sprintf(text.Magenta("%3d")+" %-40s", len(pkgbuildDirs)-n,
text.Bold(pkgBase))
toPrint += fmt.Sprintf(text.Magenta("%3d")+" %-40s", len(bases)-n,
text.Bold(base.String()))
if base.AnyIsInSet(installed) {
if installed.Contains(pkgBase) {
toPrint += text.Bold(text.Green(gotext.Get(" (Installed)")))
}
@ -35,14 +33,15 @@ func pkgbuildNumberMenu(buildDir string, bases []dep.Base, installed stringset.S
toPrint += "\n"
}
fmt.Print(toPrint)
fmt.Fprint(w, toPrint)
}
func selectionMenu(buildDir string, bases []dep.Base, installed stringset.StringSet,
message string, noConfirm bool, defaultAnswer string, skipFunc func(string) bool) ([]dep.Base, error) {
selected := make([]dep.Base, 0)
func selectionMenu(w io.Writer, pkgbuildDirs map[string]string, bases []string, installed mapset.Set[string],
message string, noConfirm bool, defaultAnswer string, skipFunc func(string) bool,
) ([]string, error) {
selected := make([]string, 0)
pkgbuildNumberMenu(buildDir, bases, installed)
pkgbuildNumberMenu(w, pkgbuildDirs, bases, installed)
text.Infoln(message)
text.Infoln(gotext.Get("%s [A]ll [Ab]ort [I]nstalled [No]tInstalled or (1 2 3, 1-3, ^4)", text.Cyan(gotext.Get("[N]one"))))
@ -63,40 +62,38 @@ func selectionMenu(buildDir string, bases []dep.Base, installed stringset.String
return selected, nil
}
for i, base := range bases {
pkg := base.Pkgbase()
if skipFunc != nil && skipFunc(pkg) {
for i, pkgBase := range bases {
if skipFunc != nil && skipFunc(pkgBase) {
continue
}
anyInstalled := base.AnyIsInSet(installed)
anyInstalled := installed.Contains(pkgBase)
if !eIsInclude && eExclude.Get(len(bases)-i) {
continue
}
if anyInstalled && (eOtherInclude.Get("i") || eOtherInclude.Get("installed")) {
selected = append(selected, base)
selected = append(selected, pkgBase)
continue
}
if !anyInstalled && (eOtherInclude.Get("no") || eOtherInclude.Get("notinstalled")) {
selected = append(selected, base)
selected = append(selected, pkgBase)
continue
}
if eOtherInclude.Get("a") || eOtherInclude.Get("all") {
selected = append(selected, base)
selected = append(selected, pkgBase)
continue
}
if eIsInclude && (eInclude.Get(len(bases)-i) || eOtherInclude.Get(pkg)) {
selected = append(selected, base)
if eIsInclude && (eInclude.Get(len(bases)-i) || eOtherInclude.Get(pkgBase)) {
selected = append(selected, pkgBase)
}
if !eIsInclude && (!eExclude.Get(len(bases)-i) && !eOtherExclude.Get(pkg)) {
selected = append(selected, base)
if !eIsInclude && (!eExclude.Get(len(bases)-i) && !eOtherExclude.Get(pkgBase)) {
selected = append(selected, pkgBase)
}
}

View File

@ -3,40 +3,10 @@ package query
import (
"github.com/leonelquinteros/gotext"
"github.com/Jguer/yay/v11/pkg/db"
"github.com/Jguer/yay/v11/pkg/settings/parser"
"github.com/Jguer/yay/v11/pkg/text"
)
// GetPackageNamesBySource returns package names with and without correspondence in SyncDBS respectively.
func GetPackageNamesBySource(dbExecutor db.Executor) (local, remote []string, err error) {
for _, localpkg := range dbExecutor.LocalPackages() {
pkgName := localpkg.Name()
if dbExecutor.SyncPackage(pkgName) != nil {
local = append(local, pkgName)
} else {
remote = append(remote, pkgName)
}
}
return local, remote, err
}
// GetRemotePackages returns packages with no correspondence in SyncDBS.
func GetRemotePackages(dbExecutor db.Executor) (
remote []db.IPackage,
remoteNames []string) {
for _, localpkg := range dbExecutor.LocalPackages() {
pkgName := localpkg.Name()
if dbExecutor.SyncPackage(pkgName) == nil {
remote = append(remote, localpkg)
remoteNames = append(remoteNames, pkgName)
}
}
return remote, remoteNames
}
func RemoveInvalidTargets(targets []string, mode parser.TargetMode) []string {
filteredTargets := make([]string, 0)

View File

@ -4,6 +4,8 @@ import (
"os"
"os/exec"
"strings"
"github.com/Jguer/yay/v11/pkg/text"
)
type Runner interface {
@ -15,10 +17,12 @@ type OSRunner struct{}
func (r *OSRunner) Show(cmd *exec.Cmd) error {
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
text.Debugln("running", cmd.String())
return cmd.Run()
}
func (r *OSRunner) Capture(cmd *exec.Cmd) (stdout, stderr string, err error) {
text.Debugln("capturing", cmd.String())
outbuf, err := cmd.Output()
stdout = strings.TrimSpace(string(outbuf))

View File

@ -11,36 +11,59 @@ import (
"github.com/Jguer/yay/v11/pkg/db"
"github.com/Jguer/yay/v11/pkg/dep"
"github.com/Jguer/yay/v11/pkg/download"
"github.com/Jguer/yay/v11/pkg/menus"
"github.com/Jguer/yay/v11/pkg/settings"
"github.com/Jguer/yay/v11/pkg/settings/exe"
"github.com/Jguer/yay/v11/pkg/text"
gosrc "github.com/Morganamilo/go-srcinfo"
mapset "github.com/deckarep/golang-set/v2"
"github.com/leonelquinteros/gotext"
)
type PostDownloadHookFunc func(ctx context.Context, config *settings.Configuration, w io.Writer, pkgbuildDirsByBase map[string]string) error
type Preparer struct {
dbExecutor db.Executor
cmdBuilder exe.ICmdBuilder
config *settings.Configuration
dbExecutor db.Executor
cmdBuilder exe.ICmdBuilder
config *settings.Configuration
postDownloadHooks []PostDownloadHookFunc
makeDeps []string
}
func NewPreparer(dbExecutor db.Executor, cmdBuilder exe.ICmdBuilder, config *settings.Configuration) *Preparer {
preper := &Preparer{
dbExecutor: dbExecutor,
cmdBuilder: cmdBuilder,
config: config,
postDownloadHooks: []PostDownloadHookFunc{},
}
if config.CleanMenu {
preper.postDownloadHooks = append(preper.postDownloadHooks, menus.CleanFn)
}
if config.DiffMenu {
preper.postDownloadHooks = append(preper.postDownloadHooks, menus.DiffFn)
}
if config.EditMenu {
preper.postDownloadHooks = append(preper.postDownloadHooks, menus.EditFn)
}
return preper
}
func (preper *Preparer) ShouldCleanAURDirs(pkgBuildDirs map[string]string) PostInstallHookFunc {
if !preper.config.CleanAfter {
return nil
}
dirs := make([]string, 0, len(pkgBuildDirs))
for _, dir := range pkgBuildDirs {
dirs = append(dirs, dir)
}
text.Debugln("added post install hook to clean up AUR dirs", dirs)
text.Debugln("added post install hook to clean up AUR dirs", pkgBuildDirs)
return func(ctx context.Context) error {
cleanAfter(ctx, preper.config.Runtime.CmdBuilder, dirs)
cleanAfter(ctx, preper.config.Runtime.CmdBuilder, pkgBuildDirs)
return nil
}
}
@ -109,30 +132,56 @@ func (preper *Preparer) Present(w io.Writer, targets []map[string]*dep.InstallIn
}
func (preper *Preparer) PrepareWorkspace(ctx context.Context, targets []map[string]*dep.InstallInfo) (map[string]string, error) {
aurBases := mapset.NewThreadUnsafeSet[string]()
pkgBuildDirs := make(map[string]string, 0)
aurBasesToClone := mapset.NewThreadUnsafeSet[string]()
pkgBuildDirsByBase := make(map[string]string, len(targets))
for _, layer := range targets {
for pkgName, info := range layer {
for _, info := range layer {
if info.Source == dep.AUR {
pkgBase := *info.AURBase
aurBases.Add(pkgBase)
pkgBuildDirs[pkgName] = filepath.Join(config.BuildDir, pkgBase)
pkgBuildDir := filepath.Join(preper.config.BuildDir, pkgBase)
if preper.needToCloneAURBase(info, pkgBuildDir) {
aurBasesToClone.Add(pkgBase)
}
pkgBuildDirsByBase[pkgBase] = pkgBuildDir
} else if info.Source == dep.SrcInfo {
pkgBuildDirs[pkgName] = *info.SrcinfoPath
pkgBase := *info.AURBase
pkgBuildDirsByBase[pkgBase] = *info.SrcinfoPath
}
}
}
if _, errA := download.AURPKGBUILDRepos(ctx,
preper.cmdBuilder, aurBases.ToSlice(), config.AURURL, config.BuildDir, false); errA != nil {
preper.cmdBuilder, aurBasesToClone.ToSlice(),
config.AURURL, config.BuildDir, false); errA != nil {
return nil, errA
}
if errP := downloadPKGBUILDSourceFanout(ctx, config.Runtime.CmdBuilder,
pkgBuildDirs, false, config.MaxConcurrentDownloads); errP != nil {
pkgBuildDirsByBase, false, config.MaxConcurrentDownloads); errP != nil {
text.Errorln(errP)
}
return pkgBuildDirs, nil
for _, hookFn := range preper.postDownloadHooks {
if err := hookFn(ctx, preper.config, os.Stdout, pkgBuildDirsByBase); err != nil {
return nil, err
}
}
return pkgBuildDirsByBase, nil
}
func (preper *Preparer) needToCloneAURBase(installInfo *dep.InstallInfo, pkgbuildDir string) bool {
if preper.config.ReDownload == "all" {
return true
}
srcinfoFile := filepath.Join(pkgbuildDir, ".SRCINFO")
if pkgbuild, err := gosrc.ParseFile(srcinfoFile); err == nil {
if db.VerCmp(pkgbuild.Version(), installInfo.Version) >= 0 {
return false
}
}
return true
}

View File

@ -73,11 +73,7 @@ func biggestPackages(dbExecutor db.Executor) {
func localStatistics(ctx context.Context, dbExecutor db.Executor) error {
info := statistics(dbExecutor)
_, remoteNames, err := query.GetPackageNamesBySource(dbExecutor)
if err != nil {
return err
}
remoteNames := dbExecutor.InstalledRemotePackageNames()
text.Infoln(gotext.Get("Yay version v%s", yayVersion))
fmt.Println(text.Bold(text.Cyan("===========================================")))
text.Infoln(gotext.Get("Total installed packages: %s", text.Cyan(strconv.Itoa(info.Totaln))))
@ -124,11 +120,8 @@ func printUpdateList(ctx context.Context, cmdArgs *parser.Arguments,
old := os.Stdout // keep backup of the real stdout
os.Stdout = nil
localNames, remoteNames, err := query.GetPackageNamesBySource(dbExecutor)
if err != nil {
os.Stdout = old
return err
}
remoteNames := dbExecutor.InstalledRemotePackageNames()
localNames := dbExecutor.InstalledSyncPackageNames()
aurUp, repoUp, err := upList(ctx, nil, warnings, dbExecutor, enableDowngrade, filter)
os.Stdout = old // restoring the real stdout

10
sync.go
View File

@ -52,11 +52,7 @@ func syncInstall(ctx context.Context,
topoSorted := graph.TopoSortedLayerMap()
preparer := &Preparer{
dbExecutor: dbExecutor,
cmdBuilder: config.Runtime.CmdBuilder,
config: config,
}
preparer := NewPreparer(dbExecutor, config.Runtime.CmdBuilder, config)
installer := &Installer{dbExecutor: dbExecutor}
if errP := preparer.Present(os.Stdout, topoSorted); errP != nil {
@ -73,6 +69,10 @@ func syncInstall(ctx context.Context,
return err
}
if cleanAURDirsFunc := preparer.ShouldCleanAURDirs(pkgBuildDirs); cleanAURDirsFunc != nil {
installer.AddPostInstallHook(cleanAURDirsFunc)
}
err = installer.Install(ctx, cmdArgs, topoSorted, pkgBuildDirs)
if err != nil {
if errHook := installer.RunPostInstallHooks(ctx); errHook != nil {

View File

@ -41,7 +41,8 @@ func upList(ctx context.Context, aurCache *metadata.Client,
warnings *query.AURWarnings, dbExecutor db.Executor, enableDowngrade bool,
filter upgrade.Filter,
) (aurUp, repoUp upgrade.UpSlice, err error) {
remote, remoteNames := query.GetRemotePackages(dbExecutor)
remote := dbExecutor.InstalledRemotePackages()
remoteNames := dbExecutor.InstalledRemotePackageNames()
var (
wg sync.WaitGroup

6
vcs.go
View File

@ -23,11 +23,7 @@ func createDevelDB(ctx context.Context, config *settings.Configuration, dbExecut
wg sync.WaitGroup
)
_, remoteNames, err := query.GetPackageNamesBySource(dbExecutor)
if err != nil {
return err
}
remoteNames := dbExecutor.InstalledRemotePackageNames()
info, err := query.AURInfoPrint(ctx, config.Runtime.AURClient, remoteNames, config.RequestSplitN)
if err != nil {
return err