/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/transform.py

  • Committer: Robert Collins
  • Date: 2006-03-03 02:09:49 UTC
  • mto: (1594.2.4 integration)
  • mto: This revision was merged to the branch mainline in revision 1596.
  • Revision ID: robertc@robertcollins.net-20060303020949-0ddc6f33d0a43943
Smoke test for RevisionStore factories creating revision stores.

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
                           ReusingTransform, NotVersionedError, CantMoveRoot,
23
23
                           ExistingLimbo, ImmortalLimbo)
24
24
from bzrlib.inventory import InventoryEntry
25
 
from bzrlib.osutils import (file_kind, supports_executable, pathjoin, lexists,
26
 
                            delete_any)
27
 
from bzrlib.progress import DummyProgress, ProgressPhase
 
25
from bzrlib.osutils import file_kind, supports_executable, pathjoin
 
26
from bzrlib.progress import DummyProgress
28
27
from bzrlib.trace import mutter, warning
29
 
import bzrlib.ui 
30
28
 
31
29
 
32
30
ROOT_PARENT = "root-parent"
38
36
    map[key] = value
39
37
 
40
38
 
41
 
class _TransformResults(object):
42
 
    def __init__(self, modified_paths):
43
 
        object.__init__(self)
44
 
        self.modified_paths = modified_paths
45
 
 
46
 
 
47
39
class TreeTransform(object):
48
40
    """Represent a tree transformation.
49
41
    
287
279
        os.symlink(target, self._limbo_name(trans_id))
288
280
        unique_add(self._new_contents, trans_id, 'symlink')
289
281
 
 
282
    @staticmethod
 
283
    def delete_any(full_path):
 
284
        """Delete a file or directory."""
 
285
        try:
 
286
            os.unlink(full_path)
 
287
        except OSError, e:
 
288
        # We may be renaming a dangling inventory id
 
289
            if e.errno not in (errno.EISDIR, errno.EACCES, errno.EPERM):
 
290
                raise
 
291
            os.rmdir(full_path)
 
292
 
290
293
    def cancel_creation(self, trans_id):
291
294
        """Cancel the creation of new file contents."""
292
295
        del self._new_contents[trans_id]
293
 
        delete_any(self._limbo_name(trans_id))
 
296
        self.delete_any(self._limbo_name(trans_id))
294
297
 
295
298
    def delete_contents(self, trans_id):
296
299
        """Schedule the contents of a path entry for deletion"""
428
431
        except KeyError:
429
432
            return os.path.basename(self._tree_id_paths[trans_id])
430
433
 
431
 
    def by_parent(self):
 
434
    def _by_parent(self):
432
435
        """Return a map of parent: children for known parents.
433
436
        
434
437
        Only new paths and parents of tree files with assigned ids are used.
455
458
        # ensure all children of all existent parents are known
456
459
        # all children of non-existent parents are known, by definition.
457
460
        self._add_tree_children()
458
 
        by_parent = self.by_parent()
 
461
        by_parent = self._by_parent()
459
462
        conflicts.extend(self._unversioned_parents(by_parent))
460
463
        conflicts.extend(self._parent_loops())
461
464
        conflicts.extend(self._duplicate_entries(by_parent))
472
475
        Active parents are those which gain children, and those which are
473
476
        removed.  This is a necessary first step in detecting conflicts.
474
477
        """
475
 
        parents = self.by_parent().keys()
 
478
        parents = self._by_parent().keys()
476
479
        parents.extend([t for t in self._removed_contents if 
477
480
                        self.tree_kind(t) == 'directory'])
478
481
        for trans_id in self._removed_id:
504
507
                continue
505
508
            yield self.trans_id_tree_path(childpath)
506
509
 
507
 
    def has_named_child(self, by_parent, parent_id, name):
508
 
        try:
509
 
            children = by_parent[parent_id]
510
 
        except KeyError:
511
 
            children = []
512
 
        for child in children:
513
 
            if self.final_name(child) == name:
514
 
                return True
515
 
        try:
516
 
            path = self._tree_id_paths[parent_id]
517
 
        except KeyError:
518
 
            return False
519
 
        childpath = joinpath(path, name)
520
 
        child_id = self._tree_path_ids.get(childpath)
521
 
        if child_id is None:
522
 
            return lexists(self._tree.abspath(childpath))
523
 
        else:
524
 
            if tt.final_parent(child_id) != parent_id:
525
 
                return False
526
 
            if child_id in tt._removed_contents:
527
 
                # XXX What about dangling file-ids?
528
 
                return False
529
 
            else:
530
 
                return True
531
 
 
532
510
    def _parent_loops(self):
533
511
        """No entry should be its own ancestor"""
534
512
        conflicts = []
620
598
                if name == last_name:
621
599
                    conflicts.append(('duplicate', last_trans_id, trans_id,
622
600
                    name))
623
 
                try:
624
 
                    kind = self.final_kind(trans_id)
625
 
                except NoSuchFile:
626
 
                    kind = None
627
 
                file_id = self.final_file_id(trans_id)
628
 
                if kind is not None or file_id is not None:
629
 
                    last_name = name
630
 
                    last_trans_id = trans_id
 
601
                last_name = name
 
602
                last_trans_id = trans_id
631
603
        return conflicts
632
604
 
633
605
    def _duplicate_ids(self):
687
659
            raise MalformedTransform(conflicts=conflicts)
688
660
        limbo_inv = {}
689
661
        inv = self._tree.inventory
690
 
        child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
691
 
        try:
692
 
            child_pb.update('Apply phase', 0, 2)
693
 
            self._apply_removals(inv, limbo_inv)
694
 
            child_pb.update('Apply phase', 1, 2)
695
 
            modified_paths = self._apply_insertions(inv, limbo_inv)
696
 
        finally:
697
 
            child_pb.finished()
 
662
        self._apply_removals(inv, limbo_inv)
 
663
        self._apply_insertions(inv, limbo_inv)
698
664
        self._tree._write_inventory(inv)
699
665
        self.__done = True
700
666
        self.finalize()
701
 
        return _TransformResults(modified_paths)
702
667
 
703
668
    def _limbo_name(self, trans_id):
704
669
        """Generate the limbo name of a file"""
713
678
        """
714
679
        tree_paths = list(self._tree_path_ids.iteritems())
715
680
        tree_paths.sort(reverse=True)
716
 
        child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
717
 
        try:
718
 
            for num, data in enumerate(tree_paths):
719
 
                path, trans_id = data
720
 
                child_pb.update('removing file', num, len(tree_paths))
721
 
                full_path = self._tree.abspath(path)
722
 
                if trans_id in self._removed_contents:
723
 
                    delete_any(full_path)
724
 
                elif trans_id in self._new_name or trans_id in \
725
 
                    self._new_parent:
726
 
                    try:
727
 
                        os.rename(full_path, self._limbo_name(trans_id))
728
 
                    except OSError, e:
729
 
                        if e.errno != errno.ENOENT:
730
 
                            raise
731
 
                if trans_id in self._removed_id:
732
 
                    if trans_id == self._new_root:
733
 
                        file_id = self._tree.inventory.root.file_id
734
 
                    else:
735
 
                        file_id = self.tree_file_id(trans_id)
 
681
        for num, data in enumerate(tree_paths):
 
682
            path, trans_id = data
 
683
            self._pb.update('removing file', num+1, len(tree_paths))
 
684
            full_path = self._tree.abspath(path)
 
685
            if trans_id in self._removed_contents:
 
686
                self.delete_any(full_path)
 
687
            elif trans_id in self._new_name or trans_id in self._new_parent:
 
688
                try:
 
689
                    os.rename(full_path, self._limbo_name(trans_id))
 
690
                except OSError, e:
 
691
                    if e.errno != errno.ENOENT:
 
692
                        raise
 
693
            if trans_id in self._removed_id:
 
694
                if trans_id == self._new_root:
 
695
                    file_id = self._tree.inventory.root.file_id
 
696
                else:
 
697
                    file_id = self.tree_file_id(trans_id)
 
698
                del inv[file_id]
 
699
            elif trans_id in self._new_name or trans_id in self._new_parent:
 
700
                file_id = self.tree_file_id(trans_id)
 
701
                if file_id is not None:
 
702
                    limbo_inv[trans_id] = inv[file_id]
