Example #1
0
def seed_cache(
        options,  # type: Namespace
        pex,  # type: PEX
):
    # type: (...) -> Iterable[str]
    pex_path = pex.path()
    with TRACER.timed("Seeding local caches for {}".format(pex_path)):
        if options.unzip:
            unzip_dir = pex.pex_info().unzip_dir
            if unzip_dir is None:
                raise AssertionError(
                    "Expected PEX-INFO for {} to have the components of an unzip directory"
                    .format(pex_path))
            with atomic_directory(unzip_dir, exclusive=True) as chroot:
                if chroot:
                    with TRACER.timed("Extracting {}".format(pex_path)):
                        with open_zip(options.pex_name) as pex_zip:
                            pex_zip.extractall(chroot)
            return [pex.interpreter.binary, unzip_dir]
        elif options.venv:
            with TRACER.timed("Creating venv from {}".format(pex_path)):
                venv_pex = ensure_venv(pex)
                return [venv_pex]
        else:
            with TRACER.timed(
                    "Extracting code and distributions for {}".format(
                        pex_path)):
                pex.activate()
            return [os.path.abspath(options.pex_name)]
Example #2
0
    def add_distribution(self, dist, dist_name=None):
        """Add a :class:`pkg_resources.Distribution` from its handle.

        :param dist: The distribution to add to this environment.
        :keyword dist_name: (optional) The name of the distribution e.g. 'Flask-0.10.0'.  By default
          this will be inferred from the distribution itself should it be formatted in a standard way.
        :type dist: :class:`pkg_resources.Distribution`
        """
        if dist.location in self._distributions:
            TRACER.log("Skipping adding {} - already added from {}".format(
                dist, dist.location),
                       V=9)
            return
        self._ensure_unfrozen("Adding a distribution")
        dist_name = dist_name or os.path.basename(dist.location)
        self._distributions[dist.location] = dist

        if os.path.isdir(dist.location):
            dist_hash = self._add_dist_dir(dist.location, dist_name)
        elif dist.location.endswith(".whl"):
            dist_hash = self._add_dist_wheel_file(dist.location, dist_name)
        else:
            raise self.InvalidDistribution(
                "Unsupported distribution type: {}, pex can only accept dist "
                "dirs and wheels.".format(dist))

        # add dependency key so that it can rapidly be retrieved from cache
        self._pex_info.add_distribution(dist_name, dist_hash)
Example #3
0
File: pex.py Project: jsirois/pex
  def demote_bootstrap(cls):
    TRACER.log('Bootstrap complete, performing final sys.path modifications...')

    should_log = {level: TRACER.should_log(V=level) for level in range(1, 10)}

    def log(msg, V=1):
      if should_log.get(V, False):
        print('pex: {}'.format(msg), file=sys.stderr)

    # Remove the third party resources pex uses and demote pex bootstrap code to the end of
    # sys.path for the duration of the run to allow conflicting versions supplied by user
    # dependencies to win during the course of the execution of user code.
    unregister_finders()
    third_party.uninstall()

    bootstrap = Bootstrap.locate()
    log('Demoting code from %s' % bootstrap, V=2)
    for module in bootstrap.demote():
      log('un-imported {}'.format(module), V=9)

    import pex
    log('Re-imported pex from {}'.format(pex.__path__), V=3)

    log('PYTHONPATH contains:')
    for element in sys.path:
      log('  %c %s' % (' ' if os.path.exists(element) else '*', element))
    log('  * - paths that do not exist or will be imported via zipimport')
Example #4
0
    def create(
        cls,
        venv_dir,  # type: str
        interpreter=None,  # type: Optional[PythonInterpreter]
        force=False,  # type: bool
    ):
        # type: (...) -> Virtualenv
        venv_dir = os.path.abspath(venv_dir)
        safe_mkdir(venv_dir, clean=force)

        interpreter = interpreter or PythonInterpreter.get()
        if interpreter.is_venv:
            base_interpreter = interpreter.resolve_base_interpreter()
            TRACER.log(
                "Ignoring enclosing venv {} and using its base interpreter {} to create venv at {}"
                " instead.".format(interpreter.prefix, base_interpreter.binary, venv_dir),
                V=3,
            )
            interpreter = base_interpreter

        if interpreter.version[0] >= 3 and not interpreter.identity.interpreter == "PyPy":
            # N.B.: PyPy3 comes equipped with a venv module but it does not seem to work.
            interpreter.execute(args=["-m", "venv", "--without-pip", venv_dir])
        else:
            virtualenv_py = resource_string(__name__, "virtualenv_16.7.10_py")
            with named_temporary_file(mode="wb") as fp:
                fp.write(virtualenv_py)
                fp.close()
                interpreter.execute(
                    args=[fp.name, "--no-pip", "--no-setuptools", "--no-wheel", venv_dir],
                )
        return cls(venv_dir)
Example #5
0
    def _extras_paths(cls):
        # type: () -> Iterator[str]
        standard_lib = sysconfig.get_python_lib(standard_lib=True)

        try:
            makefile = sysconfig.parse_makefile(  # type: ignore[attr-defined]
                sysconfig.get_makefile_filename()
            )
        except (AttributeError, IOError):
            # This is not available by default in PyPy's distutils.sysconfig or it simply is
            # no longer available on the system (IOError ENOENT)
            makefile = {}

        extras_paths = filter(
            None, makefile.get("EXTRASPATH", "").split(":")
        )  # type: Iterable[str]
        for path in extras_paths:
            yield os.path.join(standard_lib, path)

        # Handle .pth injected paths as extras.
        sitedirs = cls._get_site_packages()
        for pth_path in cls._scan_pth_files(sitedirs):
            TRACER.log("Found .pth file: %s" % pth_path, V=3)
            for extras_path in iter_pth_paths(pth_path):
                yield extras_path
Example #6
0
File: pex.py Project: jsirois/pex
  def _wrap_coverage(self, runner, *args):
    if not self._vars.PEX_COVERAGE and self._vars.PEX_COVERAGE_FILENAME is None:
      return runner(*args)

    try:
      import coverage
    except ImportError:
      die('Could not bootstrap coverage module, aborting.')

    pex_coverage_filename = self._vars.PEX_COVERAGE_FILENAME
    if pex_coverage_filename is not None:
      cov = coverage.coverage(data_file=pex_coverage_filename)
    else:
      cov = coverage.coverage(data_suffix=True)

    TRACER.log('Starting coverage.')
    cov.start()

    try:
      return runner(*args)
    finally:
      TRACER.log('Stopping coverage')
      cov.stop()

      # TODO(wickman) Post-process coverage to elide $PEX_ROOT and make
      # the report more useful/less noisy.  #89
      if pex_coverage_filename:
        cov.save()
      else:
        cov.report(show_missing=False, ignore_errors=True, file=sys.stdout)
