示例#1
0
    def test_get_descendant_cpaths(self):
        root_tree = CDirTree()
        root_tree.add(CFile("dir1/a.txt", 1, 2))
        root_tree.add(CDir("dir2/"))
        root_tree.add(CDir("dir3/p/q/r"))
        root_tree.add(CFile("dir3/p/x.txt", 1, 5))

        dcp = root_tree.get_descendant_cpaths()
        self.assertEqual(len(dcp), 8)
示例#2
0
    def test_to_dict__to_json_equal(self):
        root_tree1 = CDirTree()
        root_tree1.add(CFile("dir1/a.txt", 1, 2))
        root_tree1.add(CDir("dir2/"))
        root_tree1.add(CDir("dir3/p/q/r"))
        root_tree1.add(CFile("dir3/p/x.txt", 1, 5))

        root_to_dict = json.loads(json.dumps(root_tree1.to_dict()))  # for removing tuple list inconsistency
        self.assertEqual(root_to_dict, json.loads(root_tree1.to_json()))
示例#3
0
    def test_get_children(self):
        root_tree = CDirTree()
        root_tree.add(CFile("dir1/a.txt", 1, 2))
        root_tree.add(CDir("dir2/"))
        root_tree.add(CDir("dir3/p/q/r"))
        root_tree.add(CFile("dir3/p/x.txt", 1, 5))

        children = root_tree.get_children()
        self.assertIsInstance(children[0], CDirTree)
        self.assertEqual(3, len(children))
示例#4
0
    def test_exists(self):
        tree1 = CDirTree("a/b/c")
        ftree = tree1.add(CDir('a/b/c/d/e/f'))

        # Notice this FALSE
        self.assertFalse(tree1.exists(('a', 'b')))
        self.assertTrue(tree1.exists(('d', )))
示例#5
0
    def test_add(self):
        tree1 = CDirTree("a/b/c")
        etree = tree1.add(CDir('a/b/c/d/e'))
        self.assertEqual(etree.path, 'a/b/c/d/e/')

        ddir = tree1.get(CPath("a/b/c/d/"))
        self.assertEqual(('a', 'b', 'c', 'd'), ddir.names)

        ddir2 = tree1.get(CPath("a/b/c/d"))
        self.assertIsNotNone(ddir2)

        ddir4 = tree1.get(CDir("a/b/c/d"))
        self.assertIsNotNone(ddir4)

        ddir3 = tree1.get(CFile("a/b/c/d", 1, 1))
        self.assertIsNone(ddir3)
示例#6
0
    def test_to_dict_to_json_equal(self):
        tree = CRootDirTree("anything")
        tree.add(CFile("a path", 1, 23))
        tree.add(CDir("b path/"))

        tree_dict = json.loads(json.dumps( tree.to_dict() ))  # for converting tuples into list inside

        self.assertEqual(tree_dict, json.loads(tree.to_json()))
示例#7
0
    def test_as_cdir(self):
        tree1 = CDirTree("")
        self.assertIsInstance(tree1, CDir)
        self.assertIs(tree1.as_cdir.__class__, CDir)
        self.assertEqual(tuple(), tree1.names)

        tree2 = CDirTree("a/b/c")
        etree = tree2.add(CDir('a/b/c/d/e'))
        self.assertEqual(('a', 'b', 'c', 'd', 'e'), etree.names)
示例#8
0
    def test_diff(self):
        root_tree1 = CDirTree()
        root_tree1.add(CFile("dir1/a.txt", 1, 2))
        root_tree1.add(CDir("dir2/"))
        root_tree1.add(CDir("dir3/p/q/r"))
        root_tree1.add(CFile("dir3/p/x.txt", 1, 5))

        root_tree2 = CDirTree()
        root_tree2.add(CFile("dir1/a.txt", 11, 55))
        root_tree2.add(CDir("dir3/p/q/r"))
        root_tree2.add(CFile("dir3/p/x.txt", 1, 5))

        diff = root_tree1.diff(root_tree2)
        self.assertIsNotNone(diff.modified.get(CPath("dir1/a.txt")))
        self.assertTrue(len(diff.modified.get_children_cpaths()), 1)
        self.assertTrue(diff.new.is_empty)
        self.assertIsNotNone(diff.deleted.get(CPath("dir2/")))
        self.assertTrue(len(diff.deleted.get_children_cpaths()), 1)
