示例#1
0
文件: test_util.py 项目: jjhelmus/pex
def test_dir_hash():
    # type: () -> None
    with temporary_dir() as tmp_dir:
        safe_mkdir(os.path.join(tmp_dir, "a", "b"))
        with safe_open(os.path.join(tmp_dir, "c", "d", "e.py"), "w") as fp:
            fp.write("contents1")
        with safe_open(os.path.join(tmp_dir, "f.py"), "w") as fp:
            fp.write("contents2")
        hash1 = CacheHelper.dir_hash(tmp_dir)

        os.rename(os.path.join(tmp_dir, "c"),
                  os.path.join(tmp_dir, "c-renamed"))
        assert hash1 != CacheHelper.dir_hash(tmp_dir)

        os.rename(os.path.join(tmp_dir, "c-renamed"),
                  os.path.join(tmp_dir, "c"))
        assert hash1 == CacheHelper.dir_hash(tmp_dir)

        touch(os.path.join(tmp_dir, "c", "d", "e.pyc"))
        assert hash1 == CacheHelper.dir_hash(tmp_dir)
        touch(os.path.join(tmp_dir, "c", "d", "e.pyc.123456789"))
        assert hash1 == CacheHelper.dir_hash(tmp_dir)

        pycache_dir = os.path.join(tmp_dir, "__pycache__")
        safe_mkdir(pycache_dir)
        touch(os.path.join(pycache_dir, "f.pyc"))
        assert hash1 == CacheHelper.dir_hash(tmp_dir)
        touch(os.path.join(pycache_dir, "f.pyc.123456789"))
        assert hash1 == CacheHelper.dir_hash(tmp_dir)

        touch(os.path.join(pycache_dir, "f.py"))
        assert hash1 == CacheHelper.dir_hash(
            tmp_dir
        ), "All content under __pycache__ directories should be ignored."
示例#2
0
  def _add_dist_zip(self, path, dist_name):
    # We need to distinguish between wheels and other zips. Most of the time,
    # when we have a zip, it contains its contents in an importable form.
    # But wheels don't have to be importable, so we need to force them
    # into an importable shape. We can do that by installing it into its own
    # wheel dir.
    if dist_name.endswith("whl"):
      from pex.third_party.wheel.install import WheelFile
      tmp = safe_mkdtemp()
      whltmp = os.path.join(tmp, dist_name)
      os.mkdir(whltmp)
      wf = WheelFile(path)
      wf.install(overrides=self._get_installer_paths(whltmp), force=True)
      for root, _, files in os.walk(whltmp):
        pruned_dir = os.path.relpath(root, tmp)
        for f in files:
          fullpath = os.path.join(root, f)
          target = os.path.join(self._pex_info.internal_cache, pruned_dir, f)
          self._copy_or_link(fullpath, target)
      return CacheHelper.dir_hash(whltmp)

    with open_zip(path) as zf:
      for name in zf.namelist():
        if name.endswith('/'):
          continue
        target = os.path.join(self._pex_info.internal_cache, dist_name, name)
        self._chroot.write(zf.read(name), target)
      return CacheHelper.zip_hash(zf)
示例#3
0
    def _add_dist_zip(self, path, dist_name):
        # We need to distinguish between wheels and other zips. Most of the time,
        # when we have a zip, it contains its contents in an importable form.
        # But wheels don't have to be importable, so we need to force them
        # into an importable shape. We can do that by installing it into its own
        # wheel dir.
        if dist_name.endswith("whl"):
            from pex.third_party.wheel.install import WheelFile
            tmp = safe_mkdtemp()
            whltmp = os.path.join(tmp, dist_name)
            os.mkdir(whltmp)
            wf = WheelFile(path)
            wf.install(overrides=self._get_installer_paths(whltmp), force=True)
            for root, _, files in os.walk(whltmp):
                pruned_dir = os.path.relpath(root, tmp)
                for f in files:
                    fullpath = os.path.join(root, f)
                    target = os.path.join(self._pex_info.internal_cache,
                                          pruned_dir, f)
                    self._copy_or_link(fullpath, target)
            return CacheHelper.dir_hash(whltmp)

        with open_zip(path) as zf:
            for name in zf.namelist():
                if name.endswith('/'):
                    continue
                target = os.path.join(self._pex_info.internal_cache, dist_name,
                                      name)
                self._chroot.write(zf.read(name), target)
            return CacheHelper.zip_hash(zf)
