/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: 2010-05-06 11:08:10 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506110810-h3j07fh5gmw54s25
Cleaner matcher matching revised unlocking protocol.

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
import os
18
18
import errno
19
19
from stat import S_ISREG, S_IEXEC
 
20
import time
20
21
 
21
22
from bzrlib.lazy_import import lazy_import
22
23
lazy_import(globals(), """
30
31
    multiparent,
31
32
    osutils,
32
33
    revision as _mod_revision,
 
34
    ui,
33
35
    )
34
36
""")
35
37
from bzrlib.errors import (DuplicateKey, MalformedTransform, NoSuchFile,
36
 
                           ReusingTransform, NotVersionedError, CantMoveRoot,
 
38
                           ReusingTransform, CantMoveRoot,
37
39
                           ExistingLimbo, ImmortalLimbo, NoFinalPath,
38
40
                           UnableCreateSymlink)
39
41
from bzrlib.filters import filtered_output_bytes, ContentFilterContext
48
50
    splitpath,
49
51
    supports_executable,
50
52
)
51
 
from bzrlib.progress import DummyProgress, ProgressPhase
 
53
from bzrlib.progress import ProgressPhase
52
54
from bzrlib.symbol_versioning import (
53
55
        deprecated_function,
54
56
        deprecated_in,
78
80
class TreeTransformBase(object):
79
81
    """The base class for TreeTransform and its kin."""
80
82
 
81
 
    def __init__(self, tree, pb=DummyProgress(),
 
83
    def __init__(self, tree, pb=None,
82
84
                 case_sensitive=True):
83
85
        """Constructor.
84
86
 
85
87
        :param tree: The tree that will be transformed, but not necessarily
86
88
            the output tree.
87
 
        :param pb: A ProgressTask indicating how much progress is being made
 
89
        :param pb: ignored
88
90
        :param case_sensitive: If True, the target of the transform is
89
91
            case sensitive, not just case preserving.
90
92
        """
1061
1063
class DiskTreeTransform(TreeTransformBase):
1062
1064
    """Tree transform storing its contents on disk."""
1063
1065
 
1064
 
    def __init__(self, tree, limbodir, pb=DummyProgress(),
 
1066
    def __init__(self, tree, limbodir, pb=None,
1065
1067
                 case_sensitive=True):
1066
1068
        """Constructor.
1067
1069
        :param tree: The tree that will be transformed, but not necessarily
1068
1070
            the output tree.
1069
1071
        :param limbodir: A directory where new files can be stored until
1070
1072
            they are installed in their proper places
1071
 
        :param pb: A ProgressBar indicating how much progress is being made
 
1073
        :param pb: ignored
1072
1074
        :param case_sensitive: If True, the target of the transform is
1073
1075
            case sensitive, not just case preserving.
1074
1076
        """
1084
1086
        self._limbo_children_names = {}
1085
1087
        # List of transform ids that need to be renamed from limbo into place
1086
1088
        self._needs_rename = set()
 
1089
        self._creation_mtime = None
1087
1090
 
1088
1091
    def finalize(self):
1089
1092
        """Release the working tree lock, if held, clean up limbo dir.
1157
1160
            if trans_id not in self._new_contents:
1158
1161
                continue
1159
1162
            new_path = self._limbo_name(trans_id)
1160
 
            os.rename(old_path, new_path)
 
1163
            osutils.rename(old_path, new_path)
 
1164
            for descendant in self._limbo_descendants(trans_id):
 
1165
                desc_path = self._limbo_files[descendant]
 
1166
                desc_path = new_path + desc_path[len(old_path):]
 
1167
                self._limbo_files[descendant] = desc_path
 
1168
 
 
1169
    def _limbo_descendants(self, trans_id):
 
1170
        """Return the set of trans_ids whose limbo paths descend from this."""
 
1171
        descendants = set(self._limbo_children.get(trans_id, []))
 
1172
        for descendant in list(descendants):
 
1173
            descendants.update(self._limbo_descendants(descendant))
 
1174
        return descendants
1161
1175
 
1162
1176
    def create_file(self, contents, trans_id, mode_id=None):
1163
1177
        """Schedule creation of a new file.
1185
1199
            f.writelines(contents)
1186
1200
        finally:
1187
1201
            f.close()
 
1202
        self._set_mtime(name)
1188
1203
        self._set_mode(trans_id, mode_id, S_ISREG)
1189
1204
 
1190
1205
    def _read_file_chunks(self, trans_id):
1197
1212
    def _read_symlink_target(self, trans_id):
1198
1213
        return os.readlink(self._limbo_name(trans_id))
1199
1214
 
 
1215
    def _set_mtime(self, path):
 
1216
        """All files that are created get the same mtime.
 
1217
 
 
1218
        This time is set by the first object to be created.
 
1219
        """
 
1220
        if self._creation_mtime is None:
 
1221
            self._creation_mtime = time.time()
 
1222
        os.utime(path, (self._creation_mtime, self._creation_mtime))
 
1223
 
1200
1224
    def create_hardlink(self, path, trans_id):
1201
1225
        """Schedule creation of a hard link"""
1202
1226
        name = self._limbo_name(trans_id)
1316
1340
    FileMover does not delete files until it is sure that a rollback will not
1317
1341
    happen.
1318
1342
    """
1319
 
    def __init__(self, tree, pb=DummyProgress()):
 
1343
    def __init__(self, tree, pb=None):
1320
1344
        """Note: a tree_write lock is taken on the tree.
1321
1345
 
1322
1346
        Use TreeTransform.finalize() to release the lock (can be omitted if
1668
1692
    unversioned files in the input tree.
1669
1693
    """
1670
1694
 
1671
 
    def __init__(self, tree, pb=DummyProgress(), case_sensitive=True):
 
1695
    def __init__(self, tree, pb=None, case_sensitive=True):
1672
1696
        tree.lock_read()
1673
1697
        limbodir = osutils.mkdtemp(prefix='bzr-limbo-')
1674
1698
        DiskTreeTransform.__init__(self, tree, limbodir, pb, case_sensitive)
1965
1989
    def get_file_mtime(self, file_id, path=None):
1966
1990
        """See Tree.get_file_mtime"""
1967
1991
        if not self._content_change(file_id):
1968
 
            return self._transform._tree.get_file_mtime(file_id, path)
 
1992
            return self._transform._tree.get_file_mtime(file_id)
1969
1993
        return self._stat_limbo_file(file_id).st_mtime
1970
1994
 
1971
1995
    def _file_size(self, entry, stat_value):
2025
2049
                statval = os.lstat(limbo_name)
2026
2050
                size = statval.st_size
2027
2051
                if not supports_executable():
2028
 
                    executable = None
 
2052
                    executable = False
2029
2053
                else:
2030
2054
                    executable = statval.st_mode & S_IEXEC
2031
2055
            else:
2033
2057
                executable = None
2034
2058
            if kind == 'symlink':
2035
2059
                link_or_sha1 = os.readlink(limbo_name).decode(osutils._fs_enc)
2036
 
        if supports_executable():
2037
 
            executable = tt._new_executability.get(trans_id, executable)
 
2060
        executable = tt._new_executability.get(trans_id, executable)
2038
2061
        return kind, size, executable, link_or_sha1
2039
2062
 
2040
2063
    def iter_changes(self, from_tree, include_unchanged=False,
2353
2376
        new_desired_files = desired_files
2354
2377
    else:
2355
2378
        iter = accelerator_tree.iter_changes(tree, include_unchanged=True)
2356
 
        unchanged = dict((f, p[1]) for (f, p, c, v, d, n, k, e)
2357
 
                         in iter if not (c or e[0] != e[1]))
 
2379
        unchanged = [(f, p[1]) for (f, p, c, v, d, n, k, e)
 
2380
                     in iter if not (c or e[0] != e[1])]
 
2381
        if accelerator_tree.supports_content_filtering():
 
2382
            unchanged = [(f, p) for (f, p) in unchanged
 
2383
                         if not accelerator_tree.iter_search_rules([p]).next()]
 
2384
        unchanged = dict(unchanged)
2358
2385
        new_desired_files = []
2359
2386
        count = 0
2360
2387
        for file_id, (trans_id, tree_path) in desired_files:
2563
2590
 
2564
2591
 
2565
2592
def revert(working_tree, target_tree, filenames, backups=False,
2566
 
           pb=DummyProgress(), change_reporter=None):
 
2593
           pb=None, change_reporter=None):
2567
2594
    """Revert a working tree's contents to those of a target tree."""
2568
2595
    target_tree.lock_read()
 
2596
    pb = ui.ui_factory.nested_progress_bar()
2569
2597
    tt = TreeTransform(working_tree, pb)
2570
2598
    try:
2571
2599
        pp = ProgressPhase("Revert phase", 3, pb)
2590
2618
def _prepare_revert_transform(working_tree, target_tree, tt, filenames,
2591
2619
                              backups, pp, basis_tree=None,
2592
2620
                              merge_modified=None):
2593
 
    pp.next_phase()
2594
2621
    child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
2595
2622
    try:
2596
2623
        if merge_modified is None:
2600
2627
                                      merge_modified, basis_tree)
2601
2628
    finally:
2602
2629
        child_pb.finished()
2603
 
    pp.next_phase()
2604
2630
    child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
2605
2631
    try:
2606
2632
        raw_conflicts = resolve_conflicts(tt, child_pb,
2728
2754
    return merge_modified
2729
2755
 
2730
2756
 
2731
 
def resolve_conflicts(tt, pb=DummyProgress(), pass_func=None):
 
2757
def resolve_conflicts(tt, pb=None, pass_func=None):
2732
2758
    """Make many conflict-resolution attempts, but die if they fail"""
2733
2759
    if pass_func is None:
2734
2760
        pass_func = conflict_pass
2735
2761
    new_conflicts = set()
 
2762
    pb = ui.ui_factory.nested_progress_bar()
2736
2763
    try:
2737
2764
        for n in range(10):
2738
2765
            pb.update('Resolution pass', n+1, 10)
2742
2769
            new_conflicts.update(pass_func(tt, conflicts))
2743
2770
        raise MalformedTransform(conflicts=conflicts)
2744
2771
    finally:
2745
 
        pb.clear()
 
2772
        pb.finished()
2746
2773
 
2747
2774
 
2748
2775
def conflict_pass(tt, conflicts, path_tree=None):
2797
2824
                        # special-case the other tree root (move its
2798
2825
                        # children to current root)
2799
2826
                        if entry.parent_id is None:
2800
 
                            create=False
 
2827
                            create = False
2801
2828
                            moved = _reparent_transform_children(
2802
2829
                                tt, trans_id, tt.root)
2803
2830
                            for child in moved:
2871
2898
        self.pending_deletions = []
2872
2899
 
2873
2900
    def rename(self, from_, to):
2874
 
        """Rename a file from one path to another.  Functions like os.rename"""
 
2901
        """Rename a file from one path to another."""
2875
2902
        try:
2876
 
            os.rename(from_, to)
 
2903
            osutils.rename(from_, to)
2877
2904
        except OSError, e:
2878
2905
            if e.errno in (errno.EEXIST, errno.ENOTEMPTY):
2879
2906
                raise errors.FileExists(to, str(e))
2893
2920
    def rollback(self):
2894
2921
        """Reverse all renames that have been performed"""
2895
2922
        for from_, to in reversed(self.past_renames):
2896
 
            os.rename(to, from_)
 
2923
            osutils.rename(to, from_)
2897
2924
        # after rollback, don't reuse _FileMover
2898
2925
        past_renames = None
2899
2926
        pending_deletions = None