/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/revisiontree.py

  • Committer: John Arbash Meinel
  • Date: 2008-07-09 21:42:24 UTC
  • mto: This revision was merged to the branch mainline in revision 3543.
  • Revision ID: john@arbash-meinel.com-20080709214224-r75k87r6a01pfc3h
Restore a real weave merge to 'bzr merge --weave'.

To do so efficiently, we only add the simple LCAs to the final weave
object, unless we run into complexities with the merge graph.
This gives the same effective result as adding all the texts,
with the advantage of not having to extract all of them.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005, 2007 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
 
17
"""RevisionTree - a Tree implementation backed by repository data for a revision."""
 
18
 
 
19
from cStringIO import StringIO
 
20
 
 
21
from bzrlib import (
 
22
    errors,
 
23
    osutils,
 
24
    revision,
 
25
    symbol_versioning,
 
26
    )
 
27
from bzrlib.tree import Tree
 
28
 
 
29
 
 
30
class RevisionTree(Tree):
 
31
    """Tree viewing a previous revision.
 
32
 
 
33
    File text can be retrieved from the text store.
 
34
    """
 
35
 
 
36
    def __init__(self, branch, inv, revision_id):
 
37
        # for compatability the 'branch' parameter has not been renamed to 
 
38
        # repository at this point. However, we should change RevisionTree's
 
39
        # construction to always be via Repository and not via direct 
 
40
        # construction - this will mean that we can change the constructor
 
41
        # with much less chance of breaking client code.
 
42
        self._repository = branch
 
43
        self._inventory = inv
 
44
        self._revision_id = revision_id
 
45
 
 
46
    def supports_tree_reference(self):
 
47
        return True
 
48
 
 
49
    def get_parent_ids(self):
 
50
        """See Tree.get_parent_ids.
 
51
 
 
52
        A RevisionTree's parents match the revision graph.
 
53
        """
 
54
        if self._revision_id in (None, revision.NULL_REVISION):
 
55
            parent_ids = []
 
56
        else:
 
57
            parent_ids = self._repository.get_revision(
 
58
                self._revision_id).parent_ids
 
59
        return parent_ids
 
60
        
 
61
    def get_revision_id(self):
 
62
        """Return the revision id associated with this tree."""
 
63
        return self._revision_id
 
64
 
 
65
    def get_file_lines(self, file_id):
 
66
        return osutils.split_lines(self.get_file_text(file_id))
 
67
 
 
68
    def get_file_text(self, file_id):
 
69
        return list(self.iter_files_bytes([(file_id, None)]))[0][1]
 
70
 
 
71
    def get_file(self, file_id, path=None):
 
72
        return StringIO(self.get_file_text(file_id))
 
73
 
 
74
    def iter_files_bytes(self, desired_files):
 
75
        """See Tree.iter_files_bytes.
 
76
 
 
77
        This version is implemented on top of Repository.extract_files_bytes"""
 
78
        repo_desired_files = [(f, self.inventory[f].revision, i)
 
79
                              for f, i in desired_files]
 
80
        try:
 
81
            for result in self._repository.iter_files_bytes(repo_desired_files):
 
82
                yield result
 
83
        except errors.RevisionNotPresent, e:
 
84
            raise errors.NoSuchFile(e.revision_id)
 
85
 
 
86
    def annotate_iter(self, file_id,
 
87
                      default_revision=revision.CURRENT_REVISION):
 
88
        """See Tree.annotate_iter"""
 
89
        text_key = (file_id, self.inventory[file_id].revision)
 
90
        annotations = self._repository.texts.annotate(text_key)
 
91
        return [(key[-1], line) for key, line in annotations]
 
92
 
 
93
    def get_file_size(self, file_id):
 
94
        """See Tree.get_file_size"""
 
95
        return self._inventory[file_id].text_size
 
96
 
 
97
    def get_file_sha1(self, file_id, path=None, stat_value=None):
 
98
        ie = self._inventory[file_id]
 
99
        if ie.kind == "file":
 
100
            return ie.text_sha1
 
101
        return None
 
102
 
 
103
    def get_file_mtime(self, file_id, path=None):
 
104
        ie = self._inventory[file_id]
 
105
        revision = self._repository.get_revision(ie.revision)
 
106
        return revision.timestamp
 
107
 
 
108
    def is_executable(self, file_id, path=None):
 
109
        ie = self._inventory[file_id]
 
110
        if ie.kind != "file":
 
111
            return None
 
112
        return ie.executable
 
113
 
 
114
    def has_filename(self, filename):
 
115
        return bool(self.inventory.path2id(filename))
 
116
 
 
117
    def list_files(self, include_root=False):
 
118
        # The only files returned by this are those from the version
 
119
        entries = self.inventory.iter_entries()
 
120
        # skip the root for compatability with the current apis.
 
121
        if self.inventory.root is not None and not include_root:
 
122
            # skip the root for compatability with the current apis.
 
123
            entries.next()
 
124
        for path, entry in entries:
 
125
            yield path, 'V', entry.kind, entry.file_id, entry
 
126
 
 
127
    def get_symlink_target(self, file_id):
 
128
        ie = self._inventory[file_id]
 
129
        return ie.symlink_target;
 
130
 
 
131
    def get_reference_revision(self, file_id, path=None):
 
132
        return self.inventory[file_id].reference_revision
 
133
 
 
134
    def get_root_id(self):
 
135
        if self.inventory.root:
 
136
            return self.inventory.root.file_id
 
137
 
 
138
    def kind(self, file_id):
 
139
        return self._inventory[file_id].kind
 
140
 
 
141
    def path_content_summary(self, path):
 
142
        """See Tree.path_content_summary."""
 
143
        id = self.inventory.path2id(path)
 
144
        if id is None:
 
145
            return ('missing', None, None, None)
 
146
        entry = self._inventory[id]
 
147
        kind = entry.kind
 
148
        if kind == 'file':
 
149
            return (kind, entry.text_size, entry.executable, entry.text_sha1)
 
150
        elif kind == 'symlink':
 
151
            return (kind, None, None, entry.symlink_target)
 
152
        else:
 
153
            return (kind, None, None, None)
 
154
 
 
155
    def _comparison_data(self, entry, path):
 
156
        if entry is None:
 
157
            return None, False, None
 
158
        return entry.kind, entry.executable, None
 
159
 
 
160
    def _file_size(self, entry, stat_value):
 
161
        return entry.text_size
 
162
 
 
163
    def _get_ancestors(self, default_revision):
 
164
        return set(self._repository.get_ancestry(self._revision_id,
 
165
                                                 topo_sorted=False))
 
166
 
 
167
    def lock_read(self):
 
168
        self._repository.lock_read()
 
169
 
 
170
    def __repr__(self):
 
171
        return '<%s instance at %x, rev_id=%r>' % (
 
172
            self.__class__.__name__, id(self), self._revision_id)
 
173
 
 
174
    def unlock(self):
 
175
        self._repository.unlock()
 
176
 
 
177
    def walkdirs(self, prefix=""):
 
178
        _directory = 'directory'
 
179
        inv = self.inventory
 
180
        top_id = inv.path2id(prefix)
 
181
        if top_id is None:
 
182
            pending = []
 
183
        else:
 
184
            pending = [(prefix, '', _directory, None, top_id, None)]
 
185
        while pending:
 
186
            dirblock = []
 
187
            currentdir = pending.pop()
 
188
            # 0 - relpath, 1- basename, 2- kind, 3- stat, id, v-kind
 
189
            if currentdir[0]:
 
190
                relroot = currentdir[0] + '/'
 
191
            else:
 
192
                relroot = ""
 
193
            # FIXME: stash the node in pending
 
194
            entry = inv[currentdir[4]]
 
195
            for name, child in entry.sorted_children():
 
196
                toppath = relroot + name
 
197
                dirblock.append((toppath, name, child.kind, None,
 
198
                    child.file_id, child.kind
 
199
                    ))
 
200
            yield (currentdir[0], entry.file_id), dirblock
 
201
            # push the user specified dirs from dirblock
 
202
            for dir in reversed(dirblock):
 
203
                if dir[2] == _directory:
 
204
                    pending.append(dir)