mirror of
https://github.com/Jguer/yay
synced 2024-10-01 13:53:32 +00:00
feat(new_install): show (#1915)
* show new packages in upgrade form if they exist * refactor up select * remove unused graph parts * readd len * Complete upgrade graphing * Extract to upgrade pkg * remove unused dep method * remove uneeded dep * cleanup method * specify io Reader for testing * use specified input vector * fix non-active devel * test base cases * add devel test cases * add range tests * add logger struct * use logger struct in upgrade * follow golangci recommendations * update deps * update golangci
This commit is contained in:
parent
4f50b799ef
commit
0bf4c2e502
|
@ -8,5 +8,5 @@ COPY go.mod .
|
|||
RUN pacman-key --init && pacman -Sy && pacman -S --overwrite=* --noconfirm archlinux-keyring && \
|
||||
pacman -Su --overwrite=* --needed --noconfirm doxygen meson asciidoc go git gcc make sudo base-devel && \
|
||||
rm -rfv /var/cache/pacman/* /var/lib/pacman/sync/* && \
|
||||
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.50.1 && \
|
||||
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.51.1 && \
|
||||
go mod download
|
||||
|
|
8
cmd.go
8
cmd.go
|
@ -205,16 +205,16 @@ func getFilter(cmdArgs *parser.Arguments) (upgrade.Filter, error) {
|
|||
case deps && explicit:
|
||||
return nil, errors.New(gotext.Get("invalid option: '--deps' and '--explicit' may not be used together"))
|
||||
case deps:
|
||||
return func(pkg upgrade.Upgrade) bool {
|
||||
return func(pkg *upgrade.Upgrade) bool {
|
||||
return pkg.Reason == alpm.PkgReasonDepend
|
||||
}, nil
|
||||
case explicit:
|
||||
return func(pkg upgrade.Upgrade) bool {
|
||||
return func(pkg *upgrade.Upgrade) bool {
|
||||
return pkg.Reason == alpm.PkgReasonExplicit
|
||||
}, nil
|
||||
}
|
||||
|
||||
return func(pkg upgrade.Upgrade) bool {
|
||||
return func(pkg *upgrade.Upgrade) bool {
|
||||
return true
|
||||
}, nil
|
||||
}
|
||||
|
@ -406,7 +406,7 @@ func displayNumberMenu(ctx context.Context, pkgS []string, dbExecutor db.Executo
|
|||
|
||||
text.Infoln(gotext.Get("Packages to install (eg: 1 2 3, 1-3 or ^4)"))
|
||||
|
||||
numberBuf, err := text.GetInput("", false)
|
||||
numberBuf, err := text.GetInput(os.Stdin, "", false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
8
go.mod
8
go.mod
|
@ -9,9 +9,9 @@ require (
|
|||
github.com/bradleyjkemp/cupaloy v2.3.0+incompatible
|
||||
github.com/leonelquinteros/gotext v1.5.1
|
||||
github.com/stretchr/testify v1.8.1
|
||||
golang.org/x/sys v0.3.0
|
||||
golang.org/x/term v0.3.0
|
||||
golang.org/x/text v0.5.0 // indirect
|
||||
golang.org/x/sys v0.5.0
|
||||
golang.org/x/term v0.5.0
|
||||
golang.org/x/text v0.7.0 // indirect
|
||||
gopkg.in/h2non/gock.v1 v1.1.2
|
||||
)
|
||||
|
||||
|
@ -28,7 +28,7 @@ require (
|
|||
github.com/deckarep/golang-set/v2 v2.1.0
|
||||
github.com/itchyny/gojq v0.12.11 // indirect
|
||||
github.com/itchyny/timefmt-go v0.1.5 // indirect
|
||||
github.com/ohler55/ojg v1.15.0 // indirect
|
||||
github.com/ohler55/ojg v1.17.4 // indirect
|
||||
)
|
||||
|
||||
go 1.19
|
||||
|
|
8
go.sum
8
go.sum
|
@ -31,6 +31,8 @@ github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy
|
|||
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
|
||||
github.com/ohler55/ojg v1.15.0 h1:Z95FvBiMsMOOGP9Nzv5OVV4ND2KnEMxk0GOS8Kvcahg=
|
||||
github.com/ohler55/ojg v1.15.0/go.mod h1:7Ghirupn8NC8hSSDpI0gcjorPxj+vSVIONDWfliHR1k=
|
||||
github.com/ohler55/ojg v1.17.4 h1:6Ss87DyAZHU0ODZu6Cmuahj5UiVaRD1n8C4KNm0qMYg=
|
||||
github.com/ohler55/ojg v1.17.4/go.mod h1:7Ghirupn8NC8hSSDpI0gcjorPxj+vSVIONDWfliHR1k=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
|
@ -62,15 +64,21 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI=
|
||||
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
|
||||
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
|
||||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||
|
|
|
@ -72,8 +72,6 @@ func graphPackage(
|
|||
}
|
||||
|
||||
fmt.Fprintln(os.Stdout, graph.String())
|
||||
fmt.Fprintln(os.Stdout, "\nlayers\n", graph.TopoSortedLayers())
|
||||
fmt.Fprintln(os.Stdout, "\ninverted order\n", graph.TopoSorted())
|
||||
fmt.Fprintln(os.Stdout, "\nlayers map\n", graph.TopoSortedLayerMap(nil))
|
||||
|
||||
return nil
|
||||
|
|
|
@ -26,6 +26,12 @@ type Upgrade struct {
|
|||
Reason alpm.PkgReason
|
||||
}
|
||||
|
||||
type SyncUpgrade struct {
|
||||
Package alpm.IPackage
|
||||
LocalVersion string
|
||||
Reason alpm.PkgReason
|
||||
}
|
||||
|
||||
type Executor interface {
|
||||
AlpmArchitectures() ([]string, error)
|
||||
BiggestPackages() []IPackage
|
||||
|
@ -45,7 +51,8 @@ type Executor interface {
|
|||
PackageProvides(IPackage) []Depend
|
||||
PackagesFromGroup(string) []IPackage
|
||||
RefreshHandle() error
|
||||
RepoUpgrades(bool) ([]Upgrade, error)
|
||||
SyncUpgrades(enableDowngrade bool) (
|
||||
map[string]SyncUpgrade, error)
|
||||
Repos() []string
|
||||
SatisfierFromDB(string, string) IPackage
|
||||
SyncPackage(string) IPackage
|
||||
|
|
|
@ -14,7 +14,6 @@ import (
|
|||
"github.com/Jguer/yay/v11/pkg/db"
|
||||
"github.com/Jguer/yay/v11/pkg/settings"
|
||||
"github.com/Jguer/yay/v11/pkg/text"
|
||||
"github.com/Jguer/yay/v11/pkg/upgrade"
|
||||
)
|
||||
|
||||
type AlpmExecutor struct {
|
||||
|
@ -204,7 +203,7 @@ func (ae *AlpmExecutor) questionCallback() func(question alpm.QuestionAny) {
|
|||
break
|
||||
}
|
||||
|
||||
numberBuf, err := text.GetInput("", false)
|
||||
numberBuf, err := text.GetInput(os.Stdin, "", false)
|
||||
if err != nil {
|
||||
text.Errorln(err)
|
||||
break
|
||||
|
@ -407,18 +406,19 @@ func (ae *AlpmExecutor) PackageGroups(pkg alpm.IPackage) []string {
|
|||
|
||||
// upRepo gathers local packages and checks if they have new versions.
|
||||
// Output: Upgrade type package list.
|
||||
func (ae *AlpmExecutor) RepoUpgrades(enableDowngrade bool) ([]db.Upgrade, error) {
|
||||
func (ae *AlpmExecutor) SyncUpgrades(enableDowngrade bool) (
|
||||
map[string]db.SyncUpgrade, error,
|
||||
) {
|
||||
ups := map[string]db.SyncUpgrade{}
|
||||
var errReturn error
|
||||
|
||||
slice := []db.Upgrade{}
|
||||
|
||||
localDB, errDB := ae.handle.LocalDB()
|
||||
if errDB != nil {
|
||||
return slice, errDB
|
||||
return ups, errDB
|
||||
}
|
||||
|
||||
if err := ae.handle.TransInit(alpm.TransFlagNoLock); err != nil {
|
||||
return slice, err
|
||||
return ups, err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
|
@ -426,7 +426,7 @@ func (ae *AlpmExecutor) RepoUpgrades(enableDowngrade bool) ([]db.Upgrade, error)
|
|||
}()
|
||||
|
||||
if err := ae.handle.SyncSysupgrade(enableDowngrade); err != nil {
|
||||
return slice, err
|
||||
return ups, err
|
||||
}
|
||||
|
||||
_ = ae.handle.TransGetAdd().ForEach(func(pkg alpm.IPackage) error {
|
||||
|
@ -438,18 +438,16 @@ func (ae *AlpmExecutor) RepoUpgrades(enableDowngrade bool) ([]db.Upgrade, error)
|
|||
reason = localPkg.Reason()
|
||||
}
|
||||
|
||||
slice = append(slice, upgrade.Upgrade{
|
||||
Name: pkg.Name(),
|
||||
Base: pkg.Base(),
|
||||
Repository: pkg.DB().Name(),
|
||||
LocalVersion: localVer,
|
||||
RemoteVersion: pkg.Version(),
|
||||
Reason: reason,
|
||||
})
|
||||
ups[pkg.Name()] = db.SyncUpgrade{
|
||||
Package: pkg,
|
||||
Reason: reason,
|
||||
LocalVersion: localVer,
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return slice, errReturn
|
||||
return ups, errReturn
|
||||
}
|
||||
|
||||
func (ae *AlpmExecutor) BiggestPackages() []alpm.IPackage {
|
||||
|
|
|
@ -16,12 +16,30 @@ type (
|
|||
|
||||
type DBExecutor struct {
|
||||
db.Executor
|
||||
IsCorrectVersionInstalledFn func(string, string) bool
|
||||
SyncPackageFn func(string) IPackage
|
||||
PackagesFromGroupFn func(string) []IPackage
|
||||
LocalSatisfierExistsFn func(string) bool
|
||||
SyncSatisfierFn func(string) IPackage
|
||||
AlpmArchitecturesFn func() ([]string, error)
|
||||
IsCorrectVersionInstalledFn func(string, string) bool
|
||||
SyncPackageFn func(string) IPackage
|
||||
PackagesFromGroupFn func(string) []IPackage
|
||||
LocalSatisfierExistsFn func(string) bool
|
||||
SyncSatisfierFn func(string) IPackage
|
||||
AlpmArchitecturesFn func() ([]string, error)
|
||||
InstalledRemotePackageNamesFn func() []string
|
||||
InstalledRemotePackagesFn func() map[string]IPackage
|
||||
SyncUpgradesFn func(bool) (map[string]db.SyncUpgrade, error)
|
||||
ReposFn func() []string
|
||||
}
|
||||
|
||||
func (t *DBExecutor) InstalledRemotePackageNames() []string {
|
||||
if t.InstalledRemotePackageNamesFn != nil {
|
||||
return t.InstalledRemotePackageNamesFn()
|
||||
}
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (t *DBExecutor) InstalledRemotePackages() map[string]IPackage {
|
||||
if t.InstalledRemotePackagesFn != nil {
|
||||
return t.InstalledRemotePackagesFn()
|
||||
}
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (t *DBExecutor) AlpmArchitectures() ([]string, error) {
|
||||
|
@ -93,40 +111,46 @@ func (t *DBExecutor) PackagesFromGroup(s string) []IPackage {
|
|||
panic("implement me")
|
||||
}
|
||||
|
||||
func (t DBExecutor) RefreshHandle() error {
|
||||
func (t *DBExecutor) RefreshHandle() error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (t DBExecutor) RepoUpgrades(b bool) ([]Upgrade, error) {
|
||||
func (t *DBExecutor) SyncUpgrades(b bool) (map[string]db.SyncUpgrade, error) {
|
||||
if t.SyncUpgradesFn != nil {
|
||||
return t.SyncUpgradesFn(b)
|
||||
}
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (t DBExecutor) Repos() []string {
|
||||
func (t *DBExecutor) Repos() []string {
|
||||
if t.ReposFn != nil {
|
||||
return t.ReposFn()
|
||||
}
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (t DBExecutor) SatisfierFromDB(s, s2 string) IPackage {
|
||||
func (t *DBExecutor) SatisfierFromDB(s, s2 string) IPackage {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (t DBExecutor) SyncPackage(s string) IPackage {
|
||||
func (t *DBExecutor) SyncPackage(s string) IPackage {
|
||||
if t.SyncPackageFn != nil {
|
||||
return t.SyncPackageFn(s)
|
||||
}
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (t DBExecutor) SyncPackages(s ...string) []IPackage {
|
||||
func (t *DBExecutor) SyncPackages(s ...string) []IPackage {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (t DBExecutor) SyncSatisfier(s string) IPackage {
|
||||
func (t *DBExecutor) SyncSatisfier(s string) IPackage {
|
||||
if t.SyncSatisfierFn != nil {
|
||||
return t.SyncSatisfierFn(s)
|
||||
}
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (t DBExecutor) SyncSatisfierExists(s string) bool {
|
||||
func (t *DBExecutor) SyncSatisfierExists(s string) bool {
|
||||
panic("implement me")
|
||||
}
|
||||
|
|
|
@ -516,7 +516,7 @@ func providerMenu(dep string, providers providers, noConfirm bool) *query.Pkg {
|
|||
return providers.Pkgs[0]
|
||||
}
|
||||
|
||||
numberBuf, err := text.GetInput("", false)
|
||||
numberBuf, err := text.GetInput(os.Stdin, "", false)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
|
||||
|
|
|
@ -21,12 +21,16 @@ import (
|
|||
)
|
||||
|
||||
type InstallInfo struct {
|
||||
Source Source
|
||||
Reason Reason
|
||||
Version string
|
||||
SrcinfoPath *string
|
||||
AURBase *string
|
||||
SyncDBName *string
|
||||
Source Source
|
||||
Reason Reason
|
||||
Version string
|
||||
LocalVersion string
|
||||
SrcinfoPath *string
|
||||
AURBase *string
|
||||
SyncDBName *string
|
||||
|
||||
Upgrade bool
|
||||
Devel bool
|
||||
}
|
||||
|
||||
func (i *InstallInfo) String() string {
|
||||
|
@ -150,6 +154,13 @@ func (g *Grapher) GraphFromTargets(ctx context.Context,
|
|||
},
|
||||
})
|
||||
|
||||
g.GraphSyncPkg(ctx, graph, pkg, &InstallInfo{
|
||||
Source: Sync,
|
||||
Reason: Explicit,
|
||||
Version: pkg.Version(),
|
||||
SyncDBName: &dbName,
|
||||
})
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -205,7 +216,7 @@ func (g *Grapher) pickSrcInfoPkgs(pkgs []aurc.Pkg) ([]aurc.Pkg, error) {
|
|||
}
|
||||
text.Infoln(gotext.Get("Packages to exclude") + " (eg: \"1 2 3\", \"1-3\", \"^4\"):")
|
||||
|
||||
numberBuf, err := text.GetInput("", g.noConfirm)
|
||||
numberBuf, err := text.GetInput(os.Stdin, "", g.noConfirm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -284,6 +295,44 @@ func (g *Grapher) addDepNodes(ctx context.Context, pkg *aur.Pkg, graph *topo.Gra
|
|||
}
|
||||
}
|
||||
|
||||
func (g *Grapher) GraphSyncPkg(ctx context.Context,
|
||||
graph *topo.Graph[string, *InstallInfo],
|
||||
pkg alpm.IPackage, instalInfo *InstallInfo,
|
||||
) *topo.Graph[string, *InstallInfo] {
|
||||
if graph == nil {
|
||||
graph = topo.New[string, *InstallInfo]()
|
||||
}
|
||||
|
||||
graph.AddNode(pkg.Name())
|
||||
g.ValidateAndSetNodeInfo(graph, pkg.Name(), &topo.NodeInfo[*InstallInfo]{
|
||||
Color: colorMap[Explicit],
|
||||
Background: bgColorMap[Sync],
|
||||
Value: instalInfo,
|
||||
})
|
||||
|
||||
return graph
|
||||
}
|
||||
|
||||
func (g *Grapher) GraphAURTarget(ctx context.Context,
|
||||
graph *topo.Graph[string, *InstallInfo],
|
||||
pkg *aurc.Pkg, instalInfo *InstallInfo,
|
||||
) *topo.Graph[string, *InstallInfo] {
|
||||
if graph == nil {
|
||||
graph = topo.New[string, *InstallInfo]()
|
||||
}
|
||||
|
||||
graph.AddNode(pkg.Name)
|
||||
g.ValidateAndSetNodeInfo(graph, pkg.Name, &topo.NodeInfo[*InstallInfo]{
|
||||
Color: colorMap[Explicit],
|
||||
Background: bgColorMap[AUR],
|
||||
Value: instalInfo,
|
||||
})
|
||||
|
||||
g.addDepNodes(ctx, pkg, graph)
|
||||
|
||||
return graph
|
||||
}
|
||||
|
||||
func (g *Grapher) GraphFromAURCache(ctx context.Context,
|
||||
graph *topo.Graph[string, *InstallInfo],
|
||||
targets []string,
|
||||
|
@ -302,19 +351,12 @@ func (g *Grapher) GraphFromAURCache(ctx context.Context,
|
|||
|
||||
pkg := provideMenu(g.w, target, aurPkgs, g.noConfirm)
|
||||
|
||||
graph.AddNode(pkg.Name)
|
||||
g.ValidateAndSetNodeInfo(graph, pkg.Name, &topo.NodeInfo[*InstallInfo]{
|
||||
Color: colorMap[Explicit],
|
||||
Background: bgColorMap[AUR],
|
||||
Value: &InstallInfo{
|
||||
Source: AUR,
|
||||
Reason: Explicit,
|
||||
AURBase: &pkg.PackageBase,
|
||||
Version: pkg.Version,
|
||||
},
|
||||
graph = g.GraphAURTarget(ctx, graph, pkg, &InstallInfo{
|
||||
AURBase: &pkg.PackageBase,
|
||||
Reason: Explicit,
|
||||
Source: AUR,
|
||||
Version: pkg.Version,
|
||||
})
|
||||
|
||||
g.addDepNodes(ctx, pkg, graph)
|
||||
}
|
||||
|
||||
return graph, nil
|
||||
|
@ -486,7 +528,7 @@ func provideMenu(w io.Writer, dep string, options []aur.Pkg, noConfirm bool) *au
|
|||
return &options[0]
|
||||
}
|
||||
|
||||
numberBuf, err := text.GetInput("", false)
|
||||
numberBuf, err := text.GetInput(os.Stdin, "", false)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
|
||||
|
@ -576,28 +618,3 @@ func archStringToString(alpmArches []string, archString []gosrc.ArchString) []st
|
|||
|
||||
return pkgs
|
||||
}
|
||||
|
||||
func AddUpgradeToGraph(pkg *db.Upgrade, graph *topo.Graph[string, *InstallInfo]) {
|
||||
source := Sync
|
||||
if pkg.Repository == "aur" || pkg.Repository == "devel" {
|
||||
source = AUR
|
||||
}
|
||||
|
||||
reason := Explicit
|
||||
if pkg.Reason == alpm.PkgReasonDepend {
|
||||
reason = Dep
|
||||
}
|
||||
|
||||
graph.AddNode(pkg.Name)
|
||||
graph.SetNodeInfo(pkg.Name, &topo.NodeInfo[*InstallInfo]{
|
||||
Color: colorMap[reason],
|
||||
Background: bgColorMap[source],
|
||||
Value: &InstallInfo{
|
||||
Source: source,
|
||||
Reason: reason,
|
||||
Version: pkg.RemoteVersion,
|
||||
AURBase: &pkg.Base,
|
||||
SyncDBName: &pkg.Repository,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ func editor(editorConfig, editorFlags string, noConfirm bool) (editor string, ar
|
|||
for {
|
||||
text.Infoln(gotext.Get("Edit PKGBUILD with?"))
|
||||
|
||||
editorInput, err := text.GetInput("", noConfirm)
|
||||
editorInput, err := text.GetInput(os.Stdin, "", noConfirm)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
continue
|
||||
|
|
|
@ -46,7 +46,7 @@ func selectionMenu(w io.Writer, pkgbuildDirs map[string]string, bases []string,
|
|||
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"))))
|
||||
|
||||
selectInput, err := text.GetInput(defaultAnswer, noConfirm)
|
||||
selectInput, err := text.GetInput(os.Stdin, defaultAnswer, noConfirm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -41,9 +41,7 @@ func AURInfo(ctx context.Context, aurClient aur.ClientInterface, names []string,
|
|||
}
|
||||
|
||||
mux.Lock()
|
||||
for i := range tempInfo {
|
||||
info = append(info, tempInfo[i])
|
||||
}
|
||||
info = append(info, tempInfo...)
|
||||
mux.Unlock()
|
||||
}
|
||||
|
||||
|
|
|
@ -215,9 +215,7 @@ func queryAUR(ctx context.Context,
|
|||
Contains: true,
|
||||
})
|
||||
|
||||
for i := range q {
|
||||
r = append(r, q[i])
|
||||
}
|
||||
r = append(r, q...)
|
||||
|
||||
if errM == nil {
|
||||
return r, nil
|
||||
|
|
|
@ -295,6 +295,7 @@ func NewConfig(version string) (*Configuration, error) {
|
|||
AURClient: nil,
|
||||
VoteClient: voteClient,
|
||||
QueryBuilder: nil,
|
||||
Logger: text.NewLogger(os.Stdout, os.Stdin, newConfig.Debug, "runtime"),
|
||||
}
|
||||
|
||||
var errAURCache error
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/Jguer/yay/v11/pkg/query"
|
||||
"github.com/Jguer/yay/v11/pkg/settings/exe"
|
||||
"github.com/Jguer/yay/v11/pkg/settings/parser"
|
||||
"github.com/Jguer/yay/v11/pkg/text"
|
||||
"github.com/Jguer/yay/v11/pkg/vcs"
|
||||
|
||||
"github.com/Jguer/aur"
|
||||
|
@ -35,4 +36,5 @@ type Runtime struct {
|
|||
VoteClient *vote.Client
|
||||
AURCache AURCache
|
||||
DBExecutor db.Executor
|
||||
Logger *text.Logger
|
||||
}
|
||||
|
|
|
@ -3,10 +3,10 @@ package text
|
|||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"io"
|
||||
)
|
||||
|
||||
func GetInput(defaultValue string, noConfirm bool) (string, error) {
|
||||
func (l *Logger) GetInput(defaultValue string, noConfirm bool) (string, error) {
|
||||
Info()
|
||||
|
||||
if defaultValue != "" || noConfirm {
|
||||
|
@ -14,7 +14,7 @@ func GetInput(defaultValue string, noConfirm bool) (string, error) {
|
|||
return defaultValue, nil
|
||||
}
|
||||
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
reader := bufio.NewReader(l.r)
|
||||
|
||||
buf, overflow, err := reader.ReadLine()
|
||||
if err != nil {
|
||||
|
@ -27,3 +27,7 @@ func GetInput(defaultValue string, noConfirm bool) (string, error) {
|
|||
|
||||
return string(buf), nil
|
||||
}
|
||||
|
||||
func GetInput(r io.Reader, defaultValue string, noConfirm bool) (string, error) {
|
||||
return globalLogger.GetInput(defaultValue, noConfirm)
|
||||
}
|
||||
|
|
|
@ -21,61 +21,55 @@ const (
|
|||
var (
|
||||
cachedColumnCount = -1
|
||||
DebugMode = false
|
||||
globalLogger = NewLogger(os.Stdout, os.Stdin, DebugMode, "global")
|
||||
)
|
||||
|
||||
func Debugln(a ...interface{}) {
|
||||
if !DebugMode {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Fprintln(os.Stdout, append([]interface{}{Bold(yellow("[DEBUG]"))}, a...)...)
|
||||
fmt.Fprint(os.Stdout, ResetCode)
|
||||
globalLogger.Debugln(a...)
|
||||
}
|
||||
|
||||
func OperationInfoln(a ...interface{}) {
|
||||
fmt.Fprint(os.Stdout, append([]interface{}{Bold(Cyan(opSymbol + " ")), boldCode}, a...)...)
|
||||
fmt.Fprintln(os.Stdout, ResetCode)
|
||||
globalLogger.OperationInfoln(a...)
|
||||
}
|
||||
|
||||
func OperationInfo(a ...interface{}) {
|
||||
fmt.Fprint(os.Stdout, append([]interface{}{Bold(Cyan(opSymbol + " ")), boldCode}, a...)...)
|
||||
fmt.Fprint(os.Stdout, ResetCode)
|
||||
globalLogger.OperationInfo(a...)
|
||||
}
|
||||
|
||||
func SprintOperationInfo(a ...interface{}) string {
|
||||
return fmt.Sprint(append([]interface{}{Bold(Cyan(opSymbol + " ")), boldCode}, a...)...) + ResetCode
|
||||
return globalLogger.SprintOperationInfo(a...)
|
||||
}
|
||||
|
||||
func Info(a ...interface{}) {
|
||||
fmt.Fprint(os.Stdout, append([]interface{}{Bold(Green(arrow + " "))}, a...)...)
|
||||
globalLogger.Info(a...)
|
||||
}
|
||||
|
||||
func Infoln(a ...interface{}) {
|
||||
fmt.Fprintln(os.Stdout, append([]interface{}{Bold(Green(arrow))}, a...)...)
|
||||
globalLogger.Infoln(a...)
|
||||
}
|
||||
|
||||
func SprintWarn(a ...interface{}) string {
|
||||
return fmt.Sprint(append([]interface{}{Bold(yellow(smallArrow + " "))}, a...)...)
|
||||
return globalLogger.SprintWarn(a...)
|
||||
}
|
||||
|
||||
func Warn(a ...interface{}) {
|
||||
fmt.Fprint(os.Stdout, append([]interface{}{Bold(yellow(smallArrow + " "))}, a...)...)
|
||||
globalLogger.Warn(a...)
|
||||
}
|
||||
|
||||
func Warnln(a ...interface{}) {
|
||||
fmt.Fprintln(os.Stdout, append([]interface{}{Bold(yellow(smallArrow))}, a...)...)
|
||||
globalLogger.Warnln(a...)
|
||||
}
|
||||
|
||||
func SprintError(a ...interface{}) string {
|
||||
return fmt.Sprint(append([]interface{}{Bold(Red(smallArrow + " "))}, a...)...)
|
||||
return globalLogger.SprintError(a...)
|
||||
}
|
||||
|
||||
func Error(a ...interface{}) {
|
||||
fmt.Fprint(os.Stderr, append([]interface{}{Bold(Red(smallArrow + " "))}, a...)...)
|
||||
globalLogger.Error(a...)
|
||||
}
|
||||
|
||||
func Errorln(a ...interface{}) {
|
||||
fmt.Fprintln(os.Stderr, append([]interface{}{Bold(Red(smallArrow))}, a...)...)
|
||||
globalLogger.Errorln(a...)
|
||||
}
|
||||
|
||||
func getColumnCount() int {
|
||||
|
|
84
pkg/text/service.go
Normal file
84
pkg/text/service.go
Normal file
|
@ -0,0 +1,84 @@
|
|||
package text
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
type Logger struct {
|
||||
name string
|
||||
debug bool
|
||||
w io.Writer
|
||||
r io.Reader
|
||||
}
|
||||
|
||||
func NewLogger(w io.Writer, r io.Reader, debug bool, name string) *Logger {
|
||||
return &Logger{
|
||||
w: w,
|
||||
name: name,
|
||||
debug: debug,
|
||||
r: r,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Child(name string) *Logger {
|
||||
return NewLogger(l.w, l.r, l.debug, name)
|
||||
}
|
||||
|
||||
func (l *Logger) Debugln(a ...any) {
|
||||
if !DebugMode {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Fprintln(l.w, append([]interface{}{
|
||||
Bold(yellow(fmt.Sprintf("[DEBUG:%s]", l.name))),
|
||||
}, a...)...)
|
||||
}
|
||||
|
||||
func (l *Logger) OperationInfoln(a ...any) {
|
||||
fmt.Fprintln(l.w, l.SprintOperationInfo(a...))
|
||||
}
|
||||
|
||||
func (l *Logger) OperationInfo(a ...any) {
|
||||
fmt.Fprint(l.w, l.SprintOperationInfo(a...))
|
||||
}
|
||||
|
||||
func (l *Logger) SprintOperationInfo(a ...any) string {
|
||||
return fmt.Sprint(append([]interface{}{Bold(Cyan(opSymbol + " ")), boldCode}, a...)...) + ResetCode
|
||||
}
|
||||
|
||||
func (l *Logger) Info(a ...any) {
|
||||
fmt.Fprint(l.w, append([]interface{}{Bold(Green(arrow + " "))}, a...)...)
|
||||
}
|
||||
|
||||
func (l *Logger) Infoln(a ...any) {
|
||||
fmt.Fprintln(l.w, append([]interface{}{Bold(Green(arrow))}, a...)...)
|
||||
}
|
||||
|
||||
func (l *Logger) Warn(a ...any) {
|
||||
fmt.Fprint(l.w, l.SprintWarn(a...))
|
||||
}
|
||||
|
||||
func (l *Logger) Warnln(a ...any) {
|
||||
fmt.Fprintln(l.w, l.SprintWarn(a...))
|
||||
}
|
||||
|
||||
func (l *Logger) SprintWarn(a ...any) string {
|
||||
return fmt.Sprint(append([]interface{}{Bold(yellow(smallArrow + " "))}, a...)...)
|
||||
}
|
||||
|
||||
func (l *Logger) Error(a ...any) {
|
||||
fmt.Fprint(l.w, l.SprintError(a...))
|
||||
}
|
||||
|
||||
func (l *Logger) Errorln(a ...any) {
|
||||
fmt.Fprintln(l.w, l.SprintError(a...))
|
||||
}
|
||||
|
||||
func (l *Logger) SprintError(a ...any) string {
|
||||
return fmt.Sprint(append([]interface{}{Bold(Red(smallArrow + " "))}, a...)...)
|
||||
}
|
||||
|
||||
func (l *Logger) Printf(format string, a ...any) {
|
||||
fmt.Fprintf(l.w, format, a...)
|
||||
}
|
163
pkg/topo/dep.go
163
pkg/topo/dep.go
|
@ -3,12 +3,13 @@ package topo
|
|||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/Jguer/yay/v11/pkg/text"
|
||||
)
|
||||
|
||||
type (
|
||||
AliasMap[T comparable] map[T]T
|
||||
NodeSet[T comparable] map[T]bool
|
||||
DepMap[T comparable] map[T]NodeSet[T]
|
||||
NodeSet[T comparable] map[T]bool
|
||||
DepMap[T comparable] map[T]NodeSet[T]
|
||||
)
|
||||
|
||||
type NodeInfo[V any] struct {
|
||||
|
@ -20,9 +21,7 @@ type NodeInfo[V any] struct {
|
|||
type CheckFn[T comparable, V any] func(T, V) error
|
||||
|
||||
type Graph[T comparable, V any] struct {
|
||||
alias AliasMap[T] // alias -> aliased
|
||||
aliases DepMap[T] // aliased -> alias
|
||||
nodes NodeSet[T]
|
||||
nodes NodeSet[T]
|
||||
|
||||
// node info map
|
||||
nodeInfo map[T]*NodeInfo[V]
|
||||
|
@ -31,7 +30,6 @@ type Graph[T comparable, V any] struct {
|
|||
dependencies DepMap[T]
|
||||
// `dependents` tracks parent -> children.
|
||||
dependents DepMap[T]
|
||||
// Keep track of the nodes of the graph themselves.
|
||||
}
|
||||
|
||||
func New[T comparable, V any]() *Graph[T, V] {
|
||||
|
@ -39,8 +37,6 @@ func New[T comparable, V any]() *Graph[T, V] {
|
|||
nodes: make(NodeSet[T]),
|
||||
dependencies: make(DepMap[T]),
|
||||
dependents: make(DepMap[T]),
|
||||
alias: make(AliasMap[T]),
|
||||
aliases: make(DepMap[T]),
|
||||
nodeInfo: make(map[T]*NodeInfo[V]),
|
||||
}
|
||||
}
|
||||
|
@ -50,71 +46,34 @@ func (g *Graph[T, V]) Len() int {
|
|||
}
|
||||
|
||||
func (g *Graph[T, V]) Exists(node T) bool {
|
||||
// check aliases
|
||||
node = g.getAlias(node)
|
||||
|
||||
_, ok := g.nodes[node]
|
||||
|
||||
return ok
|
||||
}
|
||||
|
||||
func (g *Graph[T, V]) Alias(node, alias T) error {
|
||||
if alias == node {
|
||||
return nil
|
||||
}
|
||||
|
||||
// add node
|
||||
func (g *Graph[T, V]) AddNode(node T) {
|
||||
g.nodes[node] = true
|
||||
}
|
||||
|
||||
// add alias
|
||||
if _, ok := g.alias[alias]; ok {
|
||||
return ErrConflictingAlias
|
||||
func (g *Graph[T, V]) ForEach(f CheckFn[T, V]) error {
|
||||
for node := range g.nodes {
|
||||
if err := f(node, g.nodeInfo[node].Value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
g.alias[alias] = node
|
||||
g.aliases.addNodeToNodeset(node, alias)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Graph[T, V]) AddNode(node T) {
|
||||
node = g.getAlias(node)
|
||||
|
||||
g.nodes[node] = true
|
||||
}
|
||||
|
||||
func (g *Graph[T, V]) getAlias(node T) T {
|
||||
if aliasNode, ok := g.alias[node]; ok {
|
||||
return aliasNode
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
func (g *Graph[T, V]) SetNodeInfo(node T, nodeInfo *NodeInfo[V]) {
|
||||
g.nodeInfo[g.getAlias(node)] = nodeInfo
|
||||
g.nodeInfo[node] = nodeInfo
|
||||
}
|
||||
|
||||
func (g *Graph[T, V]) GetNodeInfo(node T) *NodeInfo[V] {
|
||||
return g.nodeInfo[g.getAlias(node)]
|
||||
}
|
||||
|
||||
// Retrieve aliases of a node.
|
||||
func (g *Graph[T, V]) GetAliases(node T) []T {
|
||||
size := len(g.aliases[node])
|
||||
aliases := make([]T, 0, size)
|
||||
|
||||
for alias := range g.aliases[node] {
|
||||
aliases = append(aliases, alias)
|
||||
}
|
||||
|
||||
return aliases
|
||||
return g.nodeInfo[node]
|
||||
}
|
||||
|
||||
func (g *Graph[T, V]) DependOn(child, parent T) error {
|
||||
child = g.getAlias(child)
|
||||
parent = g.getAlias(parent)
|
||||
|
||||
if child == parent {
|
||||
return ErrSelfReferential
|
||||
}
|
||||
|
@ -182,20 +141,8 @@ func (g *Graph[T, V]) HasDependent(parent, child T) bool {
|
|||
return ok
|
||||
}
|
||||
|
||||
func (g *Graph[T, V]) Leaves() []T {
|
||||
leaves := make([]T, 0)
|
||||
|
||||
for node := range g.nodes {
|
||||
if _, ok := g.dependencies[node]; !ok {
|
||||
leaves = append(leaves, node)
|
||||
}
|
||||
}
|
||||
|
||||
return leaves
|
||||
}
|
||||
|
||||
// LeavesMap returns a map of leaves with the node as key and the node info value as value.
|
||||
func (g *Graph[T, V]) LeavesMap() map[T]V {
|
||||
// leavesMap returns a map of leaves with the node as key and the node info value as value.
|
||||
func (g *Graph[T, V]) leavesMap() map[T]V {
|
||||
leaves := make(map[T]V, 0)
|
||||
|
||||
for node := range g.nodes {
|
||||
|
@ -212,29 +159,6 @@ func (g *Graph[T, V]) LeavesMap() map[T]V {
|
|||
return leaves
|
||||
}
|
||||
|
||||
// TopoSortedLayers returns a slice of all of the graph nodes in topological sort order.
|
||||
func (g *Graph[T, V]) TopoSortedLayers() [][]T {
|
||||
layers := [][]T{}
|
||||
|
||||
// Copy the graph
|
||||
shrinkingGraph := g.clone()
|
||||
|
||||
for {
|
||||
leaves := shrinkingGraph.Leaves()
|
||||
if len(leaves) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
layers = append(layers, leaves)
|
||||
|
||||
for _, leafNode := range leaves {
|
||||
shrinkingGraph.remove(leafNode)
|
||||
}
|
||||
}
|
||||
|
||||
return layers
|
||||
}
|
||||
|
||||
// TopoSortedLayerMap returns a slice of all of the graph nodes in topological sort order with their node info.
|
||||
func (g *Graph[T, V]) TopoSortedLayerMap(checkFn CheckFn[T, V]) []map[T]V {
|
||||
layers := []map[T]V{}
|
||||
|
@ -243,7 +167,7 @@ func (g *Graph[T, V]) TopoSortedLayerMap(checkFn CheckFn[T, V]) []map[T]V {
|
|||
shrinkingGraph := g.clone()
|
||||
|
||||
for {
|
||||
leaves := shrinkingGraph.LeavesMap()
|
||||
leaves := shrinkingGraph.leavesMap()
|
||||
if len(leaves) == 0 {
|
||||
break
|
||||
}
|
||||
|
@ -263,17 +187,50 @@ func (g *Graph[T, V]) TopoSortedLayerMap(checkFn CheckFn[T, V]) []map[T]V {
|
|||
return layers
|
||||
}
|
||||
|
||||
func (dm DepMap[T]) removeFromDepmap(key, node T) {
|
||||
// returns if it was the last
|
||||
func (dm DepMap[T]) removeFromDepmap(key, node T) bool {
|
||||
if nodes := dm[key]; len(nodes) == 1 {
|
||||
// The only element in the nodeset must be `node`, so we
|
||||
// can delete the entry entirely.
|
||||
delete(dm, key)
|
||||
return true
|
||||
} else {
|
||||
// Otherwise, remove the single node from the nodeset.
|
||||
delete(nodes, node)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Prune removes the node,
|
||||
// its dependencies if there are no other dependents
|
||||
// and its dependents
|
||||
func (g *Graph[T, V]) Prune(node T) {
|
||||
// Remove edges from things that depend on `node`.
|
||||
for dependent := range g.dependents[node] {
|
||||
last := g.dependencies.removeFromDepmap(dependent, node)
|
||||
text.Debugln("pruning dependent", dependent, last)
|
||||
if last {
|
||||
g.Prune(dependent)
|
||||
}
|
||||
}
|
||||
|
||||
delete(g.dependents, node)
|
||||
|
||||
// Remove all edges from node to the things it depends on.
|
||||
for dependency := range g.dependencies[node] {
|
||||
last := g.dependents.removeFromDepmap(dependency, node)
|
||||
text.Debugln("pruning dependency", dependency, last)
|
||||
if last {
|
||||
g.Prune(dependency)
|
||||
}
|
||||
}
|
||||
|
||||
delete(g.dependencies, node)
|
||||
|
||||
// Finally, remove the node itself.
|
||||
delete(g.nodes, node)
|
||||
}
|
||||
|
||||
func (g *Graph[T, V]) remove(node T) {
|
||||
// Remove edges from things that depend on `node`.
|
||||
for dependent := range g.dependents[node] {
|
||||
|
@ -293,24 +250,6 @@ func (g *Graph[T, V]) remove(node T) {
|
|||
delete(g.nodes, node)
|
||||
}
|
||||
|
||||
// TopoSorted returns all the nodes in the graph is topological sort order.
|
||||
func (g *Graph[T, V]) TopoSorted() []T {
|
||||
nodeCount := 0
|
||||
layers := g.TopoSortedLayers()
|
||||
|
||||
for _, layer := range layers {
|
||||
nodeCount += len(layer)
|
||||
}
|
||||
|
||||
allNodes := make([]T, 0, nodeCount)
|
||||
|
||||
for _, layer := range layers {
|
||||
allNodes = append(allNodes, layer...)
|
||||
}
|
||||
|
||||
return allNodes
|
||||
}
|
||||
|
||||
func (g *Graph[T, V]) Dependencies(child T) NodeSet[T] {
|
||||
return g.buildTransitive(child, g.immediateDependencies)
|
||||
}
|
||||
|
|
303
pkg/upgrade/service.go
Normal file
303
pkg/upgrade/service.go
Normal file
|
@ -0,0 +1,303 @@
|
|||
package upgrade
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
|
||||
"github.com/Jguer/aur"
|
||||
"github.com/Jguer/aur/metadata"
|
||||
"github.com/Jguer/go-alpm/v2"
|
||||
mapset "github.com/deckarep/golang-set/v2"
|
||||
"github.com/leonelquinteros/gotext"
|
||||
|
||||
"github.com/Jguer/yay/v11/pkg/db"
|
||||
"github.com/Jguer/yay/v11/pkg/dep"
|
||||
"github.com/Jguer/yay/v11/pkg/intrange"
|
||||
"github.com/Jguer/yay/v11/pkg/multierror"
|
||||
"github.com/Jguer/yay/v11/pkg/query"
|
||||
"github.com/Jguer/yay/v11/pkg/settings"
|
||||
"github.com/Jguer/yay/v11/pkg/text"
|
||||
"github.com/Jguer/yay/v11/pkg/topo"
|
||||
"github.com/Jguer/yay/v11/pkg/vcs"
|
||||
)
|
||||
|
||||
type UpgradeService struct {
|
||||
grapher *dep.Grapher
|
||||
aurCache settings.AURCache
|
||||
aurClient aur.ClientInterface
|
||||
dbExecutor db.Executor
|
||||
vcsStore vcs.Store
|
||||
runtime *settings.Runtime
|
||||
cfg *settings.Configuration
|
||||
log *text.Logger
|
||||
noConfirm bool
|
||||
}
|
||||
|
||||
func NewUpgradeService(grapher *dep.Grapher, aurCache settings.AURCache,
|
||||
aurClient aur.ClientInterface, dbExecutor db.Executor,
|
||||
vcsStore vcs.Store, runtime *settings.Runtime, cfg *settings.Configuration,
|
||||
noConfirm bool, logger *text.Logger,
|
||||
) *UpgradeService {
|
||||
return &UpgradeService{
|
||||
grapher: grapher,
|
||||
aurCache: aurCache,
|
||||
aurClient: aurClient,
|
||||
dbExecutor: dbExecutor,
|
||||
vcsStore: vcsStore,
|
||||
runtime: runtime,
|
||||
cfg: cfg,
|
||||
noConfirm: noConfirm,
|
||||
log: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// upGraph adds packages to upgrade to the graph.
|
||||
func (u *UpgradeService) upGraph(ctx context.Context, graph *topo.Graph[string, *dep.InstallInfo],
|
||||
warnings *query.AURWarnings, enableDowngrade bool,
|
||||
filter Filter,
|
||||
) (err error) {
|
||||
var (
|
||||
develUp UpSlice
|
||||
errs multierror.MultiError
|
||||
aurdata = make(map[string]*aur.Pkg)
|
||||
aurUp UpSlice
|
||||
)
|
||||
|
||||
remote := u.dbExecutor.InstalledRemotePackages()
|
||||
remoteNames := u.dbExecutor.InstalledRemotePackageNames()
|
||||
|
||||
if u.runtime.Mode.AtLeastAUR() {
|
||||
u.log.OperationInfoln(gotext.Get("Searching AUR for updates..."))
|
||||
|
||||
var _aurdata []aur.Pkg
|
||||
if u.aurCache != nil {
|
||||
_aurdata, err = u.aurCache.Get(ctx, &metadata.AURQuery{Needles: remoteNames, By: aur.Name})
|
||||
} else {
|
||||
_aurdata, err = query.AURInfo(ctx, u.aurClient, remoteNames, warnings, u.cfg.RequestSplitN)
|
||||
}
|
||||
|
||||
errs.Add(err)
|
||||
|
||||
if err == nil {
|
||||
for i := range _aurdata {
|
||||
pkg := &_aurdata[i]
|
||||
aurdata[pkg.Name] = pkg
|
||||
}
|
||||
|
||||
aurUp = UpAUR(remote, aurdata, u.cfg.TimeUpdate)
|
||||
}
|
||||
|
||||
if u.cfg.Devel {
|
||||
u.log.OperationInfoln(gotext.Get("Checking development packages..."))
|
||||
|
||||
develUp = UpDevel(ctx, remote, aurdata, u.vcsStore)
|
||||
|
||||
u.vcsStore.CleanOrphans(remote)
|
||||
}
|
||||
}
|
||||
|
||||
names := mapset.NewThreadUnsafeSet[string]()
|
||||
for i := range develUp.Up {
|
||||
up := &develUp.Up[i]
|
||||
// check if deps are satisfied for aur packages
|
||||
reason := dep.Explicit
|
||||
if up.Reason == alpm.PkgReasonDepend {
|
||||
reason = dep.Dep
|
||||
}
|
||||
|
||||
if filter != nil && !filter(up) {
|
||||
continue
|
||||
}
|
||||
|
||||
aurPkg := aurdata[up.Name]
|
||||
graph = u.grapher.GraphAURTarget(ctx, graph, aurPkg, &dep.InstallInfo{
|
||||
Reason: reason,
|
||||
Source: dep.AUR,
|
||||
AURBase: &aurPkg.PackageBase,
|
||||
Upgrade: true,
|
||||
Devel: true,
|
||||
LocalVersion: up.LocalVersion,
|
||||
})
|
||||
names.Add(up.Name)
|
||||
}
|
||||
|
||||
for i := range aurUp.Up {
|
||||
up := &aurUp.Up[i]
|
||||
// add devel packages if they are not already in the list
|
||||
if names.Contains(up.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
// check if deps are satisfied for aur packages
|
||||
reason := dep.Explicit
|
||||
if up.Reason == alpm.PkgReasonDepend {
|
||||
reason = dep.Dep
|
||||
}
|
||||
|
||||
if filter != nil && !filter(up) {
|
||||
continue
|
||||
}
|
||||
|
||||
aurPkg := aurdata[up.Name]
|
||||
graph = u.grapher.GraphAURTarget(ctx, graph, aurPkg, &dep.InstallInfo{
|
||||
Reason: reason,
|
||||
Source: dep.AUR,
|
||||
AURBase: &aurPkg.PackageBase,
|
||||
Upgrade: true,
|
||||
Version: up.RemoteVersion,
|
||||
LocalVersion: up.LocalVersion,
|
||||
})
|
||||
}
|
||||
|
||||
if u.cfg.Runtime.Mode.AtLeastRepo() {
|
||||
u.log.OperationInfoln(gotext.Get("Searching databases for updates..."))
|
||||
|
||||
syncUpgrades, err := u.dbExecutor.SyncUpgrades(enableDowngrade)
|
||||
for _, up := range syncUpgrades {
|
||||
dbName := up.Package.DB().Name()
|
||||
if filter != nil && !filter(&db.Upgrade{
|
||||
Name: up.Package.Name(),
|
||||
RemoteVersion: up.Package.Version(),
|
||||
Repository: dbName,
|
||||
Base: up.Package.Base(),
|
||||
LocalVersion: up.LocalVersion,
|
||||
Reason: up.Reason,
|
||||
}) {
|
||||
continue
|
||||
}
|
||||
|
||||
reason := dep.Explicit
|
||||
if up.Reason == alpm.PkgReasonDepend {
|
||||
reason = dep.Dep
|
||||
}
|
||||
|
||||
graph = u.grapher.GraphSyncPkg(ctx, graph, up.Package, &dep.InstallInfo{
|
||||
Source: dep.Sync,
|
||||
Reason: reason,
|
||||
Version: up.Package.Version(),
|
||||
SyncDBName: &dbName,
|
||||
LocalVersion: up.LocalVersion,
|
||||
Upgrade: true,
|
||||
})
|
||||
}
|
||||
|
||||
errs.Add(err)
|
||||
}
|
||||
|
||||
return errs.Return()
|
||||
}
|
||||
|
||||
func (u *UpgradeService) graphToUpSlice(graph *topo.Graph[string, *dep.InstallInfo]) (aurUp, repoUp UpSlice) {
|
||||
aurUp = UpSlice{Up: make([]Upgrade, 0, graph.Len())}
|
||||
repoUp = UpSlice{Up: make([]Upgrade, 0, graph.Len()), Repos: u.dbExecutor.Repos()}
|
||||
|
||||
_ = graph.ForEach(func(name string, info *dep.InstallInfo) error {
|
||||
alpmReason := alpm.PkgReasonExplicit
|
||||
if info.Reason == dep.Dep {
|
||||
alpmReason = alpm.PkgReasonDepend
|
||||
}
|
||||
|
||||
if info.Source == dep.AUR {
|
||||
aurRepo := "aur"
|
||||
if info.Devel {
|
||||
aurRepo = "devel"
|
||||
}
|
||||
aurUp.Up = append(aurUp.Up, Upgrade{
|
||||
Name: name,
|
||||
RemoteVersion: info.Version,
|
||||
Repository: aurRepo,
|
||||
Base: *info.AURBase,
|
||||
LocalVersion: info.LocalVersion,
|
||||
Reason: alpmReason,
|
||||
})
|
||||
} else if info.Source == dep.Sync {
|
||||
repoUp.Up = append(repoUp.Up, Upgrade{
|
||||
Name: name,
|
||||
RemoteVersion: info.Version,
|
||||
Repository: *info.SyncDBName,
|
||||
Base: "",
|
||||
LocalVersion: info.LocalVersion,
|
||||
Reason: alpmReason,
|
||||
})
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
return aurUp, repoUp
|
||||
}
|
||||
|
||||
func (u *UpgradeService) GraphUpgrades(ctx context.Context,
|
||||
graph *topo.Graph[string, *dep.InstallInfo],
|
||||
enableDowngrade bool,
|
||||
) (*topo.Graph[string, *dep.InstallInfo], error) {
|
||||
if graph == nil {
|
||||
graph = topo.New[string, *dep.InstallInfo]()
|
||||
}
|
||||
|
||||
warnings := query.NewWarnings()
|
||||
|
||||
err := u.upGraph(ctx, graph, warnings, enableDowngrade,
|
||||
func(*Upgrade) bool { return true })
|
||||
if err != nil {
|
||||
return graph, err
|
||||
}
|
||||
|
||||
warnings.Print()
|
||||
|
||||
if graph.Len() == 0 {
|
||||
return graph, nil
|
||||
}
|
||||
|
||||
errUp := u.userExcludeUpgrades(graph)
|
||||
return graph, errUp
|
||||
}
|
||||
|
||||
// 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]) error {
|
||||
allUpLen := graph.Len()
|
||||
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...)}
|
||||
|
||||
u.log.Printf("%s"+text.Bold(" %d ")+"%s\n", text.Bold(text.Cyan("::")), allUpLen, text.Bold(gotext.Get("Packages to upgrade.")))
|
||||
allUp.Print(u.log)
|
||||
|
||||
u.log.Infoln(gotext.Get("Packages to exclude: (eg: \"1 2 3\", \"1-3\", \"^4\" or repo name)"))
|
||||
u.log.Warnln(gotext.Get("May cause partial upgrades and break systems"))
|
||||
|
||||
numbers, err := u.log.GetInput(u.cfg.AnswerUpgrade, settings.NoConfirm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// upgrade menu asks you which packages to NOT upgrade so in this case
|
||||
// exclude and include are kind of swapped
|
||||
exclude, include, otherExclude, otherInclude := intrange.ParseNumberMenu(numbers)
|
||||
isInclude := len(include) == 0 && len(otherInclude) == 0
|
||||
|
||||
for i := range allUp.Up {
|
||||
up := &allUp.Up[i]
|
||||
if isInclude && otherExclude.Get(up.Repository) {
|
||||
u.log.Debugln("pruning", up.Name)
|
||||
graph.Prune(up.Name)
|
||||
}
|
||||
|
||||
if isInclude && exclude.Get(allUpLen-i) {
|
||||
u.log.Debugln("pruning", up.Name)
|
||||
graph.Prune(up.Name)
|
||||
continue
|
||||
}
|
||||
|
||||
if !isInclude && !(include.Get(allUpLen-i) || otherInclude.Get(up.Repository)) {
|
||||
u.log.Debugln("pruning", up.Name)
|
||||
graph.Prune(up.Name)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
287
pkg/upgrade/service_test.go
Normal file
287
pkg/upgrade/service_test.go
Normal file
|
@ -0,0 +1,287 @@
|
|||
package upgrade
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Jguer/aur"
|
||||
"github.com/Jguer/aur/metadata"
|
||||
"github.com/Jguer/go-alpm/v2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/Jguer/yay/v11/pkg/db"
|
||||
"github.com/Jguer/yay/v11/pkg/db/mock"
|
||||
"github.com/Jguer/yay/v11/pkg/dep"
|
||||
"github.com/Jguer/yay/v11/pkg/settings"
|
||||
"github.com/Jguer/yay/v11/pkg/settings/parser"
|
||||
"github.com/Jguer/yay/v11/pkg/text"
|
||||
"github.com/Jguer/yay/v11/pkg/topo"
|
||||
"github.com/Jguer/yay/v11/pkg/vcs"
|
||||
|
||||
mockaur "github.com/Jguer/yay/v11/pkg/dep/mock"
|
||||
)
|
||||
|
||||
func ptrString(s string) *string {
|
||||
return &s
|
||||
}
|
||||
|
||||
func TestUpgradeService_GraphUpgrades(t *testing.T) {
|
||||
linuxDepInfo := &dep.InstallInfo{
|
||||
Reason: dep.Explicit,
|
||||
Source: dep.Sync,
|
||||
AURBase: nil,
|
||||
LocalVersion: "4.5.0-1",
|
||||
Version: "5.0.0-1",
|
||||
SyncDBName: ptrString("core"),
|
||||
Upgrade: true,
|
||||
Devel: false,
|
||||
}
|
||||
|
||||
exampleDepInfoDevel := &dep.InstallInfo{
|
||||
Source: dep.AUR,
|
||||
Reason: dep.Dep,
|
||||
AURBase: ptrString("example"),
|
||||
LocalVersion: "2.2.1.r32.41baa362-1",
|
||||
Version: "",
|
||||
Upgrade: true,
|
||||
Devel: true,
|
||||
}
|
||||
|
||||
exampleDepInfoAUR := &dep.InstallInfo{
|
||||
Source: dep.AUR,
|
||||
Reason: dep.Dep,
|
||||
AURBase: ptrString("example"),
|
||||
LocalVersion: "2.2.1.r32.41baa362-1",
|
||||
Version: "2.2.1.r69.g8a10460-1",
|
||||
Upgrade: true,
|
||||
Devel: false,
|
||||
}
|
||||
|
||||
yayDepInfo := &dep.InstallInfo{
|
||||
Reason: dep.Explicit,
|
||||
Source: dep.AUR,
|
||||
AURBase: ptrString("yay"),
|
||||
LocalVersion: "10.2.3",
|
||||
Version: "10.2.4",
|
||||
Upgrade: true,
|
||||
Devel: false,
|
||||
}
|
||||
|
||||
dbExe := &mock.DBExecutor{
|
||||
InstalledRemotePackageNamesFn: func() []string {
|
||||
return []string{"yay", "example-git"}
|
||||
},
|
||||
InstalledRemotePackagesFn: func() map[string]mock.IPackage {
|
||||
mapRemote := make(map[string]mock.IPackage)
|
||||
mapRemote["yay"] = &mock.Package{
|
||||
PName: "yay",
|
||||
PBase: "yay",
|
||||
PVersion: "10.2.3",
|
||||
PReason: alpm.PkgReasonExplicit,
|
||||
}
|
||||
|
||||
mapRemote["example-git"] = &mock.Package{
|
||||
PName: "example-git",
|
||||
PBase: "example",
|
||||
PVersion: "2.2.1.r32.41baa362-1",
|
||||
PReason: alpm.PkgReasonDepend,
|
||||
}
|
||||
|
||||
return mapRemote
|
||||
},
|
||||
SyncUpgradesFn: func(bool) (map[string]db.SyncUpgrade, error) {
|
||||
mapUpgrades := make(map[string]db.SyncUpgrade)
|
||||
|
||||
coreDB := mock.NewDB("core")
|
||||
mapUpgrades["linux"] = db.SyncUpgrade{
|
||||
Package: &mock.Package{
|
||||
PName: "linux",
|
||||
PVersion: "5.0.0-1",
|
||||
PReason: alpm.PkgReasonDepend,
|
||||
PDB: coreDB,
|
||||
},
|
||||
LocalVersion: "4.5.0-1",
|
||||
Reason: alpm.PkgReasonExplicit,
|
||||
}
|
||||
return mapUpgrades, nil
|
||||
},
|
||||
ReposFn: func() []string { return []string{"core"} },
|
||||
}
|
||||
vcsStore := &vcs.Mock{
|
||||
ToUpgradeReturn: []string{"example-git"},
|
||||
}
|
||||
|
||||
mockAUR := &mockaur.MockAUR{
|
||||
GetFn: func(ctx context.Context, query *metadata.AURQuery) ([]aur.Pkg, error) {
|
||||
return []aur.Pkg{
|
||||
{Name: "yay", Version: "10.2.4", PackageBase: "yay"},
|
||||
{Name: "example-git", Version: "2.2.1.r69.g8a10460-1", PackageBase: "example"},
|
||||
}, nil
|
||||
},
|
||||
}
|
||||
grapher := dep.NewGrapher(dbExe, mockAUR,
|
||||
false, true, io.Discard, false, false)
|
||||
|
||||
cfg := &settings.Configuration{
|
||||
Runtime: &settings.Runtime{Mode: parser.ModeAny},
|
||||
}
|
||||
|
||||
type fields struct {
|
||||
input io.Reader
|
||||
output io.Writer
|
||||
noConfirm bool
|
||||
devel bool
|
||||
}
|
||||
type args struct {
|
||||
graph *topo.Graph[string, *dep.InstallInfo]
|
||||
enableDowngrade bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
mustExist map[string]*dep.InstallInfo
|
||||
mustNotExist map[string]bool
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "no input",
|
||||
fields: fields{
|
||||
input: strings.NewReader("\n"),
|
||||
output: io.Discard,
|
||||
noConfirm: false,
|
||||
},
|
||||
args: args{
|
||||
graph: nil,
|
||||
enableDowngrade: false,
|
||||
},
|
||||
mustExist: map[string]*dep.InstallInfo{
|
||||
"yay": yayDepInfo,
|
||||
"linux": linuxDepInfo,
|
||||
"example-git": exampleDepInfoAUR,
|
||||
},
|
||||
mustNotExist: map[string]bool{},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "no input devel",
|
||||
fields: fields{
|
||||
input: strings.NewReader("\n"),
|
||||
output: io.Discard,
|
||||
noConfirm: false,
|
||||
devel: true,
|
||||
},
|
||||
args: args{
|
||||
graph: nil,
|
||||
enableDowngrade: false,
|
||||
},
|
||||
mustExist: map[string]*dep.InstallInfo{
|
||||
"yay": yayDepInfo,
|
||||
"linux": linuxDepInfo,
|
||||
"example-git": exampleDepInfoDevel,
|
||||
},
|
||||
mustNotExist: map[string]bool{},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "exclude yay",
|
||||
fields: fields{
|
||||
input: strings.NewReader("1\n"),
|
||||
output: io.Discard,
|
||||
noConfirm: false,
|
||||
},
|
||||
args: args{
|
||||
graph: nil,
|
||||
enableDowngrade: false,
|
||||
},
|
||||
mustExist: map[string]*dep.InstallInfo{
|
||||
"linux": linuxDepInfo,
|
||||
"example-git": exampleDepInfoAUR,
|
||||
},
|
||||
mustNotExist: map[string]bool{"yay": true},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "exclude linux",
|
||||
fields: fields{
|
||||
input: strings.NewReader("3\n"),
|
||||
output: io.Discard,
|
||||
noConfirm: false,
|
||||
},
|
||||
args: args{
|
||||
graph: nil,
|
||||
enableDowngrade: false,
|
||||
},
|
||||
mustExist: map[string]*dep.InstallInfo{
|
||||
"yay": yayDepInfo,
|
||||
"example-git": exampleDepInfoAUR,
|
||||
},
|
||||
mustNotExist: map[string]bool{"linux": true},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "only linux",
|
||||
fields: fields{
|
||||
input: strings.NewReader("^3\n"),
|
||||
output: io.Discard,
|
||||
noConfirm: false,
|
||||
},
|
||||
args: args{
|
||||
graph: nil,
|
||||
enableDowngrade: false,
|
||||
},
|
||||
mustExist: map[string]*dep.InstallInfo{
|
||||
"linux": linuxDepInfo,
|
||||
},
|
||||
mustNotExist: map[string]bool{"yay": true, "example-git": true},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "exclude all",
|
||||
fields: fields{
|
||||
input: strings.NewReader("1-3\n"),
|
||||
output: io.Discard,
|
||||
noConfirm: false,
|
||||
},
|
||||
args: args{
|
||||
graph: nil,
|
||||
enableDowngrade: false,
|
||||
},
|
||||
mustExist: map[string]*dep.InstallInfo{},
|
||||
mustNotExist: map[string]bool{"yay": true, "example-git": true, "linux": true},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cfg.Devel = tt.fields.devel
|
||||
u := &UpgradeService{
|
||||
log: text.NewLogger(tt.fields.output, tt.fields.input, true, "test"),
|
||||
grapher: grapher,
|
||||
aurCache: mockAUR,
|
||||
dbExecutor: dbExe,
|
||||
vcsStore: vcsStore,
|
||||
runtime: cfg.Runtime,
|
||||
cfg: cfg,
|
||||
noConfirm: tt.fields.noConfirm,
|
||||
}
|
||||
|
||||
got, err := u.GraphUpgrades(context.Background(), tt.args.graph, tt.args.enableDowngrade)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("UpgradeService.GraphUpgrades() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
|
||||
for node, info := range tt.mustExist {
|
||||
assert.True(t, got.Exists(node), node)
|
||||
assert.Equal(t, info, got.GetNodeInfo(node).Value)
|
||||
}
|
||||
|
||||
for node := range tt.mustNotExist {
|
||||
assert.False(t, got.Exists(node), node)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -10,7 +10,7 @@ import (
|
|||
)
|
||||
|
||||
// Filter decides if specific package should be included in theincluded in the results.
|
||||
type Filter func(Upgrade) bool
|
||||
type Filter func(*Upgrade) bool
|
||||
|
||||
// Upgrade type describes a system upgrade.
|
||||
type Upgrade = db.Upgrade
|
||||
|
@ -100,7 +100,7 @@ func GetVersionDiff(oldVersion, newVersion string) (left, right string) {
|
|||
}
|
||||
|
||||
// Print prints the details of the packages to upgrade.
|
||||
func (u UpSlice) Print() {
|
||||
func (u UpSlice) Print(logger *text.Logger) {
|
||||
longestName, longestVersion := 0, 0
|
||||
|
||||
for k := range u.Up {
|
||||
|
@ -120,10 +120,10 @@ func (u UpSlice) Print() {
|
|||
upgrade := &u.Up[k]
|
||||
left, right := GetVersionDiff(upgrade.LocalVersion, upgrade.RemoteVersion)
|
||||
|
||||
fmt.Print(text.Magenta(fmt.Sprintf(numberPadding, len(u.Up)-k)))
|
||||
logger.Printf(text.Magenta(fmt.Sprintf(numberPadding, len(u.Up)-k)))
|
||||
|
||||
fmt.Printf(namePadding, StylizedNameWithRepository(upgrade))
|
||||
logger.Printf(namePadding, StylizedNameWithRepository(upgrade))
|
||||
|
||||
fmt.Printf("%s -> %s\n", fmt.Sprintf(versionPadding, left), right)
|
||||
logger.Printf("%s -> %s\n", fmt.Sprintf(versionPadding, left), right)
|
||||
}
|
||||
}
|
||||
|
|
4
print.go
4
print.go
|
@ -100,7 +100,7 @@ func printNumberOfUpdates(ctx context.Context, dbExecutor db.Executor, enableDow
|
|||
warnings := query.NewWarnings()
|
||||
old := os.Stdout // keep backup of the real stdout
|
||||
os.Stdout = nil
|
||||
aurUp, repoUp, err := upList(ctx, nil, warnings, dbExecutor, enableDowngrade, filter)
|
||||
aurUp, repoUp, err := upList(ctx, warnings, dbExecutor, enableDowngrade, filter)
|
||||
os.Stdout = old // restoring the real stdout
|
||||
|
||||
if err != nil {
|
||||
|
@ -123,7 +123,7 @@ func printUpdateList(ctx context.Context, cmdArgs *parser.Arguments,
|
|||
remoteNames := dbExecutor.InstalledRemotePackageNames()
|
||||
localNames := dbExecutor.InstalledSyncPackageNames()
|
||||
|
||||
aurUp, repoUp, err := upList(ctx, nil, warnings, dbExecutor, enableDowngrade, filter)
|
||||
aurUp, repoUp, err := upList(ctx, warnings, dbExecutor, enableDowngrade, filter)
|
||||
os.Stdout = old // restoring the real stdout
|
||||
|
||||
if err != nil {
|
||||
|
|
7
sync.go
7
sync.go
|
@ -15,6 +15,7 @@ import (
|
|||
"github.com/Jguer/yay/v11/pkg/settings/parser"
|
||||
"github.com/Jguer/yay/v11/pkg/srcinfo"
|
||||
"github.com/Jguer/yay/v11/pkg/text"
|
||||
"github.com/Jguer/yay/v11/pkg/upgrade"
|
||||
|
||||
"github.com/leonelquinteros/gotext"
|
||||
)
|
||||
|
@ -54,7 +55,11 @@ func syncInstall(ctx context.Context,
|
|||
if cmdArgs.ExistsArg("u", "sysupgrade") {
|
||||
var errSysUp error
|
||||
|
||||
graph, _, errSysUp = sysupgradeTargetsV2(ctx, aurCache, dbExecutor, graph, cmdArgs.ExistsDouble("u", "sysupgrade"))
|
||||
upService := upgrade.NewUpgradeService(
|
||||
grapher, aurCache, config.Runtime.AURClient,
|
||||
dbExecutor, config.Runtime.VCSStore, config.Runtime, config, settings.NoConfirm, config.Runtime.Logger.Child("upgrade"))
|
||||
|
||||
graph, errSysUp = upService.GraphUpgrades(ctx, graph, cmdArgs.ExistsDouble("u", "sysupgrade"))
|
||||
if errSysUp != nil {
|
||||
return errSysUp
|
||||
}
|
||||
|
|
139
upgrade.go
139
upgrade.go
|
@ -3,23 +3,21 @@ package main
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/Jguer/yay/v11/pkg/db"
|
||||
"github.com/Jguer/yay/v11/pkg/dep"
|
||||
"github.com/Jguer/yay/v11/pkg/intrange"
|
||||
"github.com/Jguer/yay/v11/pkg/multierror"
|
||||
"github.com/Jguer/yay/v11/pkg/query"
|
||||
"github.com/Jguer/yay/v11/pkg/settings"
|
||||
"github.com/Jguer/yay/v11/pkg/stringset"
|
||||
"github.com/Jguer/yay/v11/pkg/text"
|
||||
"github.com/Jguer/yay/v11/pkg/topo"
|
||||
"github.com/Jguer/yay/v11/pkg/upgrade"
|
||||
|
||||
aur "github.com/Jguer/aur"
|
||||
"github.com/Jguer/aur/metadata"
|
||||
alpm "github.com/Jguer/go-alpm/v2"
|
||||
"github.com/leonelquinteros/gotext"
|
||||
)
|
||||
|
@ -27,9 +25,10 @@ import (
|
|||
func filterUpdateList(list []db.Upgrade, filter upgrade.Filter) []db.Upgrade {
|
||||
tmp := list[:0]
|
||||
|
||||
for _, pkg := range list {
|
||||
if filter(pkg) {
|
||||
tmp = append(tmp, pkg)
|
||||
for i := range list {
|
||||
up := &list[i]
|
||||
if filter(up) {
|
||||
tmp = append(tmp, *up)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,7 +36,7 @@ func filterUpdateList(list []db.Upgrade, filter upgrade.Filter) []db.Upgrade {
|
|||
}
|
||||
|
||||
// upList returns lists of packages to upgrade from each source.
|
||||
func upList(ctx context.Context, aurCache settings.AURCache,
|
||||
func upList(ctx context.Context,
|
||||
warnings *query.AURWarnings, dbExecutor db.Executor, enableDowngrade bool,
|
||||
filter upgrade.Filter,
|
||||
) (aurUp, repoUp upgrade.UpSlice, err error) {
|
||||
|
@ -45,10 +44,10 @@ func upList(ctx context.Context, aurCache settings.AURCache,
|
|||
remoteNames := dbExecutor.InstalledRemotePackageNames()
|
||||
|
||||
var (
|
||||
wg sync.WaitGroup
|
||||
develUp upgrade.UpSlice
|
||||
repoSlice []db.Upgrade
|
||||
errs multierror.MultiError
|
||||
wg sync.WaitGroup
|
||||
develUp upgrade.UpSlice
|
||||
syncUpgrades map[string]db.SyncUpgrade
|
||||
errs multierror.MultiError
|
||||
)
|
||||
|
||||
aurdata := make(map[string]*aur.Pkg)
|
||||
|
@ -64,7 +63,7 @@ func upList(ctx context.Context, aurCache settings.AURCache,
|
|||
wg.Add(1)
|
||||
|
||||
go func() {
|
||||
repoSlice, err = dbExecutor.RepoUpgrades(enableDowngrade)
|
||||
syncUpgrades, err = dbExecutor.SyncUpgrades(enableDowngrade)
|
||||
errs.Add(err)
|
||||
wg.Done()
|
||||
}()
|
||||
|
@ -74,11 +73,7 @@ func upList(ctx context.Context, aurCache settings.AURCache,
|
|||
text.OperationInfoln(gotext.Get("Searching AUR for updates..."))
|
||||
|
||||
var _aurdata []aur.Pkg
|
||||
if aurCache != nil {
|
||||
_aurdata, err = aurCache.Get(ctx, &metadata.AURQuery{Needles: remoteNames, By: aur.Name})
|
||||
} else {
|
||||
_aurdata, err = query.AURInfo(ctx, config.Runtime.AURClient, remoteNames, warnings, config.RequestSplitN)
|
||||
}
|
||||
_aurdata, err = query.AURInfo(ctx, config.Runtime.AURClient, remoteNames, warnings, config.RequestSplitN)
|
||||
|
||||
errs.Add(err)
|
||||
|
||||
|
@ -129,7 +124,25 @@ func upList(ctx context.Context, aurCache settings.AURCache,
|
|||
aurUp = develUp
|
||||
aurUp.Repos = []string{"aur", "devel"}
|
||||
|
||||
repoUp = upgrade.UpSlice{Up: repoSlice, Repos: dbExecutor.Repos()}
|
||||
repoUp = upgrade.UpSlice{
|
||||
Up: make([]db.Upgrade, 0, len(syncUpgrades)),
|
||||
Repos: dbExecutor.Repos(),
|
||||
}
|
||||
for _, up := range syncUpgrades {
|
||||
dbUp := db.Upgrade{
|
||||
Name: up.Package.Name(),
|
||||
RemoteVersion: up.Package.Version(),
|
||||
Repository: up.Package.DB().Name(),
|
||||
Base: up.Package.Base(),
|
||||
LocalVersion: up.LocalVersion,
|
||||
Reason: up.Reason,
|
||||
}
|
||||
if filter != nil && !filter(&dbUp) {
|
||||
continue
|
||||
}
|
||||
|
||||
repoUp.Up = append(repoUp.Up, dbUp)
|
||||
}
|
||||
|
||||
aurUp.Up = filterUpdateList(aurUp.Up, filter)
|
||||
repoUp.Up = filterUpdateList(repoUp.Up, filter)
|
||||
|
@ -195,11 +208,11 @@ func upgradePkgsMenu(aurUp, repoUp upgrade.UpSlice) (stringset.StringSet, []stri
|
|||
allUp := upgrade.UpSlice{Up: append(repoUp.Up, aurUp.Up...), Repos: append(repoUp.Repos, aurUp.Repos...)}
|
||||
|
||||
fmt.Printf("%s"+text.Bold(" %d ")+"%s\n", text.Bold(text.Cyan("::")), allUpLen, text.Bold(gotext.Get("Packages to upgrade.")))
|
||||
allUp.Print()
|
||||
allUp.Print(config.Runtime.Logger)
|
||||
|
||||
text.Infoln(gotext.Get("Packages to exclude") + " (eg: \"1 2 3\", \"1-3\", \"^4\" or repo name):")
|
||||
|
||||
numbers, err := text.GetInput(config.AnswerUpgrade, settings.NoConfirm)
|
||||
numbers, err := text.GetInput(os.Stdin, config.AnswerUpgrade, settings.NoConfirm)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
@ -251,8 +264,8 @@ func sysupgradeTargets(ctx context.Context, dbExecutor db.Executor,
|
|||
) (stringset.StringSet, []string, error) {
|
||||
warnings := query.NewWarnings()
|
||||
|
||||
aurUp, repoUp, err := upList(ctx, nil, warnings, dbExecutor, enableDowngrade,
|
||||
func(upgrade.Upgrade) bool { return true })
|
||||
aurUp, repoUp, err := upList(ctx, warnings, dbExecutor, enableDowngrade,
|
||||
func(*upgrade.Upgrade) bool { return true })
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
@ -261,85 +274,3 @@ func sysupgradeTargets(ctx context.Context, dbExecutor db.Executor,
|
|||
|
||||
return upgradePkgsMenu(aurUp, repoUp)
|
||||
}
|
||||
|
||||
// Targets for sys upgrade.
|
||||
func sysupgradeTargetsV2(ctx context.Context,
|
||||
aurCache settings.AURCache,
|
||||
dbExecutor db.Executor,
|
||||
graph *topo.Graph[string, *dep.InstallInfo],
|
||||
enableDowngrade bool,
|
||||
) (*topo.Graph[string, *dep.InstallInfo], stringset.StringSet, error) {
|
||||
warnings := query.NewWarnings()
|
||||
|
||||
aurUp, repoUp, err := upList(ctx, aurCache, warnings, dbExecutor, enableDowngrade,
|
||||
func(upgrade.Upgrade) bool { return true })
|
||||
if err != nil {
|
||||
return graph, nil, err
|
||||
}
|
||||
|
||||
warnings.Print()
|
||||
|
||||
ignore := make(stringset.StringSet)
|
||||
|
||||
allUpLen := len(repoUp.Up) + len(aurUp.Up)
|
||||
if allUpLen == 0 {
|
||||
return graph, ignore, nil
|
||||
}
|
||||
|
||||
sort.Sort(repoUp)
|
||||
sort.Sort(aurUp)
|
||||
|
||||
allUp := upgrade.UpSlice{Up: append(repoUp.Up, aurUp.Up...), Repos: append(repoUp.Repos, aurUp.Repos...)}
|
||||
|
||||
fmt.Printf("%s"+text.Bold(" %d ")+"%s\n", text.Bold(text.Cyan("::")), allUpLen, text.Bold(gotext.Get("Packages to upgrade.")))
|
||||
allUp.Print()
|
||||
|
||||
text.Infoln(gotext.Get("Packages to exclude: (eg: \"1 2 3\", \"1-3\", \"^4\" or repo name)"))
|
||||
|
||||
numbers, err := text.GetInput(config.AnswerUpgrade, settings.NoConfirm)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// upgrade menu asks you which packages to NOT upgrade so in this case
|
||||
// include and exclude are kind of swapped
|
||||
include, exclude, otherInclude, otherExclude := intrange.ParseNumberMenu(numbers)
|
||||
|
||||
isInclude := len(exclude) == 0 && len(otherExclude) == 0
|
||||
|
||||
for i := range repoUp.Up {
|
||||
pkg := &repoUp.Up[i]
|
||||
if isInclude && otherInclude.Get(pkg.Repository) {
|
||||
ignore.Set(pkg.Name)
|
||||
}
|
||||
|
||||
if isInclude && !include.Get(len(repoUp.Up)-i+len(aurUp.Up)) {
|
||||
dep.AddUpgradeToGraph(pkg, graph)
|
||||
continue
|
||||
}
|
||||
|
||||
if !isInclude && (exclude.Get(len(repoUp.Up)-i+len(aurUp.Up)) || otherExclude.Get(pkg.Repository)) {
|
||||
dep.AddUpgradeToGraph(pkg, graph)
|
||||
continue
|
||||
}
|
||||
|
||||
ignore.Set(pkg.Name)
|
||||
}
|
||||
|
||||
for i := range aurUp.Up {
|
||||
pkg := &aurUp.Up[i]
|
||||
if isInclude && otherInclude.Get(pkg.Repository) {
|
||||
continue
|
||||
}
|
||||
|
||||
if isInclude && !include.Get(len(aurUp.Up)-i) {
|
||||
dep.AddUpgradeToGraph(pkg, graph)
|
||||
}
|
||||
|
||||
if !isInclude && (exclude.Get(len(aurUp.Up)-i) || otherExclude.Get(pkg.Repository)) {
|
||||
dep.AddUpgradeToGraph(pkg, graph)
|
||||
}
|
||||
}
|
||||
|
||||
return graph, ignore, err
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue