Skip to content

Commit

Permalink
PythonToolPrepBase now sets up its interpreter. (#6928)
Browse files Browse the repository at this point in the history
Previously it was relying on the good graces of the underlying
interpreter running Pants in combination with the demands of resolving
the particular requirements needed by the tool in question.

Simplify the code by eliminating `_create_requirements` target injection
and just passing PythonRequirements directly to PexBuilderWrapper.

Prep work for #6927
  • Loading branch information
jsirois authored Dec 14, 2018
1 parent 2876264 commit 78a5269
Showing 1 changed file with 24 additions and 49 deletions.
73 changes: 24 additions & 49 deletions src/python/pants/backend/python/tasks/python_tool_prep_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,15 @@

import os

from pex.interpreter import PythonInterpreter
from pex.pex import PEX
from pex.pex_builder import PEXBuilder

from pants.backend.python.interpreter_cache import PythonInterpreterCache
from pants.backend.python.python_requirement import PythonRequirement
from pants.backend.python.subsystems.pex_build_util import PexBuilderWrapper
from pants.backend.python.targets.python_requirement_library import PythonRequirementLibrary
from pants.base.build_environment import get_buildroot
from pants.base.exceptions import TaskError
from pants.base.workunit import WorkUnitLabel
from pants.build_graph.address import Address
from pants.task.task import Task
from pants.util.dirutil import fast_relpath, safe_concurrent_creation
from pants.util.dirutil import safe_concurrent_creation


class PythonToolInstance(object):
Expand Down Expand Up @@ -54,58 +50,37 @@ def subsystem_dependencies(cls):
return super(PythonToolPrepBase, cls).subsystem_dependencies() + (
cls.tool_subsystem_cls.scoped(cls),
PexBuilderWrapper.Factory,
PythonInterpreterCache,
)

@classmethod
def product_types(cls):
return [cls.tool_instance_cls]

@property
def create_target_dirs(self):
return True

def _tool_subsystem(self):
return self.tool_subsystem_cls.scoped_instance(self)

def _create_requirements(self, context, workdir):
tool_subsystem = self._tool_subsystem()
address = Address(spec_path=fast_relpath(workdir, get_buildroot()),
target_name=tool_subsystem.options_scope)
context.build_graph.inject_synthetic_target(
address=address,
target_type=PythonRequirementLibrary,
requirements=[PythonRequirement(r) for r in tool_subsystem.get_requirement_specs()]
)
return context.build_graph.get_target(address=address)

def _build_tool_pex(self, context, interpreter, pex_path, requirements_lib):
def _build_tool_pex(self, tool_subsystem, interpreter, pex_path):
with safe_concurrent_creation(pex_path) as chroot:
pex_builder = PexBuilderWrapper.Factory.create(
builder=PEXBuilder(path=chroot, interpreter=interpreter),
log=context.log)
pex_builder.add_requirement_libs_from(req_libs=[requirements_lib])
pex_builder.set_entry_point(self._tool_subsystem().get_entry_point())
log=self.context.log)
reqs = [PythonRequirement(r) for r in tool_subsystem.get_requirement_specs()]
pex_builder.add_resolved_requirements(reqs=reqs)
pex_builder.set_entry_point(tool_subsystem.get_entry_point())
pex_builder.freeze()

def execute(self):
tool_req_lib = self._create_requirements(self.context, self.workdir)

with self.invalidated(targets=[tool_req_lib]) as invalidation_check:
pex_name = self._tool_subsystem().options_scope
interpreter = PythonInterpreter.get()
if len(invalidation_check.all_vts) != 1:
raise TaskError('Expected exactly one versioned target found {}: {}'.format(
len(invalidation_check.all_vts), invalidation_check.all_vts))
vt = invalidation_check.all_vts[0]
pex_path = os.path.join(vt.results_dir, '{}.pex'.format(pex_name))

if invalidation_check.invalid_vts:
with self.context.new_workunit(name='create-{}-pex'.format(pex_name),
labels=[WorkUnitLabel.PREP]):
self._build_tool_pex(context=self.context,
interpreter=interpreter,
pex_path=pex_path,
requirements_lib=tool_req_lib)

tool_instance = self.tool_instance_cls(pex_path, interpreter)
self.context.products.register_data(self.tool_instance_cls, tool_instance)
tool_subsystem = self.tool_subsystem_cls.scoped_instance(self)
pex_name = tool_subsystem.options_scope
pex_path = os.path.join(self.workdir, self.fingerprint, '{}.pex'.format(pex_name))

interpreter_cache = PythonInterpreterCache.global_instance()
interpreter = interpreter_cache.select_interpreter_for_targets([])

if not os.path.exists(pex_path):
with self.context.new_workunit(name='create-{}-pex'.format(pex_name),
labels=[WorkUnitLabel.PREP]):
self._build_tool_pex(tool_subsystem=tool_subsystem,
interpreter=interpreter,
pex_path=pex_path)

tool_instance = self.tool_instance_cls(pex_path, interpreter)
self.context.products.register_data(self.tool_instance_cls, tool_instance)

0 comments on commit 78a5269

Please sign in to comment.