ltmpl: Add version compare support to installpkg
This adds support for enforcing version requirements on installed packages. See the documentation in ltmpl.installpkg for details.
This commit is contained in:
parent
f2c8d4f6bb
commit
be166dc724
@ -1,5 +1,9 @@
|
|||||||
## lorax template file: populate the ramdisk (runtime image)
|
## lorax template file: populate the ramdisk (runtime image)
|
||||||
<%page args="basearch, product"/>
|
<%page args="basearch, product"/>
|
||||||
|
<%
|
||||||
|
# This version of grub2 moves the font directory and is needed to keep the efi template from failing.
|
||||||
|
GRUB2VER="1:2.06-3"
|
||||||
|
%>
|
||||||
|
|
||||||
## anaconda package
|
## anaconda package
|
||||||
installpkg anaconda anaconda-widgets kexec-tools-anaconda-addon anaconda-install-img-deps
|
installpkg anaconda anaconda-widgets kexec-tools-anaconda-addon anaconda-install-img-deps
|
||||||
@ -37,12 +41,13 @@ installpkg glibc-all-langpacks
|
|||||||
## arch-specific packages (bootloaders etc.)
|
## arch-specific packages (bootloaders etc.)
|
||||||
%if basearch == "aarch64":
|
%if basearch == "aarch64":
|
||||||
installpkg efibootmgr
|
installpkg efibootmgr
|
||||||
installpkg grub2-efi-aa64-cdboot shim-aa64
|
installpkg grub2-efi-aa64-cdboot>=${GRUB2VER}
|
||||||
|
installpkg shim-aa64
|
||||||
installpkg uboot-tools
|
installpkg uboot-tools
|
||||||
%endif
|
%endif
|
||||||
%if basearch in ("arm", "armhfp"):
|
%if basearch in ("arm", "armhfp"):
|
||||||
installpkg efibootmgr
|
installpkg efibootmgr
|
||||||
installpkg grub2-efi-arm-cdboot
|
installpkg grub2-efi-arm-cdboot>=${GRUB2VER}
|
||||||
installpkg grubby-deprecated
|
installpkg grubby-deprecated
|
||||||
installpkg kernel-lpae
|
installpkg kernel-lpae
|
||||||
installpkg uboot-tools
|
installpkg uboot-tools
|
||||||
@ -51,19 +56,22 @@ installpkg glibc-all-langpacks
|
|||||||
installpkg gpart
|
installpkg gpart
|
||||||
%endif
|
%endif
|
||||||
%if basearch == "x86_64":
|
%if basearch == "x86_64":
|
||||||
installpkg grub2-tools-efi
|
installpkg grub2-tools-efi>=${GRUB2VER}
|
||||||
installpkg efibootmgr
|
installpkg efibootmgr
|
||||||
installpkg shim-x64 grub2-efi-x64-cdboot
|
installpkg shim-x64
|
||||||
installpkg shim-ia32 grub2-efi-ia32-cdboot
|
installpkg grub2-efi-x64-cdboot>=${GRUB2VER}
|
||||||
|
installpkg shim-ia32
|
||||||
|
installpkg grub2-efi-ia32-cdboot>=${GRUB2VER}
|
||||||
%endif
|
%endif
|
||||||
%if basearch in ("i386", "x86_64"):
|
%if basearch in ("i386", "x86_64"):
|
||||||
installpkg biosdevname syslinux
|
installpkg biosdevname syslinux
|
||||||
installpkg grub2-tools grub2-tools-minimal grub2-tools-extra
|
installpkg grub2-tools>=${GRUB2VER} grub2-tools-minimal>=${GRUB2VER}
|
||||||
|
installpkg grub2-tools-extra>=${GRUB2VER}
|
||||||
%endif
|
%endif
|
||||||
%if basearch == "ppc64le":
|
%if basearch == "ppc64le":
|
||||||
installpkg powerpc-utils lsvpd ppc64-diag
|
installpkg powerpc-utils lsvpd ppc64-diag
|
||||||
installpkg grub2-tools grub2-tools-minimal grub2-tools-extra
|
installpkg grub2-tools>=${GRUB2VER} grub2-tools-minimal>=${GRUB2VER}
|
||||||
installpkg grub2-${basearch}
|
installpkg grub2-tools-extra>=${GRUB2VER} grub2-${basearch}>=${GRUB2VER}
|
||||||
%endif
|
%endif
|
||||||
%if basearch == "s390x":
|
%if basearch == "s390x":
|
||||||
installpkg lsscsi s390utils-base s390utils-cmsfs-fuse s390utils-hmcdrvfs
|
installpkg lsscsi s390utils-base s390utils-cmsfs-fuse s390utils-hmcdrvfs
|
||||||
|
@ -185,8 +185,149 @@ class TemplateRunner(object):
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
class InstallpkgMixin:
|
||||||
|
"""Helper class used with *Runner classes"""
|
||||||
|
def _pkgver(self, pkg_spec):
|
||||||
|
"""
|
||||||
|
Helper to parse package version compare operators
|
||||||
|
|
||||||
|
Returns a list of matching package objects or an empty list
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
"bash>4.01"
|
||||||
|
"tmux>=3.1.4-5"
|
||||||
|
"grub2<2.06"
|
||||||
|
"""
|
||||||
|
# Always return the highest of the filtered results
|
||||||
|
if not any(g for g in ['=', '<', '>', '!'] if g in pkg_spec):
|
||||||
|
query = dnf.subject.Subject(pkg_spec).get_best_query(self.dbo.sack)
|
||||||
|
else:
|
||||||
|
pcv = re.split(r'([!<>=]+)', pkg_spec)
|
||||||
|
if not pcv[0]:
|
||||||
|
raise RuntimeError("Missing package name")
|
||||||
|
if not pcv[-1]:
|
||||||
|
raise RuntimeError("Missing version")
|
||||||
|
if len(pcv) != 3:
|
||||||
|
raise RuntimeError("Too many comparisons")
|
||||||
|
|
||||||
|
query = dnf.subject.Subject(pcv[0]).get_best_query(self.dbo.sack)
|
||||||
|
|
||||||
|
# Parse the comparison operators
|
||||||
|
if pcv[1] == "=" or pcv[1] == "==":
|
||||||
|
query.filterm(evr__eq = pcv[2])
|
||||||
|
elif pcv[1] == "!=" or pcv[1] == "<>":
|
||||||
|
query.filterm(evr__neq = pcv[2])
|
||||||
|
elif pcv[1] == ">":
|
||||||
|
query.filterm(evr__gt = pcv[2])
|
||||||
|
elif pcv[1] == ">=" or pcv[1] == "=>":
|
||||||
|
query.filterm(evr__gte = pcv[2])
|
||||||
|
elif pcv[1] == "<":
|
||||||
|
query.filterm(evr__lt = pcv[2])
|
||||||
|
elif pcv[1] == "<=" or pcv[1] == "=<":
|
||||||
|
query.filterm(evr__lte = pcv[2])
|
||||||
|
|
||||||
|
# MUST be added last. Otherwise it will only return the latest, not the latest of the
|
||||||
|
# filtered results.
|
||||||
|
query.filterm(latest=True)
|
||||||
|
return [pkg for pkg in query.apply()]
|
||||||
|
|
||||||
|
def installpkg(self, *pkgs):
|
||||||
|
'''
|
||||||
|
installpkg [--required|--optional] [--except PKGGLOB [--except PKGGLOB ...]] PKGGLOB [PKGGLOB ...]
|
||||||
|
Request installation of all packages matching the given globs.
|
||||||
|
Note that this is just a *request* - nothing is *actually* installed
|
||||||
|
until the 'run_pkg_transaction' command is given.
|
||||||
|
|
||||||
|
The non-except PKGGLOB can contain a version comparison. This should
|
||||||
|
not be used as a substitute for package dependencies, it should be
|
||||||
|
used to enforce installation of tools required by the templates. eg.
|
||||||
|
grub2 changed the font location in 2.06-2 so the current templates
|
||||||
|
require grub2 to be 2.06-2 or later.
|
||||||
|
|
||||||
|
installpkg tmux>=2.8 bash=5.0.0-1
|
||||||
|
|
||||||
|
It supports the =,!=,>,>=,<,<= operators. == is an alias for =, and
|
||||||
|
<> is an alias for !=
|
||||||
|
|
||||||
|
There should be no spaces between the package name, the compare
|
||||||
|
operator, and the version.
|
||||||
|
|
||||||
|
NOTE: When testing for equality you must include the version AND
|
||||||
|
release, otherwise it won't match anything.
|
||||||
|
|
||||||
|
--required is now the default. If the PKGGLOB can be missing pass --optional
|
||||||
|
'''
|
||||||
|
if pkgs[0] == '--optional':
|
||||||
|
pkgs = pkgs[1:]
|
||||||
|
required = False
|
||||||
|
elif pkgs[0] == '--required':
|
||||||
|
pkgs = pkgs[1:]
|
||||||
|
required = True
|
||||||
|
else:
|
||||||
|
required = True
|
||||||
|
|
||||||
|
excludes = []
|
||||||
|
while '--except' in pkgs:
|
||||||
|
idx = pkgs.index('--except')
|
||||||
|
if len(pkgs) == idx+1:
|
||||||
|
raise ValueError("installpkg needs an argument after --except")
|
||||||
|
|
||||||
|
# TODO: Check for bare version compare operators
|
||||||
|
excludes.append(pkgs[idx+1])
|
||||||
|
pkgs = pkgs[:idx] + pkgs[idx+2:]
|
||||||
|
|
||||||
|
errors = False
|
||||||
|
for p in pkgs:
|
||||||
|
# Did a version compare operatore end up in the list?
|
||||||
|
if p[0] in ['=', '<', '>', '!']:
|
||||||
|
raise RuntimeError("Version compare operators cannot be surrounded by spaces")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Start by using Subject to generate a package query, which will
|
||||||
|
# give us a query object similar to what dbo.install would select,
|
||||||
|
# minus the handling for multilib. This query may contain
|
||||||
|
# multiple arches. Pull the package names out of that, filter any
|
||||||
|
# that match the excludes patterns, and pass those names back to
|
||||||
|
# dbo.install to do the actual, arch and version and multilib
|
||||||
|
# aware, package selction.
|
||||||
|
|
||||||
|
# dnf queries don't have a concept of negative globs which is why
|
||||||
|
# the filtering is done the hard way.
|
||||||
|
|
||||||
|
# Get the latest package, or package matching the selected version
|
||||||
|
pkgnames = self._pkgver(p)
|
||||||
|
if not pkgnames:
|
||||||
|
raise dnf.exceptions.PackageNotFoundError("no package matched", p)
|
||||||
|
|
||||||
|
# Apply excludes to the name only
|
||||||
|
for exclude in excludes:
|
||||||
|
pkgnames = [pkg for pkg in pkgnames if not fnmatch.fnmatch(pkg.name, exclude)]
|
||||||
|
|
||||||
|
# Convert to a sorted NVR list for installation
|
||||||
|
pkgnvrs = sorted(["{}-{}-{}".format(pkg.name, pkg.version, pkg.release) for pkg in pkgnames])
|
||||||
|
|
||||||
|
# If the request is a glob, expand it in the log
|
||||||
|
if any(g for g in ['*','?','.'] if g in p):
|
||||||
|
logger.info("installpkg: %s expands to %s", p, ",".join(pkgnvrs))
|
||||||
|
|
||||||
|
for pkgnvr in pkgnvrs:
|
||||||
|
try:
|
||||||
|
self.dbo.install(pkgnvr)
|
||||||
|
except Exception as e: # pylint: disable=broad-except
|
||||||
|
if required:
|
||||||
|
raise
|
||||||
|
# Not required, log it and continue processing pkgs
|
||||||
|
logger.error("installpkg %s failed: %s", pkgnvr, str(e))
|
||||||
|
except Exception as e: # pylint: disable=broad-except
|
||||||
|
logger.error("installpkg %s failed: %s", p, str(e))
|
||||||
|
errors = True
|
||||||
|
|
||||||
|
if errors and required:
|
||||||
|
raise Exception("Required installpkg failed.")
|
||||||
|
|
||||||
|
|
||||||
# TODO: operate inside an actual chroot for safety? Not that RPM bothers..
|
# TODO: operate inside an actual chroot for safety? Not that RPM bothers..
|
||||||
class LoraxTemplateRunner(TemplateRunner):
|
class LoraxTemplateRunner(TemplateRunner, InstallpkgMixin):
|
||||||
'''
|
'''
|
||||||
This class parses and executes Lorax templates. Sample usage:
|
This class parses and executes Lorax templates. Sample usage:
|
||||||
|
|
||||||
@ -531,77 +672,6 @@ class LoraxTemplateRunner(TemplateRunner):
|
|||||||
logger.error('command returned failure (%d)', e.returncode)
|
logger.error('command returned failure (%d)', e.returncode)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def installpkg(self, *pkgs):
|
|
||||||
'''
|
|
||||||
installpkg [--required|--optional] [--except PKGGLOB [--except PKGGLOB ...]] PKGGLOB [PKGGLOB ...]
|
|
||||||
Request installation of all packages matching the given globs.
|
|
||||||
Note that this is just a *request* - nothing is *actually* installed
|
|
||||||
until the 'run_pkg_transaction' command is given.
|
|
||||||
|
|
||||||
--required is now the default. If the PKGGLOB can be missing pass --optional
|
|
||||||
'''
|
|
||||||
if pkgs[0] == '--optional':
|
|
||||||
pkgs = pkgs[1:]
|
|
||||||
required = False
|
|
||||||
elif pkgs[0] == '--required':
|
|
||||||
pkgs = pkgs[1:]
|
|
||||||
required = True
|
|
||||||
else:
|
|
||||||
required = True
|
|
||||||
|
|
||||||
excludes = []
|
|
||||||
while '--except' in pkgs:
|
|
||||||
idx = pkgs.index('--except')
|
|
||||||
if len(pkgs) == idx+1:
|
|
||||||
raise ValueError("installpkg needs an argument after --except")
|
|
||||||
|
|
||||||
excludes.append(pkgs[idx+1])
|
|
||||||
pkgs = pkgs[:idx] + pkgs[idx+2:]
|
|
||||||
|
|
||||||
errors = False
|
|
||||||
for p in pkgs:
|
|
||||||
try:
|
|
||||||
# Start by using Subject to generate a package query, which will
|
|
||||||
# give us a query object similar to what dbo.install would select,
|
|
||||||
# minus the handling for multilib. This query may contain
|
|
||||||
# multiple arches. Pull the package names out of that, filter any
|
|
||||||
# that match the excludes patterns, and pass those names back to
|
|
||||||
# dbo.install to do the actual, arch and version and multilib
|
|
||||||
# aware, package selction.
|
|
||||||
|
|
||||||
# dnf queries don't have a concept of negative globs which is why
|
|
||||||
# the filtering is done the hard way.
|
|
||||||
|
|
||||||
pkgnames = [pkg for pkg in dnf.subject.Subject(p).get_best_query(self.dbo.sack).filter(latest=True)]
|
|
||||||
if not pkgnames:
|
|
||||||
raise dnf.exceptions.PackageNotFoundError("no package matched", p)
|
|
||||||
|
|
||||||
# Apply excludes to the name only
|
|
||||||
for exclude in excludes:
|
|
||||||
pkgnames = [pkg for pkg in pkgnames if not fnmatch.fnmatch(pkg.name, exclude)]
|
|
||||||
|
|
||||||
# Convert to a sorted NVR list for installation
|
|
||||||
pkgnvrs = sorted(["{}-{}-{}".format(pkg.name, pkg.version, pkg.release) for pkg in pkgnames])
|
|
||||||
|
|
||||||
# If the request is a glob, expand it in the log
|
|
||||||
if any(g for g in ['*','?','.'] if g in p):
|
|
||||||
logger.info("installpkg: %s expands to %s", p, ",".join(pkgnvrs))
|
|
||||||
|
|
||||||
for pkgnvr in pkgnvrs:
|
|
||||||
try:
|
|
||||||
self.dbo.install(pkgnvr)
|
|
||||||
except Exception as e: # pylint: disable=broad-except
|
|
||||||
if required:
|
|
||||||
raise
|
|
||||||
# Not required, log it and continue processing pkgs
|
|
||||||
logger.error("installpkg %s failed: %s", pkgnvr, str(e))
|
|
||||||
except Exception as e: # pylint: disable=broad-except
|
|
||||||
logger.error("installpkg %s failed: %s", p, str(e))
|
|
||||||
errors = True
|
|
||||||
|
|
||||||
if errors and required:
|
|
||||||
raise Exception("Required installpkg failed.")
|
|
||||||
|
|
||||||
def removepkg(self, *pkgs):
|
def removepkg(self, *pkgs):
|
||||||
'''
|
'''
|
||||||
removepkg PKGGLOB [PKGGLOB...]
|
removepkg PKGGLOB [PKGGLOB...]
|
||||||
@ -800,7 +870,7 @@ class LoraxTemplateRunner(TemplateRunner):
|
|||||||
except CalledProcessError:
|
except CalledProcessError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class LiveTemplateRunner(TemplateRunner):
|
class LiveTemplateRunner(TemplateRunner, InstallpkgMixin):
|
||||||
"""
|
"""
|
||||||
This class parses and executes a limited Lorax template. Sample usage:
|
This class parses and executes a limited Lorax template. Sample usage:
|
||||||
|
|
||||||
@ -817,68 +887,3 @@ class LiveTemplateRunner(TemplateRunner):
|
|||||||
self.pkgnames = []
|
self.pkgnames = []
|
||||||
|
|
||||||
super(LiveTemplateRunner, self).__init__(fatalerrors, templatedir, defaults)
|
super(LiveTemplateRunner, self).__init__(fatalerrors, templatedir, defaults)
|
||||||
|
|
||||||
def installpkg(self, *pkgs):
|
|
||||||
'''
|
|
||||||
installpkg [--required|--optional] [--except PKGGLOB [--except PKGGLOB ...]] PKGGLOB [PKGGLOB ...]
|
|
||||||
Request installation of all packages matching the given globs.
|
|
||||||
Note that this is just a *request* - nothing is *actually* installed
|
|
||||||
until the 'run_pkg_transaction' command is given.
|
|
||||||
|
|
||||||
--required is now the default. If the PKGGLOB can be missing pass --optional
|
|
||||||
'''
|
|
||||||
if pkgs[0] == '--optional':
|
|
||||||
pkgs = pkgs[1:]
|
|
||||||
required = False
|
|
||||||
elif pkgs[0] == '--required':
|
|
||||||
pkgs = pkgs[1:]
|
|
||||||
required = True
|
|
||||||
else:
|
|
||||||
required = True
|
|
||||||
|
|
||||||
excludes = []
|
|
||||||
while '--except' in pkgs:
|
|
||||||
idx = pkgs.index('--except')
|
|
||||||
if len(pkgs) == idx+1:
|
|
||||||
raise ValueError("installpkg needs an argument after --except")
|
|
||||||
|
|
||||||
excludes.append(pkgs[idx+1])
|
|
||||||
pkgs = pkgs[:idx] + pkgs[idx+2:]
|
|
||||||
|
|
||||||
errors = False
|
|
||||||
for p in pkgs:
|
|
||||||
try:
|
|
||||||
# Start by using Subject to generate a package query, which will
|
|
||||||
# give us a query object similar to what dbo.install would select,
|
|
||||||
# minus the handling for multilib. This query may contain
|
|
||||||
# multiple arches. Pull the package names out of that, filter any
|
|
||||||
# that match the excludes patterns, and pass those names back to
|
|
||||||
# dbo.install to do the actual, arch and version and multilib
|
|
||||||
# aware, package selction.
|
|
||||||
|
|
||||||
# dnf queries don't have a concept of negative globs which is why
|
|
||||||
# the filtering is done the hard way.
|
|
||||||
|
|
||||||
pkgnames = [pkg for pkg in dnf.subject.Subject(p).get_best_query(self.dbo.sack).filter(latest=True)]
|
|
||||||
if not pkgnames:
|
|
||||||
raise dnf.exceptions.PackageNotFoundError("no package matched", p)
|
|
||||||
|
|
||||||
# Apply excludes to the name only
|
|
||||||
for exclude in excludes:
|
|
||||||
pkgnames = [pkg for pkg in pkgnames if not fnmatch.fnmatch(pkg.name, exclude)]
|
|
||||||
|
|
||||||
# Convert to a sorted NVR list for installation
|
|
||||||
pkgnvrs = sorted(["{}-{}-{}".format(pkg.name, pkg.version, pkg.release) for pkg in pkgnames])
|
|
||||||
|
|
||||||
# If the request is a glob, expand it in the log
|
|
||||||
if any(g for g in ['*','?','.'] if g in p):
|
|
||||||
logger.info("installpkg: %s expands to %s", p, ",".join(pkgnvrs))
|
|
||||||
|
|
||||||
self.pkgs.extend(pkgnvrs)
|
|
||||||
self.pkgnames.extend([pkg.name for pkg in pkgnames])
|
|
||||||
except Exception as e: # pylint: disable=broad-except
|
|
||||||
logger.error("installpkg %s failed: %s", p, str(e))
|
|
||||||
errors = True
|
|
||||||
|
|
||||||
if errors and required:
|
|
||||||
raise Exception("Required installpkg failed.")
|
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
<%page />
|
<%page />
|
||||||
installpkg anaconda-core
|
installpkg anaconda-core
|
||||||
installpkg --optional exact-1.3.17
|
installpkg --optional exact-1.3.17
|
||||||
installpkg --except fake-homer fake-*
|
installpkg --except fake-homer --except fake-milhouse --except fake-lisa fake-*
|
||||||
installpkg --required lots-of-files
|
installpkg --required lots-of-files
|
||||||
installpkg known-path
|
installpkg known-path
|
||||||
-installpkg missing-package
|
-installpkg missing-package
|
||||||
|
installpkg fake-milhouse>1.0.0-4
|
||||||
|
installpkg fake-lisa<1.2.0-1
|
||||||
run_pkg_transaction
|
run_pkg_transaction
|
||||||
|
@ -115,8 +115,10 @@ class LoraxTemplateRunnerTestCase(unittest.TestCase):
|
|||||||
self.repo1_dir = tempfile.mkdtemp(prefix="lorax.test.repo.")
|
self.repo1_dir = tempfile.mkdtemp(prefix="lorax.test.repo.")
|
||||||
makeFakeRPM(self.repo1_dir, "anaconda-core", 0, "0.0.1", "1")
|
makeFakeRPM(self.repo1_dir, "anaconda-core", 0, "0.0.1", "1")
|
||||||
makeFakeRPM(self.repo1_dir, "exact", 0, "1.3.17", "1")
|
makeFakeRPM(self.repo1_dir, "exact", 0, "1.3.17", "1")
|
||||||
makeFakeRPM(self.repo1_dir, "fake-milhouse", 0, "1.0.0", "1")
|
makeFakeRPM(self.repo1_dir, "fake-milhouse", 0, "1.0.0", "1", ["/fake-milhouse/1.0.0-1"])
|
||||||
|
makeFakeRPM(self.repo1_dir, "fake-bart", 0, "1.0.0", "6")
|
||||||
makeFakeRPM(self.repo1_dir, "fake-bart", 2, "1.13.0", "6")
|
makeFakeRPM(self.repo1_dir, "fake-bart", 2, "1.13.0", "6")
|
||||||
|
makeFakeRPM(self.repo1_dir, "fake-bart", 2, "2.3.0", "1")
|
||||||
makeFakeRPM(self.repo1_dir, "fake-homer", 0, "0.4.0", "2")
|
makeFakeRPM(self.repo1_dir, "fake-homer", 0, "0.4.0", "2")
|
||||||
makeFakeRPM(self.repo1_dir, "lots-of-files", 0, "0.1.1", "1",
|
makeFakeRPM(self.repo1_dir, "lots-of-files", 0, "0.1.1", "1",
|
||||||
["/lorax-files/file-one.txt",
|
["/lorax-files/file-one.txt",
|
||||||
@ -126,12 +128,15 @@ class LoraxTemplateRunnerTestCase(unittest.TestCase):
|
|||||||
os.system("createrepo_c " + self.repo1_dir)
|
os.system("createrepo_c " + self.repo1_dir)
|
||||||
|
|
||||||
self.repo2_dir = tempfile.mkdtemp(prefix="lorax.test.repo.")
|
self.repo2_dir = tempfile.mkdtemp(prefix="lorax.test.repo.")
|
||||||
makeFakeRPM(self.repo2_dir, "fake-milhouse", 0, "1.3.0", "1")
|
makeFakeRPM(self.repo2_dir, "fake-milhouse", 0, "1.0.0", "4", ["/fake-milhouse/1.0.0-4"])
|
||||||
makeFakeRPM(self.repo2_dir, "fake-lisa", 0, "1.2.0", "1")
|
makeFakeRPM(self.repo2_dir, "fake-milhouse", 0, "1.0.7", "1", ["/fake-milhouse/1.0.7-1"])
|
||||||
|
makeFakeRPM(self.repo2_dir, "fake-milhouse", 0, "1.3.0", "1", ["/fake-milhouse/1.3.0-1"])
|
||||||
|
makeFakeRPM(self.repo2_dir, "fake-lisa", 0, "1.2.0", "1", ["/fake-lisa/1.2.0-1"])
|
||||||
|
makeFakeRPM(self.repo2_dir, "fake-lisa", 0, "1.1.4", "5", ["/fake-lisa/1.1.4-5"])
|
||||||
os.system("createrepo_c " + self.repo2_dir)
|
os.system("createrepo_c " + self.repo2_dir)
|
||||||
|
|
||||||
self.repo3_dir = tempfile.mkdtemp(prefix="lorax.test.debug.repo.")
|
self.repo3_dir = tempfile.mkdtemp(prefix="lorax.test.debug.repo.")
|
||||||
makeFakeRPM(self.repo3_dir, "fake-marge", 0, "2.3.0", "1", ["/fake-marge/file-one.txt"])
|
makeFakeRPM(self.repo3_dir, "fake-marge", 0, "2.3.0", "1", ["/fake-marge/2.3.0-1"])
|
||||||
makeFakeRPM(self.repo3_dir, "fake-marge-debuginfo", 0, "2.3.0", "1", ["/fake-marge/file-one-debuginfo.txt"])
|
makeFakeRPM(self.repo3_dir, "fake-marge-debuginfo", 0, "2.3.0", "1", ["/fake-marge/file-one-debuginfo.txt"])
|
||||||
os.system("createrepo_c " + self.repo3_dir)
|
os.system("createrepo_c " + self.repo3_dir)
|
||||||
|
|
||||||
@ -154,24 +159,89 @@ class LoraxTemplateRunnerTestCase(unittest.TestCase):
|
|||||||
shutil.rmtree(self.repo2_dir)
|
shutil.rmtree(self.repo2_dir)
|
||||||
shutil.rmtree(self.root_dir)
|
shutil.rmtree(self.root_dir)
|
||||||
|
|
||||||
def test_00_runner_multi_repo(self):
|
def test_pkgver_errors(self):
|
||||||
|
"""Test error states of _pkgver"""
|
||||||
|
with self.assertRaises(RuntimeError) as e:
|
||||||
|
self.runner._pkgver("=")
|
||||||
|
self.assertEqual(str(e.exception), "Missing package name")
|
||||||
|
|
||||||
|
|
||||||
|
with self.assertRaises(RuntimeError) as e:
|
||||||
|
self.runner._pkgver("foopkg=")
|
||||||
|
self.assertEqual(str(e.exception), "Missing version")
|
||||||
|
|
||||||
|
with self.assertRaises(RuntimeError) as e:
|
||||||
|
self.runner._pkgver("foopkg>1.0.0-1<1.0.6-1")
|
||||||
|
self.assertEqual(str(e.exception), "Too many comparisons")
|
||||||
|
|
||||||
|
|
||||||
|
def test_00_pkgver(self):
|
||||||
|
"""Test all the version comparison operators with pkgver"""
|
||||||
|
matrix = [
|
||||||
|
("fake-milhouse>=2.1.0-1", ""), # Not available
|
||||||
|
("fake-bart>=2:3.0.0-2", ""), # Not available
|
||||||
|
("fake-bart>2:1.13.0-6", "fake-bart-2:2.3.0-1"),
|
||||||
|
("fake-bart<2:1.13.0-6", "fake-bart-1.0.0-6"),
|
||||||
|
("fake-milhouse==1.3.0-1", "fake-milhouse-1.3.0-1"),
|
||||||
|
("fake-milhouse=1.3.0-1", "fake-milhouse-1.3.0-1"),
|
||||||
|
("fake-milhouse=1.0.0-4", "fake-milhouse-1.0.0-4"),
|
||||||
|
("fake-milhouse!=1.3.0-1", "fake-milhouse-1.0.7-1"),
|
||||||
|
("fake-milhouse<>1.3.0-1", "fake-milhouse-1.0.7-1"),
|
||||||
|
("fake-milhouse>1.0.0-4", "fake-milhouse-1.3.0-1"),
|
||||||
|
("fake-milhouse>=1.3.0", "fake-milhouse-1.3.0-1"),
|
||||||
|
("fake-milhouse>=1.0.7-1", "fake-milhouse-1.3.0-1"),
|
||||||
|
("fake-milhouse=>1.0.0-4", "fake-milhouse-1.3.0-1"),
|
||||||
|
("fake-milhouse<=1.0.0-4", "fake-milhouse-1.0.0-4"),
|
||||||
|
("fake-milhouse=<1.0.7-1", "fake-milhouse-1.0.7-1"),
|
||||||
|
("fake-milhouse<1.3.0", "fake-milhouse-1.0.7-1"),
|
||||||
|
("fake-milhouse<1.3.0-1", "fake-milhouse-1.0.7-1"),
|
||||||
|
("fake-milhouse<1.0.7-1", "fake-milhouse-1.0.0-4"),
|
||||||
|
]
|
||||||
|
|
||||||
|
def nevra(pkg):
|
||||||
|
if pkg.epoch:
|
||||||
|
return "{}-{}:{}-{}".format(pkg.name, pkg.epoch, pkg.version, pkg.release)
|
||||||
|
else:
|
||||||
|
return "{}-{}-{}".format(pkg.name, pkg.version, pkg.release)
|
||||||
|
|
||||||
|
print([nevra(p) for p in list(self.dnfbase.sack.query().available())])
|
||||||
|
for t in matrix:
|
||||||
|
r = self.runner._pkgver(t[0])
|
||||||
|
if t[1]:
|
||||||
|
self.assertTrue(len(r) > 0, t[0])
|
||||||
|
self.assertEqual(nevra(self.runner._pkgver(t[0])[0]), t[1], t[0])
|
||||||
|
else:
|
||||||
|
self.assertEqual(r, [], t[0])
|
||||||
|
|
||||||
|
def test_01_runner_multi_repo(self):
|
||||||
"""Test installing packages with updates in a 2nd repo"""
|
"""Test installing packages with updates in a 2nd repo"""
|
||||||
# If this does not raise an error it means that:
|
# If this does not raise an error it means that:
|
||||||
# Installing a named package works (anaconda-core)
|
# Installing a named package works (anaconda-core)
|
||||||
# Installing a pinned package works (exact-1.3.17)
|
# Installing a pinned package works (exact-1.3.17)
|
||||||
# Installing a globbed set of package names from multiple repos works
|
# Installing a globbed set of package names from multiple repos works
|
||||||
|
# Installing a package using version compare
|
||||||
# removepkg removes a package's files
|
# removepkg removes a package's files
|
||||||
# removefrom removes some, but not all, of a package's files
|
# removefrom removes some, but not all, of a package's files
|
||||||
#
|
#
|
||||||
# These all need to be done in one template because run_pkg_transaction can only run once
|
# These all need to be done in one template because run_pkg_transaction can only run once
|
||||||
self.runner.run("install-test.tmpl")
|
self.runner.run("install-test.tmpl")
|
||||||
self.runner.run("install-remove-test.tmpl")
|
self.runner.run("install-remove-test.tmpl")
|
||||||
self.assertFalse(os.path.exists(joinpaths(self.root_dir, "/known-path/file-one.txt")))
|
|
||||||
self.assertTrue(os.path.exists(joinpaths(self.root_dir, "/lorax-files/file-one.txt")))
|
def exists(p):
|
||||||
self.assertFalse(os.path.exists(joinpaths(self.root_dir, "/lorax-files/file-two.txt")))
|
return os.path.exists(joinpaths(self.root_dir, p))
|
||||||
|
|
||||||
|
self.assertFalse(exists("/known-path/file-one.txt"))
|
||||||
|
self.assertTrue(exists("/lorax-files/file-one.txt"))
|
||||||
|
self.assertFalse(exists("/lorax-files/file-two.txt"))
|
||||||
|
self.assertTrue(exists("/fake-marge/2.3.0-1"))
|
||||||
|
|
||||||
# Check the debug log
|
# Check the debug log
|
||||||
self.assertTrue(os.path.exists(joinpaths(self.root_dir, "/root/debug-pkgs.log")))
|
self.assertTrue(exists("/root/debug-pkgs.log"))
|
||||||
|
|
||||||
|
# Check package version installs
|
||||||
|
self.assertTrue(exists("/fake-lisa/1.1.4-5"))
|
||||||
|
self.assertFalse(exists("/fake-lisa/1.2.0-1"))
|
||||||
|
self.assertTrue(exists("/fake-milhouse/1.3.0-1"))
|
||||||
|
|
||||||
def test_install_file(self):
|
def test_install_file(self):
|
||||||
"""Test append, and install template commands"""
|
"""Test append, and install template commands"""
|
||||||
|
Loading…
Reference in New Issue
Block a user