summaryrefslogtreecommitdiff
path: root/setup.py
diff options
context:
space:
mode:
Diffstat (limited to 'setup.py')
-rw-r--r--setup.py147
1 files changed, 126 insertions, 21 deletions
diff --git a/setup.py b/setup.py
index fc369cb7cc..c741c568a4 100644
--- a/setup.py
+++ b/setup.py
@@ -1,17 +1,132 @@
+
+import json
import os
import os.path
import sys
+from collections import defaultdict
+from distutils.command.build_scripts import build_scripts as BuildScripts
+from distutils.command.sdist import sdist as SDist
-sys.path.insert(0, os.path.abspath('lib'))
-from ansible.release import __version__, __author__
try:
from setuptools import setup, find_packages
+ from setuptools.command.build_py import build_py as BuildPy
+ from setuptools.command.install_lib import install_lib as InstallLib
+ from setuptools.command.install_scripts import install_scripts as InstallScripts
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).")
sys.exit(1)
+sys.path.insert(0, os.path.abspath('lib'))
+from ansible.release import __version__, __author__
+
+
+SYMLINK_CACHE = 'SYMLINK_CACHE.json'
+
+
+def _find_symlinks(topdir, extension=''):
+ """Find symlinks that should be maintained
+
+ Maintained symlinks exist in the bin dir or are modules which have
+ aliases. Our heuristic is that they are a link in a certain path which
+ point to a file in the same directory.
+ """
+ symlinks = defaultdict(list)
+ for base_path, dirs, files in os.walk(topdir):
+ for filename in files:
+ filepath = os.path.join(base_path, filename)
+ if os.path.islink(filepath) and filename.endswith(extension):
+ target = os.readlink(filepath)
+ if os.path.dirname(target) == '':
+ link = filepath[len(topdir):]
+ if link.startswith('/'):
+ link = link[1:]
+ symlinks[os.path.basename(target)].append(link)
+ return symlinks
+
+
+def _cache_symlinks(symlink_data):
+ with open(SYMLINK_CACHE, 'w') as f:
+ f.write(json.dumps(symlink_data))
+
+
+def _maintain_symlinks(symlink_type, base_path):
+ """Switch a real file into a symlink"""
+ try:
+ # 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())
+ except IOError as e:
+ if e.errno == 2:
+ # SYMLINKS_CACHE doesn't exist. Fallback to trying to create the
+ # cache now. Will work if we're running directly from a git
+ # checkout or from an sdist created earlier.
+ symlink_data = {'script': _find_symlinks('bin'),
+ 'library': _find_symlinks('lib', '.py'),
+ }
+
+ # Sanity check that something we know should be a symlink was
+ # found. We'll take that to mean that the current directory
+ # structure properly reflects symlinks in the git repo
+ if 'ansible-playbook' in symlink_data['script']['ansible']:
+ _cache_symlinks(symlink_data)
+ else:
+ raise
+ else:
+ raise
+ symlinks = symlink_data[symlink_type]
+
+ for source in symlinks:
+ for dest in symlinks[source]:
+ dest_path = os.path.join(base_path, dest)
+ if not os.path.islink(dest_path):
+ try:
+ os.unlink(dest_path)
+ except OSError as e:
+ if e.errno == 2:
+ # File does not exist which is all we wanted
+ pass
+ os.symlink(source, dest_path)
+
+
+class BuildPyCommand(BuildPy):
+ def run(self):
+ BuildPy.run(self)
+ _maintain_symlinks('library', self.build_lib)
+
+
+class BuildScriptsCommand(BuildScripts):
+ def run(self):
+ BuildScripts.run(self)
+ _maintain_symlinks('script', self.build_dir)
+
+
+class InstallLibCommand(InstallLib):
+ def run(self):
+ InstallLib.run(self)
+ _maintain_symlinks('library', self.install_dir)
+
+
+class InstallScriptsCommand(InstallScripts):
+ def run(self):
+ InstallScripts.run(self)
+ _maintain_symlinks('script', self.install_dir)
+
+
+class SDistCommand(SDist):
+ def run(self):
+ # have to generate the cache of symlinks for release as sdist is the
+ # only command that has access to symlinks from the git repo
+ symlinks = {'script': _find_symlinks('bin'),
+ 'library': _find_symlinks('lib', '.py'),
+ }
+ _cache_symlinks(symlinks)
+
+ SDist.run(self)
+
+
with open('requirements.txt') as requirements_file:
install_requirements = requirements_file.read().splitlines()
if not install_requirements:
@@ -33,26 +148,16 @@ if crypto_backend:
install_requirements.append(crypto_backend)
-SYMLINKS = {'ansible': frozenset(('ansible-console',
- 'ansible-doc',
- 'ansible-galaxy',
- 'ansible-playbook',
- 'ansible-pull',
- 'ansible-vault'))}
-
-for source in SYMLINKS:
- for dest in SYMLINKS[source]:
- dest_path = os.path.join('bin', dest)
- if not os.path.islink(dest_path):
- try:
- os.unlink(dest_path)
- except OSError as e:
- if e.errno == 2:
- # File does not exist which is all we wanted
- pass
- os.symlink(source, dest_path)
-
setup(
+ # Use the distutils SDist so that symlinks are not expanded
+ # Use a custom Build for the same reason
+ cmdclass={
+ 'build_py': BuildPyCommand,
+ 'build_scripts': BuildScriptsCommand,
+ 'install_lib': InstallLibCommand,
+ 'install_scripts': InstallScriptsCommand,
+ 'sdist': SDistCommand,
+ },
name='ansible',
version=__version__,
description='Radically simple IT automation',