mirror of
https://github.com/mudler/luet.git
synced 2025-08-31 14:52:02 +00:00
Review version comparision logic
This commit is contained in:
committed by
Ettore Di Giacinto
parent
bbeb800611
commit
91d05b071d
@@ -20,7 +20,6 @@ import (
|
||||
"encoding/json"
|
||||
"sync"
|
||||
|
||||
version "github.com/hashicorp/go-version"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -178,16 +177,11 @@ func (db *InMemoryDatabase) getProvide(p Package) (Package, error) {
|
||||
|
||||
for ve, _ := range versions {
|
||||
|
||||
v, err := version.NewVersion(p.GetVersion())
|
||||
match, err := p.VersionMatchSelector(ve)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "Error on match version")
|
||||
}
|
||||
constraints, err := version.NewConstraint(ve)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if constraints.Check(v) {
|
||||
if match {
|
||||
pa, ok := db.ProvidesDatabase[p.GetPackageName()][ve]
|
||||
if !ok {
|
||||
return nil, errors.New("No versions found for package")
|
||||
@@ -257,15 +251,12 @@ func (db *InMemoryDatabase) FindPackages(p Package) ([]Package, error) {
|
||||
}
|
||||
var versionsInWorld []Package
|
||||
for ve, _ := range versions {
|
||||
v, err := version.NewVersion(ve)
|
||||
match, err := p.SelectorMatchVersion(ve)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "Error on match selector")
|
||||
}
|
||||
constraints, err := version.NewConstraint(p.GetVersion())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if constraints.Check(v) {
|
||||
|
||||
if match {
|
||||
w, err := db.FindPackage(&DefaultPackage{Name: p.GetName(), Category: p.GetCategory(), Version: ve})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Cache mismatch - this shouldn't happen")
|
||||
|
@@ -83,6 +83,8 @@ type Package interface {
|
||||
GetLicense() string
|
||||
|
||||
IsSelector() bool
|
||||
VersionMatchSelector(string) (bool, error)
|
||||
SelectorMatchVersion(string) (bool, error)
|
||||
}
|
||||
|
||||
type Tree interface {
|
||||
@@ -322,15 +324,11 @@ func (p *DefaultPackage) Expand(definitiondb PackageDatabase) ([]Package, error)
|
||||
return nil, err
|
||||
}
|
||||
for _, w := range all {
|
||||
v, err := version.NewVersion(w.GetVersion())
|
||||
match, err := p.SelectorMatchVersion(w.GetVersion())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
constraints, err := version.NewConstraint(p.GetVersion())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if constraints.Check(v) {
|
||||
if match {
|
||||
versionsInWorld = append(versionsInWorld, w)
|
||||
}
|
||||
}
|
||||
|
262
pkg/package/version.go
Normal file
262
pkg/package/version.go
Normal file
@@ -0,0 +1,262 @@
|
||||
// Copyright © 2019 Ettore Di Giacinto <mudler@gentoo.org>,
|
||||
// Daniele Rondina <geaaru@sabayonlinux.org>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
version "github.com/hashicorp/go-version"
|
||||
)
|
||||
|
||||
// Package Selector Condition
|
||||
type PkgSelectorCondition int
|
||||
|
||||
type PkgVersionSelector struct {
|
||||
Version string
|
||||
VersionSuffix string
|
||||
Condition PkgSelectorCondition
|
||||
// TODO: Integrate support for multiple repository
|
||||
}
|
||||
|
||||
const (
|
||||
PkgCondInvalid = 0
|
||||
// >
|
||||
PkgCondGreater = 1
|
||||
// >=
|
||||
PkgCondGreaterEqual = 2
|
||||
// <
|
||||
PkgCondLess = 3
|
||||
// <=
|
||||
PkgCondLessEqual = 4
|
||||
// =
|
||||
PkgCondEqual = 5
|
||||
// !
|
||||
PkgCondNot = 6
|
||||
// ~
|
||||
PkgCondAnyRevision = 7
|
||||
// =<pkg>*
|
||||
PkgCondMatchVersion = 8
|
||||
)
|
||||
|
||||
func ParseVersion(v string) (PkgVersionSelector, error) {
|
||||
var ans PkgVersionSelector = PkgVersionSelector{
|
||||
Version: "",
|
||||
VersionSuffix: "",
|
||||
Condition: PkgCondInvalid,
|
||||
}
|
||||
|
||||
if strings.HasPrefix(v, ">=") {
|
||||
v = v[2:]
|
||||
ans.Condition = PkgCondGreaterEqual
|
||||
} else if strings.HasPrefix(v, ">") {
|
||||
v = v[1:]
|
||||
ans.Condition = PkgCondGreater
|
||||
} else if strings.HasPrefix(v, "<=") {
|
||||
v = v[2:]
|
||||
ans.Condition = PkgCondLessEqual
|
||||
} else if strings.HasPrefix(v, "<") {
|
||||
v = v[1:]
|
||||
ans.Condition = PkgCondLess
|
||||
} else if strings.HasPrefix(v, "=") {
|
||||
v = v[1:]
|
||||
if strings.HasSuffix(v, "*") {
|
||||
ans.Condition = PkgCondMatchVersion
|
||||
v = v[0 : len(v)-1]
|
||||
} else {
|
||||
ans.Condition = PkgCondEqual
|
||||
}
|
||||
} else if strings.HasPrefix(v, "~") {
|
||||
v = v[1:]
|
||||
ans.Condition = PkgCondAnyRevision
|
||||
} else if strings.HasPrefix(v, "!") {
|
||||
v = v[1:]
|
||||
ans.Condition = PkgCondNot
|
||||
}
|
||||
|
||||
regexPkg := regexp.MustCompile(
|
||||
fmt.Sprintf("(%s|%s|%s|%s|%s|%s)((%s|%s|%s|%s|%s|%s|%s)+)*$",
|
||||
// Version regex
|
||||
// 1.1
|
||||
"[0-9]+[.][0-9]+[a-z]*",
|
||||
// 1
|
||||
"[0-9]+[a-z]*",
|
||||
// 1.1.1
|
||||
"[0-9]+[.][0-9]+[.][0-9]+[a-z]*",
|
||||
// 1.1.1.1
|
||||
"[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+[a-z]*",
|
||||
// 1.1.1.1.1
|
||||
"[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+[.][0-9]+[a-z]*",
|
||||
// 1.1.1.1.1.1
|
||||
"[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+[.][0-9]+[.][0-9]+[a-z]*",
|
||||
// suffix
|
||||
"-r[0-9]+",
|
||||
"_p[0-9]+",
|
||||
"_pre[0-9]*",
|
||||
"_rc[0-9]+",
|
||||
// handle also rc without number
|
||||
"_rc",
|
||||
"_alpha",
|
||||
"_beta",
|
||||
),
|
||||
)
|
||||
matches := regexPkg.FindAllString(v, -1)
|
||||
|
||||
if len(matches) > 0 {
|
||||
// Check if there patch
|
||||
if strings.Contains(matches[0], "_p") {
|
||||
ans.Version = matches[0][0:strings.Index(matches[0], "_p")]
|
||||
ans.VersionSuffix = matches[0][strings.Index(matches[0], "_p"):]
|
||||
} else if strings.Contains(matches[0], "_rc") {
|
||||
ans.Version = matches[0][0:strings.Index(matches[0], "_rc")]
|
||||
ans.VersionSuffix = matches[0][strings.Index(matches[0], "_rc"):]
|
||||
} else if strings.Contains(matches[0], "_alpha") {
|
||||
ans.Version = matches[0][0:strings.Index(matches[0], "_alpha")]
|
||||
ans.VersionSuffix = matches[0][strings.Index(matches[0], "_alpha"):]
|
||||
} else if strings.Contains(matches[0], "_beta") {
|
||||
ans.Version = matches[0][0:strings.Index(matches[0], "_beta")]
|
||||
ans.VersionSuffix = matches[0][strings.Index(matches[0], "_beta"):]
|
||||
} else if strings.Contains(matches[0], "-r") {
|
||||
ans.Version = matches[0][0:strings.Index(matches[0], "-r")]
|
||||
ans.VersionSuffix = matches[0][strings.Index(matches[0], "-r"):]
|
||||
} else {
|
||||
ans.Version = matches[0]
|
||||
}
|
||||
}
|
||||
|
||||
// Set condition if there isn't a prefix but only a version
|
||||
if ans.Condition == PkgCondInvalid && ans.Version != "" {
|
||||
ans.Condition = PkgCondEqual
|
||||
}
|
||||
|
||||
// NOTE: Now suffix complex like _alpha_rc1 are not supported.
|
||||
return ans, nil
|
||||
}
|
||||
|
||||
func PackageAdmit(selector, i PkgVersionSelector) (bool, error) {
|
||||
var v1 *version.Version = nil
|
||||
var v2 *version.Version = nil
|
||||
var ans bool
|
||||
var err error
|
||||
|
||||
if selector.Version != "" {
|
||||
v1, err = version.NewVersion(selector.Version)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
if i.Version != "" {
|
||||
v2, err = version.NewVersion(i.Version)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
// If version is not defined match always package
|
||||
ans = true
|
||||
}
|
||||
|
||||
// If package doesn't define version admit all versions of the package.
|
||||
if selector.Version == "" {
|
||||
ans = true
|
||||
} else {
|
||||
if selector.Condition == PkgCondInvalid || selector.Condition == PkgCondEqual {
|
||||
// case 1: source-pkg-1.0 and dest-pkg-1.0 or dest-pkg without version
|
||||
if i.Version != "" && i.Version == selector.Version && selector.VersionSuffix == i.VersionSuffix {
|
||||
ans = true
|
||||
}
|
||||
} else if selector.Condition == PkgCondAnyRevision {
|
||||
if v1 != nil && v2 != nil {
|
||||
ans = v1.Equal(v2)
|
||||
}
|
||||
} else if selector.Condition == PkgCondMatchVersion {
|
||||
// TODO: case of 7.3* where 7.30 is accepted.
|
||||
if v1 != nil && v2 != nil {
|
||||
segments := v1.Segments()
|
||||
n := strings.Count(selector.Version, ".")
|
||||
switch n {
|
||||
case 0:
|
||||
segments[0]++
|
||||
case 1:
|
||||
segments[1]++
|
||||
case 2:
|
||||
segments[2]++
|
||||
default:
|
||||
segments[len(segments)-1]++
|
||||
}
|
||||
nextVersion := strings.Trim(strings.Replace(fmt.Sprint(segments), " ", ".", -1), "[]")
|
||||
constraints, err := version.NewConstraint(
|
||||
fmt.Sprintf(">= %s, < %s", selector.Version, nextVersion),
|
||||
)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
ans = constraints.Check(v2)
|
||||
}
|
||||
} else if v1 != nil && v2 != nil {
|
||||
|
||||
// TODO: Integrate check of version suffix
|
||||
switch selector.Condition {
|
||||
case PkgCondGreaterEqual:
|
||||
ans = v2.GreaterThanOrEqual(v1)
|
||||
case PkgCondLessEqual:
|
||||
ans = v2.LessThanOrEqual(v1)
|
||||
case PkgCondGreater:
|
||||
ans = v2.GreaterThan(v1)
|
||||
case PkgCondLess:
|
||||
ans = v2.LessThan(v1)
|
||||
case PkgCondNot:
|
||||
ans = !v2.Equal(v1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ans, nil
|
||||
}
|
||||
|
||||
func (p *DefaultPackage) SelectorMatchVersion(v string) (bool, error) {
|
||||
if !p.IsSelector() {
|
||||
return false, errors.New("Package is not a selector")
|
||||
}
|
||||
|
||||
vS, err := ParseVersion(p.GetVersion())
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
vSI, err := ParseVersion(v)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return PackageAdmit(vS, vSI)
|
||||
}
|
||||
|
||||
func (p *DefaultPackage) VersionMatchSelector(selector string) (bool, error) {
|
||||
vS, err := ParseVersion(selector)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
vSI, err := ParseVersion(p.GetVersion())
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return PackageAdmit(vS, vSI)
|
||||
}
|
184
pkg/package/version_test.go
Normal file
184
pkg/package/version_test.go
Normal file
@@ -0,0 +1,184 @@
|
||||
// Copyright © 2019 Ettore Di Giacinto <mudler@gentoo.org>
|
||||
// Daniele Rondina <geaaru@sabayonlinux.org>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package pkg_test
|
||||
|
||||
import (
|
||||
. "github.com/mudler/luet/pkg/package"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Versions", func() {
|
||||
|
||||
Context("Versions Parser1", func() {
|
||||
v, err := ParseVersion(">=1.0")
|
||||
It("ParseVersion1", func() {
|
||||
var c PkgSelectorCondition = PkgCondGreaterEqual
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(v.Version).Should(Equal("1.0"))
|
||||
Expect(v.VersionSuffix).Should(Equal(""))
|
||||
Expect(v.Condition).Should(Equal(c))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Versions Parser2", func() {
|
||||
v, err := ParseVersion(">1.0")
|
||||
It("ParseVersion2", func() {
|
||||
var c PkgSelectorCondition = PkgCondGreater
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(v.Version).Should(Equal("1.0"))
|
||||
Expect(v.VersionSuffix).Should(Equal(""))
|
||||
Expect(v.Condition).Should(Equal(c))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Versions Parser3", func() {
|
||||
v, err := ParseVersion("<=1.0")
|
||||
It("ParseVersion3", func() {
|
||||
var c PkgSelectorCondition = PkgCondLessEqual
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(v.Version).Should(Equal("1.0"))
|
||||
Expect(v.VersionSuffix).Should(Equal(""))
|
||||
Expect(v.Condition).Should(Equal(c))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Versions Parser4", func() {
|
||||
v, err := ParseVersion("<1.0")
|
||||
It("ParseVersion4", func() {
|
||||
var c PkgSelectorCondition = PkgCondLess
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(v.Version).Should(Equal("1.0"))
|
||||
Expect(v.VersionSuffix).Should(Equal(""))
|
||||
Expect(v.Condition).Should(Equal(c))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Versions Parser5", func() {
|
||||
v, err := ParseVersion("=1.0")
|
||||
It("ParseVersion5", func() {
|
||||
var c PkgSelectorCondition = PkgCondEqual
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(v.Version).Should(Equal("1.0"))
|
||||
Expect(v.VersionSuffix).Should(Equal(""))
|
||||
Expect(v.Condition).Should(Equal(c))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Versions Parser6", func() {
|
||||
v, err := ParseVersion("!1.0")
|
||||
It("ParseVersion6", func() {
|
||||
var c PkgSelectorCondition = PkgCondNot
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(v.Version).Should(Equal("1.0"))
|
||||
Expect(v.VersionSuffix).Should(Equal(""))
|
||||
Expect(v.Condition).Should(Equal(c))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Versions Parser7", func() {
|
||||
v, err := ParseVersion("")
|
||||
It("ParseVersion7", func() {
|
||||
var c PkgSelectorCondition = PkgCondInvalid
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(v.Version).Should(Equal(""))
|
||||
Expect(v.VersionSuffix).Should(Equal(""))
|
||||
Expect(v.Condition).Should(Equal(c))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Versions Parser8", func() {
|
||||
v, err := ParseVersion("=12.1.0.2_p1")
|
||||
It("ParseVersion8", func() {
|
||||
var c PkgSelectorCondition = PkgCondEqual
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(v.Version).Should(Equal("12.1.0.2"))
|
||||
Expect(v.VersionSuffix).Should(Equal("_p1"))
|
||||
Expect(v.Condition).Should(Equal(c))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Versions Parser9", func() {
|
||||
v, err := ParseVersion(">=0.0.20190406.4.9.172-r1")
|
||||
It("ParseVersion9", func() {
|
||||
var c PkgSelectorCondition = PkgCondGreaterEqual
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(v.Version).Should(Equal("0.0.20190406.4.9.172"))
|
||||
Expect(v.VersionSuffix).Should(Equal("-r1"))
|
||||
Expect(v.Condition).Should(Equal(c))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Versions Parser10", func() {
|
||||
v, err := ParseVersion(">=0.0.20190406.4.9.172_alpha")
|
||||
It("ParseVersion10", func() {
|
||||
var c PkgSelectorCondition = PkgCondGreaterEqual
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(v.Version).Should(Equal("0.0.20190406.4.9.172"))
|
||||
Expect(v.VersionSuffix).Should(Equal("_alpha"))
|
||||
Expect(v.Condition).Should(Equal(c))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Selector1", func() {
|
||||
v1, err := ParseVersion(">=0.0.20190406.4.9.172-r1")
|
||||
v2, err2 := ParseVersion("1.0.111")
|
||||
match, err3 := PackageAdmit(v1, v2)
|
||||
It("Selector1", func() {
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(err2).Should(BeNil())
|
||||
Expect(err3).Should(BeNil())
|
||||
Expect(match).Should(Equal(true))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Selector2", func() {
|
||||
v1, err := ParseVersion(">=0.0.20190406.4.9.172-r1")
|
||||
v2, err2 := ParseVersion("0")
|
||||
match, err3 := PackageAdmit(v1, v2)
|
||||
It("Selector2", func() {
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(err2).Should(BeNil())
|
||||
Expect(err3).Should(BeNil())
|
||||
Expect(match).Should(Equal(false))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Selector3", func() {
|
||||
v1, err := ParseVersion(">0")
|
||||
v2, err2 := ParseVersion("0.0.40-alpha")
|
||||
match, err3 := PackageAdmit(v1, v2)
|
||||
It("Selector3", func() {
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(err2).Should(BeNil())
|
||||
Expect(err3).Should(BeNil())
|
||||
Expect(match).Should(Equal(true))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Selector4", func() {
|
||||
v1, err := ParseVersion(">0")
|
||||
v2, err2 := ParseVersion("")
|
||||
match, err3 := PackageAdmit(v1, v2)
|
||||
It("Selector4", func() {
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(err2).Should(BeNil())
|
||||
Expect(err3).Should(BeNil())
|
||||
Expect(match).Should(Equal(true))
|
||||
})
|
||||
})
|
||||
})
|
Reference in New Issue
Block a user