We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Nondeterministic "invalid command 'bdist_wheel'" resulting in "Untranslateable" exception
I just started using pex. About half of the time I run it, it works great. The other half of the time, it fails like this.

```
> pex --python python2.7 abc.zip -v
**** Failed to install enum34-1.0.4. stdout: :: Packaging enum34

**** Failed to install enum34-1.0.4. stderr:
usage: setup.py [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]
   or: setup.py --help [cmd1 cmd2 ...]
   or: setup.py --help-commands
   or: setup.py cmd --help

error: invalid command 'bdist_wheel'

pex: Failed to install package at /tmp/tmppcotrf/enum34-1.0.4: Failed to install /tmp/tmppcotrf/enum34-1.0.4
Traceback (most recent call last):
  File "/bin/pex", line 9, in <module>
    load_entry_point('pex==1.0.3', 'console_scripts', 'pex')()
  File "/usr/lib/python3.3/site-packages/pex/bin/pex.py", line 509, in main
    pex_builder = build_pex(reqs, options, resolver_options_builder)
  File "/usr/lib/python3.3/site-packages/pex/bin/pex.py", line 471, in build_pex
    resolveds = resolver.resolve(resolvables)
  File "/usr/lib/python3.3/site-packages/pex/resolver.py", line 191, in resolve
    dist = self.build(package, resolvable.options)
  File "/usr/lib/python3.3/site-packages/pex/resolver.py", line 248, in build
    dist = super(CachingResolver, self).build(package, options)
  File "/usr/lib/python3.3/site-packages/pex/resolver.py", line 160, in build
    raise Untranslateable('Package %s is not translateable by %s' % (package, translator))
pex.resolver.Untranslateable: Package SourcePackage('file:///home/chris/.pex/build/enum34-1.0.4.zip') is not translateable by ChainedTranslator(WheelTranslator, EggTranslator, SourceTranslator)
```