736
703
                    del inv[file_id]
737
 
                elif trans_id in self._new_name or trans_id in self._new_parent:
738
 
                    file_id = self.tree_file_id(trans_id)
739
 
                    if file_id is not None:
740
 
                        limbo_inv[trans_id] = inv[file_id]
741
 
                        del inv[file_id]
742
 
        finally:
743
 
            child_pb.finished()
 
704
        self._pb.clear()
744
705
 
745
706
    def _apply_insertions(self, inv, limbo_inv):
746
707
        """Perform tree operations that insert directory/inventory names.
750
711
        parent-to-child order.
751
712
        """
752
713
        new_paths = self.new_paths()
753
 
        modified_paths = []
754
 
        child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
755
 
        try:
756
 
            for num, (path, trans_id) in enumerate(new_paths):
757
 
                child_pb.update('adding file', num, len(new_paths))
 
714
        for num, (path, trans_id) in enumerate(new_paths):
 
715
            self._pb.update('adding file', num+1, len(new_paths))
 
716
            try:
 
717
                kind = self._new_contents[trans_id]
 
718
            except KeyError:
 
719
                kind = contents = None
 
720
            if trans_id in self._new_contents or self.path_changed(trans_id):
 
721
                full_path = self._tree.abspath(path)
758
722
                try:
759
 
                    kind = self._new_contents[trans_id]
760
 
                except KeyError:
761
 
                    kind = contents = None
762
 
                if trans_id in self._new_contents or \
763
 
                    self.path_changed(trans_id):
764
 
                    full_path = self._tree.abspath(path)
765
 
                    try:
766
 
                        os.rename(self._limbo_name(trans_id), full_path)
767
 
                    except OSError, e:
768
 
                        # We may be renaming a dangling inventory id
769
 
                        if e.errno != errno.ENOENT:
770
 
                            raise
771
 
                    if trans_id in self._new_contents:
772
 
                        modified_paths.append(full_path)
773
 
                        del self._new_contents[trans_id]
774
 
 
775
 
                if trans_id in self._new_id:
776
 
                    if kind is None:
777
 
                        kind = file_kind(self._tree.abspath(path))
778
 
                    inv.add_path(path, kind, self._new_id[trans_id])
779
 
                elif trans_id in self._new_name or trans_id in\
780
 
                    self._new_parent:
781
 
                    entry = limbo_inv.get(trans_id)
782
 
                    if entry is not None:
783
 
                        entry.name = self.final_name(trans_id)
784
 
                        parent_path = os.path.dirname(path)
785
 
                        entry.parent_id = \
786
 
                            self._tree.inventory.path2id(parent_path)
787
 
                        inv.add(entry)
788
 
 
789
 
                # requires files and inventory entries to be in place
790
 
                if trans_id in self._new_executability:
791
 
                    self._set_executability(path, inv, trans_id)
792
 
        finally:
793
 
            child_pb.finished()
794
 
        return modified_paths
 
723
                    os.rename(self._limbo_name(trans_id), full_path)
 
724
                except OSError, e:
 
725
                    # We may be renaming a dangling inventory id
 
726
                    if e.errno != errno.ENOENT:
 
727
                        raise
 
728
                if trans_id in self._new_contents:
 
729
                    del self._new_contents[trans_id]
 
730
 
 
731
            if trans_id in self._new_id:
 
732
                if kind is None:
 
733
                    kind = file_kind(self._tree.abspath(path))
 
734
                inv.add_path(path, kind, self._new_id[trans_id])
 
735
            elif trans_id in self._new_name or trans_id in self._new_parent:
 
736
                entry = limbo_inv.get(trans_id)
 
737
                if entry is not None:
 
738
                    entry.name = self.final_name(trans_id)
 
739
                    parent_path = os.path.dirname(path)
 
740
                    entry.parent_id = self._tree.inventory.path2id(parent_path)
 
741
                    inv.add(entry)
 
742
 
 
743
            # requires files and inventory entries to be in place
 
744
            if trans_id in self._new_executability:
 
745
                self._set_executability(path, inv, trans_id)
 
746
        self._pb.clear()
795
747
 
796
748
    def _set_executability(self, path, inv, trans_id):
