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

  • Committer: Jelmer Vernooij
  • Date: 2009-07-22 13:10:44 UTC
  • mfrom: (0.200.588 trunk)
  • mto: (0.200.597 trunk)
  • mto: This revision was merged to the branch mainline in revision 6960.
  • Revision ID: jelmer@samba.org-20090722131044-r30g8w06xd8f40fl
merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
 
from cStringIO import (
18
 
    StringIO,
19
 
    )
20
 
import dulwich as git
21
17
from dulwich.objects import (
22
18
    Commit,
23
19
    Tag,
 
20
    S_ISGITLINK,
24
21
    )
25
22
from dulwich.object_store import (
26
23
    tree_lookup_path,
27
24
    )
 
25
import re
28
26
import stat
29
27
 
30
28
from bzrlib import (
35
33
    urlutils,
36
34
    )
37
35
from bzrlib.errors import (
38
 
    InvalidRevisionId,
39
36
    NoSuchId,
40
 
    NoSuchRevision,
41
37
    )
42
38
from bzrlib.inventory import (
43
39
    Inventory,
65
61
    DEFAULT_FILE_MODE,
66
62
    inventory_to_tree_and_blobs,
67
63
    mode_is_executable,
68
 
    text_to_blob,
 
64
    squash_revision,
69
65
    warn_unusual_mode,
70
66
    )
71
67
from bzrlib.plugins.git.object_store import (
81
77
    )
82
78
 
83
79
 
84
 