Example #7
0
def iter_pth_paths(filename):
    """Given a .pth file, extract and yield all inner paths without honoring imports.

    This shadows Python's site.py behavior, which is invoked at interpreter startup.
    """
    try:
        f = open(filename, "rU" if PY2 else "r")  # noqa
    except IOError:
        return

    dirname = os.path.dirname(filename)
    known_paths = set()

    with f:
        for i, line in enumerate(f, start=1):
            line = line.rstrip()
            if not line or line.startswith("#"):
                continue
            elif line.startswith(("import ", "import\t")):
                # One important side effect of executing import lines can be alteration of the
                # sys.path directly or indirectly as a programmatic way to add sys.path entries
                # in contrast to the standard .pth mechanism of including fixed paths as
                # individual lines in the file. Here we capture all such programmatic attempts
                # to expand the sys.path and report the additions.
                original_sys_path = sys.path[:]
                try:
                    # N.B.: Setting sys.path to empty is ok since all the .pth files we find and
                    # execute have already been found and executed by our ambient sys.executable
                    # when it started up before running this PEX file. As such, all symbols imported
                    # by the .pth files then will still be available now as cached in sys.modules.
                    sys.path = []
                    exec_function(line, globals_map={})
                    for path in sys.path:
                        yield path
                except Exception as e:
                    # NB: import lines are routinely abused with extra code appended using `;` so
                    # the class of exceptions that might be raised in broader than ImportError. As
                    # such we catch broadly here.
                    TRACER.log(
                        "Error executing line {linenumber} of {pth_file} with content:\n"
                        "{content}\n"
                        "Error was:\n"
                        "{error}".format(linenumber=i,
                                         pth_file=filename,
                                         content=line,
                                         error=e),
                        V=9,
                    )

                    # Defer error handling to the higher level site.py logic invoked at startup.
                    return
                finally:
                    sys.path = original_sys_path
            else:
                extras_dir, extras_dir_case_insensitive = makepath(
                    dirname, line)
                if extras_dir_case_insensitive not in known_paths and os.path.exists(
                        extras_dir):
                    yield extras_dir
                    known_paths.add(extras_dir_case_insensitive)
Example #8
0
    def patch_sys(self):
        # type: () -> None
        """Patch sys with all site scrubbed."""
        inherit_path = self._vars.PEX_INHERIT_PATH
        if inherit_path == InheritPath.FALSE:
            inherit_path = self._pex_info.inherit_path

        def patch_dict(old_value, new_value):
            # type: (Dict[_K, _V], Mapping[_K, _V]) -> None
            old_value.clear()
            old_value.update(new_value)

        def patch_all(path, path_importer_cache, modules):
            # type: (List[str], Mapping[str, Any], Mapping[str, ModuleType]) -> None
            sys.path[:] = path
            patch_dict(sys.path_importer_cache, path_importer_cache)
            patch_dict(sys.modules, modules)

        new_sys_path, new_sys_path_importer_cache, new_sys_modules = self.minimum_sys(inherit_path)

        if self._vars.PEX_EXTRA_SYS_PATH:
            TRACER.log("Adding %s to sys.path" % self._vars.PEX_EXTRA_SYS_PATH)
            new_sys_path.extend(self._vars.PEX_EXTRA_SYS_PATH.split(":"))
        TRACER.log("New sys.path: %s" % new_sys_path)

        patch_all(new_sys_path, new_sys_path_importer_cache, new_sys_modules)
Example #9
0
    def _execute(self):
        # type: () -> Any
        force_interpreter = self._vars.PEX_INTERPRETER

        self._clean_environment(strip_pex_env=self._pex_info.strip_pex_env)

        if force_interpreter:
            TRACER.log("PEX_INTERPRETER specified, dropping into interpreter")
            return self.execute_interpreter()

        if self._pex_info_overrides.script and self._pex_info_overrides.entry_point:
            return "Cannot specify both script and entry_point for a PEX!"

        if self._pex_info.script and self._pex_info.entry_point:
            return "Cannot specify both script and entry_point for a PEX!"

        if self._pex_info_overrides.script:
            return self.execute_script(self._pex_info_overrides.script)
        elif self._pex_info_overrides.entry_point:
            return self.execute_entry(self._pex_info_overrides.entry_point)
        elif self._pex_info.script:
            return self.execute_script(self._pex_info.script)
        elif self._pex_info.entry_point:
            return self.execute_entry(self._pex_info.entry_point)
        else:
            TRACER.log("No entry point specified, dropping into interpreter")
            return self.execute_interpreter()
Example #10
0
    def __init__(
        self,
        pex,  # type: str
        pex_info=None,  # type: Optional[PexInfo]
        interpreter=None,  # type: Optional[PythonInterpreter]
    ):
        # type: (...) -> None
        self._pex = pex
        self._pex_info = pex_info or PexInfo.from_pex(pex)
        self._internal_cache = os.path.join(self._pex, self._pex_info.internal_cache)
        self._activated = False
        self._working_set = None
        self._interpreter = interpreter or PythonInterpreter.get()
        self._inherit_path = self._pex_info.inherit_path
        self._supported_tags = frozenset(self._interpreter.identity.supported_tags)
        self._target_interpreter_env = self._interpreter.identity.env_markers

        # For the bug this works around, see: https://bitbucket.org/pypy/pypy/issues/1686
        # NB: This must be installed early before the underlying pex is loaded in any way.
        if self._interpreter.identity.python_tag.startswith("pp") and zipfile.is_zipfile(self._pex):
            self._install_pypy_zipimporter_workaround(self._pex)

        super(PEXEnvironment, self).__init__(
            search_path=[] if self._pex_info.inherit_path == InheritPath.FALSE else sys.path,
            platform=self._interpreter.identity.platform_tag,
        )
        TRACER.log(
            "E: tags for %r x %r -> %s" % (self.platform, self._interpreter, self._supported_tags),
            V=9,
        )
Example #11
0
    def __init__(self, pex, pex_info, interpreter=None, **kw):
        self._internal_cache = os.path.join(pex, pex_info.internal_cache)
        self._pex = pex
        self._pex_info = pex_info
        self._activated = False
        self._working_set = None
        self._interpreter = interpreter or PythonInterpreter.get()
        self._inherit_path = pex_info.inherit_path
        self._supported_tags = frozenset(
            self._interpreter.identity.supported_tags)
        self._target_interpreter_env = self._interpreter.identity.env_markers

        # For the bug this works around, see: https://bitbucket.org/pypy/pypy/issues/1686
        # NB: This must be installed early before the underlying pex is loaded in any way.
        if self._interpreter.identity.python_tag.startswith(
                'pp') and zipfile.is_zipfile(self._pex):
            self._install_pypy_zipimporter_workaround(self._pex)

        super(PEXEnvironment, self).__init__(
            search_path=[] if pex_info.inherit_path == 'false' else sys.path,
            platform=self._interpreter.identity.platform_tag,
            **kw)
        TRACER.log('E: tags for %r x %r -> %s' %
                   (self.platform, self._interpreter, self._supported_tags),
                   V=9)
Example #12
0
    def run(self, args=(), with_chroot=False, blocking=True, setsid=False, env=None, **kwargs):
        """Run the PythonEnvironment in an interpreter in a subprocess.

        :keyword args: Additional arguments to be passed to the application being invoked by the
          environment.
        :keyword with_chroot: Run with cwd set to the environment's working directory.
        :keyword blocking: If true, return the return code of the subprocess.
          If false, return the Popen object of the invoked subprocess.
        :keyword setsid: If true, run the PEX in a separate operating system session.
        :keyword env: An optional environment dict to use as the PEX subprocess environment. If none is
                      passed, the ambient environment is inherited.
        Remaining keyword arguments are passed directly to subprocess.Popen.
        """
        if env is not None:
            # If explicit env vars are passed, we don't want clean any of these.
            env = env.copy()
        else:
            env = os.environ.copy()
            self._clean_environment(env=env)

        cmdline = self.cmdline(args)
        TRACER.log("PEX.run invoking %s" % " ".join(cmdline))
        process = Executor.open_process(
            cmdline,
            cwd=self._pex if with_chroot else os.getcwd(),
            preexec_fn=os.setsid if setsid else None,
            stdin=kwargs.pop("stdin", None),
            stdout=kwargs.pop("stdout", None),
            stderr=kwargs.pop("stderr", None),
            env=env,
            **kwargs
        )
        return process.wait() if blocking else process
