/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: Vincent Ladeuil
  • Date: 2010-01-25 15:55:48 UTC
  • mto: (4985.1.4 add-attr-cleanup)
  • mto: This revision was merged to the branch mainline in revision 4988.
  • Revision ID: v.ladeuil+lp@free.fr-20100125155548-0l352pujvt5bzl5e
Deploy addAttrCleanup on the whole test suite.

Several use case worth mentioning:

- setting a module or any other object attribute is the majority
by far. In some cases the setting itself is deferred but most of
the time we want to set at the same time we add the cleanup.

- there multiple occurrences of protecting hooks or ui factory
which are now useless (the test framework takes care of that now),

- there was some lambda uses that can now be avoided.

That first cleanup already simplifies things a lot.

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
 
from dulwich.objects import (
22
 
    Blob,
23
 
    Tree,
24
 
    )
25
 
 
26
 
 
27
 
from bzrlib import (
28
 
    errors,
29
 
    inventory,
30
 
    osutils,
31
 
    ui,
32
 
    )
33
 
 
34
 
from bzrlib.plugins.git.mapping import (
35
 
    mode_kind,
36
 
    mode_is_executable,
37
 
    )
38
 
 
39
 
 
40
 
class GitInventoryEntry(inventory.InventoryEntry):
41
 
 
42
 
    _git_class = None
43
 
 
44
 
    def __init__(self, inv, parent_id, hexsha, path, name, executable):
45
 
        self.name = name
46
 
        self.parent_id = parent_id
47
 
        self._inventory = inv
48
 
        self._object = None
49
 
        self.hexsha = hexsha
50
 
        self.path = path
51
 
        self.revision = self._inventory.revision_id
52
 
        self.executable = executable
53
 
        self.file_id = self._inventory.fileid_map.lookup_file_id(
54
 
            path.encode('utf-8'))
55
 
 
56
 
    @property
57
 
    def object(self):
58
 
        if self._object is None:
59
 
            self._object = self._inventory.store[self.hexsha]
60
 
            assert isinstance(self._object, self._git_class), \
61
 
                    "Expected instance of %r, got %r" % \
62
 
                    (self._git_class, self._object)
63
 
        return self._object
64
 
 
65
 
 
66
 
class GitInventoryFile(GitInventoryEntry):
67
 
 
68
 
    _git_class = Blob
69
 
 
70
 
    def __init__(self, inv, parent_id, hexsha, path, basename, executable):
71
 
        super(GitInventoryFile, self).__init__(inv, parent_id, hexsha, path,
72
 
            basename, executable)
73
 
        self.kind = 'file'
74
 
        self.text_id = None
75
 
        self.symlink_target = None
76
 
 
77
 
    @property
78
 
    def text_sha1(self):
79
 
        return osutils.sha_strings(self.object.chunked)
80
 
 
81
 
    @property
82
 
    def text_size(self):
83
 
        return len(self.object.data)
84
 
 
85
 
    def __repr__(self):
86
 
        return ("%s(%r, %r, parent_id=%r, sha1=%r, len=%s, revision=%s)"
87
 
                % (self.__class__.__name__,
88
 
                   self.file_id,
89
 
                   self.name,
90
 
                   self.parent_id,
91
 
                   self.text_sha1,
92
 
                   self.text_size,
93
 
                   self.revision))
94
 
 
95
 
    def kind_character(self):
96
 
        """See InventoryEntry.kind_character."""
97
 
        return ''
98
 
 
99
 
    def copy(self):
100
 
        other = inventory.InventoryFile(self.file_id, self.name,
101
 
            self.parent_id)
102
 
        other.executable = self.executable
103
 
        other.text_id = self.text_id
104
 
        other.text_sha1 = self.text_sha1
105
 
        other.text_size = self.text_size
106
 
        other.revision = self.revision
107
 
        return other
108
 
 
109
 
 
110
 
class GitInventoryLink(GitInventoryEntry):
111
 
 
112
 
    _git_class = Blob
113
 
 
114
 
    def __init__(self, inv, parent_id, hexsha, path, basename, executable):
115
 
        super(GitInventoryLink, self).__init__(inv, parent_id, hexsha, path, basename, executable)
116
 
        self.text_sha1 = None
117
 
        self.text_size = None
118
 
        self.kind = 'symlink'
119
 
 
120
 
    @property
121
 
    def symlink_target(self):
122
 
        return self.object.data
123
 
 
124
 
    def kind_character(self):
125
 
        """See InventoryEntry.kind_character."""
126
 
        return ''
127
 
 
128
 
    def copy(self):
129
 
        other = inventory.InventoryLink(self.file_id, self.name, self.parent_id)
130
 
        other.executable = self.executable
131
 
        other.symlink_target = self.symlink_target
132
 
        other.revision = self.revision
133
 
        return other
134
 
 
135
 
 
136
 
class GitInventoryTreeReference(GitInventoryEntry):
137
 
 
138
 
    _git_class = None
139
 
 
140
 
    def __init__(self, inv, parent_id, hexsha, path, basename, executable):
