~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transform.py

Added progress bars to tree-changing operations

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
                           ExistingLimbo, ImmortalLimbo)
24
24
from bzrlib.inventory import InventoryEntry
25
25
from bzrlib.osutils import file_kind, supports_executable, pathjoin
 
26
from bzrlib.progress import DummyProgress
26
27
from bzrlib.trace import mutter, warning
27
28
 
28
29
 
60
61
     * version_file
61
62
     * set_executability
62
63
    """
63
 
    def __init__(self, tree):
 
64
    def __init__(self, tree, pb=DummyProgress()):
64
65
        """Note: a write lock is taken on the tree.
65
66
        
66
67
        Use TreeTransform.finalize() to release the lock
94
95
        self._tree_id_paths = {}
95
96
        self._new_root = self.trans_id_tree_file_id(tree.get_root_id())
96
97
        self.__done = False
 
98
        self._pb = pb
97
99
 
98
100
    def __get_root(self):
99
101
        return self._new_root
676
678
        """
677
679
        tree_paths = list(self._tree_path_ids.iteritems())
678
680
        tree_paths.sort(reverse=True)
679
 
        for path, trans_id in tree_paths:
 
681
        for num, data in enumerate(tree_paths):
 
682
            path, trans_id = data
 
683
            self._pb.update('removing file', num+1, len(tree_paths))
680
684
            full_path = self._tree.abspath(path)
681
685
            if trans_id in self._removed_contents:
682
686
                self.delete_any(full_path)
697
701
                if file_id is not None:
698
702
                    limbo_inv[trans_id] = inv[file_id]
699
703
                    del inv[file_id]
 
704
        self._pb.clear()
700
705
 
701
706
    def _apply_insertions(self, inv, limbo_inv):
702
707
        """Perform tree operations that insert directory/inventory names.
705
710
        limbo any files that needed renaming.  This must be done in strict
706
711
        parent-to-child order.
707
712
        """
708
 
        for path, trans_id in self.new_paths():
 
713
        new_paths = self.new_paths()
 
714
        for num, (path, trans_id) in enumerate(new_paths):
 
715
            self._pb.update('adding file', num+1, len(new_paths))
709
716
            try:
710
717
                kind = self._new_contents[trans_id]
711
718
            except KeyError:
736
743
            # requires files and inventory entries to be in place
737
744
            if trans_id in self._new_executability:
738
745
                self._set_executability(path, inv, trans_id)
 
746
        self._pb.clear()
739
747
 
740
748
    def _set_executability(self, path, inv, trans_id):
741
749
        """Set the executability of versioned files """
985
993
    return has_contents, contents_mod, meta_mod
986
994
 
987
995
 
988
 
def revert(working_tree, target_tree, filenames, backups=False):
 
996
def revert(working_tree, target_tree, filenames, backups=False, 
 
997
           pb=DummyProgress()):
989
998
    """Revert a working tree's contents to those of a target tree."""
990
999
    interesting_ids = find_interesting(working_tree, target_tree, filenames)
991
1000
    def interesting(file_id):
992
1001
        return interesting_ids is None or file_id in interesting_ids
993
1002
 
994
 
    tt = TreeTransform(working_tree)
 
1003
    tt = TreeTransform(working_tree, pb)
995
1004
    try:
996
1005
        trans_id = {}
997
1006
        def trans_id_file_id(file_id):
1000
1009
            except KeyError:
1001
1010
                return tt.trans_id_tree_file_id(file_id)
1002
1011
 
1003
 
        for file_id in topology_sorted_ids(target_tree):
1004
 
            if not interesting(file_id):
1005
 
                continue
 
1012
        sorted_interesting = [i for i in topology_sorted_ids(target_tree) if
 
1013
                              interesting(i)]
 
1014
        for id_num, file_id in enumerate(sorted_interesting):
 
1015
            pb.update("Reverting file", id_num+1, len(sorted_interesting))
1006
1016
            if file_id not in working_tree.inventory:
1007
1017
                entry = target_tree.inventory[file_id]
1008
1018
                parent_id = trans_id_file_id(entry.parent_id)
1011
1021
            else:
1012
1022
                change_entry(tt, file_id, working_tree, target_tree, 
1013
1023
                             trans_id_file_id, backups, trans_id)
1014
 
        for file_id in working_tree.inventory:
1015
 
            if not interesting(file_id):
1016
 
                continue
 
1024
        wt_interesting = [i for i in working_tree.inventory if interesting(i)]
 
1025
        for id_num, file_id in enumerate(wt_interesting):
 
1026
            pb.update("New file check", id_num+1, len(sorted_interesting))
1017
1027
            if file_id not in target_tree:
1018
1028
                tt.unversion_file(tt.trans_id_tree_file_id(file_id))
1019
 
        raw_conflicts = resolve_conflicts(tt)
 
1029
        raw_conflicts = resolve_conflicts(tt, pb)
1020
1030
        for line in conflicts_strings(cook_conflicts(raw_conflicts, tt)):
1021
1031
            warning(line)
1022
1032
        tt.apply()
1023
1033
    finally:
1024
1034
        tt.finalize()
1025
 
 
1026
 
 
1027
 
def resolve_conflicts(tt):
 
1035
        pb.clear()
 
1036
 
 
1037
 
 
1038
def resolve_conflicts(tt, pb=DummyProgress()):
1028
1039
    """Make many conflict-resolution attempts, but die if they fail"""
1029
1040
    new_conflicts = set()
1030
 
    for n in range(10):
1031
 
        conflicts = tt.find_conflicts()
1032
 
        if len(conflicts) == 0:
1033
 
            return new_conflicts
1034
 
        new_conflicts.update(conflict_pass(tt, conflicts))
1035
 
    raise MalformedTransform(conflicts=conflicts)
 
1041
    try:
 
1042
        for n in range(10):
 
1043
            pb.update('Resolution pass', n+1, 10)
 
1044
            conflicts = tt.find_conflicts()
 
1045
            if len(conflicts) == 0:
 
1046
                return new_conflicts
 
1047
            new_conflicts.update(conflict_pass(tt, conflicts))
 
1048
        raise MalformedTransform(conflicts=conflicts)
 
1049
    finally:
 
1050
        pb.clear()
1036
1051
 
1037
1052
 
1038
1053
def conflict_pass(tt, conflicts):