Commit 707f5ba7 by willmcgugan

Some fixes

parent f5dfa021
...@@ -211,7 +211,7 @@ class FS(object): ...@@ -211,7 +211,7 @@ class FS(object):
path -- Pach to check path -- Pach to check
""" """
return self.getsyspath(path, None) is not None return self.getsyspath(path, allow_none=True) is not None
def open(self, path, mode="r", **kwargs): def open(self, path, mode="r", **kwargs):
...@@ -492,11 +492,26 @@ class FS(object): ...@@ -492,11 +492,26 @@ class FS(object):
depth first search. Use 'depth' if you plan to create or depth first search. Use 'depth' if you plan to create or
delete files as you go. delete files as you go.
""" """
for path, files in self.walk(path, wildcard, dir_wildcard, search): for path, files in self.walk(path, wildcard=wildcard, dir_widlcard=dir_wildcard, search=search):
for f in files: for f in files:
yield pathjoin(path, f) yield pathjoin(path, f)
def walkdirs(self, path="/", wildcard=None, search="breadth"):
""" Like the 'walk' method but yields directories.
path -- Root path to start walking
wildcard -- If given, only return dictories that match this wildcard
search -- A string dentifying the method used to walk the directories.
Can be 'breadth' for a breadth first search, or 'depth' for a
depth first search. Use 'depth' if you plan to create or
delete files as you go.
"""
for p, files in self.walk(path, wildcard=wildcard, search=search):
yield p
def getsize(self, path): def getsize(self, path):
"""Returns the size (in bytes) of a resource. """Returns the size (in bytes) of a resource.
...@@ -565,7 +580,7 @@ class FS(object): ...@@ -565,7 +580,7 @@ class FS(object):
src -- Source path src -- Source path
dst -- Destination path dst -- Destination path
overwrite -- If True, then an existing file at the destination path overwrite -- If True, then an existing file at the destination path
will be silently overwritte; if False then an exception will be silently overwritten; if False then an exception
will be raised in this case. will be raised in this case.
""" """
...@@ -617,9 +632,9 @@ class FS(object): ...@@ -617,9 +632,9 @@ class FS(object):
except OSError: except OSError:
pass pass
def movefile_noerrors(src, dst, overwrite, chunk_size): def movefile_noerrors(src, dst, **kwargs):
try: try:
return self.move(src, dst, overwrite, chunk_size) return self.move(src, dst, **kwargs)
except FSError: except FSError:
return return
if ignore_errors: if ignore_errors:
...@@ -627,10 +642,15 @@ class FS(object): ...@@ -627,10 +642,15 @@ class FS(object):
else: else:
movefile = self.move movefile = self.move
self.makedir(dst, allow_recreate=overwrite) src = abspath(src)
dst = abspath(dst)
if dst:
self.makedir(dst, allow_recreate=overwrite)
for dirname, filenames in self.walk(src, search="depth"): for dirname, filenames in self.walk(src, search="depth"):
dst_dirname = relpath(dirname[len(src):]) dst_dirname = relpath(frombase(src, abspath(dirname)))
dst_dirpath = pathjoin(dst, dst_dirname) dst_dirpath = pathjoin(dst, dst_dirname)
self.makedir(dst_dirpath, allow_recreate=True, recursive=True) self.makedir(dst_dirpath, allow_recreate=True, recursive=True)
...@@ -657,9 +677,9 @@ class FS(object): ...@@ -657,9 +677,9 @@ class FS(object):
""" """
if not self.isdir(src): if not self.isdir(src):
raise ResourceInvalidError(src, msg="Source is not a directory: %(path)s") raise ResourceInvalidError(src, msg="Source is not a directory: %(path)s")
def copyfile_noerrors(src, dst, overwrite): def copyfile_noerrors(src, dst, **kwargs):
try: try:
return self.copy(src, dst, overwrite=overwrite) return self.copy(src, dst, **kwargs)
except FSError: except FSError:
return return
if ignore_errors: if ignore_errors:
...@@ -667,14 +687,17 @@ class FS(object): ...@@ -667,14 +687,17 @@ class FS(object):
else: else:
copyfile = self.copy copyfile = self.copy
copyfile = self.copy src = abspath(src)
dst = abspath(dst)
if dst: if dst:
self.makedir(dst, allow_recreate=overwrite) self.makedir(dst, allow_recreate=overwrite)
for dirname, filenames in self.walk(src): for dirname, filenames in self.walk(src):
dst_dirname = relpath(dirname[len(src):]) dst_dirname = relpath(frombase(src, abspath(dirname)))
dst_dirpath = pathjoin(dst, dst_dirname) dst_dirpath = pathjoin(dst, dst_dirname)
self.makedir(dst_dirpath, allow_recreate=True) self.makedir(dst_dirpath, allow_recreate=True, recursive=True)
for filename in filenames: for filename in filenames:
...@@ -724,7 +747,7 @@ class SubFS(FS): ...@@ -724,7 +747,7 @@ class SubFS(FS):
def __init__(self, parent, sub_dir): def __init__(self, parent, sub_dir):
self.parent = parent self.parent = parent
self.sub_dir = abspath(normpath(sub_dir)) self.sub_dir = abspath(normpath(sub_dir))
FS.__init__(self,thread_synchronize=False) FS.__init__(self, thread_synchronize=False)
def __str__(self): def __str__(self):
return "<SubFS: %s in %s>" % (self.sub_dir, self.parent) return "<SubFS: %s in %s>" % (self.sub_dir, self.parent)
......
...@@ -52,6 +52,15 @@ class MountFS(FS): ...@@ -52,6 +52,15 @@ class MountFS(FS):
return self, head_path, tail_path return self, head_path, tail_path
def getsyspath(self, path, allow_none=False):
fs, mount_path, delegate_path = self._delegate(path)
if fs is self:
if allow_none:
return None
else:
raise NoSysPathError(path=path)
return fs.getsyspath(delegate_path, allow_none=allow_none)
@synchronize @synchronize
def desc(self, path): def desc(self, path):
fs, mount_path, delegate_path = self._delegate(path) fs, mount_path, delegate_path = self._delegate(path)
...@@ -309,5 +318,3 @@ class MountFS(FS): ...@@ -309,5 +318,3 @@ class MountFS(FS):
if fs is self: if fs is self:
return [] return []
return fs.listxattrs(delegate_path) return fs.listxattrs(delegate_path)
...@@ -178,7 +178,7 @@ def issamedir(path1, path2): ...@@ -178,7 +178,7 @@ def issamedir(path1, path2):
return pathsplit(normpath(path1))[0] == pathsplit(normpath(path2))[0] return pathsplit(normpath(path1))[0] == pathsplit(normpath(path2))[0]
def isprefix(path1,path2): def isprefix(path1, path2):
"""Return true is path1 is a prefix of path2. """Return true is path1 is a prefix of path2.
>>> isprefix("foo/bar", "foo/bar/spam.txt") >>> isprefix("foo/bar", "foo/bar/spam.txt")
...@@ -203,6 +203,20 @@ def isprefix(path1,path2): ...@@ -203,6 +203,20 @@ def isprefix(path1,path2):
return True return True
def forcedir(path): def forcedir(path):
"""Ensure the path ends with a trailing /
>>> forcedir("foo/bar")
'foo/bar/'
>>> forcedir("foo/bar/")
'foo/bar/'
"""
if not path.endswith('/'): if not path.endswith('/'):
return path + '/' return path + '/'
return path return path
def frombase(path1, path2):
if not isprefix(path1, path2):
raise ValueError("path1 must be a prefix of path2")
return path2[len(path1):]
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
import shutil import shutil
from fs.mountfs import MountFS from fs.mountfs import MountFS
from fs.path import pathjoin
def copyfile(src_fs, src_path, dst_fs, dst_path, chunk_size=16384): def copyfile(src_fs, src_path, dst_fs, dst_path, chunk_size=16384):
"""Copy a file from one filesystem to another. Will use system copyfile, if both files have a syspath. """Copy a file from one filesystem to another. Will use system copyfile, if both files have a syspath.
...@@ -18,11 +19,11 @@ def copyfile(src_fs, src_path, dst_fs, dst_path, chunk_size=16384): ...@@ -18,11 +19,11 @@ def copyfile(src_fs, src_path, dst_fs, dst_path, chunk_size=16384):
chunk_size -- Size of chunks to move if system copyfile is not available (default 16K) chunk_size -- Size of chunks to move if system copyfile is not available (default 16K)
""" """
src_syspath = src_fs.getsyspath(src_path) or "" src_syspath = src_fs.getsyspath(src_path, allow_none=True)
dst_syspath = dst_fs.getsyspath(dst_path) or "" dst_syspath = dst_fs.getsyspath(dst_path, allow_none=True)
# System copy if there are two sys paths # System copy if there are two sys paths
if src_syspath and dst_syspath: if src_syspath is not None and dst_syspath is not None:
shutil.copyfile(src_syspath, dst_syspath) shutil.copyfile(src_syspath, dst_syspath)
return return
...@@ -57,11 +58,11 @@ def movefile(src_fs, src_path, dst_fs, dst_path, chunk_size=16384): ...@@ -57,11 +58,11 @@ def movefile(src_fs, src_path, dst_fs, dst_path, chunk_size=16384):
chunk_size -- Size of chunks to move if system copyfile is not available (default 16K) chunk_size -- Size of chunks to move if system copyfile is not available (default 16K)
""" """
src_syspath = src_fs.getsyspath(src_path) or "" src_syspath = src_fs.getsyspath(src_path, allow_none=True)
dst_syspath = dst_fs.getsyspath(dst_path) or "" dst_syspath = dst_fs.getsyspath(dst_path, allow_none=True)
# System copy if there are two sys paths # System copy if there are two sys paths
if src_syspath and dst_syspath: if src_syspath is not None and dst_syspath is not None:
shutil.movefile(src_syspath, dst_syspath) shutil.movefile(src_syspath, dst_syspath)
return return
...@@ -87,7 +88,7 @@ def movefile(src_fs, src_path, dst_fs, dst_path, chunk_size=16384): ...@@ -87,7 +88,7 @@ def movefile(src_fs, src_path, dst_fs, dst_path, chunk_size=16384):
dst.close() dst.close()
def movedir(fs1, fs2, ignore_errors=False, chunk_size=16384): def movedir(fs1, fs2, overwrite=False, ignore_errors=False, chunk_size=16384):
"""Moves contents of a directory from one filesystem to another. """Moves contents of a directory from one filesystem to another.
fs1 -- Source filesystem, or a tuple of (<filesystem>, <directory path>) fs1 -- Source filesystem, or a tuple of (<filesystem>, <directory path>)
...@@ -104,12 +105,16 @@ def movedir(fs1, fs2, ignore_errors=False, chunk_size=16384): ...@@ -104,12 +105,16 @@ def movedir(fs1, fs2, ignore_errors=False, chunk_size=16384):
fs2 = fs2.opendir(dir2) fs2 = fs2.opendir(dir2)
mount_fs = MountFS() mount_fs = MountFS()
mount_fs.mount('dir1', fs1) mount_fs.mount('src', fs1)
mount_fs.mount('dir2', fs2) mount_fs.mount('dst', fs2)
mount_fs.movedir('dir1', 'dir2', ignore_errors=ignore_errors, chunk_size=chunk_size)
mount_fs.movedir('src', 'dst',
overwrite=overwrite,
ignore_errors=ignore_errors,
chunk_size=chunk_size)
def copydir(fs1, fs2, ignore_errors=False, chunk_size=16384):
def copydir(fs1, fs2, overwrite=False, ignore_errors=False, chunk_size=16384):
"""Copies contents of a directory from one filesystem to another. """Copies contents of a directory from one filesystem to another.
fs1 -- Source filesystem, or a tuple of (<filesystem>, <directory path>) fs1 -- Source filesystem, or a tuple of (<filesystem>, <directory path>)
...@@ -126,9 +131,12 @@ def copydir(fs1, fs2, ignore_errors=False, chunk_size=16384): ...@@ -126,9 +131,12 @@ def copydir(fs1, fs2, ignore_errors=False, chunk_size=16384):
fs2 = fs2.opendir(dir2) fs2 = fs2.opendir(dir2)
mount_fs = MountFS() mount_fs = MountFS()
mount_fs.mount('dir1', fs1) mount_fs.mount('src', fs1)
mount_fs.mount('dir2', fs2) mount_fs.mount('dst', fs2)
mount_fs.copydir('dir1', 'dir2', ignore_errors=ignore_errors, chunk_size=chunk_size) mount_fs.copydir('src', 'dst',
overwrite=overwrite,
ignore_errors=ignore_errors,
chunk_size=chunk_size)
def countbytes(fs): def countbytes(fs):
...@@ -244,16 +252,49 @@ def find_duplicates(fs, compare_paths=None, quick=False, signature_chunk_size=16 ...@@ -244,16 +252,49 @@ def find_duplicates(fs, compare_paths=None, quick=False, signature_chunk_size=16
paths = list(set(paths).difference(dups)) paths = list(set(paths).difference(dups))
def print_fs(fs, path="/", max_levels=5, indent=' '*2):
"""Prints a filesystem listing to stdout (including sub dirs). Useful as a debugging aid.
Be careful about printing a OSFS, or any other large filesystem.
Without max_levels set, this function will traverse the entire directory tree.
fs -- A filesystem object
path -- Path of root to list (default "/")
max_levels -- Maximum levels of dirs to list (default 5), set to None for no maximum
indent -- String to indent each directory level (default two spaces)
"""
def print_dir(fs, path, level):
try:
dir_listing = [(fs.isdir(pathjoin(path,p)), p) for p in fs.listdir(path)]
except Exception, e:
print indent*level + "... unabled to retrieve directory list (reason: %s) ..." % str(e)
return
dir_listing.sort(key = lambda (isdir, p):(not isdir, p.lower()))
for is_dir, item in dir_listing:
if is_dir:
print indent*level + '[%s]' % item
if max_levels is None or level < max_levels:
print_dir(fs, pathjoin(path, item), level+1)
if max_levels is not None:
if level >= max_levels:
print indent*(level+1) + "..."
else:
print indent*level + '%s' % item
print_dir(fs, path, 0)
if __name__ == "__main__": if __name__ == "__main__":
from osfs import * from osfs import *
fs = OSFS('~/copytest') fs = OSFS('~/copytest')
from memoryfs import * from memoryfs import *
m = MemoryFS() m = MemoryFS()
m.makedir('maps') m.makedir('maps')
copydir((fs, 'maps'), (m, 'maps')) copydir((fs, 'maps'), (m, 'maps'))
from browsewin import browse from browsewin import browse
browse(m) browse(m)
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