Implementation of all-matches functionality + tests

When performing an *aptly snapshot pull*, users might list dependency
versions that can potentially match multiple packages in the source
snapshot. However, the current implementation of the 'snapshot pull'
command only allows one package to be pulled from a snapshot at a time
for a given dependency.

The newly implemented all-matches flag allows users to pull all the
matching packages from a source snapshot, provided that they satisfy the
version requirements indicated by the dependencies.

The all-matches flag defaults to false and only produces the described
behaviour when it is explicitly set to true.
This commit is contained in:
Simon Aquino
2014-06-27 01:40:41 +01:00
parent 856dd7021c
commit 3cf281965b
7 changed files with 255 additions and 68 deletions
+36 -25
View File
@@ -18,6 +18,7 @@ func aptlySnapshotPull(cmd *commander.Command, args []string) error {
noDeps := context.flags.Lookup("no-deps").Value.Get().(bool) noDeps := context.flags.Lookup("no-deps").Value.Get().(bool)
noRemove := context.flags.Lookup("no-remove").Value.Get().(bool) noRemove := context.flags.Lookup("no-remove").Value.Get().(bool)
allMatches := context.flags.Lookup("all-matches").Value.Get().(bool)
// Load <name> snapshot // Load <name> snapshot
snapshot, err := context.CollectionFactory().SnapshotCollection().ByName(args[0]) snapshot, err := context.CollectionFactory().SnapshotCollection().ByName(args[0])
@@ -97,24 +98,30 @@ func aptlySnapshotPull(cmd *commander.Command, args []string) error {
dep := dependencies[i] dep := dependencies[i]
// Search for package that can satisfy dependencies // Search for package that can satisfy dependencies
pkg := sourcePackageList.Search(dep) searchResults := sourcePackageList.Search(dep, allMatches)
if pkg == nil { if searchResults == nil {
context.Progress().ColoredPrintf("@y[!]@| @!Dependency %s can't be satisfied with source %s@|", &dep, source) context.Progress().ColoredPrintf("@y[!]@| @!Dependency %s can't be satisfied with source %s@|", &dep, source)
continue continue
} }
if !noRemove { if !noRemove {
// Remove all packages with the same name and architecture // Remove all packages with the same name and architecture
for p := packageList.Search(deb.Dependency{Architecture: pkg.Architecture, Pkg: pkg.Name}); p != nil; { for _, pkg := range searchResults {
packageList.Remove(p) for pS := packageList.Search(deb.Dependency{Architecture: pkg.Architecture, Pkg: pkg.Name}, allMatches); pS != nil; {
context.Progress().ColoredPrintf("@r[-]@| %s removed", p) for _, p := range pS {
p = packageList.Search(deb.Dependency{Architecture: pkg.Architecture, Pkg: pkg.Name}) packageList.Remove(p)
context.Progress().ColoredPrintf("@r[-]@| %s removed", p)
}
pS = packageList.Search(deb.Dependency{Architecture: pkg.Architecture, Pkg: pkg.Name}, allMatches)
}
} }
} }
// Add new discovered package // Add new discovered package
packageList.Add(pkg) for _, pkg := range searchResults {
context.Progress().ColoredPrintf("@g[+]@| %s added", pkg) packageList.Add(pkg)
context.Progress().ColoredPrintf("@g[+]@| %s added", pkg)
}
if noDeps { if noDeps {
continue continue
@@ -122,26 +129,28 @@ func aptlySnapshotPull(cmd *commander.Command, args []string) error {
// Find missing dependencies for single added package // Find missing dependencies for single added package
pL := deb.NewPackageList() pL := deb.NewPackageList()
pL.Add(pkg) for _, pkg := range searchResults {
pL.Add(pkg)
var missing []deb.Dependency var missing []deb.Dependency
missing, err = pL.VerifyDependencies(context.DependencyOptions(), []string{arch}, packageList, nil) missing, err = pL.VerifyDependencies(context.DependencyOptions(), []string{arch}, packageList, nil)
if err != nil { if err != nil {
context.Progress().ColoredPrintf("@y[!]@| @!Error while verifying dependencies for pkg %s: %s@|", pkg, err) context.Progress().ColoredPrintf("@y[!]@| @!Error while verifying dependencies for pkg %s: %s@|", pkg, err)
}
// Append missing dependencies to the list of dependencies to satisfy
for _, misDep := range missing {
found := false
for _, d := range dependencies {
if d == misDep {
found = true
break
}
} }
if !found { // Append missing dependencies to the list of dependencies to satisfy
dependencies = append(dependencies, misDep) for _, misDep := range missing {
found := false
for _, d := range dependencies {
if d == misDep {
found = true
break
}
}
if !found {
dependencies = append(dependencies, misDep)
}
} }
} }
} }
@@ -186,6 +195,8 @@ Example:
cmd.Flag.Bool("dry-run", false, "don't create destination snapshot, just show what would be pulled") cmd.Flag.Bool("dry-run", false, "don't create destination snapshot, just show what would be pulled")
cmd.Flag.Bool("no-deps", false, "don't process dependencies, just pull listed packages") cmd.Flag.Bool("no-deps", false, "don't process dependencies, just pull listed packages")
cmd.Flag.Bool("no-remove", false, "don't remove other package versions when pulling package") cmd.Flag.Bool("no-remove", false, "don't remove other package versions when pulling package")
cmd.Flag.Bool("all-matches", false, "pull all the packages that satisfy the dependency version requirements")
return cmd return cmd
} }
+31 -11
View File
@@ -263,7 +263,7 @@ func (l *PackageList) VerifyDependencies(options int, architectures []string, so
continue continue
} }
if sources.Search(dep) == nil { if sources.Search(dep, false) == nil {
variantsMissing = append(variantsMissing, dep) variantsMissing = append(variantsMissing, dep)
missingCount++ missingCount++
} else { } else {
@@ -326,29 +326,47 @@ func (l *PackageList) PrepareIndex() {
} }
// Search searches package index for specified package // Search searches package index for specified package
func (l *PackageList) Search(dep Dependency) *Package { func (l *PackageList) Search(dep Dependency, allMatches bool) []*Package {
if !l.indexed { if !l.indexed {
panic("list not indexed, can't search") panic("list not indexed, can't search")
} }
searchResults := []*Package{}
if dep.Relation == VersionDontCare { if dep.Relation == VersionDontCare {
for _, p := range l.providesIndex[dep.Pkg] { for _, p := range l.providesIndex[dep.Pkg] {
if p.MatchesArchitecture(dep.Architecture) { if p.MatchesArchitecture(dep.Architecture) {
return p searchResults = append(searchResults, p)
if !allMatches {
break
}
} }
} }
if len(searchResults) != 0 {
return searchResults
}
} }
i := sort.Search(len(l.packagesIndex), func(j int) bool { return l.packagesIndex[j].Name >= dep.Pkg }) i := sort.Search(len(l.packagesIndex), func(j int) bool { return l.packagesIndex[j].Name >= dep.Pkg })
for i < len(l.packagesIndex) && l.packagesIndex[i].Name == dep.Pkg { for i < len(l.packagesIndex) && l.packagesIndex[i].Name == dep.Pkg {
p := l.packagesIndex[i] p := l.packagesIndex[i]
if p.MatchesDependency(dep) { if p.MatchesDependency(dep, allMatches) {
return p searchResults = append(searchResults, p)
if !allMatches {
break
}
} }
i++ i++
} }
if len(searchResults) != 0 {
return searchResults
}
return nil return nil
} }
@@ -396,7 +414,7 @@ func (l *PackageList) Filter(queries []string, withDependencies bool, source *Pa
for i < len(l.packagesIndex) && l.packagesIndex[i].Name == dep.Pkg { for i < len(l.packagesIndex) && l.packagesIndex[i].Name == dep.Pkg {
p := l.packagesIndex[i] p := l.packagesIndex[i]
if p.MatchesDependency(dep) { if p.MatchesDependency(dep, false) {
result.Add(p) result.Add(p)
} }
i++ i++
@@ -423,11 +441,13 @@ func (l *PackageList) Filter(queries []string, withDependencies bool, source *Pa
// try to satisfy dependencies // try to satisfy dependencies
for _, dep := range missing { for _, dep := range missing {
p := l.Search(dep) searchResults := l.Search(dep, false)
if p != nil { if searchResults != nil {
result.Add(p) for _, p := range searchResults {
dependencySource.Add(p) result.Add(p)
added++ dependencySource.Add(p)
added++
}
} }
} }
} }
+95 -16
View File
@@ -7,6 +7,43 @@ import (
"strings" "strings"
) )
type containsChecker struct {
*CheckerInfo
}
func (c *containsChecker) Check(params []interface{}, names []string) (result bool, error string) {
var (
pkgSlice1 []*Package
pkgSlice2 []*Package
ok bool
)
pkgMap := make (map[*Package]bool)
pkgSlice1, ok = params[0].([]*Package)
if !ok {
return false, "The first parameter is not a Package slice"
}
pkgSlice2, ok = params[1].([]*Package)
if !ok {
return false, "The second parameter is not a Package slice"
}
for _, pkg := range pkgSlice2 {
pkgMap[pkg] = true
}
for _, pkg := range pkgSlice1 {
if _, ok := pkgMap[pkg]; !ok {
return false, ""
}
}
return true, ""
}
var Contains Checker = &containsChecker{&CheckerInfo{Name: "Contains", Params: []string{"Container", "Expected to contain"}}}
type PackageListSuite struct { type PackageListSuite struct {
// Simple list with "real" packages from stanzas // Simple list with "real" packages from stanzas
list *PackageList list *PackageList
@@ -14,8 +51,10 @@ type PackageListSuite struct {
// Mocked packages in list // Mocked packages in list
packages []*Package packages []*Package
packages2 []*Package
sourcePackages []*Package sourcePackages []*Package
il *PackageList il *PackageList
il2 *PackageList
} }
var _ = Suite(&PackageListSuite{}) var _ = Suite(&PackageListSuite{})
@@ -60,6 +99,20 @@ func (s *PackageListSuite) SetUpTest(c *C) {
} }
s.il.PrepareIndex() s.il.PrepareIndex()
s.il2 = NewPackageList()
s.packages2 = []*Package{
&Package{Name: "mailer", Version: "3.5.8", Architecture: "amd64", Source: "postfix (1.3)", Provides: []string{"mail-agent"}, deps: &PackageDependencies{}},
&Package{Name: "sendmail", Version: "1.0", Architecture: "amd64", Source: "postfix (1.3)", Provides: []string{"mail-agent"}, deps: &PackageDependencies{}},
&Package{Name: "app", Version: "1.1-bp1", Architecture: "amd64", deps: &PackageDependencies{PreDepends: []string{"dpkg (>= 1.6)"}, Depends: []string{"lib (>> 0.9)", "data (>= 1.0)"}}},
&Package{Name: "app", Version: "1.1-bp2", Architecture: "amd64", deps: &PackageDependencies{PreDepends: []string{"dpkg (>= 1.6)"}, Depends: []string{"lib (>> 0.9)", "data (>= 1.0)"}}},
&Package{Name: "app", Version: "1.2", Architecture: "amd64", deps: &PackageDependencies{PreDepends: []string{"dpkg (>= 1.6)"}, Depends: []string{"lib (>> 0.9) | libx (>= 1.5)", "data (>= 1.0) | mail-agent"}}},
&Package{Name: "app", Version: "3.0", Architecture: "amd64", deps: &PackageDependencies{PreDepends: []string{"dpkg >= 1.6)"}, Depends: []string{"lib (>> 0.9)", "data (>= 1.0)"}}},
}
for _, p := range s.packages2 {
s.il2.Add(p)
}
s.il2.PrepareIndex()
s.sourcePackages = []*Package{ s.sourcePackages = []*Package{
&Package{Name: "postfix", Version: "1.3", Architecture: "source", SourceArchitecture: "any", IsSource: true, deps: &PackageDependencies{}}, &Package{Name: "postfix", Version: "1.3", Architecture: "source", SourceArchitecture: "any", IsSource: true, deps: &PackageDependencies{}},
&Package{Name: "app", Version: "1.1~bp1", Architecture: "source", SourceArchitecture: "any", IsSource: true, deps: &PackageDependencies{}}, &Package{Name: "app", Version: "1.1~bp1", Architecture: "source", SourceArchitecture: "any", IsSource: true, deps: &PackageDependencies{}},
@@ -196,28 +249,54 @@ func (s *PackageListSuite) TestAppend(c *C) {
} }
func (s *PackageListSuite) TestSearch(c *C) { func (s *PackageListSuite) TestSearch(c *C) {
c.Check(func() { s.list.Search(Dependency{Architecture: "i386", Pkg: "app"}) }, Panics, "list not indexed, can't search") //allMatches = False
c.Check(func() { s.list.Search(Dependency{Architecture: "i386", Pkg: "app"}, false) }, Panics, "list not indexed, can't search")
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app"}), Equals, s.packages[3]) c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app"}, false), DeepEquals, []*Package{s.packages[3]})
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "mail-agent"}), Equals, s.packages[4]) c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "mail-agent"}, false), DeepEquals, []*Package{s.packages[4]})
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "puppy"}), IsNil) c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "puppy"}, false), IsNil)
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionEqual, Version: "1.1~bp1"}), Equals, s.packages[3]) c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionEqual, Version: "1.1~bp1"}, false), DeepEquals, []*Package{s.packages[3]})
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionEqual, Version: "1.1~bp2"}), IsNil) c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionEqual, Version: "1.1~bp2"}, false), IsNil)
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionLess, Version: "1.1"}), Equals, s.packages[3]) c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionLess, Version: "1.1"}, false), DeepEquals, []*Package{s.packages[3]})
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionLess, Version: "1.1~~"}), IsNil) c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionLess, Version: "1.1~~"}, false), IsNil)
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionLessOrEqual, Version: "1.1"}), Equals, s.packages[3]) c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionLessOrEqual, Version: "1.1"}, false), DeepEquals, []*Package{s.packages[3]})
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionLessOrEqual, Version: "1.1~bp1"}), Equals, s.packages[3]) c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionLessOrEqual, Version: "1.1~bp1"}, false), DeepEquals, []*Package{s.packages[3]})
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionLessOrEqual, Version: "1.1~~"}), IsNil) c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionLessOrEqual, Version: "1.1~~"}, false), IsNil)
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionGreater, Version: "1.0"}), Equals, s.packages[3]) c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionGreater, Version: "1.0"}, false), DeepEquals, []*Package{s.packages[3]})
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionGreater, Version: "1.2"}), IsNil) c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionGreater, Version: "1.2"}, false), IsNil)
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionGreaterOrEqual, Version: "1.0"}, false), DeepEquals, []*Package{s.packages[3]})
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionGreaterOrEqual, Version: "1.1~bp1"}, false), DeepEquals, []*Package{s.packages[3]})
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionGreaterOrEqual, Version: "1.2"}, false), IsNil)
// allMatches = True
c.Check(s.il2.Search(Dependency{Architecture: "amd64", Pkg: "app"}, true), Contains, []*Package{s.packages2[2], s.packages2[3], s.packages2[4], s.packages2[5]})
c.Check(s.il2.Search(Dependency{Architecture: "amd64", Pkg: "mail-agent"}, true), Contains, []*Package{s.packages2[0], s.packages2[1]})
c.Check(s.il2.Search(Dependency{Architecture: "amd64", Pkg: "puppy"}, true), IsNil)
c.Check(s.il2.Search(Dependency{Architecture: "amd64", Pkg: "app", Relation: VersionEqual, Version: "1.1"}, true), Contains, []*Package{s.packages2[2], s.packages2[3]})
c.Check(s.il2.Search(Dependency{Architecture: "amd64", Pkg: "app", Relation: VersionEqual, Version: "1.1"}, true), Contains, []*Package{s.packages2[2], s.packages2[3]})
c.Check(s.il2.Search(Dependency{Architecture: "amd64", Pkg: "app", Relation: VersionEqual, Version: "3"}, true), Contains, []*Package{s.packages2[5]})
c.Check(s.il2.Search(Dependency{Architecture: "amd64", Pkg: "app", Relation: VersionLess, Version: "1.2"}, true), Contains, []*Package{s.packages2[2], s.packages2[3]})
c.Check(s.il2.Search(Dependency{Architecture: "amd64", Pkg: "app", Relation: VersionLess, Version: "1.1~"}, true), IsNil)
c.Check(s.il2.Search(Dependency{Architecture: "amd64", Pkg: "app", Relation: VersionLessOrEqual, Version: "1.2"}, true), Contains, []*Package{s.packages2[2], s.packages2[3], s.packages2[4]})
c.Check(s.il2.Search(Dependency{Architecture: "amd64", Pkg: "app", Relation: VersionLessOrEqual, Version: "1.1-bp1"}, true), Contains, []*Package{s.packages2[2]})
c.Check(s.il2.Search(Dependency{Architecture: "amd64", Pkg: "app", Relation: VersionLessOrEqual, Version: "1.0"}, true), IsNil)
c.Check(s.il2.Search(Dependency{Architecture: "amd64", Pkg: "app", Relation: VersionGreater, Version: "1.1"}, true), Contains, []*Package{s.packages2[2], s.packages2[3], s.packages2[4], s.packages2[5]})
c.Check(s.il2.Search(Dependency{Architecture: "amd64", Pkg: "app", Relation: VersionGreater, Version: "5.0"}, true), IsNil)
c.Check(s.il2.Search(Dependency{Architecture: "amd64", Pkg: "app", Relation: VersionGreaterOrEqual, Version: "1.2"}, true), Contains, []*Package{s.packages2[4], s.packages2[5]})
c.Check(s.il2.Search(Dependency{Architecture: "amd64", Pkg: "app", Relation: VersionGreaterOrEqual, Version: "1.1~bp1"}, true), Contains, []*Package{s.packages2[2], s.packages2[3], s.packages2[4], s.packages2[5]})
c.Check(s.il2.Search(Dependency{Architecture: "amd64", Pkg: "app", Relation: VersionGreaterOrEqual, Version: "5.0"}, true), IsNil)
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionGreaterOrEqual, Version: "1.0"}), Equals, s.packages[3])
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionGreaterOrEqual, Version: "1.1~bp1"}), Equals, s.packages[3])
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionGreaterOrEqual, Version: "1.2"}), IsNil)
} }
func (s *PackageListSuite) TestFilter(c *C) { func (s *PackageListSuite) TestFilter(c *C) {
+8 -2
View File
@@ -198,7 +198,7 @@ func (p *Package) MatchesArchitecture(arch string) bool {
} }
// MatchesDependency checks whether package matches specified dependency // MatchesDependency checks whether package matches specified dependency
func (p *Package) MatchesDependency(dep Dependency) bool { func (p *Package) MatchesDependency(dep Dependency, allMatches bool) bool {
if dep.Pkg != p.Name { if dep.Pkg != p.Name {
return false return false
} }
@@ -212,9 +212,15 @@ func (p *Package) MatchesDependency(dep Dependency) bool {
} }
r := CompareVersions(p.Version, dep.Version) r := CompareVersions(p.Version, dep.Version)
switch dep.Relation { switch dep.Relation {
case VersionEqual: case VersionEqual:
return r == 0 if allMatches {
rn := CompareVersions(p.Version, dep.NextVersion())
return r+rn == 0 || r == 0
} else {
return r == 0
}
case VersionLess: case VersionLess:
return r < 0 return r < 0
case VersionGreater: case VersionGreater:
+20 -14
View File
@@ -172,38 +172,44 @@ func (s *PackageSuite) TestMatchesDependency(c *C) {
p := NewPackageFromControlFile(s.stanza) p := NewPackageFromControlFile(s.stanza)
// exact match // exact match
c.Check(p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "i386", Relation: VersionEqual, Version: "7.40-2"}), Equals, true) c.Check(p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "i386", Relation: VersionEqual, Version: "7.40-2"}, false), Equals, true)
// exact match, same version, no revision specified
c.Check(p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "i386", Relation: VersionEqual, Version: "7.40"}, false), Equals, false)
// non-exact match, same version, no revision specified
c.Check(p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "i386", Relation: VersionEqual, Version: "7.40"}, true), Equals, true)
// different name // different name
c.Check(p.MatchesDependency(Dependency{Pkg: "alien-arena", Architecture: "i386", Relation: VersionEqual, Version: "7.40-2"}), Equals, false) c.Check(p.MatchesDependency(Dependency{Pkg: "alien-arena", Architecture: "i386", Relation: VersionEqual, Version: "7.40-2"}, false), Equals, false)
// different version // different version
c.Check(p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "i386", Relation: VersionEqual, Version: "7.40-3"}), Equals, false) c.Check(p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "i386", Relation: VersionEqual, Version: "7.40-3"}, false), Equals, false)
// different arch // different arch
c.Check(p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "amd64", Relation: VersionEqual, Version: "7.40-2"}), Equals, false) c.Check(p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "amd64", Relation: VersionEqual, Version: "7.40-2"}, false), Equals, false)
// empty arch // empty arch
c.Check(p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "", Relation: VersionEqual, Version: "7.40-2"}), Equals, true) c.Check(p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "", Relation: VersionEqual, Version: "7.40-2"}, false), Equals, true)
// version don't care // version don't care
c.Check(p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "i386", Relation: VersionDontCare, Version: ""}), Equals, true) c.Check(p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "i386", Relation: VersionDontCare, Version: ""}, false), Equals, true)
// > // >
c.Check(p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "i386", Relation: VersionGreater, Version: "7.40-2"}), Equals, false) c.Check(p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "i386", Relation: VersionGreater, Version: "7.40-2"}, false), Equals, false)
c.Check(p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "i386", Relation: VersionGreater, Version: "7.40-1"}), Equals, true) c.Check(p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "i386", Relation: VersionGreater, Version: "7.40-1"}, false), Equals, true)
// < // <
c.Check(p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "i386", Relation: VersionLess, Version: "7.40-2"}), Equals, false) c.Check(p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "i386", Relation: VersionLess, Version: "7.40-2"}, false), Equals, false)
c.Check(p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "i386", Relation: VersionLess, Version: "7.40-3"}), Equals, true) c.Check(p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "i386", Relation: VersionLess, Version: "7.40-3"}, false), Equals, true)
// >= // >=
c.Check(p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "i386", Relation: VersionGreaterOrEqual, Version: "7.40-2"}), Equals, true) c.Check(p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "i386", Relation: VersionGreaterOrEqual, Version: "7.40-2"}, false), Equals, true)
c.Check(p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "i386", Relation: VersionGreaterOrEqual, Version: "7.40-3"}), Equals, false) c.Check(p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "i386", Relation: VersionGreaterOrEqual, Version: "7.40-3"}, false), Equals, false)
// <= // <=
c.Check(p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "i386", Relation: VersionLessOrEqual, Version: "7.40-2"}), Equals, true) c.Check(p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "i386", Relation: VersionLessOrEqual, Version: "7.40-2"}, false), Equals, true)
c.Check(p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "i386", Relation: VersionLessOrEqual, Version: "7.40-1"}), Equals, false) c.Check(p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "i386", Relation: VersionLessOrEqual, Version: "7.40-1"}, false), Equals, false)
} }
func (s *PackageSuite) TestGetDependencies(c *C) { func (s *PackageSuite) TestGetDependencies(c *C) {
+23
View File
@@ -188,6 +188,29 @@ type Dependency struct {
Architecture string Architecture string
} }
// NextVersion returns the next version of a dependency (eg. if d.Version = 1.9, it returns 1.10)
func (d *Dependency) NextVersion() string {
l := len(d.Version)
if l == 0 {
return ""
}
i := l
for i > 0 {
_, err := strconv.ParseUint(d.Version[i-1:l],10,0)
if err != nil { break }
i--
}
v, err := strconv.ParseUint(d.Version[i:l],10,0)
if err != nil {
return d.Version
}
return d.Version[0:i] + strconv.Itoa(int(v)+1)
}
// Hash calculates some predefined unique ID of Dependency // Hash calculates some predefined unique ID of Dependency
func (d *Dependency) Hash() string { func (d *Dependency) Hash() string {
return fmt.Sprintf("%s:%s:%d:%s", d.Architecture, d.Pkg, d.Relation, d.Version) return fmt.Sprintf("%s:%s:%d:%s", d.Architecture, d.Pkg, d.Relation, d.Version)
+42
View File
@@ -217,3 +217,45 @@ func (s *VersionSuite) TestDependencyString(c *C) {
d.Architecture = "i386" d.Architecture = "i386"
c.Check(d.String(), Equals, "dpkg [i386]") c.Check(d.String(), Equals, "dpkg [i386]")
} }
func (s *VersionSuite) TestDependencyNextVersion(c *C){
d, _ := ParseDependency("dpkg(=1.7)")
d.Architecture = "i386"
c.Check(d.NextVersion(), Equals, "1.8")
d, _ = ParseDependency("dpkg(=1.9)")
d.Architecture = "i386"
c.Check(d.NextVersion(), Equals, "1.10")
d, _ = ParseDependency("dpkg(=9)")
d.Architecture = "i386"
c.Check(d.NextVersion(), Equals, "10")
d, _ = ParseDependency("dpkg(=9.909)")
d.Architecture = "i386"
c.Check(d.NextVersion(), Equals, "9.910")
d, _ = ParseDependency("dpkg(=9.0.9)")
d.Architecture = "i386"
c.Check(d.NextVersion(), Equals, "9.0.10")
d, _ = ParseDependency("dpkg(=9.0.100)")
d.Architecture = "i386"
c.Check(d.NextVersion(), Equals, "9.0.101")
d, _ = ParseDependency("dpkg(=9.0.0-209)")
d.Architecture = "i386"
c.Check(d.NextVersion(), Equals, "9.0.0-210")
d, _ = ParseDependency("dpkg(=9.0.0-209rel)")
d.Architecture = "i386"
c.Check(d.NextVersion(), Equals, "9.0.0-209rel")
d, _ = ParseDependency("dpkg(=9.0.0-rel219)")
d.Architecture = "i386"
c.Check(d.NextVersion(), Equals, "9.0.0-rel220")
d, _ = ParseDependency("dpkg")
d.Architecture = "i386"
c.Check(d.NextVersion(), Equals, "")
}