797
749
        """Set the executability of versioned files """
905
857
def build_tree(tree, wt):
906
858
    """Create working tree for a branch, using a Transaction."""
907
859
    file_trans_id = {}
908
 
    top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
909
 
    pp = ProgressPhase("Build phase", 2, top_pb)
910
860
    tt = TreeTransform(wt)
911
861
    try:
912
 
        pp.next_phase()
913
862
        file_trans_id[wt.get_root_id()] = tt.trans_id_tree_file_id(wt.get_root_id())
914
863
        file_ids = topology_sorted_ids(tree)
915
 
        pb = bzrlib.ui.ui_factory.nested_progress_bar()
916
 
        try:
917
 
            for num, file_id in enumerate(file_ids):
918
 
                pb.update("Building tree", num, len(file_ids))
919
 
                entry = tree.inventory[file_id]
920
 
                if entry.parent_id is None:
921
 
                    continue
922
 
                if entry.parent_id not in file_trans_id:
923
 
                    raise repr(entry.parent_id)
924
 
                parent_id = file_trans_id[entry.parent_id]
925
 
                file_trans_id[file_id] = new_by_entry(tt, entry, parent_id, 
926
 
                                                      tree)
927
 
        finally:
928
 
            pb.finished()
929
 
        pp.next_phase()
 
864
        for file_id in file_ids:
 
865
            entry = tree.inventory[file_id]
 
866
            if entry.parent_id is None:
 
867
                continue
 
868
            if entry.parent_id not in file_trans_id:
 
869
                raise repr(entry.parent_id)
 
870
            parent_id = file_trans_id[entry.parent_id]
 
871
            file_trans_id[file_id] = new_by_entry(tt, entry, parent_id, tree)
930
872
        tt.apply()
931
873
    finally:
932
874
        tt.finalize()
933
 
        top_pb.finished()
934
875
 
935
876
def new_by_entry(tt, entry, parent_id, tree):
936
877
    """Create a new file according to its inventory entry"""
971
912
    else:
972
913
        interesting_ids = set()
973
914
        for tree_path in filenames:
974
 
            not_found = True
975
915
            for tree in (working_tree, target_tree):
 
916
                not_found = True
976
917
                file_id = tree.inventory.path2id(tree_path)
977
918
                if file_id is not None:
978
919
                    interesting_ids.add(file_id)
979
920
                    not_found = False
980
 
            if not_found:
981
 
                raise NotVersionedError(path=tree_path)
 
921
                if not_found:
 
922
                    raise NotVersionedError(path=tree_path)
982
923
    return interesting_ids
983
924
 
984
925
 
985
926
def change_entry(tt, file_id, working_tree, target_tree, 
986
 
                 trans_id_file_id, backups, trans_id, by_parent):
 
927
                 trans_id_file_id, backups, trans_id):
987
928
    """Replace a file_id's contents with those from a target tree."""
988
929
    e_trans_id = trans_id_file_id(file_id)
989
930
    entry = target_tree.inventory[file_id]
996
937
                tt.delete_contents(e_trans_id)
997
938
            else:
998
939
                parent_trans_id = trans_id_file_id(entry.parent_id)
999
 
                backup_name = get_backup_name(entry, by_parent,
1000
 
                                              parent_trans_id, tt)
1001
 
                tt.adjust_path(backup_name, parent_trans_id, e_trans_id)
 
940
                tt.adjust_path(entry.name+"~", parent_trans_id, e_trans_id)
1002
941
                tt.unversion_file(e_trans_id)
1003
942
                e_trans_id = tt.create_path(entry.name, parent_trans_id)
1004
943
                tt.version_file(file_id, e_trans_id)
1022
961
        tt.adjust_path(entry.name, parent_trans_id, e_trans_id)
1023
962
 
1024
963
 
1025
 
def get_backup_name(entry, by_parent, parent_trans_id, tt):
1026
 
    """Produce a backup-style name that appears to be available"""
1027
 
    def name_gen():
1028
 
        counter = 1
1029
 
        while True:
1030
 
            yield "%s.~%d~" % (entry.name, counter)
1031
 
            counter += 1
1032
 
    for name in name_gen():
