Commit 772ec802 by rfkelly0

Make SubFS a subclass of WrapFS, move it into its own module

parent 0dc38117
...@@ -39,8 +39,10 @@ ...@@ -39,8 +39,10 @@
* New fs.expose implementations: * New fs.expose implementations:
* dokan: mount an FS object as a drive using Dokan (win32-only) * dokan: mount an FS object as a drive using Dokan (win32-only)
* Modified listdir and walk methods to accept callables as well as strings * Modified listdir and walk methods to accept callables as well as strings
for wildcards for wildcards.
* Fix operation of OSFS on win32 when it points to the root of a drive. * Fixed operation of OSFS on win32 when it points to the root of a drive.
* Made SubFS a subclass of WrapFS, and moved it into its own module at
fs.wrapfs.subfs.
* Fix OSFS.add_watcher on linux platforms; previous version would cancel * Fix OSFS.add_watcher on linux platforms; previous version would cancel
any watchers when a new one was added. any watchers when a new one was added.
...@@ -33,6 +33,8 @@ from fs.path import * ...@@ -33,6 +33,8 @@ from fs.path import *
from fs.errors import * from fs.errors import *
from fs.local_functools import wraps from fs.local_functools import wraps
SubFS = None # this is lazily imported from fs.wrapfs.subfs
class DummyLock(object): class DummyLock(object):
"""A dummy lock object that doesn't do anything. """A dummy lock object that doesn't do anything.
...@@ -521,10 +523,12 @@ class FS(object): ...@@ -521,10 +523,12 @@ class FS(object):
:param path: path to directory to open :param path: path to directory to open
:rtype: An FS object :rtype: An FS object
""" """
global SubFS
if SubFS is None:
from fs.wrapfs.subfs import SubFS
if not self.exists(path): if not self.exists(path):
raise ResourceNotFoundError(path) raise ResourceNotFoundError(path)
sub_fs = SubFS(self, path) return SubFS(self, path)
return sub_fs
def walk(self, def walk(self,
path="/", path="/",
...@@ -883,137 +887,6 @@ class FS(object): ...@@ -883,137 +887,6 @@ class FS(object):
browse(self) browse(self)
class SubFS(FS):
"""A SubFS represents a sub directory of another filesystem object.
SubFS objects are returned by opendir, which effectively creates a
'sandbox' filesystem that can only access files/dirs under a root path
within its 'parent' dir.
"""
def __init__(self, parent, sub_dir):
self.parent = parent
self.sub_dir = abspath(normpath(sub_dir))
FS.__init__(self, thread_synchronize=False)
def __str__(self):
return "<SubFS: %s in %s>" % (self.sub_dir, self.parent)
def __unicode__(self):
return u"<SubFS: %s in %s>" % (self.sub_dir, self.parent)
def __repr__(self):
return str(self)
def desc(self, path):
if self.isdir(path):
return "Sub dir of %s" % str(self.parent)
else:
return "File in sub dir of %s" % str(self.parent)
def _delegate(self, path):
return pathjoin(self.sub_dir, relpath(normpath(path)))
def getsyspath(self, path, allow_none=False):
return self.parent.getsyspath(self._delegate(path), allow_none=allow_none)
def open(self, path, mode="r", **kwargs):
return self.parent.open(self._delegate(path), mode)
def exists(self, path):
return self.parent.exists(self._delegate(path))
def opendir(self, path):
if not self.exists(path):
raise ResourceNotFoundError(path)
path = self._delegate(path)
sub_fs = self.parent.opendir(path)
return sub_fs
def isdir(self, path):
return self.parent.isdir(self._delegate(path))
def isfile(self, path):
return self.parent.isfile(self._delegate(path))
def listdir(self, path="./", wildcard=None, full=False, absolute=False, dirs_only=False, files_only=False):
paths = self.parent.listdir(self._delegate(path),
wildcard=wildcard,
full=False,
absolute=False,
dirs_only=dirs_only,
files_only=files_only)
if absolute:
listpath = normpath(path)
paths = [abspath(pathjoin(listpath, path)) for path in paths]
elif full:
listpath = normpath(path)
paths = [relpath(pathjoin(listpath, path)) for path in paths]
return paths
def makedir(self, path, recursive=False, allow_recreate=False):
return self.parent.makedir(self._delegate(path), recursive=recursive, allow_recreate=allow_recreate)
def remove(self, path):
return self.parent.remove(self._delegate(path))
def removedir(self, path, recursive=False,force=False):
# Careful not to recurse outside the subdir
if path in ("","/"):
if force:
for path2 in self.listdir(path,absolute=True,files_only=True):
try:
self.remove(path2)
except ResourceNotFoundError:
pass
for path2 in self.listdir(path,absolute=True,dirs_only=True):
try:
self.removedir(path2,force=True)
except ResourceNotFoundError:
pass
else:
self.parent.removedir(self._delegate(path),force=force)
if recursive:
try:
self.removedir(dirname(path),recursive=True)
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))
def getsize(self, path):
return self.parent.getsize(self._delegate(path))
def rename(self, src, dst):
return self.parent.rename(self._delegate(src), self._delegate(dst))
def move(self, src, dst, **kwds):
self.parent.move(self._delegate(src),self._delegate(dst),**kwds)
def movedir(self, src, dst, **kwds):
self.parent.movedir(self._delegate(src),self._delegate(dst),**kwds)
def copy(self, src, dst, **kwds):
self.parent.copy(self._delegate(src),self._delegate(dst),**kwds)
def copydir(self, src, dst, **kwds):
self.parent.copydir(self._delegate(src),self._delegate(dst),**kwds)
def createfile(self, path, data=""):
return self.parent.createfile(self._delegate(path),data)
def setcontents(self, path, data=""):
return self.parent.setcontents(self._delegate(path),data)
def getcontents(self, path):
return self.parent.getcontents(self._delegate(path))
def flags_to_mode(flags): def flags_to_mode(flags):
"""Convert an os.O_* flag bitmask into an FS mode string.""" """Convert an os.O_* flag bitmask into an FS mode string."""
......
...@@ -21,6 +21,7 @@ import fnmatch ...@@ -21,6 +21,7 @@ import fnmatch
from fs.base import FS, threading, synchronize from fs.base import FS, threading, synchronize
from fs.errors import * from fs.errors import *
from fs.path import *
from fs.local_functools import wraps from fs.local_functools import wraps
...@@ -146,6 +147,8 @@ class WrapFS(FS): ...@@ -146,6 +147,8 @@ class WrapFS(FS):
@rewrite_errors @rewrite_errors
def listdir(self, path="", **kwds): def listdir(self, path="", **kwds):
full = kwds.pop("full",False)
absolute = kwds.pop("absolute",False)
wildcard = kwds.pop("wildcard","*") wildcard = kwds.pop("wildcard","*")
if wildcard is None: if wildcard is None:
wildcard = lambda fn:True wildcard = lambda fn:True
...@@ -154,16 +157,22 @@ class WrapFS(FS): ...@@ -154,16 +157,22 @@ class WrapFS(FS):
wildcard = lambda fn:bool (wildcard_re.match(fn)) wildcard = lambda fn:bool (wildcard_re.match(fn))
info = kwds.get("info",False) info = kwds.get("info",False)
entries = [] entries = []
for e in self.wrapped_fs.listdir(self._encode(path),**kwds): enc_path = self._encode(path)
for e in self.wrapped_fs.listdir(enc_path,**kwds):
if info: if info:
e = e.copy() e = e.copy()
e["name"] = self._decode(e["name"]) fullnm = pathjoin(enc_path,e["name"])
e["name"] = basename(self._decode(fullnm))
if not wildcard(e["name"]): if not wildcard(e["name"]):
continue continue
else: else:
e = self._decode(e) e = basename(self._decode(pathjoin(enc_path,e)))
if not wildcard(e): if not wildcard(e):
continue continue
if full:
e = pathjoin(path,e)
elif absolute:
e = abspath(pathjoin(path,e))
entries.append(e) entries.append(e)
return entries return entries
......
"""
fs.wrapfs.subfs
===============
An FS wrapper class for accessing just a subdirectory for an FS.
"""
from fs.wrapfs import WrapFS
from fs.errors import *
from fs.path import *
class SubFS(WrapFS):
"""A SubFS represents a sub directory of another filesystem object.
SubFS objects are returned by opendir, which effectively creates a
'sandbox' filesystem that can only access files/dirs under a root path
within its 'parent' dir.
"""
def __init__(self, wrapped_fs, sub_dir):
self.sub_dir = abspath(normpath(sub_dir))
super(SubFS,self).__init__(wrapped_fs)
def _encode(self, path):
return pathjoin(self.sub_dir, relpath(normpath(path)))
def _decode(self, path):
return abspath(normpath(path))[len(self.sub_dir):]
def __str__(self):
return "<SubFS: %s in %s>" % (self.sub_dir, self.wrapped_fs)
def __unicode__(self):
return u"<SubFS: %s in %s>" % (self.sub_dir, self.wrapped_fs)
def __repr__(self):
return str(self)
def desc(self, path):
if self.isdir(path):
return "Sub dir of %s" % str(self.wrapped_fs)
else:
return "File in sub dir of %s" % str(self.wrapped_fs)
def opendir(self, path):
if not self.exists(path):
raise ResourceNotFoundError(path)
path = self._encode(path)
return self.wrapped_fs.opendir(path)
def close(self):
self.closed = True
def removedir(self, path, recursive=False, force=False):
# Careful not to recurse outside the subdir
path = normpath(path)
if path in ("","/"):
if not force:
for path2 in self.listdir(path):
raise DirectoryNotEmptyError(path)
else:
for path2 in self.listdir(path,absolute=True,files_only=True):
try:
self.remove(path2)
except ResourceNotFoundError:
pass
for path2 in self.listdir(path,absolute=True,dirs_only=True):
try:
self.removedir(path2,force=True)
except ResourceNotFoundError:
pass
else:
super(SubFS,self).removedir(path,force=force)
if recursive:
try:
self.removedir(dirname(path),recursive=True)
except DirectoryNotEmptyError:
pass
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