Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(upgrade): separate menu for pulled along dependencies #2141

Merged
merged 1 commit into from
Apr 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"errors"
"fmt"
"net/http"
"os"
"strings"

alpm "github.com/Jguer/go-alpm/v2"
Expand Down Expand Up @@ -403,9 +402,9 @@ func displayNumberMenu(ctx context.Context, cfg *settings.Configuration, pkgS []
return nil
}

text.Infoln(gotext.Get("Packages to install (eg: 1 2 3, 1-3 or ^4)"))
cfg.Runtime.Logger.Infoln(gotext.Get("Packages to install (eg: 1 2 3, 1-3 or ^4)"))

numberBuf, err := text.GetInput(os.Stdin, "", false)
numberBuf, err := cfg.Runtime.Logger.GetInput("", false)
if err != nil {
return err
}
Expand Down
137 changes: 137 additions & 0 deletions cmd_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package main

import (
"context"
"fmt"
"io"
"os"
"os/exec"
"strings"
"testing"

"github.com/Jguer/aur"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/Jguer/yay/v12/pkg/db/mock"
mockaur "github.com/Jguer/yay/v12/pkg/dep/mock"
"github.com/Jguer/yay/v12/pkg/query"
"github.com/Jguer/yay/v12/pkg/settings"
"github.com/Jguer/yay/v12/pkg/settings/exe"
"github.com/Jguer/yay/v12/pkg/settings/parser"
"github.com/Jguer/yay/v12/pkg/text"
"github.com/Jguer/yay/v12/pkg/vcs"
)

func TestYogurtMenuAURDB(t *testing.T) {
t.Skip("skip until Operation service is an interface")
t.Parallel()
makepkgBin := t.TempDir() + "/makepkg"
pacmanBin := t.TempDir() + "/pacman"
gitBin := t.TempDir() + "/git"
f, err := os.OpenFile(makepkgBin, os.O_RDONLY|os.O_CREATE, 0o755)
require.NoError(t, err)
require.NoError(t, f.Close())

f, err = os.OpenFile(pacmanBin, os.O_RDONLY|os.O_CREATE, 0o755)
require.NoError(t, err)
require.NoError(t, f.Close())

f, err = os.OpenFile(gitBin, os.O_RDONLY|os.O_CREATE, 0o755)
require.NoError(t, err)
require.NoError(t, f.Close())

captureOverride := func(cmd *exec.Cmd) (stdout string, stderr string, err error) {
return "", "", nil
}

showOverride := func(cmd *exec.Cmd) error {
return nil
}

mockRunner := &exe.MockRunner{CaptureFn: captureOverride, ShowFn: showOverride}
cmdBuilder := &exe.CmdBuilder{
MakepkgBin: makepkgBin,
SudoBin: "su",
PacmanBin: pacmanBin,
PacmanConfigPath: "/etc/pacman.conf",
GitBin: "git",
Runner: mockRunner,
SudoLoopEnabled: false,
}

cmdArgs := parser.MakeArguments()
cmdArgs.AddArg("Y")
cmdArgs.AddTarget("yay")

db := &mock.DBExecutor{
AlpmArchitecturesFn: func() ([]string, error) {
return []string{"x86_64"}, nil
},
RefreshHandleFn: func() error {
return nil
},
ReposFn: func() []string {
return []string{"aur"}
},
SyncPackagesFn: func(s ...string) []mock.IPackage {
return []mock.IPackage{
&mock.Package{
PName: "yay",
PBase: "yay",
PVersion: "10.0.0",
PDB: mock.NewDB("aur"),
},
}
},
LocalPackageFn: func(s string) mock.IPackage {
return nil
},
}
aurCache := &mockaur.MockAUR{
GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) {
return []aur.Pkg{
{
Name: "yay",
PackageBase: "yay",
Version: "10.0.0",
},
}, nil
},
}
logger := text.NewLogger(io.Discard, os.Stderr, strings.NewReader("1\n"), true, "test")
cfg := &settings.Configuration{
NewInstallEngine: true,
RemoveMake: "no",
Runtime: &settings.Runtime{
Logger: logger,
CmdBuilder: cmdBuilder,
VCSStore: &vcs.Mock{},
QueryBuilder: query.NewSourceQueryBuilder(aurCache, logger, "votes", parser.ModeAny, "name",
true, false, true),
AURCache: aurCache,
},
}

err = handleCmd(context.Background(), cfg, cmdArgs, db)
require.NoError(t, err)

wantCapture := []string{}
wantShow := []string{
"pacman -S -y --config /etc/pacman.conf --",
"pacman -S -y -u --config /etc/pacman.conf --",
}

require.Len(t, mockRunner.ShowCalls, len(wantShow))
require.Len(t, mockRunner.CaptureCalls, len(wantCapture))

for i, call := range mockRunner.ShowCalls {
show := call.Args[0].(*exec.Cmd).String()
show = strings.ReplaceAll(show, makepkgBin, "makepkg")
show = strings.ReplaceAll(show, pacmanBin, "pacman")
show = strings.ReplaceAll(show, gitBin, "pacman")

// options are in a different order on different systems and on CI root user is used
assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), fmt.Sprintf("%d - %s", i, show))
}
}
4 changes: 4 additions & 0 deletions pkg/db/mock/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type DBExecutor struct {
RefreshHandleFn func() error
ReposFn func() []string
SyncPackageFn func(string) IPackage
SyncPackagesFn func(...string) []IPackage
SyncSatisfierFn func(string) IPackage
SyncUpgradesFn func(bool) (map[string]db.SyncUpgrade, error)
}
Expand Down Expand Up @@ -170,6 +171,9 @@ func (t *DBExecutor) SyncPackage(s string) IPackage {
}

func (t *DBExecutor) SyncPackages(s ...string) []IPackage {
if t.SyncPackagesFn != nil {
return t.SyncPackagesFn(s...)
}
panic("implement me")
}

Expand Down
12 changes: 6 additions & 6 deletions pkg/query/query_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,12 +211,12 @@ func (s *SourceQueryBuilder) Results(dbExecutor db.Executor, verboseSearch Searc
}

pkg := s.queryMap[s.results[i].source][s.results[i].name]
if s.results[i].source == sourceAUR {
aurPkg := pkg.(aur.Pkg)
toPrint += aurPkgSearchString(&aurPkg, dbExecutor, s.singleLineResults)
} else {
syncPkg := pkg.(alpm.IPackage)
toPrint += syncPkgSearchString(syncPkg, dbExecutor, s.singleLineResults)

switch pPkg := pkg.(type) {
case aur.Pkg:
toPrint += aurPkgSearchString(&pPkg, dbExecutor, s.singleLineResults)
case alpm.IPackage:
toPrint += syncPkgSearchString(pPkg, dbExecutor, s.singleLineResults)
}

s.logger.Println(toPrint)
Expand Down
2 changes: 2 additions & 0 deletions pkg/settings/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"net/http"
"os"
"path/filepath"
"time"

"github.com/leonelquinteros/gotext"

Expand Down Expand Up @@ -68,6 +69,7 @@ func BuildRuntime(cfg *Configuration, cmdArgs *parser.Arguments, version string)
metadata.WithCacheFilePath(filepath.Join(cfg.BuildDir, "aur.json")),
metadata.WithRequestEditorFn(userAgentFn),
metadata.WithBaseURL(cfg.AURURL),
metadata.WithCustomCacheValidity(100000*time.Hour),
metadata.WithDebugLogger(logger.Debugln),
)
if errAURCache != nil {
Expand Down
40 changes: 29 additions & 11 deletions pkg/upgrade/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,21 +262,43 @@ func (u *UpgradeService) GraphUpgrades(ctx context.Context,
// userExcludeUpgrades asks the user which packages to exclude from the upgrade and
// removes them from the graph
func (u *UpgradeService) UserExcludeUpgrades(graph *topo.Graph[string, *dep.InstallInfo]) ([]string, error) {
allUpLen := graph.Len()
if allUpLen == 0 {
if graph.Len() == 0 {
return []string{}, nil
}
aurUp, repoUp := u.graphToUpSlice(graph)

sort.Sort(repoUp)
sort.Sort(aurUp)

allUp := UpSlice{Up: append(repoUp.Up, aurUp.Up...), Repos: append(repoUp.Repos, aurUp.Repos...)}
allUp := UpSlice{Repos: append(repoUp.Repos, aurUp.Repos...)}
for _, up := range repoUp.Up {
if up.LocalVersion == "" && up.Reason != alpm.PkgReasonExplicit {
allUp.PulledDeps = append(allUp.PulledDeps, up)
} else {
allUp.Up = append(allUp.Up, up)
}
}

for _, up := range aurUp.Up {
if up.LocalVersion == "" && up.Reason != alpm.PkgReasonExplicit {
allUp.PulledDeps = append(allUp.PulledDeps, up)
} else {
allUp.Up = append(allUp.Up, up)
}
}

if len(allUp.PulledDeps) > 0 {
u.log.Printf("%s"+text.Bold(" %d ")+"%s\n", text.Bold(text.Cyan("::")),
len(allUp.PulledDeps), text.Bold(gotext.Get("%s will also be installed for this operation",
gotext.GetN("dependency", "dependencies", len(allUp.PulledDeps)))))
allUp.PrintDeps(u.log)
}

u.log.Printf("%s"+text.Bold(" %d ")+"%s\n", text.Bold(text.Cyan("::")), allUpLen, text.Bold(gotext.Get("Packages to upgrade/install.")))
u.log.Printf("%s"+text.Bold(" %d ")+"%s\n", text.Bold(text.Cyan("::")),
len(allUp.Up), text.Bold(gotext.Get("%s to upgrade/install.", gotext.GetN("package", "packages", len(allUp.Up)))))
allUp.Print(u.log)

u.log.Infoln(gotext.Get("Packages to exclude: (eg: \"1 2 3\", \"1-3\", \"^4\" or repo name)"))
u.log.Infoln(gotext.Get("%s to exclude: (eg: \"1 2 3\", \"1-3\", \"^4\" or repo name)", gotext.GetN("package", "packages", len(allUp.Up))))
u.log.Warnln(gotext.Get("Excluding packages may cause partial upgrades and break systems"))

numbers, err := u.log.GetInput(u.cfg.AnswerUpgrade, settings.NoConfirm)
Expand All @@ -292,24 +314,20 @@ func (u *UpgradeService) UserExcludeUpgrades(graph *topo.Graph[string, *dep.Inst
excluded := make([]string, 0)
for i := range allUp.Up {
up := &allUp.Up[i]
// choices do not apply to non-installed packages
if up.LocalVersion == "" {
continue
}

if isInclude && otherExclude.Get(up.Repository) {
u.log.Debugln("pruning", up.Name)
excluded = append(excluded, graph.Prune(up.Name)...)
continue
}

if isInclude && exclude.Get(allUpLen-i) {
if isInclude && exclude.Get(len(allUp.Up)-i) {
u.log.Debugln("pruning", up.Name)
excluded = append(excluded, graph.Prune(up.Name)...)
continue
}

if !isInclude && !(include.Get(allUpLen-i) || otherInclude.Get(up.Repository)) {
if !isInclude && !(include.Get(len(allUp.Up)-i) || otherInclude.Get(up.Repository)) {
u.log.Debugln("pruning", up.Name)
excluded = append(excluded, graph.Prune(up.Name)...)
continue
Expand Down
14 changes: 5 additions & 9 deletions pkg/upgrade/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ func TestUpgradeService_GraphUpgrades(t *testing.T) {
{
name: "exclude linux",
fields: fields{
input: strings.NewReader("4\n"),
input: strings.NewReader("3\n"),
output: io.Discard,
noConfirm: false,
},
Expand All @@ -301,7 +301,7 @@ func TestUpgradeService_GraphUpgrades(t *testing.T) {
{
name: "only linux",
fields: fields{
input: strings.NewReader("^4\n"),
input: strings.NewReader("^3\n"),
output: io.Discard,
noConfirm: false,
},
Expand Down Expand Up @@ -642,7 +642,6 @@ func TestUpgradeService_GraphUpgrades_zfs_dkms(t *testing.T) {
}
type fields struct {
input io.Reader
output io.Writer
noConfirm bool
devel bool
}
Expand All @@ -664,7 +663,6 @@ func TestUpgradeService_GraphUpgrades_zfs_dkms(t *testing.T) {
name: "no input",
fields: fields{
input: strings.NewReader("\n"),
output: io.Discard,
noConfirm: false,
},
args: args{
Expand All @@ -684,7 +682,6 @@ func TestUpgradeService_GraphUpgrades_zfs_dkms(t *testing.T) {
name: "no input - inverted order",
fields: fields{
input: strings.NewReader("\n"),
output: io.Discard,
noConfirm: false,
},
args: args{
Expand Down Expand Up @@ -742,16 +739,15 @@ func TestUpgradeService_GraphUpgrades_zfs_dkms(t *testing.T) {
ReposFn: func() []string { return []string{"core"} },
}

logger := text.NewLogger(io.Discard, os.Stderr,
tt.fields.input, true, "test")
grapher := dep.NewGrapher(dbExe, mockAUR,
false, true, false, false, false, text.NewLogger(tt.fields.output, os.Stderr,
tt.fields.input, true, "test"))
false, true, false, false, false, logger)

cfg := &settings.Configuration{
Devel: tt.fields.devel, Mode: parser.ModeAny,
}

logger := text.NewLogger(tt.fields.output, os.Stderr,
tt.fields.input, true, "test")
u := &UpgradeService{
log: logger,
grapher: grapher,
Expand Down
36 changes: 34 additions & 2 deletions pkg/upgrade/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ func StylizedNameWithRepository(u *Upgrade) string {

// upSlice is a slice of Upgrades.
type UpSlice struct {
Up []Upgrade
Repos []string
Up []Upgrade
Repos []string
PulledDeps []Upgrade
}

func (u UpSlice) Len() int { return len(u.Up) }
Expand Down Expand Up @@ -84,3 +85,34 @@ func (u UpSlice) Print(logger *text.Logger) {
}
}
}

func (u UpSlice) PrintDeps(logger *text.Logger) {
longestName, longestVersion := 0, 0

for k := range u.PulledDeps {
upgrade := &u.PulledDeps[k]
packNameLen := len(StylizedNameWithRepository(upgrade))
packVersion, _ := query.GetVersionDiff(upgrade.LocalVersion, upgrade.RemoteVersion)
packVersionLen := len(packVersion)
longestName = intrange.Max(packNameLen, longestName)
longestVersion = intrange.Max(packVersionLen, longestVersion)
}

lenUp := len(u.PulledDeps)
longestNumber := len(fmt.Sprintf("%v", lenUp))
namePadding := fmt.Sprintf(" %s%%-%ds ", strings.Repeat(" ", longestNumber), longestName)
versionPadding := fmt.Sprintf("%%-%ds", longestVersion)

for k := range u.PulledDeps {
upgrade := &u.PulledDeps[k]
left, right := query.GetVersionDiff(upgrade.LocalVersion, upgrade.RemoteVersion)

logger.Printf(namePadding, StylizedNameWithRepository(upgrade))
logger.Printf("%s -> %s\n", fmt.Sprintf(versionPadding, left), right)
if upgrade.Extra != "" {
logger.Println(strings.Repeat(" ", longestNumber), strings.ToLower(upgrade.Extra))
}
}

logger.Println()
}
Loading