diff options
Diffstat (limited to 'src/virtualenv/util/path/_sync.py')
| -rw-r--r-- | src/virtualenv/util/path/_sync.py | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/src/virtualenv/util/path/_sync.py b/src/virtualenv/util/path/_sync.py new file mode 100644 index 0000000..c3d6111 --- /dev/null +++ b/src/virtualenv/util/path/_sync.py @@ -0,0 +1,50 @@ +from __future__ import absolute_import, unicode_literals + +import logging +import os +import shutil +from functools import partial + +import six + +HAS_SYMLINK = hasattr(os, "symlink") + + +def ensure_dir(path): + if not path.exists(): + logging.debug("created %s", six.ensure_text(str(path))) + os.makedirs(six.ensure_text(str(path))) + + +def symlink_or_copy(do_copy, src, dst, relative_symlinks_ok=False): + """ + Try symlinking a target, and if that fails, fall back to copying. + """ + if do_copy is False and HAS_SYMLINK is False: # if no symlink, always use copy + do_copy = True + if not do_copy: + try: + if not dst.is_symlink(): # can't link to itself! + if relative_symlinks_ok: + assert src.parent == dst.parent + os.symlink(six.ensure_text(src.name), six.ensure_text(str(dst))) + else: + os.symlink(six.ensure_text(str(src)), six.ensure_text(str(dst))) + except OSError as exception: + logging.warning( + "symlink failed %r, for %s to %s, will try copy", + exception, + six.ensure_text(str(src)), + six.ensure_text(str(dst)), + ) + do_copy = True + if do_copy: + copier = shutil.copy2 if src.is_file() else shutil.copytree + copier(six.ensure_text(str(src)), six.ensure_text(str(dst))) + logging.debug("%s %s to %s", "copy" if do_copy else "symlink", six.ensure_text(str(src)), six.ensure_text(str(dst))) + + +symlink = partial(symlink_or_copy, False) +copy = partial(symlink_or_copy, True) + +__all__ = ("ensure_dir", "symlink", "copy", "symlink_or_copy") |
