Let walk_generator follow links, add skip_symlinks to copy_dir.
This commit is contained in:
parent
5e5f55cf1f
commit
9ef8254191
1 changed files with 38 additions and 24 deletions
|
@ -100,6 +100,7 @@ def copy_dir(
|
|||
files_per_second=None,
|
||||
overwrite_old=True,
|
||||
precalcsize=False,
|
||||
skip_symlinks=True,
|
||||
stop_event=None,
|
||||
validate_hash=False,
|
||||
):
|
||||
|
@ -169,6 +170,8 @@ def copy_dir(
|
|||
bytes (showing 100% always).
|
||||
This may take a while if the source directory is large.
|
||||
|
||||
skip_symlinks:
|
||||
If True, symlink dirs are skipped and symlink files are not copied.
|
||||
|
||||
stop_event:
|
||||
If provided, a threading.Event object which when set indicates that we
|
||||
|
@ -220,34 +223,45 @@ def copy_dir(
|
|||
callback_exclusion=callback_exclusion,
|
||||
exclude_directories=exclude_directories,
|
||||
exclude_filenames=exclude_filenames,
|
||||
yield_style='nested',
|
||||
)
|
||||
for source_file in walker:
|
||||
if stop_event and stop_event.is_set():
|
||||
break
|
||||
|
||||
if source_file.is_link:
|
||||
def denester(walker):
|
||||
for (directory, children, files) in walker:
|
||||
if skip_symlinks and directory.is_link:
|
||||
continue
|
||||
|
||||
# The source abspath will only end in os.sep if it is the drive root.
|
||||
# Non-root folders already have their trailing slash stripped by
|
||||
# pathclass. Using rstrip helps us make the following transformation:
|
||||
# source: A:\
|
||||
# destination: B:\backup
|
||||
# destination_new_root: B:\backup
|
||||
# A:\myfile.txt
|
||||
# -> replace(A:, B:\backup\A)
|
||||
# -> B:\backup\A\myfile.txt
|
||||
#
|
||||
# Without disturbing the other case in which source is not drive root.
|
||||
# source: A:\Documents
|
||||
# destination: B:\backup\A\Documents
|
||||
# destination_new_root: B:\backup\A\Documents
|
||||
# A:\Documents\myfile.txt
|
||||
# -> replace(A:\Documents, B:\backup\A\Documents)
|
||||
# -> B:\backup\A\Documents\myfile.txt
|
||||
destination_file = pathclass.Path(source_file.absolute_path.replace(
|
||||
destination_dir = pathclass.Path(directory.absolute_path.replace(
|
||||
source.absolute_path.rstrip(os.sep),
|
||||
destination.absolute_path,
|
||||
1
|
||||
))
|
||||
destination_files = (destination_dir.with_child(file.basename) for file in files)
|
||||
for (source_file, destination_file) in zip(files, destination_files):
|
||||
yield (source_file, destination_file)
|
||||
|
||||
walker = denester(walker)
|
||||
|
||||
for (source_file, destination_file) in walker:
|
||||
if stop_event and stop_event.is_set():
|
||||
break
|
||||
|
||||
if skip_symlinks and source_file.is_link:
|
||||
continue
|
||||
|
||||
if destination_file.is_dir:
|
||||
raise DestinationIsDirectory(destination_file)
|
||||
|
@ -708,7 +722,7 @@ def walk_generator(
|
|||
|
||||
yield pathclass.Path(child_file_abspath)
|
||||
|
||||
walker = os.walk(path.absolute_path, onerror=callback_permission_denied)
|
||||
walker = os.walk(path.absolute_path, onerror=callback_permission_denied, followlinks=True)
|
||||
if yield_style == 'flat':
|
||||
for step in walker:
|
||||
yield from walkstep_flat(*step)
|
||||
|
|
Loading…
Reference in a new issue