/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

NEWS section template into a separate file

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
21
20
 
22
21
from bzrlib.lazy_import import lazy_import
23
22
lazy_import(globals(), """
25
24
    annotate,
26
25
    bencode,
27
26
    bzrdir,
28
 
    commit,
29
27
    delta,
30
28
    errors,
31
29
    inventory,
32
30
    multiparent,
33
31
    osutils,
34
32
    revision as _mod_revision,
35
 
    ui,
36
33
    )
37
34
""")
38
35
from bzrlib.errors import (DuplicateKey, MalformedTransform, NoSuchFile,
39
 
                           ReusingTransform, CantMoveRoot,
 
36
                           ReusingTransform, NotVersionedError, CantMoveRoot,
40
37
                           ExistingLimbo, ImmortalLimbo, NoFinalPath,
41
38
                           UnableCreateSymlink)
42
39
from bzrlib.filters import filtered_output_bytes, ContentFilterContext
51
48
    splitpath,
52
49
    supports_executable,
53
50
)
54
 
from bzrlib.progress import ProgressPhase
 
51
from bzrlib.progress import DummyProgress, ProgressPhase
55
52
from bzrlib.symbol_versioning import (
56
53
        deprecated_function,
57
54
        deprecated_in,
81
78
class TreeTransformBase(object):
82
79
    """The base class for TreeTransform and its kin."""
83
80
 
84
 
    def __init__(self, tree, pb=None,
 
81
    def __init__(self, tree, pb=DummyProgress(),
85
82
                 case_sensitive=True):
86
83
        """Constructor.
87
84
 
88
85
        :param tree: The tree that will be transformed, but not necessarily
89
86
            the output tree.
90
 
        :param pb: ignored
 
87
        :param pb: A ProgressTask indicating how much progress is being made
91
88
        :param case_sensitive: If True, the target of the transform is
92
89
            case sensitive, not just case preserving.
93
90
        """
928
925
        """
929
926
        return _PreviewTree(self)
930
927
 
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):
 
928
    def commit(self, branch, message, merge_parents=None, strict=False):
934
929
        """Commit the result of this TreeTransform to a branch.
935
930
 
936
931
        :param branch: The branch to commit to.
937
932
        :param message: The message to attach to the commit.
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.)
 
933
        :param merge_parents: Additional parents specified by pending merges.
952
934
        :return: The revision_id of the revision committed.
953
935
        """
954
936
        self._check_malformed()
971
953
        if self._tree.get_revision_id() != last_rev_id:
972
954
            raise ValueError('TreeTransform not based on branch basis: %s' %
973
955
                             self._tree.get_revision_id())
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)
 
956
        builder = branch.get_commit_builder(parent_ids)
981
957
        preview = self.get_preview_tree()
982
958
        list(builder.record_iter_changes(preview, last_rev_id,
983
959
                                         self.iter_changes()))
1085
1061
class DiskTreeTransform(TreeTransformBase):
1086
1062
    """Tree transform storing its contents on disk."""
1087
1063
 
1088
 
    def __init__(self, tree, limbodir, pb=None,
 
1064
    def __init__(self, tree, limbodir, pb=DummyProgress(),
1089
1065
                 case_sensitive=True):
1090
1066
        """Constructor.
1091
1067
        :param tree: The tree that will be transformed, but not necessarily
1092
1068
            the output tree.
1093
1069
        :param limbodir: A directory where new files can be stored until
1094
1070
            they are installed in their proper places
1095
 
        :param pb: ignored
 
1071
        :param pb: A ProgressBar indicating how much progress is being made
1096
1072
        :param case_sensitive: If True, the target of the transform is
1097
1073
            case sensitive, not just case preserving.
1098
1074
        """
1108
1084
        self._limbo_children_names = {}
1109
1085
        # List of transform ids that need to be renamed from limbo into place
1110
1086
        self._needs_rename = set()
1111
 
        self._creation_mtime = None
1112
1087
 
1113
1088
    def finalize(self):
1114
1089
        """Release the working tree lock, if held, clean up limbo dir.
1182
1157
            if trans_id not in self._new_contents:
1183
1158
                continue
1184
1159
            new_path = self._limbo_name(trans_id)
1185
 
            osutils.rename(old_path, new_path)
1186
 
            for descendant in self._limbo_descendants(trans_id):
1187
 
                desc_path = self._limbo_files[descendant]
1188
 
                desc_path = new_path + desc_path[len(old_path):]
1189
 
                self._limbo_files[descendant] = desc_path
1190
 
 
1191
 
    def _limbo_descendants(self, trans_id):
1192
 
        """Return the set of trans_ids whose limbo paths descend from this."""
1193
 
        descendants = set(self._limbo_children.get(trans_id, []))
1194
 
        for descendant in list(descendants):
1195
 
            descendants.update(self._limbo_descendants(descendant))
1196
 
        return descendants
 
1160
            os.rename(old_path, new_path)
1197
1161
 
1198
1162
    def create_file(self, contents, trans_id, mode_id=None):
1199
1163
        """Schedule creation of a new file.
1221
1185
            f.writelines(contents)
1222
1186
        finally:
1223
1187
            f.close()
1224
 
        self._set_mtime(name)
1225
1188
        self._set_mode(trans_id, mode_id, S_ISREG)
1226
1189
 
1227
1190
    def _read_file_chunks(self, trans_id):
1234
1197
    def _read_symlink_target(self, trans_id):
1235
1198
        return os.readlink(self._limbo_name(trans_id))
1236
1199
 
1237
 
    def _set_mtime(self, path):
1238
 
        """All files that are created get the same mtime.
1239
 
 
1240
 
        This time is set by the first object to be created.
1241
 
        """
1242
 
        if self._creation_mtime is None:
1243
 
            self._creation_mtime = time.time()
1244
 
        os.utime(path, (self._creation_mtime, self._creation_mtime))
1245
 
 
1246
1200
    def create_hardlink(self, path, trans_id):
1247
1201
        """Schedule creation of a hard link"""
1248
1202
        name = self._limbo_name(trans_id)
1362
1316
    FileMover does not delete files until it is sure that a rollback will not
1363
1317
    happen.
1364
1318
    """
1365
 
    def __init__(self, tree, pb=None):
 
1319
    def __init__(self, tree, pb=DummyProgress()):
1366
1320
        """Note: a tree_write lock is taken on the tree.
1367
1321
 
1368
1322
        Use TreeTransform.finalize() to release the lock (can be omitted if
1714
1668
    unversioned files in the input tree.
1715
1669
    """
1716
1670
 
1717
 
    def __init__(self, tree, pb=None, case_sensitive=True):
 
1671
    def __init__(self, tree, pb=DummyProgress(), case_sensitive=True):
1718
1672
        tree.lock_read()
1719
1673
        limbodir = osutils.mkdtemp(prefix='bzr-limbo-')
1720
1674
        DiskTreeTransform.__init__(self, tree, limbodir, pb, case_sensitive)
1820
1774
            executable = self.is_executable(file_id, path)
1821
1775
        return kind, executable, None
1822
1776
 
1823
 
    def is_locked(self):
1824
 
        return False
1825
 
 
1826
1777
    def lock_read(self):
1827
1778
        # Perhaps in theory, this should lock the TreeTransform?
1828
 
        return self
 
1779
        pass
1829
1780
 
1830
1781
    def unlock(self):
1831
1782
        pass
2014
1965
    def get_file_mtime(self, file_id, path=None):
2015
1966
        """See Tree.get_file_mtime"""
2016
1967
        if not self._content_change(file_id):
2017
 
            return self._transform._tree.get_file_mtime(file_id)
 
1968
            return self._transform._tree.get_file_mtime(file_id, path)
2018
1969
        return self._stat_limbo_file(file_id).st_mtime
2019
1970
 
2020
1971
    def _file_size(self, entry, stat_value):
2074
2025
                statval = os.lstat(limbo_name)
2075
2026
                size = statval.st_size
2076
2027
                if not supports_executable():
2077
 
                    executable = False
 
2028
                    executable = None
2078
2029
                else:
2079
2030
                    executable = statval.st_mode & S_IEXEC
2080
2031
            else:
2082
2033
                executable = None
2083
2034
            if kind == 'symlink':
2084
2035
                link_or_sha1 = os.readlink(limbo_name).decode(osutils._fs_enc)
2085
 
        executable = tt._new_executability.get(trans_id, executable)
 
2036
        if supports_executable():
 
2037
            executable = tt._new_executability.get(trans_id, executable)
2086
2038
        return kind, size, executable, link_or_sha1
2087
2039
 
2088
2040
    def iter_changes(self, from_tree, include_unchanged=False,
2401
2353
        new_desired_files = desired_files
2402
2354
    else:
2403
2355
        iter = accelerator_tree.iter_changes(tree, include_unchanged=True)
2404
 
        unchanged = [(f, p[1]) for (f, p, c, v, d, n, k, e)
2405
 
                     in iter if not (c or e[0] != e[1])]
2406
 
        if accelerator_tree.supports_content_filtering():
2407
 
            unchanged = [(f, p) for (f, p) in unchanged
2408
 
                         if not accelerator_tree.iter_search_rules([p]).next()]
2409
 
        unchanged = dict(unchanged)
 
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]))
2410
2358
        new_desired_files = []
