/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 bzrlib/repository.py

  • Committer: Robert Collins
  • Date: 2010-05-06 23:41:35 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506234135-yivbzczw1sejxnxc
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
expected to return an object which can be used to unlock them. This reduces
duplicate code when using cleanups. The previous 'tokens's returned by
``Branch.lock_write`` and ``Repository.lock_write`` are now attributes
on the result of the lock_write. ``repository.RepositoryWriteLockResult``
and ``branch.BranchWriteLockResult`` document this. (Robert Collins)

``log._get_info_for_log_files`` now takes an add_cleanup callable.
(Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
    check,
26
26
    chk_map,
27
27
    config,
28
 
    controldir,
29
28
    debug,
 
29
    errors,
30
30
    fetch as _mod_fetch,
31
31
    fifo_cache,
32
32
    generate_ids,
39
39
    lockdir,
40
40
    lru_cache,
41
41
    osutils,
42
 
    pyutils,
43
42
    revision as _mod_revision,
44
43
    static_tuple,
45
44
    symbol_versioning,
46
45
    trace,
47
46
    tsort,
 
47
    ui,
48
48
    versionedfile,
49
49
    )
50
50
from bzrlib.bundle import serializer
53
53
from bzrlib.testament import Testament
54
54
""")
55
55
 
56
 
import sys
57
 
from bzrlib import (
58
 
    errors,
59
 
    registry,
60
 
    ui,
61
 
    )
62
56
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
63
57
from bzrlib.inter import InterObject
64
58
from bzrlib.inventory import (
67
61
    ROOT_ID,
68
62
    entry_factory,
69
63
    )
70
 
from bzrlib.recordcounter import RecordCounter
71
 
from bzrlib.lock import _RelockDebugMixin, LogicalLockResult
 
64
from bzrlib.lock import _RelockDebugMixin
 
65
from bzrlib import registry
72
66
from bzrlib.trace import (
73
67
    log_exception_quietly, note, mutter, mutter_callsite, warning)
74
68
 
77
71
_deprecation_warning_done = False
78
72
 
79
73
 
80
 
class IsInWriteGroupError(errors.InternalBzrError):
81
 
 
82
 
    _fmt = "May not refresh_data of repo %(repo)s while in a write group."
83
 
 
84
 
    def __init__(self, repo):
85
 
        errors.InternalBzrError.__init__(self, repo=repo)
86
 
 
87
 
 
88
74
class CommitBuilder(object):
89
75
    """Provides an interface to build up a commit.
90
76
 
115
101
 
116
102
        if committer is None:
117
103
            self._committer = self._config.username()
118
 
        elif not isinstance(committer, unicode):
119
 
            self._committer = committer.decode() # throw if non-ascii
120
104
        else:
121
105
            self._committer = committer
122
106
 
247
231
 
248
232
    def _gen_revision_id(self):
249
233
        """Return new revision-id."""
250
 
        return generate_ids.gen_revision_id(self._committer, self._timestamp)
 
234
        return generate_ids.gen_revision_id(self._config.username(),
 
235
                                            self._timestamp)
251
236
 
252
237
    def _generate_revision_if_needed(self):
253
238
        """Create a revision id if None was supplied.
293
278
 
294
279
        :param tree: The tree which is being committed.
295
280
        """
296
 
        if len(self.parents) == 0:
297
 
            raise errors.RootMissing()
 
281
        # NB: if there are no parents then this method is not called, so no
 
282
        # need to guard on parents having length.
298
283
        entry = entry_factory['directory'](tree.path2id(''), '',
299
284
            None)
300
285
        entry.revision = self._new_revision_id
438
423
            else:
439
424
                # we don't need to commit this, because the caller already
440
425
                # determined that an existing revision of this file is
441
 
                # appropriate. If it's not being considered for committing then
 
426
                # appropriate. If its not being considered for committing then
442
427
                # it and all its parents to the root must be unaltered so
443
428
                # no-change against the basis.
444
429
                if ie.revision == self._new_revision_id:
760
745
                    # after iter_changes examines and decides it has changed,
761
746
                    # we will unconditionally record a new version even if some
762
747
                    # other process reverts it while commit is running (with
763
 
                    # the revert happening after iter_changes did its
 
748
                    # the revert happening after iter_changes did it's
764
749
                    # examination).
765
750
                    if change[7][1]:
766
751
                        entry.executable = True
875
860
        # versioned roots do not change unless the tree found a change.
876
861
 
877
862
 
878
 
class RepositoryWriteLockResult(LogicalLockResult):
 
863
class RepositoryWriteLockResult(object):
879
864
    """The result of write locking a repository.
880
865
 
881
866
    :ivar repository_token: The token obtained from the underlying lock, or
884
869
    """
885
870
 
886
871
    def __init__(self, unlock, repository_token):
887
 
        LogicalLockResult.__init__(self, unlock)
888
872
        self.repository_token = repository_token
889
 
 
890
 
    def __repr__(self):