In the above example it failed on `enum34`, but which dependency it fails on appears random as well.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pex/installer.py`
Content:
```
1 # Copyright 2014 Pants project contributors (see CONTRIBUTORS.md).
2 # Licensed under the Apache License, Version 2.0 (see LICENSE).
3 
4 from __future__ import absolute_import, print_function
5 
6 import os
7 import sys
8 import tempfile
9 
10 from pkg_resources import Distribution, PathMetadata
11 
12 from .common import safe_mkdtemp, safe_rmtree
13 from .compatibility import WINDOWS
14 from .executor import Executor
15 from .interpreter import PythonInterpreter
16 from .tracer import TRACER
17 from .version import SETUPTOOLS_REQUIREMENT, WHEEL_REQUIREMENT
18 
19 __all__ = (
20   'Installer',
21   'Packager'
22 )
23 
24 
25 def after_installation(function):
26   def function_wrapper(self, *args, **kw):
27     self._installed = self.run()
28     if not self._installed:
29       raise Installer.InstallFailure('Failed to install %s' % self._source_dir)
30     return function(self, *args, **kw)
31   return function_wrapper
32 
33 
34 class InstallerBase(object):
35   SETUP_BOOTSTRAP_HEADER = "import sys"
36   SETUP_BOOTSTRAP_MODULE = "sys.path.insert(0, %(path)r); import %(module)s"
37   SETUP_BOOTSTRAP_FOOTER = """
38 __file__ = 'setup.py'
39 sys.argv[0] = 'setup.py'
40 exec(compile(open(__file__, 'rb').read(), __file__, 'exec'))
41 """
42 
43   class Error(Exception): pass
44   class InstallFailure(Error): pass
45   class IncapableInterpreter(Error): pass
46 
47   def __init__(self, source_dir, strict=True, interpreter=None, install_dir=None):
48     """
49       Create an installer from an unpacked source distribution in source_dir.
50 
51       If strict=True, fail if any installation dependencies (e.g. distribute)
52       are missing.
53     """
54     self._source_dir = source_dir
55     self._install_tmp = install_dir or safe_mkdtemp()
56     self._installed = None
57     self._strict = strict
58     self._interpreter = interpreter or PythonInterpreter.get()
59     if not self._interpreter.satisfies(self.capability) and strict:
60       raise self.IncapableInterpreter('Interpreter %s not capable of running %s' % (
61           self._interpreter.binary, self.__class__.__name__))
62 
63   def mixins(self):
64     """Return a map from import name to requirement to load into setup script prior to invocation.
65 
66        May be subclassed.
67     """
68     return {}
69 
70   @property
71   def install_tmp(self):
72     return self._install_tmp
73 
74   def _setup_command(self):
75     """the setup command-line to run, to be implemented by subclasses."""
76     raise NotImplementedError
77 
78   def _postprocess(self):
79     """a post-processing function to run following setup.py invocation."""
80 
81   @property
82   def capability(self):
83     """returns the list of requirements for the interpreter to run this installer."""
84     return list(self.mixins().values())
85 
86   @property
87   def bootstrap_script(self):
88     bootstrap_modules = []
89     for module, requirement in self.mixins().items():
90       path = self._interpreter.get_location(requirement)
91       if not path:
92         assert not self._strict  # This should be caught by validation
93         continue
94       bootstrap_modules.append(self.SETUP_BOOTSTRAP_MODULE % {'path': path, 'module': module})
95     return '\n'.join(
96         [self.SETUP_BOOTSTRAP_HEADER] + bootstrap_modules + [self.SETUP_BOOTSTRAP_FOOTER])
97 
98   def run(self):
99     if self._installed is not None:
100       return self._installed
101 
102     with TRACER.timed('Installing %s' % self._install_tmp, V=2):
103       command = [self._interpreter.binary, '-'] + self._setup_command()
104       try:
105         Executor.execute(command,
106                          env=self._interpreter.sanitized_environment(),
107                          cwd=self._source_dir,
108                          stdin_payload=self.bootstrap_script.encode('ascii'))
109         self._installed = True
110       except Executor.NonZeroExit as e:
111         self._installed = False
112         name = os.path.basename(self._source_dir)
113         print('**** Failed to install %s (caused by: %r\n):' % (name, e), file=sys.stderr)
114         print('stdout:\n%s\nstderr:\n%s\n' % (e.stdout, e.stderr), file=sys.stderr)
115         return self._installed
116 
117     self._postprocess()
118     return self._installed
119 
120   def cleanup(self):
121     safe_rmtree(self._install_tmp)
122 
123 
124 class Installer(InstallerBase):
125   """Install an unpacked distribution with a setup.py."""
126 
127   def __init__(self, source_dir, strict=True, interpreter=None):
128     """
129       Create an installer from an unpacked source distribution in source_dir.
130 
131       If strict=True, fail if any installation dependencies (e.g. setuptools)
132       are missing.
133     """
134     super(Installer, self).__init__(source_dir, strict=strict, interpreter=interpreter)
135     self._egg_info = None
136     fd, self._install_record = tempfile.mkstemp()
137     os.close(fd)
138 
139   def _setup_command(self):
140     return ['install',
141            '--root=%s' % self._install_tmp,
142            '--prefix=',
143            '--single-version-externally-managed',
144            '--record', self._install_record]
145 
146   def _postprocess(self):
147     installed_files = []
148     egg_info = None
149     with open(self._install_record) as fp:
150       installed_files = fp.read().splitlines()
151       for line in installed_files:
152         if line.endswith('.egg-info'):
153           assert line.startswith('/'), 'Expect .egg-info to be within install_tmp!'
154           egg_info = line
155           break
156 
157     if not egg_info:
158       self._installed = False
159       return self._installed
160 
161     installed_files = [os.path.relpath(fn, egg_info) for fn in installed_files if fn != egg_info]
162 
163     self._egg_info = os.path.join(self._install_tmp, egg_info[1:])
164     with open(os.path.join(self._egg_info, 'installed-files.txt'), 'w') as fp:
165       fp.write('\n'.join(installed_files))
166       fp.write('\n')
167 
168     return self._installed
169 
170   @after_installation
171   def egg_info(self):
172     return self._egg_info
173 
174   @after_installation
175   def root(self):
176     egg_info = self.egg_info()
177     assert egg_info
178     return os.path.realpath(os.path.dirname(egg_info))
179 
180   @after_installation
181   def distribution(self):
182     base_dir = self.root()
183     egg_info = self.egg_info()
184     metadata = PathMetadata(base_dir, egg_info)
185     return Distribution.from_location(base_dir, os.path.basename(egg_info), metadata=metadata)
186 
187 
188 class DistributionPackager(InstallerBase):
189   def mixins(self):
190     mixins = super(DistributionPackager, self).mixins().copy()
191     mixins.update(setuptools=SETUPTOOLS_REQUIREMENT)
192     return mixins
193 
194   def find_distribution(self):
195     dists = os.listdir(self.install_tmp)
196     if len(dists) == 0:
197       raise self.InstallFailure('No distributions were produced!')
198     elif len(dists) > 1:
199       raise self.InstallFailure('Ambiguous source distributions found: %s' % (' '.join(dists)))
200     else:
201       return os.path.join(self.install_tmp, dists[0])
202 
203 
204 class Packager(DistributionPackager):
205   """
206     Create a source distribution from an unpacked setup.py-based project.
207   """
208 
209   def _setup_command(self):
210     if WINDOWS:
211       return ['sdist', '--formats=zip', '--dist-dir=%s' % self._install_tmp]
212     else:
213       return ['sdist', '--formats=gztar', '--dist-dir=%s' % self._install_tmp]
214 
215   @after_installation
216   def sdist(self):
217     return self.find_distribution()
218 
219 
220 class EggInstaller(DistributionPackager):
221   """
222     Create a source distribution from an unpacked setup.py-based project.
223   """
224 
225   def _setup_command(self):
226     return ['bdist_egg', '--dist-dir=%s' % self._install_tmp]
227 
228   @after_installation
229   def bdist(self):
230     return self.find_distribution()
231 
232 
233 class WheelInstaller(DistributionPackager):
234   """
235     Create a source distribution from an unpacked setup.py-based project.
236   """
237   MIXINS = {
238       'setuptools': SETUPTOOLS_REQUIREMENT,
239       'wheel': WHEEL_REQUIREMENT,
240   }
241 
242   def mixins(self):
243     mixins = super(WheelInstaller, self).mixins().copy()
244     mixins.update(self.MIXINS)
245     return mixins
246 
247   def _setup_command(self):
248     return ['bdist_wheel', '--dist-dir=%s' % self._install_tmp]
249 
250   @after_installation
251   def bdist(self):
252     return self.find_distribution()
253
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pex/installer.py b/pex/installer.py
--- a/pex/installer.py
+++ b/pex/installer.py
@@ -33,7 +33,8 @@
 
 class InstallerBase(object):
   SETUP_BOOTSTRAP_HEADER = "import sys"
