Compare commits

..

8 Commits

Author SHA1 Message Date
Ettore Di Giacinto
585b72c3d0 Tag 0.17.13 2021-10-06 12:20:05 +02:00
Ettore Di Giacinto
f7aa6c3428 fix: always append templates from tree path
Otherwise shared templates from trees are not working when
--from-repositories is enabled.
2021-10-06 11:08:53 +02:00
Ettore Di Giacinto
2970d8e52e Tag 0.17.12 2021-09-22 09:46:17 +02:00
Ettore Di Giacinto
ff46bc7641 Don't use semver library for ordering by default
Use debian to parse versions and selections.
This covers ordering of versions like -0,-1 in sequence plus many others
not available with semver. It is backward compatible as we do support
the same featureset as before as tests are passing (adding more actually
to cover interesting cases)
2021-09-21 14:16:39 +02:00
Ettore Di Giacinto
e3063985b2 Tag bugfix release 0.17.11 2021-09-17 15:54:35 +02:00
Ettore Di Giacinto
a348fd4835 Replace Yaml with YAML in function, add debug output when extracting runtime data 2021-09-17 14:46:32 +02:00
Ettore Di Giacinto
fc45eae80a create-repo: annotate runtime definition in artifacts 2021-09-17 14:30:06 +02:00
Ettore Di Giacinto
b73ac21004 create-repo: don't inherit build requirements in runtime 2021-09-17 12:06:39 +02:00
16 changed files with 329 additions and 802 deletions

View File

@@ -26,7 +26,6 @@ import (
_gentoo "github.com/Sabayon/pkgs-checker/pkg/gentoo" _gentoo "github.com/Sabayon/pkgs-checker/pkg/gentoo"
pkg "github.com/mudler/luet/pkg/package" pkg "github.com/mudler/luet/pkg/package"
version "github.com/mudler/luet/pkg/versioner"
) )
func CreateRegexArray(rgx []string) ([]*regexp.Regexp, error) { func CreateRegexArray(rgx []string) ([]*regexp.Regexp, error) {
@@ -56,63 +55,73 @@ func packageData(p string) (string, string) {
} }
return cat, name return cat, name
} }
func ParsePackageStr(p string) (*pkg.DefaultPackage, error) {
if !(strings.HasPrefix(p, "=") || strings.HasPrefix(p, ">") || func packageHasGentooSelector(v string) bool {
strings.HasPrefix(p, "<")) { return (strings.HasPrefix(v, "=") || strings.HasPrefix(v, ">") ||
ver := ">=0" strings.HasPrefix(v, "<"))
cat := "" }
name := ""
if strings.Contains(p, "@") { func gentooVersion(gp *_gentoo.GentooPackage) string {
packageinfo := strings.Split(p, "@")
ver = packageinfo[1]
cat, name = packageData(packageinfo[0])
} else {
cat, name = packageData(p)
}
return &pkg.DefaultPackage{ condition := gp.Condition.String()
Name: name, if condition == "=" {
Category: cat, condition = ""
Version: ver,
Uri: make([]string, 0),
}, nil
} }
gp, err := _gentoo.ParsePackageStr(p) pkgVersion := fmt.Sprintf("%s%s%s",
if err != nil { condition,
return nil, err gp.Version,
} gp.VersionSuffix,
if gp.Version == "" { )
gp.Version = "0"
gp.Condition = _gentoo.PkgCondGreaterEqual
}
pkgVersion := ""
if gp.VersionBuild != "" { if gp.VersionBuild != "" {
pkgVersion = fmt.Sprintf("%s%s%s+%s", pkgVersion = fmt.Sprintf("%s%s%s+%s",
version.PkgSelectorConditionFromInt(gp.Condition.Int()).String(), condition,
gp.Version, gp.Version,
gp.VersionSuffix, gp.VersionSuffix,
gp.VersionBuild, gp.VersionBuild,
) )
}
return pkgVersion
}
func ParsePackageStr(p string) (*pkg.DefaultPackage, error) {
if packageHasGentooSelector(p) {
gp, err := _gentoo.ParsePackageStr(p)
if err != nil {
return nil, err
}
if gp.Version == "" {
gp.Version = "0"
gp.Condition = _gentoo.PkgCondGreaterEqual
}
return &pkg.DefaultPackage{
Name: gp.Name,
Category: gp.Category,
Version: gentooVersion(gp),
Uri: make([]string, 0),
}, nil
}
ver := ">=0"
cat := ""
name := ""
if strings.Contains(p, "@") {
packageinfo := strings.Split(p, "@")
ver = packageinfo[1]
cat, name = packageData(packageinfo[0])
} else { } else {
pkgVersion = fmt.Sprintf("%s%s%s", cat, name = packageData(p)
version.PkgSelectorConditionFromInt(gp.Condition.Int()).String(),
gp.Version,
gp.VersionSuffix,
)
} }
pack := &pkg.DefaultPackage{ return &pkg.DefaultPackage{
Name: gp.Name, Name: name,
Category: gp.Category, Category: cat,
Version: pkgVersion, Version: ver,
Uri: make([]string, 0), Uri: make([]string, 0),
} }, nil
return pack, nil
} }
func CheckErr(err error) { func CheckErr(err error) {

View File

@@ -80,7 +80,7 @@ Afterwards, you can use the content generated and associate it with a tree and a
} }
a.Files = filelist a.Files = filelist
a.CompileSpec.GetPackage().SetBuildTimestamp(time.Now().String()) a.CompileSpec.GetPackage().SetBuildTimestamp(time.Now().String())
err = a.WriteYaml(dst) err = a.WriteYAML(dst)
if err != nil { if err != nil {
Fatal("failed writing metadata yaml file for ", packageName, ": ", err.Error()) Fatal("failed writing metadata yaml file for ", packageName, ": ", err.Error())
} }

