~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/repository.py

  • Committer: Martin
  • Date: 2010-05-16 15:18:43 UTC
  • mfrom: (5235 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5239.
  • Revision ID: gzlist@googlemail.com-20100516151843-lu53u7caehm3ie3i
Merge bzr.dev to resolve conflicts in NEWS and _chk_map_pyx

Show diffs side-by-side

added added

removed removed

Lines of Context:
26
26
    chk_map,
27
27
    config,
28
28
    debug,
29
 
    errors,
30
29
    fetch as _mod_fetch,
31
30
    fifo_cache,
32
31
    generate_ids,
53
52
from bzrlib.testament import Testament
54
53
""")
55
54
 
 
55
from bzrlib import (
 
56
    errors,
 
57
    registry,
 
58
    )
56
59
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
57
60
from bzrlib.inter import InterObject
58
61
from bzrlib.inventory import (
61
64
    ROOT_ID,
62
65
    entry_factory,
63
66
    )
64
 
from bzrlib.lock import _RelockDebugMixin
65
 
from bzrlib import registry
 
67
from bzrlib.lock import _RelockDebugMixin, LogicalLockResult
66
68
from bzrlib.trace import (
67
69
    log_exception_quietly, note, mutter, mutter_callsite, warning)
68
70
 
71
73
_deprecation_warning_done = False
72
74
 
73
75
 
 
76
class IsInWriteGroupError(errors.InternalBzrError):
 
77
 
 
78
    _fmt = "May not refresh_data of repo %(repo)s while in a write group."
 
79
 
 
80
    def __init__(self, repo):
 
81
        errors.InternalBzrError.__init__(self, repo=repo)
 
82
 
 
83
 
74
84
class CommitBuilder(object):
75
85
    """Provides an interface to build up a commit.
76
86
 
278
288
 
279
289
        :param tree: The tree which is being committed.
280
290
        """
281
 
        # NB: if there are no parents then this method is not called, so no
282
 
        # need to guard on parents having length.
 
291
        if len(self.parents) == 0:
 
292
            raise errors.RootMissing()
283
293
        entry = entry_factory['directory'](tree.path2id(''), '',
284
294
            None)
285
295
        entry.revision = self._new_revision_id
860
870
        # versioned roots do not change unless the tree found a change.
861
871
 
862
872
 
 
873
class RepositoryWriteLockResult(LogicalLockResult):
 
874
    """The result of write locking a repository.
 
875
 
 
876
    :ivar repository_token: The token obtained from the underlying lock, or
 
877
        None.
 
878
    :ivar unlock: A callable which will unlock the lock.
 
879
    """
 
880
 
 
881
    def __init__(self, unlock, repository_token):
 
882
        LogicalLockResult.__init__(self, unlock)
 
883
        self.repository_token = repository_token
 
884
 
 
885
    def __repr__(self):
 
886
        return "RepositoryWriteLockResult(%s, %s)" % (self.repository_token,
 
887
            self.unlock)
 
888
 
 
889
 
863
890
######################################################################
864
891
# Repositories
865
892
 
866
893
 
867
 
class Repository(_RelockDebugMixin):
 
894
class Repository(_RelockDebugMixin, bzrdir.ControlComponent):
868
895
    """Repository holding history for one or more branches.
869
896
 
870
897
    The repository holds and retrieves historical information including
1018
1045
                " id and insertion revid (%r, %r)"
1019
1046
                % (inv.revision_id, revision_id))
1020
1047
        if inv.root is None:
1021
 
            raise AssertionError()
 
1048
            raise errors.RootMissing()
1022
1049
        return self._add_inventory_checked(revision_id, inv, parents)
1023
1050
 
1024
1051
    def _add_inventory_checked(self, revision_id, inv, parents):
1291
1318
 
1292
1319
        :param _format: The format of the repository on disk.
1293
1320
        :param a_bzrdir: The BzrDir of the repository.
1294
 
 
1295
 
        In the future we will have a single api for all stores for
1296
 
        getting file texts, inventories and revisions, then
1297
 
        this construct will accept instances of those things.
1298
1321
        """
 
1322
        # In the future we will have a single api for all stores for
 
1323
        # getting file texts, inventories and revisions, then
 
1324
        # this construct will accept instances of those things.
1299
1325
        super(Repository, self).__init__()
1300
1326
        self._format = _format
1301
1327
        # the following are part of the public API for Repository:
1316
1342
        # rather copying them?
1317
1343
        self._safe_to_return_from_cache = False
1318
1344
 
 
1345
    @property
 
1346
    def user_transport(self):
 
1347
        return self.bzrdir.user_transport
 
1348
 
 
1349
    @property
 
1350
    def control_transport(self):
 
1351
        return self._transport
 
1352
 
1319
1353
    def __repr__(self):
1320
1354
        if self._fallback_repositories:
1321
1355
            return '%s(%r, fallback_repositories=%r)' % (
1369
1403
        data during reads, and allows a 'write_group' to be obtained. Write
1370
1404
        groups must be used for actual data insertion.
1371
1405
 
 
1406
        A token should be passed in if you know that you have locked the object
 
1407
        some other way, and need to synchronise this object's state with that
 
1408
        fact.
 
1409
 
 
1410
        XXX: this docstring is duplicated in many places, e.g. lockable_files.py
 
1411
 
1372
1412
        :param token: if this is already locked, then lock_write will fail
1373
1413
            unless the token matches the existing lock.
1374
1414
        :returns: a token if this instance supports tokens, otherwise None.
1377
1417
        :raises MismatchedToken: if the specified token doesn't match the token
1378
1418
            of the existing lock.
1379
1419
        :seealso: start_write_group.
1380
 
 
1381
 
        A token should be passed in if you know that you have locked the object
1382
 
        some other way, and need to synchronise this object's state with that
1383
 
        fact.
1384
 
 
1385
 
        XXX: this docstring is duplicated in many places, e.g. lockable_files.py
 
1420
        :return: A RepositoryWriteLockResult.
1386
1421
        """