-  SETUP_BOOTSTRAP_MODULE = "sys.path.insert(0, %(path)r); import %(module)s"
+  SETUP_BOOTSTRAP_PYPATH = "sys.path.insert(0, %(path)r)"
+  SETUP_BOOTSTRAP_MODULE = "import %(module)s"
   SETUP_BOOTSTRAP_FOOTER = """
 __file__ = 'setup.py'
 sys.argv[0] = 'setup.py'
@@ -85,15 +86,21 @@
 
   @property
   def bootstrap_script(self):
+    bootstrap_sys_paths = []
     bootstrap_modules = []
     for module, requirement in self.mixins().items():
       path = self._interpreter.get_location(requirement)
       if not path:
         assert not self._strict  # This should be caught by validation
         continue
-      bootstrap_modules.append(self.SETUP_BOOTSTRAP_MODULE % {'path': path, 'module': module})
+      bootstrap_sys_paths.append(self.SETUP_BOOTSTRAP_PYPATH % {'path': path})
+      bootstrap_modules.append(self.SETUP_BOOTSTRAP_MODULE % {'module': module})
     return '\n'.join(
-        [self.SETUP_BOOTSTRAP_HEADER] + bootstrap_modules + [self.SETUP_BOOTSTRAP_FOOTER])
+      [self.SETUP_BOOTSTRAP_HEADER] +
+      bootstrap_sys_paths +
+      bootstrap_modules +
+      [self.SETUP_BOOTSTRAP_FOOTER]
+    )
 
   def run(self):
     if self._installed is not None:

{"golden_diff": "diff --git a/pex/installer.py b/pex/installer.py\n--- a/pex/installer.py\n+++ b/pex/installer.py\n@@ -33,7 +33,8 @@\n \n class InstallerBase(object):\n   SETUP_BOOTSTRAP_HEADER = \"import sys\"\n-  SETUP_BOOTSTRAP_MODULE = \"sys.path.insert(0, %(path)r); import %(module)s\"\n+  SETUP_BOOTSTRAP_PYPATH = \"sys.path.insert(0, %(path)r)\"\n+  SETUP_BOOTSTRAP_MODULE = \"import %(module)s\"\n   SETUP_BOOTSTRAP_FOOTER = \"\"\"\n __file__ = 'setup.py'\n sys.argv[0] = 'setup.py'\n@@ -85,15 +86,21 @@\n \n   @property\n   def bootstrap_script(self):\n+    bootstrap_sys_paths = []\n     bootstrap_modules = []\n     for module, requirement in self.mixins().items():\n       path = self._interpreter.get_location(requirement)\n       if not path:\n         assert not self._strict  # This should be caught by validation\n         continue\n-      bootstrap_modules.append(self.SETUP_BOOTSTRAP_MODULE % {'path': path, 'module': module})\n+      bootstrap_sys_paths.append(self.SETUP_BOOTSTRAP_PYPATH % {'path': path})\n+      bootstrap_modules.append(self.SETUP_BOOTSTRAP_MODULE % {'module': module})\n     return '\\n'.join(\n-        [self.SETUP_BOOTSTRAP_HEADER] + bootstrap_modules + [self.SETUP_BOOTSTRAP_FOOTER])\n+      [self.SETUP_BOOTSTRAP_HEADER] +\n+      bootstrap_sys_paths +\n+      bootstrap_modules +\n+      [self.SETUP_BOOTSTRAP_FOOTER]\n+    )\n \n   def run(self):\n     if self._installed is not None:\n", "issue": "Nondeterministic \"invalid command 'bdist_wheel'\" resulting in \"Untranslateable\" exception\nI just started using pex. About half of the time I run it, it works great. The other half of the time, it fails like this.\n\n```\n> pex --python python2.7 abc.zip -v\n**** Failed to install enum34-1.0.4. stdout: :: Packaging enum34\n\n**** Failed to install enum34-1.0.4. stderr:\nusage: setup.py [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]\n   or: setup.py --help [cmd1 cmd2 ...]\n   or: setup.py --help-commands\n   or: setup.py cmd --help\n\nerror: invalid command 'bdist_wheel'\n\npex: Failed to install package at /tmp/tmppcotrf/enum34-1.0.4: Failed to install /tmp/tmppcotrf/enum34-1.0.4\nTraceback (most recent call last):\n  File \"/bin/pex\", line 9, in <module>\n    load_entry_point('pex==1.0.3', 'console_scripts', 'pex')()\n  File \"/usr/lib/python3.3/site-packages/pex/bin/pex.py\", line 509, in main\n    pex_builder = build_pex(reqs, options, resolver_options_builder)\n  File \"/usr/lib/python3.3/site-packages/pex/bin/pex.py\", line 471, in build_pex\n    resolveds = resolver.resolve(resolvables)\n  File \"/usr/lib/python3.3/site-packages/pex/resolver.py\", line 191, in resolve\n    dist = self.build(package, resolvable.options)\n  File \"/usr/lib/python3.3/site-packages/pex/resolver.py\", line 248, in build\n    dist = super(CachingResolver, self).build(package, options)\n  File \"/usr/lib/python3.3/site-packages/pex/resolver.py\", line 160, in build\n    raise Untranslateable('Package %s is not translateable by %s' % (package, translator))\npex.resolver.Untranslateable: Package SourcePackage('file:///home/chris/.pex/build/enum34-1.0.4.zip') is not translateable by ChainedTranslator(WheelTranslator, EggTranslator, SourceTranslator)\n```\n\nIn the above example it failed on `enum34`, but which dependency it fails on appears random as well.\n\n", "before_files": [{"content": "# Copyright 2014 Pants project contributors (see CONTRIBUTORS.md).\n# Licensed under the Apache License, Version 2.0 (see LICENSE).\n\nfrom __future__ import absolute_import, print_function\n\nimport os\nimport sys\nimport tempfile\n\nfrom pkg_resources import Distribution, PathMetadata\n\nfrom .common import safe_mkdtemp, safe_rmtree\nfrom .compatibility import WINDOWS\nfrom .executor import Executor\nfrom .interpreter import PythonInterpreter\nfrom .tracer import TRACER\nfrom .version import SETUPTOOLS_REQUIREMENT, WHEEL_REQUIREMENT\n\n__all__ = (\n  'Installer',\n  'Packager'\n)\n\n\ndef after_installation(function):\n  def function_wrapper(self, *args, **kw):\n    self._installed = self.run()\n    if not self._installed:\n      raise Installer.InstallFailure('Failed to install %s' % self._source_dir)\n    return function(self, *args, **kw)\n  return function_wrapper\n\n\nclass InstallerBase(object):\n  SETUP_BOOTSTRAP_HEADER = \"import sys\"\n  SETUP_BOOTSTRAP_MODULE = \"sys.path.insert(0, %(path)r); import %(module)s\"\n  SETUP_BOOTSTRAP_FOOTER = \"\"\"\n__file__ = 'setup.py'\nsys.argv[0] = 'setup.py'\nexec(compile(open(__file__, 'rb').read(), __file__, 'exec'))\n\"\"\"\n\n  class Error(Exception): pass\n  class InstallFailure(Error): pass\n  class IncapableInterpreter(Error): pass\n\n  def __init__(self, source_dir, strict=True, interpreter=None, install_dir=None):\n    \"\"\"\n      Create an installer from an unpacked source distribution in source_dir.\n\n      If strict=True, fail if any installation dependencies (e.g. distribute)\n      are missing.\n    \"\"\"\n    self._source_dir = source_dir\n    self._install_tmp = install_dir or safe_mkdtemp()\n    self._installed = None\n    self._strict = strict\n    self._interpreter = interpreter or PythonInterpreter.get()\n    if not self._interpreter.satisfies(self.capability) and strict:\n      raise self.IncapableInterpreter('Interpreter %s not capable of running %s' % (\n          self._interpreter.binary, self.__class__.__name__))\n\n  def mixins(self):\n    \"\"\"Return a map from import name to requirement to load into setup script prior to invocation.\n\n       May be subclassed.\n    \"\"\"\n    return {}\n\n  @property\n  def install_tmp(self):\n    return self._install_tmp\n\n  def _setup_command(self):\n    \"\"\"the setup command-line to run, to be implemented by subclasses.\"\"\"\n    raise NotImplementedError\n\n  def _postprocess(self):\n    \"\"\"a post-processing function to run following setup.py invocation.\"\"\"\n\n  @property\n  def capability(self):\n    \"\"\"returns the list of requirements for the interpreter to run this installer.\"\"\"\n    return list(self.mixins().values())\n\n  @property\n  def bootstrap_script(self):\n    bootstrap_modules = []\n    for module, requirement in self.mixins().items():\n      path = self._interpreter.get_location(requirement)\n      if not path:\n        assert not self._strict  # This should be caught by validation\n        continue\n      bootstrap_modules.append(self.SETUP_BOOTSTRAP_MODULE % {'path': path, 'module': module})\n    return '\\n'.join(\n        [self.SETUP_BOOTSTRAP_HEADER] + bootstrap_modules + [self.SETUP_BOOTSTRAP_FOOTER])\n\n  def run(self):\n    if self._installed is not None:\n      return self._installed\n\n    with TRACER.timed('Installing %s' % self._install_tmp, V=2):\n      command = [self._interpreter.binary, '-'] + self._setup_command()\n      try:\n        Executor.execute(command,\n                         env=self._interpreter.sanitized_environment(),\n                         cwd=self._source_dir,\n                         stdin_payload=self.bootstrap_script.encode('ascii'))\n        self._installed = True\n      except Executor.NonZeroExit as e:\n        self._installed = False\n        name = os.path.basename(self._source_dir)\n        print('**** Failed to install %s (caused by: %r\\n):' % (name, e), file=sys.stderr)\n        print('stdout:\\n%s\\nstderr:\\n%s\\n' % (e.stdout, e.stderr), file=sys.stderr)\n        return self._installed\n\n    self._postprocess()\n    return self._installed\n\n  def cleanup(self):\n    safe_rmtree(self._install_tmp)\n\n\nclass Installer(InstallerBase):\n  \"\"\"Install an unpacked distribution with a setup.py.\"\"\"\n\n  def __init__(self, source_dir, strict=True, interpreter=None):\n    \"\"\"\n      Create an installer from an unpacked source distribution in source_dir.\n\n      If strict=True, fail if any installation dependencies (e.g. setuptools)\n      are missing.\n    \"\"\"\n    super(Installer, self).__init__(source_dir, strict=strict, interpreter=interpreter)\n    self._egg_info = None\n    fd, self._install_record = tempfile.mkstemp()\n    os.close(fd)\n\n  def _setup_command(self):\n    return ['install',\n           '--root=%s' % self._install_tmp,\n           '--prefix=',\n           '--single-version-externally-managed',\n           '--record', self._install_record]\n\n  def _postprocess(self):\n    installed_files = []\n    egg_info = None\n    with open(self._install_record) as fp:\n      installed_files = fp.read().splitlines()\n      for line in installed_files:\n        if line.endswith('.egg-info'):\n          assert line.startswith('/'), 'Expect .egg-info to be within install_tmp!'\n          egg_info = line\n          break\n\n    if not egg_info:\n      self._installed = False\n      return self._installed\n\n    installed_files = [os.path.relpath(fn, egg_info) for fn in installed_files if fn != egg_info]\n\n    self._egg_info = os.path.join(self._install_tmp, egg_info[1:])\n    with open(os.path.join(self._egg_info, 'installed-files.txt'), 'w') as fp:\n      fp.write('\\n'.join(installed_files))\n      fp.write('\\n')\n\n    return self._installed\n\n  @after_installation\n  def egg_info(self):\n    return self._egg_info\n\n  @after_installation\n  def root(self):\n    egg_info = self.egg_info()\n    assert egg_info\n    return os.path.realpath(os.path.dirname(egg_info))\n\n  @after_installation\n  def distribution(self):\n    base_dir = self.root()\n    egg_info = self.egg_info()\n    metadata = PathMetadata(base_dir, egg_info)\n    return Distribution.from_location(base_dir, os.path.basename(egg_info), metadata=metadata)\n\n\nclass DistributionPackager(InstallerBase):\n  def mixins(self):\n    mixins = super(DistributionPackager, self).mixins().copy()\n    mixins.update(setuptools=SETUPTOOLS_REQUIREMENT)\n    return mixins\n\n  def find_distribution(self):\n    dists = os.listdir(self.install_tmp)\n    if len(dists) == 0:\n      raise self.InstallFailure('No distributions were produced!')\n    elif len(dists) > 1:\n      raise self.InstallFailure('Ambiguous source distributions found: %s' % (' '.join(dists)))\n    else:\n      return os.path.join(self.install_tmp, dists[0])\n\n\nclass Packager(DistributionPackager):\n  \"\"\"\n    Create a source distribution from an unpacked setup.py-based project.\n  \"\"\"\n\n  def _setup_command(self):\n    if WINDOWS:\n      return ['sdist', '--formats=zip', '--dist-dir=%s' % self._install_tmp]\n    else:\n      return ['sdist', '--formats=gztar', '--dist-dir=%s' % self._install_tmp]\n\n  @after_installation\n  def sdist(self):\n    return self.find_distribution()\n\n\nclass EggInstaller(DistributionPackager):\n  \"\"\"\n    Create a source distribution from an unpacked setup.py-based project.\n  \"\"\"\n\n  def _setup_command(self):\n    return ['bdist_egg', '--dist-dir=%s' % self._install_tmp]\n\n  @after_installation\n  def bdist(self):\n    return self.find_distribution()\n\n\nclass WheelInstaller(DistributionPackager):\n  \"\"\"\n    Create a source distribution from an unpacked setup.py-based project.\n  \"\"\"\n  MIXINS = {\n      'setuptools': SETUPTOOLS_REQUIREMENT,\n      'wheel': WHEEL_REQUIREMENT,\n  }\n\n  def mixins(self):\n    mixins = super(WheelInstaller, self).mixins().copy()\n    mixins.update(self.MIXINS)\n    return mixins\n\n  def _setup_command(self):\n    return ['bdist_wheel', '--dist-dir=%s' % self._install_tmp]\n\n  @after_installation\n  def bdist(self):\n    return self.find_distribution()\n", "path": "pex/installer.py"}], "after_files": [{"content": "# Copyright 2014 Pants project contributors (see CONTRIBUTORS.md).\n# Licensed under the Apache License, Version 2.0 (see LICENSE).\n\nfrom __future__ import absolute_import, print_function\n\nimport os\nimport sys\nimport tempfile\n\nfrom pkg_resources import Distribution, PathMetadata\n\nfrom .common import safe_mkdtemp, safe_rmtree\nfrom .compatibility import WINDOWS\nfrom .executor import Executor\nfrom .interpreter import PythonInterpreter\nfrom .tracer import TRACER\nfrom .version import SETUPTOOLS_REQUIREMENT, WHEEL_REQUIREMENT\n\n__all__ = (\n  'Installer',\n  'Packager'\n)\n\n\ndef after_installation(function):\n  def function_wrapper(self, *args, **kw):\n    self._installed = self.run()\n    if not self._installed:\n      raise Installer.InstallFailure('Failed to install %s' % self._source_dir)\n    return function(self, *args, **kw)\n  return function_wrapper\n\n\nclass InstallerBase(object):\n  SETUP_BOOTSTRAP_HEADER = \"import sys\"\n  SETUP_BOOTSTRAP_PYPATH = \"sys.path.insert(0, %(path)r)\"\n  SETUP_BOOTSTRAP_MODULE = \"import %(module)s\"\n  SETUP_BOOTSTRAP_FOOTER = \"\"\"\n__file__ = 'setup.py'\nsys.argv[0] = 'setup.py'\nexec(compile(open(__file__, 'rb').read(), __file__, 'exec'))\n\"\"\"\n\n  class Error(Exception): pass\n  class InstallFailure(Error): pass\n  class IncapableInterpreter(Error): pass\n\n  def __init__(self, source_dir, strict=True, interpreter=None, install_dir=None):\n    \"\"\"\n      Create an installer from an unpacked source distribution in source_dir.\n\n      If strict=True, fail if any installation dependencies (e.g. distribute)\n      are missing.\n    \"\"\"\n    self._source_dir = source_dir\n    self._install_tmp = install_dir or safe_mkdtemp()\n    self._installed = None\n    self._strict = strict\n    self._interpreter = interpreter or PythonInterpreter.get()\n    if not self._interpreter.satisfies(self.capability) and strict:\n      raise self.IncapableInterpreter('Interpreter %s not capable of running %s' % (\n          self._interpreter.binary, self.__class__.__name__))\n\n  def mixins(self):\n    \"\"\"Return a map from import name to requirement to load into setup script prior to invocation.\n\n       May be subclassed.\n    \"\"\"\n    return {}\n\n  @property\n  def install_tmp(self):\n    return self._install_tmp\n\n  def _setup_command(self):\n    \"\"\"the setup command-line to run, to be implemented by subclasses.\"\"\"\n    raise NotImplementedError\n\n  def _postprocess(self):\n    \"\"\"a post-processing function to run following setup.py invocation.\"\"\"\n\n  @property\n  def capability(self):\n    \"\"\"returns the list of requirements for the interpreter to run this installer.\"\"\"\n    return list(self.mixins().values())\n\n  @property\n  def bootstrap_script(self):\n    bootstrap_sys_paths = []\n    bootstrap_modules = []\n    for module, requirement in self.mixins().items():\n      path = self._interpreter.get_location(requirement)\n      if not path:\n        assert not self._strict  # This should be caught by validation\n        continue\n      bootstrap_sys_paths.append(self.SETUP_BOOTSTRAP_PYPATH % {'path': path})\n      bootstrap_modules.append(self.SETUP_BOOTSTRAP_MODULE % {'module': module})\n    return '\\n'.join(\n      [self.SETUP_BOOTSTRAP_HEADER] +\n      bootstrap_sys_paths +\n      bootstrap_modules +\n      [self.SETUP_BOOTSTRAP_FOOTER]\n    )\n\n  def run(self):\n    if self._installed is not None:\n      return self._installed\n\n    with TRACER.timed('Installing %s' % self._install_tmp, V=2):\n      command = [self._interpreter.binary, '-'] + self._setup_command()\n      try:\n        Executor.execute(command,\n                         env=self._interpreter.sanitized_environment(),\n                         cwd=self._source_dir,\n                         stdin_payload=self.bootstrap_script.encode('ascii'))\n        self._installed = True\n      except Executor.NonZeroExit as e:\n        self._installed = False\n        name = os.path.basename(self._source_dir)\n        print('**** Failed to install %s (caused by: %r\\n):' % (name, e), file=sys.stderr)\n        print('stdout:\\n%s\\nstderr:\\n%s\\n' % (e.stdout, e.stderr), file=sys.stderr)\n        return self._installed\n\n    self._postprocess()\n    return self._installed\n\n  def cleanup(self):\n    safe_rmtree(self._install_tmp)\n\n\nclass Installer(InstallerBase):\n  \"\"\"Install an unpacked distribution with a setup.py.\"\"\"\n\n  def __init__(self, source_dir, strict=True, interpreter=None):\n    \"\"\"\n      Create an installer from an unpacked source distribution in source_dir.\n\n      If strict=True, fail if any installation dependencies (e.g. setuptools)\n      are missing.\n    \"\"\"\n    super(Installer, self).__init__(source_dir, strict=strict, interpreter=interpreter)\n    self._egg_info = None\n    fd, self._install_record = tempfile.mkstemp()\n    os.close(fd)\n\n  def _setup_command(self):\n    return ['install',\n           '--root=%s' % self._install_tmp,\n           '--prefix=',\n           '--single-version-externally-managed',\n           '--record', self._install_record]\n\n  def _postprocess(self):\n    installed_files = []\n    egg_info = None\n    with open(self._install_record) as fp:\n      installed_files = fp.read().splitlines()\n      for line in installed_files:\n        if line.endswith('.egg-info'):\n          assert line.startswith('/'), 'Expect .egg-info to be within install_tmp!'\n          egg_info = line\n          break\n\n    if not egg_info:\n      self._installed = False\n      return self._installed\n\n    installed_files = [os.path.relpath(fn, egg_info) for fn in installed_files if fn != egg_info]\n\n    self._egg_info = os.path.join(self._install_tmp, egg_info[1:])\n    with open(os.path.join(self._egg_info, 'installed-files.txt'), 'w') as fp:\n      fp.write('\\n'.join(installed_files))\n      fp.write('\\n')\n\n    return self._installed\n\n  @after_installation\n  def egg_info(self):\n    return self._egg_info\n\n  @after_installation\n  def root(self):\n    egg_info = self.egg_info()\n    assert egg_info\n    return os.path.realpath(os.path.dirname(egg_info))\n\n  @after_installation\n  def distribution(self):\n    base_dir = self.root()\n    egg_info = self.egg_info()\n    metadata = PathMetadata(base_dir, egg_info)\n    return Distribution.from_location(base_dir, os.path.basename(egg_info), metadata=metadata)\n\n\nclass DistributionPackager(InstallerBase):\n  def mixins(self):\n    mixins = super(DistributionPackager, self).mixins().copy()\n    mixins.update(setuptools=SETUPTOOLS_REQUIREMENT)\n    return mixins\n\n  def find_distribution(self):\n    dists = os.listdir(self.install_tmp)\n    if len(dists) == 0:\n      raise self.InstallFailure('No distributions were produced!')\n    elif len(dists) > 1:\n      raise self.InstallFailure('Ambiguous source distributions found: %s' % (' '.join(dists)))\n    else:\n      return os.path.join(self.install_tmp, dists[0])\n\n\nclass Packager(DistributionPackager):\n  \"\"\"\n    Create a source distribution from an unpacked setup.py-based project.\n  \"\"\"\n\n  def _setup_command(self):\n    if WINDOWS:\n      return ['sdist', '--formats=zip', '--dist-dir=%s' % self._install_tmp]\n    else:\n      return ['sdist', '--formats=gztar', '--dist-dir=%s' % self._install_tmp]\n\n  @after_installation\n  def sdist(self):\n    return self.find_distribution()\n\n\nclass EggInstaller(DistributionPackager):\n  \"\"\"\n    Create a source distribution from an unpacked setup.py-based project.\n  \"\"\"\n\n  def _setup_command(self):\n    return ['bdist_egg', '--dist-dir=%s' % self._install_tmp]\n\n  @after_installation\n  def bdist(self):\n    return self.find_distribution()\n\n\nclass WheelInstaller(DistributionPackager):\n  \"\"\"\n    Create a source distribution from an unpacked setup.py-based project.\n  \"\"\"\n  MIXINS = {\n      'setuptools': SETUPTOOLS_REQUIREMENT,\n      'wheel': WHEEL_REQUIREMENT,\n  }\n\n  def mixins(self):\n    mixins = super(WheelInstaller, self).mixins().copy()\n    mixins.update(self.MIXINS)\n    return mixins\n\n  def _setup_command(self):\n    return ['bdist_wheel', '--dist-dir=%s' % self._install_tmp]\n\n  @after_installation\n  def bdist(self):\n    return self.find_distribution()\n", "path": "pex/installer.py"}]}