Example #13
0
  def set_script(self, script):
    """Set the entry point of this PEX environment based upon a distribution script.

    :param script: The script name as defined either by a console script or ordinary
      script within the setup.py of one of the distributions added to the PEX.
    :raises: :class:`PEXBuilder.InvalidExecutableSpecification` if the script is not found
      in any distribution added to the PEX.
    """

    # check if 'script' is a console_script
    dist, entry_point = get_entry_point_from_console_script(script, self._distributions)
    if entry_point:
      self.set_entry_point(entry_point)
      TRACER.log('Set entrypoint to console_script %r in %r' % (entry_point, dist))
      return

    # check if 'script' is an ordinary script
    dist, _, _ = get_script_from_distributions(script, self._distributions)
    if dist:
      if self._pex_info.entry_point:
        raise self.InvalidExecutableSpecification('Cannot set both entry point and script of PEX!')
      self._pex_info.script = script
      TRACER.log('Set entrypoint to script %r in %r' % (script, dist))
      return

    raise self.InvalidExecutableSpecification(
        'Could not find script %r in any distribution %s within PEX!' % (
            script, ', '.join(str(d) for d in self._distributions)))
Example #14
0
 def __init__(self, *args, **kw):
     TRACER.log(
         'Warning, using a UrllibContext which is known to be flaky.')
     TRACER.log(
         'Please build pex with the requests module for more reliable downloads.'
     )
     super(UrllibContext, self).__init__(*args, **kw)
Example #15
0
    def run(self,
            args=(),
            with_chroot=False,
            blocking=True,
            setsid=False,
            **kwargs):
        """Run the PythonEnvironment in an interpreter in a subprocess.

    :keyword args: Additional arguments to be passed to the application being invoked by the
      environment.
    :keyword with_chroot: Run with cwd set to the environment's working directory.
    :keyword blocking: If true, return the return code of the subprocess.
      If false, return the Popen object of the invoked subprocess.
    :keyword setsid: If true, run the PEX in a separate operating system session.

    Remaining keyword arguments are passed directly to subprocess.Popen.
    """
        self.clean_environment()

        cmdline = self.cmdline(args)
        TRACER.log('PEX.run invoking %s' % ' '.join(cmdline))
        process = Executor.open_process(
            cmdline,
            cwd=self._pex if with_chroot else os.getcwd(),
            preexec_fn=os.setsid if setsid else None,
            stdin=kwargs.pop('stdin', None),
            stdout=kwargs.pop('stdout', None),
            stderr=kwargs.pop('stderr', None),
            **kwargs)
        return process.wait() if blocking else process
Example #16
0
    def _execute(self):
        force_interpreter = self._vars.PEX_INTERPRETER

        self.clean_environment()

        if force_interpreter:
            TRACER.log('PEX_INTERPRETER specified, dropping into interpreter')
            return self.execute_interpreter()

        if self._pex_info_overrides.script and self._pex_info_overrides.entry_point:
            die('Cannot specify both script and entry_point for a PEX!')

        if self._pex_info.script and self._pex_info.entry_point:
            die('Cannot specify both script and entry_point for a PEX!')

        if self._pex_info_overrides.script:
            return self.execute_script(self._pex_info_overrides.script)
        elif self._pex_info_overrides.entry_point:
            return self.execute_entry(self._pex_info_overrides.entry_point)
        elif self._pex_info.script:
            return self.execute_script(self._pex_info.script)
        elif self._pex_info.entry_point:
            return self.execute_entry(self._pex_info.entry_point)
        else:
            TRACER.log('No entry point specified, dropping into interpreter')
            return self.execute_interpreter()
Example #17
0
    def set_script(self, script):
        """Set the entry point of this PEX environment based upon a distribution script.

        :param script: The script name as defined either by a console script or ordinary
          script within the setup.py of one of the distributions added to the PEX.
        :raises: :class:`PEXBuilder.InvalidExecutableSpecification` if the script is not found
          in any distribution added to the PEX.
        """

        # check if 'script' is a console_script
        dist, entry_point = get_entry_point_from_console_script(
            script, self._distributions.values())
        if entry_point:
            self.set_entry_point(entry_point)
            TRACER.log("Set entrypoint to console_script %r in %r" %
                       (entry_point, dist))
            return

        # check if 'script' is an ordinary script
        dist_script = get_script_from_distributions(
            script, self._distributions.values())
        if dist_script:
            if self._pex_info.entry_point:
                raise self.InvalidExecutableSpecification(
                    "Cannot set both entry point and script of PEX!")
            self._pex_info.script = script
            TRACER.log("Set entrypoint to script %r in %r" %
                       (script, dist_script.dist))
            return

        raise self.InvalidExecutableSpecification(
            "Could not find script %r in any distribution %s within PEX!" %
            (script, ", ".join(str(d) for d in self._distributions.values())))
Example #18
0
File: pex.py Project: jsirois/pex
  def _execute(self):
    force_interpreter = self._vars.PEX_INTERPRETER

    self.clean_environment()

    if force_interpreter:
      TRACER.log('PEX_INTERPRETER specified, dropping into interpreter')
      return self.execute_interpreter()

    if self._pex_info_overrides.script and self._pex_info_overrides.entry_point:
      die('Cannot specify both script and entry_point for a PEX!')

    if self._pex_info.script and self._pex_info.entry_point:
      die('Cannot specify both script and entry_point for a PEX!')

    if self._pex_info_overrides.script:
      return self.execute_script(self._pex_info_overrides.script)
    elif self._pex_info_overrides.entry_point:
      return self.execute_entry(self._pex_info_overrides.entry_point)
    elif self._pex_info.script:
      return self.execute_script(self._pex_info.script)
    elif self._pex_info.entry_point:
      return self.execute_entry(self._pex_info.entry_point)
    else:
      TRACER.log('No entry point specified, dropping into interpreter')
      return self.execute_interpreter()
Example #19
0
    def demote_bootstrap(cls):
        TRACER.log(
            'Bootstrap complete, performing final sys.path modifications...')

        should_log = {
            level: TRACER.should_log(V=level)
            for level in range(1, 10)
        }

        def log(msg, V=1):
            if should_log.get(V, False):
                print('pex: {}'.format(msg), file=sys.stderr)

        # Remove the third party resources pex uses and demote pex bootstrap code to the end of
        # sys.path for the duration of the run to allow conflicting versions supplied by user
        # dependencies to win during the course of the execution of user code.
        third_party.uninstall()

        bootstrap = Bootstrap.locate()
        log('Demoting code from %s' % bootstrap, V=2)
        for module in bootstrap.demote():
            log('un-imported {}'.format(module), V=9)

        import pex
        log('Re-imported pex from {}'.format(pex.__path__), V=3)

        log('PYTHONPATH contains:')
        for element in sys.path:
            log('  %c %s' % (' ' if os.path.exists(element) else '*', element))
        log('  * - paths that do not exist or will be imported via zipimport')
Example #20
0
def matched_interpreters_iter(interpreters_iter, constraints):
  """Given some filters, yield any interpreter that matches at least one of them.

  :param interpreters_iter: A `PythonInterpreter` iterable for filtering.
  :param constraints: A sequence of strings that constrain the interpreter compatibility for this
    pex. Each string uses the Requirement-style format, e.g. 'CPython>=3' or '>=2.7,<3' for
    requirements agnostic to interpreter class. Multiple requirement strings may be combined
    into a list to OR the constraints, such as ['CPython>=2.7,<3', 'CPython>=3.4'].
  :return: returns a generator that yields compatible interpreters
  :raises: :class:`UnsatisfiableInterpreterConstraintsError` if constraints were given and could
           not be satisfied. The exception will only be raised when the returned generator is fully
           consumed.
  """
  candidates = []
  found = False

  for interpreter in interpreters_iter:
    if any(interpreter.identity.matches(filt) for filt in constraints):
      TRACER.log("Constraints on interpreters: %s, Matching Interpreter: %s"
                 % (constraints, interpreter.binary), V=3)
      found = True
      yield interpreter

    if not found:
      candidates.append(interpreter)

  if not found:
    raise UnsatisfiableInterpreterConstraintsError(constraints, candidates)
Example #21
0
    def _execute(self):
        force_interpreter = self._vars.PEX_INTERPRETER

        # N.B.: This is set in `__main__.py` of the executed PEX by `PEXBuilder` when we've been
        # executed from within a PEX zip file in `--unzip` mode.  We replace `sys.argv[0]` to avoid
        # confusion and allow the user code we hand off to to provide useful messages and fully valid
        # re-execs that always re-directed through the PEX file.
        sys.argv[0] = os.environ.pop('__PEX_EXE__', sys.argv[0])

        self._clean_environment(strip_pex_env=self._pex_info.strip_pex_env)

        if force_interpreter:
            TRACER.log('PEX_INTERPRETER specified, dropping into interpreter')
            return self.execute_interpreter()

        if self._pex_info_overrides.script and self._pex_info_overrides.entry_point:
            die('Cannot specify both script and entry_point for a PEX!')

        if self._pex_info.script and self._pex_info.entry_point:
            die('Cannot specify both script and entry_point for a PEX!')

        if self._pex_info_overrides.script:
            return self.execute_script(self._pex_info_overrides.script)
        elif self._pex_info_overrides.entry_point:
            return self.execute_entry(self._pex_info_overrides.entry_point)
        elif self._pex_info.script:
            return self.execute_script(self._pex_info.script)
        elif self._pex_info.entry_point:
            return self.execute_entry(self._pex_info.entry_point)
        else:
            TRACER.log('No entry point specified, dropping into interpreter')
            return self.execute_interpreter()
Example #22
0
File: pex.py Project: Houzz/pex
def _resolve_and_link_interpreter(requirement, fetchers, target_link, installer_provider):
  # Short-circuit if there is a local copy
  if os.path.exists(target_link) and os.path.exists(os.path.realpath(target_link)):
    egg = EggPackage(os.path.realpath(target_link))
    if egg.satisfies(requirement):
      return egg

  context = Context.get()
  iterator = Iterator(fetchers=fetchers, crawler=Crawler(context))
  links = [link for link in iterator.iter(requirement) if isinstance(link, SourcePackage)]

  with TRACER.timed('Interpreter cache resolving %s' % requirement, V=2):
    for link in links:
      with TRACER.timed('Fetching %s' % link, V=3):
        sdist = context.fetch(link)

      with TRACER.timed('Installing %s' % link, V=3):
        installer = installer_provider(sdist)
        dist_location = installer.bdist()
        target_location = os.path.join(
            os.path.dirname(target_link), os.path.basename(dist_location))
        shutil.move(dist_location, target_location)
        _safe_link(target_location, target_link)

      return EggPackage(target_location)
Example #23
0
  def __init__(self, pex, pex_info, interpreter=None, **kw):
    self._internal_cache = os.path.join(pex, pex_info.internal_cache)
    self._pex = pex
    self._pex_info = pex_info
    self._activated = False
    self._working_set = None
    self._interpreter = interpreter or PythonInterpreter.get()
    self._inherit_path = pex_info.inherit_path
    self._supported_tags = []

    # For the bug this works around, see: https://bitbucket.org/pypy/pypy/issues/1686
    # NB: This must be installed early before the underlying pex is loaded in any way.
    if self._interpreter.identity.abbr_impl == 'pp' and zipfile.is_zipfile(self._pex):
      self._install_pypy_zipimporter_workaround(self._pex)

    platform = Platform.current()
    platform_name = platform.platform
    super(PEXEnvironment, self).__init__(
      search_path=[] if pex_info.inherit_path == 'false' else sys.path,
      # NB: Our pkg_resources.Environment base-class wants the platform name string and not the
      # pex.platform.Platform object.
      platform=platform_name,
      **kw
    )
    self._target_interpreter_env = self._interpreter.identity.pkg_resources_env(platform_name)
    self._supported_tags.extend(platform.supported_tags(self._interpreter))
    TRACER.log(
      'E: tags for %r x %r -> %s' % (self.platform, self._interpreter, self._supported_tags),
      V=9
    )
Example #24
0
File: util.py Project: tdyas/pex
    def cache_distribution(cls, zf, source, target_dir):
        """Possibly cache a wheel from within a zipfile into `target_dir`.

    Given a zipfile handle and a source path prefix corresponding to a wheel install embedded within
    that zip, maybe extract the wheel install into the target cache and then return a distribution
    from the cache.

    :param zf: An open zip file (a zipped pex).
    :type zf: :class:`zipfile.ZipFile`
    :param str source: The path prefix of a wheel install embedded in the zip file.
    :param str target_dir: The directory to cache the distribution in if not already cached.
    :returns: The cached distribution.
    :rtype: :class:`pex.third_party.pkg_resources.Distribution`
    """
        with atomic_directory(target_dir, source=source) as target_dir_tmp:
            if target_dir_tmp is None:
                TRACER.log('Using cached {}'.format(target_dir))
            else:
                with TRACER.timed('Caching {}:{} in {}'.format(
                        zf.filename, source, target_dir)):
                    for name in zf.namelist():
                        if name.startswith(source) and not name.endswith('/'):
                            zf.extract(name, target_dir_tmp)

        dist = DistributionHelper.distribution_from_path(target_dir)
        assert dist is not None, 'Failed to cache distribution '.format(source)
        return dist
Example #25
0
    def _wrap_coverage(self, runner, *args):
        if not self._vars.PEX_COVERAGE and self._vars.PEX_COVERAGE_FILENAME is None:
            return runner(*args)

        try:
            import coverage
        except ImportError:
            die('Could not bootstrap coverage module, aborting.')

        pex_coverage_filename = self._vars.PEX_COVERAGE_FILENAME
        if pex_coverage_filename is not None:
            cov = coverage.coverage(data_file=pex_coverage_filename)
        else:
            cov = coverage.coverage(data_suffix=True)

        TRACER.log('Starting coverage.')
        cov.start()

        try:
            return runner(*args)
        finally:
            TRACER.log('Stopping coverage')
            cov.stop()

            # TODO(wickman) Post-process coverage to elide $PEX_ROOT and make
            # the report more useful/less noisy.  #89
            if pex_coverage_filename:
                cov.save()
            else:
                cov.report(show_missing=False,
                           ignore_errors=True,
                           file=sys.stdout)
Example #26
0
    def __init__(self, pex, pex_info, interpreter=None, **kw):
        self._internal_cache = os.path.join(pex, pex_info.internal_cache)
        self._pex = pex
        self._pex_info = pex_info
        self._activated = False
        self._working_set = None
        self._interpreter = interpreter or PythonInterpreter.get()
        self._inherit_path = pex_info.inherit_path
        self._supported_tags = []

        # For the bug this works around, see: https://bitbucket.org/pypy/pypy/issues/1686
        # NB: This must be installed early before the underlying pex is loaded in any way.
        if self._interpreter.identity.abbr_impl == 'pp' and zipfile.is_zipfile(
                self._pex):
            self._install_pypy_zipimporter_workaround(self._pex)

        platform = Platform.current()
        platform_name = platform.platform
        super(PEXEnvironment, self).__init__(
            search_path=[] if pex_info.inherit_path == 'false' else sys.path,
            # NB: Our pkg_resources.Environment base-class wants the platform name string and not the
            # pex.platform.Platform object.
            platform=platform_name,
            **kw)
        self._target_interpreter_env = self._interpreter.identity.pkg_resources_env(
            platform_name)
        self._supported_tags.extend(platform.supported_tags(self._interpreter))
        TRACER.log('E: tags for %r x %r -> %s' %
                   (self.platform, self._interpreter, self._supported_tags),
                   V=9)
Example #27
0
    def cache_distribution(cls, zf, source, target_dir):
        # type: (ZipFile, str, str) -> Distribution
        """Possibly cache a wheel from within a zipfile into `target_dir`.

        Given a zipfile handle and a source path prefix corresponding to a wheel install embedded within
        that zip, maybe extract the wheel install into the target cache and then return a distribution
        from the cache.

        :param zf: An open zip file (a zipped pex).
        :param source: The path prefix of a wheel install embedded in the zip file.
        :param target_dir: The directory to cache the distribution in if not already cached.
        :returns: The cached distribution.
        """
        with atomic_directory(target_dir, source=source,
                              exclusive=True) as target_dir_tmp:
            if target_dir_tmp is None:
                TRACER.log("Using cached {}".format(target_dir))
            else:
                with TRACER.timed("Caching {}:{} in {}".format(
                        zf.filename, source, target_dir)):
                    for name in zf.namelist():
                        if name.startswith(source) and not name.endswith("/"):
                            zf.extract(name, target_dir_tmp)

        dist = DistributionHelper.distribution_from_path(target_dir)
        assert dist is not None, "Failed to cache distribution: {} ".format(
            source)
        return dist
Example #28
0
    def _create_isolated_cmd(
            cls,
            binary,  # type: str
            args=None,  # type: Optional[Iterable[str]]
            pythonpath=None,  # type: Optional[Iterable[str]]
            env=None,  # type: Optional[Mapping[str, str]]
    ):
        # type: (...) -> Tuple[Iterable[str], Mapping[str, str]]
        cmd = [binary]

        # Don't add the user site directory to `sys.path`.
        #
        # Additionally, it would be nice to pass `-S` to disable adding site-packages but unfortunately
        # some python distributions include portions of the standard library there.
        cmd.append("-s")

        env = cls._sanitized_environment(env=env)
        pythonpath = list(pythonpath or ())
        if pythonpath:
            env["PYTHONPATH"] = os.pathsep.join(pythonpath)
        else:
            # Turn off reading of PYTHON* environment variables.
            cmd.append("-E")

        if args:
            cmd.extend(args)

        rendered_command = " ".join(cmd)
        if pythonpath:
            rendered_command = "PYTHONPATH={} {}".format(
                env["PYTHONPATH"], rendered_command)
        TRACER.log("Executing: {}".format(rendered_command), V=3)

        return cmd, env
Example #29
0
File: pex.py Project: windie/heron
def _resolve_and_link_interpreter(requirement, fetchers, target_link,
                                  installer_provider):
    # Short-circuit if there is a local copy
    if os.path.exists(target_link) and os.path.exists(
            os.path.realpath(target_link)):
        egg = EggPackage(os.path.realpath(target_link))
        if egg.satisfies(requirement):
            return egg

    context = Context.get()
    iterator = Iterator(fetchers=fetchers, crawler=Crawler(context))
    links = [
        link for link in iterator.iter(requirement)
        if isinstance(link, SourcePackage)
    ]

    with TRACER.timed('Interpreter cache resolving %s' % requirement, V=2):
        for link in links:
            with TRACER.timed('Fetching %s' % link, V=3):
                sdist = context.fetch(link)

            with TRACER.timed('Installing %s' % link, V=3):
                installer = installer_provider(sdist)
                dist_location = installer.bdist()
                target_location = os.path.join(os.path.dirname(target_link),
                                               os.path.basename(dist_location))
                shutil.move(dist_location, target_location)
                _safe_link(target_location, target_link)

            return EggPackage(target_location)
Example #30
0
    def _create_isolated_cmd(cls,
                             binary,
                             args=None,
                             pythonpath=None,
                             env=None):
        cmd = [binary]

        # Don't add the user site directory to `sys.path`.
        #
        # Additionally, it would be nice to pass `-S` to disable adding site-packages but unfortunately
        # some python distributions include portions of the standard library there.
        cmd.append('-s')

        env = cls._sanitized_environment(env=env)
        pythonpath = list(pythonpath or ())
        if pythonpath:
            env['PYTHONPATH'] = os.pathsep.join(pythonpath)
        else:
            # Turn off reading of PYTHON* environment variables.
            cmd.append('-E')

        if args:
            cmd.extend(args)

        rendered_command = ' '.join(cmd)
        if pythonpath:
            rendered_command = 'PYTHONPATH={} {}'.format(
                env['PYTHONPATH'], rendered_command)
        TRACER.log('Executing: {}'.format(rendered_command), V=3)

        return cmd, env
Example #31
0
 def from_id_string(cls, id_string):
     TRACER.log('creating PythonIdentity from id string: %s' % id_string,
                V=3)
     values = str(id_string).split()
     if len(values) != 6:
         raise cls.InvalidError("Invalid id string: %s" % id_string)
     return cls(*values)
Example #32
0
def build_pex(args, options, resolver_option_builder):
  with TRACER.timed('Resolving interpreter', V=2):
    interpreter = interpreter_from_options(options)

  if interpreter is None:
    die('Could not find compatible interpreter', CANNOT_SETUP_INTERPRETER)

  pex_builder = PEXBuilder(path=safe_mkdtemp(), interpreter=interpreter)

  pex_info = pex_builder.info
  pex_info.zip_safe = options.zip_safe
  pex_info.always_write_cache = options.always_write_cache
  pex_info.ignore_errors = options.ignore_errors
  pex_info.inherit_path = options.inherit_path

  resolvables = [Resolvable.get(arg, resolver_option_builder) for arg in args]

  for requirements_txt in options.requirement_files:
    resolvables.extend(requirements_from_file(requirements_txt, resolver_option_builder))

  # pip states the constraints format is identical tor requirements
  # https://pip.pypa.io/en/stable/user_guide/#constraints-files
  for constraints_txt in options.constraint_files:
    constraints = []
    for r in requirements_from_file(constraints_txt, resolver_option_builder):
      r.is_constraint = True
      constraints.append(r)
    resolvables.extend(constraints)

  resolver_kwargs = dict(interpreter=interpreter, platform=options.platform)

  if options.cache_dir:
    resolver = CachingResolver(options.cache_dir, options.cache_ttl, **resolver_kwargs)
  else:
    resolver = Resolver(**resolver_kwargs)

  with TRACER.timed('Resolving distributions'):
    try:
      resolveds = resolver.resolve(resolvables)
    except Unsatisfiable as e:
      die(e)

  for dist in resolveds:
    log('  %s' % dist, v=options.verbosity)
    pex_builder.add_distribution(dist)
    pex_builder.add_requirement(dist.as_requirement())

  if options.entry_point and options.script:
    die('Must specify at most one entry point or script.', INVALID_OPTIONS)

  if options.entry_point:
    pex_builder.set_entry_point(options.entry_point)
  elif options.script:
    pex_builder.set_script(options.script)

  if options.python_shebang:
    pex_builder.set_shebang(options.python_shebang)

  return pex_builder
Example #33
0
 def crawl_local(cls, link):
   try:
     dirents = os.listdir(link.local_path)
   except OSError as e:
     TRACER.log('Failed to read %s: %s' % (link.local_path, e), V=1)
     return set(), set()
   files, dirs = partition([os.path.join(link.local_path, fn) for fn in dirents], os.path.isdir)
   return set(map(Link.from_filename, files)), set(map(Link.from_filename, dirs))
Example #34
0
 def _validate(self):
     if self._hasher:
         if self._hash_value != self._hasher.hexdigest():
             raise Context.Error('%s failed checksum!' % (self._link.url))
         else:
             TRACER.log('Validated %s (%s)' %
                        (self._link.filename, self._link.fragment),
                        V=3)
Example #35
0
 def crawl_link(cls, context, link):
   if link.local:
     return cls.crawl_local(link)
   elif link.remote:
     return cls.crawl_remote(context, link)
   else:
     TRACER.log('Failed to crawl %s: unknown scheme %s' % (link.url, link.scheme))
     return set(), set()
Example #36
0
File: http.py Project: jsirois/pex
 def get(cls):
   for context_class in cls._REGISTRY:
     try:
       context = context_class()
       TRACER.log('Constructed %s context %r' % (context.__class__.__name__, context), V=4)
       return context
     except cls.Error:
       continue
   raise cls.Error('Could not initialize a request context.')
Example #37
0
 def record_unresolved(dist_not_found):
     # type: (_DistributionNotFound) -> None
     TRACER.log("Failed to resolve a requirement: {}".format(dist_not_found.requirement))
     requirers = unresolved_reqs.get(dist_not_found.requirement)
     if requirers is None:
         requirers = OrderedSet()
         unresolved_reqs[dist_not_found.requirement] = requirers
     if dist_not_found.required_by:
         requirers.add(dist_not_found.required_by)
Example #38
0
 def crawl_remote(cls, context, link):
   try:
     link = context.resolve(link)
     content = context.content(link)
   except context.Error as e:
     TRACER.log('Failed to read %s: %s' % (link.url, e), V=1)
     return set(), set()
   links = set(link.join(href) for href in PageParser.links(content))
   rel_links = set(link.join(href) for href in PageParser.rel_links(content))
   return links, rel_links
Example #39
0
File: pex.py Project: jsirois/pex
  def execute_script(self, script_name):
    dists = list(self._activate())

    dist, entry_point = get_entry_point_from_console_script(script_name, dists)
    if entry_point:
      TRACER.log('Found console_script %r in %r' % (entry_point, dist))
      sys.exit(self.execute_entry(entry_point))

    dist, script_path, script_content = get_script_from_distributions(script_name, dists)
    if not dist:
      raise self.NotFound('Could not find script %r in pex!' % script_name)
    TRACER.log('Found script %r in %r' % (script_name, dist))
    return self.execute_content(script_path, script_content, argv0=script_name)
Example #40
0
File: pex.py Project: twitter/heron
def build_pex(args, options, resolver_option_builder, interpreter=None):
    if interpreter is None:
        with TRACER.timed("Resolving interpreter", V=2):
            interpreter = interpreter_from_options(options)

    if interpreter is None:
        die("Could not find compatible interpreter", CANNOT_SETUP_INTERPRETER)

    pex_builder = PEXBuilder(path=safe_mkdtemp(), interpreter=interpreter)

    pex_info = pex_builder.info
    pex_info.zip_safe = options.zip_safe
    pex_info.always_write_cache = options.always_write_cache
    pex_info.ignore_errors = options.ignore_errors
    pex_info.inherit_path = options.inherit_path

    resolvables = [Resolvable.get(arg, resolver_option_builder) for arg in args]

    for requirements_txt in options.requirement_files:
        resolvables.extend(requirements_from_file(requirements_txt, resolver_option_builder))

    resolver_kwargs = dict(interpreter=interpreter, platform=options.platform)

    if options.cache_dir:
        resolver = CachingResolver(options.cache_dir, options.cache_ttl, **resolver_kwargs)
    else:
        resolver = Resolver(**resolver_kwargs)

    with TRACER.timed("Resolving distributions"):
        try:
            resolveds = resolver.resolve(resolvables)
        except Unsatisfiable as e:
            die(e)

    for dist in resolveds:
        log("  %s" % dist, v=options.verbosity)
        pex_builder.add_distribution(dist)
        pex_builder.add_requirement(dist.as_requirement())

    if options.entry_point and options.script:
        die("Must specify at most one entry point or script.", INVALID_OPTIONS)

    if options.entry_point:
        pex_builder.set_entry_point(options.entry_point)
    elif options.script:
        pex_builder.set_script(options.script)

    if options.python_shebang:
        pex_builder.set_shebang(options.python_shebang)

    return pex_builder
Example #41
0
  def from_env(cls, hashbang):
    """Resolve a PythonInterpreter as /usr/bin/env would.

       :param hashbang: A string, e.g. "python3.3" representing some binary on the $PATH.
    """
    paths = os.getenv('PATH', '').split(':')
    for path in paths:
      for fn in cls.expand_path(path):
        basefile = os.path.basename(fn)
        if hashbang == basefile:
          try:
            return cls.from_binary(fn)
          except Exception as e:
            TRACER.log('Could not identify %s: %s' % (fn, e))
Example #42
0
 def __init__(self, allow_prereleases=None, interpreter=None, platform=None, use_manylinux=None):
   self._interpreter = interpreter or PythonInterpreter.get()
   self._platform = self._maybe_expand_platform(self._interpreter, platform)
   self._allow_prereleases = allow_prereleases
   platform_name = self._platform.platform
   self._target_interpreter_env = self._interpreter.identity.pkg_resources_env(platform_name)
   self._supported_tags = self._platform.supported_tags(
     self._interpreter,
     use_manylinux
   )
   TRACER.log(
     'R: tags for %r x %r -> %s' % (self._platform, self._interpreter, self._supported_tags),
     V=9
   )
Example #43
0
def vendor_runtime(chroot, dest_basedir, label, root_module_names):
  """Includes portions of vendored distributions in a chroot.

  The portion to include is selected by root module name. If the module is a file, just it is
  included. If the module represents a package, the package and all its sub-packages are added
  recursively.

  :param chroot: The chroot to add vendored code to.
  :type chroot: :class:`pex.common.Chroot`
  :param str dest_basedir: The prefix to store the vendored code under in the ``chroot``.
  :param str label: The chroot label for the vendored code fileset.
  :param root_module_names: The names of the root vendored modules to include in the chroot.
  :type root_module_names: :class:`collections.Iterable` of str
  :raise: :class:`ValueError` if any of the given ``root_module_names`` could not be found amongst
          the vendored code and added to the chroot.
  """
  vendor_module_names = {root_module_name: False for root_module_name in root_module_names}
  for spec in iter_vendor_specs():
    for root, dirs, files in os.walk(spec.target_dir):
      if root == spec.target_dir:
        dirs[:] = [pkg_name for pkg_name in dirs if pkg_name in vendor_module_names]
        files[:] = [mod_name for mod_name in files if mod_name[:-3] in vendor_module_names]
        vendored_names = dirs + files
        if vendored_names:
          pkg_path = ''
          for pkg in spec.relpath.split(os.sep):
            pkg_path = os.path.join(pkg_path, pkg)
            pkg_file = os.path.join(pkg_path, '__init__.py')
            src = os.path.join(VendorSpec.ROOT, pkg_file)
            dest = os.path.join(dest_basedir, pkg_file)
            if os.path.exists(src):
              chroot.copy(src, dest, label)
            else:
              # We delete `pex/vendor/_vendored/<dist>/__init__.py` when isolating third_party.
              chroot.touch(dest, label)
          for name in vendored_names:
            vendor_module_names[name] = True
            TRACER.log('Vendoring {} from {} @ {}'.format(name, spec, spec.target_dir), V=3)

      for filename in files:
        if not filename.endswith('.pyc'):  # Sources and data only.
          src = os.path.join(root, filename)
          dest = os.path.join(dest_basedir, spec.relpath, os.path.relpath(src, spec.target_dir))
          chroot.copy(src, dest, label)

  if not all(vendor_module_names.values()):
    raise ValueError('Failed to extract {module_names} from:\n\t{specs}'.format(
      module_names=', '.join(module
                             for module, written in vendor_module_names.items() if not written),
      specs='\n\t'.join('{} @ {}'.format(spec, spec.target_dir) for spec in iter_vendor_specs())))
Example #44
0
def matched_interpreters(interpreters, constraints):
  """Given some filters, yield any interpreter that matches at least one of them.

  :param interpreters: a list of PythonInterpreter objects for filtering
  :param constraints: A sequence of strings that constrain the interpreter compatibility for this
    pex. Each string uses the Requirement-style format, e.g. 'CPython>=3' or '>=2.7,<3' for
    requirements agnostic to interpreter class. Multiple requirement strings may be combined
    into a list to OR the constraints, such as ['CPython>=2.7,<3', 'CPython>=3.4'].
  :return interpreter: returns a generator that yields compatible interpreters
  """
  for interpreter in interpreters:
    if any(interpreter.identity.matches(filt) for filt in constraints):
      TRACER.log("Constraints on interpreters: %s, Matching Interpreter: %s"
                 % (constraints, interpreter.binary), V=3)
      yield interpreter
Example #45
0
 def build(self, package, options):
   context = options.get_context()
   translator = options.get_translator(self._interpreter, self._supported_tags)
   with TRACER.timed('Fetching %s' % package.url, V=2):
     local_package = Package.from_href(context.fetch(package))
   if local_package is None:
     raise Untranslateable('Could not fetch package %s' % package)
   with TRACER.timed('Translating %s into distribution' % local_package.local_path, V=2):
     dist = translator.translate(local_package)
   if dist is None:
     raise Untranslateable('Package %s is not translateable by %s' % (package, translator))
   if not distribution_compatible(dist, self._supported_tags):
     raise Untranslateable(
       'Could not get distribution for %s on platform %s.' % (package, self._platform))
   return dist
Example #46
0
def build_pex(args):
    with TRACER.timed('Resolving interpreter', V=2):
        interpreter = _establish_interpreter(args)

    if interpreter is None:
        die('Could not find compatible interpreter', CANNOT_SETUP_INTERPRETER)

    pex_builder = PEXBuilder(path=safe_mkdtemp(), interpreter=interpreter, preamble=_PREAMBLE)

    pex_info = pex_builder.info

    pex_info.zip_safe = False
    pex_info.always_write_cache = True
    pex_info.inherit_path = False

    resolver_option_builder = _establish_resolver_options(args)
    reqs = args.reqs
    resolvables = [Resolvable.get(req, resolver_option_builder) for req in reqs]

    for requirements_txt in args.requirement_files:
        resolvables.extend(requirements_from_file(requirements_txt, resolver_option_builder))

    resolver_kwargs = dict(interpreter=interpreter, platform=args.platform)
    _add_spex_deps(resolvables, pex_builder, resolver_option_builder=resolver_option_builder)

    if not args.disable_cache:
        resolver = CachingResolver(args.cache_dir, args.cache_ttl, **resolver_kwargs)
    else:
        resolver = Resolver(**resolver_kwargs)

    resolveds = []
    with TRACER.timed('Resolving distributions'):
        try:
            resolveds = resolver.resolve(resolvables)
        except Unsatisfiable as exception:
            die(exception)

    for dist in resolveds:
        log('  %s' % dist, verbose=args.verbosity)
        pex_builder.add_distribution(dist)
        pex_builder.add_requirement(dist.as_requirement())

    pex_builder.set_entry_point('spex:spex')

    if args.python_shebang:
        pex_builder.set_shebang(args.python_shebang)

    return pex_builder
Example #47
0
def maybe_reexec_pex(compatibility_constraints):
  """
  Handle environment overrides for the Python interpreter to use when executing this pex.

  This function supports interpreter filtering based on interpreter constraints stored in PEX-INFO
  metadata. If PEX_PYTHON is set in a pexrc, it attempts to obtain the binary location of the
  interpreter specified by PEX_PYTHON. If PEX_PYTHON_PATH is set, it attempts to search the path for
  a matching interpreter in accordance with the interpreter constraints. If both variables are
  present in a pexrc, this function gives precedence to PEX_PYTHON_PATH and errors out if no
  compatible interpreters can be found on said path.

  If neither variable is set, we fall back to plain PEX execution using PATH searching or the
  currently executing interpreter. If compatibility constraints are used, we match those constraints
  against these interpreters.

  :param compatibility_constraints: list of requirements-style strings that constrain the
  Python interpreter to re-exec this pex with.
  """
  if os.environ.pop('SHOULD_EXIT_BOOTSTRAP_REEXEC', None):
    # We've already been here and selected an interpreter. Continue to execution.
    return

  target = None
  with TRACER.timed('Selecting runtime interpreter based on pexrc', V=3):
    if ENV.PEX_PYTHON and not ENV.PEX_PYTHON_PATH:
      # preserve PEX_PYTHON re-exec for backwards compatibility
      # TODO: Kill this off completely in favor of PEX_PYTHON_PATH
      # https://github.com/pantsbuild/pex/issues/431
      target = _select_pex_python_interpreter(ENV.PEX_PYTHON,
                                              compatibility_constraints=compatibility_constraints)
    elif ENV.PEX_PYTHON_PATH:
      target = _select_interpreter(pex_python_path=ENV.PEX_PYTHON_PATH,
                                   compatibility_constraints=compatibility_constraints)

    elif compatibility_constraints:
      # Apply constraints to target using regular PATH
      target = _select_interpreter(compatibility_constraints=compatibility_constraints)

  if target and os.path.realpath(target) != os.path.realpath(sys.executable):
    cmdline = [target] + sys.argv
    TRACER.log('Re-executing: cmdline="%s", sys.executable="%s", PEX_PYTHON="%s", '
               'PEX_PYTHON_PATH="%s", COMPATIBILITY_CONSTRAINTS="%s"'
               % (cmdline, sys.executable, ENV.PEX_PYTHON, ENV.PEX_PYTHON_PATH,
                  compatibility_constraints))
    ENV.delete('PEX_PYTHON')
    ENV.delete('PEX_PYTHON_PATH')
    os.environ['SHOULD_EXIT_BOOTSTRAP_REEXEC'] = '1'
    os.execve(target, cmdline, ENV.copy())
Example #48
0
  def write_zipped_internal_cache(cls, pex, pex_info):
    prefix_length = len(pex_info.internal_cache) + 1
    existing_cached_distributions = []
    newly_cached_distributions = []
    zip_safe_distributions = []
    with open_zip(pex) as zf:
      # Distribution names are the first element after ".deps/" and before the next "/"
      distribution_names = set(filter(None, (filename[prefix_length:].split('/')[0]
          for filename in zf.namelist() if filename.startswith(pex_info.internal_cache))))
      # Create Distribution objects from these, and possibly write to disk if necessary.
      for distribution_name in distribution_names:
        internal_dist_path = '/'.join([pex_info.internal_cache, distribution_name])
        # First check if this is already cached
        dist_digest = pex_info.distributions.get(distribution_name) or CacheHelper.zip_hash(
            zf, internal_dist_path)
        cached_location = os.path.join(pex_info.install_cache, '%s.%s' % (
          distribution_name, dist_digest))
        if os.path.exists(cached_location):
          dist = DistributionHelper.distribution_from_path(cached_location)
          if dist is not None:
            existing_cached_distributions.append(dist)
            continue
        else:
          dist = DistributionHelper.distribution_from_path(os.path.join(pex, internal_dist_path))
          if dist is not None:
            if DistributionHelper.zipsafe(dist) and not pex_info.always_write_cache:
              zip_safe_distributions.append(dist)
              continue

        with TRACER.timed('Caching %s' % dist):
          newly_cached_distributions.append(
            CacheHelper.cache_distribution(zf, internal_dist_path, cached_location))

    return existing_cached_distributions, newly_cached_distributions, zip_safe_distributions
Example #49
0
  def activate(self):
    if not self._activated:
      with TRACER.timed('Activating PEX virtual environment from %s' % self._pex):
        self._working_set = self._activate()
      self._activated = True

    return self._working_set
