|
|
|
@ -1,4 +1,6 @@
|
|
|
|
|
|
|
|
|
|
from __future__ import print_function
|
|
|
|
|
|
|
|
|
|
import json
|
|
|
|
|
import os
|
|
|
|
|
import os.path
|
|
|
|
@ -16,7 +18,7 @@ try:
|
|
|
|
|
except ImportError:
|
|
|
|
|
print("Ansible now needs setuptools in order to build. Install it using"
|
|
|
|
|
" your package manager (usually python-setuptools) or via pip (pip"
|
|
|
|
|
" install setuptools).")
|
|
|
|
|
" install setuptools).", file=sys.stderr)
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
sys.path.insert(0, os.path.abspath('lib'))
|
|
|
|
@ -49,7 +51,7 @@ def _find_symlinks(topdir, extension=''):
|
|
|
|
|
|
|
|
|
|
def _cache_symlinks(symlink_data):
|
|
|
|
|
with open(SYMLINK_CACHE, 'w') as f:
|
|
|
|
|
f.write(json.dumps(symlink_data))
|
|
|
|
|
json.dump(symlink_data, f)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _maintain_symlinks(symlink_type, base_path):
|
|
|
|
@ -58,7 +60,7 @@ def _maintain_symlinks(symlink_type, base_path):
|
|
|
|
|
# Try the cache first because going from git checkout to sdist is the
|
|
|
|
|
# only time we know that we're going to cache correctly
|
|
|
|
|
with open(SYMLINK_CACHE, 'r') as f:
|
|
|
|
|
symlink_data = json.loads(f.read())
|
|
|
|
|
symlink_data = json.load(f)
|
|
|
|
|
except (IOError, OSError) as e:
|
|
|
|
|
# IOError on py2, OSError on py3. Both have errno
|
|
|
|
|
if e.errno == 2:
|
|
|
|
@ -129,49 +131,87 @@ class SDistCommand(SDist):
|
|
|
|
|
SDist.run(self)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with open('requirements.txt') as requirements_file:
|
|
|
|
|
install_requirements = requirements_file.read().splitlines()
|
|
|
|
|
if not install_requirements:
|
|
|
|
|
print("Unable to read requirements from the requirements.txt file"
|
|
|
|
|
"That indicates this copy of the source code is incomplete.")
|
|
|
|
|
sys.exit(2)
|
|
|
|
|
|
|
|
|
|
# pycrypto or cryptography. We choose a default but allow the user to
|
|
|
|
|
# override it. This translates into pip install of the sdist deciding what
|
|
|
|
|
# package to install and also the runtime dependencies that pkg_resources
|
|
|
|
|
# knows about
|
|
|
|
|
crypto_backend = os.environ.get('ANSIBLE_CRYPTO_BACKEND', None)
|
|
|
|
|
if crypto_backend:
|
|
|
|
|
if crypto_backend.strip() == 'pycrypto':
|
|
|
|
|
def read_file(file_name):
|
|
|
|
|
"""Read file and return its contents."""
|
|
|
|
|
with open(file_name, 'r') as f:
|
|
|
|
|
return f.read()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def read_requirements(file_name):
|
|
|
|
|
"""Read requirements file as a list."""
|
|
|
|
|
reqs = read_file(file_name).splitlines()
|
|
|
|
|
if not reqs:
|
|
|
|
|
raise RuntimeError(
|
|
|
|
|
"Unable to read requirements from the %s file"
|
|
|
|
|
"That indicates this copy of the source code is incomplete."
|
|
|
|
|
% file_name
|
|
|
|
|
)
|
|
|
|
|
return reqs
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PYCRYPTO_DIST = 'pycrypto'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_crypto_req():
|
|
|
|
|
"""Detect custom crypto from ANSIBLE_CRYPTO_BACKEND env var.
|
|
|
|
|
|
|
|
|
|
pycrypto or cryptography. We choose a default but allow the user to
|
|
|
|
|
override it. This translates into pip install of the sdist deciding what
|
|
|
|
|
package to install and also the runtime dependencies that pkg_resources
|
|
|
|
|
knows about.
|
|
|
|
|
"""
|
|
|
|
|
crypto_backend = os.environ.get('ANSIBLE_CRYPTO_BACKEND', '').strip()
|
|
|
|
|
|
|
|
|
|
if crypto_backend == PYCRYPTO_DIST:
|
|
|
|
|
# Attempt to set version requirements
|
|
|
|
|
crypto_backend = 'pycrypto >= 2.6'
|
|
|
|
|
return '%s >= 2.6' % PYCRYPTO_DIST
|
|
|
|
|
|
|
|
|
|
install_requirements = [r for r in install_requirements if not (r.lower().startswith('pycrypto') or r.lower().startswith('cryptography'))]
|
|
|
|
|
install_requirements.append(crypto_backend)
|
|
|
|
|
return crypto_backend or None
|
|
|
|
|
|
|
|
|
|
# specify any extra requirements for installation
|
|
|
|
|
extra_requirements = dict()
|
|
|
|
|
extra_requirements_dir = 'packaging/requirements'
|
|
|
|
|
for extra_requirements_filename in os.listdir(extra_requirements_dir):
|
|
|
|
|
filename_match = re.search(r'^requirements-(\w*).txt$', extra_requirements_filename)
|
|
|
|
|
if filename_match:
|
|
|
|
|
with open(os.path.join(extra_requirements_dir, extra_requirements_filename)) as extra_requirements_file:
|
|
|
|
|
extra_requirements[filename_match.group(1)] = extra_requirements_file.read().splitlines()
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
with open('README.rst', 'r') as readme_file:
|
|
|
|
|
longdesc = readme_file.read()
|
|
|
|
|
except (IOError, OSError):
|
|
|
|
|
longdesc = ('Ansible is a radically simple IT automation system. It handles'
|
|
|
|
|
' configuration-management, application deployment, cloud provisioning, ad-hoc'
|
|
|
|
|
' task-execution, and multinode orchestration - including trivializing things like'
|
|
|
|
|
' zero-downtime rolling updates with load balancers.\n'
|
|
|
|
|
'\n'
|
|
|
|
|
'Read the documentation and more at https://ansible.com/'
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setup_params = dict(
|
|
|
|
|
def substitute_crypto_to_req(req):
|
|
|
|
|
"""Replace crypto requirements if customized."""
|
|
|
|
|
crypto_backend = get_crypto_req()
|
|
|
|
|
|
|
|
|
|
if crypto_backend is None:
|
|
|
|
|
return req
|
|
|
|
|
|
|
|
|
|
def is_not_crypto(r):
|
|
|
|
|
CRYPTO_LIBS = PYCRYPTO_DIST, 'cryptography'
|
|
|
|
|
return not any(r.lower().startswith(c) for c in CRYPTO_LIBS)
|
|
|
|
|
|
|
|
|
|
return [r for r in req if is_not_crypto(r)] + [crypto_backend]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def read_extras():
|
|
|
|
|
"""Specify any extra requirements for installation."""
|
|
|
|
|
extras = dict()
|
|
|
|
|
extra_requirements_dir = 'packaging/requirements'
|
|
|
|
|
for extra_requirements_filename in os.listdir(extra_requirements_dir):
|
|
|
|
|
filename_match = re.search(r'^requirements-(\w*).txt$', extra_requirements_filename)
|
|
|
|
|
if not filename_match:
|
|
|
|
|
continue
|
|
|
|
|
extra_req_file_path = os.path.join(extra_requirements_dir, extra_requirements_filename)
|
|
|
|
|
try:
|
|
|
|
|
extras[filename_match.group(1)] = read_file(extra_req_file_path).splitlines()
|
|
|
|
|
except RuntimeError:
|
|
|
|
|
pass
|
|
|
|
|
return extras
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_dynamic_setup_params():
|
|
|
|
|
"""Add dynamically calculated setup params to static ones."""
|
|
|
|
|
return {
|
|
|
|
|
# Retrieve the long description from the README
|
|
|
|
|
'long_description': read_file('README.rst'),
|
|
|
|
|
'install_requires': substitute_crypto_to_req(
|
|
|
|
|
read_requirements('requirements.txt'),
|
|
|
|
|
),
|
|
|
|
|
'extras_require': read_extras(),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static_setup_params = dict(
|
|
|
|
|
# Use the distutils SDist so that symlinks are not expanded
|
|
|
|
|
# Use a custom Build for the same reason
|
|
|
|
|
cmdclass={
|
|
|
|
@ -184,7 +224,6 @@ setup_params = dict(
|
|
|
|
|
name='ansible',
|
|
|
|
|
version=__version__,
|
|
|
|
|
description='Radically simple IT automation',
|
|
|
|
|
long_description=longdesc,
|
|
|
|
|
author=__author__,
|
|
|
|
|
author_email='info@ansible.com',
|
|
|
|
|
url='https://ansible.com/',
|
|
|
|
@ -197,7 +236,6 @@ setup_params = dict(
|
|
|
|
|
license='GPLv3+',
|
|
|
|
|
# Ansible will also make use of a system copy of python-six and
|
|
|
|
|
# python-selectors2 if installed but use a Bundled copy if it's not.
|
|
|
|
|
install_requires=install_requirements,
|
|
|
|
|
python_requires='>=2.6,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*',
|
|
|
|
|
package_dir={'': 'lib'},
|
|
|
|
|
packages=find_packages('lib'),
|
|
|
|
@ -245,7 +283,6 @@ setup_params = dict(
|
|
|
|
|
'bin/ansible-inventory',
|
|
|
|
|
],
|
|
|
|
|
data_files=[],
|
|
|
|
|
extras_require=extra_requirements,
|
|
|
|
|
# Installing as zip files would break due to references to __file__
|
|
|
|
|
zip_safe=False
|
|
|
|
|
)
|
|
|
|
@ -253,6 +290,7 @@ setup_params = dict(
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
|
"""Invoke installation process using setuptools."""
|
|
|
|
|
setup_params = dict(static_setup_params, **get_dynamic_setup_params())
|
|
|
|
|
setup(**setup_params)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|