/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: John Arbash Meinel
  • Date: 2006-09-20 14:51:03 UTC
  • mfrom: (0.8.23 version_info)
  • mto: This revision was merged to the branch mainline in revision 2028.
  • Revision ID: john@arbash-meinel.com-20060920145103-02725c6d6c886040
[merge] version-info plugin, and cleanup for layout in bzr

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006, 2007 Canonical Ltd
 
1
# Copyright (C) 2006 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
18
18
import errno
19
19
from stat import S_ISREG
20
20
 
21
 
from bzrlib.lazy_import import lazy_import
22
 
lazy_import(globals(), """
23
 
from bzrlib import (
24
 
    bzrdir,
25
 
    delta,
26
 
    errors,
27
 
    inventory
28
 
    )
29
 
""")
 
21
from bzrlib import bzrdir, errors
30
22
from bzrlib.errors import (DuplicateKey, MalformedTransform, NoSuchFile,
31
23
                           ReusingTransform, NotVersionedError, CantMoveRoot,
32
 
                           ExistingLimbo, ImmortalLimbo, NoFinalPath)
 
24
                           ExistingLimbo, ImmortalLimbo)
33
25
from bzrlib.inventory import InventoryEntry
34
26
from bzrlib.osutils import (file_kind, supports_executable, pathjoin, lexists,
35
27
                            delete_any)
36
28
from bzrlib.progress import DummyProgress, ProgressPhase
37
 
from bzrlib.symbol_versioning import deprecated_function, zero_fifteen
38
29
from bzrlib.trace import mutter, warning
39
30
from bzrlib import tree
40
 
import bzrlib.ui
 
31
import bzrlib.ui 
41
32
import bzrlib.urlutils as urlutils
42
33
 
43
34
 
108
99
        self._new_contents = {}
109
100
        self._removed_contents = set()
110
101
        self._new_executability = {}
111
 
        self._new_reference_revision = {}
112
102
        self._new_id = {}
113
103
        self._non_present_ids = {}
114
104
        self._r_new_id = {}
283
273
                os.unlink(name)
284
274
                raise
285
275
 
286
 
            f.writelines(contents)
 
276
            for segment in contents:
 
277
                f.write(segment)
287
278
        finally:
288
279
            f.close()
289
280
        self._set_mode(trans_id, mode_id, S_ISREG)
301
292
        except KeyError:
302
293
            return
303
294
        try:
304
 
            mode = os.stat(self._tree.abspath(old_path)).st_mode
 
295
            mode = os.stat(old_path).st_mode
305
296
        except OSError, e:
306
297
            if e.errno == errno.ENOENT:
307
298
                return
359
350
        else:
360
351
            unique_add(self._new_executability, trans_id, executability)
361
352
 
362
 
    def set_tree_reference(self, revision_id, trans_id):
363
 
        """Set the reference associated with a directory"""
364
 
        unique_add(self._new_reference_revision, trans_id, revision_id)
365
 
 
366
353
    def version_file(self, file_id, trans_id):
367
354
        """Schedule a file to become versioned."""
368
355
        assert file_id is not None
470
457
        try:
471
458
            return self._new_name[trans_id]
472
459
        except KeyError:
473
 
            try:
474
 
                return os.path.basename(self._tree_id_paths[trans_id])
475
 
            except KeyError:
476
 
                raise NoFinalPath(trans_id, self)
 
460
            return os.path.basename(self._tree_id_paths[trans_id])
477
461
 
478
462
    def by_parent(self):
479
463
        """Return a map of parent: children for known parents.
586
570
            parent_id = trans_id
587
571
            while parent_id is not ROOT_PARENT:
588
572
                seen.add(parent_id)
589
 
                try:
590
 
                    parent_id = self.final_parent(parent_id)
591
 
                except KeyError:
592
 
                    break
 
573
                parent_id = self.final_parent(parent_id)
593
574
                if parent_id == trans_id:
594
575
                    conflicts.append(('parent loop', trans_id))
595
576
                if parent_id in seen:
738
719
        conflicts = self.find_conflicts()
739
720
        if len(conflicts) != 0:
740
721
            raise MalformedTransform(conflicts=conflicts)
 
722
        limbo_inv = {}
741
723
        inv = self._tree.inventory
742
 
        inventory_delta = []
743
724
        child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
744
725
        try:
745
726
            child_pb.update('Apply phase', 0, 2)
746
 
            self._apply_removals(inv, inventory_delta)
 
727
            self._apply_removals(inv, limbo_inv)
747
728
            child_pb.update('Apply phase', 1, 2)
748
 
            modified_paths = self._apply_insertions(inv, inventory_delta)
 
729
            modified_paths = self._apply_insertions(inv, limbo_inv)
749
730
        finally:
750
731
            child_pb.finished()
751
 
        self._tree.apply_inventory_delta(inventory_delta)
 
732
        self._tree._write_inventory(inv)
752
733
        self.__done = True
753
734
        self.finalize()
754
735
        return _TransformResults(modified_paths)
757
738
        """Generate the limbo name of a file"""
758
739
        return pathjoin(self._limbodir, trans_id)
759
740
 
760
 
    def _apply_removals(self, inv, inventory_delta):
 
741
    def _apply_removals(self, inv, limbo_inv):
761
742
        """Perform tree operations that remove directory/inventory names.
762
743
        
763
744
        That is, delete files that are to be deleted, and put any files that
786
767
                        file_id = self._tree.inventory.root.file_id
787
768
                    else:
788
769
                        file_id = self.tree_file_id(trans_id)
789
 
                    assert file_id is not None
790
 
                    inventory_delta.append((path, None, file_id, None))
 
770
                    del inv[file_id]
 
771
                elif trans_id in self._new_name or trans_id in self._new_parent:
 
772
                    file_id = self.tree_file_id(trans_id)
 
773
                    if file_id is not None:
 
774
                        limbo_inv[trans_id] = inv[file_id]
 
775
                        del inv[file_id]
791
776
        finally:
792
777
            child_pb.finished()
793
778
 
794
 
    def _apply_insertions(self, inv, inventory_delta):
 
779
    def _apply_insertions(self, inv, limbo_inv):
795
780
        """Perform tree operations that insert directory/inventory names.
796
781
        
797
782
        That is, create any files that need to be created, and restore from
803
788
        child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
804
789
        try:
805
790
            for num, (path, trans_id) in enumerate(new_paths):
806
 
                new_entry = None
807
791
                child_pb.update('adding file', num, len(new_paths))
808
792
                try:
809
793
                    kind = self._new_contents[trans_id]
825
809
                if trans_id in self._new_id:
826
810
                    if kind is None:
827
811
                        kind = file_kind(self._tree.abspath(path))
828
 
                    if trans_id in self._new_reference_revision:
829
 
                        new_entry = inventory.TreeReference(
830
 
                            self._new_id[trans_id],
831
 
                            self._new_name[trans_id], 
832
 
                            self.final_file_id(self._new_parent[trans_id]),
833
 
                            None, self._new_reference_revision[trans_id])
834
 
                    else:
835
 
                        new_entry = inventory.make_entry(kind,
836
 
                            self.final_name(trans_id),
837
 
                            self.final_file_id(self.final_parent(trans_id)),
838
 
                            self._new_id[trans_id])
839
 
                else:
840
 
                    if trans_id in self._new_name or trans_id in\
841
 
                        self._new_parent or\
842
 
                        trans_id in self._new_executability:
843
 
                        file_id = self.final_file_id(trans_id)
844
 
                        if file_id is not None:
845
 
                            entry = inv[file_id]
846
 
                            new_entry = entry.copy()
847
 
 
848
 
                    if trans_id in self._new_name or trans_id in\
849
 
                        self._new_parent:
850
 
                            if new_entry is not None:
851
 
                                new_entry.name = self.final_name(trans_id)
852
 
                                parent = self.final_parent(trans_id)
853
 
                                parent_id = self.final_file_id(parent)
854
 
                                new_entry.parent_id = parent_id
855
 
 
 
812
                    inv.add_path(path, kind, self._new_id[trans_id])
 
813
                elif trans_id in self._new_name or trans_id in\
 
814
                    self._new_parent:
 
815
                    entry = limbo_inv.get(trans_id)
 
816
                    if entry is not None:
 
817
                        entry.name = self.final_name(trans_id)
 
818
                        parent_path = os.path.dirname(path)
 
819
                        entry.parent_id = \
 
820
                            self._tree.inventory.path2id(parent_path)
 
821
                        inv.add(entry)
 
822
 
 
823
                # requires files and inventory entries to be in place
856
824
                if trans_id in self._new_executability:
857
 
                    self._set_executability(path, new_entry, trans_id)
858
 
                if new_entry is not None:
859
 
                    if new_entry.file_id in inv:
860
 
                        old_path = inv.id2path(new_entry.file_id)
861
 
                    else:
862
 
                        old_path = None
863
 
                    inventory_delta.append((old_path, path,
864
 
                                            new_entry.file_id,
865
 
                                            new_entry))
 
825
                    self._set_executability(path, inv, trans_id)
866
826
        finally:
867
827
            child_pb.finished()
868
828
        return modified_paths
869
829
 
870
 
    def _set_executability(self, path, entry, trans_id):
 
830
    def _set_executability(self, path, inv, trans_id):
871
831
        """Set the executability of versioned files """
 
832
        file_id = inv.path2id(path)
872
833
        new_executability = self._new_executability[trans_id]
873
 
        entry.executable = new_executability
 
834
        inv[file_id].executable = new_executability
874
835
        if supports_executable():
875
836
            abspath = self._tree.abspath(path)
876
837
            current_mode = os.stat(abspath).st_mode
937
898
        self.create_symlink(target, trans_id)
938
899
        return trans_id
939
900
 
940
 
    def _affected_ids(self):
941
 
        """Return the set of transform ids affected by the transform"""
942
 
        trans_ids = set(self._removed_id)
943
 
        trans_ids.update(self._new_id.keys())
944
 
        trans_ids.update(self._removed_contents)
945
 
        trans_ids.update(self._new_contents.keys())
946
 
        trans_ids.update(self._new_executability.keys())
947
 
        trans_ids.update(self._new_name.keys())
948
 
        trans_ids.update(self._new_parent.keys())
949
 
        return trans_ids
950
 
 
951
 
    def _get_file_id_maps(self):
952
 
        """Return mapping of file_ids to trans_ids in the to and from states"""
953
 
        trans_ids = self._affected_ids()
954
 
        from_trans_ids = {}
955
 
        to_trans_ids = {}
956
 
        # Build up two dicts: trans_ids associated with file ids in the
957
 
        # FROM state, vs the TO state.
958
 
        for trans_id in trans_ids:
959
 
            from_file_id = self.tree_file_id(trans_id)
960
 
            if from_file_id is not None:
961
 
                from_trans_ids[from_file_id] = trans_id
962
 
            to_file_id = self.final_file_id(trans_id)
963
 
            if to_file_id is not None:
964
 
                to_trans_ids[to_file_id] = trans_id
965
 
        return from_trans_ids, to_trans_ids
966
 
 
967
 
    def _from_file_data(self, from_trans_id, from_versioned, file_id):
968
 
        """Get data about a file in the from (tree) state
969
 
 
970
 
        Return a (name, parent, kind, executable) tuple
971
 
        """
972
 
        from_path = self._tree_id_paths.get(from_trans_id)
973
 
        if from_versioned:
974
 
            # get data from working tree if versioned
975
 
            from_entry = self._tree.inventory[file_id]
976
 
            from_name = from_entry.name
977
 
            from_parent = from_entry.parent_id
978
 
        else:
979
 
            from_entry = None
980
 
            if from_path is None:
981
 
                # File does not exist in FROM state
982
 
                from_name = None
983
 
                from_parent = None
984
 
            else:
985
 
                # File exists, but is not versioned.  Have to use path-
986
 
                # splitting stuff
987
 
                from_name = os.path.basename(from_path)
988
 
                tree_parent = self.get_tree_parent(from_trans_id)
989
 
                from_parent = self.tree_file_id(tree_parent)
990
 
        if from_path is not None:
991
 
            from_kind, from_executable, from_stats = \
992
 
                self._tree._comparison_data(from_entry, from_path)
993
 
        else:
994
 
            from_kind = None
995
 
            from_executable = False
996
 
        return from_name, from_parent, from_kind, from_executable
997
 
 
998
 
    def _to_file_data(self, to_trans_id, from_trans_id, from_executable):
999
 
        """Get data about a file in the to (target) state
1000
 
 
1001
 
        Return a (name, parent, kind, executable) tuple
1002
 
        """
1003
 
        to_name = self.final_name(to_trans_id)
1004
 
        try:
1005
 
            to_kind = self.final_kind(to_trans_id)
1006
 
        except NoSuchFile:
1007
 
            to_kind = None
1008
 
        to_parent = self.final_file_id(self.final_parent(to_trans_id))
1009
 
        if to_trans_id in self._new_executability:
1010
 
            to_executable = self._new_executability[to_trans_id]
1011
 
        elif to_trans_id == from_trans_id:
1012
 
            to_executable = from_executable
1013
 
        else:
1014
 
            to_executable = False
1015
 
        return to_name, to_parent, to_kind, to_executable
1016
 
 
1017
 
    def _iter_changes(self):
1018
 
        """Produce output in the same format as Tree._iter_changes.
1019
 
 
1020
 
        Will produce nonsensical results if invoked while inventory/filesystem
1021
 
        conflicts (as reported by TreeTransform.find_conflicts()) are present.
1022
 
 
1023
 
        This reads the Transform, but only reproduces changes involving a
1024
 
        file_id.  Files that are not versioned in either of the FROM or TO
1025
 
        states are not reflected.
1026
 
        """
1027
 
        final_paths = FinalPaths(self)
1028
 
        from_trans_ids, to_trans_ids = self._get_file_id_maps()
1029
 
        results = []
1030
 
        # Now iterate through all active file_ids
1031
 
        for file_id in set(from_trans_ids.keys() + to_trans_ids.keys()):
1032
 
            modified = False
1033
 
            from_trans_id = from_trans_ids.get(file_id)
1034
 
            # find file ids, and determine versioning state
1035
 
            if from_trans_id is None:
1036
 
                from_versioned = False
1037
 
                from_trans_id = to_trans_ids[file_id]
1038
 
            else:
1039
 
                from_versioned = True
1040
 
            to_trans_id = to_trans_ids.get(file_id)
1041
 
            if to_trans_id is None:
1042
 
                to_versioned = False
1043
 
                to_trans_id = from_trans_id
1044
 
            else:
1045
 
                to_versioned = True
1046
 
 
1047
 
            from_name, from_parent, from_kind, from_executable = \
1048
 
                self._from_file_data(from_trans_id, from_versioned, file_id)
1049
 
 
1050
 
            to_name, to_parent, to_kind, to_executable = \
1051
 
                self._to_file_data(to_trans_id, from_trans_id, from_executable)
1052
 
 
1053
 
            if not from_versioned:
1054
 
                from_path = None
1055
 
            else:
1056
 
                from_path = self._tree_id_paths.get(from_trans_id)
1057
 
            if not to_versioned:
1058
 
                to_path = None
1059
 
            else:
1060
 
                to_path = final_paths.get_path(to_trans_id)
1061
 
            if from_kind != to_kind:
1062
 
                modified = True
1063
 
            elif to_kind in ('file', 'symlink') and (
1064
 
                to_trans_id != from_trans_id or
1065
 
                to_trans_id in self._new_contents):
1066
 
                modified = True
1067
 
            if (not modified and from_versioned == to_versioned and
1068
 
                from_parent==to_parent and from_name == to_name and
1069
 
                from_executable == to_executable):
1070
 
                continue
1071
 
            results.append((file_id, (from_path, to_path), modified,
1072
 
                   (from_versioned, to_versioned),
1073
 
                   (from_parent, to_parent),
1074
 
                   (from_name, to_name),
1075
 
                   (from_kind, to_kind),
1076
 
                   (from_executable, to_executable)))
1077
 
        return iter(sorted(results, key=lambda x:x[1]))
1078
 
 
1079
 
 
1080
901
def joinpath(parent, child):
1081
902
    """Join tree-relative paths, handling the tree root specially"""
1082
903
    if parent is None or parent == "":
1133
954
      it is silently replaced.
1134
955
    - Otherwise, conflict resolution will move the old file to 'oldname.moved'.
1135
956
    """
1136
 
    wt.lock_tree_write()
1137
 
    try:
1138
 
        tree.lock_read()
1139
 
        try:
1140
 
            return _build_tree(tree, wt)
1141
 
        finally:
1142
 
            tree.unlock()
1143
 
    finally:
1144
 
        wt.unlock()
1145
 
 
1146
 
def _build_tree(tree, wt):
1147
 
    """See build_tree."""
1148
 
    if len(wt.inventory) > 1:  # more than just a root
1149
 
        raise errors.WorkingTreeAlreadyPopulated(base=wt.basedir)
 
957
    assert 2 > len(wt.inventory)
1150
958
    file_trans_id = {}
1151
959
    top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1152
960
    pp = ProgressPhase("Build phase", 2, top_pb)
1153
 
    if tree.inventory.root is not None:
1154
 
        # this is kindof a hack: we should be altering the root 
1155
 
        # as partof the regular tree shape diff logic.
1156
 
        # the conditional test hereis to avoid doing an
1157
 
        # expensive operation (flush) every time the root id
1158
 
        # is set within the tree, nor setting the root and thus
1159
 
        # marking the tree as dirty, because we use two different
1160
 
        # idioms here: tree interfaces and inventory interfaces.
1161
 
        if wt.path2id('') != tree.inventory.root.file_id:
1162
 
            wt.set_root_id(tree.inventory.root.file_id)
1163
 
            wt.flush()
1164
961
    tt = TreeTransform(wt)
1165
962
    divert = set()
1166
963
    try:
1196
993
                        if kind == 'directory':
1197
994
                            reparent = True
1198
995
                if entry.parent_id not in file_trans_id:
1199
 
                    raise AssertionError(
1200
 
                        'entry %s parent id %r is not in file_trans_id %r'
1201
 
                        % (entry, entry.parent_id, file_trans_id))
 
996
                    raise repr(entry.parent_id)
1202
997
                parent_id = file_trans_id[entry.parent_id]
1203
998
                file_trans_id[file_id] = new_by_entry(tt, entry, parent_id,
1204
999
                                                      tree)
1282
1077
        executable = tree.is_executable(entry.file_id)
1283
1078
        return tt.new_file(name, parent_id, contents, entry.file_id, 
1284
1079
                           executable)
1285
 
    elif kind in ('directory', 'tree-reference'):
1286
 
        trans_id = tt.new_directory(name, parent_id, entry.file_id)
1287
 
        if kind == 'tree-reference':
1288
 
            tt.set_tree_reference(entry.reference_revision, trans_id)
1289
 
        return trans_id 
 
1080
    elif kind == 'directory':
 
1081
        return tt.new_directory(name, parent_id, entry.file_id)
1290
1082
    elif kind == 'symlink':
1291
1083
        target = tree.get_symlink_target(entry.file_id)
1292
1084
        return tt.new_symlink(name, parent_id, target, entry.file_id)
1293
 
    else:
1294
 
        raise errors.BadFileKindError(name, kind)
1295
1085
 
1296
1086
def create_by_entry(tt, entry, tree, trans_id, lines=None, mode_id=None):
1297
1087
    """Create new file contents according to an inventory entry."""
1310
1100
        tt.set_executability(entry.executable, trans_id)
1311
1101
 
1312
1102
 
1313
 
@deprecated_function(zero_fifteen)
1314
1103
def find_interesting(working_tree, target_tree, filenames):
1315
 
    """Find the ids corresponding to specified filenames.
1316
 
    
1317
 
    Deprecated: Please use tree1.paths2ids(filenames, [tree2]).
1318
 
    """
1319
 
    working_tree.lock_read()
1320
 
    try:
1321
 
        target_tree.lock_read()
1322
 
        try:
1323
 
            return working_tree.paths2ids(filenames, [target_tree])
1324
 
        finally:
1325
 
            target_tree.unlock()
1326
 
    finally:
1327
 
        working_tree.unlock()
 
1104
    """Find the ids corresponding to specified filenames."""
 
1105
    trees = (working_tree, target_tree)
 
1106
    return tree.find_ids_across_trees(filenames, trees)
1328
1107
 
1329
1108
 
1330
1109
def change_entry(tt, file_id, working_tree, target_tree, 
1368
1147
 
1369
1148
 
1370
1149
def get_backup_name(entry, by_parent, parent_trans_id, tt):
1371
 
    return _get_backup_name(entry.name, by_parent, parent_trans_id, tt)
1372
 
 
1373
 
 
1374
 
def _get_backup_name(name, by_parent, parent_trans_id, tt):
1375
1150
    """Produce a backup-style name that appears to be available"""
1376
1151
    def name_gen():
1377
1152
        counter = 1
1378
1153
        while True:
1379
 
            yield "%s.~%d~" % (name, counter)
 
1154
            yield "%s.~%d~" % (entry.name, counter)
1380
1155
            counter += 1
1381
 
    for new_name in name_gen():
1382
 
        if not tt.has_named_child(by_parent, parent_trans_id, new_name):
1383
 
            return new_name
1384
 
 
 
1156
    for name in name_gen():
 
1157
        if not tt.has_named_child(by_parent, parent_trans_id, name):
 
1158
            return name
1385
1159
 
1386
1160
def _entry_changes(file_id, entry, working_tree):
1387
1161
    """Determine in which ways the inventory entry has changed.
1410
1184
    return has_contents, contents_mod, meta_mod
1411
1185
 
1412
1186
 
1413
 
def revert(working_tree, target_tree, filenames, backups=False,
1414
 
           pb=DummyProgress(), change_reporter=None):
 
1187
def revert(working_tree, target_tree, filenames, backups=False, 
 
1188
           pb=DummyProgress()):
1415
1189
    """Revert a working tree's contents to those of a target tree."""
1416
 
    target_tree.lock_read()
 
1190
    interesting_ids = find_interesting(working_tree, target_tree, filenames)
 
1191
    def interesting(file_id):
 
1192
        return interesting_ids is None or (file_id in interesting_ids)
 
1193
 
1417
1194
    tt = TreeTransform(working_tree, pb)
1418
1195
    try:
1419
 
        pp = ProgressPhase("Revert phase", 3, pb)
1420
 
        pp.next_phase()
1421
 
        child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1422
 
        try:
1423
 
            _alter_files(working_tree, target_tree, tt, child_pb,
1424
 
                         filenames, backups)
 
1196
        merge_modified = working_tree.merge_modified()
 
1197
        trans_id = {}
 
1198
        def trans_id_file_id(file_id):
 
1199
            try:
 
1200
                return trans_id[file_id]
 
1201
            except KeyError:
 
1202
                return tt.trans_id_tree_file_id(file_id)
 
1203
 
 
1204
        pp = ProgressPhase("Revert phase", 4, pb)
 
1205
        pp.next_phase()
 
1206
        sorted_interesting = [i for i in topology_sorted_ids(target_tree) if
 
1207
                              interesting(i)]
 
1208
        child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
 
1209
        try:
 
1210
            by_parent = tt.by_parent()
 
1211
            for id_num, file_id in enumerate(sorted_interesting):
 
1212
                child_pb.update("Reverting file", id_num+1, 
 
1213
                                len(sorted_interesting))
 
1214
                if file_id not in working_tree.inventory:
 
1215
                    entry = target_tree.inventory[file_id]
 
1216
                    parent_id = trans_id_file_id(entry.parent_id)
 
1217
                    e_trans_id = new_by_entry(tt, entry, parent_id, target_tree)
 
1218
                    trans_id[file_id] = e_trans_id
 
1219
                else:
 
1220
                    backup_this = backups
 
1221
                    if file_id in merge_modified:
 
1222
                        backup_this = False
 
1223
                        del merge_modified[file_id]
 
1224
                    change_entry(tt, file_id, working_tree, target_tree, 
 
1225
                                 trans_id_file_id, backup_this, trans_id,
 
1226
                                 by_parent)
 
1227
        finally:
 
1228
            child_pb.finished()
 
1229
        pp.next_phase()
 
1230
        wt_interesting = [i for i in working_tree.inventory if interesting(i)]
 
1231
        child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
 
1232
        try:
 
1233
            for id_num, file_id in enumerate(wt_interesting):
 
1234
                child_pb.update("New file check", id_num+1, 
 
1235
                                len(sorted_interesting))
 
1236
                if file_id not in target_tree:
 
1237
                    trans_id = tt.trans_id_tree_file_id(file_id)
 
1238
                    tt.unversion_file(trans_id)
 
1239
                    try:
 
1240
                        file_kind = working_tree.kind(file_id)
 
1241
                    except NoSuchFile:
 
1242
                        file_kind = None
 
1243
                    if file_kind != 'file' and file_kind is not None:
 
1244
                        keep_contents = False
 
1245
                        delete_merge_modified = False
 
1246
                    else:
 
1247
                        if (file_id in merge_modified and 
 
1248
                            merge_modified[file_id] == 
 
1249
                            working_tree.get_file_sha1(file_id)):
 
1250
                            keep_contents = False
 
1251
                            delete_merge_modified = True
 
1252
                        else:
 
1253
                            keep_contents = True
 
1254
                            delete_merge_modified = False
 
1255
                    if not keep_contents:
 
1256
                        tt.delete_contents(trans_id)
 
1257
                    if delete_merge_modified:
 
1258
                        del merge_modified[file_id]
1425
1259
        finally:
1426
1260
            child_pb.finished()
1427
1261
        pp.next_phase()
1431
1265
        finally:
1432
1266
            child_pb.finished()
1433
1267
        conflicts = cook_conflicts(raw_conflicts, tt)
1434
 
        if change_reporter:
1435
 
            change_reporter = delta._ChangeReporter(
1436
 
                unversioned_filter=working_tree.is_ignored)
1437
 
            delta.report_changes(tt._iter_changes(), change_reporter)
1438
1268
        for conflict in conflicts:
1439
1269
            warning(conflict)
1440
1270
        pp.next_phase()
1441
1271
        tt.apply()
1442
1272
        working_tree.set_merge_modified({})
1443
1273
    finally:
1444
 
        target_tree.unlock()
1445
1274
        tt.finalize()
1446
1275
        pb.clear()
1447
1276
    return conflicts
1448
1277
 
1449
1278
 
1450
 
def _alter_files(working_tree, target_tree, tt, pb, specific_files,
1451
 
                 backups):
1452
 
    merge_modified = working_tree.merge_modified()
1453
 
    change_list = target_tree._iter_changes(working_tree,
1454
 
        specific_files=specific_files, pb=pb)
1455
 
    if target_tree.inventory.root is None:
1456
 
        skip_root = True
1457
 
    else:
1458
 
        skip_root = False
1459
 
    basis_tree = None
1460
 
    try:
1461
 
        for id_num, (file_id, path, changed_content, versioned, parent, name,
1462
 
                kind, executable) in enumerate(change_list):
1463
 
            if skip_root and file_id[0] is not None and parent[0] is None:
1464
 
                continue
1465
 
            trans_id = tt.trans_id_file_id(file_id)
1466
 
            mode_id = None
1467
 
            if changed_content:
1468
 
                keep_content = False
1469
 
                if kind[0] == 'file' and (backups or kind[1] is None):
1470
 
                    wt_sha1 = working_tree.get_file_sha1(file_id)
1471
 
                    if merge_modified.get(file_id) != wt_sha1:
1472
 
                        # acquire the basis tree lazyily to prevent the expense
1473
 
                        # of accessing it when its not needed ? (Guessing, RBC,
1474
 
                        # 200702)
1475
 
                        if basis_tree is None:
1476
 
                            basis_tree = working_tree.basis_tree()
1477
 
                            basis_tree.lock_read()
1478
 
                        if file_id in basis_tree:
1479
 
                            if wt_sha1 != basis_tree.get_file_sha1(file_id):
1480
 
                                keep_content = True
1481
 
                        elif kind[1] is None and not versioned[1]:
1482
 
                            keep_content = True
1483
 
                if kind[0] is not None:
1484
 
                    if not keep_content:
1485
 
                        tt.delete_contents(trans_id)
1486
 
                    elif kind[1] is not None:
1487
 
                        parent_trans_id = tt.trans_id_file_id(parent[0])
1488
 
                        by_parent = tt.by_parent()
1489
 
                        backup_name = _get_backup_name(name[0], by_parent,
1490
 
                                                       parent_trans_id, tt)
1491
 
                        tt.adjust_path(backup_name, parent_trans_id, trans_id)
1492
 
                        new_trans_id = tt.create_path(name[0], parent_trans_id)
1493
 
                        if versioned == (True, True):
1494
 
                            tt.unversion_file(trans_id)
1495
 
                            tt.version_file(file_id, new_trans_id)
1496
 
                        # New contents should have the same unix perms as old
1497
 
                        # contents
1498
 
                        mode_id = trans_id
1499
 
                        trans_id = new_trans_id
1500
 
                if kind[1] == 'directory':
1501
 
                    tt.create_directory(trans_id)
1502
 
                elif kind[1] == 'symlink':
1503
 
                    tt.create_symlink(target_tree.get_symlink_target(file_id),
1504
 
                                      trans_id)
1505
 
                elif kind[1] == 'file':
1506
 
                    tt.create_file(target_tree.get_file_lines(file_id),
1507
 
                                   trans_id, mode_id)
1508
 
                    # preserve the execute bit when backing up
1509
 
                    if keep_content and executable[0] == executable[1]:
1510
 
                        tt.set_executability(executable[1], trans_id)
1511
 
                else:
1512
 
                    assert kind[1] is None
1513
 
            if versioned == (False, True):
1514
 
                tt.version_file(file_id, trans_id)
1515
 
            if versioned == (True, False):
1516
 
                tt.unversion_file(trans_id)
1517
 
            if (name[1] is not None and 
1518
 
                (name[0] != name[1] or parent[0] != parent[1])):
1519
 
                tt.adjust_path(
1520
 
                    name[1], tt.trans_id_file_id(parent[1]), trans_id)
1521
 
            if executable[0] != executable[1] and kind[1] == "file":
1522
 
                tt.set_executability(executable[1], trans_id)
1523
 
    finally:
1524
 
        if basis_tree is not None:
1525
 
            basis_tree.unlock()
1526
 
 
1527
 
 
1528
1279
def resolve_conflicts(tt, pb=DummyProgress(), pass_func=None):
1529
1280
    """Make many conflict-resolution attempts, but die if they fail"""
1530
1281
    if pass_func is None: