Fix depsolve version globbing
The blueprint version glob was being applied to the whole package NEVRA by yum (it lacks a separate API for just globbing versions), so this implements that in filterVersionGlob using fnmatchcase on the package names, and the yum package verGT comparison on the versions for the selected package. Also includes tests. Resolves: rhbz#1628114
This commit is contained in:
parent
9685fdd7aa
commit
2a85694c9b
@ -19,6 +19,7 @@ log = logging.getLogger("lorax-composer")
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
from ConfigParser import ConfigParser
|
from ConfigParser import ConfigParser
|
||||||
|
import fnmatch
|
||||||
from glob import glob
|
from glob import glob
|
||||||
import time
|
import time
|
||||||
|
|
||||||
@ -188,6 +189,24 @@ def projects_info(yb, project_names):
|
|||||||
yb.closeRpmDB()
|
yb.closeRpmDB()
|
||||||
return sorted(map(yaps_to_project_info, ybl.available), key=lambda p: p["name"].lower())
|
return sorted(map(yaps_to_project_info, ybl.available), key=lambda p: p["name"].lower())
|
||||||
|
|
||||||
|
def filterVersionGlob(pkgs, version):
|
||||||
|
"""Filter a list of yum package objects with a version glob
|
||||||
|
|
||||||
|
:param pkgs: list of yum package objects
|
||||||
|
:type pkgs: list
|
||||||
|
:param version: version matching glob
|
||||||
|
:type version: str
|
||||||
|
|
||||||
|
pkgs should be a list of all the versions of the *same* package.
|
||||||
|
Return the latest package that matches the 'version' glob.
|
||||||
|
"""
|
||||||
|
# Pick the version(s) matching the version glob
|
||||||
|
matches = [po for po in pkgs if fnmatch.fnmatchcase(po.version, version)]
|
||||||
|
if not matches:
|
||||||
|
raise RuntimeError("No package version matching %s" % version)
|
||||||
|
|
||||||
|
# yum implements __cmd__ using verCMP so this will return the highest matching version
|
||||||
|
return max(matches)
|
||||||
|
|
||||||
def projects_depsolve(yb, projects, groups):
|
def projects_depsolve(yb, projects, groups):
|
||||||
"""Return the dependencies for a list of projects
|
"""Return the dependencies for a list of projects
|
||||||
@ -212,10 +231,21 @@ def projects_depsolve(yb, projects, groups):
|
|||||||
for name, version in projects:
|
for name, version in projects:
|
||||||
if not version:
|
if not version:
|
||||||
version = "*"
|
version = "*"
|
||||||
pattern = "%s-%s" % (name, version)
|
pattern = "%s %s" % (name, version)
|
||||||
|
|
||||||
|
# yum.install's pattern matches the whole nevra, which can result in -* matching
|
||||||
|
# unexpected packages. So we need to implement our own version globbing.
|
||||||
|
pkgs = yb.pkgSack.searchNames([name])
|
||||||
|
if not pkgs:
|
||||||
|
install_errors.append((name, "No package name matching %s" % name))
|
||||||
|
continue
|
||||||
|
|
||||||
try:
|
try:
|
||||||
yb.install(pattern=pattern)
|
po = filterVersionGlob(pkgs, version)
|
||||||
except YumBaseError as e:
|
log.debug("Chose %s as best match for %s", po.nevra, pattern)
|
||||||
|
|
||||||
|
yb.install(po=po)
|
||||||
|
except (YumBaseError, RuntimeError) as e:
|
||||||
install_errors.append((pattern, str(e)))
|
install_errors.append((pattern, str(e)))
|
||||||
|
|
||||||
# Were there problems installing these packages?
|
# Were there problems installing these packages?
|
||||||
|
@ -23,6 +23,7 @@ import tempfile
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from yum.Errors import YumBaseError
|
from yum.Errors import YumBaseError
|
||||||
|
from yum.packages import PackageObject
|
||||||
|
|
||||||
from pylorax.sysutils import joinpaths
|
from pylorax.sysutils import joinpaths
|
||||||
from pylorax.api.config import configure, make_yum_dirs
|
from pylorax.api.config import configure, make_yum_dirs
|
||||||
@ -30,7 +31,7 @@ from pylorax.api.projects import api_time, api_changelog, yaps_to_project, yaps_
|
|||||||
from pylorax.api.projects import tm_to_dep, yaps_to_module, projects_list, projects_info, projects_depsolve
|
from pylorax.api.projects import tm_to_dep, yaps_to_module, projects_list, projects_info, projects_depsolve
|
||||||
from pylorax.api.projects import modules_list, modules_info, ProjectsError, dep_evra, dep_nevra
|
from pylorax.api.projects import modules_list, modules_info, ProjectsError, dep_evra, dep_nevra
|
||||||
from pylorax.api.projects import repo_to_source, get_repo_sources, delete_repo_source, source_to_repo
|
from pylorax.api.projects import repo_to_source, get_repo_sources, delete_repo_source, source_to_repo
|
||||||
from pylorax.api.projects import yum_repo_to_file_repo
|
from pylorax.api.projects import yum_repo_to_file_repo, filterVersionGlob
|
||||||
from pylorax.api.yumbase import get_base_object
|
from pylorax.api.yumbase import get_base_object
|
||||||
|
|
||||||
|
|
||||||
@ -59,6 +60,15 @@ class TM(object):
|
|||||||
release = "release"
|
release = "release"
|
||||||
arch = "arch"
|
arch = "arch"
|
||||||
|
|
||||||
|
def NewPackageObject(name, epoch, version, release, arch):
|
||||||
|
po = PackageObject()
|
||||||
|
po.name = name
|
||||||
|
po.epoch = epoch
|
||||||
|
po.version = version
|
||||||
|
po.release = release
|
||||||
|
po.arch = arch
|
||||||
|
po.pkgtup = (po.name, po.arch, po.epoch, po.version, po.release)
|
||||||
|
return po
|
||||||
|
|
||||||
class ProjectsTest(unittest.TestCase):
|
class ProjectsTest(unittest.TestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -204,6 +214,52 @@ class ProjectsTest(unittest.TestCase):
|
|||||||
with self.assertRaises(ProjectsError):
|
with self.assertRaises(ProjectsError):
|
||||||
projects_depsolve(self.yb, [("nada-package", "*.*")], [])
|
projects_depsolve(self.yb, [("nada-package", "*.*")], [])
|
||||||
|
|
||||||
|
def test_projects_depsolve_glob(self):
|
||||||
|
"""Test that depsolving with a '*' version glob doesn't glob package names"""
|
||||||
|
deps = projects_depsolve(self.yb, [("python", "*")], [])
|
||||||
|
self.assertTrue(len(deps) > 1)
|
||||||
|
self.assertTrue("python" in [dep["name"] for dep in deps])
|
||||||
|
self.assertTrue("python-blivet" not in [dep["name"] for dep in deps])
|
||||||
|
|
||||||
|
def test_projects_filterVersionGlob(self):
|
||||||
|
"""Test the filterVersionGlob function"""
|
||||||
|
pkgs = [NewPackageObject("foopkg", "0", "1.1.5", "el7", "x86_64"),
|
||||||
|
NewPackageObject("foopkg", "0", "1.2.0", "el7", "x86_64"),
|
||||||
|
NewPackageObject("foopkg", "0", "2.4.3", "el7", "x86_64"),
|
||||||
|
NewPackageObject("foopkg", "0", "2.4.17", "el7", "x86_64"),
|
||||||
|
NewPackageObject("foopkg", "0", "2.10.0", "el7", "x86_64"),
|
||||||
|
NewPackageObject("foopkg", "0", "3.0.0", "el7", "x86_64")]
|
||||||
|
|
||||||
|
# 1.1.5 version
|
||||||
|
self.assertEqual(filterVersionGlob(pkgs, "1.1.5"), pkgs[0])
|
||||||
|
|
||||||
|
# Newest 1.x.x version
|
||||||
|
self.assertEqual(filterVersionGlob(pkgs, "1.*.*"), pkgs[1])
|
||||||
|
|
||||||
|
# Newest 2.4.x version
|
||||||
|
self.assertEqual(filterVersionGlob(pkgs, "2.4.*"), pkgs[3])
|
||||||
|
|
||||||
|
# Newest 2.x version
|
||||||
|
self.assertEqual(filterVersionGlob(pkgs, "2.*"), pkgs[4])
|
||||||
|
|
||||||
|
# Newest version
|
||||||
|
self.assertEqual(filterVersionGlob(pkgs, "*"), pkgs[5])
|
||||||
|
|
||||||
|
def test_projects_filterVersionGlob_epoch(self):
|
||||||
|
"""Test the filterVersionGlob function with epoch"""
|
||||||
|
pkgs = [NewPackageObject("foopkg", "2", "1.1.5", "el7", "x86_64"),
|
||||||
|
NewPackageObject("foopkg", "2", "1.2.0", "el7", "x86_64"),
|
||||||
|
NewPackageObject("foopkg", "0", "2.4.3", "el7", "x86_64")]
|
||||||
|
|
||||||
|
# 1.1.5 version
|
||||||
|
self.assertEqual(filterVersionGlob(pkgs, "1.1.5"), pkgs[0])
|
||||||
|
|
||||||
|
# Newest 1.x.x version
|
||||||
|
self.assertEqual(filterVersionGlob(pkgs, "1.*.*"), pkgs[1])
|
||||||
|
|
||||||
|
# Newest version
|
||||||
|
self.assertEqual(filterVersionGlob(pkgs, "*"), pkgs[1])
|
||||||
|
|
||||||
def test_modules_list(self):
|
def test_modules_list(self):
|
||||||
modules = modules_list(self.yb, None)
|
modules = modules_list(self.yb, None)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user