/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: Martin Pool
  • Date: 2010-06-24 06:53:06 UTC
  • mfrom: (5317 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5343.
  • Revision ID: mbp@sourcefrog.net-20100624065306-qcx1wg84ufuckime
merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
    annotate,
26
26
    bencode,
27
27
    bzrdir,
 
28
    commit,
28
29
    delta,
29
30
    errors,
30
31
    inventory,
31
32
    multiparent,
32
33
    osutils,
33
34
    revision as _mod_revision,
 
35
    ui,
34
36
    )
35
37
""")
36
38
from bzrlib.errors import (DuplicateKey, MalformedTransform, NoSuchFile,
37
 
                           ReusingTransform, NotVersionedError, CantMoveRoot,
 
39
                           ReusingTransform, CantMoveRoot,
38
40
                           ExistingLimbo, ImmortalLimbo, NoFinalPath,
39
41
                           UnableCreateSymlink)
40
42
from bzrlib.filters import filtered_output_bytes, ContentFilterContext
49
51
    splitpath,
50
52
    supports_executable,
51
53
)
52
 
from bzrlib.progress import DummyProgress, ProgressPhase
 
54
from bzrlib.progress import ProgressPhase
53
55
from bzrlib.symbol_versioning import (
54
56
        deprecated_function,
55
57
        deprecated_in,
79
81
class TreeTransformBase(object):
80
82
    """The base class for TreeTransform and its kin."""
81
83
 
82
 
    def __init__(self, tree, pb=DummyProgress(),
 
84
    def __init__(self, tree, pb=None,
83
85
                 case_sensitive=True):
84
86
        """Constructor.
85
87
 
86
88
        :param tree: The tree that will be transformed, but not necessarily
87
89
            the output tree.
88
 
        :param pb: A ProgressTask indicating how much progress is being made
 
90
        :param pb: ignored
89
91
        :param case_sensitive: If True, the target of the transform is
90
92
            case sensitive, not just case preserving.
91
93
        """
926
928
        """
927
929
        return _PreviewTree(self)
928
930
 
929
 
    def commit(self, branch, message, merge_parents=None, strict=False):
 
931
    def commit(self, branch, message, merge_parents=None, strict=False,
 
932
               timestamp=None, timezone=None, committer=None, authors=None,
 
933
               revprops=None, revision_id=None):
930
934
        """Commit the result of this TreeTransform to a branch.
931
935
 
932
936
        :param branch: The branch to commit to.
933
937
        :param message: The message to attach to the commit.
934
 
        :param merge_parents: Additional parents specified by pending merges.
 
938
        :param merge_parents: Additional parent revision-ids specified by
 
939
            pending merges.
 
940
        :param strict: If True, abort the commit if there are unversioned
 
941
            files.
 
942
        :param timestamp: if not None, seconds-since-epoch for the time and
 
943
            date.  (May be a float.)
 
944
        :param timezone: Optional timezone for timestamp, as an offset in
 
945
            seconds.
 
946
        :param committer: Optional committer in email-id format.
 
947
            (e.g. "J Random Hacker <jrandom@example.com>")
 
948
        :param authors: Optional list of authors in email-id format.
 
949
        :param revprops: Optional dictionary of revision properties.
 
950
        :param revision_id: Optional revision id.  (Specifying a revision-id
 
951
            may reduce performance for some non-native formats.)
935
952
        :return: The revision_id of the revision committed.
936
953
        """
937
954
        self._check_malformed()
954
971
        if self._tree.get_revision_id() != last_rev_id:
955
972
            raise ValueError('TreeTransform not based on branch basis: %s' %
956
973
                             self._tree.get_revision_id())
957
 
        builder = branch.get_commit_builder(parent_ids)
 
974
        revprops = commit.Commit.update_revprops(revprops, branch, authors)
 
975
        builder = branch.get_commit_builder(parent_ids,
 
976
                                            timestamp=timestamp,
 
977
                                            timezone=timezone,
 
978
                                            committer=committer,
 
979
                                            revprops=revprops,
 
980
                                            revision_id=revision_id)
958
981
        preview = self.get_preview_tree()
959
982
        list(builder.record_iter_changes(preview, last_rev_id,
960
983
                                         self.iter_changes()))
1062
1085
class DiskTreeTransform(TreeTransformBase):
1063
1086
    """Tree transform storing its contents on disk."""
1064
1087
 
1065
 
    def __init__(self, tree, limbodir, pb=DummyProgress(),
 
1088
    def __init__(self, tree, limbodir, pb=None,
1066
1089
                 case_sensitive=True):
1067
1090
        """Constructor.
1068
1091
        :param tree: The tree that will be transformed, but not necessarily
1069
1092
            the output tree.
1070
1093
        :param limbodir: A directory where new files can be stored until
1071
1094
            they are installed in their proper places
1072
 
        :param pb: A ProgressBar indicating how much progress is being made
 
1095
        :param pb: ignored
1073
1096
        :param case_sensitive: If True, the target of the transform is
1074
1097
            case sensitive, not just case preserving.
1075
1098
        """
1159
1182
            if trans_id not in self._new_contents:
1160
1183
                continue
1161
1184
            new_path = self._limbo_name(trans_id)
1162
 
            os.rename(old_path, new_path)
 
1185
            osutils.rename(old_path, new_path)
1163
1186
            for descendant in self._limbo_descendants(trans_id):
1164
1187
                desc_path = self._limbo_files[descendant]
1165
1188
                desc_path = new_path + desc_path[len(old_path):]
1339
1362
    FileMover does not delete files until it is sure that a rollback will not
1340
1363
    happen.
1341
1364
    """
1342
 
    def __init__(self, tree, pb=DummyProgress()):
 
1365
    def __init__(self, tree, pb=None):
1343
1366
        """Note: a tree_write lock is taken on the tree.
1344
1367
 
1345
1368
        Use TreeTransform.finalize() to release the lock (can be omitted if
1634
1657
                      or trans_id in self._new_parent):
1635
1658
                    try:
1636
1659
                        mover.rename(full_path, self._limbo_name(trans_id))
1637
 
                    except OSError, e:
 
1660
                    except errors.TransformRenameFailed, e:
1638
1661
                        if e.errno != errno.ENOENT:
1639
1662
                            raise
1640
1663
                    else:
1665
1688
                if trans_id in self._needs_rename:
1666
1689
                    try:
1667
1690
                        mover.rename(self._limbo_name(trans_id), full_path)
1668
 
                    except OSError, e:
 
1691
                    except errors.TransformRenameFailed, e:
1669
1692
                        # We may be renaming a dangling inventory id
1670
1693
                        if e.errno != errno.ENOENT:
1671
1694
                            raise
1691
1714
    unversioned files in the input tree.
1692
1715
    """
1693
1716
 
1694
 
    def __init__(self, tree, pb=DummyProgress(), case_sensitive=True):
 
1717
    def __init__(self, tree, pb=None, case_sensitive=True):
1695
1718
        tree.lock_read()
1696
1719
        limbodir = osutils.mkdtemp(prefix='bzr-limbo-')
1697
1720
        DiskTreeTransform.__init__(self, tree, limbodir, pb, case_sensitive)
1769
1792
        parent_keys = [(file_id, self._file_revision(t, file_id)) for t in
1770
1793
                       self._iter_parent_trees()]
1771
1794
        vf.add_lines((file_id, tree_revision), parent_keys,
1772
 
                     self.get_file(file_id).readlines())
 
1795
                     self.get_file_lines(file_id))
1773
1796
        repo = self._get_repository()
1774
1797
        base_vf = repo.texts
1775
1798
        if base_vf not in vf.fallback_versionedfiles:
1797
1820
            executable = self.is_executable(file_id, path)
1798
1821
        return kind, executable, None
1799
1822
 
 
1823
    def is_locked(self):
 
1824
        return False
 
1825
 
1800
1826
    def lock_read(self):
1801
1827
        # Perhaps in theory, this should lock the TreeTransform?
1802
 
        pass
 
1828
        return self
1803
1829
 
1804
1830
    def unlock(self):
1805
1831
        pass
2265
2291
    for num, _unused in enumerate(wt.all_file_ids()):
2266
2292
        if num > 0:  # more than just a root
2267
2293
            raise errors.WorkingTreeAlreadyPopulated(base=wt.basedir)
2268
 
    existing_files = set()
2269
 
    for dir, files in wt.walkdirs():
2270
 
        existing_files.update(f[0] for f in files)
2271
2294
    file_trans_id = {}
2272
2295
    top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
2273
2296
    pp = ProgressPhase("Build phase", 2, top_pb)
2297
2320
                precomputed_delta = []
2298
2321
            else:
2299
2322
                precomputed_delta = None
 
2323
            # Check if tree inventory has content. If so, we populate
 
2324
            # existing_files with the directory content. If there are no
 
2325
            # entries we skip populating existing_files as its not used.
 
2326
            # This improves performance and unncessary work on large
 
2327
            # directory trees. (#501307)
 
2328
            if total > 0:
 
2329
                existing_files = set()
 
2330
                for dir, files in wt.walkdirs():
 
2331
                    existing_files.update(f[0] for f in files)
2300
2332
            for num, (tree_path, entry) in \
2301
2333
                enumerate(tree.inventory.iter_entries_by_dir()):
2302
2334
                pb.update("Building tree", num - len(deferred_contents), total)
2434
2466
    if entry.kind == "directory":
2435
2467
        return True
2436
2468
    if entry.kind == "file":
2437
 
        if tree.get_file(file_id).read() == file(target_path, 'rb').read():
2438
 
            return True
 
2469
        f = file(target_path, 'rb')
 
2470
        try:
 
2471
            if tree.get_file_text(file_id) == f.read():
 
2472
                return True
 
2473
        finally:
 
2474
            f.close()
2439
2475
    elif entry.kind == "symlink":
2440
2476
        if tree.get_symlink_target(file_id) == os.readlink(target_path):
2441
2477
            return True
2589
2625
 
2590
2626
 
2591
2627
def revert(working_tree, target_tree, filenames, backups=False,
2592
 
           pb=DummyProgress(), change_reporter=None):
 
2628
           pb=None, change_reporter=None):
2593
2629
    """Revert a working tree's contents to those of a target tree."""
2594
2630
    target_tree.lock_read()
 
2631
    pb = ui.ui_factory.nested_progress_bar()
2595
2632
    tt = TreeTransform(working_tree, pb)
2596
2633
    try:
2597
2634
        pp = ProgressPhase("Revert phase", 3, pb)
2616
2653
def _prepare_revert_transform(working_tree, target_tree, tt, filenames,
2617
2654
                              backups, pp, basis_tree=None,
2618
2655
                              merge_modified=None):
2619
 
    pp.next_phase()
2620
2656
    child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
2621
2657
    try:
2622
2658
        if merge_modified is None:
2626
2662
                                      merge_modified, basis_tree)
2627
2663
    finally:
2628
2664
        child_pb.finished()
2629
 
    pp.next_phase()
2630
2665
    child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
2631
2666
    try:
2632
2667
        raw_conflicts = resolve_conflicts(tt, child_pb,
2754
2789
    return merge_modified
2755
2790
 
2756
2791
 
2757
 
def resolve_conflicts(tt, pb=DummyProgress(), pass_func=None):
 
2792
def resolve_conflicts(tt, pb=None, pass_func=None):
2758
2793
    """Make many conflict-resolution attempts, but die if they fail"""
2759
2794
    if pass_func is None:
2760
2795
        pass_func = conflict_pass
2761
2796
    new_conflicts = set()
 
2797
    pb = ui.ui_factory.nested_progress_bar()
2762
2798
    try:
2763
2799
        for n in range(10):
2764
2800
            pb.update('Resolution pass', n+1, 10)
2768
2804
            new_conflicts.update(pass_func(tt, conflicts))
2769
2805
        raise MalformedTransform(conflicts=conflicts)
2770
2806
    finally:
2771
 
        pb.clear()
 
2807
        pb.finished()
2772
2808
 
2773
2809
 
2774
2810
def conflict_pass(tt, conflicts, path_tree=None):
2823
2859
                        # special-case the other tree root (move its
2824
2860
                        # children to current root)
2825
2861
                        if entry.parent_id is None:
2826
 
                            create=False
 
2862
                            create = False
2827
2863
                            moved = _reparent_transform_children(
2828
2864
                                tt, trans_id, tt.root)
2829
2865
                            for child in moved:
2897
2933
        self.pending_deletions = []
2898
2934
 
2899
2935
    def rename(self, from_, to):
2900
 
        """Rename a file from one path to another.  Functions like os.rename"""
 
2936
        """Rename a file from one path to another."""
2901
2937
        try:
2902
 
            os.rename(from_, to)
2903
 
        except OSError, e:
 
2938
            osutils.rename(from_, to)
 
2939
        except (IOError, OSError), e:
2904
2940
            if e.errno in (errno.EEXIST, errno.ENOTEMPTY):
2905
2941
                raise errors.FileExists(to, str(e))
2906
 
            raise
 
2942
            # normal OSError doesn't include filenames so it's hard to see where
 
2943
            # the problem is, see https://bugs.launchpad.net/bzr/+bug/491763
 
2944
            raise errors.TransformRenameFailed(from_, to, str(e), e.errno)
2907
2945
        self.past_renames.append((from_, to))
2908
2946
 
2909
2947
    def pre_delete(self, from_, to):
2919
2957
    def rollback(self):
2920
2958
        """Reverse all renames that have been performed"""
2921
2959
        for from_, to in reversed(self.past_renames):
2922
 
            os.rename(to, from_)
 
2960
            try:
 
2961
                osutils.rename(to, from_)
 
2962
            except (OSError, IOError), e:
 
2963
                raise errors.TransformRenameFailed(to, from_, str(e), e.errno)                
2923
2964
        # after rollback, don't reuse _FileMover
2924
2965
        past_renames = None
2925
2966
        pending_deletions = None