def import_git_blob(texts, mapping, path, hexsha, base_inv, parent_id, 
 
80
def import_git_blob(texts, mapping, path, hexsha, base_inv, base_ie, parent_id, 
85
81
    revision_id, parent_invs, shagitmap, lookup_object, executable, symlink):
86
82
    """Import a git blob object into a bzr repository.
87
83
 
98
94
    # We just have to hope this is indeed utf-8:
99
95
    ie = cls(file_id, urlutils.basename(path).decode("utf-8"), parent_id)
100
96
    ie.executable = executable
101
 
    ie.text_id = hexsha
102
97
    # See if this has changed at all
103
 
    try:
104
 
        base_ie = base_inv[file_id]
105
 
    except NoSuchId:
106
 
        base_ie = None
 
98
    if base_ie is None:
107
99
        base_sha = None
108
100
    else:
109
 
        base_sha = base_ie.text_id
110
101
        try:
111
 
            if base_sha is None:
112
 
                base_sha = shagitmap.lookup_blob(file_id, base_ie.revision)
 
102
            base_sha = shagitmap.lookup_blob(file_id, base_ie.revision)
113
103
        except KeyError:
114
104
            base_sha = None
115
105
        else:
121
111
        ie.text_size = base_ie.text_size
122
112
        ie.text_sha1 = base_ie.text_sha1
123
113
        ie.symlink_target = base_ie.symlink_target
124
 
        ie.revision = base_ie.revision
 
114
        if ie.executable == base_ie.executable:
 
115
            ie.revision = base_ie.revision
 
116
        else:
 
117
            blob = lookup_object(hexsha)
125
118
    else:
126
119
        blob = lookup_object(hexsha)
127
120
        if ie.kind == "symlink":
 
121
            ie.revision = None
128
122
            ie.symlink_target = blob.data
129
123
            ie.text_size = None
130
124
            ie.text_sha1 = None
143
137
                pie = pinv[file_id]
144
138
            except NoSuchId:
145
139
                continue
146
 
        if pie.text_sha1 == ie.text_sha1:
 
140
        if pie.text_sha1 == ie.text_sha1 and pie.executable == ie.executable and pie.symlink_target == ie.symlink_target:
147
141
            # found a revision in one of the parents to use
148
142
            ie.revision = pie.revision
149
143
            break
157
151
        shamap = [(hexsha, "blob", (ie.file_id, ie.revision))]
158
152
    else:
159
153
        shamap = []
160
 
    if file_id in base_inv:
 
154
    invdelta = []
 
155
    if base_ie is not None: 
161
156
        old_path = base_inv.id2path(file_id)
 
157
        if base_ie.kind == "directory":
 
158
            invdelta.extend(remove_disappeared_children(old_path, base_ie.children, []))
162
159
    else:
163
160
        old_path = None
164
 
    return ([(old_path, path, file_id, ie)], shamap)
165
 
 
166
 
 
167
 
def import_git_tree(texts, mapping, path, hexsha, base_inv, parent_id, 
 
161
    invdelta.append((old_path, path, file_id, ie))
 
162
    return (invdelta, shamap)
 
163
 
 
164
 
 
165
def import_git_submodule(texts, mapping, path, hexsha, base_inv, base_ie, parent_id, 
 
166
    revision_id, parent_invs, shagitmap, lookup_object):
 
167
    raise NotImplementedError(import_git_submodule)
 
168
 
 
169
 
 
170
def remove_disappeared_children(path, base_children, existing_children):
 
171
    ret = []
 
172
    deletable = [(osutils.pathjoin(path, k), v) for k,v in base_children.iteritems() if k not in existing_children]
 
173
    while deletable:
 
174
        (path, ie) = deletable.pop()
 
175
        ret.append((path, None, ie.file_id, None))
 
176
        if ie.kind == "directory":
 
177
            for name, child_ie in ie.children.iteritems():
 
178
                deletable.append((osutils.pathjoin(path, name), child_ie))
 
179
    return ret
 
180
 
 
181
 
 
182
def import_git_tree(texts, mapping, path, hexsha, base_inv, base_ie, parent_id, 
168
183
    revision_id, parent_invs, shagitmap, lookup_object):
169
184
    """Import a git tree object into a bzr repository.
170
185
 
179
194
    # We just have to hope this is indeed utf-8:
180
195
    ie = InventoryDirectory(file_id, urlutils.basename(path.decode("utf-8")), 
181
196
        parent_id)
182
 
    ie.text_id = hexsha
183
 
    try:
184
 
        base_ie = base_inv[file_id]
185
 
    except NoSuchId:
 
197
    if base_ie is None:
186
198
        # Newly appeared here
187
 
        base_ie = None
188
199
        ie.revision = revision_id
189
 
        texts.add_lines((file_id, ie.revision), (), [])
 
200
        texts.insert_record_stream([FulltextContentFactory((file_id, ie.revision), (), None, "")])
190
201
        invdelta.append((None, path, file_id, ie))
191
202
    else:
192
 
        base_sha = base_ie.text_id
193
203
        # See if this has changed at all
194
204
        try:
195
 
            if base_sha is None:
196
 
                base_sha = shagitmap.lookup_tree(file_id, base_inv.revision_id)
 
205
            base_sha = shagitmap.lookup_tree(file_id, base_inv.revision_id)
197
206
        except KeyError:
198
207
            pass
199
208
        else:
200
209
            if base_sha == hexsha:
201
210
                # If nothing has changed since the base revision, we're done
202
211
                return [], {}, []
 
212
        if base_ie.kind != "directory":
 
213
            ie.revision = revision_id
 
214
            texts.insert_record_stream([FulltextContentFactory((ie.file_id, ie.revision), (), None, "")])
 
215
            invdelta.append((base_inv.id2path(ie.file_id), path, ie.file_id, ie))
 
216
    if base_ie is not None and base_ie.kind == "directory":
 
217
        base_children = base_ie.children
 
218
    else:
 
219
        base_children = {}
203
220
    # Remember for next time
204
221
    existing_children = set()
205
222
    child_modes = {}
210
227
        existing_children.add(basename)
211
228
        child_path = osutils.pathjoin(path, name)
212
229
        if stat.S_ISDIR(mode):
213
 
            subinvdelta, grandchildmodes, subshamap = import_git_tree(texts, 
214
 
                    mapping, child_path, child_hexsha, base_inv, file_id, 
215
 
                    revision_id, parent_invs, shagitmap, lookup_object)
 
230
            subinvdelta, grandchildmodes, subshamap = import_git_tree(
 
231
                    texts, mapping, child_path, child_hexsha, base_inv, 
 
232
                    base_children.get(basename), file_id, revision_id, parent_invs, shagitmap,
 
233
                    lookup_object)
 
234
            invdelta.extend(subinvdelta)
 
235
            child_modes.update(grandchildmodes)
 
236
            shamap.extend(subshamap)
 
237
        elif S_ISGITLINK(mode): # submodule
 
238
            subinvdelta, grandchildmodes, subshamap = import_git_submodule(
 
239
                    texts, mapping, child_path, child_hexsha, base_inv, base_ie.get(basename),
 
240
                    file_id, revision_id, parent_invs, shagitmap, lookup_object)
216
241
            invdelta.extend(subinvdelta)
217
242
            child_modes.update(grandchildmodes)
218
243
            shamap.extend(subshamap)
219
244
        else:
220
245
            subinvdelta, subshamap = import_git_blob(texts, mapping, 
221
 
                    child_path, child_hexsha, base_inv, file_id, revision_id, 
222
 
                    parent_invs, shagitmap, lookup_object, 
 
246
                    child_path, child_hexsha, base_inv, base_children.get(basename), file_id,
 
247
                    revision_id, parent_invs, shagitmap, lookup_object, 
223
248
                    mode_is_executable(mode), stat.S_ISLNK(mode))
224
249
            invdelta.extend(subinvdelta)
225
250
            shamap.extend(subshamap)
227
252
                        stat.S_IFLNK, DEFAULT_FILE_MODE|0111):
228
253
            child_modes[child_path] = mode
229
254
    # Remove any children that have disappeared
230
 
    if base_ie is not None and base_ie.kind == 'directory':
231
 
        deletable = [v for k,v in base_ie.children.iteritems() if k not in existing_children]
232
 
        while deletable:
233
 
            ie = deletable.pop()
234
 
            invdelta.append((base_inv.id2path(ie.file_id), None, ie.file_id, None))
235
 
            if ie.kind == "directory":
236
 
                deletable.extend(ie.children.values())
 
255
    if base_ie is not None and base_ie.kind == "directory":
 
256
        invdelta.extend(remove_disappeared_children(base_inv.id2path(file_id), 
 
257
            base_children, existing_children))
237
258
    shamap.append((hexsha, "tree", (file_id, revision_id)))
238
259
    return invdelta, child_modes, shamap
239
260
 
272
293
            rev = mapping.import_commit(o)
273
294
            if repo.has_revision(rev.revision_id):
274
295
                continue
 
296
            squash_revision(repo, rev)
275
297
            root_trees[rev.revision_id] = o.tree
276
298
            revisions[rev.revision_id] = rev
277
299
            graph.append((rev.revision_id, rev.parent_ids))
302
324
                parent_invs_cache[parent_id] = parent_inv
303
325
        if parent_invs == []:
304
326
            base_inv = Inventory(root_id=None)
 
327
            base_ie = None
305
328
        else:
306
329
            base_inv = parent_invs[0]
 
330
            base_ie = base_inv.root
307
331
        inv_delta, unusual_modes, shamap = import_git_tree(repo.texts, 
308
 
                mapping, "", root_trees[revid], base_inv, None, revid, 
 
332
                mapping, "", root_trees[revid], base_inv, base_ie, None, revid, 
309
333
                parent_invs, target_git_object_retriever._idmap, lookup_object)
310
334
        target_git_object_retriever._idmap.add_entries(shamap)
311
335
        if unusual_modes != {}:
312
336
            for path, mode in unusual_modes.iteritems():
313
337
                warn_unusual_mode(rev.foreign_revid, path, mode)
 
338
            mapping.import_unusual_file_modes(rev, unusual_modes)
314
339
        try:
315
340
            basis_id = rev.parent_ids[0]
316
341
        except IndexError:
320
345
        parent_invs_cache[rev.revision_id] = inv
321
346
        repo.add_revision(rev.revision_id, rev)
322
347
        if "verify" in debug.debug_flags:
323
 
            objs = inventory_to_tree_and_blobs(inv, repo.texts, mapping)
 
348
            new_unusual_modes = mapping.export_unusual_file_modes(rev)
 
349
            if new_unusual_modes != unusual_modes:
 
350
                raise AssertionError("unusual modes don't match: %r != %r" % (unusual_modes, new_unusual_modes))
 
351
            objs = inventory_to_tree_and_blobs(inv, repo.texts, mapping, unusual_modes)
324
352
            for sha1, newobj, path in objs:
325
353
                assert path is not None
326
354
                oldobj = tree_lookup_path(lookup_object, root_trees[revid], path)
327
 
                assert oldobj == newobj, "%r != %r in %s" % (oldobj, newobj, path)
 
355
                if oldobj != newobj:
 
356
                    raise AssertionError("%r != %r in %s" % (oldobj, newobj, path))
328
357
 
329
358
    target_git_object_retriever._idmap.commit()
330
359
 
369
398
            else:
370
399
                ret = [mapping.revision_id_bzr_to_foreign(revid)[0] for revid in interesting_heads if revid not in (None, NULL_REVISION)]
371
400
            return [rev for rev in ret if not self.target.has_revision(mapping.revision_id_foreign_to_bzr(rev))]
372
 
        self.fetch_objects(determine_wants, mapping, pb)
 
401
        pack_hint = self.fetch_objects(determine_wants, mapping, pb)
 
402
        if pack_hint is not None and self.target._format.pack_compresses:
 
403
            self.target.pack(hint=pack_hint)
373
404
        return self._refs
374
405
 
375
406
 
 
407
_GIT_PROGRESS_RE = re.compile(r"(.*?): +(\d+)% \((\d+)/(\d+)\)")
 
408
def report_git_progress(pb, text):
 
409
    text = text.rstrip("\r\n")
 
410
    g = _GIT_PROGRESS_RE.match(text)
 
411
    if g is not None:
 
412
        (text, pct, current, total) = g.groups()
 
413
        pb.update(text, int(current), int(total))
 
414
    else:
 
415
        pb.update(text, 0, 0)
 
416
 
 
417
 
376
418
class InterRemoteGitNonGitRepository(InterGitNonGitRepository):
377
419
    """InterRepository that copies revisions from a remote Git into a non-Git 
378
420
    repository."""
379
421
 
 
422
    def get_target_heads(self):
 
423
        # FIXME: This should be more efficient
 
424
        all_revs = self.target.all_revision_ids()
 
425
        parent_map = self.target.get_parent_map(all_revs)
 
426
        all_parents = set()
 
427
        map(all_parents.update, parent_map.itervalues())
 
428
        return set(all_revs) - all_parents
 
429
 
380
430
    def fetch_objects(self, determine_wants, mapping, pb=None):
381
431
        def progress(text):
382
 
            pb.update("git: %s" % text.rstrip("\r\n"), 0, 0)
 
432
            report_git_progress(pb, text)
383
433
        store = BazaarObjectStore(self.target, mapping)
384
434
        self.target.lock_write()
385
435
        try:
386
 
            heads = self.target.get_graph().heads(self.target.all_revision_ids())
 
436
            heads = self.get_target_heads()
387
437
            graph_walker = store.get_graph_walker(
388
438
                    [store._lookup_revision_sha1(head) for head in heads])
389
439
            recorded_wants = []
405
455
                    import_git_objects(self.target, mapping, objects_iter, 
406
456
                            store, recorded_wants, pb)
407
457
                finally:
408
 
                    self.target.commit_write_group()
 
458
                    return self.target.commit_write_group()
409
459
            finally:
410
460
                if create_pb:
411
461
                    create_pb.finished()
440
490
                            self.source._git.object_store, 
441
491
                            target_git_object_retriever, wants, pb)
442
492
                finally:
443
 
                    self.target.commit_write_group()
 
493
                    return self.target.commit_write_group()
444
494
            finally:
445
495
                self.target.unlock()
446
496
        finally: