示例#1
0
async def resolve_plugins(
        request: PluginsRequest,
        global_options: GlobalOptions) -> ResolvedPluginDistributions:
    """This rule resolves plugins using a VenvPex, and exposes the absolute paths of their dists.

    NB: This relies on the fact that PEX constructs venvs in a stable location (within the
    `named_caches` directory), but consequently needs to disable the process cache: see the
    ProcessCacheScope reference in the body.
    """
    requirements = PexRequirements(
        req_strings=sorted(global_options.plugins),
        constraints_strings=(str(constraint)
                             for constraint in request.constraints),
    )
    if not requirements:
        return ResolvedPluginDistributions()

    python: PythonExecutable | None = None
    if not request.interpreter_constraints:
        python = cast(
            PythonExecutable,
            PythonExecutable.fingerprinted(
                sys.executable,
                ".".join(map(str, sys.version_info[:3])).encode("utf8")),
        )

    plugins_pex = await Get(
        VenvPex,
        PexRequest(
            output_filename="pants_plugins.pex",
            internal_only=True,
            python=python,
            requirements=requirements,
            interpreter_constraints=request.interpreter_constraints,
            description=
            f"Resolving plugins: {', '.join(requirements.req_strings)}",
        ),
    )

    # NB: We run this Process per-restart because it (intentionally) leaks named cache
    # paths in a way that invalidates the Process-cache. See the method doc.
    cache_scope = (ProcessCacheScope.PER_SESSION
                   if global_options.plugins_force_resolve else
                   ProcessCacheScope.PER_RESTART_SUCCESSFUL)

    plugins_process_result = await Get(
        ProcessResult,
        VenvPexProcess(
            plugins_pex,
            argv=
            ("-c",
             "import os, site; print(os.linesep.join(site.getsitepackages()))"
             ),
            description="Extracting plugin locations",
            level=LogLevel.DEBUG,
            cache_scope=cache_scope,
        ),
    )
    return ResolvedPluginDistributions(
        plugins_process_result.stdout.decode().strip().split("\n"))
示例#2
0
async def find_interpreter(
        interpreter_constraints: InterpreterConstraints,
        pex_runtime_env: PexRuntimeEnvironment) -> PythonExecutable:
    formatted_constraints = " OR ".join(
        str(constraint) for constraint in interpreter_constraints)
    result = await Get(
        ProcessResult,
        PexCliProcess(
            description=
            f"Find interpreter for constraints: {formatted_constraints}",
            subcommand=(),
            # Here, we run the Pex CLI with no requirements, which just selects an interpreter.
            # Normally, this would start an isolated repl. By passing `--`, we force the repl to
            # instead act as an interpreter (the selected one) and tell us about itself. The upshot
            # is we run the Pex interpreter selection logic unperturbed but without resolving any
            # distributions.
            extra_args=(
                *interpreter_constraints.generate_pex_arg_list(),
                "--",
                "-c",
                # N.B.: The following code snippet must be compatible with Python 2.7 and
                # Python 3.5+.
                #
                # When hashing, we pick 8192 for efficiency of reads and fingerprint updates
                # (writes) since it's a common OS buffer size and an even multiple of the
                # hash block size.
                dedent("""\
                    import hashlib, os, sys

                    python = os.path.realpath(sys.executable)
                    print(python)

                    hasher = hashlib.sha256()
                    with open(python, "rb") as fp:
                      for chunk in iter(lambda: fp.read(8192), b""):
                          hasher.update(chunk)
                    print(hasher.hexdigest())
                    """),
            ),
            level=LogLevel.DEBUG,
            # NB: We want interpreter discovery to re-run fairly frequently
            # (PER_RESTART_SUCCESSFUL), but not on every run of Pants (NEVER, which is effectively
            # per-Session). See #10769 for a solution that is less of a tradeoff.
            cache_scope=ProcessCacheScope.PER_RESTART_SUCCESSFUL,
        ),
    )
    path, fingerprint = result.stdout.decode().strip().splitlines()

    if pex_runtime_env.verbosity > 0:
        log_output = result.stderr.decode()
        if log_output:
            logger.info("%s", log_output)

    return PythonExecutable(path=path, fingerprint=fingerprint)
示例#3
0
async def find_interpreter(
        interpreter_constraints: PexInterpreterConstraints
) -> PythonExecutable:
    formatted_constraints = " OR ".join(
        str(constraint) for constraint in interpreter_constraints)
    process = await Get(
        Process,
        PexCliProcess(
            description=
            f"Find interpreter for constraints: {formatted_constraints}",
            # Here, we run the Pex CLI with no requirements, which just selects an interpreter.
            # Normally, this would start an isolated repl. By passing `--`, we force the repl to
            # instead act as an interpreter (the selected one) and tell us about itself. The upshot
            # is we run the Pex interpreter selection logic unperturbed but without resolving any
            # distributions.
            argv=(
                *interpreter_constraints.generate_pex_arg_list(),
                "--",
                "-c",
                # N.B.: The following code snippet must be compatible with Python 2.7 and
                # Python 3.5+.
                dedent("""\
                    import hashlib
                    import os
                    import sys

                    python = os.path.realpath(sys.executable)
                    print(python)

                    hasher = hashlib.sha256()
                    with open(python, "rb") as fp:
                      # We pick 8192 for efficiency of reads and fingerprint updates
                      # (writes) since it's a common OS buffer size and an even
                      # multiple of the hash block size.
                      for chunk in iter(lambda: fp.read(8192), b""):
                          hasher.update(chunk)
                    print(hasher.hexdigest())
                    """),
            ),
            level=LogLevel.DEBUG,
        ),
    )
    result = await Get(
        ProcessResult,
        UncacheableProcess(process=process, scope=ProcessScope.PER_SESSION))
    path, fingerprint = result.stdout.decode().strip().splitlines()
    return PythonExecutable(path=path, fingerprint=fingerprint)