示例#1
0
def assert_chroot_perms(copyfn):
    with temporary_dir() as src:
        one = os.path.join(src, "one")
        touch(one)

        two = os.path.join(src, "two")
        touch(two)
        chmod_plus_x(two)

        with temporary_dir() as dst:
            chroot = Chroot(dst)
            copyfn(chroot, one, "one")
            copyfn(chroot, two, "two")
            assert extract_perms(one) == extract_perms(
                os.path.join(chroot.path(), "one"))
            assert extract_perms(two) == extract_perms(
                os.path.join(chroot.path(), "two"))

            zip_path = os.path.join(src, "chroot.zip")
            chroot.zip(zip_path)
            with temporary_dir() as extract_dir:
                with contextlib.closing(PermPreservingZipFile(zip_path)) as zf:
                    zf.extractall(extract_dir)

                    assert extract_perms(one) == extract_perms(
                        os.path.join(extract_dir, "one"))
                    assert extract_perms(two) == extract_perms(
                        os.path.join(extract_dir, "two"))
示例#2
0
    def build(self,
              filename,
              bytecode_compile=True,
              deterministic_timestamp=False):
        """Package the PEX into a zipfile.

        :param filename: The filename where the PEX should be stored.
        :param bytecode_compile: If True, precompile .py files into .pyc files.
        :param deterministic_timestamp: If True, will use our hardcoded time for zipfile timestamps.

        If the PEXBuilder is not yet frozen, it will be frozen by ``build``.  This renders the
        PEXBuilder immutable.
        """
        if not self._frozen:
            self.freeze(bytecode_compile=bytecode_compile)
        tmp_zip = filename + "~"
        try:
            os.unlink(tmp_zip)
            self._logger.warning(
                "Previous binary unexpectedly exists, cleaning: {}".format(
                    tmp_zip))
        except OSError:
            # The expectation is that the file does not exist, so continue
            pass
        with safe_open(tmp_zip, "ab") as pexfile:
            assert os.path.getsize(pexfile.name) == 0
            pexfile.write(to_bytes("{}\n".format(self._shebang)))
        with TRACER.timed("Zipping PEX file."):
            self._chroot.zip(tmp_zip,
                             mode="a",
                             deterministic_timestamp=deterministic_timestamp)
        if os.path.exists(filename):
            os.unlink(filename)
        os.rename(tmp_zip, filename)
        chmod_plus_x(filename)
示例#3
0
  def build(self, filename, bytecode_compile=True, deterministic_timestamp=False):
    """Package the PEX into a zipfile.

    :param filename: The filename where the PEX should be stored.
    :param bytecode_compile: If True, precompile .py files into .pyc files.
    :param deterministic_timestamp: If True, will use our hardcoded time for zipfile timestamps.

    If the PEXBuilder is not yet frozen, it will be frozen by ``build``.  This renders the
    PEXBuilder immutable.
    """
    if not self._frozen:
      self.freeze(bytecode_compile=bytecode_compile)
    try:
      os.unlink(filename + '~')
      self._logger.warning('Previous binary unexpectedly exists, cleaning: %s' % (filename + '~'))
    except OSError:
      # The expectation is that the file does not exist, so continue
      pass
    if os.path.dirname(filename):
      safe_mkdir(os.path.dirname(filename))
    with open(filename + '~', 'ab') as pexfile:
      assert os.path.getsize(pexfile.name) == 0
      pexfile.write(to_bytes('%s\n' % self._shebang))
    self._chroot.zip(filename + '~', mode='a', deterministic_timestamp=deterministic_timestamp)
    if os.path.exists(filename):
      os.unlink(filename)
    os.rename(filename + '~', filename)
    chmod_plus_x(filename)
示例#4
0
  def build(self, filename, bytecode_compile=True, deterministic_timestamp=False):
    """Package the PEX into a zipfile.

    :param filename: The filename where the PEX should be stored.
    :param bytecode_compile: If True, precompile .py files into .pyc files.
    :param deterministic_timestamp: If True, will use our hardcoded time for zipfile timestamps.

    If the PEXBuilder is not yet frozen, it will be frozen by ``build``.  This renders the
    PEXBuilder immutable.
    """
    if not self._frozen:
      self.freeze(bytecode_compile=bytecode_compile)
    try:
      os.unlink(filename + '~')
      self._logger.warn('Previous binary unexpectedly exists, cleaning: %s' % (filename + '~'))
    except OSError:
      # The expectation is that the file does not exist, so continue
      pass
    if os.path.dirname(filename):
      safe_mkdir(os.path.dirname(filename))
    with open(filename + '~', 'ab') as pexfile:
      assert os.path.getsize(pexfile.name) == 0
      pexfile.write(to_bytes('%s\n' % self._shebang))
    self._chroot.zip(filename + '~', mode='a', deterministic_timestamp=deterministic_timestamp)
    if os.path.exists(filename):
      os.unlink(filename)
    os.rename(filename + '~', filename)
    chmod_plus_x(filename)
示例#5
0
def test_is_exe(temporary_working_dir):
    # type: (str) -> None
    touch("all_exe")
    chmod_plus_x("all_exe")
    assert is_exe("all_exe")

    touch("other_exe")
    os.chmod("other_exe", 0o665)
    assert not is_exe("other_exe")

    touch("not_exe")
    assert not is_exe("not_exe")

    os.mkdir("exe_dir")
    chmod_plus_x("exe_dir")
    assert not is_exe("exe_dir")
示例#6
0
def zip_fixture():
    with temporary_dir() as target_dir:
        one = os.path.join(target_dir, "one")
        touch(one)

        two = os.path.join(target_dir, "two")
        touch(two)
        chmod_plus_x(two)

        assert extract_perms(one) != extract_perms(two)

        zip_file = os.path.join(target_dir, "test.zip")
        with contextlib.closing(PermPreservingZipFile(zip_file, "w")) as zf:
            zf.write(one, "one")
            zf.write(two, "two")

        yield zip_file, os.path.join(target_dir, "extract"), one, two
示例#7
0
文件: test_common.py 项目: tdyas/pex
def zip_fixture():
  with temporary_dir() as target_dir:
    one = os.path.join(target_dir, 'one')
    touch(one)

    two = os.path.join(target_dir, 'two')
    touch(two)
    chmod_plus_x(two)

    assert extract_perms(one) != extract_perms(two)

    zip_file = os.path.join(target_dir, 'test.zip')
    with contextlib.closing(PermPreservingZipFile(zip_file, 'w')) as zf:
      zf.write(one, 'one')
      zf.write(two, 'two')

    yield zip_file, os.path.join(target_dir, 'extract'), one, two
示例#8
0
def zip_fixture():
  with temporary_dir() as target_dir:
    one = os.path.join(target_dir, 'one')
    touch(one)

    two = os.path.join(target_dir, 'two')
    touch(two)
    chmod_plus_x(two)

    assert extract_perms(one) != extract_perms(two)

    zip_file = os.path.join(target_dir, 'test.zip')
    with contextlib.closing(PermPreservingZipFile(zip_file, 'w')) as zf:
      zf.write(one, 'one')
      zf.write(two, 'two')

    yield zip_file, os.path.join(target_dir, 'extract'), one, two
示例#9
0
    def build(self,
              filename,
              bytecode_compile=True,
              deterministic_timestamp=False):
        """Package the PEX into a zipfile.

        :param filename: The filename where the PEX should be stored.
        :param bytecode_compile: If True, precompile .py files into .pyc files.
        :param deterministic_timestamp: If True, will use our hardcoded time for zipfile timestamps.

        If the PEXBuilder is not yet frozen, it will be frozen by ``build``.  This renders the
        PEXBuilder immutable.
        """
        if not self._frozen:
            self.freeze(bytecode_compile=bytecode_compile)
        tmp_zip = filename + "~"
        try:
            os.unlink(tmp_zip)
            self._logger.warning(
                "Previous binary unexpectedly exists, cleaning: {}".format(
                    tmp_zip))
        except OSError:
            # The expectation is that the file does not exist, so continue
            pass
        with safe_open(tmp_zip, "ab") as pexfile:
            assert os.path.getsize(pexfile.name) == 0
            pexfile.write(to_bytes("{}\n".format(self._shebang)))
        with TRACER.timed("Zipping PEX file."):
            self._chroot.zip(
                tmp_zip,
                mode="a",
                deterministic_timestamp=deterministic_timestamp,
                # When configured with a `copy_mode` of `CopyMode.SYMLINK`, we symlink distributions
                # as pointers to installed wheel directories in ~/.pex/installed_wheels/... Since
                # those installed wheels reside in a shared cache, they can be in-use by other
                # processes and so their code may be in the process of being bytecode compiled as we
                # attempt to zip up our chroot. Bytecode compilation produces ephemeral temporary
                # pyc files that we should avoid copying since they are unuseful and inherently
                # racy.
                exclude_file=is_pyc_temporary_file,
            )
        if os.path.exists(filename):
            os.unlink(filename)
        os.rename(tmp_zip, filename)
        chmod_plus_x(filename)
示例#10
0
def assert_chroot_perms(copyfn):
  with temporary_dir() as src:
    one = os.path.join(src, 'one')
    touch(one)

    two = os.path.join(src, 'two')
    touch(two)
    chmod_plus_x(two)

    with temporary_dir() as dst:
      chroot = Chroot(dst)
      copyfn(chroot, one, 'one')
      copyfn(chroot, two, 'two')
      assert extract_perms(one) == extract_perms(os.path.join(chroot.path(), 'one'))
      assert extract_perms(two) == extract_perms(os.path.join(chroot.path(), 'two'))

      zip_path = os.path.join(src, 'chroot.zip')
      chroot.zip(zip_path)
      with temporary_dir() as extract_dir:
        with contextlib.closing(PermPreservingZipFile(zip_path)) as zf:
          zf.extractall(extract_dir)

          assert extract_perms(one) == extract_perms(os.path.join(extract_dir, 'one'))
          assert extract_perms(two) == extract_perms(os.path.join(extract_dir, 'two'))
示例#11
0
def populate_venv_with_pex(
        venv,  # type: Virtualenv
        pex,  # type: PEX
        bin_path=BinPath.FALSE,  # type: BinPath.Value
        python=None,  # type: Optional[str]
        collisions_ok=True,  # type: bool
):
    # type: (...) -> str

    venv_python = python or venv.interpreter.binary
    venv_bin_dir = os.path.dirname(python) if python else venv.bin_dir
    venv_dir = os.path.dirname(venv_bin_dir) if python else venv.venv_dir

    # 1. Populate the venv with the PEX contents.
    provenance = defaultdict(list)

    def record_provenance(src_to_dst):
        # type: (Iterable[Tuple[str, str]]) -> None
        for src, dst in src_to_dst:
            provenance[dst].append(src)

    pex_info = pex.pex_info()
    if zipfile.is_zipfile(pex.path()):
        record_provenance(
            PEXEnvironment(pex.path()).explode_code(venv.site_packages_dir,
                                                    exclude=("__main__.py", )))
    else:
        record_provenance(
            _copytree(
                src=pex.path(),
                dst=venv.site_packages_dir,
                exclude=(pex_info.internal_cache, pex_builder.BOOTSTRAP_DIR,
                         "__main__.py"),
            ))

    for dist in pex.activate():
        record_provenance(
            _copytree(src=dist.location,
                      dst=venv.site_packages_dir,
                      exclude=("bin", )))
        dist_bin_dir = os.path.join(dist.location, "bin")
        if os.path.isdir(dist_bin_dir):
            record_provenance(_copytree(dist_bin_dir, venv.bin_dir))

    collisions = {
        dst: srcs
        for dst, srcs in provenance.items() if len(srcs) > 1
    }
    if collisions:
        message_lines = [
            "Encountered {collision} building venv at {venv_dir} from {pex}:".
            format(collision=pluralize(collisions, "collision"),
                   venv_dir=venv_dir,
                   pex=pex.path())
        ]
        for index, (dst, srcs) in enumerate(collisions.items(), start=1):
            message_lines.append(
                "{index}. {dst} was provided by:\n\t{srcs}".format(
                    index=index, dst=dst, srcs="\n\t".join(srcs)))
        message = "\n".join(message_lines)
        if not collisions_ok:
            raise CollisionError(message)
        pex_warnings.warn(message)

    # 2. Add a __main__ to the root of the venv for running the venv dir like a loose PEX dir
    # and a main.py for running as a script.
    shebang = "#!{} -sE".format(venv_python)
    main_contents = dedent("""\
        {shebang}

        if __name__ == "__main__":
            import os
            import sys

            venv_dir = os.path.abspath(os.path.dirname(__file__))
            venv_bin_dir = os.path.join(venv_dir, "bin")
            shebang_python = {shebang_python!r}
            python = os.path.join(venv_bin_dir, os.path.basename(shebang_python))
            if sys.executable not in (python, shebang_python):
                sys.stderr.write("Re-execing from {{}}\\n".format(sys.executable))
                os.execv(python, [python, "-sE"] + sys.argv)

            os.environ["VIRTUAL_ENV"] = venv_dir
            sys.path.extend(os.environ.get("PEX_EXTRA_SYS_PATH", "").split(os.pathsep))

            bin_path = os.environ.get("PEX_VENV_BIN_PATH", {bin_path!r})
            if bin_path != "false":
                PATH = os.environ.get("PATH", "").split(os.pathsep)
                if bin_path == "prepend":
                    PATH.insert(0, venv_bin_dir)
                elif bin_path == "append":
                    PATH.append(venv_bin_dir)
                else:
                    sys.stderr.write(
                        "PEX_VENV_BIN_PATH must be one of 'false', 'prepend' or 'append', given: "
                        "{{!r}}\\n".format(
                            bin_path
                        )
                    )
                    sys.exit(1)
                os.environ["PATH"] = os.pathsep.join(PATH)

            PEX_EXEC_OVERRIDE_KEYS = ("PEX_INTERPRETER", "PEX_SCRIPT", "PEX_MODULE")
            pex_overrides = {{
                key: os.environ.pop(key) for key in PEX_EXEC_OVERRIDE_KEYS if key in os.environ
            }}
            if len(pex_overrides) > 1:
                sys.stderr.write(
                    "Can only specify one of {{overrides}}; found: {{found}}\\n".format(
                        overrides=", ".join(PEX_EXEC_OVERRIDE_KEYS),
                        found=" ".join("{{}}={{}}".format(k, v) for k, v in pex_overrides.items())
                    )
                )
                sys.exit(1)

            pex_script = pex_overrides.get("PEX_SCRIPT")
            if pex_script:
                script_path = os.path.join(venv_bin_dir, pex_script)
                os.execv(script_path, [script_path] + sys.argv[1:])

            pex_interpreter = pex_overrides.get("PEX_INTERPRETER", "").lower() in ("1", "true")
            PEX_INTERPRETER_ENTRYPOINT = "code:interact"
            entry_point = (
                PEX_INTERPRETER_ENTRYPOINT
                if pex_interpreter
                else pex_overrides.get("PEX_MODULE", {entry_point!r} or PEX_INTERPRETER_ENTRYPOINT)
            )
            if entry_point == PEX_INTERPRETER_ENTRYPOINT and len(sys.argv) > 1:
                args = sys.argv[1:]
                arg = args[0]
                if arg == "-m":
                    if len(args) < 2:
                        sys.stderr.write("Argument expected for the -m option\\n")
                        sys.exit(2)
                    entry_point = module = args[1]
                    sys.argv = args[1:]
                    # Fall through to entry_point handling below.
                else:
                    filename = arg
                    sys.argv = args
                    if arg == "-c":
                        if len(args) < 2:
                            sys.stderr.write("Argument expected for the -c option\\n")
                            sys.exit(2)
                        filename = "-c <cmd>"
                        content = args[1]
                        sys.argv = ["-c"] + args[2:]
                    elif arg == "-":
                        content = sys.stdin.read()
                    else:
                        with open(arg) as fp:
                            content = fp.read()

                    ast = compile(content, filename, "exec", flags=0, dont_inherit=1)
                    globals_map = globals().copy()
                    globals_map["__name__"] = "__main__"
                    globals_map["__file__"] = filename
                    locals_map = globals_map
                    {exec_ast}
                    sys.exit(0)

            module_name, _, function = entry_point.partition(":")
            if not function:
                import runpy
                runpy.run_module(module_name, run_name="__main__")
            else:
                import importlib
                module = importlib.import_module(module_name)
                # N.B.: Functions may be hung off top-level objects in the module namespace,
                # e.g.: Class.method; so we drill down through any attributes to the final function
                # object.
                namespace, func = module, None
                for attr in function.split("."):
                    func = namespace = getattr(namespace, attr)
                sys.exit(func())
        """.format(
        shebang=shebang,
        shebang_python=venv_python,
        bin_path=bin_path,
        entry_point=pex_info.entry_point,
        exec_ast=("exec ast in globals_map, locals_map"
                  if venv.interpreter.version[0] == 2 else
                  "exec(ast, globals_map, locals_map)"),
    ))
    with open(venv.join_path("__main__.py"), "w") as fp:
        fp.write(main_contents)
    chmod_plus_x(fp.name)
    os.symlink(os.path.basename(fp.name), venv.join_path("pex"))

    # 3. Re-write any (console) scripts to use the venv Python.
    for script in venv.rewrite_scripts(python=venv_python, python_args="-sE"):
        TRACER.log("Re-writing {}".format(script))

    return shebang