/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 breezy/plugins/git/repository.py

Merge test-run support.

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
 
20
20
from __future__ import absolute_import
21
21
 
22
 
from .. import (
 
22
from ... import (
23
23
    check,
24
24
    errors,
25
25
    graph as _mod_graph,
29
29
    trace,
30
30
    transactions,
31
31
    ui,
 
32
    version_info as breezy_version,
32
33
    )
33
 
from ..decorators import only_raises
34
 
from ..foreign import (
 
34
from ...decorators import only_raises
 
35
from ...foreign import (
35
36
    ForeignRepository,
36
37
    )
37
 
from ..sixish import (
38
 
    viewitems,
39
 
    viewvalues,
40
 
    )
41
38
 
42
39
from .commit import (
43
40
    GitCommitBuilder,
68
65
    )
69
66
 
70
67
 
 
68
class RepoReconciler(object):
 
69
    """Reconciler that reconciles a repository.
 
70
 
 
71
    """
 
72
 
 
73
    def __init__(self, repo, other=None, thorough=False):
 
74
        """Construct a RepoReconciler.
 
75
 
 
76
        :param thorough: perform a thorough check which may take longer but
 
77
                         will correct non-data loss issues such as incorrect
 
78
                         cached data.
 
79
        """
 
80
        self.repo = repo
 
81
 
 
82
    def reconcile(self):
 
83
        """Perform reconciliation.
 
84
 
 
85
        After reconciliation the following attributes document found issues:
 
86
        inconsistent_parents: The number of revisions in the repository whose
 
87
                              ancestry was being reported incorrectly.
 
88
        garbage_inventories: The number of inventory objects without revisions
 
89
                             that were garbage collected.
 
90
        """
 
91
 
 
92
 
71
93
class GitCheck(check.Check):
72
94
 
73
95
    def __init__(self, repository, check_repo=True):
80
102
    def check(self, callback_refs=None, check_repo=True):
81
103
        if callback_refs is None:
82
104
            callback_refs = {}
83
 
        with self.repository.lock_read(), \
84
 
                ui.ui_factory.nested_progress_bar() as self.progress:
 
105
        with self.repository.lock_read(), ui.ui_factory.nested_progress_bar() as self.progress:
85
106
            shas = set(self.repository._git.object_store)
86
107
            self.object_count = len(shas)
87
108
            # TODO(jelmer): Check more things
108
129
 
109
130
_optimisers_loaded = False
110
131
 
111
 
 
112
132
def lazy_load_optimisers():
113
133
    global _optimisers_loaded
114
134
    if _optimisers_loaded:
135
155
    def __init__(self, gitdir):
136
156
        self._transport = gitdir.root_transport
137
157
        super(GitRepository, self).__init__(GitRepositoryFormat(),
138
 
                                            gitdir, control_files=None)
 
158
            gitdir, control_files=None)
139
159
        self.base = gitdir.root_transport.base
140
160
        lazy_load_optimisers()
141
161
        self._lock_mode = None
143
163
 
144
164
    def add_fallback_repository(self, basis_url):
145
165
        raise errors.UnstackableRepositoryFormat(self._format,
146
 
                                                 self.control_transport.base)
 
166
            self.control_transport.base)
147
167
 
148
168
    def is_shared(self):
149
169
        return False
216
236
 
217
237
    def reconcile(self, other=None, thorough=False):
218
238
        """Reconcile this repository."""
219
 
        from ..reconcile import ReconcileResult
220
 
        ret = ReconcileResult()
221
 
        ret.aborted = False
222
 
        return ret
 
239
        reconciler = RepoReconciler(self, thorough=thorough)
 
240
        reconciler.reconcile()
 
241
        return reconciler
223
242
 
224
243
    def supports_rich_root(self):
225
244
        return True
265
284
        :param lossy: Whether to discard data that can not be natively
266
285
            represented, when pushing to a foreign VCS
267
286
        """
268
 
        builder = GitCommitBuilder(
269
 
            self, parents, config, timestamp, timezone, committer, revprops,
270
 
            revision_id, lossy)
 
287
        builder = GitCommitBuilder(self, parents, config,
 
288
                timestamp, timezone, committer, revprops, revision_id,
 
289
                lossy)
271
290
        self.start_write_group()
272
291
        return builder
273
292
 
298
317
        for (file_id, revision_id, identifier) in desired_files:
299
318
            per_revision.setdefault(revision_id, []).append(
300
319
                (file_id, identifier))
301
 
        for revid, files in viewitems(per_revision):
 
320
        for revid, files in per_revision.iteritems():
302
321
            try:
303
322
                (commit_id, mapping) = self.lookup_bzr_revision_id(revid)
304
323
            except errors.NoSuchRevision:
315
334
                    raise errors.RevisionNotPresent((fileid, revid), self)
316
335
                try:
317
336
                    obj = tree_lookup_path(
318
 
                        self._git.object_store.__getitem__, root_tree,
319
 
                        path.encode('utf-8'))
 
337
                        self._git.object_store.__getitem__, root_tree, path)
320
338
                    if isinstance(obj, tuple):
321
339
                        (mode, item_id) = obj
322
340
                        obj = self._git.object_store[item_id]
323
341
                except KeyError:
324
342
                    raise errors.RevisionNotPresent((fileid, revid), self)
325
343
                else:
326
 
                    if obj.type_name == b"tree":
 
344
                    if obj.type_name == "tree":
327
345
                        yield (identifier, [])
328
 
                    elif obj.type_name == b"blob":
 
346
                    elif obj.type_name == "blob":
329
347
                        yield (identifier, obj.chunked)
330
348
                    else:
331
349
                        raise AssertionError("file text resolved to %r" % obj)
332
350
 
333
351
    def gather_stats(self, revid=None, committers=None):
334
352
        """See Repository.gather_stats()."""
335
 
        result = super(LocalGitRepository, self).gather_stats(
336
 
            revid, committers)
 
353
        result = super(LocalGitRepository, self).gather_stats(revid, committers)
337
354
        revs = []
338
355
        for sha in self._git.object_store:
339
356
            o = self._git.object_store[sha]
340
 
            if o.type_name == b"commit":
 
357
            if o.type_name == "commit":
341
358
                revs.append(o.id)
342
359
        result['revisions'] = len(revs)
343
360
        return result
348
365
            o = self._git.object_store[sha]
349
366
            if not isinstance(o, Commit):
350
367
                continue
351
 
            revid = mapping.revision_id_foreign_to_bzr(o.id)
352
 
            yield o.id, revid
 
368
            rev, roundtrip_revid, verifiers = mapping.import_commit(o,
 
369
                mapping.revision_id_foreign_to_bzr)
 
370
            yield o.id, rev.revision_id, roundtrip_revid
353
371
 
354
372
    def all_revision_ids(self):
355
373
        ret = set()
356
 
        for git_sha, revid in self._iter_revision_ids():
357
 
            ret.add(revid)
 
374
        for git_sha, revid, roundtrip_revid in self._iter_revision_ids():
 
375
            if roundtrip_revid:
 
376
                ret.add(roundtrip_revid)
 
377
            else:
 
378
                ret.add(revid)
358
379
        return list(ret)
359
380
 
360
381
    def _get_parents(self, revid, no_alternates=False):
383
404
    def get_parent_map(self, revids, no_alternates=False):
384
405
        parent_map = {}
385
406
        for revision_id in revids:
386
 
            parents = self._get_parents(
387
 
                revision_id, no_alternates=no_alternates)
 
407
            parents = self._get_parents(revision_id, no_alternates=no_alternates)
388
408
            if revision_id == _mod_revision.NULL_REVISION:
389
409
                parent_map[revision_id] = ()
390
410
                continue
410
430
                    this_parent_map[revid] = parents
411
431
            parent_map.update(this_parent_map)
412
432
            pending = set()
413
 
            for values in viewvalues(this_parent_map):
414
 
                pending.update(values)
 
433
            map(pending.update, this_parent_map.itervalues())
415
434
            pending = pending.difference(parent_map)
416
435
        return _mod_graph.KnownGraph(parent_map)
417
436
 
441
460
        :raise KeyError: If foreign revision was not found
442
461
        :return: bzr revision id
443
462
        """
444
 
        if not isinstance(foreign_revid, bytes):
 
463
        if type(foreign_revid) is not str:
445
464
            raise TypeError(foreign_revid)
446
465
        if mapping is None:
447
466
            mapping = self.get_mapping()
450
469
        commit = self._git.object_store.peel_sha(foreign_revid)
451
470
        if not isinstance(commit, Commit):
452
471
            raise NotCommitError(commit.id)
453
 
        revid = mapping.get_revision_id(commit)
 
472
        rev, roundtrip_revid, verifiers = mapping.import_commit(commit,
 
473
            mapping.revision_id_foreign_to_bzr)
454
474
        # FIXME: check testament before doing this?
455
 
        return revid
 
475
        if roundtrip_revid:
 
476
            return roundtrip_revid
 
477
        else:
 
478
            return rev.revision_id
456
479
 
457
480
    def has_signature_for_revision_id(self, revision_id):
458
481
        """Check whether a GPG signature is present for this revision.
488
511
            without_sig = Commit.from_string(commit.as_raw_string())
489
512
            without_sig.gpgsig = None
490
513
 
491
 
            (result, key, plain_text) = gpg_strategy.verify(
492
 
                without_sig.as_raw_string(), commit.gpgsig)
 
514
            (result, key, plain_text) = gpg_strategy.verify(without_sig.as_raw_string(), commit.gpgsig)
493
515
            return (result, key)
494
516
 
495
517
    def lookup_bzr_revision_id(self, bzr_revid, mapping=None):
501
523
            details
502
524
        """
