Skip to content

Commit 224952c

Browse files
author
atollk
committed
Changes proposed by code review.
1 parent b4b3478 commit 224952c

File tree

8 files changed

+73
-45
lines changed

8 files changed

+73
-45
lines changed

fs/_bulk.py

Lines changed: 36 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@
1111

1212
from six.moves.queue import Queue
1313

14-
from .copy import copy_file_internal
14+
from .copy import copy_file_internal, copy_modified_time
1515
from .errors import BulkCopyFailed
16+
from .tools import copy_file_data
1617

1718
if typing.TYPE_CHECKING:
1819
from .base import FS
1920
from types import TracebackType
20-
from typing import List, Optional, Text, Type
21+
from typing import List, Optional, Text, Type, IO, Tuple
2122

2223

2324
class _Worker(threading.Thread):
@@ -55,40 +56,32 @@ def __call__(self):
5556
class _CopyTask(_Task):
5657
"""A callable that copies from one file another."""
5758

58-
def __init__(
59-
self,
60-
src_fs, # type: FS
61-
src_path, # type: Text
62-
dst_fs, # type: FS
63-
dst_path, # type: Text
64-
preserve_time, # type: bool
65-
):
66-
# type: (...) -> None
67-
self.src_fs = src_fs
68-
self.src_path = src_path
69-
self.dst_fs = dst_fs
70-
self.dst_path = dst_path
71-
self.preserve_time = preserve_time
59+
def __init__(self, src_file, dst_file):
60+
# type: (IO, IO) -> None
61+
self.src_file = src_file
62+
self.dst_file = dst_file
7263

7364
def __call__(self):
7465
# type: () -> None
75-
copy_file_internal(
76-
self.src_fs,
77-
self.src_path,
78-
self.dst_fs,
79-
self.dst_path,
80-
preserve_time=self.preserve_time,
81-
)
66+
try:
67+
copy_file_data(self.src_file, self.dst_file, chunk_size=1024 * 1024)
68+
finally:
69+
try:
70+
self.src_file.close()
71+
finally:
72+
self.dst_file.close()
8273

8374

8475
class Copier(object):
8576
"""Copy files in worker threads."""
8677

87-
def __init__(self, num_workers=4):
88-
# type: (int) -> None
78+
def __init__(self, num_workers=4, preserve_time=False):
79+
# type: (int, bool) -> None
8980
if num_workers < 0:
9081
raise ValueError("num_workers must be >= 0")
9182
self.num_workers = num_workers
83+
self.preserve_time = preserve_time
84+
self.all_tasks = [] # type: List[Tuple[FS, Text, FS, Text]]
9285
self.queue = None # type: Optional[Queue[_Task]]
9386
self.workers = [] # type: List[_Worker]
9487
self.errors = [] # type: List[Exception]
@@ -97,7 +90,7 @@ def __init__(self, num_workers=4):
9790
def start(self):
9891
"""Start the workers."""
9992
if self.num_workers:
100-
self.queue = Queue()
93+
self.queue = Queue(maxsize=self.num_workers)
10194
self.workers = [_Worker(self) for _ in range(self.num_workers)]
10295
for worker in self.workers:
10396
worker.start()
@@ -106,10 +99,18 @@ def start(self):
10699
def stop(self):
107100
"""Stop the workers (will block until they are finished)."""
108101
if self.running and self.num_workers:
102+
# Notify the workers that all tasks have arrived
103+
# and wait for them to finish.
109104
for _worker in self.workers:
110105
self.queue.put(None)
111106
for worker in self.workers:
112107
worker.join()
108+
109+
# If the "last modified" time is to be preserved, do it now.
110+
if self.preserve_time:
111+
for args in self.all_tasks:
112+
copy_modified_time(*args)
113+
113114
# Free up references held by workers
114115
del self.workers[:]
115116
self.queue.join()
@@ -139,8 +140,15 @@ def copy(self, src_fs, src_path, dst_fs, dst_path, preserve_time=False):
139140
if self.queue is None:
140141
# This should be the most performant for a single-thread
141142
copy_file_internal(
142-
src_fs, src_path, dst_fs, dst_path, preserve_time=preserve_time
143+
src_fs, src_path, dst_fs, dst_path, preserve_time=self.preserve_time
143144
)
144145
else:
145-
task = _CopyTask(src_fs, src_path, dst_fs, dst_path, preserve_time)
146+
self.all_tasks.append((src_fs, src_path, dst_fs, dst_path))
147+
src_file = src_fs.openbin(src_path, "r")
148+
try:
149+
dst_file = dst_fs.openbin(dst_path, "w")
150+
except Exception:
151+
src_file.close()
152+
raise
153+
task = _CopyTask(src_file, dst_file)
146154
self.queue.put(task)

fs/base.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import six
2323

2424
from . import copy, errors, fsencode, iotools, move, tools, walk, wildcard
25-
from .copy import copy_mtime
25+
from .copy import copy_modified_time
2626
from .glob import BoundGlobber
2727
from .mode import validate_open_mode
2828
from .path import abspath, join, normpath
@@ -426,7 +426,8 @@ def copy(
426426
with closing(self.open(src_path, "rb")) as read_file:
427427
# FIXME(@althonos): typing complains because open return IO
428428
self.upload(dst_path, read_file) # type: ignore
429-
copy_mtime(self, src_path, self, dst_path)
429+
if preserve_time:
430+
copy_modified_time(self, src_path, self, dst_path)
430431

431432
def copydir(
432433
self,
@@ -1150,12 +1151,15 @@ def move(self, src_path, dst_path, overwrite=False, preserve_time=False):
11501151
except OSError:
11511152
pass
11521153
else:
1154+
if preserve_time:
1155+
copy_modified_time(self, src_path, self, dst_path)
11531156
return
11541157
with self._lock:
11551158
with self.open(src_path, "rb") as read_file:
11561159
# FIXME(@althonos): typing complains because open return IO
11571160
self.upload(dst_path, read_file) # type: ignore
1158-
copy_mtime(self, src_path, self, dst_path)
1161+
if preserve_time:
1162+
copy_modified_time(self, src_path, self, dst_path)
11591163
self.remove(src_path)
11601164

11611165
def open(

fs/copy.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ def copy_file(
166166
else:
167167
with _src_fs.openbin(src_path) as read_file:
168168
_dst_fs.upload(dst_path, read_file)
169-
copy_mtime(_src_fs, src_path, _dst_fs, dst_path)
169+
copy_modified_time(_src_fs, src_path, _dst_fs, dst_path)
170170

171171

172172
def copy_file_internal(
@@ -207,7 +207,7 @@ def copy_file_internal(
207207
dst_fs.upload(dst_path, read_file)
208208

209209
if preserve_time:
210-
copy_mtime(src_fs, src_path, dst_fs, dst_path)
210+
copy_modified_time(src_fs, src_path, dst_fs, dst_path)
211211

212212

213213
def copy_file_if_newer(
@@ -334,10 +334,11 @@ def dst():
334334
from ._bulk import Copier
335335

336336
with src() as _src_fs, dst() as _dst_fs:
337-
_thread_safe = is_thread_safe(_src_fs, _dst_fs)
338-
copier = Copier(num_workers=workers if _thread_safe else 0)
339-
with copier:
340-
with _src_fs.lock(), _dst_fs.lock():
337+
with _src_fs.lock(), _dst_fs.lock():
338+
_thread_safe = is_thread_safe(_src_fs, _dst_fs)
339+
with Copier(
340+
num_workers=workers if _thread_safe else 0, preserve_time=preserve_time
341+
) as copier:
341342
_dst_fs.makedir(_dst_path, recreate=True)
342343
for dir_path, dirs, files in walker.walk(_src_fs, _src_path):
343344
copy_path = combine(_dst_path, frombase(_src_path, dir_path))
@@ -351,7 +352,6 @@ def dst():
351352
src_path,
352353
_dst_fs,
353354
dst_path,
354-
preserve_time=preserve_time,
355355
)
356356
on_copy(_src_fs, src_path, _dst_fs, dst_path)
357357
pass
@@ -408,7 +408,9 @@ def dst():
408408
with src() as _src_fs, dst() as _dst_fs:
409409
with _src_fs.lock(), _dst_fs.lock():
410410
_thread_safe = is_thread_safe(_src_fs, _dst_fs)
411-
with Copier(num_workers=workers if _thread_safe else 0) as copier:
411+
with Copier(
412+
num_workers=workers if _thread_safe else 0, preserve_time=preserve_time
413+
) as copier:
412414
_dst_fs.makedir(_dst_path, recreate=True)
413415
namespace = ("details", "modified")
414416
dst_state = {
@@ -445,12 +447,11 @@ def dst():
445447
dir_path,
446448
_dst_fs,
447449
copy_path,
448-
preserve_time=preserve_time,
449450
)
450451
on_copy(_src_fs, dir_path, _dst_fs, copy_path)
451452

452453

453-
def copy_mtime(
454+
def copy_modified_time(
454455
src_fs, # type: Union[FS, Text]
455456
src_path, # type: Text
456457
dst_fs, # type: Union[FS, Text]

fs/memoryfs.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
from . import errors
1717
from .base import FS
18+
from .copy import copy_modified_time
1819
from .enums import ResourceType, Seek
1920
from .info import Info
2021
from .mode import Mode
@@ -465,6 +466,9 @@ def move(self, src_path, dst_path, overwrite=False, preserve_time=False):
465466
dst_dir_entry.set_entry(dst_name, src_entry)
466467
src_dir_entry.remove_entry(src_name)
467468

469+
if preserve_time:
470+
copy_modified_time(self, src_path, self, dst_path)
471+
468472
def movedir(self, src_path, dst_path, create=False, preserve_time=False):
469473
src_dir, src_name = split(self.validatepath(src_path))
470474
dst_dir, dst_name = split(self.validatepath(dst_path))
@@ -484,6 +488,9 @@ def movedir(self, src_path, dst_path, create=False, preserve_time=False):
484488
dst_dir_entry.set_entry(dst_name, src_entry)
485489
src_dir_entry.remove_entry(src_name)
486490

491+
if preserve_time:
492+
copy_modified_time(self, src_path, self, dst_path)
493+
487494
def openbin(self, path, mode="r", buffering=-1, **options):
488495
# type: (Text, Text, int, **Any) -> BinaryIO
489496
_mode = Mode(mode)

fs/mirror.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,9 @@ def dst():
8787

8888
with src() as _src_fs, dst() as _dst_fs:
8989
_thread_safe = is_thread_safe(_src_fs, _dst_fs)
90-
with Copier(num_workers=workers if _thread_safe else 0) as copier:
90+
with Copier(
91+
num_workers=workers if _thread_safe else 0, preserve_time=preserve_time
92+
) as copier:
9193
with _src_fs.lock(), _dst_fs.lock():
9294
_mirror(
9395
_src_fs,

fs/osfs.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
from .mode import Mode, validate_open_mode
5050
from .errors import FileExpected, NoURL
5151
from ._url_tools import url_quote
52-
from .copy import copy_mtime
52+
from .copy import copy_modified_time
5353

5454
if typing.TYPE_CHECKING:
5555
from typing import (
@@ -454,7 +454,7 @@ def copy(self, src_path, dst_path, overwrite=False, preserve_time=False):
454454
sent = sendfile(fd_dst, fd_src, offset, maxsize)
455455
offset += sent
456456
if preserve_time:
457-
copy_mtime(self, src_path, self, dst_path)
457+
copy_modified_time(self, src_path, self, dst_path)
458458
except OSError as e:
459459
# the error is not a simple "sendfile not supported" error
460460
if e.errno not in self._sendfile_error_codes:

fs/wrapfs.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ def movedir(self, src_path, dst_path, create=False, preserve_time=False):
186186
raise errors.ResourceNotFound(dst_path)
187187
if not src_fs.getinfo(_src_path).is_dir:
188188
raise errors.DirectoryExpected(src_path)
189-
move_dir(src_fs, _src_path, dst_fs, _dst_path)
189+
move_dir(src_fs, _src_path, dst_fs, _dst_path, preserve_time=preserve_time)
190190

191191
def openbin(self, path, mode="r", buffering=-1, **options):
192192
# type: (Text, Text, int, **Any) -> BinaryIO

tests/test_move.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ def test_move_fs(self):
2121
src_file2_info = src_fs.getinfo("foo/bar/baz.txt", namespaces)
2222

2323
dst_fs = open_fs("mem://")
24+
dst_fs.create("test.txt")
25+
dst_fs.setinfo("test.txt", {"details": {"modified": 1000000}})
26+
2427
fs.move.move_fs(src_fs, dst_fs, preserve_time=self.preserve_time)
2528

2629
self.assertTrue(dst_fs.isdir("foo/bar"))
@@ -44,6 +47,9 @@ def test_move_dir(self):
4447
src_file2_info = src_fs.getinfo("foo/bar/baz.txt", namespaces)
4548

4649
dst_fs = open_fs("mem://")
50+
dst_fs.create("test.txt")
51+
dst_fs.setinfo("test.txt", {"details": {"modified": 1000000}})
52+
4753
fs.move.move_dir(src_fs, "/foo", dst_fs, "/", preserve_time=self.preserve_time)
4854

4955
self.assertTrue(dst_fs.isdir("bar"))

0 commit comments

Comments
 (0)