Mini Shell
"""
Setup of Python virtualenv sandboxes.
.. versionadded:: 0.17.0
"""
import logging
import os
import salt.utils.functools
import salt.utils.platform
import salt.utils.versions
import salt.version
from salt.exceptions import CommandExecutionError, CommandNotFoundError
log = logging.getLogger(__name__)
# Define the module's virtual name
__virtualname__ = "virtualenv"
def __virtual__():
if "virtualenv.create" in __salt__:
return __virtualname__
return (False, "virtualenv module could not be loaded")
def managed(
name,
venv_bin=None,
requirements=None,
system_site_packages=False,
distribute=False,
use_wheel=False,
clear=False,
python=None,
extra_search_dir=None,
never_download=None,
prompt=None,
user=None,
cwd=None,
index_url=None,
extra_index_url=None,
pre_releases=False,
no_deps=False,
pip_download=None,
pip_download_cache=None,
pip_exists_action=None,
pip_ignore_installed=False,
proxy=None,
use_vt=False,
env_vars=None,
no_use_wheel=False,
pip_upgrade=False,
pip_pkgs=None,
pip_no_cache_dir=False,
pip_cache_dir=None,
process_dependency_links=False,
no_binary=None,
**kwargs,
):
"""
Create a virtualenv and optionally manage it with pip
name
Path to the virtualenv.
venv_bin: virtualenv
The name (and optionally path) of the virtualenv command. This can also
be set globally in the minion config file as ``virtualenv.venv_bin``.
requirements: None
Path to a pip requirements file. If the path begins with ``salt://``
the file will be transferred from the master file server.
use_wheel: False
Prefer wheel archives (requires pip >= 1.4).
python: None
Python executable used to build the virtualenv
user: None
The user under which to run virtualenv and pip.
cwd: None
Path to the working directory where `pip install` is executed.
no_deps: False
Pass `--no-deps` to `pip install`.
pip_exists_action: None
Default action of pip when a path already exists: (s)witch, (i)gnore,
(w)ipe, (b)ackup.
proxy: None
Proxy address which is passed to `pip install`.
env_vars: None
Set environment variables that some builds will depend on. For example,
a Python C-module may have a Makefile that needs INCLUDE_PATH set to
pick up a header file while compiling.
no_use_wheel: False
Force to not use wheel archives (requires pip>=1.4)
no_binary
Force to not use binary packages (requires pip >= 7.0.0)
Accepts either :all: to disable all binary packages, :none: to empty the set,
or a list of one or more packages
pip_upgrade: False
Pass `--upgrade` to `pip install`.
pip_pkgs: None
As an alternative to `requirements`, pass a list of pip packages that
should be installed.
process_dependency_links: False
Run pip install with the --process_dependency_links flag.
.. versionadded:: 2017.7.0
Also accepts any kwargs that the virtualenv module will. However, some
kwargs, such as the ``pip`` option, require ``- distribute: True``.
.. code-block:: yaml
/var/www/myvirtualenv.com:
virtualenv.managed:
- system_site_packages: False
- requirements: salt://REQUIREMENTS.txt
- env_vars:
PATH_VAR: '/usr/local/bin/'
"""
ret = {"name": name, "result": True, "comment": "", "changes": {}}
if "virtualenv.create" not in __salt__:
ret["result"] = False
ret["comment"] = "Virtualenv was not detected on this system"
return ret
if salt.utils.platform.is_windows():
venv_py = os.path.join(name, "Scripts", "python.exe")
else:
venv_py = os.path.join(name, "bin", "python")
venv_exists = os.path.exists(venv_py)
# Bail out early if the specified requirements file can't be found
if requirements and requirements.startswith("salt://"):
cached_requirements = __salt__["cp.is_cached"](requirements, __env__)
if not cached_requirements:
# It's not cached, let's cache it.
cached_requirements = __salt__["cp.cache_file"](requirements, __env__)
# Check if the master version has changed.
if cached_requirements and __salt__["cp.hash_file"](
requirements, __env__
) != __salt__["cp.hash_file"](cached_requirements, __env__):
cached_requirements = __salt__["cp.cache_file"](requirements, __env__)
if not cached_requirements:
ret.update(
{
"result": False,
"comment": "pip requirements file '{}' not found".format(
requirements
),
}
)
return ret
requirements = cached_requirements
# If it already exists, grab the version for posterity
if venv_exists and clear:
ret["changes"]["cleared_packages"] = __salt__["pip.freeze"](bin_env=name)
ret["changes"]["old"] = __salt__["cmd.run_stderr"](f"{venv_py} -V").strip("\n")
# Create (or clear) the virtualenv
if __opts__["test"]:
if venv_exists and clear:
ret["result"] = None
ret["comment"] = f"Virtualenv {name} is set to be cleared"
return ret
if venv_exists and not clear:
ret["comment"] = f"Virtualenv {name} is already created"
return ret
ret["result"] = None
ret["comment"] = f"Virtualenv {name} is set to be created"
return ret
if not venv_exists or (venv_exists and clear):
try:
venv_ret = __salt__["virtualenv.create"](
name,
venv_bin=venv_bin,
system_site_packages=system_site_packages,
distribute=distribute,
clear=clear,
python=python,
extra_search_dir=extra_search_dir,
never_download=never_download,
prompt=prompt,
user=user,
use_vt=use_vt,
**kwargs,
)
except CommandNotFoundError as err:
ret["result"] = False
ret["comment"] = f"Failed to create virtualenv: {err}"
return ret
if venv_ret["retcode"] != 0:
ret["result"] = False
ret["comment"] = venv_ret["stdout"] + venv_ret["stderr"]
return ret
ret["result"] = True
ret["changes"]["new"] = __salt__["cmd.run_stderr"](f"{venv_py} -V").strip("\n")
if clear:
ret["comment"] = "Cleared existing virtualenv"
else:
ret["comment"] = "Created new virtualenv"
elif venv_exists:
ret["comment"] = "virtualenv exists"
# Check that the pip binary supports the 'use_wheel' option
if use_wheel:
min_version = "1.4"
max_version = "9.0.3"
cur_version = __salt__["pip.version"](bin_env=name)
too_low = salt.utils.versions.compare(
ver1=cur_version, oper="<", ver2=min_version
)
too_high = salt.utils.versions.compare(
ver1=cur_version, oper=">", ver2=max_version
)
if too_low or too_high:
ret["result"] = False
ret["comment"] = (
"The 'use_wheel' option is only supported in "
"pip between {} and {}. The version of pip detected "
"was {}.".format(min_version, max_version, cur_version)
)
return ret
# Check that the pip binary supports the 'no_use_wheel' option
if no_use_wheel:
min_version = "1.4"
max_version = "9.0.3"
cur_version = __salt__["pip.version"](bin_env=name)
too_low = salt.utils.versions.compare(
ver1=cur_version, oper="<", ver2=min_version
)
too_high = salt.utils.versions.compare(
ver1=cur_version, oper=">", ver2=max_version
)
if too_low or too_high:
ret["result"] = False
ret["comment"] = (
"The 'no_use_wheel' option is only supported in "
"pip between {} and {}. The version of pip detected "
"was {}.".format(min_version, max_version, cur_version)
)
return ret
# Check that the pip binary supports the 'no_binary' option
if no_binary:
min_version = "7.0.0"
cur_version = __salt__["pip.version"](bin_env=name)
too_low = salt.utils.versions.compare(
ver1=cur_version, oper="<", ver2=min_version
)
if too_low:
ret["result"] = False
ret["comment"] = (
"The 'no_binary' option is only supported in "
"pip {} and newer. The version of pip detected "
"was {}.".format(min_version, cur_version)
)
return ret
# Populate the venv via a requirements file
if requirements or pip_pkgs:
try:
before = set(__salt__["pip.freeze"](bin_env=name, user=user, use_vt=use_vt))
except CommandExecutionError as exc:
ret["result"] = False
ret["comment"] = exc.strerror
return ret
if requirements:
if isinstance(requirements, str):
req_canary = requirements.split(",")[0]
elif isinstance(requirements, list):
req_canary = requirements[0]
else:
raise TypeError("pip requirements must be either a string or a list")
if req_canary != os.path.abspath(req_canary):
cwd = os.path.dirname(os.path.abspath(req_canary))
pip_ret = __salt__["pip.install"](
pkgs=pip_pkgs,
requirements=requirements,
process_dependency_links=process_dependency_links,
bin_env=name,
use_wheel=use_wheel,
no_use_wheel=no_use_wheel,
no_binary=no_binary,
user=user,
cwd=cwd,
index_url=index_url,
extra_index_url=extra_index_url,
download=pip_download,
download_cache=pip_download_cache,
pre_releases=pre_releases,
exists_action=pip_exists_action,
ignore_installed=pip_ignore_installed,
upgrade=pip_upgrade,
no_deps=no_deps,
proxy=proxy,
use_vt=use_vt,
env_vars=env_vars,
no_cache_dir=pip_no_cache_dir,
cache_dir=pip_cache_dir,
**kwargs,
)
ret["result"] &= pip_ret["retcode"] == 0
if pip_ret["retcode"] > 0:
ret["comment"] = "{}\n{}\n{}".format(
ret["comment"], pip_ret["stdout"], pip_ret["stderr"]
)
after = set(__salt__["pip.freeze"](bin_env=name))
new = list(after - before)
old = list(before - after)
if new or old:
ret["changes"]["packages"] = {
"new": new if new else "",
"old": old if old else "",
}
return ret
manage = salt.utils.functools.alias_function(managed, "manage")
Zerion Mini Shell 1.0