1.1 --- a/imiptools/filesys.py Sun Sep 06 01:06:28 2015 +0200
1.2 +++ b/imiptools/filesys.py Sun Sep 06 01:15:30 2015 +0200
1.3 @@ -21,20 +21,55 @@
1.4
1.5 import errno
1.6 from imiptools.config import DEFAULT_PERMISSIONS, DEFAULT_DIR_PERMISSIONS
1.7 -from os.path import abspath, commonprefix, exists, join
1.8 -from os import chmod, makedirs, mkdir, rmdir
1.9 +from os.path import abspath, commonprefix, exists, join, split
1.10 +from os import chmod, makedirs, mkdir, rename, rmdir
1.11 from time import sleep, time
1.12
1.13 -def check_dir(base, dir):
1.14 - return commonprefix([base, abspath(dir)]) == base
1.15 +def check_dir(base, filename):
1.16 +
1.17 + "Return whether 'base' contains 'filename'."
1.18 +
1.19 + return commonprefix([base, abspath(filename)]) == base
1.20 +
1.21 +def remaining_parts(base, filename):
1.22 +
1.23 + "Return the remaining parts from 'base' provided by 'filename'."
1.24 +
1.25 + if not check_dir(base, filename):
1.26 + return None
1.27 +
1.28 + filename = abspath(filename)
1.29 +
1.30 + parts = []
1.31 + while True:
1.32 + filename, part = split(filename)
1.33 + if check_dir(base, filename):
1.34 + parts.insert(0, part)
1.35 + else:
1.36 + break
1.37 +
1.38 + return parts
1.39
1.40 def fix_permissions(filename, is_dir=False):
1.41 +
1.42 + """
1.43 + Fix permissions for 'filename', with 'is_dir' indicating whether the object
1.44 + should be a directory or not.
1.45 + """
1.46 +
1.47 try:
1.48 chmod(filename, is_dir and DEFAULT_DIR_PERMISSIONS or DEFAULT_PERMISSIONS)
1.49 except OSError:
1.50 pass
1.51
1.52 def make_path(base, parts):
1.53 +
1.54 + """
1.55 + Make the path within 'base' having components defined by the given 'parts'.
1.56 + Note that this function does not check the parts for suitability. To do so,
1.57 + use the FileBase methods instead.
1.58 + """
1.59 +
1.60 for part in parts:
1.61 pathname = join(base, part)
1.62 if not exists(pathname):
1.63 @@ -55,6 +90,14 @@
1.64 fix_permissions(self.store_dir, True)
1.65
1.66 def get_file_object(self, base, *parts):
1.67 +
1.68 + """
1.69 + Within the given 'base' location, return a path corresponding to the
1.70 + given 'parts'.
1.71 + """
1.72 +
1.73 + # Handle "empty" components.
1.74 +
1.75 pathname = join(base, *parts)
1.76 return check_dir(base, pathname) and pathname or None
1.77
1.78 @@ -67,6 +110,10 @@
1.79
1.80 parent = expected = self.store_dir
1.81
1.82 + # Handle "empty" components.
1.83 +
1.84 + parts = [p for p in parts if p]
1.85 +
1.86 for part in parts:
1.87 filename = self.get_file_object(expected, part)
1.88 if not filename:
1.89 @@ -79,11 +126,33 @@
1.90
1.91 return filename
1.92
1.93 + def move_object(self, source, target):
1.94 +
1.95 + "Move 'source' to 'target'."
1.96 +
1.97 + if not self.ensure_parent(target):
1.98 + return False
1.99 + rename(source, target)
1.100 +
1.101 + def ensure_parent(self, target):
1.102 +
1.103 + "Ensure that the parent of 'target' exists."
1.104 +
1.105 + parts = remaining_parts(self.store_dir, target)
1.106 + if not parts or not self.get_file_object(self.store_dir, *parts[:-1]):
1.107 + return False
1.108 +
1.109 + make_path(self.store_dir, parts[:-1])
1.110 + return True
1.111 +
1.112 # Locking methods.
1.113 # This uses the directory creation method exploited by MoinMoin.util.lock.
1.114 # However, a simple single lock type mechanism is employed here.
1.115
1.116 def get_lock_dir(self, *parts):
1.117 +
1.118 + "Return the lock directory defined by the given 'parts'."
1.119 +
1.120 parts = parts and list(parts) or []
1.121 parts.append(self.lock_name)
1.122 return self.get_object_in_store(*parts)