/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

Reduce number of round trips when fetching from Git.

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
"""Git inventory."""
19
19
 
20
20
 
 
21
import stat
 
22
 
 
23
 
21
24
from dulwich.objects import (
22
25
    Blob,
23
26
    Tree,
29
32
    inventory,
30
33
    osutils,
31
34
    ui,
32
 
    )
33
 
 
34
 
from bzrlib.plugins.git.mapping import (
35
 
    mode_kind,
36
 
    mode_is_executable,
 
35
    urlutils,
37
36
    )
38
37
 
39
38
 
67
66
    _git_class = Blob
68
67
 
69
68
    def __init__(self, inv, parent_id, hexsha, path, basename, executable):
70
 
        super(GitInventoryFile, self).__init__(inv, parent_id, hexsha, path,
71
 
            basename, executable)
 
69
        super(GitInventoryFile, self).__init__(inv, parent_id, hexsha, path, basename, executable)
72
70
        self.kind = 'file'
73
71
        self.text_id = None
74
72
        self.symlink_target = None
96
94
        return ''
97
95
 
98
96
    def copy(self):
99
 
        other = inventory.InventoryFile(self.file_id, self.name,
100
 
            self.parent_id)
 
97
        other = inventory.InventoryFile(self.file_id, self.name, self.parent_id)
101
98
        other.executable = self.executable
102
99
        other.text_id = self.text_id
103
100
        other.text_sha1 = self.text_sha1
126
123
 
127
124
    def copy(self):
128
125
        other = inventory.InventoryLink(self.file_id, self.name, self.parent_id)
129
 
        other.executable = self.executable
130
126
        other.symlink_target = self.symlink_target
131
127
        other.revision = self.revision
132
128
        return other
133
129
 
134
130
 
135
 
class GitInventoryTreeReference(GitInventoryEntry):
136
 
 
137
 
    _git_class = None
138
 
 
139
 
    def __init__(self, inv, parent_id, hexsha, path, basename, executable):
140
 
        super(GitInventoryTreeReference, self).__init__(inv, parent_id, hexsha, path, basename, executable)
141
 
        self.hexsha = hexsha
142
 
        self.reference_revision = inv.mapping.revision_id_foreign_to_bzr(hexsha)
143
 
        self.text_sha1 = None
144
 
        self.text_size = None
145
 
        self.symlink_target = None
146
 
        self.kind = 'tree-reference'
147
 
        self._children = None
148
 
 
149
 
    def kind_character(self):
150
 
        """See InventoryEntry.kind_character."""
151
 
        return '/'
152
 
 
153
 
 
154
131
class GitInventoryDirectory(GitInventoryEntry):
155
132
 
156
133
    _git_class = Tree
178
155
        for mode, name, hexsha in self.object.entries():
179
156
            basename = name.decode("utf-8")
180
157
            child_path = osutils.pathjoin(self.path, basename)
181
 
            executable = mode_is_executable(mode)
182
 
            kind_class = {'directory': GitInventoryDirectory,
183
 
                          'file': GitInventoryFile,
184
 
                          'symlink': GitInventoryLink,
185
 
                          'tree-reference': GitInventoryTreeReference}[mode_kind(mode)]
 
158
            entry_kind = (mode & 0700000) / 0100000
 
159
            fs_mode = mode & 0777
 
160
            executable = bool(fs_mode & 0111)
 
161
            if entry_kind == 0:
 
162
                kind_class = GitInventoryDirectory
 
163
            elif entry_kind == 1:
 
164
                file_kind = (mode & 070000) / 010000
 
165
                if file_kind == 0:
 
166
                    kind_class = GitInventoryFile
 
167
                elif file_kind == 2:
 
168
                    kind_class = GitInventoryLink
 
169
                else:
 
170
                    raise AssertionError(
 
171
                        "Unknown file kind, perms=%o." % (mode,))
 
172
            else:
 
173
                raise AssertionError(
 
174
                    "Unknown blob kind, perms=%r." % (mode,))
186
175
            self._children[basename] = kind_class(self._inventory, self.file_id, hexsha, child_path, basename, executable)
187
176
 
188
177
    def copy(self):
189
 
        other = inventory.InventoryDirectory(self.file_id, self.name,
 
178
        other = inventory.InventoryDirectory(self.file_id, self.name, 
190
179
                                             self.parent_id)
191
180
        other.revision = self.revision
192
181
        # note that children are *not* copied; they're pulled across when
203
192
        self.root = GitInventoryDirectory(self, None, tree_id, u"", u"", False)
204
193
 
205
194
    def _get_ie(self, path):
206
 
        if path == "":
207
 
            return self.root
208
195
        parts = path.split("/")
209
196
        ie = self.root
210
197
        for name in parts:
211
 
            ie = ie.children[name]
 
198
            ie = ie.children[name] 
212
199
        return ie
213
200
 
214
201
    def has_filename(self, path):
252
239
class GitIndexInventory(inventory.Inventory):
253
240
    """Inventory that retrieves its contents from an index file."""
254
241
 
255
 
    def __init__(self, basis_inventory, mapping, index, store):
 
242
    def __init__(self, basis_inventory, mapping, index):
256
243
        super(GitIndexInventory, self).__init__(revision_id=None, root_id=basis_inventory.root.file_id)
257
244
        self.basis_inv = basis_inventory
258
245
        self.mapping = mapping
259
246
        self.index = index
260
 
        self._contents_read = False
261
 
        self.root = self.add_path("", 'directory',
262
 
            self.mapping.generate_file_id(""), None)
263
 
 
264
 
    def iter_entries_by_dir(self, specific_file_ids=None, yield_parents=False):
265
 
        self._read_contents()
266
 
        return super(GitIndexInventory, self).iter_entries_by_dir(specific_file_ids=specific_file_ids, yield_parents=yield_parents)
267
 
 
268
 
    def has_id(self, file_id):
269
 
        try:
270
 
            self.id2path(file_id)
271
 
            return True
272
 
        except errors.NoSuchId:
273
 
            return False
274
 
 
275
 
    def has_filename(self, path):
276
 
        if path in self.index:
277
 
            return True
278
 
        self._read_contents()
279
 
        return super(GitIndexInventory, self).has_filename(path)
280
 
 
281
 
    def id2path(self, file_id):
282
 
        path = self.mapping.parse_file_id(file_id)
283
 
        if path in self.index:
284
 
            return path
285
 
        self._read_contents()
286
 
        return super(GitIndexInventory, self).id2path(file_id)
287
 
 
288
 
    def path2id(self, path):
289
 
        if path in self.index:
290
 
            return self.mapping.generate_file_id(path)
291
 
        self._read_contents()
292
 
        return super(GitIndexInventory, self).path2id(path)
293
 
 
294
 
    def __getitem__(self, file_id):
295
 
        self._read_contents()
296
 
        return super(GitIndexInventory, self).__getitem__(file_id)
297
 
 
298
 
    def _read_contents(self):
299
 
        if self._contents_read:
300
 
            return
301
 
        self._contents_read = True
 
247
 
302
248
        pb = ui.ui_factory.nested_progress_bar()
303
249
        try:
304
250
            for i, (path, value) in enumerate(self.index.iteritems()):
305
 
                pb.update("creating working inventory from index",
 
251
                pb.update("creating working inventory from index", 
306
252
                        i, len(self.index))
307
253
                assert isinstance(path, str)
308
254
                assert isinstance(value, tuple) and len(value) == 10
309
 
                (ctime, mtime, dev, ino, mode, uid, gid, size, sha, flags) = value
 
255
                (ctime, mtime, ino, dev, mode, uid, gid, size, sha, flags) = value
310
256
                try:
311
257
                    old_ie = self.basis_inv._get_ie(path)
312
258
                except KeyError:
315
261
                    file_id = self.mapping.generate_file_id(path)
316
262
                else:
317
263
                    file_id = old_ie.file_id
318
 
                kind = mode_kind(mode)
 
264
                if stat.S_ISLNK(mode):
 
265
                    kind = 'symlink'
 
266
                else:
 
267
                    assert stat.S_ISREG(mode)
 
268
                    kind = 'file'
319
269
                if old_ie is not None and old_ie.hexsha == sha:
320
270
                    # Hasn't changed since basis inv
321
271
                    self.add_parents(path)
322
272
                    self.add(old_ie)
323
273
                else:
324
 
                    ie = self.add_path(path, kind, file_id,
325
 
                        self.add_parents(path))
326
 
                    data = store[sha].data
327
 
                    if kind == "symlink":
328
 
                        ie.symlink_target = data
329
 
                    else:
330
 
                        ie.text_sha1 = osutils.sha_string(data)
331
 
                        ie.text_size = len(data)
 
274
                    ie = self.add_path(path, kind, file_id, self.add_parents(path))
332
275
                    ie.revision = None
333
276
        finally:
334
277
            pb.finished()
335
278
 
336
279
    def add_parents(self, path):
337
280
        dirname, _ = osutils.split(path)
338
 
        file_id = super(GitIndexInventory, self).path2id(dirname)
 
281
        file_id = self.path2id(dirname)
339
282
        if file_id is None:
340
283
            if dirname == "":
341
284
                parent_fid = None
342
285
            else:
343
286
                parent_fid = self.add_parents(dirname)
344
 
            ie = self.add_path(dirname, 'directory',
 
287
            ie = self.add_path(dirname, 'directory', 
345
288
                    self.mapping.generate_file_id(dirname), parent_fid)
346
289
            if ie.file_id in self.basis_inv:
347
290
                ie.revision = self.basis_inv[ie.file_id].revision