in src/python/pants/util/dirutil.py [0:0]
def mergetree(src, dst, symlinks=False, ignore=None, file_filter=None):
"""Just like `shutil.copytree`, except the `dst` dir may exist.
The `src` directory will be walked and its contents copied into `dst`. If `dst` already exists the
`src` tree will be overlayed in it; ie: existing files in `dst` will be over-written with files
from `src` when they have the same subtree path.
"""
safe_mkdir(dst)
if not file_filter:
file_filter = lambda _: True
for src_path, dirnames, filenames in safe_walk(src, topdown=True, followlinks=True):
ignorenames = ()
if ignore:
to_ignore = ignore(src_path, dirnames + filenames)
if to_ignore:
ignorenames = frozenset(to_ignore)
src_relpath = os.path.relpath(src_path, src)
dst_path = os.path.join(dst, src_relpath)
visit_dirs = []
for dirname in dirnames:
if dirname in ignorenames:
continue
src_dir = os.path.join(src_path, dirname)
dst_dir = os.path.join(dst_path, dirname)
if os.path.exists(dst_dir):
if not os.path.isdir(dst_dir):
raise ExistingFileError('While copying the tree at {} to {}, encountered directory {} in '
'the source tree that already exists in the destination as a '
'non-directory.'.format(src, dst, dst_dir))
visit_dirs.append(dirname)
elif symlinks and os.path.islink(src_dir):
link = os.readlink(src_dir)
os.symlink(link, dst_dir)
# We need to halt the walk at a symlink dir; so we do not place dirname in visit_dirs
# here.
else:
os.makedirs(dst_dir)
visit_dirs.append(dirname)
# In-place mutate dirnames to halt the walk when the dir is ignored by the caller.
dirnames[:] = visit_dirs
for filename in filenames:
if filename in ignorenames:
continue
src_file_relpath = os.path.join(src_relpath, filename)
if not file_filter(src_file_relpath):
continue
dst_filename = os.path.join(dst_path, filename)
if os.path.exists(dst_filename):
if not os.path.isfile(dst_filename):
raise ExistingDirError('While copying the tree at {} to {}, encountered file {} in the '
'source tree that already exists in the destination as a non-file.'
.format(src, dst, dst_filename))
else:
os.unlink(dst_filename)
src_filename = os.path.join(src_path, filename)
if symlinks and os.path.islink(src_filename):
link = os.readlink(src_filename)
os.symlink(link, dst_filename)
else:
shutil.copy2(src_filename, dst_filename)