|
|
import posixpath
class File: """File abstraction. Only real method is to get fullpath"""
def __init__(self, name, parent_dir): self.name = name self.parent_dir = parent_dir self.fullpath = None
def get_fullpath(self, real_time=False): if self.fullpath is None or real_time: if self.parent is None: self.fullpath = self.name else: self.fullpath = posixpath.join( self.parent_dir.get_fullpath(real_time), self.name ) return self.fullpath
class Directory(File): """Directory abstraction with optional listener"""
def __init__(self, name, is_listening=False): super().__init__(name, None) self.children = {} self.is_listening = is_listening if is_listening: self.modified = False
def __index__(self, key): try: return self.children[key] except KeyError: raise FileNotFoundError
def mark_modified(self): if self.is_listening: self.modified = True if self.parent_dir: self.parent_dir.mark_modified()
def traverse(self, path, create_intermediate=False, notify=True): """Traverse filesystem returning either file or directory""" if type(path) == str: path = path.split("/")
if len(path) == 1: return self[path[0]]
_next, *rest = path if _next == "..": if self.parent_dir: selected = self.parent_dir else: selected = self elif _next == ".": selected = self else: try: selected = self[_next] except FileNotFoundError as e: if create_intermediate: new = Directory(_next, self.is_listening) self.add_child(new, notify) selected = new else: raise e return selected.traverse( rest, create_intermediate=create_intermediate, notify=notify )
def add_child(self, child, notify=True): if notify and self.is_listening: self.mark_modified() self.children[child.name] = child child.parent_dir = self
def remove_child(self, child_name, notify=True): if notify and self.is_listening: self.mark_modified() del self[child_name]
def iter_files(self): for child in self.children.values(): if isinstance(child, Directory): yield from child.iter_files() else: yield child
@classmethod def from_dir_listing(cls, listing, rootname="", sep="/", is_listening=False): """Create a Directory object with files from file listing""" root = Directory(rootname, is_listening=is_listening) for file in listing: parts, file = file.split(sep) parent = root.traverse(parts, create_intermediate=True, notify=False) file = File(file) parent.add_child(file, notify=False) return root
def get_unmodified(dirtree: Directory): if dirtree.modified: for child in dirtree.children.values(): if isinstance(child, Directory): yield from get_unmodified(child) else: yield child.get_fullpath() else: yield dirtree.get_fullpath() + dirtree.sep
|