Skip to content

Commit 01b1818

Browse files
author
willmcgugan@gmail.com
committed
adde utils.copydir_progress method
1 parent a16d951 commit 01b1818

3 files changed

Lines changed: 53 additions & 2 deletions

File tree

CHANGES.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@
8989
* Added archivefs to fs.contrib, contributed by btimby
9090
* Added some polish to fstree command and unicode box lines rather than ascii art
9191

92-
0.5:
92+
0.5.1:
9393

9494
* Fixed a hang bug in readline
95+
* Added copydir_progress to fs.utils
9596

fs/memoryfs.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,7 @@ def settimes(self, path, accessed_time=None, modified_time=None):
542542
@synchronize
543543
def _on_close_memory_file(self, open_file, path):
544544
dir_entry = self._get_dir_entry(path)
545-
if dir_entry is not None:
545+
if dir_entry is not None and open_file in dir_entry.open_files:
546546
dir_entry.open_files.remove(open_file)
547547

548548

fs/utils.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,56 @@ def copydir(fs1, fs2, create_destination=True, ignore_errors=False, chunk_size=6
258258
chunk_size=chunk_size)
259259

260260

261+
def copydir_progress(progress_callback, fs1, fs2, create_destination=True, ignore_errors=False, chunk_size=64*1024):
262+
"""
263+
Copies the contents of a directory from one fs to another, with a callback function to display progress.
264+
265+
`progress_callback` should be a function with two parameters; `step` and `num_steps`.
266+
267+
`num_steps` is the number of steps in the copy process, and `step` is the current step. `num_steps` may be None if the number
268+
of steps is still being calculated.
269+
270+
"""
271+
if isinstance(fs1, tuple):
272+
fs1, dir1 = fs1
273+
fs1 = fs1.opendir(dir1)
274+
if isinstance(fs2, tuple):
275+
fs2, dir2 = fs2
276+
if create_destination:
277+
fs2.makedir(dir2, allow_recreate=True, recursive=True)
278+
fs2 = fs2.opendir(dir2)
279+
280+
def do_callback(step, num_steps):
281+
try:
282+
progress_callback(step, num_steps)
283+
except:
284+
pass
285+
286+
do_callback(0, None)
287+
288+
file_count = 0
289+
copy_paths = []
290+
for dir_path, file_paths in fs1.walk():
291+
copy_paths.append((dir_path, file_paths))
292+
file_count += len(file_paths)
293+
do_callback(0, file_count)
294+
295+
step = 0
296+
for i, (dir_path, file_paths) in enumerate(copy_paths):
297+
try:
298+
fs2.makedir(dir_path, allow_recreate=True)
299+
for path in file_paths:
300+
copy_path = pathjoin(dir_path, path)
301+
with fs1.open(copy_path, 'rb') as src_file:
302+
fs2.setcontents(copy_path, src_file, chunk_size=chunk_size)
303+
step += 1
304+
except:
305+
if ignore_errors:
306+
continue
307+
raise
308+
do_callback(step, file_count)
309+
310+
261311
def remove_all(fs, path):
262312
"""Remove everything in a directory. Returns True if successful.
263313

0 commit comments

Comments
 (0)