mirror of
https://github.com/mudler/luet.git
synced 2025-09-16 23:31:08 +00:00
Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
585b72c3d0 | ||
|
f7aa6c3428 | ||
|
2970d8e52e | ||
|
ff46bc7641 | ||
|
e3063985b2 | ||
|
a348fd4835 | ||
|
fc45eae80a | ||
|
b73ac21004 |
@@ -26,7 +26,6 @@ import (
|
||||
|
||||
_gentoo "github.com/Sabayon/pkgs-checker/pkg/gentoo"
|
||||
pkg "github.com/mudler/luet/pkg/package"
|
||||
version "github.com/mudler/luet/pkg/versioner"
|
||||
)
|
||||
|
||||
func CreateRegexArray(rgx []string) ([]*regexp.Regexp, error) {
|
||||
@@ -56,63 +55,73 @@ func packageData(p string) (string, string) {
|
||||
}
|
||||
return cat, name
|
||||
}
|
||||
func ParsePackageStr(p string) (*pkg.DefaultPackage, error) {
|
||||
|
||||
if !(strings.HasPrefix(p, "=") || strings.HasPrefix(p, ">") ||
|
||||
strings.HasPrefix(p, "<")) {
|
||||
ver := ">=0"
|
||||
cat := ""
|
||||
name := ""
|
||||
func packageHasGentooSelector(v string) bool {
|
||||
return (strings.HasPrefix(v, "=") || strings.HasPrefix(v, ">") ||
|
||||
strings.HasPrefix(v, "<"))
|
||||
}
|
||||
|
||||
if strings.Contains(p, "@") {
|
||||
packageinfo := strings.Split(p, "@")
|
||||
ver = packageinfo[1]
|
||||
cat, name = packageData(packageinfo[0])
|
||||
} else {
|
||||
cat, name = packageData(p)
|
||||
}
|
||||
func gentooVersion(gp *_gentoo.GentooPackage) string {
|
||||
|
||||
return &pkg.DefaultPackage{
|
||||
Name: name,
|
||||
Category: cat,
|
||||
Version: ver,
|
||||
Uri: make([]string, 0),
|
||||
}, nil
|
||||
condition := gp.Condition.String()
|
||||
if condition == "=" {
|
||||
condition = ""
|
||||
}
|
||||
|
||||
gp, err := _gentoo.ParsePackageStr(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if gp.Version == "" {
|
||||
gp.Version = "0"
|
||||
gp.Condition = _gentoo.PkgCondGreaterEqual
|
||||
}
|
||||
|
||||
pkgVersion := ""
|
||||
pkgVersion := fmt.Sprintf("%s%s%s",
|
||||
condition,
|
||||
gp.Version,
|
||||
gp.VersionSuffix,
|
||||
)
|
||||
if gp.VersionBuild != "" {
|
||||
pkgVersion = fmt.Sprintf("%s%s%s+%s",
|
||||
version.PkgSelectorConditionFromInt(gp.Condition.Int()).String(),
|
||||
condition,
|
||||
gp.Version,
|
||||
gp.VersionSuffix,
|
||||
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 {
|
||||
pkgVersion = fmt.Sprintf("%s%s%s",
|
||||
version.PkgSelectorConditionFromInt(gp.Condition.Int()).String(),
|
||||
gp.Version,
|
||||
gp.VersionSuffix,
|
||||
)
|
||||
cat, name = packageData(p)
|
||||
}
|
||||
|
||||
pack := &pkg.DefaultPackage{
|
||||
Name: gp.Name,
|
||||
Category: gp.Category,
|
||||
Version: pkgVersion,
|
||||
return &pkg.DefaultPackage{
|
||||
Name: name,
|
||||
Category: cat,
|
||||
Version: ver,
|
||||
Uri: make([]string, 0),
|
||||
}
|
||||
|
||||
return pack, nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
func CheckErr(err error) {
|
||||
|
@@ -80,7 +80,7 @@ Afterwards, you can use the content generated and associate it with a tree and a
|
||||
}
|
||||
a.Files = filelist
|
||||
a.CompileSpec.GetPackage().SetBuildTimestamp(time.Now().String())
|
||||
err = a.WriteYaml(dst)
|
||||
err = a.WriteYAML(dst)
|
||||
if err != nil {
|
||||
Fatal("failed writing metadata yaml file for ", packageName, ": ", err.Error())
|
||||
}
|
||||
|
@@ -41,7 +41,7 @@ var Verbose bool
|
||||
var LockedCommands = []string{"install", "uninstall", "upgrade"}
|
||||
|
||||
const (
|
||||
LuetCLIVersion = "0.17.10"
|
||||
LuetCLIVersion = "0.17.13"
|
||||
LuetEnvPrefix = "LUET"
|
||||
license = `
|
||||
Luet Copyright (C) 2019-2021 Ettore Di Giacinto
|
||||
|
@@ -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
|
||||
func TemplateFolders(fromRepo bool, treePaths []string) []string {
|
||||
templateFolders := []string{}
|
||||
if !fromRepo {
|
||||
for _, t := range treePaths {
|
||||
templateFolders = append(templateFolders, filepath.Join(t, "templates"))
|
||||
}
|
||||
} else {
|
||||
for _, t := range treePaths {
|
||||
templateFolders = append(templateFolders, filepath.Join(t, "templates"))
|
||||
}
|
||||
if fromRepo {
|
||||
for _, s := range installer.SystemRepositories(LuetCfg) {
|
||||
templateFolders = append(templateFolders, filepath.Join(s.TreePath, "templates"))
|
||||
}
|
||||
|
@@ -442,7 +442,7 @@ func (cs *LuetCompiler) genArtifact(p *compilerspec.LuetCompilationSpec, builder
|
||||
a.CompileSpec = p
|
||||
a.CompileSpec.GetPackage().SetBuildTimestamp(time.Now().String())
|
||||
|
||||
err = a.WriteYaml(p.GetOutputPath())
|
||||
err = a.WriteYAML(p.GetOutputPath())
|
||||
if err != nil {
|
||||
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.CompileSpec.GetPackage().SetBuildTimestamp(time.Now().String())
|
||||
|
||||
err = a.WriteYaml(p.GetOutputPath())
|
||||
err = a.WriteYAML(p.GetOutputPath())
|
||||
if err != nil {
|
||||
return a, errors.Wrap(err, "Failed while writing metadata file")
|
||||
}
|
||||
|
@@ -63,6 +63,7 @@ type PackageArtifact struct {
|
||||
CompressionType compression.Implementation `json:"compressiontype"`
|
||||
Files []string `json:"files"`
|
||||
PackageCacheImage string `json:"package_cacheimage"`
|
||||
Runtime *pkg.DefaultPackage `json:"runtime,omitempty"`
|
||||
}
|
||||
|
||||
func (p *PackageArtifact) ShallowCopy() *PackageArtifact {
|
||||
@@ -101,19 +102,23 @@ func (a *PackageArtifact) Verify() error {
|
||||
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.
|
||||
err := a.Hash()
|
||||
if err != nil {
|
||||
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)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "While marshalling for PackageArtifact YAML")
|
||||
|
@@ -318,7 +318,17 @@ func GenerateRepository(p ...RepositoryOption) (*LuetSystemRepository, error) {
|
||||
}
|
||||
if _, err := runtimeTree.FindPackage(art.CompileSpec.Package); err != nil && art.CompileSpec.Package.Name != "" {
|
||||
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
|
||||
|
@@ -29,7 +29,7 @@ func (s *System) ExecuteFinalizers(packs []pkg.Package) error {
|
||||
executedFinalizer := map[string]bool{}
|
||||
for _, p := range packs {
|
||||
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 {
|
||||
Warning("Failed rendering finalizer for ", p.HumanReadableString(), err.Error())
|
||||
errs = multierror.Append(errs, err)
|
||||
|
@@ -21,11 +21,14 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
fileHelper "github.com/mudler/luet/pkg/helpers/file"
|
||||
|
||||
"github.com/mudler/luet/pkg/helpers/docker"
|
||||
"github.com/mudler/luet/pkg/helpers/match"
|
||||
version "github.com/mudler/luet/pkg/versioner"
|
||||
@@ -124,7 +127,11 @@ type Package interface {
|
||||
JSON() ([]byte, error)
|
||||
}
|
||||
|
||||
const PackageMetaSuffix = "metadata.yaml"
|
||||
const (
|
||||
PackageMetaSuffix = "metadata.yaml"
|
||||
PackageCollectionFile = "collection.yaml"
|
||||
PackageDefinitionFile = "definition.yaml"
|
||||
)
|
||||
|
||||
type Tree interface {
|
||||
GetPackageSet() PackageDatabase
|
||||
@@ -215,11 +222,14 @@ func GetRawPackages(yml []byte) (rawPackages, error) {
|
||||
return rawPackages.Packages, nil
|
||||
|
||||
}
|
||||
func DefaultPackagesFromYaml(yml []byte) ([]DefaultPackage, error) {
|
||||
|
||||
var unescaped struct {
|
||||
Packages []DefaultPackage `json:"packages"`
|
||||
}
|
||||
type Collection struct {
|
||||
Packages []DefaultPackage `json:"packages"`
|
||||
}
|
||||
|
||||
func DefaultPackagesFromYAML(yml []byte) ([]DefaultPackage, error) {
|
||||
|
||||
var unescaped Collection
|
||||
source, err := yaml.YAMLToJSON(yml)
|
||||
if err != nil {
|
||||
return []DefaultPackage{}, err
|
||||
@@ -381,6 +391,10 @@ func (p *DefaultPackage) MatchLabel(r *regexp.Regexp) bool {
|
||||
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 {
|
||||
return match.MapHasKey(&p.Annotations, label)
|
||||
}
|
||||
@@ -703,6 +717,39 @@ func (set Packages) Unique() Packages {
|
||||
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) {
|
||||
if _, ok := visited[pack.HumanReadableString()]; ok {
|
||||
return nil, nil
|
||||
|
@@ -90,12 +90,12 @@ func (r *CompilerRecipe) Load(path string) error {
|
||||
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
|
||||
}
|
||||
|
||||
switch info.Name() {
|
||||
case DefinitionFile:
|
||||
case pkg.PackageDefinitionFile:
|
||||
|
||||
pack, err := ReadDefinitionFile(currentpath)
|
||||
if err != nil {
|
||||
@@ -130,14 +130,14 @@ func (r *CompilerRecipe) Load(path string) error {
|
||||
return errors.Wrap(err, "Error creating package "+pack.GetName())
|
||||
}
|
||||
|
||||
case CollectionFile:
|
||||
case pkg.PackageCollectionFile:
|
||||
|
||||
dat, err := ioutil.ReadFile(currentpath)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Error reading file "+currentpath)
|
||||
}
|
||||
|
||||
packs, err := pkg.DefaultPackagesFromYaml(dat)
|
||||
packs, err := pkg.DefaultPackagesFromYAML(dat)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Error reading yaml "+currentpath)
|
||||
}
|
||||
|
@@ -56,7 +56,7 @@ func (r *InstallerRecipe) Save(path string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(filepath.Join(dir, DefinitionFile), data, 0644)
|
||||
err = ioutil.WriteFile(filepath.Join(dir, pkg.PackageDefinitionFile), data, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -86,7 +86,7 @@ func (r *InstallerRecipe) Load(path string) error {
|
||||
// the function that handles each file or dir
|
||||
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
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ func (r *InstallerRecipe) Load(path string) error {
|
||||
}
|
||||
|
||||
switch info.Name() {
|
||||
case DefinitionFile:
|
||||
case pkg.PackageDefinitionFile:
|
||||
pack, err := pkg.DefaultPackageFromYaml(dat)
|
||||
if err != nil {
|
||||
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())
|
||||
}
|
||||
|
||||
case CollectionFile:
|
||||
packs, err := pkg.DefaultPackagesFromYaml(dat)
|
||||
case pkg.PackageCollectionFile:
|
||||
packs, err := pkg.DefaultPackagesFromYAML(dat)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Error reading yaml "+currentpath)
|
||||
}
|
||||
|
@@ -33,11 +33,6 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
DefinitionFile = "definition.yaml"
|
||||
CollectionFile = "collection.yaml"
|
||||
)
|
||||
|
||||
func NewGeneralRecipe(db pkg.PackageDatabase) Builder { return &Recipe{Database: db} }
|
||||
|
||||
// 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())
|
||||
os.MkdirAll(dir, os.ModePerm)
|
||||
|
||||
err := WriteDefinitionFile(p, filepath.Join(dir, DefinitionFile))
|
||||
err := WriteDefinitionFile(p, filepath.Join(dir, pkg.PackageDefinitionFile))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -96,7 +91,7 @@ func (r *Recipe) Load(path string) error {
|
||||
// the function that handles each file or dir
|
||||
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
|
||||
}
|
||||
|
||||
@@ -106,7 +101,7 @@ func (r *Recipe) Load(path string) error {
|
||||
}
|
||||
|
||||
switch info.Name() {
|
||||
case DefinitionFile:
|
||||
case pkg.PackageDefinitionFile:
|
||||
pack, err := pkg.DefaultPackageFromYaml(dat)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Error reading yaml "+currentpath)
|
||||
@@ -118,8 +113,8 @@ func (r *Recipe) Load(path string) error {
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Error creating package "+pack.GetName())
|
||||
}
|
||||
case CollectionFile:
|
||||
packs, err := pkg.DefaultPackagesFromYaml(dat)
|
||||
case pkg.PackageCollectionFile:
|
||||
packs, err := pkg.DefaultPackagesFromYAML(dat)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Error reading yaml "+currentpath)
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
@@ -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(""))
|
||||
})
|
||||
})
|
||||
|
||||
})
|
@@ -1,5 +1,4 @@
|
||||
// Copyright © 2019-2020 Ettore Di Giacinto <mudler@gentoo.org>,
|
||||
// Daniele Rondina <geaaru@sabayonlinux.org>
|
||||
// Copyright © 2019-2021 Ettore Di Giacinto <mudler@gentoo.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
|
||||
@@ -18,15 +17,79 @@ package version
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
semver "github.com/hashicorp/go-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
|
||||
// It tries different approaches to sort, validate, and sanitize to a common versioning format
|
||||
// that is understendable by the whole code
|
||||
@@ -38,55 +101,49 @@ func DefaultVersioner() Versioner {
|
||||
|
||||
func (w *WrappedVersioner) Validate(version string) error {
|
||||
if !debversion.Valid(version) {
|
||||
return errors.New("Invalid version")
|
||||
return errors.New("invalid version")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *WrappedVersioner) ValidateSelector(version string, selector string) bool {
|
||||
vS, err := ParseVersion(selector)
|
||||
func (w *WrappedVersioner) ValidateSelector(vv string, selector string) bool {
|
||||
if vv == "" {
|
||||
return true
|
||||
}
|
||||
vv = w.Sanitize(vv)
|
||||
selector = w.Sanitize(selector)
|
||||
|
||||
sel := readPackageSelector(selector)
|
||||
|
||||
selectorV, err := version.NewVersion(sel.Version)
|
||||
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)
|
||||
if err != nil {
|
||||
return false
|
||||
switch sel.Condition {
|
||||
case selectorGreaterOrEqualThen:
|
||||
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 ok
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (w *WrappedVersioner) Sanitize(s string) string {
|
||||
return 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)
|
||||
return strings.TrimSpace(strings.ReplaceAll(s, "_", "-"))
|
||||
}
|
||||
|
||||
func (w *WrappedVersioner) Sort(toSort []string) []string {
|
||||
@@ -102,35 +159,6 @@ func (w *WrappedVersioner) Sort(toSort []string) []string {
|
||||
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))
|
||||
for i, r := range versionsRaw {
|
||||
v, _ := debversion.NewVersion(r)
|
||||
|
@@ -17,6 +17,8 @@
|
||||
package version_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
. "github.com/mudler/luet/pkg/versioner"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "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
|
||||
Context("Debian Sorting", func() {
|
||||
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"}))
|
||||
})
|
||||
})
|
||||
|
||||
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())
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
})
|
||||
|
Reference in New Issue
Block a user