141
 
        super(GitInventoryTreeReference, self).__init__(inv, parent_id, hexsha, path, basename, executable)
142
 
        self.hexsha = hexsha
143
 
        self.reference_revision = inv.mapping.revision_id_foreign_to_bzr(hexsha)
144
 
        self.text_sha1 = None
145
 
        self.text_size = None
146
 
        self.symlink_target = None
147
 
        self.kind = 'tree-reference'
148
 
        self._children = None
149
 
 
150
 
    def kind_character(self):
151
 
        """See InventoryEntry.kind_character."""
152
 
        return '/'
153
 
 
154
 
 
155
 
class GitInventoryDirectory(GitInventoryEntry):
156
 
 
157
 
    _git_class = Tree
158
 
 
159
 
    def __init__(self, inv, parent_id, hexsha, path, basename, executable):
160
 
        super(GitInventoryDirectory, self).__init__(inv, parent_id, hexsha, path, basename, executable)
161
 
        self.text_sha1 = None
162
 
        self.text_size = None
163
 
        self.symlink_target = None
164
 
        self.kind = 'directory'
165
 
        self._children = None
166
 
 
167
 
    def kind_character(self):
168
 
        """See InventoryEntry.kind_character."""
169
 
        return '/'
170
 
 
171
 
    @property
172
 
    def children(self):
173
 
        if self._children is None:
174
 
            self._retrieve_children()
175
 
        return self._children
176
 
 
177
 
    def _retrieve_children(self):
178
 
        self._children = {}
179
 
        for mode, name, hexsha in self.object.entries():
180
 
            basename = name.decode("utf-8")
181
 
            child_path = osutils.pathjoin(self.path, basename)
182
 
            if self._inventory.mapping.is_control_file(child_path):
183
 
                continue
184
 
            executable = mode_is_executable(mode)
185
 
            kind_class = {'directory': GitInventoryDirectory,
186
 
                          'file': GitInventoryFile,
187
 
                          'symlink': GitInventoryLink,
188
 
                          'tree-reference': GitInventoryTreeReference}[mode_kind(mode)]
189
 
            self._children[basename] = kind_class(self._inventory,
190
 
                self.file_id, hexsha, child_path, basename, executable)
191
 
 
192
 
    def copy(self):
193
 
        other = inventory.InventoryDirectory(self.file_id, self.name,
194
 
                                             self.parent_id)
195
 
        other.revision = self.revision
196
 
        # note that children are *not* copied; they're pulled across when
197
 
        # others are added
198
 
        return other
199
 
 
200
 
 
201
 
class GitInventory(inventory.Inventory):
202
 
 
203
 
    def __repr__(self):
204
 
        return "<%s for %r in %r>" % (self.__class__.__name__,
205
 
                self.root.hexsha, self.store)
206
 
 
207
 
    def __init__(self, tree_id, mapping, fileid_map, store, revision_id):
208
 
        super(GitInventory, self).__init__(revision_id=revision_id)
209
 
        self.store = store
210
 
        self.fileid_map = fileid_map
211
 
        self.mapping = mapping
212
 
        self.root = GitInventoryDirectory(self, None, tree_id, u"", u"", False)
213
 
 
214
 
    def _get_ie(self, path):
215
 
        if path == "" or path == []:
216
 
            return self.root
217
 
        if isinstance(path, basestring):
218
 
            parts = path.split("/")
219
 
        else:
220
 
            parts = path
221
 
        ie = self.root
222
 
        for name in parts:
223
 
            ie = ie.children[name]
224
 
        return ie
225
 
 
226
 
    def has_filename(self, path):
227
 
        try:
228
 
            self._get_ie(path)
229
 
            return True
230
 
        except KeyError:
231
 
            return False
232
 
 
233
 
    def has_id(self, file_id):
234
 
        try:
235
 
            self.id2path(file_id)
236
 
            return True
237
 
        except errors.NoSuchId:
238
 
            return False
239
 
 
240
 
    def id2path(self, file_id):
241
 
        path = self.fileid_map.lookup_path(file_id)
242
 
        try:
243
 
            ie = self._get_ie(path)
244
 
            assert ie.path == path
245
 
        except KeyError:
246
 
            raise errors.NoSuchId(None, file_id)
247
 
 
248
 
    def path2id(self, path):
249
 
        try:
250
 
            return self._get_ie(path).file_id
251
 
        except KeyError:
252
 
            return None
253
 
 
254
 
    def __getitem__(self, file_id):
255
 
        if file_id == inventory.ROOT_ID:
256
 
            return self.root
257
 
        path = self.fileid_map.lookup_path(file_id)
258
 
        try:
259
 
            return self._get_ie(path)
260
 
        except KeyError:
261
 
            raise errors.NoSuchId(None, file_id)
262
 
 
263
 
 
264
 
class GitIndexInventory(inventory.Inventory):
265
 
    """Inventory that retrieves its contents from an index file."""
266
 
 
267
 
    def __repr__(self):
268
 
        return "<%s for %r>" % (self.__class__.__name__, self.index)