1033
 
        if not tt.has_named_child(by_parent, parent_trans_id, name):
1034
 
            return name
1035
 
 
1036
964
def _entry_changes(file_id, entry, working_tree):
1037
965
    """Determine in which ways the inventory entry has changed.
1038
966
 
1074
1002
 
1075
1003
    tt = TreeTransform(working_tree, pb)
1076
1004
    try:
1077
 
        merge_modified = working_tree.merge_modified()
1078
1005
        trans_id = {}
1079
1006
        def trans_id_file_id(file_id):
1080
1007
            try:
1082
1009
            except KeyError:
1083
1010
                return tt.trans_id_tree_file_id(file_id)
1084
1011
 
1085
 
        pp = ProgressPhase("Revert phase", 4, pb)
1086
 
        pp.next_phase()
1087
1012
        sorted_interesting = [i for i in topology_sorted_ids(target_tree) if
1088
1013
                              interesting(i)]
1089
 
        child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1090
 
        try:
1091
 
            by_parent = tt.by_parent()
1092
 
            for id_num, file_id in enumerate(sorted_interesting):
1093
 
                child_pb.update("Reverting file", id_num+1, 
1094
 
                                len(sorted_interesting))
1095
 
                if file_id not in working_tree.inventory:
1096
 
                    entry = target_tree.inventory[file_id]
1097
 
                    parent_id = trans_id_file_id(entry.parent_id)
1098
 
                    e_trans_id = new_by_entry(tt, entry, parent_id, target_tree)
1099
 
                    trans_id[file_id] = e_trans_id
1100
 
                else:
1101
 
                    backup_this = backups
1102
 
                    if file_id in merge_modified:
1103
 
                        backup_this = False
1104
 
                        del merge_modified[file_id]
1105
 
                    change_entry(tt, file_id, working_tree, target_tree, 
1106
 
                                 trans_id_file_id, backup_this, trans_id,
1107
 
                                 by_parent)
1108
 
        finally:
1109
 
            child_pb.finished()
1110
 
        pp.next_phase()
 
1014
        for id_num, file_id in enumerate(sorted_interesting):
 
1015
            pb.update("Reverting file", id_num+1, len(sorted_interesting))
 
1016
            if file_id not in working_tree.inventory:
 
1017
                entry = target_tree.inventory[file_id]
 
1018
                parent_id = trans_id_file_id(entry.parent_id)
 
1019
                e_trans_id = new_by_entry(tt, entry, parent_id, target_tree)
 
1020
                trans_id[file_id] = e_trans_id
 
1021
            else:
 
1022
                change_entry(tt, file_id, working_tree, target_tree, 
 
1023
                             trans_id_file_id, backups, trans_id)
1111
1024
        wt_interesting = [i for i in working_tree.inventory if interesting(i)]
1112
 
        child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1113
 
        try:
1114
 
            for id_num, file_id in enumerate(wt_interesting):
1115
 
                child_pb.update("New file check", id_num+1, 
1116
 
                                len(sorted_interesting))
1117
 
                if file_id not in target_tree:
1118
 
                    trans_id = tt.trans_id_tree_file_id(file_id)
1119
 
                    tt.unversion_file(trans_id)
1120
 
                    if file_id in merge_modified:
1121
 
                        tt.delete_contents(trans_id)
1122
 
                        del merge_modified[file_id]
1123
 
        finally:
1124
 
            child_pb.finished()
1125
 
        pp.next_phase()
1126
 
        child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1127
 
        try:
1128
 
            raw_conflicts = resolve_conflicts(tt, child_pb)
1129
 
        finally:
1130
 
            child_pb.finished()
1131
 
        conflicts = cook_conflicts(raw_conflicts, tt)
1132
 
        for conflict in conflicts:
1133
 
            warning(conflict)
1134
 
        pp.next_phase()
 
1025
        for id_num, file_id in enumerate(wt_interesting):
 
1026
            pb.update("New file check", id_num+1, len(sorted_interesting))
 
1027
            if file_id not in target_tree:
 
1028
                tt.unversion_file(tt.trans_id_tree_file_id(file_id))
 
1029
        raw_conflicts = resolve_conflicts(tt, pb)
 
1030
        for line in conflicts_strings(cook_conflicts(raw_conflicts, tt)):
 
1031
            warning(line)
1135
1032
        tt.apply()
1136
 
        working_tree.set_merge_modified({})
1137
1033
    finally:
1138
1034
        tt.finalize()
1139
1035
        pb.clear()
1140
 
    return conflicts
1141
1036
 
1142
1037
 
1143
1038
def resolve_conflicts(tt, pb=DummyProgress()):
1200
1095
def cook_conflicts(raw_conflicts, tt):
1201
1096
    """Generate a list of cooked conflicts, sorted by file path"""
1202
1097
    def key(conflict):
1203
 
        if conflict.path is not None:
1204
 
            return conflict.path, conflict.typestring
1205
 
        elif getattr(conflict, "conflict_path", None) is not None:
1206
 
            return conflict.conflict_path, conflict.typestring
 
1098
        if conflict[2] is not None:
 
1099
            return conflict[2], conflict[0]
 
1100
        elif len(conflict) == 6:
 
1101
            return conflict[4], conflict[0]
1207
1102
        else:
1208
 
            return None, conflict.typestring
 
1103
            return None, conflict[0]
1209
1104
 
1210
1105
    return sorted(list(iter_cook_conflicts(raw_conflicts, tt)), key=key)
1211
1106
 
1212
1107
def iter_cook_conflicts(raw_conflicts, tt):
1213
 
    from bzrlib.conflicts import Conflict
 
1108
    cooked_conflicts = []
1214
1109
    fp = FinalPaths(tt)
1215
1110
    for conflict in raw_conflicts:
1216
1111
        c_type = conflict[0]
1218
1113
        modified_path = fp.get_path(conflict[2])
1219
1114
        modified_id = tt.final_file_id(conflict[2])
1220
1115
        if len(conflict) == 3:
1221
 
            yield Conflict.factory(c_type, action=action, path=modified_path,
1222
 
                                     file_id=modified_id)
1223
 
             
 
1116
            yield c_type, action, modified_path, modified_id
1224
1117
        else:
1225
1118
            conflicting_path = fp.get_path(conflict[3])
1226
1119
            conflicting_id = tt.final_file_id(conflict[3])
1227
 
            yield Conflict.factory(c_type, action=action, path=modified_path,
1228
 
                                   file_id=modified_id, 
1229
 
                                   conflict_path=conflicting_path,
1230
 
                                   conflict_file_id=conflicting_id)
 
1120
            yield (c_type, action, modified_path, modified_id, 
 
1121
                   conflicting_path, conflicting_id)
 
1122
 
 
1123
 
 
1124
def conflicts_strings(conflicts):
 
1125
    """Generate strings for the provided conflicts"""
 
1126
    for conflict in conflicts:
 
1127
        conflict_type = conflict[0]
 
1128
        if conflict_type == 'text conflict':
 
1129
            yield 'Text conflict in %s' % conflict[2]
 
1130
        elif conflict_type == 'contents conflict':
 
1131
            yield 'Contents conflict in %s' % conflict[2]
 
1132
        elif conflict_type == 'path conflict':
 
1133
            yield 'Path conflict: %s / %s' % conflict[2:]
 
1134
        elif conflict_type == 'duplicate id':
 
1135
            vals = (conflict[4], conflict[1], conflict[2])
 
1136
            yield 'Conflict adding id to %s.  %s %s.' % vals
 
1137
        elif conflict_type == 'duplicate':
 
1138
            vals = (conflict[4], conflict[1], conflict[2])
 
1139
            yield 'Conflict adding file %s.  %s %s.' % vals
 
1140
        elif conflict_type == 'parent loop':
 
1141
            vals = (conflict[4], conflict[2], conflict[1])
 
1142
            yield 'Conflict moving %s into %s.  %s.' % vals
 
1143
        elif conflict_type == 'unversioned parent':
 
1144
            vals = (conflict[2], conflict[1])
 
1145
            yield 'Conflict adding versioned files to %s.  %s.' % vals
 
1146
        elif conflict_type == 'missing parent':
 
1147
            vals = (conflict[2], conflict[1])
 
1148
            yield 'Conflict adding files to %s.  %s.' % vals