feat(dep): add provider resolution on first layer (#2147)

add provider resolution on first layer
This commit is contained in:
Jo authored and GitHub committed 2023-05-01 15:56:42 +00:00
1 parent c721fe7f3b
commit 966bfb74ee
5 files changed
+201 -18

No files matched your search

+5 -1
View File
@@ -38,6 +38,7 @@ type Package struct {
PVersion string
PReason alpm.PkgReason
PDepends alpm.IDependList
PProvides alpm.IDependList
}
func (p *Package) Base() string {
@@ -172,7 +173,10 @@ func (p *Package) Packager() string {
// Provides returns DependList of packages provides by package.
func (p *Package) Provides() alpm.IDependList {
return alpm.DependList{}
if p.PProvides == nil {
return alpm.DependList{}
}
return p.PProvides
}
// Origin returns package origin.
+48 -15
View File
@@ -138,17 +138,6 @@ func (g *Grapher) GraphFromTargets(ctx context.Context,
case "": // unspecified db
if pkg := g.dbExecutor.SyncSatisfier(target.Name); pkg != nil {
dbName := pkg.DB().Name()
graph.AddNode(pkg.Name())
g.ValidateAndSetNodeInfo(graph, pkg.Name(), &topo.NodeInfo[*InstallInfo]{
Color: colorMap[Explicit],
Background: bgColorMap[Sync],
Value: &InstallInfo{
Source: Sync,
Reason: Explicit,
Version: pkg.Version(),
SyncDBName: &dbName,
},
})
g.GraphSyncPkg(ctx, graph, pkg, &InstallInfo{
Source: Sync,
@@ -302,6 +291,12 @@ func (g *Grapher) GraphSyncPkg(ctx context.Context,
}
graph.AddNode(pkg.Name())
_ = pkg.Provides().ForEach(func(p *alpm.Depend) error {
g.logger.Debugln(pkg.Name() + " provides: " + p.String())
graph.Provides(p.Name, p, pkg.Name())
return nil
})
g.ValidateAndSetNodeInfo(graph, pkg.Name(), &topo.NodeInfo[*InstallInfo]{
Color: colorMap[Explicit],
Background: bgColorMap[Sync],
@@ -322,6 +317,16 @@ func (g *Grapher) GraphAURTarget(ctx context.Context,
exists := graph.Exists(pkg.Name)
graph.AddNode(pkg.Name)
for i := range pkg.Provides {
depName, mod, version := splitDep(pkg.Provides[i])
graph.Provides(depName, &alpm.Depend{
Name: depName,
Version: version,
Mod: aurDepModToAlpmDep(mod),
}, pkg.Name)
}
g.ValidateAndSetNodeInfo(graph, pkg.Name, &topo.NodeInfo[*InstallInfo]{
Color: colorMap[instalInfo.Reason],
Background: bgColorMap[AUR],
@@ -515,15 +520,27 @@ func (g *Grapher) addNodes(
// Check if in graph already
for _, depString := range targetsToFind.ToSlice() {
depName, _, _ := splitDep(depString)
if !graph.Exists(depName) {
if !graph.Exists(depName) && !graph.ProvidesExists(depName) {
continue
}
if err := graph.DependOn(depName, parentPkgName); err != nil {
g.logger.Warnln(depString, parentPkgName, err)
if graph.Exists(depName) {
if err := graph.DependOn(depName, parentPkgName); err != nil {
g.logger.Warnln(depString, parentPkgName, err)
}
targetsToFind.Remove(depString)
}
targetsToFind.Remove(depString)
if p := graph.GetProviderNode(depName); p != nil {
if provideSatisfies(p.String(), depString, p.Version) {
if err := graph.DependOn(p.Provider, parentPkgName); err != nil {
g.logger.Warnln(p.Provider, parentPkgName, err)
}
targetsToFind.Remove(depString)
}
}
}
// Check installed
@@ -745,3 +762,19 @@ func archStringToString(alpmArches []string, archString []gosrc.ArchString) []st
return pkgs
}
func aurDepModToAlpmDep(mod string) alpm.DepMod {
switch mod {
case "=":
return alpm.DepModEq
case ">=":
return alpm.DepModGE
case "<=":
return alpm.DepModLE
case ">":
return alpm.DepModGT
case "<":
return alpm.DepModLT
}
return alpm.DepModAny
}
+114
View File
@@ -9,6 +9,7 @@ import (
"testing"
aurc "github.com/Jguer/aur"
alpm "github.com/Jguer/go-alpm/v2"
"github.com/stretchr/testify/require"
"github.com/Jguer/yay/v12/pkg/db"
@@ -205,3 +206,116 @@ func TestGrapher_GraphFromTargets_jellyfin(t *testing.T) {
})
}
}
func TestGrapher_GraphProvides_androidsdk(t *testing.T) {
mockDB := &mock.DBExecutor{
SyncPackageFn: func(string) mock.IPackage { return nil },
SyncSatisfierFn: func(s string) mock.IPackage {
switch s {
case "android-sdk":
return nil
case "jdk11-openjdk":
return &mock.Package{
PName: "jdk11-openjdk",
PVersion: "11.0.12.u7-1",
PDB: mock.NewDB("community"),
PProvides: mock.DependList{
Depends: []alpm.Depend{
{Name: "java-environment", Version: "11", Mod: alpm.DepModEq},
{Name: "java-environment-openjdk", Version: "11", Mod: alpm.DepModEq},
{Name: "jdk11-openjdk", Version: "11.0.19.u7-1", Mod: alpm.DepModEq},
},
},
}
case "java-environment":
panic("not supposed to be called")
}
panic("implement me " + s)
},
PackagesFromGroupFn: func(string) []mock.IPackage { return nil },
LocalSatisfierExistsFn: func(s string) bool {
switch s {
case "java-environment":
return false
}
switch s {
case "libxtst", "fontconfig", "freetype2", "lib32-gcc-libs", "lib32-glibc", "libx11", "libxext", "libxrender", "zlib", "gcc-libs":
return true
}
panic("implement me " + s)
},
}
mockAUR := &mockaur.MockAUR{GetFn: func(ctx context.Context, query *aurc.Query) ([]aur.Pkg, error) {
if query.Needles[0] == "android-sdk" {
jfinFn := getFromFile(t, "testdata/android-sdk.json")
return jfinFn(ctx, query)
}
panic(fmt.Sprintf("implement me %v", query.Needles))
}}
type fields struct {
dbExecutor db.Executor
aurCache aurc.QueryClient
noDeps bool
noCheckDeps bool
}
type args struct {
targets []string
}
tests := []struct {
name string
fields fields
args args
want []map[string]*InstallInfo
wantErr bool
}{
{
name: "explicit dep",
fields: fields{
dbExecutor: mockDB,
aurCache: mockAUR,
noDeps: false,
noCheckDeps: false,
},
args: args{
targets: []string{"android-sdk", "jdk11-openjdk"},
},
want: []map[string]*InstallInfo{
{
"android-sdk": {
Source: AUR,
Reason: Explicit,
Version: "26.1.1-2",
AURBase: ptrString("android-sdk"),
},
},
{
"jdk11-openjdk": {
Source: Sync,
Reason: Explicit,
Version: "11.0.12.u7-1",
SyncDBName: ptrString("community"),
},
},
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
g := NewGrapher(tt.fields.dbExecutor,
tt.fields.aurCache, false, true,
tt.fields.noDeps, tt.fields.noCheckDeps, false,
text.NewLogger(io.Discard, io.Discard, &os.File{}, true, "test"))
got, err := g.GraphFromTargets(context.Background(), nil, tt.args.targets)
require.NoError(t, err)
layers := got.TopoSortedLayerMap(nil)
require.EqualValues(t, tt.want, layers, layers)
})
}
}
+3
View File
@@ -0,0 +1,3 @@
[
{"ID":1055234,"Name":"android-sdk","PackageBaseID":13751,"PackageBase":"android-sdk","Version":"26.1.1-2","Description":"Google Android SDK","URL":"https://developer.android.com/studio/releases/sdk-tools.html","NumVotes":1487,"Popularity":0.802316,"OutOfDate":null,"Maintainer":"dreamingincode","Submitter":null,"FirstSubmitted":1194895596,"LastModified":1647982720,"URLPath":"/cgit/aur.git/snapshot/android-sdk.tar.gz","Depends":["java-environment","libxtst","fontconfig","freetype2","lib32-gcc-libs","lib32-glibc","libx11","libxext","libxrender","zlib","gcc-libs"],"OptDepends":["android-emulator","android-sdk-platform-tools","android-udev"],"License":["custom"],"Keywords":["android","development"]}
]
+31 -2
View File
@@ -4,12 +4,15 @@ import (
"fmt"
"strings"
"github.com/Jguer/go-alpm/v2"
"github.com/Jguer/yay/v12/pkg/text"
)
type (
NodeSet[T comparable] map[T]bool
DepMap[T comparable] map[T]NodeSet[T]
NodeSet[T comparable] map[T]bool
ProvidesMap[T comparable] map[T]*DependencyInfo[T]
DepMap[T comparable] map[T]NodeSet[T]
)
func (n NodeSet[T]) Slice() []T {
@@ -28,6 +31,11 @@ type NodeInfo[V any] struct {
Value V
}
type DependencyInfo[T comparable] struct {
Provider T
alpm.Depend
}
type CheckFn[T comparable, V any] func(T, V) error
type Graph[T comparable, V any] struct {
@@ -36,6 +44,9 @@ type Graph[T comparable, V any] struct {
// node info map
nodeInfo map[T]*NodeInfo[V]
// `provides` tracks provides -> node.
provides ProvidesMap[T]
// `dependencies` tracks child -> parents.
dependencies DepMap[T]
// `dependents` tracks parent -> children.
@@ -48,6 +59,7 @@ func New[T comparable, V any]() *Graph[T, V] {
dependencies: make(DepMap[T]),
dependents: make(DepMap[T]),
nodeInfo: make(map[T]*NodeInfo[V]),
provides: make(ProvidesMap[T]),
}
}
@@ -65,6 +77,23 @@ func (g *Graph[T, V]) AddNode(node T) {
g.nodes[node] = true
}
func (g *Graph[T, V]) ProvidesExists(provides T) bool {
_, ok := g.provides[provides]
return ok
}
func (g *Graph[T, V]) GetProviderNode(provides T) *DependencyInfo[T] {
return g.provides[provides]
}
func (g *Graph[T, V]) Provides(provides T, depInfo *alpm.Depend, node T) {
g.provides[provides] = &DependencyInfo[T]{
Provider: node,
Depend: *depInfo,
}
}
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 {