2411
2359
        count = 0
2412
2360
        for file_id, (trans_id, tree_path) in desired_files:
2615
2563
 
2616
2564
 
2617
2565
def revert(working_tree, target_tree, filenames, backups=False,
2618
 
           pb=None, change_reporter=None):
 
2566
           pb=DummyProgress(), change_reporter=None):
2619
2567
    """Revert a working tree's contents to those of a target tree."""
2620
2568
    target_tree.lock_read()
2621
 
    pb = ui.ui_factory.nested_progress_bar()
2622
2569
    tt = TreeTransform(working_tree, pb)
2623
2570
    try:
2624
2571
        pp = ProgressPhase("Revert phase", 3, pb)
2643
2590
def _prepare_revert_transform(working_tree, target_tree, tt, filenames,
2644
2591
                              backups, pp, basis_tree=None,
2645
2592
                              merge_modified=None):
 
2593
    pp.next_phase()
2646
2594
    child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
2647
2595
    try:
2648
2596
        if merge_modified is None:
2652
2600
                                      merge_modified, basis_tree)
2653
2601
    finally:
2654
2602
        child_pb.finished()
 
2603
    pp.next_phase()
2655
2604
    child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
2656
2605
    try:
2657
2606
        raw_conflicts = resolve_conflicts(tt, child_pb,
2779
2728
    return merge_modified
2780
2729
 
2781
2730
 
2782
 
def resolve_conflicts(tt, pb=None, pass_func=None):
 
2731
def resolve_conflicts(tt, pb=DummyProgress(), pass_func=None):
2783
2732
    """Make many conflict-resolution attempts, but die if they fail"""
2784
2733
    if pass_func is None:
2785
2734
        pass_func = conflict_pass
2786
2735
    new_conflicts = set()
2787
 
    pb = ui.ui_factory.nested_progress_bar()
2788
2736
    try:
2789
2737
        for n in range(10):
2790
2738
            pb.update('Resolution pass', n+1, 10)
2794
2742
            new_conflicts.update(pass_func(tt, conflicts))
2795
2743
        raise MalformedTransform(conflicts=conflicts)
2796
2744
    finally:
2797
 
        pb.finished()
 
2745
        pb.clear()
2798
2746
 
2799
2747
 
2800
2748
def conflict_pass(tt, conflicts, path_tree=None):
2849
2797
                        # special-case the other tree root (move its
2850
2798
                        # children to current root)
2851
2799
                        if entry.parent_id is None:
2852
 
                            create = False
 
2800
                            create=False
2853
2801
                            moved = _reparent_transform_children(
2854
2802
                                tt, trans_id, tt.root)
2855
2803
                            for child in moved:
2923
2871
        self.pending_deletions = []
2924
2872
 
2925
2873
    def rename(self, from_, to):
2926
 
        """Rename a file from one path to another."""
 
2874
        """Rename a file from one path to another.  Functions like os.rename"""
2927
2875
        try:
2928
 
            osutils.rename(from_, to)
 
2876
            os.rename(from_, to)
2929
2877
        except OSError, e:
2930
2878
            if e.errno in (errno.EEXIST, errno.ENOTEMPTY):
2931
2879
                raise errors.FileExists(to, str(e))
2945
2893
    def rollback(self):
2946
2894
        """Reverse all renames that have been performed"""
2947
2895
        for from_, to in reversed(self.past_renames):
2948
 
            osutils.rename(to, from_)
 
2896
            os.rename(to, from_)
2949
2897
        # after rollback, don't reuse _FileMover
2950
2898
        past_renames = None
2951
2899
        pending_deletions = None