mirror of
https://github.com/valitydev/salt.git
synced 2024-11-07 08:58:59 +00:00
Merge pull request #927 from fxdgear/develop
Major refactor of pip module, adding pip state module, changing virtualenv state to default no-site-packages to True
This commit is contained in:
commit
1f6a076a2c
@ -1,68 +1,374 @@
|
||||
'''
|
||||
Install Python packages with pip to either the system or a virtualenv
|
||||
'''
|
||||
__opts__ = {
|
||||
'pip_bin': 'pip',
|
||||
}
|
||||
|
||||
import os
|
||||
|
||||
def _get_pip_bin(pip, env):
|
||||
def _get_pip_bin(bin_env):
|
||||
'''
|
||||
Return the pip command to call, either from a virtualenv, an argument
|
||||
passed in, or from the global modules options
|
||||
'''
|
||||
if env:
|
||||
return os.path.join(env, 'bin', 'pip')
|
||||
if not bin_env:
|
||||
pip_bin = 'pip'
|
||||
else:
|
||||
return pip if pip else __opts__['pip_bin']
|
||||
# try to get pip bin from env
|
||||
if os.path.exists(os.path.join(bin_env, 'bin', 'pip')):
|
||||
pip_bin = os.path.join(bin_env, 'bin', 'pip')
|
||||
else:
|
||||
pip_bin = bin_env
|
||||
return pip_bin
|
||||
|
||||
def install(env='', requirements='', pkgs='', pip_bin=''):
|
||||
|
||||
def install(pkgs=None,
|
||||
requirements=None,
|
||||
env=None,
|
||||
bin_env=None,
|
||||
log=None,
|
||||
proxy=None,
|
||||
timeout=None,
|
||||
editable=None,
|
||||
find_links=None,
|
||||
index_url=None,
|
||||
extra_index_url=None,
|
||||
no_index=False,
|
||||
mirrors=None,
|
||||
build=None,
|
||||
target=None,
|
||||
download=None,
|
||||
download_cache=None,
|
||||
source=None,
|
||||
upgrade=False,
|
||||
force_reinstall=False,
|
||||
ignore_installed=False,
|
||||
no_deps=False,
|
||||
no_install=False,
|
||||
no_download=False,
|
||||
install_options=None):
|
||||
'''
|
||||
Install packages with pip
|
||||
|
||||
Install packages individually or from a pip requirements file. Install
|
||||
packages globally or to a virtualenv.
|
||||
|
||||
env : None
|
||||
The path to a virtualenv that pip should install to. This option takes
|
||||
precendence over the ``pip_bin`` argument.
|
||||
requirements : None
|
||||
The path to a pip requirements file to install from
|
||||
pkgs : None
|
||||
A list of space-separated packages to install
|
||||
pip_bin : 'pip'
|
||||
The name (and optionally path) of the pip command to call. This option
|
||||
will be ignored if the ``env`` argument is given since it will default
|
||||
to the pip that is installed in the virtualenv. This option can also be
|
||||
set in the minion config file as ``pip.pip_bin``.
|
||||
pkgs
|
||||
comma separated list of packages to install
|
||||
requirements
|
||||
path to requirements
|
||||
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.
|
||||
If installing into a virtualenv, just use the path to the virtualenv
|
||||
(/home/code/path/to/virtualenv/)
|
||||
env
|
||||
depreicated, use bin_env now
|
||||
log
|
||||
Log file where a complete (maximum verbosity) record will be kept
|
||||
proxy
|
||||
Specify a proxy in the form
|
||||
user:passwd@proxy.server:port. Note that the
|
||||
user:password@ is optional and required only if you
|
||||
are behind an authenticated proxy. If you provide
|
||||
user@proxy.server:port then you will be prompted for a
|
||||
password.
|
||||
timeout
|
||||
Set the socket timeout (default 15 seconds)
|
||||
editable
|
||||
install something editable(ie git+https://github.com/worldcompany/djangoembed.git#egg=djangoembed)
|
||||
find_links
|
||||
URL to look for packages at
|
||||
index_url
|
||||
Base URL of Python Package Index
|
||||
extra_index_url
|
||||
Extra URLs of package indexes to use in addition to ``index_url``
|
||||
no_index
|
||||
Ignore package index
|
||||
mirrors
|
||||
Specific mirror URLs to query (automatically adds --use-mirrors)
|
||||
build
|
||||
Unpack packages into ``build`` dir
|
||||
target
|
||||
Install packages into ``target`` dir
|
||||
download
|
||||
Download packages into ``download`` instead of installing them
|
||||
download_cache
|
||||
Cache downloaded packages in ``download_cache`` dir
|
||||
source
|
||||
Check out ``editable`` packages into ``source`` dir
|
||||
upgrade
|
||||
Upgrade all packages to the newest available version
|
||||
force_reinstall
|
||||
When upgrading, reinstall all packages even if they are already up-to-date.
|
||||
ignore_installed
|
||||
Ignore the installed packages (reinstalling instead)
|
||||
no_deps
|
||||
Ignore package dependencies
|
||||
no_install
|
||||
Download and unpack all packages, but don't actually install them
|
||||
no_download
|
||||
Don't download any packages, just install the ones
|
||||
already downloaded (completes an install run with
|
||||
--no-install)
|
||||
install_options
|
||||
Extra arguments to be supplied to the setup.py install
|
||||
command (use like --install-option="--install-
|
||||
scripts=/usr/local/bin"). Use multiple --install-
|
||||
option options to pass multiple options to setup.py
|
||||
install. If you are using an option with a directory
|
||||
path, be sure to use absolute path.
|
||||
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pip.install /var/www/myvirtualenv.com \\
|
||||
/path/to/requirements.txt
|
||||
salt '*' pip.install <package name>,<package2 name>
|
||||
|
||||
salt '*' pip.install requirements=/path/to/requirements.txt
|
||||
|
||||
salt '*' pip.install <package name> bin_env=/path/to/virtualenv
|
||||
|
||||
salt '*' pip.install <package name> bin_env=/path/to/pip_bin
|
||||
|
||||
Comlicated CLI example::
|
||||
|
||||
salt '*' pip.install markdown,django editable=git+https://github.com/worldcompany/djangoembed.git#egg=djangoembed upgrade=True no_deps=True
|
||||
|
||||
'''
|
||||
cmd = '{pip_bin} install {reqs} {pkgs}'.format(
|
||||
pip_bin=_get_pip_bin(pip_bin, env),
|
||||
reqs='-r {0}'.format(requirements) if requirements else '',
|
||||
pkgs=pkgs)
|
||||
# Switching from using `pip_bin` and `env` to just `bin_env`
|
||||
# cause using an env and a pip bin that's not in the env could
|
||||
# be problematic.
|
||||
# Still using the `env` variable, for backwards compatiblity sake
|
||||
# but going fwd you should specify either a pip bin or an env with
|
||||
# the `bin_env` argument and we'll take care of the rest.
|
||||
if env and not bin_env:
|
||||
bin_env = env
|
||||
|
||||
cmd = '{0} install'.format(_get_pip_bin(bin_env))
|
||||
|
||||
if pkgs:
|
||||
pkg = pkgs.replace(",", " ")
|
||||
cmd = '{cmd} {pkg} '.format(
|
||||
cmd=cmd, pkg=pkg)
|
||||
|
||||
if requirements:
|
||||
cmd = '{cmd} --requirements{requirements} '.format(
|
||||
cmd=cmd, requirements=requirements)
|
||||
|
||||
if log:
|
||||
try:
|
||||
# TODO make this check if writeable
|
||||
os.path.exists(log)
|
||||
except IOError:
|
||||
raise IOError("'%s' is not writeable" % log)
|
||||
cmd = '{cmd} --{log} '.format(
|
||||
cmd=cmd, log=log)
|
||||
|
||||
if proxy:
|
||||
cmd = '{cmd} --proxy={proxy} '.format(
|
||||
cmd=cmd, proxy=proxy)
|
||||
|
||||
if timeout:
|
||||
try:
|
||||
int(timeout)
|
||||
except ValueError:
|
||||
raise ValueError("'%s' is not a valid integer base 10.")
|
||||
cmd = '{cmd} --timeout={timeout} '.format(
|
||||
cmd=cmd, timeout=timeout)
|
||||
|
||||
if editable:
|
||||
if editable.find('egg') == -1:
|
||||
raise Exception('You must specify an egg for this editable')
|
||||
cmd = '{cmd} --editable={editable} '.format(
|
||||
cmd=cmd, editable=editable)
|
||||
|
||||
if find_links:
|
||||
if not find_links.startswith("http://"):
|
||||
raise Exception("'%s' must be a valid url" % find_links)
|
||||
cmd = '{cmd} --find_links={find_links}'.format(
|
||||
cmd=cmd, find_links=find_links)
|
||||
|
||||
if index_url:
|
||||
if not index_url.startswith("http://"):
|
||||
raise Exception("'%s' must be a valid url" % index_url)
|
||||
cmd = '{cmd} --index_url={index_url} '.format(
|
||||
cmd=cmd, index_url=index_url)
|
||||
|
||||
if extra_index_url:
|
||||
if not extra_index_url.startswith("http://"):
|
||||
raise Exception("'%s' must be a valid url" % extra_index_url)
|
||||
cmd = '{cmd} --extra_index_url={extra_index_url} '.format(
|
||||
cmd=cmd, extra_index_url=extra_index_url)
|
||||
|
||||
if no_index:
|
||||
cmd = '{cmd} --no-index '.format(cmd=cmd)
|
||||
|
||||
if mirrors:
|
||||
if not mirrors.startswith("http://"):
|
||||
raise Exception("'%s' must be a valid url" % mirrors)
|
||||
cmd = '{cmd} --use-mirrors --mirrors={mirrors} '.format(
|
||||
cmd=cmd, mirrors=mirrors)
|
||||
|
||||
if build:
|
||||
cmd = '{cmd} --build={build} '.format(
|
||||
cmd=cmd, build=build)
|
||||
|
||||
if target:
|
||||
cmd = '{cmd} --target={target} '.format(
|
||||
cmd=cmd, target=target)
|
||||
|
||||
if download:
|
||||
cmd = '{cmd} --download={download} '.format(
|
||||
cmd=cmd, download=download)
|
||||
|
||||
if download_cache:
|
||||
cmd = '{cmd} --download_cache={download_cache} '.format(
|
||||
cmd=cmd, download_cache=download_cache)
|
||||
|
||||
if source:
|
||||
cmd = '{cmd} --source={source} '.format(
|
||||
cmd=cmd, source=source)
|
||||
|
||||
if upgrade:
|
||||
cmd = '{cmd} --upgrade '.format(cmd=cmd)
|
||||
|
||||
if force_reinstall:
|
||||
cmd = '{cmd} --force-reinstall '.format(cmd=cmd)
|
||||
|
||||
if ignore_installed:
|
||||
cmd = '{cmd} --ignore-installed '.format(cmd=cmd)
|
||||
|
||||
if no_deps:
|
||||
cmd = '{cmd} --no-deps '.format(cmd=cmd)
|
||||
|
||||
if no_install:
|
||||
cmd = '{cmd} --no-install '.format(cmd=cmd)
|
||||
|
||||
if no_download:
|
||||
cmd = '{cmd} --no-download '.format(cmd=cmd)
|
||||
|
||||
if install_options:
|
||||
cmd = '{cmd} --install-options={install_options} '.format(
|
||||
cmd=cmd, install_options=install_options)
|
||||
|
||||
return __salt__['cmd.run'](cmd)
|
||||
|
||||
def freeze(env='', pip_bin=''):
|
||||
|
||||
def uninstall(pkgs=None,
|
||||
requirements=None,
|
||||
bin_env=None,
|
||||
log=None,
|
||||
proxy=None,
|
||||
timeout=None):
|
||||
'''
|
||||
Uninstall packages with pip
|
||||
|
||||
Uninstall packages individually or from a pip requirements file. Uninstall
|
||||
packages globally or from a virtualenv.
|
||||
|
||||
pkgs
|
||||
comma separated list of packages to install
|
||||
requirements
|
||||
path to requirements
|
||||
bin_env
|
||||
path to pip bin or path to virtualenv. If doing an uninstall from
|
||||
the system python and want to use a specific pip bin (pip-2.7,
|
||||
pip-2.6, etc..) just specify the pip bin you want.
|
||||
If uninstalling from a virtualenv, just use the path to the virtualenv
|
||||
(/home/code/path/to/virtualenv/)
|
||||
log
|
||||
Log file where a complete (maximum verbosity) record will be kept
|
||||
proxy
|
||||
Specify a proxy in the form
|
||||
user:passwd@proxy.server:port. Note that the
|
||||
user:password@ is optional and required only if you
|
||||
are behind an authenticated proxy. If you provide
|
||||
user@proxy.server:port then you will be prompted for a
|
||||
password.
|
||||
timeout
|
||||
Set the socket timeout (default 15 seconds)
|
||||
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pip.uninstall <package name>,<package2 name>
|
||||
|
||||
salt '*' pip.uninstall requirements=/path/to/requirements.txt
|
||||
|
||||
salt '*' pip.uninstall <package name> bin_env=/path/to/virtualenv
|
||||
|
||||
salt '*' pip.uninstall <package name> bin_env=/path/to/pip_bin
|
||||
|
||||
'''
|
||||
cmd = '{0} uninstall -y '.format(_get_pip_bin(bin_env))
|
||||
|
||||
if pkgs:
|
||||
pkg = pkgs.replace(",", " ")
|
||||
cmd = '{cmd} {pkg} '.format(
|
||||
cmd=cmd, pkg=pkg)
|
||||
|
||||
if requirements:
|
||||
cmd = '{cmd} --requirements{requirements} '.format(
|
||||
cmd=cmd, requirements=requirements)
|
||||
|
||||
if log:
|
||||
try:
|
||||
# TODO make this check if writeable
|
||||
os.path.exists(log)
|
||||
except IOError:
|
||||
raise IOError("'%s' is not writeable" % log)
|
||||
cmd = '{cmd} --{log} '.format(
|
||||
cmd=cmd, log=log)
|
||||
|
||||
if proxy:
|
||||
cmd = '{cmd} --proxy={proxy} '.format(
|
||||
cmd=cmd, proxy=proxy)
|
||||
|
||||
if timeout:
|
||||
try:
|
||||
int(timeout)
|
||||
except ValueError:
|
||||
raise ValueError("'%s' is not a valid integer base 10.")
|
||||
cmd = '{cmd} --timeout={timeout} '.format(
|
||||
cmd=cmd, timeout=timeout)
|
||||
|
||||
return __salt__['cmd.run'](cmd).split('\n')
|
||||
|
||||
|
||||
def freeze(bin_env=None):
|
||||
'''
|
||||
Return a list of installed packages either globally or in the specified
|
||||
virtualenv
|
||||
|
||||
env : None
|
||||
The path to a virtualenv that pip should install to. This option takes
|
||||
precendence over the ``pip_bin`` argument.
|
||||
pip_bin : 'pip'
|
||||
The name (and optionally path) of the pip command to call. This option
|
||||
will be ignored if the ``env`` argument is given since it will default
|
||||
to the pip that is installed in the virtualenv. This option can also be
|
||||
set in the minion config file as ``pip.pip_bin``.
|
||||
bin_env
|
||||
path to pip bin or path to virtualenv. If doing an uninstall from
|
||||
the system python and want to use a specific pip bin (pip-2.7,
|
||||
pip-2.6, etc..) just specify the pip bin you want.
|
||||
If uninstalling from a virtualenv, just use the path to the virtualenv
|
||||
(/home/code/path/to/virtualenv/)
|
||||
'''
|
||||
cmd = '{0} freeze'.format(_get_pip_bin(pip_bin, env))
|
||||
|
||||
cmd = '{0} freeze'.format(_get_pip_bin(bin_env))
|
||||
|
||||
return __salt__['cmd.run'](cmd).split('\n')
|
||||
|
||||
|
||||
def list(prefix='', bin_env=None):
|
||||
'''
|
||||
Filter list of instaslled apps from ``freeze`` and check to see if ``prefix``
|
||||
exists in the list of packages installed.
|
||||
'''
|
||||
packages = {}
|
||||
cmd = '{0} freeze'.format(_get_pip_bin(bin_env))
|
||||
for line in __salt__['cmd.run'](cmd).split("\n"):
|
||||
if len(line.split("==")) >= 2:
|
||||
name = line.split("==")[0]
|
||||
version = line.split("==")[1]
|
||||
if prefix:
|
||||
if line.lower().startswith(prefix.lower()):
|
||||
packages[name]=version
|
||||
else:
|
||||
packages[name]=version
|
||||
return packages
|
||||
|
||||
|
||||
|
||||
|
@ -11,7 +11,7 @@ __opts__ = {
|
||||
|
||||
def create(path,
|
||||
venv_bin=__opts__['venv_bin'],
|
||||
no_site_packages=True,
|
||||
no_site_packages=False,
|
||||
system_site_packages=False,
|
||||
clear=False,
|
||||
python='',
|
||||
|
138
salt/states/pip.py
Normal file
138
salt/states/pip.py
Normal file
@ -0,0 +1,138 @@
|
||||
'''
|
||||
Management of python packages
|
||||
=============================
|
||||
|
||||
A state module to manage system installed python packages
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
virtualenvwrapper:
|
||||
pip:
|
||||
- installed
|
||||
- version: 3.0.1
|
||||
'''
|
||||
|
||||
|
||||
def installed(name,
|
||||
pip_bin=None,
|
||||
requirements=None,
|
||||
env=None,
|
||||
bin_env=None,
|
||||
log=None,
|
||||
proxy=None,
|
||||
timeout=None,
|
||||
editable=None,
|
||||
find_links=None,
|
||||
index_url=None,
|
||||
extra_index_url=None,
|
||||
no_index=False,
|
||||
mirrors=None,
|
||||
build=None,
|
||||
target=None,
|
||||
download=None,
|
||||
download_cache=None,
|
||||
source=None,
|
||||
upgrade=False,
|
||||
force_reinstall=False,
|
||||
ignore_installed=False,
|
||||
no_deps=False,
|
||||
no_install=False,
|
||||
no_download=False,
|
||||
install_options=None):
|
||||
'''
|
||||
Make sure the package is installed
|
||||
|
||||
name
|
||||
The name of the python package to install
|
||||
pip_bin : None
|
||||
Deprecated, use bin_env
|
||||
env : None
|
||||
Deprecated, use bin_env
|
||||
bin_env : None
|
||||
the pip executable or virtualenv to use
|
||||
|
||||
'''
|
||||
if pip_bin and not bin_env:
|
||||
bin_env = pip_bin
|
||||
elif env and not bin_env:
|
||||
bin_env = env
|
||||
|
||||
ret = {'name': name, 'result': None, 'comment': '', 'changes': {}}
|
||||
if name in __salt__['pip.list'](name, bin_env):
|
||||
ret['result'] = True
|
||||
ret['comment'] = 'Package already installed'
|
||||
return ret
|
||||
|
||||
if __salt__['pip.install'](pkgs=name,
|
||||
requirements=requirements,
|
||||
bin_env=bin_env,
|
||||
log=log,
|
||||
proxy=proxy,
|
||||
timeout=timeout,
|
||||
editable=editable,
|
||||
find_links=find_links,
|
||||
index_url=index_url,
|
||||
extra_index_url=extra_index_url,
|
||||
no_index=no_index,
|
||||
mirrors=mirrors,
|
||||
build=build,
|
||||
target=target,
|
||||
download=download,
|
||||
download_cache=download_cache,
|
||||
source=source,
|
||||
upgrade=upgrade,
|
||||
force_reinstall=force_reinstall,
|
||||
ignore_installed=ignore_installed,
|
||||
no_deps=no_deps,
|
||||
no_install=no_install,
|
||||
no_download=no_download,
|
||||
install_options=install_options):
|
||||
pkg_list = __salt__['pip.list'](name, bin_env)
|
||||
version = pkg_list.values()[0]
|
||||
pkg_name = pkg_list.keys()[0]
|
||||
ret['result'] = True
|
||||
ret['changes']["{0}=={1}".format(pkg_name, version)] = 'Installed'
|
||||
ret['comment'] = 'Package was successfully installed'
|
||||
else:
|
||||
ret['result'] = False
|
||||
ret['comment'] = 'Could not install package'
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def removed(name,
|
||||
packages=None,
|
||||
requirements=None,
|
||||
bin_env=None,
|
||||
log=None,
|
||||
proxy=None,
|
||||
timeout=None):
|
||||
"""
|
||||
Make sure that a package is not installed.
|
||||
|
||||
name
|
||||
The name of the package to uninstall
|
||||
bin_env : None
|
||||
the pip executable or virtualenenv to use
|
||||
"""
|
||||
|
||||
ret = {'name': name, 'result': None, 'comment': '', 'changes': {}}
|
||||
if name not in __salt__["pip.list"](packages=name, bin_env=bin_env):
|
||||
ret["result"] = True
|
||||
ret["comment"] = "Pacakge is not installed."
|
||||
return ret
|
||||
|
||||
if __salt__["pip.uninstall"](packages=name,
|
||||
requirements=requirements,
|
||||
bin_env=bin_env,
|
||||
log=log,
|
||||
proxy=proxy,
|
||||
timeout=timeout):
|
||||
ret["result"] = True
|
||||
ret["changes"][name] = "Removed"
|
||||
ret["comment"] = "Package was successfully removed."
|
||||
else:
|
||||
ret["result"] = False
|
||||
ret["comment"] = "Could not remove package."
|
||||
return ret
|
||||
|
@ -62,7 +62,7 @@ def manage(name,
|
||||
|
||||
# If it already exists, grab the version for posterity
|
||||
if venv_exists and clear:
|
||||
ret['changes']['cleared_packages'] = __salt__['pip.freeze'](env=name)
|
||||
ret['changes']['cleared_packages'] = __salt__['pip.freeze'](bin_env=name)
|
||||
ret['changes']['old'] = __salt__['cmd.run_stderr'](
|
||||
'{0} -V'.format(venv_py)).strip('\n')
|
||||
|
||||
@ -109,9 +109,9 @@ def manage(name,
|
||||
else:
|
||||
new_reqs = __salt__['cp.cache_local_file'](requirements)
|
||||
|
||||
before = set(__salt__['pip.freeze'](env=name))
|
||||
__salt__['pip.install'](requirements=new_reqs, env=name)
|
||||
after = set(__salt__['pip.freeze'](env=name))
|
||||
before = set(__salt__['pip.freeze'](bin_env=name))
|
||||
__salt__['pip.install'](requirements=new_reqs, bin_env=name)
|
||||
after = set(__salt__['pip.freeze'](bin_env=name))
|
||||
|
||||
new = list(after - before)
|
||||
old = list(before - after)
|
||||
|
Loading…
Reference in New Issue
Block a user