mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge pull request #44552 from Da-Juan/avoid_unneeded_pip_install
pip_state: Check if available upgrades fulfill version requirements.
This commit is contained in:
commit
487207f61d
2 changed files with 139 additions and 1 deletions
|
@ -82,6 +82,7 @@ import re
|
|||
import shutil
|
||||
import logging
|
||||
import sys
|
||||
from pkg_resources import parse_version
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils
|
||||
|
@ -1216,3 +1217,79 @@ def upgrade(bin_env=None,
|
|||
ret['changes'] = salt.utils.compare_dicts(old, new)
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def list_all_versions(pkg,
|
||||
bin_env=None,
|
||||
include_alpha=False,
|
||||
include_beta=False,
|
||||
include_rc=False,
|
||||
user=None,
|
||||
cwd=None):
|
||||
'''
|
||||
.. versionadded:: 2017.7.3
|
||||
|
||||
List all available versions of a pip package
|
||||
|
||||
pkg
|
||||
The package to check
|
||||
|
||||
bin_env
|
||||
Path to pip bin or path to virtualenv. If doing a system install,
|
||||
and want to use a specific pip bin (pip-2.7, pip-2.6, etc..) just
|
||||
specify the pip bin you want.
|
||||
|
||||
include_alpha
|
||||
Include alpha versions in the list
|
||||
|
||||
include_beta
|
||||
Include beta versions in the list
|
||||
|
||||
include_rc
|
||||
Include release candidates versions in the list
|
||||
|
||||
user
|
||||
The user under which to run pip
|
||||
|
||||
cwd
|
||||
Current working directory to run pip from
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' pip.list_all_versions <package name>
|
||||
'''
|
||||
pip_bin = _get_pip_bin(bin_env)
|
||||
|
||||
cmd = [pip_bin, 'install', '{0}==versions'.format(pkg)]
|
||||
|
||||
cmd_kwargs = dict(cwd=cwd, runas=user, output_loglevel='quiet', redirect_stderr=True)
|
||||
if bin_env and os.path.isdir(bin_env):
|
||||
cmd_kwargs['env'] = {'VIRTUAL_ENV': bin_env}
|
||||
|
||||
result = __salt__['cmd.run_all'](cmd, **cmd_kwargs)
|
||||
|
||||
filtered = []
|
||||
if not include_alpha:
|
||||
filtered.append('a')
|
||||
if not include_beta:
|
||||
filtered.append('b')
|
||||
if not include_rc:
|
||||
filtered.append('rc')
|
||||
if filtered:
|
||||
excludes = re.compile(r'^((?!{0}).)*$'.format('|'.join(filtered)))
|
||||
else:
|
||||
excludes = re.compile(r'')
|
||||
|
||||
versions = []
|
||||
for line in result['stdout'].splitlines():
|
||||
match = re.search(r'\s*Could not find a version.* \(from versions: (.*)\)', line)
|
||||
if match:
|
||||
versions = [v for v in match.group(1).split(', ') if v and excludes.match(v)]
|
||||
versions.sort(key=parse_version)
|
||||
break
|
||||
if not versions:
|
||||
return None
|
||||
|
||||
return versions
|
||||
|
|
|
@ -23,6 +23,7 @@ requisite to a pkg.installed state for the package which provides pip
|
|||
from __future__ import absolute_import
|
||||
import re
|
||||
import logging
|
||||
from pkg_resources import parse_version
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils
|
||||
|
@ -94,7 +95,7 @@ def _fulfills_version_spec(version, version_spec):
|
|||
for oper, spec in version_spec:
|
||||
if oper is None:
|
||||
continue
|
||||
if not salt.utils.compare_versions(ver1=version, oper=oper, ver2=spec):
|
||||
if not salt.utils.compare_versions(ver1=version, oper=oper, ver2=spec, cmp_func=_pep440_version_cmp):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
@ -212,10 +213,70 @@ def _check_if_installed(prefix, state_pkg_name, version_spec,
|
|||
ret['comment'] = ('Python package {0} was already '
|
||||
'installed'.format(state_pkg_name))
|
||||
return ret
|
||||
if force_reinstall is False and upgrade:
|
||||
# Check desired version (if any) against currently-installed
|
||||
include_alpha = False
|
||||
include_beta = False
|
||||
include_rc = False
|
||||
if any(version_spec):
|
||||
for spec in version_spec:
|
||||
if 'a' in spec[1]:
|
||||
include_alpha = True
|
||||
if 'b' in spec[1]:
|
||||
include_beta = True
|
||||
if 'rc' in spec[1]:
|
||||
include_rc = True
|
||||
available_versions = __salt__['pip.list_all_versions'](
|
||||
prefix_realname, bin_env=bin_env, include_alpha=include_alpha,
|
||||
include_beta=include_beta, include_rc=include_rc, user=user,
|
||||
cwd=cwd)
|
||||
desired_version = ''
|
||||
if any(version_spec):
|
||||
for version in reversed(available_versions):
|
||||
if _fulfills_version_spec(version, version_spec):
|
||||
desired_version = version
|
||||
break
|
||||
else:
|
||||
desired_version = available_versions[-1]
|
||||
if not desired_version:
|
||||
ret['result'] = True
|
||||
ret['comment'] = ('Python package {0} was already '
|
||||
'installed and\nthe available upgrade '
|
||||
'doesn\'t fulfills the version '
|
||||
'requirements'.format(prefix_realname))
|
||||
return ret
|
||||
if _pep440_version_cmp(pip_list[prefix_realname], desired_version) == 0:
|
||||
ret['result'] = True
|
||||
ret['comment'] = ('Python package {0} was already '
|
||||
'installed'.format(state_pkg_name))
|
||||
return ret
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def _pep440_version_cmp(pkg1, pkg2, ignore_epoch=False):
|
||||
'''
|
||||
Compares two version strings using pkg_resources.parse_version.
|
||||
Return -1 if version1 < version2, 0 if version1 ==version2,
|
||||
and 1 if version1 > version2. Return None if there was a problem
|
||||
making the comparison.
|
||||
'''
|
||||
normalize = lambda x: str(x).split('!', 1)[-1] if ignore_epoch else str(x)
|
||||
pkg1 = normalize(pkg1)
|
||||
pkg2 = normalize(pkg2)
|
||||
|
||||
try:
|
||||
if parse_version(pkg1) < parse_version(pkg2):
|
||||
return -1
|
||||
if parse_version(pkg1) == parse_version(pkg2):
|
||||
return 0
|
||||
if parse_version(pkg1) > parse_version(pkg2):
|
||||
return 1
|
||||
except Exception as exc:
|
||||
logger.exception(exc)
|
||||
return None
|
||||
|
||||
|
||||
def installed(name,
|
||||
pkgs=None,
|
||||
pip_bin=None,
|
||||
|
|
Loading…
Add table
Reference in a new issue