269
 
 
270
 
    def __init__(self, basis_inventory, fileid_map, index, store):
271
 
        if basis_inventory is None:
272
 
            root_id = None
273
 
        else:
274
 
            root_id = basis_inventory.root.file_id
275
 
        super(GitIndexInventory, self).__init__(revision_id=None, root_id=root_id)
276
 
        self.basis_inv = basis_inventory
277
 
        self.fileid_map = fileid_map
278
 
        self.index = index
279
 
        self._contents_read = False
280
 
        self.store = store
281
 
        self.root = self.add_path("", 'directory',
282
 
            self.fileid_map.lookup_file_id(""), None)
283
 
 
284
 
    def iter_entries_by_dir(self, specific_file_ids=None, yield_parents=False):
285
 
        self._read_contents()
286
 
        return super(GitIndexInventory, self).iter_entries_by_dir(
287
 
            specific_file_ids=specific_file_ids, yield_parents=yield_parents)
288
 
 
289
 
    def has_id(self, file_id):
290
 
        if type(file_id) != str:
291
 
            raise AssertionError
292
 
        try:
293
 
            self.id2path(file_id)
294
 
            return True
295
 
        except errors.NoSuchId:
296
 
            return False
297
 
 
298
 
    def has_filename(self, path):
299
 
        if path in self.index:
300
 
            return True
301
 
        self._read_contents()
302
 
        return super(GitIndexInventory, self).has_filename(path)
303
 
 
304
 
    def id2path(self, file_id):
305
 
        if type(file_id) != str:
306
 
            raise AssertionError
307
 
        path = self.fileid_map.lookup_path(file_id)
308
 
        if path in self.index:
309
 
            return path
310
 
        self._read_contents()
311
 
        return super(GitIndexInventory, self).id2path(file_id)
312
 
 
313
 
    def path2id(self, path):
314
 
        if type(path) in (list, tuple):
315
 
            path = "/".join(path)
316
 
        if path in self.index:
317
 
            file_id = self.fileid_map.lookup_file_id(path)
318
 
        else:
319
 
            self._read_contents()
320
 
            file_id = super(GitIndexInventory, self).path2id(path)
321
 
        if file_id is not None and type(file_id) is not str:
322
 
            raise AssertionError
323
 
        return file_id
324
 
 
325
 
    def __getitem__(self, file_id):
326
 
        self._read_contents()
327
 
        return super(GitIndexInventory, self).__getitem__(file_id)
328
 
 
329
 
    def _read_contents(self):
330
 
        if self._contents_read:
331
 
            return
332
 
        self._contents_read = True
333
 
        pb = ui.ui_factory.nested_progress_bar()
334
 
        try:
335
 
            for i, (path, value) in enumerate(self.index.iteritems()):
336
 
                pb.update("creating working inventory from index",
337
 
                        i, len(self.index))
338
 
                assert isinstance(path, str)
339
 
                assert isinstance(value, tuple) and len(value) == 10
340
 
                (ctime, mtime, dev, ino, mode, uid, gid, size, sha, flags) = value
341
 
                if self.basis_inv is not None:
342
 
                    try:
343
 
                        old_ie = self.basis_inv._get_ie(path)
344
 
                    except KeyError:
345
 
                        old_ie = None
346
 
                else:
347
 
                    old_ie = None
348
 
                if old_ie is None:
349
 
                    file_id = self.fileid_map.lookup_file_id(path)
350
 
                else:
351
 
                    file_id = old_ie.file_id
352
 
                if type(file_id) != str:
353
 
                    raise AssertionError
354
 
                kind = mode_kind(mode)
355
 
                if old_ie is not None and old_ie.hexsha == sha:
356
 
                    # Hasn't changed since basis inv
357
 
                    self.add_parents(path)
358
 
                    self.add(old_ie)
359
 
                else:
360
 
                    ie = self.add_path(path, kind, file_id,
361
 
                        self.add_parents(path))
362
 
                    data = self.store[sha].data
363
 
                    if kind == "symlink":
364
 
                        ie.symlink_target = data
365
 
                    else:
366
 
                        ie.text_sha1 = osutils.sha_string(data)
367
 
                        ie.text_size = len(data)
368
 
                    ie.revision = None
369
 
        finally:
370
 
            pb.finished()
371
 
 
372
 
    def add_parents(self, path):
373
 
        dirname, _ = osutils.split(path)
374
 
        file_id = super(GitIndexInventory, self).path2id(dirname)
375
 
        if file_id is None:
376
 
            if dirname == "":
377
 
                parent_fid = None
378
 
            else:
379
 
                parent_fid = self.add_parents(dirname)
380
 
            ie = self.add_path(dirname, 'directory',
381
 
                    self.fileid_map.lookup_file_id(dirname), parent_fid)
382
 
            if self.basis_inv is not None and ie.file_id in self.basis_inv:
383
 
                ie.revision = self.basis_inv[ie.file_id].revision
384
 
            file_id = ie.file_id
385
 
        if type(file_id) != str:
386
 
            raise AssertionError
387
 
        return file_id
388