Commit 44dcc3bf by willmcgugan

Added settimes to a few FS impementations, and added a settimes test case

parent 1a8f4d8b
......@@ -110,6 +110,7 @@ try:
except ImportError:
wraps = lambda f:f
def synchronize(func):
"""Decorator to synchronize a method on self._lock."""
@wraps(func)
......@@ -121,7 +122,6 @@ def synchronize(func):
self._lock.release()
return acquire_lock
class FS(object):
"""The base class for Filesystem abstraction objects.
......@@ -183,7 +183,6 @@ class FS(object):
else:
self._lock = DummyLock()
def getsyspath(self, path, allow_none=False):
"""Returns the system path (a path recognised by the OS) if present.
......@@ -417,21 +416,28 @@ class FS(object):
raise UnsupportedError("rename resource")
def settimes(self, path, accessed_time=None, modified_time=None):
"""Set the access time and modifie time of a file
"""Set the accessed time and modified time of a file
:param path: path to a file
:param access_time: epoch time of file access
:param modified_time: epock time of file modification
:param accessed_time: a datetime object the file was accessed (defaults to current time)
:param modified_time: a datetime object the file was modified (defaults to current time)
"""
if self.hassyspath(path):
sys_path = self.getsyspath(path)
os.utime(sys_path, accessed_time, modified_time)
sys_path = self.getsyspath(path, allow_none=True)
if sys_path is not None:
now = datetime.datetime.now()
if accessed_time is None:
accessed_time = now
if modified_time is None:
modified_time = now
accessed_time = int(time.mktime(accessed_time.timetuple()))
modified_time = int(time.mktime(modified_time.timetuple()))
os.utime(sys_path, (accessed_time, modified_time))
return True
else:
raise UnsupportedError("settimes")
def getinfo(self, path):
"""Returns information for a path as a dictionary. The exact content of
this dictionary will vary depending on the implementation, but will
......@@ -442,7 +448,6 @@ class FS(object):
"""
raise UnsupportedError("get resource info")
def desc(self, path):
"""Returns short descriptive text regarding a path. Intended mainly as
a debugging aid
......@@ -462,7 +467,6 @@ class FS(object):
else:
return "OS file, maps to %s" % sys_path
def getcontents(self, path):
"""Returns the contents of a file as a string.
......@@ -512,7 +516,6 @@ class FS(object):
sub_fs = SubFS(self, path)
return sub_fs
def walk(self,
path="/",
wildcard=None,
......@@ -578,7 +581,6 @@ class FS(object):
else:
raise ValueError("Search should be 'breadth' or 'depth'")
def walkfiles(self,
path="/",
wildcard=None,
......@@ -597,7 +599,6 @@ class FS(object):
for f in files:
yield pathjoin(path, f)
def walkdirs(self,
path="/",
wildcard=None,
......@@ -613,8 +614,6 @@ class FS(object):
for p, files in self.walk(path, wildcard=wildcard, search=search, ignore_errors=ignore_errors):
yield p
def getsize(self, path):
"""Returns the size (in bytes) of a resource.
......@@ -714,7 +713,6 @@ class FS(object):
self.copy(src, dst, overwrite=overwrite, chunk_size=chunk_size)
self.remove(src)
def movedir(self, src, dst, overwrite=False, ignore_errors=False, chunk_size=16384):
"""moves a directory from one location to another.
......@@ -772,8 +770,6 @@ class FS(object):
self.removedir(dirname)
def copydir(self, src, dst, overwrite=False, ignore_errors=False, chunk_size=16384):
"""copies a directory from one location to another.
......@@ -820,7 +816,6 @@ class FS(object):
dst_filename = pathjoin(dst_dirpath, filename)
copyfile(src_filename, dst_filename, overwrite=overwrite, chunk_size=chunk_size)
def isdirempty(self, path):
"""Check if a directory is empty (contains no files or sub-directories)
......@@ -835,7 +830,6 @@ class FS(object):
return True
return False
def makeopendir(self, path, recursive=False):
"""makes a directory (if it doesn't exist) and returns an FS object for
the newly created directory.
......@@ -859,8 +853,6 @@ class FS(object):
from fs.utils import print_fs
print_fs(self, max_levels=max_levels)
def browse(self):
"""Displays the FS tree in a graphical window (requires wxWidgets)"""
from fs.browsewin import browse
......@@ -965,6 +957,9 @@ class SubFS(FS):
except DirectoryNotEmptyError:
pass
def settimes(self, path, accessed_time=None, modified_time=None):
return self.parent.settimes(self._delegate(path), accessed_time, modified_time)
def getinfo(self, path):
return self.parent.getinfo(self._delegate(path))
......
......@@ -85,6 +85,10 @@ class RPCFSInterface(object):
dst = self.decode_path(dst)
return self.fs.rename(src, dst)
def settimes(self, path, accessed_time, modified_time):
path = self.decode_path(path)
return self.fs.settimes(path, accessed_time, modified_time)
def getinfo(self, path):
path = self.decode_path(path)
return self.fs.getinfo(path)
......
......@@ -326,7 +326,7 @@ class MountFS(FS):
@synchronize
def unmount(self, path):
"""Unmounds a path.
"""Unmounts a path.
:param path: Path to unmount
......@@ -334,6 +334,15 @@ class MountFS(FS):
path = normpath(path)
del self.mount_tree[path]
def settimes(self, path, accessed_time=None, modified_time=None):
path = normpath(path)
fs, mount_path, delegate_path = self._delegate(path)
if fs is None:
raise ResourceNotFoundError(path)
if fs is self:
raise UnsupportedError("settimes")
fs.settimes(delegate_path, accessed_time, modified_time)
@synchronize
def getinfo(self, path):
path = normpath(path)
......
......@@ -78,6 +78,7 @@ class MultiFS(FS):
__repr__ = __str__
@synchronize
def __unicode__(self):
return u"<MultiFS: %s>" % ", ".join(unicode(fs) for fs in self.fs_sequence)
......@@ -218,6 +219,13 @@ class MultiFS(FS):
raise ResourceNotFoundError(path)
@synchronize
def settimes(self, path, accessed_time=None, modified_time=None):
for fs in self:
if fs.exists(path):
return fs.settimes(path, accessed_time, modified_time)
raise ResourceNotFoundError(path)
@synchronize
def getinfo(self, path):
for fs in self:
if fs.exists(path):
......
......@@ -215,6 +215,10 @@ class RPCFS(FS):
dst = self.encode_path(dst)
return self.proxy.rename(src,dst)
def settimes(self, path, accessed_time, modified_time):
path = self.encode_path(path)
return self.proxy.settimes(path, accessed_time, modified_time)
def getinfo(self, path):
path = self.encode_path(path)
return self.proxy.getinfo(path)
......
......@@ -13,6 +13,7 @@ logging.basicConfig(level=logging.ERROR, stream=sys.stdout)
from fs.base import *
import datetime
import unittest
import os, os.path
import pickle
......@@ -561,6 +562,26 @@ class FSTestCases(object):
finally:
f.close()
def test_settimes(self):
def cmp_datetimes(d1, d2):
"""Test datetime objects are the same to within the timestamp accuracy"""
dts1 = time.mktime(d1.timetuple())
dts2 = time.mktime(d2.timetuple())
return dts1 == dts2
d1 = datetime.datetime(2010, 6, 20, 11, 0, 9, 987699)
d2 = datetime.datetime(2010, 7, 5, 11, 0, 9, 500000)
self.fs.createfile('/dates.txt', 'check dates')
# If the implementation supports settimes, check that the times
# can be set and then retrieved
try:
self.fs.settimes('/dates.txt', d1, d2)
except UnsupportedError:
pass
else:
info = self.fs.getinfo('/dates.txt')
self.assertTrue(cmp_datetimes(d1, info['accessed_time']))
self.assertTrue(cmp_datetimes(d2, info['modified_time']))
class ThreadingTestCases:
"""Testcases for thread-safety of FS implementations."""
......
......@@ -181,7 +181,7 @@ class WrapFS(FS):
@rewrite_errors
def settimes(self, path, *args, **kwds):
return self.wrapped_fs.settimes(*args,**kwds)
return self.wrapped_fs.settimes(self._encode(path), *args,**kwds)
@rewrite_errors
def desc(self, path):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment