def getmtime(self, cpath: CPath): inside_cpath = self.__cdir_tree.get(cpath) if inside_cpath is None: raise CFSException( f'File System Error (occurred during getmtime on cpath: {cpath}):\n' f'X Path does not exist') if inside_cpath.is_dir() or cpath.is_dir(): raise CFSException( f'File System Error (occurred during getmtime on cpath: {cpath}):\n' f'X gmtime on dir') return inside_cpath.mtime
def __list(self, parent: CDirTree, do_hash=False): assert isinstance(parent, CDirTree) path_names: List[str] = self.__fs.listdir(parent) parent_names: Tuple[str, ...] = parent.names # transform path into cpath, but don't do hash because: the file might already be ignored by a fs matcher # config file. hash in listing block child_cpaths = [] for path_name in path_names: names = (*parent_names, path_name) child_cpath = CPath(names) if self.__fs.is_file(child_cpath): mtime = self.__fs.getmtime(child_cpath) size = self.__fs.getsize(child_cpath) child_cpath = CFile(names, mtime, size) else: child_cpath = CDir(names) child_cpaths.append(child_cpath) # matcher file finding block # search for fs matcher config files for child_cpath in child_cpaths: if self.__fs.is_real_fs() and child_cpath.is_file(): if FsMatcherMapper.exists(child_cpath.name): matcher_cfile = child_cpath # check includer or excluder # TODO: read content of fs matcher files (e.g. gitignore) and then match further relative to that. # make a fs matcher and attache it to the parent. content = "" with self.__fs.open(matcher_cfile, "r", encoding="utf-8") as f: content = f.read() fs_matcher: AbcFsMatcher fs_matcher = FsMatcherMapper.get(matcher_cfile.name)(content) # group will decide where to place includer and where excluder. # root group will forward to appropriate matcher group self.__fs_matcher_root_group.add(fs_matcher, parent) # now list & hash if not ignored for child_cpath in child_cpaths: if not self.__fs_matcher_root_group.should_include(child_cpath): continue if child_cpath.is_file() and do_hash: hash_value = self.__fs.gethash(child_cpath) child_cpath = CFileHashed(child_cpath.names, child_cpath.mtime, child_cpath.size, hash_value) if child_cpath.is_dir(): last_subtree = parent.add(child_cpath) self.__list(last_subtree, do_hash=do_hash) else: parent.add(child_cpath)
def getsize(self, cpath: CPath): inside_cpath = self.__cdir_tree.get(cpath) if inside_cpath is None: raise CFSException( f'File System Error (occurred during gethash on cpath: {cpath}):\n' f'X Path not found') if cpath.is_dir() or inside_cpath.is_dir(): raise CFSException( f'File System Error (occurred during getsize on cpath: {cpath}):\n' ) return inside_cpath.size
def is_ancestor(candidate_ancestor: CPath, candidate_descendant: CPath) -> bool: if not candidate_ancestor.is_dir(): raise CFSException( f"Candidate ancestor/parent must pass is_dir: {candidate_ancestor}" ) # TODO: create more specific exception if candidate_ancestor.names_count >= candidate_descendant.names_count: return False ancestor_names = candidate_ancestor.names descendant_names = candidate_descendant.names for idx, ancestor_name in enumerate(ancestor_names): descendant_name = descendant_names[idx] if ancestor_name != descendant_name: return False return True
def add(self, cpath: CPath) -> 'CDirTree': """ Add any level of descendents :returns: last sub tree """ assert isinstance(cpath, CPath) assert not isinstance(cpath, CDirTree) assert cpath.is_rel, "Cannot add absolute path to a tree" if cpath.is_dir(): cdir: CDir = cpath assert not cdir.is_root( ), f"Programmer's Error - cannot add root dir to a tree or sub tree: {cdir.to_dict()}" assert cpath.names_count > self.names_count if not self.is_root(): assert cpath.names[:self. names_count] == self.names, f"cpath.names {cpath.names} cpath.names[:self.names_count] {cpath.names[:self.names_count]}, self.names {self.names}" # assert cpath.name not in self._child_map, "Cannot add a child twice" TODO: think later whether this old check will be added in the new add check comp_left_names = tuple(cpath.names[:self.names_count]) comp_right_names = tuple(cpath.names[self.names_count:]) assert comp_left_names == self.names, f"Root didn't match: {comp_left_names} <-> {self.names}" self_own_names = comp_left_names target_tree = self # target tree is the tree where the cpath will be added as child _inc_right_names = [ ] # adding right names one by one for testing existence and adding to the tree. for dir_comp_name in comp_right_names[:-1]: _inc_right_names.append(dir_comp_name) new_target = target_tree._get_child_tree(dir_comp_name) if new_target is None: new_target = target_tree._add_child( CDir([*self_own_names, *_inc_right_names])) target_tree = new_target # After the first time of writing this line I indented this one level forward and # there was bugs of duplicate dir in visit, I remember when I indented this one. First time ok, # second time wrong, now okay last_tree = target_tree._add_child(cpath) return last_tree
def test_is_dir__empty_path_string__is_dir(self): cpath = CPath("") self.assertTrue(cpath.is_dir()) self.assertEqual(tuple([]), cpath.names)