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

  • Committer: Robert Collins
  • Date: 2007-07-15 15:40:37 UTC
  • mto: (2592.3.33 repository)
  • mto: This revision was merged to the branch mainline in revision 2624.
  • Revision ID: robertc@robertcollins.net-20070715154037-3ar8g89decddc9su
Make GraphIndex accept nodes as key, value, references, so that the method
signature is closer to what a simple key->value index delivers. Also
change the behaviour when the reference list count is zero to accept
key, value as nodes, and emit key, value to make it identical in that case
to a simple key->value index. This may not be a good idea, but for now it
seems ok.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2009 Jelmer Vernooij <jelmer@samba.org>
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
 
 
18
 
"""Git inventory."""
19
 
 
20
 
 
21
 
import stat
22
 
 
23
 
 
24
 
from bzrlib import (
25
 
    errors,
26
 
    inventory,
27
 
    osutils,
28
 
    ui,
29
 
    urlutils,
30
 
    )
31
 
 
32
 
 
33
 
class GitInventoryEntry(inventory.InventoryEntry):
34
 
 
35
 
    def __init__(self, inv, parent_id, hexsha, path, name, executable):
36
 
        self.name = name
37
 
        self.parent_id = parent_id
38
 
        self._inventory = inv
39
 
        self._object = None
40
 
        self.hexsha = hexsha
41
 
        self.path = path
42
 
        self.revision = self._inventory.revision_id
43
 
        self.executable = executable
44
 
        self.file_id = self._inventory.mapping.generate_file_id(path.encode('utf-8'))
45
 
 
46
 
    @property
47
 
    def object(self):
48
 
        if self._object is None:
49
 
            self._object = self._inventory.store[self.hexsha]
50
 
        return self._object
51
 
 
52
 
 
53
 
class GitInventoryFile(GitInventoryEntry):
54
 
 
55
 
    def __init__(self, inv, parent_id, hexsha, path, basename, executable):
56
 
        super(GitInventoryFile, self).__init__(inv, parent_id, hexsha, path, basename, executable)
57
 
        self.kind = 'file'
58
 
        self.text_id = None
59
 
        self.symlink_target = None
60
 
 
61
 
    @property
62
 
    def text_sha1(self):
63
 
        return osutils.sha_string(self.object.data)
64
 
 
65
 
    @property
66
 
    def text_size(self):
67
 
        return len(self.object.data)
68
 
 
69
 
    def __repr__(self):
70
 
        return ("%s(%r, %r, parent_id=%r, sha1=%r, len=%s, revision=%s)"
71
 
                % (self.__class__.__name__,
72
 
                   self.file_id,
73
 
                   self.name,
74
 
                   self.parent_id,
75
 
                   self.text_sha1,
76
 
                   self.text_size,
77
 
                   self.revision))
78
 
 
79
 
    def kind_character(self):
80
 
        """See InventoryEntry.kind_character."""
81
 
        return ''
82
 
 
83
 
    def copy(self):
84
 
        other = inventory.InventoryFile(self.file_id, self.name, self.parent_id)
85
 
        other.executable = self.executable
86
 
        other.text_id = self.text_id
87
 
        other.text_sha1 = self.text_sha1
88
 
        other.text_size = self.text_size
89
 
        other.revision = self.revision
90
 
        return other
91
 
 
92
 
 
93
 
class GitInventoryLink(GitInventoryEntry):
94
 
 
95
 
    def __init__(self, inv, parent_id, hexsha, path, basename, executable):
96
 
        super(GitInventoryLink, self).__init__(inv, parent_id, hexsha, path, basename, executable)
97
 
        self.text_sha1 = None
98
 
        self.text_size = None
99
 
        self.kind = 'symlink'
100
 
 
101
 
    @property
102
 
    def symlink_target(self):
103
 
        return self.object.data
104
 
 
105
 
    def kind_character(self):
106
 
        """See InventoryEntry.kind_character."""
107
 
        return ''
108
 
 
109
 
    def copy(self):
110
 
        other = inventory.InventoryLink(self.file_id, self.name, self.parent_id)
111
 
        other.symlink_target = self.symlink_target
112
 
        other.revision = self.revision
113
 
        return other
114
 
 
115
 
 
116
 
class GitInventoryDirectory(GitInventoryEntry):
117
 
 
118
 
    def __init__(self, inv, parent_id, hexsha, path, basename, executable):
119
 
        super(GitInventoryDirectory, self).__init__(inv, parent_id, hexsha, path, basename, executable)
120
 
        self.text_sha1 = None
121
 
        self.text_size = None
122
 
        self.symlink_target = None
123
 
        self.kind = 'directory'
124
 
        self._children = None
125
 
 
126
 
    def kind_character(self):
127
 
        """See InventoryEntry.kind_character."""
128
 
        return '/'
129
 
 
130
 
    @property
131
 
    def children(self):
132
 
        if self._children is None:
133
 
            self._retrieve_children()
134
 
        return self._children
135
 
 
136
 
    def _retrieve_children(self):
137
 
        self._children = {}
138
 
        for mode, name, hexsha in self.object.entries():
139
 
            basename = name.decode("utf-8")
140
 
            child_path = osutils.pathjoin(self.path, basename)
141
 
            entry_kind = (mode & 0700000) / 0100000
142
 
            fs_mode = mode & 0777
143
 
            executable = bool(fs_mode & 0111)
144
 
            if entry_kind == 0:
145
 
                kind_class = GitInventoryDirectory
146
 
            elif entry_kind == 1:
147
 
                file_kind = (mode & 070000) / 010000
148
 
                if file_kind == 0:
149
 
                    kind_class = GitInventoryFile
150
 
                elif file_kind == 2:
151
 
                    kind_class = GitInventoryLink
152
 
                else:
153
 
                    raise AssertionError(
154
 
                        "Unknown file kind, perms=%o." % (mode,))
155
 
            else:
156
 
                raise AssertionError(
157
 
                    "Unknown blob kind, perms=%r." % (mode,))
158
 
            self._children[basename] = kind_class(self._inventory, self.file_id, hexsha, child_path, basename, executable)
159
 
 
160
 
    def copy(self):
161
 
        other = inventory.InventoryDirectory(self.file_id, self.name, 
162
 
                                             self.parent_id)
163
 
        other.revision = self.revision
164
 
        # note that children are *not* copied; they're pulled across when
165
 
        # others are added
166
 
        return other
167
 
 
168
 
 
169
 
class GitInventory(inventory.Inventory):
170
 
 
171
 
    def __init__(self, tree_id, mapping, store, revision_id):
172
 
        super(GitInventory, self).__init__(revision_id=revision_id)
173
 
        self.store = store
174
 
        self.mapping = mapping
175
 
        self.root = GitInventoryDirectory(self, None, tree_id, u"", u"", False)
176
 
 
177
 
    def _get_ie(self, path):
178
 
        parts = path.split("/")
179
 
        ie = self.root
180
 
        for name in parts:
181
 
            ie = ie.children[name] 
182
 
        return ie
183
 
 
184
 
    def has_filename(self, path):
185
 
        try:
186
 
            self._get_ie(path)
187
 
            return True
188
 
        except KeyError:
189
 
            return False
190
 
 
191
 
    def has_id(self, file_id):
192
 
        try:
193
 
            self.id2path(file_id)
194
 
            return True
195
 
        except errors.NoSuchId:
196
 
            return False
197
 
 
198
 
    def id2path(self, file_id):
199
 
        path = self.mapping.parse_file_id(file_id)
200
 
        try:
201
 
            ie = self._get_ie(path)
202
 
            assert ie.path == path
203
 
        except KeyError:
204
 
            raise errors.NoSuchId(None, file_id)
205
 
 
206
 
    def path2id(self, path):
207
 
        try:
208
 
            return self._get_ie(path).file_id
209
 
        except KeyError:
210
 
            return None
211
 
 
212
 
    def __getitem__(self, file_id):
213
 
        if file_id == inventory.ROOT_ID:
214
 
            return self.root
215
 
        path = self.mapping.parse_file_id(file_id)
216
 
        try:
217
 
            return self._get_ie(path)
218
 
        except KeyError:
219
 
            raise errors.NoSuchId(None, file_id)
220
 
 
221
 
 
222
 
class GitIndexInventory(inventory.Inventory):
223
 
    """Inventory that retrieves its contents from an index file."""
224
 
 
225
 
    def __init__(self, basis_inventory, mapping, index):
226
 
        super(GitIndexInventory, self).__init__(revision_id=None, root_id=basis_inventory.root.file_id)
227
 
        self.basis_inv = basis_inventory
228
 
        self.mapping = mapping
229
 
        self.index = index
230
 
 
231
 
        pb = ui.ui_factory.nested_progress_bar()
232
 
        try:
233
 
            for i, (path, value) in enumerate(self.index.iteritems()):
234
 
                pb.update("creating working inventory from index", 
235
 
                        i, len(self.index))
236
 
                assert isinstance(path, str)
237
 
                assert isinstance(value, tuple) and len(value) == 10
238
 
                (ctime, mtime, ino, dev, mode, uid, gid, size, sha, flags) = value
239
 
                try:
240
 
                    old_ie = self.basis_inv._get_ie(path)
241
 
                except KeyError:
242
 
                    old_ie = None
243
 
                if old_ie is None:
244
 
                    file_id = self.mapping.generate_file_id(path)
245
 
                else:
246
 
                    file_id = old_ie.file_id
247
 
                if stat.S_ISLNK(mode):
248
 
                    kind = 'symlink'
249
 
                else:
250
 
                    assert stat.S_ISREG(mode)
251
 
                    kind = 'file'
252
 
                if old_ie is not None and old_ie.hexsha == sha:
253
 
                    # Hasn't changed since basis inv
254
 
                    self.add_parents(path)
255
 
                    self.add(old_ie)
256
 
                else:
257
 
                    ie = self.add_path(path, kind, file_id, self.add_parents(path))
258
 
                    ie.revision = None
259
 
        finally:
260
 
            pb.finished()
261
 
 
262
 
    def add_parents(self, path):
263
 
        dirname, _ = osutils.split(path)
264
 
        file_id = self.path2id(dirname)
265
 
        if file_id is None:
266
 
            if dirname == "":
267
 
                parent_fid = None
268
 
            else:
269
 
                parent_fid = self.add_parents(dirname)
270
 
            ie = self.add_path(dirname, 'directory', 
271
 
                    self.mapping.generate_file_id(dirname), parent_fid)
272
 
            if ie.file_id in self.basis_inv:
273
 
                ie.revision = self.basis_inv[ie.file_id].revision
274
 
            file_id = ie.file_id
275
 
        return file_id
276