891
 
        return "RepositoryWriteLockResult(%s, %s)" % (self.repository_token,
892
 
            self.unlock)
 
873
        self.unlock = unlock
893
874
 
894
875
 
895
876
######################################################################
896
877
# Repositories
897
878
 
898
879
 
899
 
class Repository(_RelockDebugMixin, controldir.ControlComponent):
 
880
class Repository(_RelockDebugMixin, bzrdir.ControlComponent):
900
881
    """Repository holding history for one or more branches.
901
882
 
902
883
    The repository holds and retrieves historical information including
949
930
        pointing to .bzr/repository.
950
931
    """
951
932
 
952
 
    # What class to use for a CommitBuilder. Often it's simpler to change this
 
933
    # What class to use for a CommitBuilder. Often its simpler to change this
953
934
    # in a Repository class subclass rather than to override
954
935
    # get_commit_builder.
955
936
    _commit_builder_class = CommitBuilder
1050
1031
                " id and insertion revid (%r, %r)"
1051
1032
                % (inv.revision_id, revision_id))
1052
1033
        if inv.root is None:
1053
 
            raise errors.RootMissing()
 
1034
            raise AssertionError()
1054
1035
        return self._add_inventory_checked(revision_id, inv, parents)
1055
1036
 
1056
1037
    def _add_inventory_checked(self, revision_id, inv, parents):
1449
1430
            for repo in self._fallback_repositories:
1450
1431
                repo.lock_read()
1451
1432
            self._refresh_data()
1452
 
        return LogicalLockResult(self.unlock)
 
1433
        return self
1453
1434
 
1454
1435
    def get_physical_lock_status(self):
1455
1436
        return self.control_files.get_physical_lock_status()
1673
1654
        return missing_keys
1674
1655
 
1675
1656
    def refresh_data(self):
1676
 
        """Re-read any data needed to synchronise with disk.
 
1657
        """Re-read any data needed to to synchronise with disk.
1677
1658
 
1678
1659
        This method is intended to be called after another repository instance
1679
1660
        (such as one used by a smart server) has inserted data into the
1680
 
        repository. On all repositories this will work outside of write groups.
1681
 
        Some repository formats (pack and newer for bzrlib native formats)
1682
 
        support refresh_data inside write groups. If called inside a write
1683
 
        group on a repository that does not support refreshing in a write group
1684
 
        IsInWriteGroupError will be raised.
 
1661
        repository. It may not be called during a write group, but may be
 
1662
        called at any other time.
1685
1663
        """
 
1664
        if self.is_in_write_group():
 
1665
            raise errors.InternalBzrError(
 
1666
                "May not refresh_data while in a write group.")
1686
1667
        self._refresh_data()
1687
1668
 
1688
1669
    def resume_write_group(self, tokens):
1727
1708
                "May not fetch while in a write group.")
1728
1709
        # fast path same-url fetch operations
1729
1710
        # TODO: lift out to somewhere common with RemoteRepository
1730
 
        # <https://bugs.launchpad.net/bzr/+bug/401646>
 
1711
        # <https://bugs.edge.launchpad.net/bzr/+bug/401646>
1731
1712
        if (self.has_same_location(source)
1732
1713
            and fetch_spec is None
1733
1714
            and self._has_same_fallbacks(source)):
2515
2496
            ancestors will be traversed.
2516
2497
        """
2517
2498
        graph = self.get_graph()
2518
 
        stop_revisions = (None, _mod_revision.NULL_REVISION)
2519
 
        return graph.iter_lefthand_ancestry(revision_id, stop_revisions)
 
2499
        next_id = revision_id
 
2500
        while True:
 
2501
            if next_id in (None, _mod_revision.NULL_REVISION):
 
2502
                return
 
2503
            try:
 
2504
                parents = graph.get_parent_map([next_id])[next_id]
 
2505
            except KeyError:
 
2506
                raise errors.RevisionNotPresent(next_id, self)
 
2507
            yield next_id
 
2508
            if len(parents) == 0:
 
2509
                return
 
2510
            else:
 
2511
                next_id = parents[0]
2520
2512
 
2521
2513
    def is_shared(self):
2522
2514
        """Return True if this repository is flagged as a shared repository."""
2623
2615
        types it should be a no-op that just returns.
2624
2616
 
2625
2617
        This stub method does not require a lock, but subclasses should use
2626
 
        @needs_write_lock as this is a long running call it's reasonable to
 
2618
        @needs_write_lock as this is a long running call its reasonable to
2627
2619
        implicitly lock for the user.
2628
2620
 
2629
2621
        :param hint: If not supplied, the whole repository is packed.
2829
2821
            % (name, from_module),
2830
2822
            DeprecationWarning,
2831
2823
            stacklevel=2)
 
2824
        m = __import__(from_module, globals(), locals(), [name])
2832
2825
        try:
2833
 
            return pyutils.get_named_object(from_module, name)
 
2826
            return getattr(m, name)
2834
2827
        except AttributeError:
2835
2828
            raise AttributeError('module %s has no name %s'
2836
 
                    % (sys.modules[from_module], name))
 
2829
                    % (m, name))
2837
2830
    globals()[name] = _deprecated_repository_forwarder
2838
2831
 
2839
2832
for _name in [
3381
3374
    'bzrlib.repofmt.groupcompress_repo',
3382
3375
    'RepositoryFormat2a',
3383
3376
    )
3384
 
format_registry.register_lazy(
3385
 
    'Bazaar development format 8\n',
3386
 
    'bzrlib.repofmt.groupcompress_repo',
3387
 
    'RepositoryFormat2aSubtree',
3388
 
    )
3389
3377
 
3390
3378
 
3391
3379
class InterRepository(InterObject):
3845
3833
                basis_id, delta, current_revision_id, parents_parents)
3846
3834
            cache[current_revision_id] = parent_tree
3847
3835
 
3848
 
    def _fetch_batch(self, revision_ids, basis_id, cache):
 
3836
    def _fetch_batch(self, revision_ids, basis_id, cache, a_graph=None):
3849
3837
        """Fetch across a few revisions.
3850
3838
 
3851
3839
        :param revision_ids: The revisions to copy
3852
3840
        :param basis_id: The revision_id of a tree that must be in cache, used
3853
3841
            as a basis for delta when no other base is available
3854
3842
        :param cache: A cache of RevisionTrees that we can use.
 
3843
        :param a_graph: A Graph object to determine the heads() of the
 
3844
            rich-root data stream.
3855
3845
        :return: The revision_id of the last converted tree. The RevisionTree
3856
3846
            for it will be in cache
3857
3847
        """
3925
3915
        if root_keys_to_create:
3926
3916
            root_stream = _mod_fetch._new_root_data_stream(
3927
3917
                root_keys_to_create, self._revision_id_to_root_id, parent_map,
3928
 
                self.source)
 
3918
                self.source, graph=a_graph)
3929
3919
            to_texts.insert_record_stream(root_stream)
3930
3920
        to_texts.insert_record_stream(from_texts.get_record_stream(
3931
3921
            text_keys, self.target._format._fetch_order,
3988
3978
        cache[basis_id] = basis_tree
3989
3979
        del basis_tree # We don't want to hang on to it here
3990
3980
        hints = []
3991
 
        a_graph = None
 
3981
        if self._converting_to_rich_root and len(revision_ids) > 100:
 
3982
            a_graph = _mod_fetch._get_rich_root_heads_graph(self.source,
 
3983
                                                            revision_ids)
 
3984
        else:
 
3985
            a_graph = None
3992
3986
 
3993
3987
        for offset in range(0, len(revision_ids), batch_size):
3994
3988
            self.target.start_write_group()
3996
3990
                pb.update('Transferring revisions', offset,
3997
3991
                          len(revision_ids))
3998
3992
                batch = revision_ids[offset:offset+batch_size]
3999
 
                basis_id = self._fetch_batch(batch, basis_id, cache)
 
3993
                basis_id = self._fetch_batch(batch, basis_id, cache,
 
3994
                                             a_graph=a_graph)
4000
3995
            except:
4001
3996
                self.source._safe_to_return_from_cache = False
4002
3997
                self.target.abort_write_group()
4068
4063
            basis_id = first_rev.parent_ids[0]
4069
4064
            # only valid as a basis if the target has it
4070
4065
            self.target.get_revision(basis_id)
4071
 
            # Try to get a basis tree - if it's a ghost it will hit the
 
4066
            # Try to get a basis tree - if its a ghost it will hit the
4072
4067
            # NoSuchRevision case.
4073
4068
            basis_tree = self.source.revision_tree(basis_id)
4074
4069
        except (IndexError, errors.NoSuchRevision):
4274
4269
                is_resume = False
4275
4270
            try:
4276
4271
                # locked_insert_stream performs a commit|suspend.
4277
 
                return self._locked_insert_stream(stream, src_format,
4278
 
                    is_resume)
 
4272
                return self._locked_insert_stream(stream, src_format, is_resume)
4279
4273
            except:
4280
4274
                self.target_repo.abort_write_group(suppress_errors=True)
4281
4275
                raise
4328
4322
                # required if the serializers are different only in terms of
4329
4323
                # the inventory.
4330
4324
                if src_serializer == to_serializer:
4331
 
                    self.target_repo.revisions.insert_record_stream(substream)
 
4325
                    self.target_repo.revisions.insert_record_stream(
 
4326
                        substream)
4332
4327
                else:
4333
4328
                    self._extract_and_insert_revisions(substream,
4334
4329
                        src_serializer)
4442
4437
        """Create a StreamSource streaming from from_repository."""
4443
4438
        self.from_repository = from_repository
4444
4439
        self.to_format = to_format
4445
 
        self._record_counter = RecordCounter()
4446
4440
 
4447
4441
    def delta_on_metadata(self):
4448
4442
        """Return True if delta's are permitted on metadata streams.