View File

@@ -41,7 +41,7 @@ var Verbose bool
var LockedCommands = []string{"install", "uninstall", "upgrade"} var LockedCommands = []string{"install", "uninstall", "upgrade"}
const ( const (
LuetCLIVersion = "0.17.10" LuetCLIVersion = "0.17.13"
LuetEnvPrefix = "LUET" LuetEnvPrefix = "LUET"
license = ` license = `
Luet Copyright (C) 2019-2021 Ettore Di Giacinto Luet Copyright (C) 2019-2021 Ettore Di Giacinto

View File

@@ -96,11 +96,10 @@ func SetCliFinalizerEnvs(finalizerEnvs []string) error {
// TemplateFolders returns the default folders which holds shared template between packages in a given tree path // TemplateFolders returns the default folders which holds shared template between packages in a given tree path
func TemplateFolders(fromRepo bool, treePaths []string) []string { func TemplateFolders(fromRepo bool, treePaths []string) []string {
templateFolders := []string{} templateFolders := []string{}
if !fromRepo { for _, t := range treePaths {
for _, t := range treePaths { templateFolders = append(templateFolders, filepath.Join(t, "templates"))
templateFolders = append(templateFolders, filepath.Join(t, "templates")) }
} if fromRepo {
} else {
for _, s := range installer.SystemRepositories(LuetCfg) { for _, s := range installer.SystemRepositories(LuetCfg) {
templateFolders = append(templateFolders, filepath.Join(s.TreePath, "templates")) templateFolders = append(templateFolders, filepath.Join(s.TreePath, "templates"))
} }

View File

@@ -442,7 +442,7 @@ func (cs *LuetCompiler) genArtifact(p *compilerspec.LuetCompilationSpec, builder
a.CompileSpec = p a.CompileSpec = p
a.CompileSpec.GetPackage().SetBuildTimestamp(time.Now().String()) a.CompileSpec.GetPackage().SetBuildTimestamp(time.Now().String())
err = a.WriteYaml(p.GetOutputPath()) err = a.WriteYAML(p.GetOutputPath())
if err != nil { if err != nil {
return a, errors.Wrap(err, "Failed while writing metadata file") return a, errors.Wrap(err, "Failed while writing metadata file")
} }
@@ -472,7 +472,7 @@ func (cs *LuetCompiler) genArtifact(p *compilerspec.LuetCompilationSpec, builder
a.Files = filelist a.Files = filelist
a.CompileSpec.GetPackage().SetBuildTimestamp(time.Now().String()) a.CompileSpec.GetPackage().SetBuildTimestamp(time.Now().String())
err = a.WriteYaml(p.GetOutputPath()) err = a.WriteYAML(p.GetOutputPath())
if err != nil { if err != nil {
return a, errors.Wrap(err, "Failed while writing metadata file") return a, errors.Wrap(err, "Failed while writing metadata file")
} }

View File

@@ -63,6 +63,7 @@ type PackageArtifact struct {
CompressionType compression.Implementation `json:"compressiontype"` CompressionType compression.Implementation `json:"compressiontype"`
Files []string `json:"files"` Files []string `json:"files"`
PackageCacheImage string `json:"package_cacheimage"` PackageCacheImage string `json:"package_cacheimage"`
Runtime *pkg.DefaultPackage `json:"runtime,omitempty"`
} }
func (p *PackageArtifact) ShallowCopy() *PackageArtifact { func (p *PackageArtifact) ShallowCopy() *PackageArtifact {
@@ -101,19 +102,23 @@ func (a *PackageArtifact) Verify() error {
return nil return nil
} }
func (a *PackageArtifact) WriteYaml(dst string) error { func (a *PackageArtifact) WriteYAML(dst string) error {
// First compute checksum of artifact. When we write the yaml we want to write up-to-date informations. // First compute checksum of artifact. When we write the yaml we want to write up-to-date informations.
err := a.Hash() err := a.Hash()
if err != nil { if err != nil {
return errors.Wrap(err, "Failed generating checksums for artifact") return errors.Wrap(err, "Failed generating checksums for artifact")
} }
//p := a.CompileSpec.GetPackage().GetPath() // Update runtime package information
if a.CompileSpec != nil && a.CompileSpec.Package != nil {
runtime, err := a.CompileSpec.Package.GetRuntimePackage()
if err != nil {
return errors.Wrapf(err, "getting runtime package for '%s'", a.CompileSpec.Package.HumanReadableString())
}
Debug(fmt.Sprintf("embedding runtime package (%s) definition to artifact metadata", a.CompileSpec.Package.HumanReadableString()))
a.Runtime = runtime
}
//a.CompileSpec.GetPackage().SetPath("")
// for _, ass := range a.CompileSpec.GetSourceAssertion() {
// ass.Package.SetPath("")
// }
data, err := yaml.Marshal(a) data, err := yaml.Marshal(a)
if err != nil { if err != nil {
return errors.Wrap(err, "While marshalling for PackageArtifact YAML") return errors.Wrap(err, "While marshalling for PackageArtifact YAML")

View File

@@ -318,7 +318,17 @@ func GenerateRepository(p ...RepositoryOption) (*LuetSystemRepository, error) {
} }
if _, err := runtimeTree.FindPackage(art.CompileSpec.Package); err != nil && art.CompileSpec.Package.Name != "" { if _, err := runtimeTree.FindPackage(art.CompileSpec.Package); err != nil && art.CompileSpec.Package.Name != "" {
Debug("Adding", art.CompileSpec.Package.HumanReadableString(), "from metadata file", currentpath) Debug("Adding", art.CompileSpec.Package.HumanReadableString(), "from metadata file", currentpath)
runtimeTree.CreatePackage(art.CompileSpec.Package) if art.Runtime != nil && art.Runtime.Name != "" {
runtimeTree.CreatePackage(art.Runtime)
} else {
// We don't have runtime at this point. So we import the package as is
r := []*pkg.DefaultPackage{}
p := art.CompileSpec.Package.Clone()
p.Requires(r)
p.SetProvides(r)
p.Conflicts(r)
runtimeTree.CreatePackage(p)
}
} }
return nil return nil

View File

@@ -29,7 +29,7 @@ func (s *System) ExecuteFinalizers(packs []pkg.Package) error {
executedFinalizer := map[string]bool{} executedFinalizer := map[string]bool{}
for _, p := range packs { for _, p := range packs {
if fileHelper.Exists(p.Rel(tree.FinalizerFile)) { if fileHelper.Exists(p.Rel(tree.FinalizerFile)) {
out, err := helpers.RenderFiles(helpers.ChartFile(p.Rel(tree.FinalizerFile)), p.Rel(tree.DefinitionFile)) out, err := helpers.RenderFiles(helpers.ChartFile(p.Rel(tree.FinalizerFile)), p.Rel(pkg.PackageDefinitionFile))
if err != nil { if err != nil {
Warning("Failed rendering finalizer for ", p.HumanReadableString(), err.Error()) Warning("Failed rendering finalizer for ", p.HumanReadableString(), err.Error())
errs = multierror.Append(errs, err) errs = multierror.Append(errs, err)

View File

@@ -21,11 +21,14 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"path/filepath" "path/filepath"
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
fileHelper "github.com/mudler/luet/pkg/helpers/file"
"github.com/mudler/luet/pkg/helpers/docker" "github.com/mudler/luet/pkg/helpers/docker"
"github.com/mudler/luet/pkg/helpers/match" "github.com/mudler/luet/pkg/helpers/match"
version "github.com/mudler/luet/pkg/versioner" version "github.com/mudler/luet/pkg/versioner"
@@ -124,7 +127,11 @@ type Package interface {
JSON() ([]byte, error) JSON() ([]byte, error)
} }
const PackageMetaSuffix = "metadata.yaml" const (
PackageMetaSuffix = "metadata.yaml"
PackageCollectionFile = "collection.yaml"
PackageDefinitionFile = "definition.yaml"
)
type Tree interface { type Tree interface {
GetPackageSet() PackageDatabase GetPackageSet() PackageDatabase
@@ -215,11 +222,14 @@ func GetRawPackages(yml []byte) (rawPackages, error) {
return rawPackages.Packages, nil return rawPackages.Packages, nil
} }
func DefaultPackagesFromYaml(yml []byte) ([]DefaultPackage, error) {
var unescaped struct { type Collection struct {
Packages []DefaultPackage `json:"packages"` Packages []DefaultPackage `json:"packages"`
} }
func DefaultPackagesFromYAML(yml []byte) ([]DefaultPackage, error) {
var unescaped Collection
source, err := yaml.YAMLToJSON(yml) source, err := yaml.YAMLToJSON(yml)
if err != nil { if err != nil {
return []DefaultPackage{}, err return []DefaultPackage{}, err
@@ -381,6 +391,10 @@ func (p *DefaultPackage) MatchLabel(r *regexp.Regexp) bool {
return match.MapMatchRegex(&p.Labels, r) return match.MapMatchRegex(&p.Labels, r)
} }
func (p DefaultPackage) IsCollection() bool {
return fileHelper.Exists(filepath.Join(p.Path, PackageCollectionFile))
}
func (p *DefaultPackage) HasAnnotation(label string) bool { func (p *DefaultPackage) HasAnnotation(label string) bool {
return match.MapHasKey(&p.Annotations, label) return match.MapHasKey(&p.Annotations, label)
} }
@@ -703,6 +717,39 @@ func (set Packages) Unique() Packages {
return result return result
} }
func (p *DefaultPackage) GetRuntimePackage() (*DefaultPackage, error) {
var r *DefaultPackage
if p.IsCollection() {
collectionFile := filepath.Join(p.Path, PackageCollectionFile)
dat, err := ioutil.ReadFile(collectionFile)
if err != nil {
return r, errors.Wrapf(err, "failed while reading '%s'", collectionFile)
}
coll, err := DefaultPackagesFromYAML(dat)
if err != nil {
return r, errors.Wrapf(err, "failed while parsing YAML '%s'", collectionFile)
}
for _, c := range coll {
if c.Matches(p) {
r = &c
break
}
}
} else {
definitionFile := filepath.Join(p.Path, PackageDefinitionFile)
dat, err := ioutil.ReadFile(definitionFile)
if err != nil {
return r, errors.Wrapf(err, "failed while reading '%s'", definitionFile)
}
d, err := DefaultPackageFromYaml(dat)
if err != nil {
return r, errors.Wrapf(err, "failed while parsing YAML '%s'", definitionFile)
}
r = &d
}
return r, nil
}
func (pack *DefaultPackage) buildFormula(definitiondb PackageDatabase, db PackageDatabase, visited map[string]interface{}) ([]bf.Formula, error) { func (pack *DefaultPackage) buildFormula(definitiondb PackageDatabase, db PackageDatabase, visited map[string]interface{}) ([]bf.Formula, error) {
if _, ok := visited[pack.HumanReadableString()]; ok { if _, ok := visited[pack.HumanReadableString()]; ok {
return nil, nil return nil, nil

View File

@@ -90,12 +90,12 @@ func (r *CompilerRecipe) Load(path string) error {
return errors.Wrap(err, "Error on walk path "+currentpath) return errors.Wrap(err, "Error on walk path "+currentpath)
} }
if info.Name() != DefinitionFile && info.Name() != CollectionFile { if info.Name() != pkg.PackageDefinitionFile && info.Name() != pkg.PackageCollectionFile {
return nil // Skip with no errors return nil // Skip with no errors
} }
switch info.Name() { switch info.Name() {
case DefinitionFile: case pkg.PackageDefinitionFile:
pack, err := ReadDefinitionFile(currentpath) pack, err := ReadDefinitionFile(currentpath)
if err != nil { if err != nil {
@@ -130,14 +130,14 @@ func (r *CompilerRecipe) Load(path string) error {
return errors.Wrap(err, "Error creating package "+pack.GetName()) return errors.Wrap(err, "Error creating package "+pack.GetName())
} }
case CollectionFile: case pkg.PackageCollectionFile:
dat, err := ioutil.ReadFile(currentpath) dat, err := ioutil.ReadFile(currentpath)
if err != nil { if err != nil {
return errors.Wrap(err, "Error reading file "+currentpath) return errors.Wrap(err, "Error reading file "+currentpath)
} }
packs, err := pkg.DefaultPackagesFromYaml(dat) packs, err := pkg.DefaultPackagesFromYAML(dat)
if err != nil { if err != nil {
return errors.Wrap(err, "Error reading yaml "+currentpath) return errors.Wrap(err, "Error reading yaml "+currentpath)
} }

View File

@@ -56,7 +56,7 @@ func (r *InstallerRecipe) Save(path string) error {
if err != nil { if err != nil {
return err return err
} }
err = ioutil.WriteFile(filepath.Join(dir, DefinitionFile), data, 0644) err = ioutil.WriteFile(filepath.Join(dir, pkg.PackageDefinitionFile), data, 0644)
if err != nil { if err != nil {
return err return err
} }
@@ -86,7 +86,7 @@ func (r *InstallerRecipe) Load(path string) error {
// the function that handles each file or dir // the function that handles each file or dir
var ff = func(currentpath string, info os.FileInfo, err error) error { var ff = func(currentpath string, info os.FileInfo, err error) error {
if info.Name() != DefinitionFile && info.Name() != CollectionFile { if info.Name() != pkg.PackageDefinitionFile && info.Name() != pkg.PackageCollectionFile {
return nil // Skip with no errors return nil // Skip with no errors
} }
@@ -96,7 +96,7 @@ func (r *InstallerRecipe) Load(path string) error {
} }
switch info.Name() { switch info.Name() {
case DefinitionFile: case pkg.PackageDefinitionFile:
pack, err := pkg.DefaultPackageFromYaml(dat) pack, err := pkg.DefaultPackageFromYaml(dat)
if err != nil { if err != nil {
return errors.Wrap(err, "Error reading yaml "+currentpath) return errors.Wrap(err, "Error reading yaml "+currentpath)
@@ -109,8 +109,8 @@ func (r *InstallerRecipe) Load(path string) error {
return errors.Wrap(err, "Error creating package "+pack.GetName()) return errors.Wrap(err, "Error creating package "+pack.GetName())
} }
case CollectionFile: case pkg.PackageCollectionFile:
packs, err := pkg.DefaultPackagesFromYaml(dat) packs, err := pkg.DefaultPackagesFromYAML(dat)
if err != nil { if err != nil {
return errors.Wrap(err, "Error reading yaml "+currentpath) return errors.Wrap(err, "Error reading yaml "+currentpath)
} }

View File

@@ -33,11 +33,6 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
const (
DefinitionFile = "definition.yaml"
CollectionFile = "collection.yaml"
)
func NewGeneralRecipe(db pkg.PackageDatabase) Builder { return &Recipe{Database: db} } func NewGeneralRecipe(db pkg.PackageDatabase) Builder { return &Recipe{Database: db} }
// Recipe is the "general" reciper for Trees // Recipe is the "general" reciper for Trees
@@ -64,7 +59,7 @@ func (r *Recipe) Save(path string) error {
dir := filepath.Join(path, p.GetCategory(), p.GetName(), p.GetVersion()) dir := filepath.Join(path, p.GetCategory(), p.GetName(), p.GetVersion())
os.MkdirAll(dir, os.ModePerm) os.MkdirAll(dir, os.ModePerm)
err := WriteDefinitionFile(p, filepath.Join(dir, DefinitionFile)) err := WriteDefinitionFile(p, filepath.Join(dir, pkg.PackageDefinitionFile))
if err != nil { if err != nil {
return err return err
} }
@@ -96,7 +91,7 @@ func (r *Recipe) Load(path string) error {
// the function that handles each file or dir // the function that handles each file or dir
var ff = func(currentpath string, info os.FileInfo, err error) error { var ff = func(currentpath string, info os.FileInfo, err error) error {
if info.Name() != DefinitionFile && info.Name() != CollectionFile { if info.Name() != pkg.PackageDefinitionFile && info.Name() != pkg.PackageCollectionFile {
return nil // Skip with no errors return nil // Skip with no errors
} }
@@ -106,7 +101,7 @@ func (r *Recipe) Load(path string) error {
} }
switch info.Name() { switch info.Name() {
case DefinitionFile: case pkg.PackageDefinitionFile:
pack, err := pkg.DefaultPackageFromYaml(dat) pack, err := pkg.DefaultPackageFromYaml(dat)
if err != nil { if err != nil {
return errors.Wrap(err, "Error reading yaml "+currentpath) return errors.Wrap(err, "Error reading yaml "+currentpath)
@@ -118,8 +113,8 @@ func (r *Recipe) Load(path string) error {
if err != nil { if err != nil {
return errors.Wrap(err, "Error creating package "+pack.GetName()) return errors.Wrap(err, "Error creating package "+pack.GetName())
} }
case CollectionFile: case pkg.PackageCollectionFile:
packs, err := pkg.DefaultPackagesFromYaml(dat) packs, err := pkg.DefaultPackagesFromYAML(dat)
if err != nil { if err != nil {
return errors.Wrap(err, "Error reading yaml "+currentpath) return errors.Wrap(err, "Error reading yaml "+currentpath)
} }

View File

@@ -1,336 +0,0 @@
// 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 version
import (
"fmt"
"regexp"
"strings"
semver "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 PkgSelectorConditionFromInt(c int) (ans PkgSelectorCondition) {
if c == PkgCondGreater {
ans = PkgCondGreater
} else if c == PkgCondGreaterEqual {
ans = PkgCondGreaterEqual
} else if c == PkgCondLess {
ans = PkgCondLess
} else if c == PkgCondLessEqual {
ans = PkgCondLessEqual
} else if c == PkgCondNot {
ans = PkgCondNot
} else if c == PkgCondAnyRevision {
ans = PkgCondAnyRevision
} else if c == PkgCondMatchVersion {
ans = PkgCondMatchVersion
} else {
ans = PkgCondInvalid
}
return
}
func (p PkgSelectorCondition) String() (ans string) {
if p == PkgCondInvalid {
ans = ""
} else if p == PkgCondGreater {
ans = ">"
} else if p == PkgCondGreaterEqual {
ans = ">="
} else if p == PkgCondLess {
ans = "<"
} else if p == PkgCondLessEqual {
ans = "<="
} else if p == PkgCondEqual {
// To permit correct matching on database
// we currently use directly package version without =
ans = ""
} else if p == PkgCondNot {
ans = "!"
} else if p == PkgCondAnyRevision {
ans = "~"
} else if p == PkgCondMatchVersion {
ans = "=*"
}
return
}
func (p PkgSelectorCondition) Int() (ans int) {
if p == PkgCondInvalid {
ans = PkgCondInvalid
} else if p == PkgCondGreater {
ans = PkgCondGreater
} else if p == PkgCondGreaterEqual {
ans = PkgCondGreaterEqual
} else if p == PkgCondLess {
ans = PkgCondLess
} else if p == PkgCondLessEqual {
ans = PkgCondLessEqual
} else if p == PkgCondEqual {
// To permit correct matching on database
// we currently use directly package version without =
ans = PkgCondEqual
} else if p == PkgCondNot {
ans = PkgCondNot
} else if p == PkgCondAnyRevision {
ans = PkgCondAnyRevision
} else if p == PkgCondMatchVersion {
ans = PkgCondMatchVersion
}
return
}
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
}
// Check if build number is present
buildIdx := strings.LastIndex(v, "+")
buildVersion := ""
if buildIdx > 0 {
// <pre-release> ::= <dot-separated pre-release identifiers>
//
// <dot-separated pre-release identifiers> ::=
// <pre-release identifier> | <pre-release identifier> "."
// <dot-separated pre-release identifiers>
//
// <build> ::= <dot-separated build identifiers>
//
// <dot-separated build identifiers> ::= <build identifier>
// | <build identifier> "." <dot-separated build identifiers>
//
// <pre-release identifier> ::= <alphanumeric identifier>
// | <numeric identifier>
//
// <build identifier> ::= <alphanumeric identifier>
// | <digits>
//
// <alphanumeric identifier> ::= <non-digit>
// | <non-digit> <identifier characters>
// | <identifier characters> <non-digit>
// | <identifier characters> <non-digit> <identifier characters>
buildVersion = v[buildIdx:]
v = v[0:buildIdx]
}
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
}
ans.Version += buildVersion
// NOTE: Now suffix complex like _alpha_rc1 are not supported.
return ans, nil
}
func PackageAdmit(selector, i PkgVersionSelector) (bool, error) {
var v1 *semver.Version = nil
var v2 *semver.Version = nil
var ans bool
var err error
var sanitizedSelectorVersion, sanitizedIVersion string
if selector.Version != "" {
// TODO: This is temporary!. I promise it.
sanitizedSelectorVersion = strings.ReplaceAll(selector.Version, "_", "-")
v1, err = semver.NewVersion(sanitizedSelectorVersion)
if err != nil {
return false, err
}
}
if i.Version != "" {
sanitizedIVersion = strings.ReplaceAll(i.Version, "_", "-")
v2, err = semver.NewVersion(sanitizedIVersion)
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(sanitizedIVersion, ".")
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 := semver.NewConstraint(
fmt.Sprintf(">= %s, < %s", sanitizedSelectorVersion, 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
}

View File

@@ -1,311 +0,0 @@
// 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 version_test
import (
gentoo "github.com/Sabayon/pkgs-checker/pkg/gentoo"
. "github.com/mudler/luet/pkg/versioner"
. "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("Versions Parser11 - semver", func() {
v, err := ParseVersion("0.1.0+0")
It("ParseVersion10", func() {
var c PkgSelectorCondition = PkgCondEqual
Expect(err).Should(BeNil())
Expect(v.Version).Should(Equal("0.1.0+0"))
Expect(v.VersionSuffix).Should(Equal(""))
Expect(v.Condition).Should(Equal(c))
})
})
Context("Versions Parser12 - semver", func() {
v, err := ParseVersion(">=0.1.0_alpha+AB")
It("ParseVersion10", func() {
var c PkgSelectorCondition = PkgCondGreaterEqual
Expect(err).Should(BeNil())
Expect(v.Version).Should(Equal("0.1.0+AB"))
Expect(v.VersionSuffix).Should(Equal("_alpha"))
Expect(v.Condition).Should(Equal(c))
})
})
Context("Versions Parser13 - semver", func() {
v, err := ParseVersion(">=0.1.0_alpha+0.1.22")
It("ParseVersion10", func() {
var c PkgSelectorCondition = PkgCondGreaterEqual
Expect(err).Should(BeNil())
Expect(v.Version).Should(Equal("0.1.0+0.1.22"))
Expect(v.VersionSuffix).Should(Equal("_alpha"))
Expect(v.Condition).Should(Equal(c))
})
})
Context("Versions Parser14 - semver", func() {
v, err := ParseVersion(">=0.1.0_alpha+0.1.22")
It("ParseVersion10", func() {
var c PkgSelectorCondition = PkgCondGreaterEqual
Expect(err).Should(BeNil())
Expect(v.Version).Should(Equal("0.1.0+0.1.22"))
Expect(v.VersionSuffix).Should(Equal("_alpha"))
Expect(v.Condition).Should(Equal(c))
})
})
Context("Versions Parser15 - semver", func() {
v, err := ParseVersion("<=0.3.222.4.5+AB")
It("ParseVersion10", func() {
var c PkgSelectorCondition = PkgCondLessEqual
Expect(err).Should(BeNil())
Expect(v.Version).Should(Equal("0.3.222.4.5+AB"))
Expect(v.VersionSuffix).Should(Equal(""))
Expect(v.Condition).Should(Equal(c))
})
})
Context("Versions Parser16 - semver", func() {
v, err := ParseVersion("<=1.0.29+pre2_p20191024")
It("ParseVersion10", func() {
var c PkgSelectorCondition = PkgCondLessEqual
Expect(err).Should(BeNil())
Expect(v.Version).Should(Equal("1.0.29+pre2_p20191024"))
Expect(v.VersionSuffix).Should(Equal(""))
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))
})
})
Context("Selector5", func() {
v1, err := ParseVersion(">0.1.0+0.4")
v2, err2 := ParseVersion("0.1.0+0.3")
match, err3 := PackageAdmit(v1, v2)
It("Selector5", func() {
Expect(err).Should(BeNil())
Expect(err2).Should(BeNil())
Expect(err3).Should(BeNil())
Expect(match).Should(Equal(false))
})
})
Context("Selector6", func() {
v1, err := ParseVersion(">=0.1.0+0.4")
v2, err2 := ParseVersion("0.1.0+0.5")
match, err3 := PackageAdmit(v1, v2)
It("Selector6", func() {
Expect(err).Should(BeNil())
Expect(err2).Should(BeNil())
Expect(err3).Should(BeNil())
Expect(match).Should(Equal(true))
})
})
PContext("Selector7", func() {
v1, err := ParseVersion(">0.1.0+0.4")
v2, err2 := ParseVersion("0.1.0+0.5")
match, err3 := PackageAdmit(v1, v2)
It("Selector7", func() {
Expect(err).Should(BeNil())
Expect(err2).Should(BeNil())
Expect(err3).Should(BeNil())
Expect(match).Should(Equal(true))
})
})
Context("Selector8", func() {
v1, err := ParseVersion(">=0")
v2, err2 := ParseVersion("1.0.29+pre2_p20191024")
match, err3 := PackageAdmit(v1, v2)
It("Selector8", func() {
Expect(err).Should(BeNil())
Expect(err2).Should(BeNil())
Expect(err3).Should(BeNil())
Expect(match).Should(Equal(true))
})
})
Context("Condition Converter 1", func() {
gp, err := gentoo.ParsePackageStr("=layer/build-1.0")
var cond gentoo.PackageCond = gentoo.PkgCondEqual
It("Converter1", func() {
Expect(err).Should(BeNil())
Expect((*gp).Condition).Should(Equal(cond))
Expect(PkgSelectorConditionFromInt((*gp).Condition.Int()).String()).Should(Equal(""))
})
})
})

View File

@@ -1,5 +1,4 @@
// Copyright © 2019-2020 Ettore Di Giacinto <mudler@gentoo.org>, // Copyright © 2019-2021 Ettore Di Giacinto <mudler@gentoo.org>
// Daniele Rondina <geaaru@sabayonlinux.org>
// //
// This program is free software; you can redistribute it and/or modify // 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 // it under the terms of the GNU General Public License as published by
@@ -18,15 +17,79 @@ package version
import ( import (
"errors" "errors"
"regexp"
"sort" "sort"
"strconv"
"strings" "strings"
"github.com/hashicorp/go-version"
semver "github.com/hashicorp/go-version" semver "github.com/hashicorp/go-version"
debversion "github.com/knqyf263/go-deb-version" debversion "github.com/knqyf263/go-deb-version"
) )
const (
selectorGreaterThen = iota
selectorLessThen = iota
selectorGreaterOrEqualThen = iota
selectorLessOrEqualThen = iota
selectorNotEqual = iota
)
type packageSelector struct {
Condition int
Version string
}
var selectors = map[string]int{
">=": selectorGreaterOrEqualThen,
">": selectorGreaterThen,
"<=": selectorLessOrEqualThen,
"<": selectorLessThen,
"!": selectorNotEqual,
}
func readPackageSelector(selector string) packageSelector {
selectorType := 0
v := ""
k := []string{}
for kk, _ := range selectors {
k = append(k, kk)
}
sort.Slice(k, func(i, j int) bool {
return len(k[i]) > len(k[j])
})
for _, p := range k {
if strings.HasPrefix(selector, p) {
selectorType = selectors[p]
v = strings.TrimPrefix(selector, p)
break
}
}
return packageSelector{
Condition: selectorType,
Version: v,
}
}
func semverCheck(vv string, selector string) (bool, error) {
c, err := semver.NewConstraint(selector)
if err != nil {
// Handle constraint not being parsable.
return false, err
}
v, err := semver.NewVersion(vv)
if err != nil {
// Handle version not being parsable.
return false, err
}
// Check if the version meets the constraints.
return c.Check(v), nil
}
// WrappedVersioner uses different means to return unique result that is understendable by Luet // WrappedVersioner uses different means to return unique result that is understendable by Luet
// It tries different approaches to sort, validate, and sanitize to a common versioning format // It tries different approaches to sort, validate, and sanitize to a common versioning format
// that is understendable by the whole code // that is understendable by the whole code
@@ -38,55 +101,49 @@ func DefaultVersioner() Versioner {
func (w *WrappedVersioner) Validate(version string) error { func (w *WrappedVersioner) Validate(version string) error {
if !debversion.Valid(version) { if !debversion.Valid(version) {
return errors.New("Invalid version") return errors.New("invalid version")
} }
return nil return nil
} }
func (w *WrappedVersioner) ValidateSelector(version string, selector string) bool { func (w *WrappedVersioner) ValidateSelector(vv string, selector string) bool {
vS, err := ParseVersion(selector) if vv == "" {
return true
}
vv = w.Sanitize(vv)
selector = w.Sanitize(selector)
sel := readPackageSelector(selector)
selectorV, err := version.NewVersion(sel.Version)
if err != nil { if err != nil {
return false f, _ := semverCheck(vv, selector)
return f
}
v, err := version.NewVersion(vv)
if err != nil {
f, _ := semverCheck(vv, selector)
return f
} }
vSI, err := ParseVersion(version) switch sel.Condition {
if err != nil { case selectorGreaterOrEqualThen:
return false return v.GreaterThan(selectorV) || v.Equal(selectorV)
case selectorLessOrEqualThen:
return v.LessThan(selectorV) || v.Equal(selectorV)
case selectorLessThen:
return v.LessThan(selectorV)
case selectorGreaterThen:
return v.GreaterThan(selectorV)
case selectorNotEqual:
return !v.Equal(selectorV)
} }
ok, err := PackageAdmit(vS, vSI)
if err != nil { return false
return false
}
return ok
} }
func (w *WrappedVersioner) Sanitize(s string) string { func (w *WrappedVersioner) Sanitize(s string) string {
return strings.ReplaceAll(s, "_", "-") return strings.TrimSpace(strings.ReplaceAll(s, "_", "-"))
}
func (w *WrappedVersioner) IsSemver(v string) bool {
// Taken https://github.com/hashicorp/go-version/blob/2b13044f5cdd3833370d41ce57d8bf3cec5e62b8/version.go#L44
// semver doesn't have a Validate method, so we should filter before
// going to use it blindly (it panics)
semverRegexp := regexp.MustCompile("^" + semver.SemverRegexpRaw + "$")
// See https://github.com/hashicorp/go-version/blob/2b13044f5cdd3833370d41ce57d8bf3cec5e62b8/version.go#L61
matches := semverRegexp.FindStringSubmatch(v)
if matches == nil {
return false
}
segmentsStr := strings.Split(matches[1], ".")
segments := make([]int64, len(segmentsStr))
for i, str := range segmentsStr {
val, err := strconv.ParseInt(str, 10, 64)
if err != nil {
return false
}
segments[i] = int64(val)
}
return (len(segments) != 0)
} }
func (w *WrappedVersioner) Sort(toSort []string) []string { func (w *WrappedVersioner) Sort(toSort []string) []string {
@@ -102,35 +159,6 @@ func (w *WrappedVersioner) Sort(toSort []string) []string {
versionsRaw = append(versionsRaw, sanitizedVersion) versionsRaw = append(versionsRaw, sanitizedVersion)
} }
versions := make([]*semver.Version, len(versionsRaw))
// Check if all of them are semver, otherwise we cannot do a good comparison
allSemverCompliant := true
for _, raw := range versionsRaw {
if !w.IsSemver(raw) {
allSemverCompliant = false
}
}
if allSemverCompliant {
for i, raw := range versionsRaw {
if w.IsSemver(raw) { // Make sure we include only semver, or go-version will panic
v, _ := semver.NewVersion(raw)
versions[i] = v
}
}
// Try first semver sorting
sort.Sort(semver.Collection(versions))
if len(versions) > 0 {
for _, v := range versions {
result = append(result, versionsMap[v.Original()])
}
return result
}
}
// Try with debian sorting
vs := make([]debversion.Version, len(versionsRaw)) vs := make([]debversion.Version, len(versionsRaw))
for i, r := range versionsRaw { for i, r := range versionsRaw {
v, _ := debversion.NewVersion(r) v, _ := debversion.NewVersion(r)

View File

@@ -17,6 +17,8 @@
package version_test package version_test
import ( import (
"fmt"
. "github.com/mudler/luet/pkg/versioner" . "github.com/mudler/luet/pkg/versioner"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
@@ -71,6 +73,14 @@ var _ = Describe("Versioner", func() {
}) })
}) })
Context("Sorting with +", func() {
versioner := DefaultVersioner()
It("finds the correct ordering", func() {
sorted := versioner.Sort([]string{"1.0+1", "1.0+0", "0.1", "1.0+3", "1.0+2", "1.9"})
Expect(sorted).Should(Equal([]string{"0.1", "1.0+0", "1.0+1", "1.0+2", "1.0+3", "1.9"}))
})
})
// from: https://github.com/knqyf263/go-deb-version/blob/master/version_test.go#L8 // from: https://github.com/knqyf263/go-deb-version/blob/master/version_test.go#L8
Context("Debian Sorting", func() { Context("Debian Sorting", func() {
versioner := DefaultVersioner() versioner := DefaultVersioner()
@@ -79,4 +89,75 @@ var _ = Describe("Versioner", func() {
Expect(sorted).Should(Equal([]string{"2:7.4.052-1ubuntu1", "2:7.4.052-1ubuntu2", "2:7.4.052-1ubuntu3", "2:7.4.052-1ubuntu3.1"})) Expect(sorted).Should(Equal([]string{"2:7.4.052-1ubuntu1", "2:7.4.052-1ubuntu2", "2:7.4.052-1ubuntu3", "2:7.4.052-1ubuntu3.1"}))
}) })
}) })
It("finds the correct ordering", func() {
versioner := DefaultVersioner()
sorted := versioner.Sort([]string{"0.0.1-beta-9", "0.0.1-alpha08-9", "0.0.1-alpha07-9", "0.0.1-alpha07-8"})
Expect(sorted).Should(Equal([]string{"0.0.1-alpha07-8", "0.0.1-alpha07-9", "0.0.1-alpha08-9", "0.0.1-beta-9"}))
})
It("finds the correct ordering", func() {
versioner := DefaultVersioner()
sorted := versioner.Sort([]string{"0.0.1-beta01", "0.0.1-alpha08", "0.0.1-alpha07"})
Expect(sorted).Should(Equal([]string{"0.0.1-alpha07", "0.0.1-alpha08", "0.0.1-beta01"}))
})
Context("Matching a selector", func() {
testCases := [][]string{
{">=1", "2"},
{"<=3", "2"},
{">0", ""},
{">0", "0.0.40-alpha"},
{">=0.1.0+0.4", "0.1.0+0.5"},
{">=0.0.20190406.4.9.172-r1", "1.0.111"},
{">=0", "1.0.29+pre2_p20191024"},
{">=0.1.0+4", "0.1.0+5"},
{">0.1.0-4", "0.1.0-5"},
{"<1.2.3-beta", "1.2.3-beta.1-1"},
{"<1.2.3", "1.2.3-beta.1"},
{">0.0.1-alpha07", "0.0.1-alpha07-8"},
{">0.0.1-alpha07-1", "0.0.1-alpha07-8"},
{">0.0.1-alpha07", "0.0.1-alpha08"},
}
versioner := DefaultVersioner()
for i, t := range testCases {
selector := testCases[i][0]
version := testCases[i][1]
It(fmt.Sprint(t), func() {
Expect(versioner.ValidateSelector(version, selector)).Should(BeTrue())
})
}
})
Context("Not matching a selector", func() {
testfalseCases := [][]string{
{">0.0.1-alpha07", "0.0.1-alpha06"},
{"<0.0.1-alpha07", "0.0.1-alpha08"},
{">0.1.0+0.4", "0.1.0+0.3"},
{">=0.0.20190406.4.9.172-r1", "0"},
{"<=1", "2"},
{">=3", "2"},
{"<0", "0.0.40-alpha"},
{"<0.1.0+0.4", "0.1.0+0.5"},
{"<=0.0.20190406.4.9.172-r1", "1.0.111"},
{"<0.1.0+4", "0.1.0+5"},
{"<=0.1.0-4", "0.1.0-5"},
}
versioner := DefaultVersioner()
for i, t := range testfalseCases {
selector := testfalseCases[i][0]
version := testfalseCases[i][1]
It(fmt.Sprint(t), func() {
Expect(versioner.ValidateSelector(version, selector)).Should(BeFalse())
})
}
})
}) })