~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transform.py

  • Committer: Aaron Bentley
  • Date: 2007-02-16 07:02:19 UTC
  • mfrom: (2292 +trunk)
  • mto: (2255.6.1 dirstate)
  • mto: This revision was merged to the branch mainline in revision 2322.
  • Revision ID: aaron.bentley@utoronto.ca-20070216070219-b22k0gwnisnxawnk
Merged bzr.dev (17 tests failing)

Show diffs side-by-side

added added

removed removed

Lines of Context:
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(), """
21
23
from bzrlib import (
22
24
    bzrdir,
 
25
    delta,
23
26
    errors,
24
27
    inventory
25
28
    )
 
29
""")
26
30
from bzrlib.errors import (DuplicateKey, MalformedTransform, NoSuchFile,
27
31
                           ReusingTransform, NotVersionedError, CantMoveRoot,
28
32
                           ExistingLimbo, ImmortalLimbo, NoFinalPath)
919
923
        self.create_symlink(target, trans_id)
920
924
        return trans_id
921
925
 
 
926
    def _affected_ids(self):
 
927
        """Return the set of transform ids affected by the transform"""
 
928
        trans_ids = set(self._removed_id)
 
929
        trans_ids.update(self._new_id.keys())
 
930
        trans_ids.update(self._removed_contents)
 
931
        trans_ids.update(self._new_contents.keys())
 
932
        trans_ids.update(self._new_executability.keys())
 
933
        trans_ids.update(self._new_name.keys())
 
934
        trans_ids.update(self._new_parent.keys())
 
935
        return trans_ids
 
936
 
 
937
    def _get_file_id_maps(self):
 
938
        """Return mapping of file_ids to trans_ids in the to and from states"""
 
939
        trans_ids = self._affected_ids()
 
940
        from_trans_ids = {}
 
941
        to_trans_ids = {}
 
942
        # Build up two dicts: trans_ids associated with file ids in the
 
943
        # FROM state, vs the TO state.
 
944
        for trans_id in trans_ids:
 
945
            from_file_id = self.tree_file_id(trans_id)
 
946
            if from_file_id is not None:
 
947
                from_trans_ids[from_file_id] = trans_id
 
948
            to_file_id = self.final_file_id(trans_id)
 
949
            if to_file_id is not None:
 
950
                to_trans_ids[to_file_id] = trans_id
 
951
        return from_trans_ids, to_trans_ids
 
952
 
 
953
    def _from_file_data(self, from_trans_id, from_versioned, file_id):
 
954
        """Get data about a file in the from (tree) state
 
955
 
 
956
        Return a (name, parent, kind, executable) tuple
 
957
        """
 
958
        from_path = self._tree_id_paths.get(from_trans_id)
 
959
        if from_versioned:
 
960
            # get data from working tree if versioned
 
961
            from_entry = self._tree.inventory[file_id]
 
962
            from_name = from_entry.name
 
963
            from_parent = from_entry.parent_id
 
964
        else:
 
965
            from_entry = None
 
966
            if from_path is None:
 
967
                # File does not exist in FROM state
 
968
                from_name = None
 
969
                from_parent = None
 
970
            else:
 
971
                # File exists, but is not versioned.  Have to use path-
 
972
                # splitting stuff
 
973
                from_name = os.path.basename(from_path)
 
974
                tree_parent = self.get_tree_parent(from_trans_id)
 
975
                from_parent = self.tree_file_id(tree_parent)
 
976
        if from_path is not None:
 
977
            from_kind, from_executable, from_stats = \
 
978
                self._tree._comparison_data(from_entry, from_path)
 
979
        else:
 
980
            from_kind = None
 
981
            from_executable = False
 
982
        return from_name, from_parent, from_kind, from_executable
 
983
 
 
984
    def _to_file_data(self, to_trans_id, from_trans_id, from_executable):
 
985
        """Get data about a file in the to (target) state
 
986
 
 
987
        Return a (name, parent, kind, executable) tuple
 
988
        """
 
989
        to_name = self.final_name(to_trans_id)
 
990
        try:
 
991
            to_kind = self.final_kind(to_trans_id)
 
992
        except NoSuchFile:
 
993
            to_kind = None
 
994
        to_parent = self.final_file_id(self.final_parent(to_trans_id))
 
995
        if to_trans_id in self._new_executability:
 
996
            to_executable = self._new_executability[to_trans_id]
 
997
        elif to_trans_id == from_trans_id:
 
998
            to_executable = from_executable
 
999
        else:
 
1000
            to_executable = False
 
1001
        return to_name, to_parent, to_kind, to_executable
 
1002
 
 
1003
    def _iter_changes(self):
 
1004
        """Produce output in the same format as Tree._iter_changes.
 
1005
 
 
1006
        Will produce nonsensical results if invoked while inventory/filesystem
 
1007
        conflicts (as reported by TreeTransform.find_conflicts()) are present.
 
1008
 
 
1009
        This reads the Transform, but only reproduces changes involving a
 
1010
        file_id.  Files that are not versioned in either of the FROM or TO
 
1011
        states are not reflected.
 
1012
        """
 
1013
        final_paths = FinalPaths(self)
 
1014
        from_trans_ids, to_trans_ids = self._get_file_id_maps()
 
1015
        results = []
 
1016
        # Now iterate through all active file_ids
 
1017
        for file_id in set(from_trans_ids.keys() + to_trans_ids.keys()):
 
1018
            modified = False
 
1019
            from_trans_id = from_trans_ids.get(file_id)
 
1020
            # find file ids, and determine versioning state
 
1021
            if from_trans_id is None:
 
1022
                from_versioned = False
 
1023
                from_trans_id = to_trans_ids[file_id]
 
1024
            else:
 
1025
                from_versioned = True
 
1026
            to_trans_id = to_trans_ids.get(file_id)
 
1027
            if to_trans_id is None:
 
1028
                to_versioned = False
 
1029
                to_trans_id = from_trans_id
 
1030
            else:
 
1031
                to_versioned = True
 
1032
 
 
1033
            from_name, from_parent, from_kind, from_executable = \
 
1034
                self._from_file_data(from_trans_id, from_versioned, file_id)
 
1035
 
 
1036
            to_name, to_parent, to_kind, to_executable = \
 
1037
                self._to_file_data(to_trans_id, from_trans_id, from_executable)
 
1038
 
 
1039
            to_path = final_paths.get_path(to_trans_id)
 
1040
            if from_kind != to_kind:
 
1041
                modified = True
 
1042
            elif to_kind in ('file' or 'symlink') and (
 
1043
                to_trans_id != from_trans_id or
 
1044
                to_trans_id in self._new_contents):
 
1045
                modified = True
 
1046
            if (not modified and from_versioned == to_versioned and
 
1047
                from_parent==to_parent and from_name == to_name and
 
1048
                from_executable == to_executable):
 
1049
                continue
 
1050
            results.append((file_id, to_path, modified,
 
1051
                   (from_versioned, to_versioned),
 
1052
                   (from_parent, to_parent),
 
1053
                   (from_name, to_name),
 
1054
                   (from_kind, to_kind),
 
1055
                   (from_executable, to_executable)))
 
1056
        return iter(sorted(results, key=lambda x:x[1]))
 
1057
 
 
1058
 
922
1059
def joinpath(parent, child):
923
1060
    """Join tree-relative paths, handling the tree root specially"""
924
1061
    if parent is None or parent == "":
1229
1366
        child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1230
1367
        try:
1231
1368
            _alter_files(working_tree, target_tree, tt, child_pb, 
1232
 
                         interesting_ids, backups, change_reporter)
 
1369
                         interesting_ids, backups)
1233
1370
        finally:
1234
1371
            child_pb.finished()
1235
1372
        pp.next_phase()
1239
1376
        finally:
1240
1377
            child_pb.finished()
1241
1378
        conflicts = cook_conflicts(raw_conflicts, tt)
 
1379
        if change_reporter:
 
1380
            change_reporter = delta.ChangeReporter(working_tree.inventory)
 
1381
            delta.report_changes(tt._iter_changes(), change_reporter)
1242
1382
        for conflict in conflicts:
1243
1383
            warning(conflict)
1244
1384
        pp.next_phase()
1250
1390
    return conflicts
1251
1391
 
1252
1392
 
1253
 
def _alter_files(working_tree, target_tree, tt, pb, interesting_ids, backups,
1254
 
                 report_changes):
1255
 
    from bzrlib import delta
 
1393
def _alter_files(working_tree, target_tree, tt, pb, interesting_ids,
 
1394
                 backups):
1256
1395
    merge_modified = working_tree.merge_modified()
1257
 
    change_list = list(target_tree._iter_changes(working_tree,
1258
 
        specific_file_ids=interesting_ids, pb=pb))
 
1396
    change_list = target_tree._iter_changes(working_tree,
 
1397
        specific_file_ids=interesting_ids, pb=pb)
1259
1398
    if target_tree.inventory.root is None:
1260
1399
        skip_root = True
1261
1400
    else:
1262
1401
        skip_root = False
1263
1402
    basis_tree = None
1264
 
    if report_changes:
1265
 
        change_reporter = delta.ChangeReporter(working_tree.inventory)
1266
 
        delta.report_changes(change_list, change_reporter)
1267
 
    for id_num, (file_id, path, changed_content, versioned, parent, name, kind,
1268
 
                 executable) in enumerate(change_list):
 
1403
    for id_num, (file_id, path, changed_content, versioned, parent, name,
 
1404
        kind, executable) in enumerate(change_list):
1269
1405
        if skip_root and file_id[0] is not None and parent[0] is None:
1270
1406
            continue
1271
1407
        trans_id = tt.trans_id_file_id(file_id)