1387
1422
        locked = self.is_locked()
1388
 
        result = self.control_files.lock_write(token=token)
 
1423
        token = self.control_files.lock_write(token=token)
1389
1424
        if not locked:
1390
1425
            self._warn_if_deprecated()
1391
1426
            self._note_lock('w')
1393
1428
                # Writes don't affect fallback repos
1394
1429
                repo.lock_read()
1395
1430
            self._refresh_data()
1396
 
        return result
 
1431
        return RepositoryWriteLockResult(self.unlock, token)
1397
1432
 
1398
1433
    def lock_read(self):
 
1434
        """Lock the repository for read operations.
 
1435
 
 
1436
        :return: An object with an unlock method which will release the lock
 
1437
            obtained.
 
1438
        """
1399
1439
        locked = self.is_locked()
1400
1440
        self.control_files.lock_read()
1401
1441
        if not locked:
1404
1444
            for repo in self._fallback_repositories:
1405
1445
                repo.lock_read()
1406
1446
            self._refresh_data()
 
1447
        return LogicalLockResult(self.unlock)
1407
1448
 
1408
1449
    def get_physical_lock_status(self):
1409
1450
        return self.control_files.get_physical_lock_status()
1469
1510
 
1470
1511
        # now gather global repository information
1471
1512
        # XXX: This is available for many repos regardless of listability.
1472
 
        if self.bzrdir.root_transport.listable():
 
1513
        if self.user_transport.listable():
1473
1514
            # XXX: do we want to __define len__() ?
1474
1515
            # Maybe the versionedfiles object should provide a different
1475
1516
            # method to get the number of keys.
1507
1548
 
1508
1549
        ret = []
1509
1550
        for branches, repository in bzrdir.BzrDir.find_bzrdirs(
1510
 
                self.bzrdir.root_transport, evaluate=Evaluator()):
 
1551
                self.user_transport, evaluate=Evaluator()):
1511
1552
            if branches is not None:
1512
1553
                ret.extend(branches)
1513
1554
            if not using and repository is not None:
1627
1668
        return missing_keys
1628
1669
 
1629
1670
    def refresh_data(self):
1630
 
        """Re-read any data needed to to synchronise with disk.
 
1671
        """Re-read any data needed to synchronise with disk.
1631
1672
 
1632
1673
        This method is intended to be called after another repository instance
1633
1674
        (such as one used by a smart server) has inserted data into the
1634
 
        repository. It may not be called during a write group, but may be
1635
 
        called at any other time.
 
1675
        repository. On all repositories this will work outside of write groups.
 
1676
        Some repository formats (pack and newer for bzrlib native formats)
 
1677
        support refresh_data inside write groups. If called inside a write
 
1678
        group on a repository that does not support refreshing in a write group
 
1679
        IsInWriteGroupError will be raised.
1636
1680
        """
1637
 
        if self.is_in_write_group():
1638
 
            raise errors.InternalBzrError(
1639
 
                "May not refresh_data while in a write group.")
1640
1681
        self._refresh_data()
1641
1682
 
1642
1683
    def resume_write_group(self, tokens):
2581
2622
            keys = tsort.topo_sort(parent_map)
2582
2623
        return [None] + list(keys)
2583
2624
 
2584
 
    def pack(self, hint=None):
 
2625
    def pack(self, hint=None, clean_obsolete_packs=False):
2585
2626
        """Compress the data within the repository.
2586
2627
 
2587
2628
        This operation only makes sense for some repository types. For other
2597
2638
            obtained from the result of commit_write_group(). Out of
2598
2639
            date hints are simply ignored, because concurrent operations
2599
2640
            can obsolete them rapidly.
 
2641
 
 
2642
        :param clean_obsolete_packs: Clean obsolete packs immediately after
 
2643
            the pack operation.
2600
2644
        """
2601
2645
 
2602
2646
    def get_transaction(self):
3168
3212
        """
3169
3213
        raise NotImplementedError(self.open)
3170
3214
 
 
3215
    def _run_post_repo_init_hooks(self, repository, a_bzrdir, shared):
 
3216
        from bzrlib.bzrdir import BzrDir, RepoInitHookParams
 
3217
        hooks = BzrDir.hooks['post_repo_init']
 
3218
        if not hooks:
 
3219
            return
 
3220
        params = RepoInitHookParams(repository, self, a_bzrdir, shared)
 
3221
        for hook in hooks:
 
3222
            hook(params)
 
3223
 
3171
3224
 
3172
3225
class MetaDirRepositoryFormat(RepositoryFormat):
3173
3226
    """Common base class for the new repositories using the metadir layout."""