Esempio n. 1
0
def test_remove_empty_dirs(tmpdir):
    """Test that remove_empty_directories does so."""
    # expect an exception if a non-list gets passed in
    stats = dd.DedupStats()
    with pytest.raises(RuntimeError):
        dd.remove_empty_directories('x', stats, False)
    assert len(stats.dir_stats) == 0

    # expect silent failure if passing in a non-existent directory
    dd.remove_empty_directories([str(tmpdir.join('x'))], stats, False)
    assert tmpdir.exists()
    assert len(stats.dir_stats) == 1
    assert str(tmpdir.join('x')) in stats.dir_stats
    assert stats.dir_stats[str(tmpdir.join('x'))].empty_dir_count == 0

    # try removing two empty dirs side by side
    DirectoryBuilder("""
        d1:
        d2:""", tmpdir)
    d1 = tmpdir.join('d1')
    d2 = tmpdir.join('d2')
    stats = dd.DedupStats()
    dd.remove_empty_directories([str(d1), str(d2)], stats, False)
    expect_exists([d1, d2], False)
    assert tmpdir.exists()
    assert len(stats.dir_stats) == 2
    assert stats.dir_stats[str(d1)].empty_dir_count == 1
    assert stats.dir_stats[str(d2)].empty_dir_count == 1

    # try two nested dirs with a file in the deepest
    DirectoryBuilder("""
        d1:
          d2:
            f1""", tmpdir)
    d1 = tmpdir.join('d1')
    d2 = d1.join('d2')
    f1 = d2.join('f1')
    stats = dd.DedupStats()
    dd.remove_empty_directories([str(d1)], stats, False)
    expect_exists([d1, d2, f1], True)
    assert len(stats.dir_stats) == 1
    assert stats.dir_stats[str(d1)].empty_dir_count == 0

    # now get rid of the file and expect both directories to be removed
    f1.remove()
    dd.remove_empty_directories([str(d1)], stats, False)
    assert len(stats.dir_stats) == 1
    expect_exists([d1, d2], False)
    assert tmpdir.exists()
    assert stats.dir_stats[str(d1)].empty_dir_count == 2
Esempio n. 2
0
def test_empty_dirs(tmpdir):
    DirectoryBuilder("""
          d1:
          d2:
        """, tmpdir)
    assert tmpdir.join('d1').check(dir=1)
    assert tmpdir.join('d2').check(dir=1)
Esempio n. 3
0
def test_structure(tmpdir):
    DirectoryBuilder(
        """
        d1:
          d2:
            f1*/1
            f2/1
            f3**
        d3:
          f4**
        f5*""", tmpdir)
    d1 = tmpdir.join('d1')
    d2 = tmpdir.join('d1', 'd2')
    d3 = tmpdir.join('d3')
    f1 = d2.join('f1')
    f2 = d2.join('f2')
    f3 = d2.join('f3')
    f4 = d3.join('f4')
    f5 = tmpdir.join('f5')
    assert d1.check(dir=1)
    assert d2.check(dir=1)
    assert d3.check(dir=1)
    assert f1.size() == f2.size()
    assert identical(f1, f5)
    assert identical(f3, f4)
Esempio n. 4
0
def test_overlapping_target_and_ro(tmpdir):
    """Test that an error is raised if a read-only directory is a parent of a target
    directory."""
    DirectoryBuilder(
        """
        readonly_dir_base:
          ro1:
            rf1*
          ro2:
            rf2**
            rf3**
          ro3:
            target_dir_base:
              td1:
                tf1            
              td2:
                tf2***
                tf3***
                tf4
        """, tmpdir)
    ro1 = tmpdir.join('readonly_dir_base', 'ro1')
    ro2 = tmpdir.join('readonly_dir_base', 'ro2')
    ro3 = tmpdir.join('readonly_dir_base', 'ro3')
    td1 = ro3.join('target_dir_base', 'td1')
    td2 = ro3.join('target_dir_base', 'td2')
    run_dedup([td1, td2], [ro1, ro2])  # should be ok
    with pytest.raises(SystemExit):
        run_dedup([td1, td2], [ro1, ro2, ro3])  # should exit
Esempio n. 5
0
    def enlarge(self):
        """
        If my parentbuilder has any subdirectories, see if they
        contain a Confix2.dir file. If any, wrap DirectoryBuilder
        objects around them and add them to the parentbuilder.
        """
        super(SubdirectoryRecognizer, self).enlarge()

        errors = []
        for name, entry in self.parentbuilder().directory().entries():
            if not isinstance(entry, VFSDirectory):
                continue
            if entry in self.__recognized_directories:
                continue
            confix2_dir_file = entry.get(const.CONFIX2_DIR)
            if confix2_dir_file is None:
                continue
            if not isinstance(confix2_dir_file, VFSFile):
                errors.append(
                    Error(
                        os.sep.join(
                            confix2_dir_file.relpath(
                                self.package().rootdirectory())) +
                        ' is not a file'))
                continue

            self.parentbuilder().add_builder(DirectoryBuilder(directory=entry))
            self.__recognized_directories.add(entry)
            pass
        if len(errors):
            raise Error('There were errors in directory '+\
                        os.sep.join(self.parentbuilder().directory().relpath(self.package().rootdirectory())), errors)
        pass
Esempio n. 6
0
def test_readonly(tmpdir, remove_empty_dirs):
    """Ensure files are not deleted from readonly directories.

    Args:
        tmpdir: pytest temporary directory fixture
    """
    DirectoryBuilder(
        """
        target_dir_base:
          td1:
            tf1*            
          td2:
            tf2***
            tf3***
            tf4
        readonly_dir_base:
          ro1:
            rf1*
          ro2:
            rf2**
            rf3**
          ro3:
        """, tmpdir)
    td1 = tmpdir.join('target_dir_base', 'td1')
    td2 = tmpdir.join('target_dir_base', 'td2')
    tf1 = td1.join('tf1')
    tf2 = td2.join('tf2')
    tf3 = td2.join('tf3')
    tf4 = td2.join('tf4')
    all_target_dirs = [td1, td2]
    ro1 = tmpdir.join('readonly_dir_base', 'ro1')
    ro2 = tmpdir.join('readonly_dir_base', 'ro2')
    ro3 = tmpdir.join('readonly_dir_base', 'ro3')
    rf1 = ro1.join('rf1')
    rf2 = ro2.join('rf2')
    rf3 = ro2.join('rf3')
    all_ro_dirs = [ro1, ro2, ro3]
    all_ro_files = [rf1, rf2, rf3]
    run_dedup(all_target_dirs, all_ro_dirs, remove_empty_dirs)
    # files in readonly directories must never be deleted
    expect_exists(all_ro_files, True)
    # readonly directories, even empty ones, must never be deleted
    expect_exists(all_ro_dirs, True)
    # the unique target file should always still exist
    assert tf4.exists()
    # now check results that differ based on remove_empty_dirs
    if not remove_empty_dirs:
        # no target dirs should have been removed
        expect_exists(all_target_dirs, True)
    else:
        # empty target dirs (namely td1) should have been removed
        assert not td1.exists()
        # but td2 should not be removed
        assert td2.exists()
    # tf1 should have been deleted because it is made a duplicate by read-only file rf1
    assert not tf1.exists()
    # exactly one of tf2 and tf3 should exist.  Exactly which was deleted depends on
    # the order that os.walk reported them to dedup.walk_dirs().
    assert tf2.exists() ^ tf3.exists()
Esempio n. 7
0
    def DIRECTORY(self, path):
        if type(path) not in (list, tuple):
            raise Error('DIRECTORY(' + str(path) +
                        '): path argument must be list or tuple')
        directory = self.__dirbuilder.directory().find(path=path)
        if directory is None:
            raise Error('DIRECTORY(): could not find directory ' + str(path))

        dirbuilder = DirectoryBuilder(directory=directory)
        self.__dirbuilder.add_builder(dirbuilder)
        return dirbuilder
Esempio n. 8
0
def test_is_same_or_subdir(tmpdir):
    """Test that `is_same_or_subdir` correctly identifies directories that are the same
    or that it identifies one directory as a subdirectory of another."""
    DirectoryBuilder("""
        t1:
            t1_1:
        t2:
        """, tmpdir)
    t1 = tmpdir.join('t1')
    t1_1 = t1.join('t1_1')
    t2 = tmpdir.join('t2')
    # Passing pathlike objects would work, but the live code will be passing in strings
    assert dd.is_same_or_subdir(str(t1), str(t1))
    assert dd.is_same_or_subdir(str(t1_1), str(t1))
    assert dd.is_same_or_subdir(str(t1_1), str(tmpdir))
    assert not dd.is_same_or_subdir(str(t1), str(t2))
Esempio n. 9
0
def test_same_target_dirs(tmpdir):
    """Expect that an error is raised if the same target directory is specified more
    than once."""
    DirectoryBuilder(
        """
        t1:
          foo*
        t2:
          bar*
        ro:
          baz
        """, tmpdir)
    t1 = tmpdir.join('t1')
    ro = tmpdir.join('ro')
    with pytest.raises(SystemExit):
        run_dedup([t1, t1], [ro], remove_empty=True)
    expect_exists([t1, ro], True)
Esempio n. 10
0
def test_size_and_content(tmpdir):
    # This usage is allowed because no conflict arises:
    #    f1 is created and its contents are saved as content group * (as before)
    #    f2 is created and its contents are copied from content group *.  Size
    #        group 1 is also created, and set to the size of f2.
    #    f3 is created and made to be the saved size of size group 1.
    DirectoryBuilder(
        """
          f1*
          f2*/1
          f3/1
        """, tmpdir)
    f1 = tmpdir.join('f1')
    f2 = tmpdir.join('f2')
    f3 = tmpdir.join('f3')
    assert f2.size() == f3.size()
    assert identical(f1, f2)
Esempio n. 11
0
def add_confix_admin(package):
    """
    If necessary, add a directory <packageroot>/confix-admin and the
    associated directory builder.

    @return: DirectoryBuilder instance representing the confix-admin
             directory
    """
    admin_builder = package.rootbuilder().find_entry_builder([const.ADMIN_DIR])
    if admin_builder:
        return admin_builder
    admin_dir = package.rootdirectory().get(const.ADMIN_DIR)
    if admin_dir is None:
        admin_dir = package.rootdirectory().add(name=const.ADMIN_DIR,
                                                entry=Directory())
        pass
    return package.rootbuilder().add_builder(
        DirectoryBuilder(directory=admin_dir))
Esempio n. 12
0
def test_size_conflict(tmpdir):
    # If a file is in both a size group and a content group, the size group must have
    # been created by a file that is also in the content group.

    # This should throw an exception because:
    #    f1 is created and its contents are saved as content group *
    #    f2 is created and its size saved in size group 1
    #    f3 must now have the same content as f1 because it is in content group
    #        *, however it is also in size group 1.  Size group 1 has some random size
    #        that could differ from the size of content group *, therefore this situation
    #        is syntactically valid but semantically invalid.
    with pytest.raises(ValueError):
        DirectoryBuilder(
            """
              f1*
              f2/1
              f3*/1
            """, tmpdir)
Esempio n. 13
0
def test_skip(tmpdir, monkeypatch):
    """Test user choice of skipping the current directory."""
    def mock_input(*args, **kwargs):
        """On the nth invocation (0 based) return the nth string in parent scope
        `input_values` list."""
        if 'invocation_count' not in mock_input.__dict__:
            mock_input.invocation_count = 0
        result = input_values[mock_input.invocation_count]
        mock_input.invocation_count += 1
        return result

    DirectoryBuilder(
        """
        td1:
          tf1*
          tf2**            
        td2:
          tf3*
          tf4**
          td2_1:
            tf6*
        td3:
          tf5**
        """, tmpdir)
    td1 = tmpdir.join('td1')
    td2 = tmpdir.join('td2')
    td2_1 = td2.join('td2_1')
    td3 = tmpdir.join('td3')
    tf1 = td1.join('tf1')
    tf2 = td1.join('tf2')
    tf3 = td2.join('tf3')
    tf4 = td2.join('tf4')
    tf5 = td3.join('tf5')
    tf6 = td2_1.join('tf6')
    # monkey patch the 'input' builtin function to use our input function
    monkeypatch.setattr('builtins.input', mock_input)
    input_values = ['skip', 'yes']
    # expect confirm to ask to delete tf3, and answer skip
    run_dedup([td1, td2, td3], confirm=True)
    # expect tf4 and td2_1 to not be examined because of skip
    expect_exists([tf1, tf2, tf3, tf4, tf6], True)
    # expect confirmation for tf5 to be deleted and supply 'yes'
    assert not tf5.exists()
Esempio n. 14
0
def test_dedup(tmpdir, remove_empty_dirs):
    """Test that duplicate files are removed, but that unique files that happen to have
    the same size are not."""
    # Build a directory structure for testing
    DirectoryBuilder(
        """
        d1:
          d2:
            f1*/1
            f2/1
            f3**
        d3:
          f4**
          f5*
        ro1:
          f6
        """, tmpdir)
    # For readability, get a handle to all the directories and files just created
    d1 = tmpdir.join('d1')
    d2 = d1.join('d2')
    d3 = tmpdir.join('d3')
    ro1 = tmpdir.join('ro1')
    f1 = d2.join('f1')
    f2 = d2.join('f2')
    f4 = d3.join('f4')
    f3 = d2.join('f3')
    f5 = d3.join('f5')
    f6 = ro1.join('f6')
    # Make sets of files and directories for comparison
    all_dirs = {d1, d2, d3, ro1}
    all_files = {f1, f2, f3, f4, f5, f6}
    expected_unique_files = {f1, f2, f3, f6}
    expected_duplicate_files = all_files - expected_unique_files
    # Run the deduplifier using parametrized flags
    run_dedup([d1, d3], [ro1], remove_empty_dirs)
    # expect duplicate files deleted and empty directories removed according to flag,
    # however none of the directories other than d3 should ever be removed
    expect_exists(all_dirs - {d3}, True)
    assert not d3.exists() == remove_empty_dirs
    expect_exists(expected_unique_files, True)
    expect_exists(expected_duplicate_files, False)
Esempio n. 15
0
def test_ro_duplicates_multiple_targets(tmpdir):
    """Test that target files matching read-only files are deleted."""
    DirectoryBuilder(
        """
        t1:
          f1*
        t2:
          f2**
          f22****
        t3:
          f3***
        ro1:
          rof1*
          rof2**
          rof3***
          rof4****
    """, tmpdir)
    t1 = tmpdir.join('t1')
    t2 = tmpdir.join('t2')
    t3 = tmpdir.join('t3')
    f1 = t1.join('f1')
    f2 = t2.join('f2')
    f22 = t2.join('f22')
    f3 = t3.join('f3')
    ro1 = tmpdir.join('ro1')
    rof1 = ro1.join('rof1')
    rof2 = ro1.join('rof2')
    rof3 = ro1.join('rof3')
    rof4 = ro1.join('rof4')
    all_target_files = [f1, f2, f22, f3]
    all_target_dirs = [t1, t2, t3]
    all_ro_files = [rof1, rof2, rof3, rof4]
    run_dedup([t1, t2, t3], [ro1], remove_empty=True)
    expect_exists(all_target_files, False)
    expect_exists(all_target_dirs, False)
    expect_exists(all_ro_files, True)
Esempio n. 16
0
def test_size_group(tmpdir):
    DirectoryBuilder("""
          f1/1
          f2/1
        """, tmpdir)
    assert tmpdir.join('f1').size() == tmpdir.join('f2').size()
Esempio n. 17
0
def test_f1(tmpdir):
    DirectoryBuilder("f1", tmpdir)
    assert tmpdir.join('f1').exists()
Esempio n. 18
0
def test_syntax(tmpdir):
    with pytest.raises(RuntimeError):
        DirectoryBuilder(':', tmpdir)
    with pytest.raises(RuntimeError):
        DirectoryBuilder('$', tmpdir)