Merge pull request #6574 from terminalmage/issue5270

Abstract version comparison and fix version specification in pip.installed states
This commit is contained in:
Thomas S Hatch 2013-08-08 12:07:27 -07:00
commit 9f2018fff4
18 changed files with 182 additions and 447 deletions

View file

@ -150,8 +150,13 @@ def latest_version(*names, **kwargs):
# If there are no installed versions that are greater than or equal
# to the install candidate, then the candidate is an upgrade, so
# add it to the return dict
if not any([compare(pkg1=x, oper='>=', pkg2=candidate)
for x in installed]):
if not any(
(salt.utils.compare_versions(ver1=x,
oper='>=',
ver2=candidate,
cmp_func=version_cmp)
for x in installed)
):
ret[name] = candidate
# Return a string if only one package name passed
@ -629,7 +634,7 @@ def upgrade_available(name):
return latest_version(name) != ''
def perform_cmp(pkg1='', pkg2=''):
def version_cmp(pkg1, pkg2):
'''
Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if
pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem
@ -637,8 +642,7 @@ def perform_cmp(pkg1='', pkg2=''):
CLI Example::
salt '*' pkg.perform_cmp '0.2.4-0ubuntu1' '0.2.4.1-0ubuntu1'
salt '*' pkg.perform_cmp pkg1='0.2.4-0ubuntu1' pkg2='0.2.4.1-0ubuntu1'
salt '*' pkg.version_cmp '0.2.4-0ubuntu1' '0.2.4.1-0ubuntu1'
'''
try:
for oper, ret in (('lt', -1), ('eq', 0), ('gt', 1)):
@ -651,18 +655,6 @@ def perform_cmp(pkg1='', pkg2=''):
return None
def compare(pkg1='', oper='==', pkg2=''):
'''
Compare two version strings.
CLI Example::
salt '*' pkg.compare '0.2.4-0' '<' '0.2.4.1-0'
salt '*' pkg.compare pkg1='0.2.4-0' oper='<' pkg2='0.2.4.1-0'
'''
return __salt__['pkg_resource.compare'](pkg1=pkg1, oper=oper, pkg2=pkg2)
def _split_repo_str(repo):
split = sourceslist.SourceEntry(repo)
return split.type, split.uri, split.dist, split.comps

View file

@ -278,29 +278,3 @@ def upgrade_available(pkg):
salt '*' pkg.upgrade_available <package name>
'''
return pkg in list_upgrades()
def perform_cmp(pkg1='', pkg2=''):
'''
Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if
pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem
making the comparison.
CLI Example::
salt '*' pkg.perform_cmp '0.2.4-0' '0.2.4.1-0'
salt '*' pkg.perform_cmp pkg1='0.2.4-0' pkg2='0.2.4.1-0'
'''
return __salt__['pkg_resource.perform_cmp'](pkg1=pkg1, pkg2=pkg2)
def compare(pkg1='', oper='==', pkg2=''):
'''
Compare two version strings.
CLI Example::
salt '*' pkg.compare '0.2.4-0' '<' '0.2.4.1-0'
salt '*' pkg.compare pkg1='0.2.4-0' oper='<' pkg2='0.2.4.1-0'
'''
return __salt__['pkg_resource.compare'](pkg1=pkg1, oper=oper, pkg2=pkg2)

View file

@ -132,7 +132,11 @@ def latest_version(*names, **kwargs):
installed = _cpv_to_version(_vartree().dep_bestmatch(name))
avail = _cpv_to_version(_porttree().dep_bestmatch(name))
if avail:
if not installed or compare(pkg1=installed, oper='<', pkg2=avail):
if not installed \
or salt.utils.compare_versions(ver1=installed,
oper='<',
ver2=avail,
cmp_func=version_cmp):
ret[name] = avail
# Return a string if only one package name passed
@ -221,8 +225,8 @@ def porttree_matches(name):
'''
matches = []
for category in _porttree().dbapi.categories:
if _porttree().dbapi.cp_list(category+"/"+name):
matches.append(category+"/"+name)
if _porttree().dbapi.cp_list(category + "/" + name):
matches.append(category + "/" + name)
return matches
@ -276,7 +280,8 @@ def refresh_db():
if 'makeconf.features_contains'in __salt__ and __salt__['makeconf.features_contains']('webrsync-gpg'):
# GPG sign verify is supported only for "webrsync"
cmd = 'emerge-webrsync -q'
if salt.utils.which('emerge-delta-webrsync'): # We prefer 'delta-webrsync' to 'webrsync'
# We prefer 'delta-webrsync' to 'webrsync'
if salt.utils.which('emerge-delta-webrsync'):
cmd = 'emerge-delta-webrsync -q'
return __salt__['cmd.retcode'](cmd) == 0
else:
@ -284,7 +289,8 @@ def refresh_db():
return True
# We fall back to "webrsync" if "rsync" fails for some reason
cmd = 'emerge-webrsync -q'
if salt.utils.which('emerge-delta-webrsync'): # We prefer 'delta-webrsync' to 'webrsync'
# We prefer 'delta-webrsync' to 'webrsync'
if salt.utils.which('emerge-delta-webrsync'):
cmd = 'emerge-delta-webrsync -q'
return __salt__['cmd.retcode'](cmd) == 0
@ -413,7 +419,7 @@ def install(name=None,
for param, version_num in pkg_params.iteritems():
original_param = param
param = _p_to_cp(param)
if param == None:
if param is None:
raise portage.dep.InvalidAtom(original_param)
if version_num is None:
@ -442,12 +448,12 @@ def install(name=None,
__salt__['portage_config.append_use_flags'](target[1:-1])
new = __salt__['portage_config.get_flags_from_package_conf']('use', target[1:-1])
if old != new:
changes[param+'-USE'] = {'old': old, 'new': new}
changes[param + '-USE'] = {'old': old, 'new': new}
target = target[:target.rfind('[')] + '"'
if keyword != None:
if keyword is not None:
__salt__['portage_config.append_to_package_conf']('accept_keywords', target[1:-1], ['~ARCH'])
changes[param+'-ACCEPT_KEYWORD'] = {'old': '', 'new': '~ARCH'}
changes[param + '-ACCEPT_KEYWORD'] = {'old': '', 'new': '~ARCH'}
targets.append(target)
else:
@ -571,7 +577,7 @@ def remove(name=None, slot=None, fromrepo=None, pkgs=None, **kwargs):
targets = ['{0}:{1}'.format(fullatom, slot)]
if fromrepo is not None:
targets = ['{0}::{1}'.format(fullatom, fromrepo)]
targets = [ fullatom ]
targets = [fullatom]
else:
targets = [x for x in pkg_params if x in old]
@ -656,7 +662,7 @@ def depclean(name=None, slot=None, fromrepo=None, pkgs=None):
targets = ['{0}:{1}'.format(fullatom, slot)]
if fromrepo is not None:
targets = ['{0}::{1}'.format(fullatom, fromrepo)]
targets = [ fullatom ]
targets = [fullatom]
else:
targets = [x for x in pkg_params if x in old]
@ -667,7 +673,7 @@ def depclean(name=None, slot=None, fromrepo=None, pkgs=None):
return __salt__['pkg_resource.find_changes'](old, new)
def perform_cmp(pkg1='', pkg2=''):
def version_cmp(pkg1, pkg2):
'''
Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if
pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem
@ -675,8 +681,7 @@ def perform_cmp(pkg1='', pkg2=''):
CLI Example::
salt '*' pkg.perform_cmp '0.2.4-0' '0.2.4.1-0'
salt '*' pkg.perform_cmp pkg1='0.2.4-0' pkg2='0.2.4.1-0'
salt '*' pkg.version_cmp '0.2.4-0' '0.2.4.1-0'
'''
regex = r'^~?([^:\[]+):?[^\[]*\[?.*$'
ver1 = re.match(regex, pkg1)
@ -687,18 +692,6 @@ def perform_cmp(pkg1='', pkg2=''):
return None
def compare(pkg1='', oper='==', pkg2=''):
'''
Compare two version strings.
CLI Example::
salt '*' pkg.compare '0.2.4-0' '<' '0.2.4.1-0'
salt '*' pkg.compare pkg1='0.2.4-0' oper='<' pkg2='0.2.4.1-0'
'''
return __salt__['pkg_resource.compare'](pkg1=pkg1, oper=oper, pkg2=pkg2)
def version_clean(version):
'''
Clean the version string removing extra data.
@ -752,7 +745,8 @@ def check_extra_requirements(pkgname, pkgver):
des_uses = set(portage.dep.dep_getusedeps(atom))
cur_use = cur_use.split()
if len([ x for x in des_uses.difference(cur_use) if x[0]!='-' or x[1:] in cur_use ]) > 0:
if len([x for x in des_uses.difference(cur_use)
if x[0] != '-' or x[1:] in cur_use]) > 0:
return False
if keyword:

View file

@ -391,32 +391,6 @@ def rehash():
__salt__['cmd.run_all']('rehash')
def perform_cmp(pkg1='', pkg2=''):
'''
Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if
pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem
making the comparison.
CLI Example::
salt '*' pkg.perform_cmp '0.2.4-0' '0.2.4.1-0'
salt '*' pkg.perform_cmp pkg1='0.2.4-0' pkg2='0.2.4.1-0'
'''
return __salt__['pkg_resource.perform_cmp'](pkg1=pkg1, pkg2=pkg2)
def compare(pkg1='', oper='==', pkg2=''):
'''
Compare two version strings.
CLI Example::
salt '*' pkg.compare '0.2.4-0' '<' '0.2.4.1-0'
salt '*' pkg.compare pkg1='0.2.4-0' oper='<' pkg2='0.2.4.1-0'
'''
return __salt__['pkg_resource.compare'](pkg1=pkg1, oper=oper, pkg2=pkg2)
def file_list(*packages):
'''
List the files that belong to a package. Not specifying any packages will

View file

@ -222,29 +222,3 @@ def purge(name=None, pkgs=None, **kwargs):
salt '*' pkg.purge pkgs='["foo", "bar"]'
'''
return remove(name=name, pkgs=pkgs)
def perform_cmp(pkg1='', pkg2=''):
'''
Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if
pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem
making the comparison.
CLI Example::
salt '*' pkg.perform_cmp '0.2.4' '0.2.4.1'
salt '*' pkg.perform_cmp pkg1='0.2.4' pkg2='0.2.4.1'
'''
return __salt__['pkg_resource.perform_cmp'](pkg1=pkg1, pkg2=pkg2)
def compare(pkg1='', oper='==', pkg2=''):
'''
Compare two version strings.
CLI Example::
salt '*' pkg.compare '0.2.4' '<' '0.2.4.1'
salt '*' pkg.compare pkg1='0.2.4' oper='<' pkg2='0.2.4.1'
'''
return __salt__['pkg_resource.compare'](pkg1=pkg1, oper=oper, pkg2=pkg2)

View file

@ -396,32 +396,6 @@ def purge(name=None, pkgs=None, **kwargs):
return _uninstall(action='purge', name=name, pkgs=pkgs)
def perform_cmp(pkg1='', pkg2=''):
'''
Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if
pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem
making the comparison.
CLI Example::
salt '*' pkg.perform_cmp '0.2.4-0' '0.2.4.1-0'
salt '*' pkg.perform_cmp pkg1='0.2.4-0' pkg2='0.2.4.1-0'
'''
return __salt__['pkg_resource.perform_cmp'](pkg1=pkg1, pkg2=pkg2)
def compare(pkg1='', oper='==', pkg2=''):
'''
Compare two version strings.
CLI Example::
salt '*' pkg.compare '0.2.4-0' '<' '0.2.4.1-0'
salt '*' pkg.compare pkg1='0.2.4-0' oper='<' pkg2='0.2.4.1-0'
'''
return __salt__['pkg_resource.compare'](pkg1=pkg1, oper=oper, pkg2=pkg2)
def file_list(*packages):
'''
List the files that belong to a package. Not specifying any packages will

View file

@ -3,7 +3,6 @@ Resources needed by pkg providers
'''
# Import python libs
import distutils.version # pylint: disable=E0611
import fnmatch
import logging
import os
@ -419,62 +418,10 @@ def find_changes(old=None, new=None):
return pkgs
def perform_cmp(pkg1='', pkg2=''):
'''
Compares two version strings using distutils.version.LooseVersion. This is
a fallback for providers which don't have a version comparison utility
built into them. Return -1 if version1 < version2, 0 if version1 ==
version2, and 1 if version1 > version2. Return None if there was a problem
making the comparison.
CLI Example::
salt '*' pkg_resource.perform_cmp
'''
try:
if distutils.version.LooseVersion(pkg1) < \
distutils.version.LooseVersion(pkg2):
return -1
elif distutils.version.LooseVersion(pkg1) == \
distutils.version.LooseVersion(pkg2):
return 0
elif distutils.version.LooseVersion(pkg1) > \
distutils.version.LooseVersion(pkg2):
return 1
except Exception as e:
log.exception(e)
return None
def compare(pkg1='', oper='==', pkg2=''):
'''
Package version comparison function.
CLI Example::
salt '*' pkg_resource.compare
'''
cmp_map = {'<': (-1,), '<=': (-1, 0), '==': (0,),
'>=': (0, 1), '>': (1,)}
if oper not in ['!='] + cmp_map.keys():
log.error('Invalid operator "{0}" for package '
'comparison'.format(oper))
return False
cmp_result = __salt__['pkg.perform_cmp'](pkg1, pkg2)
if cmp_result is None:
return False
if oper == '!=':
return cmp_result not in cmp_map['==']
else:
return cmp_result in cmp_map[oper]
def version_clean(version):
'''
Clean the version string removing extra data.
This function will simply try to call "pkg.version_clean".
This function will simply try to call ``pkg.version_clean``.
CLI Example::

View file

@ -423,32 +423,6 @@ def rehash():
__salt__['cmd.run']('rehash')
def perform_cmp(pkg1='', pkg2=''):
'''
Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if
pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem
making the comparison.
CLI Example::
salt '*' pkg.perform_cmp '0.2.4-0' '0.2.4.1-0'
salt '*' pkg.perform_cmp pkg1='0.2.4-0' pkg2='0.2.4.1-0'
'''
return __salt__['pkg_resource.perform_cmp'](pkg1=pkg1, pkg2=pkg2)
def compare(pkg1='', oper='==', pkg2=''):
'''
Compare two version strings.
CLI Example::
salt '*' pkg.compare '0.2.4-0' '<' '0.2.4.1-0'
salt '*' pkg.compare pkg1='0.2.4-0' oper='<' pkg2='0.2.4.1-0'
'''
return __salt__['pkg_resource.compare'](pkg1=pkg1, oper=oper, pkg2=pkg2)
def file_list(package):
'''
List the files that belong to a package.

View file

@ -857,29 +857,3 @@ def updating(pkg_name, filedate=None, filename=None):
cmd = 'pkg updating {0} {1}'.format(opts, pkg_name)
return __salt__['cmd.run'](cmd)
def perform_cmp(pkg1='', pkg2=''):
'''
Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if
pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem
making the comparison.
CLI Example::
salt '*' pkg.perform_cmp '0.2.4-0' '0.2.4.1-0'
salt '*' pkg.perform_cmp pkg1='0.2.4-0' pkg2='0.2.4.1-0'
'''
return __salt__['pkg_resource.perform_cmp'](pkg1=pkg1, pkg2=pkg2)
def compare(pkg1='', oper='==', pkg2=''):
'''
Compare two version strings.
CLI Example::
salt '*' pkg.compare '0.2.4-0' '<' '0.2.4.1-0'
salt '*' pkg.compare pkg1='0.2.4-0' oper='<' pkg2='0.2.4.1-0'
'''
return __salt__['pkg_resource.compare'](pkg1=pkg1, oper=oper, pkg2=pkg2)

View file

@ -194,7 +194,9 @@ def latest_version(*names, **kwargs):
if name in names:
cver = pkgs.get(name, '')
nver = version_rev.split(',')[0]
if not cver or compare(pkg1=cver, oper='<', pkg2=nver):
if not cver or salt.utils.compare_versions(ver1=cver,
oper='<',
ver2=nver):
# Remove revision for version comparison
ret[name] = version_rev
@ -326,29 +328,3 @@ def purge(name=None, pkgs=None, **kwargs):
salt '*' pkg.purge pkgs='["foo", "bar"]'
'''
return remove(name=name, pkgs=pkgs)
def perform_cmp(pkg1='', pkg2=''):
'''
Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if
pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem
making the comparison.
CLI Example::
salt '*' pkg.perform_cmp '0.2.4-0' '0.2.4.1-0'
salt '*' pkg.perform_cmp pkg1='0.2.4-0' pkg2='0.2.4.1-0'
'''
return __salt__['pkg_resource.perform_cmp'](pkg1=pkg1, pkg2=pkg2)
def compare(pkg1='', oper='==', pkg2=''):
'''
Compare two version strings.
CLI Example::
salt '*' pkg.compare '0.2.4-0' '<' '0.2.4.1-0'
salt '*' pkg.compare pkg1='0.2.4-0' oper='<' pkg2='0.2.4.1-0'
'''
return __salt__['pkg_resource.compare'](pkg1=pkg1, oper=oper, pkg2=pkg2)

View file

@ -436,29 +436,3 @@ def purge(name=None, pkgs=None, **kwargs):
salt '*' pkg.purge pkgs='["foo", "bar"]'
'''
return remove(name=name, pkgs=pkgs, **kwargs)
def perform_cmp(pkg1='', pkg2=''):
'''
Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if
pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem
making the comparison.
CLI Example::
salt '*' pkg.perform_cmp '0.2.4-0' '0.2.4.1-0'
salt '*' pkg.perform_cmp pkg1='0.2.4-0' pkg2='0.2.4.1-0'
'''
return __salt__['pkg_resource.perform_cmp'](pkg1=pkg1, pkg2=pkg2)
def compare(pkg1='', oper='==', pkg2=''):
'''
Compare two version strings.
CLI Example::
salt '*' pkg.compare '0.2.4-0' '<' '0.2.4.1-0'
salt '*' pkg.compare pkg1='0.2.4-0' oper='<' pkg2='0.2.4.1-0'
'''
return __salt__['pkg_resource.compare'](pkg1=pkg1, oper=oper, pkg2=pkg2)

View file

@ -706,29 +706,3 @@ def _get_latest_pkg_version(pkginfo):
return pkginfo.keys().pop()
pkgkeys = pkginfo.keys()
return sorted(pkgkeys, cmp=_reverse_cmp_pkg_versions).pop()
def perform_cmp(pkg1='', pkg2=''):
'''
Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if
pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem
making the comparison.
CLI Example::
salt '*' pkg.perform_cmp '0.2.4-0' '0.2.4.1-0'
salt '*' pkg.perform_cmp pkg1='0.2.4-0' pkg2='0.2.4.1-0'
'''
return __salt__['pkg_resource.perform_cmp'](pkg1=pkg1, pkg2=pkg2)
def compare(pkg1='', oper='==', pkg2=''):
'''
Compare two version strings.
CLI Example::
salt '*' pkg.compare '0.2.4-0' '<' '0.2.4.1-0'
salt '*' pkg.compare pkg1='0.2.4-0' oper='<' pkg2='0.2.4.1-0'
'''
return __salt__['pkg_resource.compare'](pkg1=pkg1, oper=oper, pkg2=pkg2)

View file

@ -1039,32 +1039,6 @@ def _parse_repo_file(filename):
return (header, repos)
def perform_cmp(pkg1='', pkg2=''):
'''
Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if
pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem
making the comparison.
CLI Example::
salt '*' pkg.perform_cmp '0.2.4-0' '0.2.4.1-0'
salt '*' pkg.perform_cmp pkg1='0.2.4-0' pkg2='0.2.4.1-0'
'''
return __salt__['pkg_resource.perform_cmp'](pkg1=pkg1, pkg2=pkg2)
def compare(pkg1='', oper='==', pkg2=''):
'''
Compare two version strings.
CLI Example::
salt '*' pkg.compare '0.2.4-0' '<' '0.2.4.1-0'
salt '*' pkg.compare pkg1='0.2.4-0' oper='<' pkg2='0.2.4.1-0'
'''
return __salt__['pkg_resource.compare'](pkg1=pkg1, oper=oper, pkg2=pkg2)
def file_list(*packages):
'''
List the files that belong to a package. Not specifying any packages will

View file

@ -505,29 +505,3 @@ def purge(name=None, pkgs=None, **kwargs):
salt '*' pkg.purge pkgs='["foo", "bar"]'
'''
return remove(name=name, pkgs=pkgs)
def perform_cmp(pkg1='', pkg2=''):
'''
Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if
pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem
making the comparison.
CLI Example::
salt '*' pkg.perform_cmp '0.2.4-0' '0.2.4.1-0'
salt '*' pkg.perform_cmp pkg1='0.2.4-0' pkg2='0.2.4.1-0'
'''
return __salt__['pkg_resource.perform_cmp'](pkg1=pkg1, pkg2=pkg2)
def compare(pkg1='', oper='==', pkg2=''):
'''
Compare two version strings.
CLI Example::
salt '*' pkg.compare '0.2.4-0' '<' '0.2.4.1-0'
salt '*' pkg.compare pkg1='0.2.4-0' oper='<' pkg2='0.2.4.1-0'
'''
return __salt__['pkg_resource.compare'](pkg1=pkg1, oper=oper, pkg2=pkg2)

View file

@ -419,29 +419,3 @@ def purge(name=None, pkgs=None, **kwargs):
salt '*' pkg.purge pkgs='["foo", "bar"]'
'''
return _uninstall(action='purge', name=name, pkgs=pkgs)
def perform_cmp(pkg1='', pkg2=''):
'''
Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if
pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem
making the comparison.
CLI Example::
salt '*' pkg.perform_cmp '0.2.4-0' '0.2.4.1-0'
salt '*' pkg.perform_cmp pkg1='0.2.4-0' pkg2='0.2.4.1-0'
'''
return __salt__['pkg_resource.perform_cmp'](pkg1=pkg1, pkg2=pkg2)
def compare(pkg1='', oper='==', pkg2=''):
'''
Compare two version strings.
CLI Example::
salt '*' pkg.compare '0.2.4-0' '<' '0.2.4.1-0'
salt '*' pkg.compare pkg1='0.2.4-0' oper='<' pkg2='0.2.4.1-0'
'''
return __salt__['pkg_resource.compare'](pkg1=pkg1, oper=oper, pkg2=pkg2)

View file

@ -19,6 +19,7 @@ requisite to a pkg.installed state for the package which provides pip
'''
# Import python libs
import re
import urlparse
# Import salt libs
@ -33,6 +34,34 @@ def __virtual__():
return 'pip' if 'pip.list' in __salt__ else False
def _find_key(prefix, pip_list):
'''
Does a case-insensitive match in the pip_list for the desired package.
'''
try:
match = next(
iter(x for x in pip_list if x.lower() == prefix.lower())
)
except StopIteration:
return None
else:
return match
def _fulfills_version_spec(version, version_spec):
'''
Check version number against version specification info and return a
boolean value based on whether or not the version number meets the
specified version.
'''
for oper, spec in (version_spec[0:2], version_spec[2:4]):
if oper is None:
continue
if not salt.utils.compare_versions(ver1=version, oper=oper, ver2=spec):
return False
return True
def installed(name,
pip_bin=None,
requirements=None,
@ -87,17 +116,38 @@ def installed(name,
elif env and not bin_env:
bin_env = env
ret = {'name': name, 'result': None, 'comment': '', 'changes': {}}
scheme, netloc, path, query, fragment = urlparse.urlsplit(name)
if scheme and netloc:
# parse as VCS url
prefix = path.lstrip('/').split('@', 1)[0]
if scheme.startswith("git+"):
prefix = prefix.rstrip(".git")
if scheme.startswith('git+'):
prefix = prefix.rstrip('.git')
else:
# Pull off any requirements specifiers
prefix = name.split('=')[0].split('<')[0].split('>')[0].strip()
# Split the passed string into the prefix and version
try:
version_spec = list(re.match(
(r'([^=<>]+)(?:(?:([<>]=?|==?)([^<>=,]+))'
r'(?:,([<>]=?|==?)([^<>=]+))?)?$'),
name
).groups())
prefix = version_spec.pop(0)
except AttributeError:
ret['result'] = False
ret['comment'] = 'Invalidly-formatted package {0}'.format(name)
return ret
else:
# Check to see if '=' was used instead of '=='. version_spec will
# contain two sets of comparison operators and version numbers, so
# we are checking elements 0 and 2 of this list.
if any((version_spec[x] == '=' for x in (0, 2))):
ret['result'] = False
ret['comment'] = ('Invalid version specification in '
'package {0}. \'=\' is not supported, use '
'\'==\' instead.'.format(name))
return ret
ret = {'name': name, 'result': None, 'comment': '', 'changes': {}}
if runas is not None:
# The user is using a deprecated argument, warn!
msg = (
@ -107,41 +157,48 @@ def installed(name,
salt.utils.warn_until((0, 18), msg)
ret.setdefault('warnings', []).append(msg)
# "There can only be one"
if runas is not None and user:
raise CommandExecutionError(
'The \'runas\' and \'user\' arguments are mutually exclusive. '
'Please use \'user\' as \'runas\' is being deprecated.'
)
# Support deprecated 'runas' arg
elif runas is not None and not user:
user = runas
# "There can only be one"
if user:
raise CommandExecutionError(
'The \'runas\' and \'user\' arguments are mutually exclusive. '
'Please use \'user\' as \'runas\' is being deprecated.'
)
# Support deprecated 'runas' arg
else:
user = runas
try:
pip_list = __salt__['pip.list'](prefix, bin_env, user=user, cwd=cwd)
pip_list = __salt__['pip.list'](prefix, bin_env=bin_env,
user=user, cwd=cwd)
prefix_realname = _find_key(prefix, pip_list)
except (CommandNotFoundError, CommandExecutionError) as err:
ret['result'] = False
ret['comment'] = 'Error installing \'{0}\': {1}'.format(name, err)
return ret
if ignore_installed is False and prefix.lower() in (p.lower()
for p in pip_list):
if force_reinstall is False and upgrade is False:
ret['result'] = True
ret['comment'] = 'Package already installed'
return ret
if ignore_installed is False and prefix_realname is not None:
if force_reinstall is False and not upgrade:
# Check desired version (if any) against currently-installed
if (
any(version_spec) and
_fulfills_version_spec(pip_list[prefix_realname],
version_spec)
) or (not any(version_spec)):
ret['result'] = True
ret['comment'] = ('Python package {0} already '
'installed'.format(name))
return ret
if __opts__['test']:
ret['result'] = None
ret['comment'] = 'Python package {0} is set to be installed'.format(
name)
ret['comment'] = \
'Python package {0} is set to be installed'.format(name)
return ret
# Replace commas (used for version ranges) with semicolons (which are not
# supported) in name so it does not treat them as multiple packages. Comma
# will be re-added in pip.install call. Wrap in double quotes to allow for
# version ranges
name = '"' + name.replace(',', ';') + '"'
# will be re-added in pip.install call.
name = name.replace(',', ';')
if repo:
name = repo
@ -153,7 +210,7 @@ def installed(name,
name = ''
pip_install_call = __salt__['pip.install'](
pkgs=name,
pkgs='"{0}"'.format(name),
requirements=requirements,
bin_env=bin_env,
log=log,

View file

@ -65,13 +65,16 @@ def __gen_rtag():
return os.path.join(__opts__['cachedir'], 'pkg_refresh')
def _fulfills_version_spec(versions, oper, desired_version):
def _fulfills_version_spec(version, oper, desired_version):
'''
Returns True if any of the installed versions match the specified version,
otherwise returns False
'''
for ver in versions:
if __salt__['pkg.compare'](pkg1=ver, oper=oper, pkg2=desired_version):
if salt.utils.compare_versions(ver1=version,
oper=oper,
ver2=desired_version,
cmp_func=__salt__.get('version_cmp')):
return True
return False
@ -170,7 +173,7 @@ def _find_install_targets(name=None, version=None, pkgs=None, sources=None):
comparison = gt_lt or ''
comparison += eq or ''
# A comparison operator of "=" is redundant, but possible.
# Change it to "==" so that it works in pkg.compare.
# Change it to "==" so that the version comparison works
if comparison in ['=', '']:
comparison = '=='
if not _fulfills_version_spec(cver, comparison, verstr):
@ -215,7 +218,7 @@ def _verify_install(desired, new_pkgs):
comparison = gt_lt or ''
comparison += eq or ''
# A comparison operator of "=" is redundant, but possible.
# Change it to "==" so that it works in pkg.compare.
# Change it to "==" so that the version comparison works.
if comparison in ('=', ''):
comparison = '=='
if _fulfills_version_spec(cver, comparison, verstr):
@ -557,10 +560,12 @@ def latest(
msg = 'No information found for "{0}".'.format(pkg)
log.error(msg)
problems.append(msg)
elif not cur[pkg] or \
__salt__['pkg.compare'](pkg1=cur[pkg],
oper='<',
pkg2=avail[pkg]):
elif not cur[pkg] \
or salt.utils.compare_versions(
ver1=cur[pkg],
oper='<',
ver2=avail[pkg],
cmp_func=__salt__.get('version_cmp')):
targets[pkg] = avail[pkg]
if problems:
@ -608,7 +613,8 @@ def latest(
if changes:
# Find failed and successful updates
failed = [x for x in targets if changes[x]['new'] != targets[x]]
failed = [x for x in targets
if not changes.get(x) or changes[x]['new'] != targets[x]]
successful = [x for x in targets if x not in failed]
comments = []

View file

@ -5,6 +5,7 @@ from __future__ import absolute_import
# Import python libs
import datetime
import distutils.version # pylint: disable=E0611
import fnmatch
import hashlib
import imp
@ -1389,3 +1390,51 @@ def warn_until(version_info,
if _dont_call_warnings is False:
warnings.warn(message, category, stacklevel=stacklevel)
def version_cmp(pkg1, pkg2):
'''
Compares two version strings using distutils.version.LooseVersion. This is
a fallback for providers which don't have a version comparison utility
built into them. Return -1 if version1 < version2, 0 if version1 ==
version2, and 1 if version1 > version2. Return None if there was a problem
making the comparison.
'''
try:
if distutils.version.LooseVersion(pkg1) < \
distutils.version.LooseVersion(pkg2):
return -1
elif distutils.version.LooseVersion(pkg1) == \
distutils.version.LooseVersion(pkg2):
return 0
elif distutils.version.LooseVersion(pkg1) > \
distutils.version.LooseVersion(pkg2):
return 1
except Exception as e:
log.exception(e)
return None
def compare_versions(ver1='', oper='==', ver2='', cmp_func=None):
'''
Compares two version numbers. Accepts a custom function to perform the
cmp-style version comparison, otherwise uses version_cmp().
'''
cmp_map = {'<': (-1,), '<=': (-1, 0), '==': (0,),
'>=': (0, 1), '>': (1,)}
if oper not in ['!='] + cmp_map.keys():
log.error('Invalid operator "{0}" for version '
'comparison'.format(oper))
return False
if cmp_func is None:
cmp_func = version_cmp
cmp_result = cmp_func(ver1, ver2)
if cmp_result is None:
return False
if oper == '!=':
return cmp_result not in cmp_map['==']
else:
return cmp_result in cmp_map[oper]