示例#4
0
  def finalize_install(self, install_requests):
    self.atomic_dir.finalize()

    # The install_chroot is keyed by the hash of the wheel file (zip) we installed. Here we add a
    # key by the hash of the exploded wheel dir (the install_chroot). This latter key is used by
    # zipped PEXes at runtime to explode their wheel chroots to the filesystem. By adding the key
    # here we short-circuit the explode process for PEXes created and run on the same machine.
    #
    # From a clean cache after building a simple pex this looks like:
    # $ rm -rf ~/.pex
    # $ python -mpex -c pex -o /tmp/pex.pex .
    # $ tree -L 4 ~/.pex/
    # /home/jsirois/.pex/
    # ├── built_wheels
    # │   └── 1003685de2c3604dc6daab9540a66201c1d1f718
    # │       └── cp-38-cp38
    # │           └── pex-2.0.2-py2.py3-none-any.whl
    # └── installed_wheels
    #     ├── 2a594cef34d2e9109bad847358d57ac4615f81f4
    #     │   └── pex-2.0.2-py2.py3-none-any.whl
    #     │       ├── bin
    #     │       ├── pex
    #     │       └── pex-2.0.2.dist-info
    #     └── ae13cba3a8e50262f4d730699a11a5b79536e3e1
    #         └── pex-2.0.2-py2.py3-none-any.whl -> /home/jsirois/.pex/installed_wheels/2a594cef34d2e9109bad847358d57ac4615f81f4/pex-2.0.2-py2.py3-none-any.whl  # noqa
    #
    # 11 directories, 1 file
    #
    # And we see in the created pex, the runtime key that the layout above satisfies:
    # $ unzip -qc /tmp/pex.pex PEX-INFO | jq .distributions
    # {
    #   "pex-2.0.2-py2.py3-none-any.whl": "ae13cba3a8e50262f4d730699a11a5b79536e3e1"
    # }
    #
    # When the pex is run, the runtime key is followed to the build time key, avoiding re-unpacking
    # the wheel:
    # $ PEX_VERBOSE=1 /tmp/pex.pex --version
    # pex: Found site-library: /usr/lib/python3.8/site-packages
    # pex: Tainted path element: /usr/lib/python3.8/site-packages
    # pex: Scrubbing from user site: /home/jsirois/.local/lib/python3.8/site-packages
    # pex: Scrubbing from site-packages: /usr/lib/python3.8/site-packages
    # pex: Activating PEX virtual environment from /tmp/pex.pex: 9.1ms
    # pex: Bootstrap complete, performing final sys.path modifications...
    # pex: PYTHONPATH contains:
    # pex:     /tmp/pex.pex
    # pex:   * /usr/lib/python38.zip
    # pex:     /usr/lib/python3.8
    # pex:     /usr/lib/python3.8/lib-dynload
    # pex:     /home/jsirois/.pex/installed_wheels/2a594cef34d2e9109bad847358d57ac4615f81f4/pex-2.0.2-py2.py3-none-any.whl  # noqa
    # pex:   * /tmp/pex.pex/.bootstrap
    # pex:   * - paths that do not exist or will be imported via zipimport
    # pex.pex 2.0.2
    #
    wheel_dir_hash = CacheHelper.dir_hash(self.install_chroot)
    runtime_key_dir = os.path.join(self.installation_root, wheel_dir_hash)
    with atomic_directory(runtime_key_dir) as work_dir:
      if work_dir:
        os.symlink(self.install_chroot, os.path.join(work_dir, self.request.wheel_file))

    return self._iter_requirements_requests(install_requests)
示例#5
0
 def _add_dist_dir(self, path, dist_name):
   for root, _, files in os.walk(path):
     for f in files:
       filename = os.path.join(root, f)
       relpath = os.path.relpath(filename, path)
       target = os.path.join(self._pex_info.internal_cache, dist_name, relpath)
       self._copy_or_link(filename, target)
   return CacheHelper.dir_hash(path)
示例#6
0
 def _add_dist_dir(self, path, dist_name):
   for root, _, files in os.walk(path):
     for f in files:
       filename = os.path.join(root, f)
       relpath = os.path.relpath(filename, path)
       target = os.path.join(self._pex_info.internal_cache, dist_name, relpath)
       self._copy_or_link(filename, target)
   return CacheHelper.dir_hash(path)
示例#7
0
文件: __init__.py 项目: meg23/pex
def isolated():
    """Returns a chroot for third_party isolated from the ``sys.path``.

    PEX will typically be installed in site-packages flat alongside many other distributions; as such,
    adding the location of the pex distribution to the ``sys.path`` will typically expose many other
    distributions. An isolated chroot can be used as a ``sys.path`` entry to effect only the exposure
    of pex.

    :return: An isolation result.
    :rtype: :class:`IsolationResult`
    """
    global _ISOLATED
    if _ISOLATED is None:
        from pex import vendor
        from pex.common import atomic_directory
        from pex.util import CacheHelper
        from pex.variables import ENV
        from pex.third_party.pkg_resources import resource_isdir, resource_listdir, resource_stream

        module = "pex"

        # TODO(John Sirois): Unify with `pex.util.DistributionHelper.access_zipped_assets`.
        def recursive_copy(srcdir, dstdir):
            os.mkdir(dstdir)
            for entry_name in resource_listdir(module, srcdir):
                if not entry_name:
                    # The `resource_listdir` function returns a '' entry name for the directory
                    # entry itself if it is either present on the filesystem or present as an
                    # explicit zip entry. Since we only care about files and subdirectories at this
                    # point, skip these entries.
                    continue
                # NB: Resource path components are always separated by /, on all systems.
                src_entry = "{}/{}".format(
                    srcdir, entry_name) if srcdir else entry_name
                dst_entry = os.path.join(dstdir, entry_name)
                if resource_isdir(module, src_entry):
                    recursive_copy(src_entry, dst_entry)
                elif not entry_name.endswith(".pyc"):
                    with open(dst_entry, "wb") as fp:
                        with closing(resource_stream(module,
                                                     src_entry)) as resource:
                            shutil.copyfileobj(resource, fp)

        pex_path = os.path.join(vendor.VendorSpec.ROOT, "pex")
        with _tracer().timed("Hashing pex"):
            dir_hash = CacheHelper.dir_hash(pex_path)
        isolated_dir = os.path.join(ENV.PEX_ROOT, "isolated", dir_hash)

        with _tracer().timed("Isolating pex"):
            with atomic_directory(isolated_dir, exclusive=True) as chroot:
                if chroot:
                    with _tracer().timed(
                            "Extracting pex to {}".format(isolated_dir)):
                        recursive_copy("", os.path.join(chroot, "pex"))

        _ISOLATED = IsolationResult(pex_hash=dir_hash,
                                    chroot_path=isolated_dir)
    return _ISOLATED
示例#8
0
文件: test_util.py 项目: mikekap/pex
def test_hash_consistency():
  for reverse in (False, True):
    with temporary_content(CONTENT) as td:
      dir_hash = CacheHelper.dir_hash(td)
      with named_temporary_file() as tf:
        write_zipfile(td, tf.name, reverse=reverse)
        with contextlib.closing(zipfile.ZipFile(tf.name, 'r')) as zf:
          zip_hash = CacheHelper.zip_hash(zf)
          assert zip_hash == dir_hash
          assert zip_hash != sha1().hexdigest()  # make sure it's not an empty hash
示例#9
0
def test_hash_consistency():
  for reverse in (False, True):
    with temporary_content(CONTENT) as td:
      dir_hash = CacheHelper.dir_hash(td)
      with named_temporary_file() as tf:
        write_zipfile(td, tf.name, reverse=reverse)
        with open_zip(tf.name, 'r') as zf:
          zip_hash = CacheHelper.zip_hash(zf)
          assert zip_hash == dir_hash
          assert zip_hash != sha1().hexdigest()  # make sure it's not an empty hash
