Repository: pantsbuild/pants

Issue:
Pex cannot resolve pants libraries for OSX
[ci.txt](https://github.com/pantsbuild/pants/files/2535807/ci.txt)

In version 1.11.0rc0, we are getting
```
Failed to execute PEX file, missing macosx_10_13_x86_64-cp-27-cp27m compatible dependencies for:
                     future
                     pantsbuild.pants.contrib.python.checks.checker
                     six
                     pycodestyle
                     pyflakes
```

for pythonstyle task. I've attached a verbosity 9 log.


Discussion:

Resolving patch:
diff --git a/contrib/python/src/python/pants/contrib/python/checks/tasks/checkstyle/checkstyle.py b/contrib/python/src/python/pants/contrib/python/checks/tasks/checkstyle/checkstyle.py
--- a/contrib/python/src/python/pants/contrib/python/checks/tasks/checkstyle/checkstyle.py
+++ b/contrib/python/src/python/pants/contrib/python/checks/tasks/checkstyle/checkstyle.py
@@ -30,7 +30,8 @@
 from pants.util.memo import memoized_classproperty, memoized_property
 from pex.pex import PEX
 from pex.pex_builder import PEXBuilder
-from pkg_resources import DistributionNotFound, Requirement, WorkingSet
+from pex.platforms import Platform
+from pkg_resources import DistributionNotFound, Environment, Requirement, WorkingSet
 
 from pants.contrib.python.checks.checker import checker
 from pants.contrib.python.checks.tasks.checkstyle.plugin_subsystem_base import \
@@ -140,12 +141,19 @@ def checker_pex(self, interpreter):
           else:
             try:
               # The checker is already on sys.path, eg: embedded in pants.pex.
+              platform = Platform.current()
+              platform_name = platform.platform
+              env = Environment(search_path=sys.path,
+                                platform=platform_name,
+                                python=interpreter.version_string)
               working_set = WorkingSet(entries=sys.path)
-              for dist in working_set.resolve([Requirement.parse(self._CHECKER_REQ)]):
+              for dist in working_set.resolve([Requirement.parse(self._CHECKER_REQ)], env=env):
                 pex_builder.add_direct_requirements(dist.requires())
-                pex_builder.add_distribution(dist)
+                # NB: We add the dist location instead of the dist itself to make sure its a
+                # distribution style pex knows how to package.
+                pex_builder.add_dist_location(dist.location)
               pex_builder.add_direct_requirements([self._CHECKER_REQ])
-            except DistributionNotFound:
+            except (DistributionNotFound, PEXBuilder.InvalidDistribution):
               # We need to resolve the checker from a local or remote distribution repo.
               pex_builder.add_resolved_requirements(
                 [PythonRequirement(self._CHECKER_REQ)])
diff --git a/src/python/pants/backend/python/tasks/pex_build_util.py b/src/python/pants/backend/python/tasks/pex_build_util.py
--- a/src/python/pants/backend/python/tasks/pex_build_util.py
+++ b/src/python/pants/backend/python/tasks/pex_build_util.py
@@ -290,5 +290,8 @@ def add_direct_requirements(self, reqs):
   def add_distribution(self, dist):
     self._builder.add_distribution(dist)
 
+  def add_dist_location(self, location):
+    self._builder.add_dist_location(location)
+
   def set_script(self, script):
     self._builder.set_script(script)


Test patch:
diff --git a/contrib/python/tests/python/pants_test/contrib/python/checks/tasks/checkstyle/BUILD b/contrib/python/tests/python/pants_test/contrib/python/checks/tasks/checkstyle/BUILD
--- a/contrib/python/tests/python/pants_test/contrib/python/checks/tasks/checkstyle/BUILD
+++ b/contrib/python/tests/python/pants_test/contrib/python/checks/tasks/checkstyle/BUILD
@@ -5,6 +5,7 @@ python_tests(
   dependencies=[
     '3rdparty/python:future',
     '3rdparty/python:parameterized',
+    '3rdparty/python:pex',
     '3rdparty/python:wheel',
     'contrib/python/src/python/pants/contrib/python/checks/tasks/checkstyle',
     'src/python/pants/backend/python/subsystems',
diff --git a/contrib/python/tests/python/pants_test/contrib/python/checks/tasks/checkstyle/test_checkstyle.py b/contrib/python/tests/python/pants_test/contrib/python/checks/tasks/checkstyle/test_checkstyle.py
--- a/contrib/python/tests/python/pants_test/contrib/python/checks/tasks/checkstyle/test_checkstyle.py
+++ b/contrib/python/tests/python/pants_test/contrib/python/checks/tasks/checkstyle/test_checkstyle.py
@@ -20,6 +20,7 @@
 from pants.util.process_handler import subprocess
 from pants_test.backend.python.tasks.python_task_test_base import PythonTaskTestBase
 from parameterized import parameterized
+from pex.interpreter import PythonInterpreter
 from wheel.install import WheelFile
 
 from pants.contrib.python.checks.tasks.checkstyle.checkstyle import Checkstyle
@@ -49,7 +50,8 @@ def build_checker_wheel(root_dir):
   @staticmethod
   def install_wheel(wheel, root_dir):
     importable_path = os.path.join(root_dir, 'install', os.path.basename(wheel))
-    overrides = {path: root_dir for path in ('purelib', 'platlib', 'headers', 'scripts', 'data')}
+    overrides = {path: importable_path
+                 for path in ('purelib', 'platlib', 'headers', 'scripts', 'data')}
     WheelFile(wheel).install(force=True, overrides=overrides)
     return importable_path
 
@@ -75,6 +77,13 @@ def task_type(cls):
   @contextmanager
   def resolve_configuration(self, resolve_local=False):
     if resolve_local:
+      # Ensure our checkstyle task runs under the same interpreter we are running under so that
+      # local resolves find dists compatible with the current interpreter.
+      current_interpreter = PythonInterpreter.get()
+      constraint = '{}=={}'.format(current_interpreter.identity.interpreter,
+                                   current_interpreter.identity.version_str)
+      self.set_options_for_scope(PythonSetup.options_scope, interpreter_constraints=[constraint])
+
       prior = sys.path[:]
       sys.path.append(self._checker_dist_importable_path)
       try: