Skip to content

Commit

Permalink
copyfile update=True ignores files per mtime
Browse files Browse the repository at this point in the history
When update=True (regardless of the value of overwrite) then files are
only copied if the destination file does not exist or its modification
time is less than the source. Ie files are only overwritten when the
source file is considered newer than the destination.
  • Loading branch information
icio committed May 6, 2014
1 parent 1ea6aba commit cb47406
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 5 deletions.
5 changes: 5 additions & 0 deletions fs/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,11 @@ class DestinationExistsError(ResourceError):
default_message = "Destination exists: %(path)s"


class DestinationNotOlderError(ResourceError):
"""Exception raised when a target destination is not older than a source."""
default_message = "Destination not older: %(path)s"


class DirectoryNotEmptyError(ResourceError):
"""Exception raised when a directory to be removed is not empty."""
default_message = "Directory is not empty: %(path)s"
Expand Down
26 changes: 21 additions & 5 deletions fs/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,24 @@

from fs.mountfs import MountFS
from fs.path import pathjoin
from fs.errors import DestinationExistsError, RemoveRootError
from fs.errors import DestinationNotOlderError, DestinationExistsError, \
RemoveRootError, ResourceNotFoundError, \
ResourceInvalidError, ParentDirectoryMissingError
from fs.base import FS


def copyfile(src_fs, src_path, dst_fs, dst_path, overwrite=True, chunk_size=64*1024):
def copyfile(src_fs, src_path, dst_fs, dst_path, overwrite=True, update=False,
chunk_size=64*1024):
"""Copy a file from one filesystem to another. Will use system copyfile, if both files have a syspath.
Otherwise file will be copied a chunk at a time.
Otherwise file will be copied a chunk at a time. In the case where ``overwrite`` is False and
``update`` is True, the behaviour of ``update`` takes precedence.
:param src_fs: Source filesystem object
:param src_path: -- Source path
:param dst_fs: Destination filesystem object
:param dst_path: Destination filesystem object
:param overwrite: Write to destination files even if they already exist
:param update: Write to destination files only if the source is newer
:param chunk_size: Size of chunks to move if system copyfile is not available (default 64K)
"""
Expand All @@ -48,8 +54,18 @@ def copyfile(src_fs, src_path, dst_fs, dst_path, overwrite=True, chunk_size=64*1
src_syspath = src_fs.getsyspath(src_path, allow_none=True)
dst_syspath = dst_fs.getsyspath(dst_path, allow_none=True)

if not overwrite and dst_fs.exists(dst_path):
raise DestinationExistsError(dst_path)
if update:
try:
src_mtime = src_fs.getinfokeys(dst_path, "modified_time")["modified_time"]
dst_mtime = dst_fs.getinfokeys(dst_path, "modified_time")["modified_time"]
if src_mtime <= dst_mtime:
raise DestinationNotOlderError(dst_path)
except (KeyError, ParentDirectoryMissingError, ResourceNotFoundError,
ResourceInvalidError), e:
pass
elif not overwrite:
if dst_fs.exists(dst_path):
raise DestinationExistsError(dst_path)

# System copy if there are two sys paths
if src_syspath is not None and dst_syspath is not None:
Expand Down

0 comments on commit cb47406

Please sign in to comment.