示例#10
0
 def _add_dist_dir(self, path, dist_name):
     target_dir = os.path.join(self._pex_info.internal_cache, dist_name)
     if self._copy_mode == CopyMode.SYMLINK:
         self._copy_or_link(path, target_dir)
     else:
         for root, _, files in os.walk(path):
             for f in files:
                 filename = os.path.join(root, f)
                 relpath = os.path.relpath(filename, path)
                 target = os.path.join(target_dir, relpath)
                 self._copy_or_link(filename, target)
     return CacheHelper.dir_hash(path)
示例#11
0
def isolated():
    """Returns a chroot for third_party isolated from the ``sys.path``.

  PEX will typically be installed in site-packages flat alongside many other distributions; as such,
  adding the location of the pex distribution to the ``sys.path`` will typically expose many other
  distributions. An isolated chroot can be used as a ``sys.path`` entry to effect only the exposure
  of pex.

  :return: An isolation result.
  :rtype: :class:`IsolationResult`
  """
    global _ISOLATED
    if _ISOLATED is None:
        from pex import vendor
        from pex.common import atomic_directory
        from pex.util import CacheHelper
        from pex.variables import ENV
        from pex.third_party.pkg_resources import resource_isdir, resource_listdir, resource_stream

        module = 'pex'

        def recursive_copy(srcdir, dstdir):
            os.mkdir(dstdir)
            for entry_name in resource_listdir(module, srcdir):
                # NB: Resource path components are always separated by /, on all systems.
                src_entry = '{}/{}'.format(
                    srcdir, entry_name) if srcdir else entry_name
                dst_entry = os.path.join(dstdir, entry_name)
                if resource_isdir(module, src_entry):
                    recursive_copy(src_entry, dst_entry)
                elif not entry_name.endswith('.pyc'):
                    with open(dst_entry, 'wb') as fp:
                        shutil.copyfileobj(resource_stream(module, src_entry),
                                           fp)

        pex_path = os.path.join(vendor.VendorSpec.ROOT, 'pex')
        with _tracer().timed('Hashing pex'):
            dir_hash = CacheHelper.dir_hash(pex_path)
        isolated_dir = os.path.join(ENV.PEX_ROOT, 'isolated', dir_hash)

        with _tracer().timed('Isolating pex'):
            with atomic_directory(isolated_dir) as chroot:
                if chroot:
                    with _tracer().timed(
                            'Extracting pex to {}'.format(isolated_dir)):
                        recursive_copy('', os.path.join(chroot, 'pex'))

        _ISOLATED = IsolationResult(pex_hash=dir_hash,
                                    chroot_path=isolated_dir)
    return _ISOLATED
示例#12
0
文件: __init__.py 项目: slyphon/pex
def isolated():
    """Returns a chroot for third_party isolated from the ``sys.path``.

  PEX will typically be installed in site-packages flat alongside many other distributions; as such,
  adding the location of the pex distribution to the ``sys.path`` will typically expose many other
  distributions. An isolated chroot can be used as a ``sys.path`` entry to effect only the exposure
  of pex.

  :return: The path of the chroot.
  :rtype: str
  """
    global _ISOLATED
    if _ISOLATED is None:
        from pex import vendor
        from pex.common import atomic_directory, safe_copy
        from pex.util import CacheHelper
        from pex.variables import ENV

        pex_path = os.path.join(vendor.VendorSpec.ROOT, 'pex')
        with _tracer().timed('Isolating pex'):
            isolated_dir = os.path.join(ENV.PEX_ROOT, 'isolated',
                                        CacheHelper.dir_hash(pex_path))
            with atomic_directory(isolated_dir) as chroot:
                if chroot:
                    with _tracer().timed(
                            'Extracting pex to {}'.format(isolated_dir)):
                        pex_path = os.path.join(vendor.VendorSpec.ROOT, 'pex')
                        for root, dirs, files in os.walk(pex_path):
                            relroot = os.path.relpath(root, pex_path)
                            for d in dirs:
                                os.makedirs(
                                    os.path.join(chroot, 'pex', relroot, d))
                            for f in files:
                                if not f.endswith('.pyc'):
                                    safe_copy(
                                        os.path.join(root, f),
                                        os.path.join(chroot, 'pex', relroot,
                                                     f))

        _ISOLATED = isolated_dir
    return _ISOLATED