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(scan) detect the dependencies for each updatable packages #1327

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
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: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ require (
github.com/briandowns/spinner v1.16.0 // indirect
github.com/cenkalti/backoff v2.2.1+incompatible
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/cheggaaa/pb/v3 v3.0.8 // indirect
github.com/cheggaaa/pb v1.0.27
github.com/d4l3k/messagediff v1.2.2-0.20190829033028-7e0a312ae40b
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21
github.com/emersion/go-smtp v0.14.0
Expand Down Expand Up @@ -87,6 +87,7 @@ require (
github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46 // indirect
github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492 // indirect
github.com/caarlos0/env/v6 v6.0.0 // indirect
github.com/cheggaaa/pb/v3 v3.0.8 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/form3tech-oss/jwt-go v3.2.2+incompatible // indirect
Expand Down Expand Up @@ -142,7 +143,7 @@ require (
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.19.1 // indirect
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 // indirect
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 // indirect
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.27.1 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2013,8 +2013,8 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 h1:2B5p2L5IfGiD7+b9BOoRMC6DgObAVZV+Fsp050NqXik=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M=
Expand Down
37 changes: 37 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 @@ -84,6 +109,18 @@ type Package struct {
Changelog *Changelog `json:"changelog,omitempty"`
AffectedProcs []AffectedProcess `json:",omitempty"`
NeedRestartProcs []NeedRestartProcess `json:",omitempty"`

// Dependencies are dependent packages
Dependencies []string `json:",omitempty"`

// 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"`
}

// FQPN returns Fully-Qualified-Package-Name
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)
}
})
}
}
Loading