~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/repository.py

Merge fix for overflow issues in pack_stat from 2.4

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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
 
from __future__ import absolute_import
18
 
 
19
17
from bzrlib.lazy_import import lazy_import
20
18
lazy_import(globals(), """
21
19
import itertools
22
20
import time
23
21
 
24
22
from bzrlib import (
 
23
    bzrdir,
25
24
    config,
26
25
    controldir,
27
26
    debug,
40
39
""")
41
40
 
42
41
from bzrlib import (
43
 
    bzrdir,
44
42
    errors,
45
43
    registry,
46
44
    symbol_versioning,
76
74
    record_root_entry = True
77
75
    # whether this commit builder supports the record_entry_contents interface
78
76
    supports_record_entry_contents = False
79
 
    # whether this commit builder will automatically update the branch that is
80
 
    # being committed to
81
 
    updates_branch = False
82
77
 
83
 
    def __init__(self, repository, parents, config_stack, timestamp=None,
 
78
    def __init__(self, repository, parents, config, timestamp=None,
84
79
                 timezone=None, committer=None, revprops=None,
85
80
                 revision_id=None, lossy=False):
86
81
        """Initiate a CommitBuilder.
95
90
        :param lossy: Whether to discard data that can not be natively
96
91
            represented, when pushing to a foreign VCS 
97
92
        """
98
 
        self._config_stack = config_stack
 
93
        self._config = config
99
94
        self._lossy = lossy
100
95
 
101
96
        if committer is None:
102
 
            self._committer = self._config_stack.get('email')
 
97
            self._committer = self._config.username()
103
98
        elif not isinstance(committer, unicode):
104
99
            self._committer = committer.decode() # throw if non-ascii
105
100
        else:
347
342
        self.control_files.break_lock()
348
343
 
349
344
    @staticmethod
350
 
    def create(controldir):
351
 
        """Construct the current default format repository in controldir."""
352
 
        return RepositoryFormat.get_default_format().initialize(controldir)
 
345
    def create(a_bzrdir):
 
346
        """Construct the current default format repository in a_bzrdir."""
 
347
        return RepositoryFormat.get_default_format().initialize(a_bzrdir)
353
348
 
354
 
    def __init__(self, _format, controldir, control_files):
 
349
    def __init__(self, _format, a_bzrdir, control_files):
355
350
        """instantiate a Repository.
356
351
 
357
352
        :param _format: The format of the repository on disk.
358
 
        :param controldir: The ControlDir of the repository.
 
353
        :param a_bzrdir: The BzrDir of the repository.
359
354
        :param control_files: Control files to use for locking, etc.
360
355
        """
361
356
        # In the future we will have a single api for all stores for
364
359
        super(Repository, self).__init__()
365
360
        self._format = _format
366
361
        # the following are part of the public API for Repository:
367
 
        self.bzrdir = controldir
 
362
        self.bzrdir = a_bzrdir
368
363
        self.control_files = control_files
369
364
        # for tests
370
365
        self._write_group = None
552
547
            def __init__(self):
553
548
                self.first_call = True
554
549
 
555
 
            def __call__(self, controldir):
556
 
                # On the first call, the parameter is always the controldir
 
550
            def __call__(self, bzrdir):
 
551
                # On the first call, the parameter is always the bzrdir
557
552
                # containing the current repo.
558
553
                if not self.first_call:
559
554
                    try:
560
 
                        repository = controldir.open_repository()
 
555
                        repository = bzrdir.open_repository()
561
556
                    except errors.NoRepositoryPresent:
562
557
                        pass
563
558
                    else:
564
559
                        return False, ([], repository)
565
560
                self.first_call = False
566
 
                value = (controldir.list_branches(), None)
 
561
                value = (bzrdir.list_branches(), None)
567
562
                return True, value
568
563
 
569
564
        ret = []
570
 
        for branches, repository in controldir.ControlDir.find_bzrdirs(
 
565
        for branches, repository in bzrdir.BzrDir.find_bzrdirs(
571
566
                self.user_transport, evaluate=Evaluator()):
572
567
            if branches is not None:
573
568
                ret.extend(branches)
607
602
        For instance, if the repository is at URL/.bzr/repository,
608
603
        Repository.open(URL) -> a Repository instance.
609
604
        """
610
 
        control = controldir.ControlDir.open(base)
 
605
        control = bzrdir.BzrDir.open(base)
611
606
        return control.open_repository()
612
607
 
613
608
    def copy_content_into(self, destination, revision_id=None):
644
639
        """
645
640
 
646
641
    def suspend_write_group(self):
647
 
        """Suspend a write group.
648
 
 
649
 
        :raise UnsuspendableWriteGroup: If the write group can not be
650
 
            suspended.
651
 
        :return: List of tokens
652
 
        """
653
642
        raise errors.UnsuspendableWriteGroup(self)
654
643
 
655
644
    def refresh_data(self):
677
666
    def _resume_write_group(self, tokens):
678
667
        raise errors.UnsuspendableWriteGroup(self)
679
668
 
680
 
    def fetch(self, source, revision_id=None, find_ghosts=False):
 
669
    def fetch(self, source, revision_id=None, find_ghosts=False,
 
670
            fetch_spec=None):
681
671
        """Fetch the content required to construct revision_id from source.
682
672
 
683
 
        If revision_id is None, then all content is copied.
 
673
        If revision_id is None and fetch_spec is None, then all content is
 
674
        copied.
684
675
 
685
676
        fetch() may not be used when the repository is in a write group -
686
677
        either finish the current write group before using fetch, or use
692
683
        :param revision_id: If specified, all the content needed for this
693
684
            revision ID will be copied to the target.  Fetch will determine for
694
685
            itself which content needs to be copied.
 
686
        :param fetch_spec: If specified, a SearchResult or
 
687
            PendingAncestryResult that describes which revisions to copy.  This
 
688
            allows copying multiple heads at once.  Mutually exclusive with
 
689
            revision_id.
695
690
        """
 
691
        if fetch_spec is not None and revision_id is not None:
 
692
            raise AssertionError(
 
693
                "fetch_spec and revision_id are mutually exclusive.")
696
694
        if self.is_in_write_group():
697
695
            raise errors.InternalBzrError(
698
696
                "May not fetch while in a write group.")
700
698
        # TODO: lift out to somewhere common with RemoteRepository
701
699
        # <https://bugs.launchpad.net/bzr/+bug/401646>
702
700
        if (self.has_same_location(source)
 
701
            and fetch_spec is None
703
702
            and self._has_same_fallbacks(source)):
704
703
            # check that last_revision is in 'from' and then return a
705
704
            # no-operation.
708
707
                self.get_revision(revision_id)
709
708
            return 0, []
710
709
        inter = InterRepository.get(source, self)
711
 
        return inter.fetch(revision_id=revision_id, find_ghosts=find_ghosts)
 
710
        return inter.fetch(revision_id=revision_id,
 
711
            find_ghosts=find_ghosts, fetch_spec=fetch_spec)
712
712
 
713
713
    def create_bundle(self, target, base, fileobj, format=None):
714
714
        return serializer.write_bundle(self, target, base, fileobj, format)
715
715
 
716
 
    def get_commit_builder(self, branch, parents, config_stack, timestamp=None,
 
716
    def get_commit_builder(self, branch, parents, config, timestamp=None,
717
717
                           timezone=None, committer=None, revprops=None,
718
718
                           revision_id=None, lossy=False):
719
719
        """Obtain a CommitBuilder for this repository.
720
720
 
721
721
        :param branch: Branch to commit to.
722
722
        :param parents: Revision ids of the parents of the new revision.
723
 
        :param config_stack: Configuration stack to use.
 
723
        :param config: Configuration to use.
724
724
        :param timestamp: Optional timestamp recorded for commit.
725
725
        :param timezone: Optional timezone for timestamp.
726
726
        :param committer: Optional committer to set for commit.
746
746
                repo.unlock()
747
747
 
748
748
    @needs_read_lock
749
 
    def clone(self, controldir, revision_id=None):
750
 
        """Clone this repository into controldir using the current format.
 
749
    def clone(self, a_bzrdir, revision_id=None):
 
750
        """Clone this repository into a_bzrdir using the current format.
751
751
 
752
752
        Currently no check is made that the format of this repository and
753
753
        the bzrdir format are compatible. FIXME RBC 20060201.
756
756
        """
757
757
        # TODO: deprecate after 0.16; cloning this with all its settings is
758
758
        # probably not very useful -- mbp 20070423
759
 
        dest_repo = self._create_sprouting_repo(
760
 
            controldir, shared=self.is_shared())
 
759
        dest_repo = self._create_sprouting_repo(a_bzrdir, shared=self.is_shared())
761
760
        self.copy_content_into(dest_repo, revision_id)
762
761
        return dest_repo
763
762
 
930
929
        parent_ids.discard(_mod_revision.NULL_REVISION)
931
930
        return parent_ids
932
931
 
 
932
    def fileids_altered_by_revision_ids(self, revision_ids):
 
933
        """Find the file ids and versions affected by revisions.
 
934
 
 
935
        :param revisions: an iterable containing revision ids.
 
936
        :return: a dictionary mapping altered file-ids to an iterable of
 
937
            revision_ids. Each altered file-ids has the exact revision_ids
 
938
            that altered it listed explicitly.
 
939
        """
 
940
        raise NotImplementedError(self.fileids_altered_by_revision_ids)
 
941
 
933
942
    def iter_files_bytes(self, desired_files):
934
943
        """Iterate through file versions.
935
944
 
1149
1158
                [parents_provider, other_repository._make_parents_provider()])
1150
1159
        return graph.Graph(parents_provider)
1151
1160
 
 
1161
    def revision_ids_to_search_result(self, result_set):
 
1162
        """Convert a set of revision ids to a graph SearchResult."""
 
1163
        result_parents = set()
 
1164
        for parents in self.get_graph().get_parent_map(
 
1165
            result_set).itervalues():
 
1166
            result_parents.update(parents)
 
1167
        included_keys = result_set.intersection(result_parents)
 
1168
        start_keys = result_set.difference(included_keys)
 
1169
        exclude_keys = result_parents.difference(result_set)
 
1170
        result = graph.SearchResult(start_keys, exclude_keys,
 
1171
            len(result_set), result_set)
 
1172
        return result
 
1173
 
1152
1174
    @needs_write_lock
1153
1175
    def set_make_working_trees(self, new_value):
1154
1176
        """Set the policy flag for making working trees when creating branches.
1172
1194
        self.store_revision_signature(gpg_strategy, plaintext, revision_id)
1173
1195
 
1174
1196
    @needs_read_lock
1175
 
    def verify_revision_signature(self, revision_id, gpg_strategy):
 
1197
    def verify_revision(self, revision_id, gpg_strategy):
1176
1198
        """Verify the signature on a revision.
1177
1199
        
1178
1200
        :param revision_id: the revision to verify
1224
1246
            return
1225
1247
        try:
1226
1248
            if branch is None:
1227
 
                conf = config.GlobalStack()
 
1249
                conf = config.GlobalConfig()
1228
1250
            else:
1229
 
                conf = branch.get_config_stack()
1230
 
            if 'format_deprecation' in conf.get('suppress_warnings'):
 
1251
                conf = branch.get_config()
 
1252
            if conf.suppress_warning('format_deprecation'):
1231
1253
                return
1232
1254
            warning("Format %s for %s is deprecated -"
1233
1255
                    " please use 'bzr upgrade' to get better performance"
1293
1315
        """Returns the policy for making working trees on new branches."""
1294
1316
        return not self._transport.has('no-working-trees')
1295
1317
 
1296
 
    @needs_write_lock
1297
 
    def update_feature_flags(self, updated_flags):
1298
 
        """Update the feature flags for this branch.
1299
 
 
1300
 
        :param updated_flags: Dictionary mapping feature names to necessities
1301
 
            A necessity can be None to indicate the feature should be removed
1302
 
        """
1303
 
        self._format._update_feature_flags(updated_flags)
1304
 
        self.control_transport.put_bytes('format', self._format.as_string())
1305
 
 
1306
1318
 
1307
1319
class RepositoryFormatRegistry(controldir.ControlComponentFormatRegistry):
1308
1320
    """Repository format registry."""
1309
1321
 
1310
1322
    def get_default(self):
1311
1323
        """Return the current default format."""
1312
 
        return controldir.format_registry.make_bzrdir('default').repository_format
 
1324
        from bzrlib import bzrdir
 
1325
        return bzrdir.format_registry.make_bzrdir('default').repository_format
1313
1326
 
1314
1327
 
1315
1328
network_format_registry = registry.FormatRegistry()
1358
1371
    created.
1359
1372
 
1360
1373
    Common instance attributes:
1361
 
    _matchingbzrdir - the controldir format that the repository format was
 
1374
    _matchingbzrdir - the bzrdir format that the repository format was
1362
1375
    originally written to work with. This can be used if manually
1363
1376
    constructing a bzrdir and repository, or more commonly for test suite
1364
1377
    parameterization.
1406
1419
    supports_versioned_directories = None
1407
1420
    # Can other repositories be nested into one of this format?
1408
1421
    supports_nesting_repositories = None
1409
 
    # Is it possible for revisions to be present without being referenced
1410
 
    # somewhere ?
1411
 
    supports_unreferenced_revisions = None
1412
1422
 
1413
1423
    def __repr__(self):
1414
1424
        return "%s()" % self.__class__.__name__
1421
1431
        return not self == other
1422
1432
 
1423
1433
    @classmethod
 
1434
    def find_format(klass, a_bzrdir):
 
1435
        """Return the format for the repository object in a_bzrdir.
 
1436
 
 
1437
        This is used by bzr native formats that have a "format" file in
 
1438
        the repository.  Other methods may be used by different types of
 
1439
        control directory.
 
1440
        """
 
1441
        try:
 
1442
            transport = a_bzrdir.get_repository_transport(None)
 
1443
            format_string = transport.get_bytes("format")
 
1444
            return format_registry.get(format_string)
 
1445
        except errors.NoSuchFile:
 
1446
            raise errors.NoRepositoryPresent(a_bzrdir)
 
1447
        except KeyError:
 
1448
            raise errors.UnknownFormatError(format=format_string,
 
1449
                                            kind='repository')
 
1450
 
 
1451
    @classmethod
1424
1452
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4, 0)))
1425
1453
    def register_format(klass, format):
1426
1454
        format_registry.register(format)
1436
1464
        """Return the current default format."""
1437
1465
        return format_registry.get_default()
1438
1466
 
 
1467
    def get_format_string(self):
 
1468
        """Return the ASCII format string that identifies this format.
 
1469
 
 
1470
        Note that in pre format ?? repositories the format string is
 
1471
        not permitted nor written to disk.
 
1472
        """
 
1473
        raise NotImplementedError(self.get_format_string)
 
1474
 
1439
1475
    def get_format_description(self):
1440
1476
        """Return the short description for this format."""
1441
1477
        raise NotImplementedError(self.get_format_description)
1442
1478
 
1443
 
    def initialize(self, controldir, shared=False):
1444
 
        """Initialize a repository of this format in controldir.
 
1479
    def initialize(self, a_bzrdir, shared=False):
 
1480
        """Initialize a repository of this format in a_bzrdir.
1445
1481
 
1446
 
        :param controldir: The controldir to put the new repository in it.
 
1482
        :param a_bzrdir: The bzrdir to put the new repository in it.
1447
1483
        :param shared: The repository should be initialized as a sharable one.
1448
1484
        :returns: The new repository object.
1449
1485
 
1450
1486
        This may raise UninitializableFormat if shared repository are not
1451
 
        compatible the controldir.
 
1487
        compatible the a_bzrdir.
1452
1488
        """
1453
1489
        raise NotImplementedError(self.initialize)
1454
1490
 
1490
1526
                'Does not support nested trees', target_format,
1491
1527
                from_format=self)
1492
1528
 
1493
 
    def open(self, controldir, _found=False):
1494
 
        """Return an instance of this format for a controldir.
 
1529
    def open(self, a_bzrdir, _found=False):
 
1530
        """Return an instance of this format for the bzrdir a_bzrdir.
1495
1531
 
1496
1532
        _found is a private parameter, do not use it.
1497
1533
        """
1498
1534
        raise NotImplementedError(self.open)
1499
1535
 
1500
 
    def _run_post_repo_init_hooks(self, repository, controldir, shared):
1501
 
        from bzrlib.controldir import ControlDir, RepoInitHookParams
1502
 
        hooks = ControlDir.hooks['post_repo_init']
 
1536
    def _run_post_repo_init_hooks(self, repository, a_bzrdir, shared):
 
1537
        from bzrlib.bzrdir import BzrDir, RepoInitHookParams
 
1538
        hooks = BzrDir.hooks['post_repo_init']
1503
1539
        if not hooks:
1504
1540
            return
1505
 
        params = RepoInitHookParams(repository, self, controldir, shared)
 
1541
        params = RepoInitHookParams(repository, self, a_bzrdir, shared)
1506
1542
        for hook in hooks:
1507
1543
            hook(params)
1508
1544
 
1509
1545
 
1510
 
class RepositoryFormatMetaDir(bzrdir.BzrFormat, RepositoryFormat):
 
1546
class MetaDirRepositoryFormat(RepositoryFormat):
1511
1547
    """Common base class for the new repositories using the metadir layout."""
1512
1548
 
1513
1549
    rich_root_data = False
1523
1559
        return matching
1524
1560
 
1525
1561
    def __init__(self):
1526
 
        RepositoryFormat.__init__(self)
1527
 
        bzrdir.BzrFormat.__init__(self)
 
1562
        super(MetaDirRepositoryFormat, self).__init__()
1528
1563
 
1529
1564
    def _create_control_files(self, a_bzrdir):
1530
1565
        """Create the required files and the initial control_files object."""
1554
1589
        finally:
1555
1590
            control_files.unlock()
1556
1591
 
1557
 
    @classmethod
1558
 
    def find_format(klass, a_bzrdir):
1559
 
        """Return the format for the repository object in a_bzrdir.
1560
 
 
1561
 
        This is used by bzr native formats that have a "format" file in
1562
 
        the repository.  Other methods may be used by different types of
1563
 
        control directory.
1564
 
        """
1565
 
        try:
1566
 
            transport = a_bzrdir.get_repository_transport(None)
1567
 
            format_string = transport.get_bytes("format")
1568
 
        except errors.NoSuchFile:
1569
 
            raise errors.NoRepositoryPresent(a_bzrdir)
1570
 
        return klass._find_format(format_registry, 'repository', format_string)
1571
 
 
1572
 
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
1573
 
            basedir=None):
1574
 
        RepositoryFormat.check_support_status(self,
1575
 
            allow_unsupported=allow_unsupported, recommend_upgrade=recommend_upgrade,
1576
 
            basedir=basedir)
1577
 
        bzrdir.BzrFormat.check_support_status(self, allow_unsupported=allow_unsupported,
1578
 
            recommend_upgrade=recommend_upgrade, basedir=basedir)
 
1592
    def network_name(self):
 
1593
        """Metadir formats have matching disk and network format strings."""
 
1594
        return self.get_format_string()
1579
1595
 
1580
1596
 
1581
1597
# formats which have no format string are not discoverable or independently
1582
1598
# creatable on disk, so are not registered in format_registry.  They're
1583
1599
# all in bzrlib.repofmt.knitreponow.  When an instance of one of these is
1584
 
# needed, it's constructed directly by the ControlDir.  Non-native formats where
 
1600
# needed, it's constructed directly by the BzrDir.  Non-native formats where
1585
1601
# the repository is not separately opened are similar.
1586
1602
 
1587
1603
format_registry.register_lazy(
1698
1714
        self.target.fetch(self.source, revision_id=revision_id)
1699
1715
 
1700
1716
    @needs_write_lock
1701
 
    def fetch(self, revision_id=None, find_ghosts=False):
 
1717
    def fetch(self, revision_id=None, find_ghosts=False,
 
1718
            fetch_spec=None):
1702
1719
        """Fetch the content required to construct revision_id.
1703
1720
 
1704
1721
        The content is copied from self.source to self.target.