2021-01-08 13:41:50 +01:00
|
|
|
From 57f9da0bd7727c46eab866941fee46a3eaf8c8ea Mon Sep 17 00:00:00 2001
|
2019-01-17 10:18:02 +01:00
|
|
|
From: Bo Maryniuk <bo@suse.de>
|
|
|
|
Date: Fri, 21 Sep 2018 17:31:39 +0200
|
|
|
|
Subject: [PATCH] Do not load pip state if there is no 3rd party
|
|
|
|
dependencies
|
|
|
|
|
|
|
|
Safe import 3rd party dependency
|
|
|
|
---
|
2021-01-08 13:41:50 +01:00
|
|
|
salt/modules/pip.py | 93 ++++++++++++++++++++++++---------------------
|
|
|
|
1 file changed, 50 insertions(+), 43 deletions(-)
|
2019-01-17 10:18:02 +01:00
|
|
|
|
|
|
|
diff --git a/salt/modules/pip.py b/salt/modules/pip.py
|
2021-01-08 13:41:50 +01:00
|
|
|
index f7c101f6e4..742e0dd48a 100644
|
2019-01-17 10:18:02 +01:00
|
|
|
--- a/salt/modules/pip.py
|
|
|
|
+++ b/salt/modules/pip.py
|
2021-01-08 13:41:50 +01:00
|
|
|
@@ -1,4 +1,3 @@
|
|
|
|
-# -*- coding: utf-8 -*-
|
|
|
|
r"""
|
|
|
|
Install Python packages with pip to either the system or a virtualenv
|
|
|
|
|
|
|
|
@@ -77,9 +76,7 @@ of the 2015.5 branch:
|
|
|
|
The issue is described here: https://github.com/saltstack/salt/issues/46163
|
|
|
|
|
|
|
|
"""
|
|
|
|
-from __future__ import absolute_import, print_function, unicode_literals
|
|
|
|
|
|
|
|
-# Import python libs
|
2019-01-17 10:18:02 +01:00
|
|
|
import logging
|
|
|
|
import os
|
2021-01-08 13:41:50 +01:00
|
|
|
import re
|
|
|
|
@@ -89,7 +86,6 @@ import tempfile
|
|
|
|
|
|
|
|
import pkg_resources # pylint: disable=3rd-party-module-not-gated
|
|
|
|
|
|
|
|
-# Import Salt libs
|
|
|
|
import salt.utils.data
|
|
|
|
import salt.utils.files
|
|
|
|
import salt.utils.json
|
|
|
|
@@ -101,6 +97,12 @@ import salt.utils.versions
|
|
|
|
from salt.exceptions import CommandExecutionError, CommandNotFoundError
|
|
|
|
from salt.ext import six
|
|
|
|
|
2019-01-17 10:18:02 +01:00
|
|
|
+try:
|
|
|
|
+ import pkg_resources
|
|
|
|
+except ImportError:
|
|
|
|
+ pkg_resources = None
|
2021-01-08 13:41:50 +01:00
|
|
|
+
|
|
|
|
+
|
|
|
|
# This needs to be named logger so we don't shadow it in pip.install
|
|
|
|
logger = logging.getLogger(__name__) # pylint: disable=C0103
|
|
|
|
|
|
|
|
@@ -118,7 +120,12 @@ def __virtual__():
|
2019-01-17 10:18:02 +01:00
|
|
|
entire filesystem. If it's not installed in a conventional location, the
|
|
|
|
user is required to provide the location of pip each time it is used.
|
2021-01-08 13:41:50 +01:00
|
|
|
"""
|
|
|
|
- return "pip"
|
2019-01-17 10:18:02 +01:00
|
|
|
+ if pkg_resources is None:
|
|
|
|
+ ret = False, 'Package dependency "pkg_resource" is missing'
|
|
|
|
+ else:
|
2021-01-08 13:41:50 +01:00
|
|
|
+ ret = "pip"
|
2019-01-17 10:18:02 +01:00
|
|
|
+
|
|
|
|
+ return ret
|
|
|
|
|
|
|
|
|
2020-04-30 16:20:16 +02:00
|
|
|
def _pip_bin_env(cwd, bin_env):
|
2021-01-08 13:41:50 +01:00
|
|
|
@@ -140,7 +147,7 @@ def _clear_context(bin_env=None):
|
|
|
|
"""
|
|
|
|
contextkey = "pip.version"
|
|
|
|
if bin_env is not None:
|
|
|
|
- contextkey = "{0}.{1}".format(contextkey, bin_env)
|
|
|
|
+ contextkey = "{}.{}".format(contextkey, bin_env)
|
|
|
|
__context__.pop(contextkey, None)
|
|
|
|
|
|
|
|
|
|
|
|
@@ -196,7 +203,7 @@ def _get_pip_bin(bin_env):
|
|
|
|
bin_path,
|
|
|
|
)
|
|
|
|
raise CommandNotFoundError(
|
|
|
|
- "Could not find a pip binary in virtualenv {0}".format(bin_env)
|
|
|
|
+ "Could not find a pip binary in virtualenv {}".format(bin_env)
|
|
|
|
)
|
|
|
|
|
|
|
|
# bin_env is the python or pip binary
|
|
|
|
@@ -209,11 +216,11 @@ def _get_pip_bin(bin_env):
|
|
|
|
return [os.path.normpath(bin_env)]
|
|
|
|
|
|
|
|
raise CommandExecutionError(
|
|
|
|
- "Could not find a pip binary within {0}".format(bin_env)
|
|
|
|
+ "Could not find a pip binary within {}".format(bin_env)
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
raise CommandNotFoundError(
|
|
|
|
- "Access denied to {0}, could not find a pip binary".format(bin_env)
|
|
|
|
+ "Access denied to {}, could not find a pip binary".format(bin_env)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
@@ -283,7 +290,7 @@ def _resolve_requirements_chain(requirements):
|
|
|
|
|
|
|
|
chain = []
|
|
|
|
|
|
|
|
- if isinstance(requirements, six.string_types):
|
|
|
|
+ if isinstance(requirements, str):
|
|
|
|
requirements = [requirements]
|
|
|
|
|
|
|
|
for req_file in requirements:
|
|
|
|
@@ -300,7 +307,7 @@ def _process_requirements(requirements, cmd, cwd, saltenv, user):
|
|
|
|
cleanup_requirements = []
|
|
|
|
|
|
|
|
if requirements is not None:
|
|
|
|
- if isinstance(requirements, six.string_types):
|
|
|
|
+ if isinstance(requirements, str):
|
|
|
|
requirements = [r.strip() for r in requirements.split(",")]
|
|
|
|
elif not isinstance(requirements, list):
|
|
|
|
raise TypeError("requirements must be a string or list")
|
|
|
|
@@ -314,7 +321,7 @@ def _process_requirements(requirements, cmd, cwd, saltenv, user):
|
|
|
|
if not cached_requirements:
|
|
|
|
ret = {
|
|
|
|
"result": False,
|
|
|
|
- "comment": "pip requirements file '{0}' not found".format(
|
|
|
|
+ "comment": "pip requirements file '{}' not found".format(
|
|
|
|
requirement
|
|
|
|
),
|
|
|
|
}
|
|
|
|
@@ -412,15 +419,15 @@ def _format_env_vars(env_vars):
|
|
|
|
ret = {}
|
|
|
|
if env_vars:
|
|
|
|
if isinstance(env_vars, dict):
|
|
|
|
- for key, val in six.iteritems(env_vars):
|
|
|
|
- if not isinstance(key, six.string_types):
|
|
|
|
+ for key, val in env_vars.items():
|
|
|
|
+ if not isinstance(key, str):
|
|
|
|
key = str(key) # future lint: disable=blacklisted-function
|
|
|
|
- if not isinstance(val, six.string_types):
|
|
|
|
+ if not isinstance(val, str):
|
|
|
|
val = str(val) # future lint: disable=blacklisted-function
|
|
|
|
ret[key] = val
|
|
|
|
else:
|
|
|
|
raise CommandExecutionError(
|
|
|
|
- "env_vars {0} is not a dictionary".format(env_vars)
|
|
|
|
+ "env_vars {} is not a dictionary".format(env_vars)
|
|
|
|
)
|
|
|
|
return ret
|
|
|
|
|
|
|
|
@@ -762,9 +769,9 @@ def install(
|
|
|
|
|
|
|
|
if log:
|
|
|
|
if os.path.isdir(log):
|
|
|
|
- raise IOError("'{0}' is a directory. Use --log path_to_file".format(log))
|
|
|
|
+ raise OSError("'{}' is a directory. Use --log path_to_file".format(log))
|
|
|
|
elif not os.access(log, os.W_OK):
|
|
|
|
- raise IOError("'{0}' is not writeable".format(log))
|
|
|
|
+ raise OSError("'{}' is not writeable".format(log))
|
|
|
|
|
|
|
|
cmd.extend(["--log", log])
|
|
|
|
|
|
|
|
@@ -790,12 +797,12 @@ def install(
|
|
|
|
int(timeout)
|
|
|
|
except ValueError:
|
|
|
|
raise ValueError(
|
|
|
|
- "'{0}' is not a valid timeout, must be an integer".format(timeout)
|
|
|
|
+ "'{}' is not a valid timeout, must be an integer".format(timeout)
|
|
|
|
)
|
|
|
|
cmd.extend(["--timeout", timeout])
|
|
|
|
|
|
|
|
if find_links:
|
|
|
|
- if isinstance(find_links, six.string_types):
|
|
|
|
+ if isinstance(find_links, str):
|
|
|
|
find_links = [l.strip() for l in find_links.split(",")]
|
|
|
|
|
|
|
|
for link in find_links:
|
|
|
|
@@ -803,7 +810,7 @@ def install(
|
|
|
|
salt.utils.url.validate(link, VALID_PROTOS) or os.path.exists(link)
|
|
|
|
):
|
|
|
|
raise CommandExecutionError(
|
|
|
|
- "'{0}' is not a valid URL or path".format(link)
|
|
|
|
+ "'{}' is not a valid URL or path".format(link)
|
|
|
|
)
|
|
|
|
cmd.extend(["--find-links", link])
|
|
|
|
|
|
|
|
@@ -815,13 +822,13 @@ def install(
|
|
|
|
|
|
|
|
if index_url:
|
|
|
|
if not salt.utils.url.validate(index_url, VALID_PROTOS):
|
|
|
|
- raise CommandExecutionError("'{0}' is not a valid URL".format(index_url))
|
|
|
|
+ raise CommandExecutionError("'{}' is not a valid URL".format(index_url))
|
|
|
|
cmd.extend(["--index-url", index_url])
|
|
|
|
|
|
|
|
if extra_index_url:
|
|
|
|
if not salt.utils.url.validate(extra_index_url, VALID_PROTOS):
|
|
|
|
raise CommandExecutionError(
|
|
|
|
- "'{0}' is not a valid URL".format(extra_index_url)
|
|
|
|
+ "'{}' is not a valid URL".format(extra_index_url)
|
|
|
|
)
|
|
|
|
cmd.extend(["--extra-index-url", extra_index_url])
|
|
|
|
|
|
|
|
@@ -836,13 +843,13 @@ def install(
|
|
|
|
" use index_url and/or extra_index_url instead"
|
|
|
|
)
|
|
|
|
|
|
|
|
- if isinstance(mirrors, six.string_types):
|
|
|
|
+ if isinstance(mirrors, str):
|
|
|
|
mirrors = [m.strip() for m in mirrors.split(",")]
|
|
|
|
|
|
|
|
cmd.append("--use-mirrors")
|
|
|
|
for mirror in mirrors:
|
|
|
|
if not mirror.startswith("http://"):
|
|
|
|
- raise CommandExecutionError("'{0}' is not a valid URL".format(mirror))
|
|
|
|
+ raise CommandExecutionError("'{}' is not a valid URL".format(mirror))
|
|
|
|
cmd.extend(["--mirrors", mirror])
|
|
|
|
|
|
|
|
if disable_version_check:
|
|
|
|
@@ -883,7 +890,7 @@ def install(
|
|
|
|
if exists_action.lower() not in ("s", "i", "w", "b"):
|
|
|
|
raise CommandExecutionError(
|
|
|
|
"The exists_action pip option only supports the values "
|
|
|
|
- "s, i, w, and b. '{0}' is not valid.".format(exists_action)
|
|
|
|
+ "s, i, w, and b. '{}' is not valid.".format(exists_action)
|
|
|
|
)
|
|
|
|
cmd.extend(["--exists-action", exists_action])
|
|
|
|
|
|
|
|
@@ -911,14 +918,14 @@ def install(
|
|
|
|
cmd.extend(["--cert", cert])
|
|
|
|
|
|
|
|
if global_options:
|
|
|
|
- if isinstance(global_options, six.string_types):
|
|
|
|
+ if isinstance(global_options, str):
|
|
|
|
global_options = [go.strip() for go in global_options.split(",")]
|
|
|
|
|
|
|
|
for opt in global_options:
|
|
|
|
cmd.extend(["--global-option", opt])
|
|
|
|
|
|
|
|
if install_options:
|
|
|
|
- if isinstance(install_options, six.string_types):
|
|
|
|
+ if isinstance(install_options, str):
|
|
|
|
install_options = [io.strip() for io in install_options.split(",")]
|
|
|
|
|
|
|
|
for opt in install_options:
|
|
|
|
@@ -929,7 +936,7 @@ def install(
|
|
|
|
try:
|
|
|
|
pkgs = [p.strip() for p in pkgs.split(",")]
|
|
|
|
except AttributeError:
|
|
|
|
- pkgs = [p.strip() for p in six.text_type(pkgs).split(",")]
|
|
|
|
+ pkgs = [p.strip() for p in str(pkgs).split(",")]
|
|
|
|
pkgs = salt.utils.data.stringify(salt.utils.data.decode_list(pkgs))
|
|
|
|
|
|
|
|
# It's possible we replaced version-range commas with semicolons so
|
|
|
|
@@ -945,7 +952,7 @@ def install(
|
|
|
|
|
|
|
|
if editable:
|
|
|
|
egg_match = re.compile(r"(?:#|#.*?&)egg=([^&]*)")
|
|
|
|
- if isinstance(editable, six.string_types):
|
|
|
|
+ if isinstance(editable, str):
|
|
|
|
editable = [e.strip() for e in editable.split(",")]
|
|
|
|
|
|
|
|
for entry in editable:
|
|
|
|
@@ -964,14 +971,14 @@ def install(
|
|
|
|
cmd.append("--allow-all-external")
|
|
|
|
|
|
|
|
if allow_external:
|
|
|
|
- if isinstance(allow_external, six.string_types):
|
|
|
|
+ if isinstance(allow_external, str):
|
|
|
|
allow_external = [p.strip() for p in allow_external.split(",")]
|
|
|
|
|
|
|
|
for pkg in allow_external:
|
|
|
|
cmd.extend(["--allow-external", pkg])
|
|
|
|
|
|
|
|
if allow_unverified:
|
|
|
|
- if isinstance(allow_unverified, six.string_types):
|
|
|
|
+ if isinstance(allow_unverified, str):
|
|
|
|
allow_unverified = [p.strip() for p in allow_unverified.split(",")]
|
|
|
|
|
|
|
|
for pkg in allow_unverified:
|
|
|
|
@@ -1106,8 +1113,8 @@ def uninstall(
|
|
|
|
try:
|
|
|
|
# TODO make this check if writeable
|
|
|
|
os.path.exists(log)
|
|
|
|
- except IOError:
|
|
|
|
- raise IOError("'{0}' is not writeable".format(log))
|
|
|
|
+ except OSError:
|
|
|
|
+ raise OSError("'{}' is not writeable".format(log))
|
|
|
|
|
|
|
|
cmd.extend(["--log", log])
|
|
|
|
|
|
|
|
@@ -1133,12 +1140,12 @@ def uninstall(
|
|
|
|
int(timeout)
|
|
|
|
except ValueError:
|
|
|
|
raise ValueError(
|
|
|
|
- "'{0}' is not a valid timeout, must be an integer".format(timeout)
|
|
|
|
+ "'{}' is not a valid timeout, must be an integer".format(timeout)
|
|
|
|
)
|
|
|
|
cmd.extend(["--timeout", timeout])
|
|
|
|
|
|
|
|
if pkgs:
|
|
|
|
- if isinstance(pkgs, six.string_types):
|
|
|
|
+ if isinstance(pkgs, str):
|
|
|
|
pkgs = [p.strip() for p in pkgs.split(",")]
|
|
|
|
if requirements:
|
|
|
|
for requirement in requirements:
|
|
|
|
@@ -1323,7 +1330,7 @@ def version(bin_env=None, cwd=None, user=None):
|
|
|
|
cwd = _pip_bin_env(cwd, bin_env)
|
|
|
|
contextkey = "pip.version"
|
|
|
|
if bin_env is not None:
|
|
|
|
- contextkey = "{0}.{1}".format(contextkey, bin_env)
|
|
|
|
+ contextkey = "{}.{}".format(contextkey, bin_env)
|
|
|
|
|
|
|
|
if contextkey in __context__:
|
|
|
|
return __context__[contextkey]
|
|
|
|
@@ -1402,7 +1409,7 @@ def list_upgrades(bin_env=None, user=None, cwd=None):
|
|
|
|
if match:
|
|
|
|
name, version_ = match.groups()
|
|
|
|
else:
|
|
|
|
- logger.error("Can't parse line '{0}'".format(line))
|
|
|
|
+ logger.error("Can't parse line '{}'".format(line))
|
|
|
|
continue
|
|
|
|
packages[name] = version_
|
|
|
|
|
|
|
|
@@ -1414,7 +1421,7 @@ def list_upgrades(bin_env=None, user=None, cwd=None):
|
|
|
|
raise CommandExecutionError("Invalid JSON", info=result)
|
|
|
|
|
|
|
|
for pkg in pkgs:
|
|
|
|
- packages[pkg["name"]] = "{0} [{1}]".format(
|
|
|
|
+ packages[pkg["name"]] = "{} [{}]".format(
|
|
|
|
pkg["latest_version"], pkg["latest_filetype"]
|
|
|
|
)
|
|
|
|
|
|
|
|
@@ -1602,17 +1609,17 @@ def list_all_versions(
|
|
|
|
"""
|
|
|
|
cwd = _pip_bin_env(cwd, bin_env)
|
|
|
|
cmd = _get_pip_bin(bin_env)
|
|
|
|
- cmd.extend(["install", "{0}==versions".format(pkg)])
|
|
|
|
+ cmd.extend(["install", "{}==versions".format(pkg)])
|
|
|
|
|
|
|
|
if index_url:
|
|
|
|
if not salt.utils.url.validate(index_url, VALID_PROTOS):
|
|
|
|
- raise CommandExecutionError("'{0}' is not a valid URL".format(index_url))
|
|
|
|
+ raise CommandExecutionError("'{}' is not a valid URL".format(index_url))
|
|
|
|
cmd.extend(["--index-url", index_url])
|
|
|
|
|
|
|
|
if extra_index_url:
|
|
|
|
if not salt.utils.url.validate(extra_index_url, VALID_PROTOS):
|
|
|
|
raise CommandExecutionError(
|
|
|
|
- "'{0}' is not a valid URL".format(extra_index_url)
|
|
|
|
+ "'{}' is not a valid URL".format(extra_index_url)
|
|
|
|
)
|
|
|
|
cmd.extend(["--extra-index-url", extra_index_url])
|
|
|
|
|
|
|
|
@@ -1632,7 +1639,7 @@ def list_all_versions(
|
|
|
|
if not include_rc:
|
|
|
|
filtered.append("rc")
|
|
|
|
if filtered:
|
|
|
|
- excludes = re.compile(r"^((?!{0}).)*$".format("|".join(filtered)))
|
|
|
|
+ excludes = re.compile(r"^((?!{}).)*$".format("|".join(filtered)))
|
|
|
|
else:
|
|
|
|
excludes = re.compile(r"")
|
|
|
|
|
2019-01-17 10:18:02 +01:00
|
|
|
--
|
2021-01-08 13:41:50 +01:00
|
|
|
2.29.2
|
2019-01-17 10:18:02 +01:00
|
|
|
|
|
|
|
|