Skip to content

Commit

Permalink
reverse deps recursively
Browse files Browse the repository at this point in the history
  • Loading branch information
kotakanbe committed Nov 5, 2021
1 parent fb9cebd commit 79c7fc9
Show file tree
Hide file tree
Showing 3 changed files with 193 additions and 1 deletion.
28 changes: 28 additions & 0 deletions models/packages.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,31 @@ func (ps Packages) FindByFQPN(nameVerRel string) (*Package, error) {
return nil, xerrors.Errorf("Failed to find the package: %s", nameVerRel)
}

// ResolveReverseDepsRecursively resolve and set reverse dependencies for each packages recursively
func (ps Packages) ResolveReverseDepsRecursively() {
for name, pkg := range ps {
depsmap := ps.resolveReverseDeps(pkg, map[string]struct{}{})
delete(depsmap, pkg.Name)
for depname := range depsmap {
pkg.ReverseDependenciesRecursively = append(pkg.ReverseDependenciesRecursively, depname)
}
ps[name] = pkg
}
}

func (ps Packages) resolveReverseDeps(pkg Package, acc map[string]struct{}) map[string]struct{} {
acc[pkg.Name] = struct{}{}
for _, name := range pkg.ReverseDependencies {
if _, ok := acc[name]; ok {
continue
}
if p, ok := ps[name]; ok {
acc = ps.resolveReverseDeps(p, acc)
}
}
return acc
}

// Package has installed binary packages.
type Package struct {
Name string `json:"name"`
Expand All @@ -91,6 +116,9 @@ type Package struct {
// ReverseDependencies are packages which depend on this package
ReverseDependencies []string `json:",omitempty"`

// ReverseDependencies are packages which depend on this package
ReverseDependenciesRecursively []string `json:",omitempty"`

// DependenciesForUpdate are packages that needs to be updated together
DependenciesForUpdate []string `json:",omitempty"`
}
Expand Down
163 changes: 163 additions & 0 deletions models/packages_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -428,3 +428,166 @@ func Test_NewPortStat(t *testing.T) {
})
}
}

func TestPackages_resolveReverseDeps(t *testing.T) {
type args struct {
pkg Package
acc map[string]struct{}
}
tests := []struct {
name string
ps Packages
args args
want map[string]struct{}
}{
{
name: "",
ps: map[string]Package{
"pkgA": {
Name: "pkgA",
ReverseDependencies: []string{"pkgB"},
},
"pkgB": {
Name: "pkgB",
ReverseDependencies: []string{"pkgC"},
},
"pkgC": {
Name: "pkgC",
ReverseDependencies: []string{""},
},
},
args: args{
pkg: Package{
Name: "pkgA",
ReverseDependencies: []string{"pkgB"},
},
acc: map[string]struct{}{},
},
want: map[string]struct{}{
"pkgA": {},
"pkgB": {},
"pkgC": {},
},
},
{
name: "",
ps: map[string]Package{
"pkgA": {
Name: "pkgA",
ReverseDependencies: []string{"pkgB"},
},
"pkgB": {
Name: "pkgB",
ReverseDependencies: []string{"pkgA", "pkgC"},
},
"pkgC": {
Name: "pkgC",
ReverseDependencies: []string{"pkgB"},
},
},
args: args{
pkg: Package{
Name: "pkgA",
ReverseDependencies: []string{"pkgB"},
},
acc: map[string]struct{}{},
},
want: map[string]struct{}{
"pkgA": {},
"pkgB": {},
"pkgC": {},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.ps.resolveReverseDeps(tt.args.pkg, tt.args.acc); !reflect.DeepEqual(got, tt.want) {
t.Errorf("Packages.resolveReverseDeps() = %v, want %v", got, tt.want)
}
})
}
}

func TestPackages_resolveReverseDepsRecursively(t *testing.T) {
tests := []struct {
name string
ps Packages
want Packages
}{
{
name: "",
ps: map[string]Package{
"pkgA": {
Name: "pkgA",
ReverseDependencies: []string{"pkgB"},
},
"pkgB": {
Name: "pkgB",
ReverseDependencies: []string{"pkgC"},
},
"pkgC": {
Name: "pkgC",
ReverseDependencies: []string{""},
},
},
want: map[string]Package{
"pkgA": {
Name: "pkgA",
ReverseDependencies: []string{"pkgB"},
ReverseDependenciesRecursively: []string{"pkgB", "pkgC"},
},
"pkgB": {
Name: "pkgB",
ReverseDependencies: []string{"pkgC"},
ReverseDependenciesRecursively: []string{"pkgC"},
},
"pkgC": {
Name: "pkgC",
ReverseDependencies: []string{""},
},
},
},
{
name: "",
ps: map[string]Package{
"pkgA": {
Name: "pkgA",
ReverseDependencies: []string{"pkgB"},
},
"pkgB": {
Name: "pkgB",
ReverseDependencies: []string{"pkgA", "pkgC"},
},
"pkgC": {
Name: "pkgC",
ReverseDependencies: []string{"pkgB"},
},
},
want: map[string]Package{
"pkgA": {
Name: "pkgA",
ReverseDependencies: []string{"pkgB"},
ReverseDependenciesRecursively: []string{"pkgB", "pkgC"},
},
"pkgB": {
Name: "pkgB",
ReverseDependencies: []string{"pkgA", "pkgC"},
ReverseDependenciesRecursively: []string{"pkgA", "pkgC"},
},
"pkgC": {
Name: "pkgC",
ReverseDependencies: []string{"pkgB"},
ReverseDependenciesRecursively: []string{"pkgA", "pkgB"},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.ps.ResolveReverseDepsRecursively()
if !reflect.DeepEqual(tt.ps, tt.want) {
t.Errorf("Packages.resolveReverseDepsRecursively() = \n%+v, want \n%+v", tt.ps, tt.want)
}
})
}
}
3 changes: 2 additions & 1 deletion scanner/redhatbase.go
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ func (o *redhatBase) scanPackages() (err error) {
resolver := yumDependentResolver{redhat: o}
resolver.detectDependenciesForUpdate()
resolver.detectReverseDependencies()
o.Packages.ResolveReverseDepsRecursively()
}

return nil
Expand Down Expand Up @@ -812,7 +813,7 @@ func (o *yumDependentResolver) detectReverseDependencies() {
}

func (o *yumDependentResolver) repoqueryWhatRequires(pkgName string) (depsPkgNames []string, err error) {
cmd := `LANGUAGE=en_US.UTF-8 repoquery --whatrequires --resolve --pkgnarrow=installed --qf "%{name}" ` + pkgName
cmd := `LANGUAGE=en_US.UTF-8 repoquery --cache --whatrequires --resolve --pkgnarrow=installed --qf "%{name}" ` + pkgName
r := o.redhat.exec(cmd, true)
if !r.isSuccess() {
return nil, xerrors.Errorf("Failed to SSH: %s", r)
Expand Down

0 comments on commit 79c7fc9

Please sign in to comment.