示例#9
0
    def test_is_sub(self):
        tree1 = CDirTree("")
        self.assertFalse(tree1.is_sub())

        tree2 = CDirTree("")
        subtree = tree2.add(CDir("a/b/c"))
        self.assertTrue(subtree.is_sub())
        "Let's check if the rule of the universe still holds"
        self.assertEqual(('a', 'b', 'c'), subtree.names)
示例#10
0
        def json_visitor_callable(path_dict):
            if path_dict['type'] == 'DIR':
                cpath = CDir(path_dict['names'])
            else:
                assert path_dict['type'] == 'FILE'
                if path_dict.get('hash', None) is None:
                    cpath = CFile(path_dict['names'], path_dict['mtime'],
                                  path_dict['size'])
                else:
                    cpath = CFileHashed(path_dict['names'], path_dict['mtime'],
                                        path_dict['size'], path_dict['hash'])

            self.__cdir_tree.add(cpath)
示例#11
0
    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)
示例#12
0
    def test_get(self):
        tree1 = CDirTree("a/b/c")
        ftree = tree1.add(CDir('a/b/c/d/e/f'))
        self.assertEqual(('a', 'b', 'c', 'd', 'e', 'f'), ftree.names)
        ddir = tree1.get(CPath('a/b/c/d/'))
        self.assertEqual('a/b/c/d/', ddir.path)

        # path type aware/unaware
        self.assertIsNotNone(
            tree1.get(CPath('a/b/c/d'))
        )
        self.assertIsNotNone(
            tree1.get(CFile('a/b/c/d', 1, 1), path_type_aware=False)
        )
        self.assertIsNone(
            tree1.get(CFile('a/b/c/d', 1, 1))
        )
示例#13
0
    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
示例#14
0
    def test_visit(self):
        root_tree = CDirTree()
        root_tree.add(CFile("dir1/a.txt", 1, 2))
        root_tree.add(CDir("dir2/"))
        root_tree.add(CDir("dir3/p/q/r"))
        root_tree.add(CFile("dir3/p/x.txt", 1, 5))

        # dir2 is a leaf dir
        dir2_is_leaf: Union[bool, None] = None

        def visitor_1(cpath, is_leaf, tree):
            nonlocal dir2_is_leaf
            if cpath.equals_by_path_only(CPath("dir2/")):
                dir2_is_leaf = is_leaf

        root_tree.visit(visitor_1)
        self.assertTrue(dir2_is_leaf)

        #  non depth first visit, the first cpath is dir1
        paths_2 = []

        def visitor_2(cpath, is_leaf, tree):
            nonlocal paths_2
            paths_2.append(cpath)

        root_tree.visit(visitor_2, False)
        self.assertTrue(paths_2[0].equals(CDir("dir1/")))

        # non depth first visit, the last path is
        # print(paths[-1].to_dict())
        self.assertTrue(paths_2[-1].equals(CFile("dir3/p/x.txt", 1, 5)))

        # depth first visit, the first cpath is dir1/a.txt
        paths_3 = []

        def visitor_3(cpath, is_leaf, tree):
            nonlocal paths_3
            paths_3.append(cpath)

        root_tree.visit(visitor_3, True)

        self.assertTrue(paths_3[0].equals(CFile("dir1/a.txt", 1, 2)))

        # length of paths
        paths_4 = []

        def visitor_4(cpath, is_leaf, tree):
            nonlocal paths_4
            paths_4.append(cpath)

        root_tree.visit(visitor_4, False)
        """
        Before bug fix:
            dir1/a.txt
            dir1/
            dir2/
            dir3/p/q/r/
            dir3/p/q/
            dir3/p/
            dir3/
            dir3/p/x.txt
            dir3/p/
        
        Count: 9, instead of 8
            
        dir3/p/  occurred two times due to having a file inside it and sub dir 
        """

        self.assertEqual(8, len(paths_4))

        self.assertEqual(
            {
                "dir1/",
                "dir1/a.txt",
                "dir2/",
                "dir3/p/",
                "dir3/p/x.txt",
                "dir3/p/q/",
                "dir3/p/q/r/",
                "dir3/"
            },
            set(cpath.path for cpath in paths_4)
        )
示例#15
0
 def as_cdir(self) -> Union[CDir, None]:
     return CDir(self.names)