Example #50
0
File: pex.py Project: 10fish/heron
def main():
  parser, resolver_options_builder = configure_clp()

  # split arguments early because optparse is dumb
  args = sys.argv[1:]
  try:
    separator = args.index('--')
    args, cmdline = args[:separator], args[separator + 1:]
  except ValueError:
    args, cmdline = args, []

  options, reqs = parser.parse_args(args=args)

  with ENV.patch(PEX_VERBOSE=str(options.verbosity)):
    with TRACER.timed('Building pex'):
      pex_builder = build_pex(reqs, options, resolver_options_builder)

    if options.pex_name is not None:
      log('Saving PEX file to %s' % options.pex_name, v=options.verbosity)
      tmp_name = options.pex_name + '~'
      safe_delete(tmp_name)
      pex_builder.build(tmp_name)
      os.rename(tmp_name, options.pex_name)
      return 0

    if options.platform != Platform.current():
      log('WARNING: attempting to run PEX with differing platform!')

    pex_builder.freeze()

    log('Running PEX file at %s with args %s' % (pex_builder.path(), cmdline), v=options.verbosity)
    pex = PEX(pex_builder.path(), interpreter=pex_builder.interpreter)
    sys.exit(pex.run(args=list(cmdline)))
Example #51
0
 def find(cls, paths):
   """
     Given a list of files or directories, try to detect python interpreters amongst them.
     Returns a list of PythonInterpreter objects.
   """
   pythons = []
   for path in paths:
     for fn in cls.expand_path(path):
       basefile = os.path.basename(fn)
       if cls._matches_binary_name(basefile):
         try:
           pythons.append(cls.from_binary(fn))
         except Exception as e:
           TRACER.log('Could not identify %s: %s' % (fn, e))
           continue
   return pythons
Example #52
0
  def run(self):
    if self._installed is not None:
      return self._installed

    with TRACER.timed('Installing %s' % self._install_tmp, V=2):
      env = self._interpreter.sanitized_environment()
      mixins = OrderedSet(['setuptools'] + self.mixins)
      env['PYTHONPATH'] = os.pathsep.join(third_party.expose(mixins))
      env['__PEX_UNVENDORED__'] = '1'

      command = [self._interpreter.binary, '-s', '-'] + self.setup_command()
      try:
        Executor.execute(command,
                         env=env,
                         cwd=self._source_dir,
                         stdin_payload=self.setup_py_wrapper.encode('ascii'))
        self._installed = True
      except Executor.NonZeroExit as e:
        self._installed = False
        name = os.path.basename(self._source_dir)
        print('**** Failed to install %s (caused by: %r\n):' % (name, e), file=sys.stderr)
        print('stdout:\n%s\nstderr:\n%s\n' % (e.stdout, e.stderr), file=sys.stderr)
        return self._installed

    return self._installed
Example #53
0
def main(args=None):
    parser = create_parser()
    args = parser.parse_args(args)

    if args.build_distro:
        if not args.spark_home:
            die("No spark home given but building a distribution")

        spark_home = os.path.realpath(os.path.abspath(args.spark_home))
        if not os.path.exists(spark_home):
            die("No spark home given but building a distribution")
        spark_name = os.path.basename(spark_home)

        args.spark_home = spark_home
        args.spark_name = spark_name
    else:
        spark_home = None
        spark_name = None

    spex_name = args.spex_name
    spex_file = spex_name + '.spex'

    with ENV.patch(PEX_VERBOSE=str(args.verbosity)):
        with TRACER.timed('Building spex'):
            with TRACER.timed('Building pex'):
                pex_builder = build_pex(args)

                with dump_args_as_config(args) as cfg:
                    pex_builder.add_resource(cfg, 'SPEX-INFO')

                    log('Saving PEX file to %s' % spex_file, verbose=args.verbosity)
                    tmp_name = args.spex_name + '~'
                    safe_delete(tmp_name)
                    pex_builder.build(tmp_name)
                    os.rename(tmp_name, spex_file)

            if args.build_distro:
                with TRACER.timed('Building spark package'):
                    spark_distro = uber_distro_location(spark_name)
                    establish_spark_distro(spark_distro, spark_home, spark_name, spex_file, spex_name)
                log('Spark package built')

                with TRACER.timed('Building full distribution'):
                    create_distro_tarball(spark_distro, spark_name, spex_file, spex_name, args)
                log('Saved full distribution to %s' % spark_distro)

    return 0
Example #54
0
File: pex.py Project: jsirois/pex
  def minimum_sys(cls, inherit_path):
    """Return the minimum sys necessary to run this interpreter, a la python -S.

    :returns: (sys.path, sys.path_importer_cache, sys.modules) tuple of a
      bare python installation.
    """
    site_libs = set(cls.site_libs())
    for site_lib in site_libs:
      TRACER.log('Found site-library: %s' % site_lib)
    for extras_path in cls._extras_paths():
      TRACER.log('Found site extra: %s' % extras_path)
      site_libs.add(extras_path)
    site_libs = set(os.path.normpath(path) for path in site_libs)

    sys_path, sys_path_importer_cache = cls.minimum_sys_path(site_libs, inherit_path)
    sys_modules = cls.minimum_sys_modules(site_libs)

    return sys_path, sys_path_importer_cache, sys_modules
Example #55
0
  def _crawl(self, link_or_links, follow_links):
    links, seen = set(), set()
    queue = Queue()
    converged = threading.Event()

    def execute():
      while not converged.is_set():
        try:
          link = queue.get(timeout=0.01)
        except Empty:
          continue
        if link not in seen:
          seen.add(link)
          try:
            roots, rels = self.crawl_link(self.context, link)
          except Exception as e:
            TRACER.log('Unknown exception encountered: %s' % e)
            for line in traceback.format_exc().splitlines():
              TRACER.log(line)
            queue.task_done()
            continue
          links.update(roots)
          if follow_links:
            for rel in rels:
              if rel not in seen:
                queue.put(rel)
        queue.task_done()

    for i, link in enumerate(link_or_links):
      TRACER.log('crawling link i=%s link=%s follow_links=%s' % (i, link, follow_links), V=3)
      queue.put(link)

    workers = []
    for _ in range(self._threads):
      worker = threading.Thread(target=execute)
      workers.append(worker)
      worker.daemon = True
      worker.start()

    queue.join()
    converged.set()

    # We deliberately do not join the worker threads, since they are no longer of any use to us.
    return links
Example #56
0
 def load_internal_cache(cls, pex, pex_info):
   """Possibly cache out the internal cache."""
   internal_cache = os.path.join(pex, pex_info.internal_cache)
   with TRACER.timed('Searching dependency cache: %s' % internal_cache, V=2):
     if os.path.isdir(pex):
       for dist in find_distributions(internal_cache):
         yield dist
     else:
       for dist in itertools.chain(*cls.write_zipped_internal_cache(pex, pex_info)):
         yield dist
Example #57
0
File: pex.py Project: jsirois/pex
  def _extras_paths(cls):
    standard_lib = sysconfig.get_python_lib(standard_lib=True)

    try:
      makefile = sysconfig.parse_makefile(sysconfig.get_makefile_filename())
    except (AttributeError, IOError):
      # This is not available by default in PyPy's distutils.sysconfig or it simply is
      # no longer available on the system (IOError ENOENT)
      makefile = {}

    extras_paths = filter(None, makefile.get('EXTRASPATH', '').split(':'))
    for path in extras_paths:
      yield os.path.join(standard_lib, path)

    # Handle .pth injected paths as extras.
    sitedirs = cls._get_site_packages()
    for pth_path in cls._scan_pth_files(sitedirs):
      TRACER.log('Found .pth file: %s' % pth_path, V=3)
      for extras_path in iter_pth_paths(pth_path):
        yield extras_path