503
525
        try:
504
 
            (git_sha, mapping) = mapping_registry.revision_id_bzr_to_foreign(
505
 
                bzr_revid)
 
526
            (git_sha, mapping) = mapping_registry.revision_id_bzr_to_foreign(bzr_revid)
506
527
        except errors.InvalidRevisionId:
507
 
            raise errors.NoSuchRevision(self, bzr_revid)
 
528
            if mapping is None:
 
529
                mapping = self.get_mapping()
 
530
            try:
 
531
                return (self._git.refs[mapping.revid_as_refname(bzr_revid)],
 
532
                        mapping)
 
533
            except KeyError:
 
534
                # Update refs from Git commit objects
 
535
                # FIXME: Hitting this a lot will be very inefficient...
 
536
                pb = ui.ui_factory.nested_progress_bar()
 
537
                try:
 
538
                    for i, (git_sha, revid, roundtrip_revid) in enumerate(self._iter_revision_ids()):
 
539
                        if not roundtrip_revid:
 
540
                            continue
 
541
                        pb.update("resolving revision id", i)
 
542
                        refname = mapping.revid_as_refname(roundtrip_revid)
 
543
                        self._git.refs[refname] = git_sha
 
544
                        if roundtrip_revid == bzr_revid:
 
545
                            return git_sha, mapping
 
546
                finally:
 
547
                    pb.finished()
 
548
                raise errors.NoSuchRevision(self, bzr_revid)
508
549
        else:
509
550
            return (git_sha, mapping)
510
551
 
511
552
    def get_revision(self, revision_id):
512
 
        if not isinstance(revision_id, bytes):
 
553
        if not isinstance(revision_id, str):
513
554
            raise errors.InvalidRevisionId(revision_id, self)
514
555
        git_commit_id, mapping = self.lookup_bzr_revision_id(revision_id)
515
556
        try:
517
558
        except KeyError:
518
559
            raise errors.NoSuchRevision(self, revision_id)
519
560
        revision, roundtrip_revid, verifiers = mapping.import_commit(
520
 
            commit, self.lookup_foreign_revision_id, strict=False)
 
561
            commit, self.lookup_foreign_revision_id)
521
562
        if revision is None:
522
563
            raise AssertionError
523
564
        # FIXME: check verifiers ?
577
618
            required_trees.update(revision.parent_ids[:1])
578
619
 
579
620
        trees = dict((t.get_revision_id(), t) for
580
 
                     t in self.revision_trees(required_trees))
 
621
            t in self.revision_trees(required_trees))
581
622
 
582
623
        # Calculate the deltas
583
624
        for revision in revisions:
587
628
                old_tree = trees[revision.parent_ids[0]]
588
629
            new_tree = trees[revision.revision_id]
589
630
            if specific_fileids is not None:
590
 
                specific_files = [new_tree.id2path(
591
 
                    fid) for fid in specific_fileids]
 
631
                specific_files = [new_tree.id2path(fid) for fid in specific_fileids]
592
632
            else:
593
633
                specific_files = None
594
 
            yield new_tree.changes_from(
595
 
                old_tree, specific_files=specific_files)
 
634
            yield new_tree.changes_from(old_tree, specific_files=specific_files)
596
635
 
597
636
    def set_make_working_trees(self, trees):
598
637
        raise errors.UnsupportedOperation(self.set_make_working_trees, self)
599
638
 
600
639
    def fetch_objects(self, determine_wants, graph_walker, resolve_ext_ref,
601
 
                      progress=None, limit=None):
 
640
        progress=None, limit=None):
602
641
        return self._git.fetch_objects(determine_wants, graph_walker, progress,
603
 
                                       limit=limit)
 
642
            limit=limit)
604
643
 
605
644
 
606
645
class GitRepositoryFormat(repository.RepositoryFormat):
652
691
 
653
692
 
654
693
def get_extra_interrepo_test_combinations():
655
 
    from ..bzr.groupcompress_repo import RepositoryFormat2a
 
694
    from ...bzr.groupcompress_repo import RepositoryFormat2a
656
695
    from . import interrepo
657
696
    return [
658
 
        (interrepo.InterLocalGitNonGitRepository,
659
 
         GitRepositoryFormat(), RepositoryFormat2a()),
660
 
        (interrepo.InterLocalGitLocalGitRepository,
661
 
         GitRepositoryFormat(), GitRepositoryFormat()),
662
 
        (interrepo.InterToLocalGitRepository,
663
 
         RepositoryFormat2a(), GitRepositoryFormat()),
 
697
            (interrepo.InterLocalGitNonGitRepository, GitRepositoryFormat(), RepositoryFormat2a()),
 
698
            (interrepo.InterLocalGitLocalGitRepository, GitRepositoryFormat(), GitRepositoryFormat()),
 
699
            (interrepo.InterToLocalGitRepository, RepositoryFormat2a(), GitRepositoryFormat()),
664
700
        ]