summaryrefslogtreecommitdiff
path: root/baserockimport/exts/python.find_deps
diff options
context:
space:
mode:
Diffstat (limited to 'baserockimport/exts/python.find_deps')
-rwxr-xr-xbaserockimport/exts/python.find_deps124
1 files changed, 86 insertions, 38 deletions
diff --git a/baserockimport/exts/python.find_deps b/baserockimport/exts/python.find_deps
index 91a9e39..b173110 100755
--- a/baserockimport/exts/python.find_deps
+++ b/baserockimport/exts/python.find_deps
@@ -24,6 +24,7 @@
from __future__ import print_function
+import contextlib
import sys
import subprocess
import os
@@ -32,6 +33,7 @@ import tempfile
import logging
import select
import signal
+import shutil
import pkg_resources
import xmlrpclib
@@ -262,65 +264,109 @@ def find_build_deps(source, name, version=None):
return build_deps
+
+@contextlib.contextmanager
+def temporary_virtualenv():
+ tempdir = tempfile.mkdtemp()
+
+ logging.debug('Creating virtualenv in %s', tempdir)
+ p = subprocess.Popen(['virtualenv', tempdir], stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+
+ while True:
+ line = p.stdout.readline()
+ if line == '':
+ break
+
+ logging.debug(line.rstrip('\n'))
+
+ p.wait() # even with eof, wait for termination
+
+ try:
+ yield tempdir
+ finally:
+ logging.debug('Removing virtualenv at %s', tempdir)
+ shutil.rmtree(tempdir)
+
+
def find_runtime_deps(source, name, version=None, use_requirements_file=False):
logging.debug('Finding runtime dependencies for %s%s at %s'
% (name, ' %s' % version if version else '', source))
- # Run our patched pip to get a list of installed deps
- # Run pip install . --list-dependencies=instdeps.txt with cwd=source
-
# Some temporary file needed for storing the requirements
tmpfd, tmppath = tempfile.mkstemp()
logging.debug('Writing install requirements to: %s', tmppath)
- args = ['pip', 'install', '.', '--list-dependencies=%s' % tmppath]
- if use_requirements_file:
- args.insert(args.index('.') + 1, '-r')
- args.insert(args.index('.') + 2, 'requirements.txt')
+ with temporary_virtualenv() as virtenv_path:
+ shutil.copytree(source, os.path.join(virtenv_path, 'source'))
- logging.debug('Running pip, args: %s' % args)
+ pip_runner = os.path.join(os.path.dirname(os.path.abspath(__file__)),
+ 'python_run_pip')
+ logging.debug('pip_runner: %s', pip_runner)
- p = subprocess.Popen(args, cwd=source, stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT)
+ subprocess_env = os.environ.copy()
+ subprocess_env['TMPDIR'] = os.path.join(virtenv_path, 'tmp')
+ logging.debug('Using %s as TMPDIR', subprocess_env['TMPDIR'])
+ p = subprocess.Popen(pip_runner, cwd=virtenv_path, env=subprocess_env,
+ stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
- output = []
- while True:
- line = p.stdout.readline()
- if line == '':
- break
+ output = []
+ while True:
+ line = p.stdout.readline()
+ if line == '':
+ break
- logging.debug(line.rstrip('\n'))
- output.append(line)
+ logging.debug(line.rstrip('\n'))
+ output.append(line)
- p.wait() # even with eof, wait for termination
+ p.wait() # even with eof, wait for termination
- logging.debug('pip exited with code: %d' % p.returncode)
+ logging.debug('pip exited with code: %d' % p.returncode)
- if p.returncode != 0:
- error('Failed to get runtime dependencies for %s%s at %s. Output from '
- 'Pip: %s' % (name, ' %s' % version if version else '', source,
- ' '.join(output)))
+ if p.returncode != 0:
+ error('Failed to get runtime dependencies for %s%s at %s. Output '
+ 'from Pip: %s' % (name, ' %s' % version if version else '',
+ source, ' '.join(output)))
+
+ # Now run pip freeze
+ logging.debug('Running pip freeze')
+
+ p = subprocess.Popen(['/bin/bash', '-c',
+ 'source bin/activate; '
+ 'pip freeze --disable-pip-version-check'],
+ cwd=virtenv_path,
+ stdout=tmpfd, stderr=subprocess.PIPE)
- with os.fdopen(tmpfd) as tmpfile:
- ss = resolve_specs(pkg_resources.parse_requirements(tmpfile))
- logging.debug("Resolved specs for %s: %s" % (name, ss))
+ _, err = p.communicate()
+ os.close(tmpfd)
- logging.debug("Removing root package from specs")
+ if p.returncode != 0:
+ error('failed to get runtime dependencies for %s%s at %s: %s'
+ % (name, ' %s' % version if version else '', source, err))
- # filter out "root" package
- # hyphens and underscores are treated as equivalents
- # in distribution names
- specsets = {k: v for (k, v) in ss.iteritems()
- if k not in [name, name.replace('_', '-')]}
+ with open(tmppath) as f:
+ logging.debug(f.read())
- versions = resolve_versions(specsets)
- logging.debug('Resolved versions: %s' % versions)
+ with open(tmppath) as tmpfile:
+ ss = resolve_specs(pkg_resources.parse_requirements(tmpfile))
+ logging.debug("Resolved specs for %s: %s" % (name, ss))
- # Since any of the candidates in versions should satisfy
- # all specs, we just pick the first version we see
- runtime_deps = {name: vs[0] for (name, vs) in versions.iteritems()}
+ logging.debug("Removing root package from specs")
- os.remove(tmppath)
+ # filter out "root" package
+ # hyphens and underscores are treated as equivalents
+ # in distribution names
+ specsets = {k: v for (k, v) in ss.iteritems()
+ if k not in [name, name.replace('_', '-')]}
+
+ versions = resolve_versions(specsets)
+ logging.debug('Resolved versions: %s' % versions)
+
+ # Since any of the candidates in versions should satisfy
+ # all specs, we just pick the first version we see
+ runtime_deps = {name: vs[0] for (name, vs) in versions.iteritems()}
+
+ os.remove(tmppath)
if (len(runtime_deps) == 0 and not use_requirements_file
and os.path.isfile(os.path.join(source, 'requirements.txt'))):
@@ -360,6 +406,8 @@ class PythonFindDepsExtension(ImportExtension):
root = {'python': deps}
+ logging.debug('Returning %s', root)
+
print(json.dumps(root))
if __name__ == '__main__':