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

  • Committer: Breezy landing bot
  • Author(s): Jelmer Vernooij
  • Date: 2017-06-07 18:37:11 UTC
  • mfrom: (6667.2.1 trunk)
  • Revision ID: breezy.the.bot@gmail.com-20170607183711-oz0x9xqqh9x8jgas
Use ControlDir rather than BzrDir, remove unused imports.

Merged from https://code.launchpad.net/~jelmer/brz/small-fixes/+merge/325196

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005-2011 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
from __future__ import absolute_import
 
18
 
 
19
from .lazy_import import lazy_import
 
20
lazy_import(globals(), """
 
21
import itertools
 
22
import time
 
23
 
 
24
from breezy import (
 
25
    config,
 
26
    controldir,
 
27
    debug,
 
28
    generate_ids,
 
29
    graph,
 
30
    osutils,
 
31
    revision as _mod_revision,
 
32
    testament as _mod_testament,
 
33
    gpg,
 
34
    )
 
35
from breezy.bundle import serializer
 
36
from breezy.i18n import gettext
 
37
""")
 
38
 
 
39
from . import (
 
40
    bzrdir,
 
41
    errors,
 
42
    registry,
 
43
    ui,
 
44
    )
 
45
from .decorators import needs_read_lock, needs_write_lock, only_raises
 
46
from .inter import InterObject
 
47
from .lock import _RelockDebugMixin, LogicalLockResult
 
48
from .sixish import (
 
49
    viewitems,
 
50
    viewvalues,
 
51
    )
 
52
from .trace import (
 
53
    log_exception_quietly, note, mutter, mutter_callsite, warning)
 
54
 
 
55
 
 
56
# Old formats display a warning, but only once
 
57
_deprecation_warning_done = False
 
58
 
 
59
 
 
60
class IsInWriteGroupError(errors.InternalBzrError):
 
61
 
 
62
    _fmt = "May not refresh_data of repo %(repo)s while in a write group."
 
63
 
 
64
    def __init__(self, repo):
 
65
        errors.InternalBzrError.__init__(self, repo=repo)
 
66
 
 
67
 
 
68
class CommitBuilder(object):
 
69
    """Provides an interface to build up a commit.
 
70
 
 
71
    This allows describing a tree to be committed without needing to
 
72
    know the internals of the format of the repository.
 
73
    """
 
74
 
 
75
    # all clients should supply tree roots.
 
76
    record_root_entry = True
 
77
    # whether this commit builder supports the record_entry_contents interface
 
78
    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
 
 
83
    def __init__(self, repository, parents, config_stack, timestamp=None,
 
84
                 timezone=None, committer=None, revprops=None,
 
85
                 revision_id=None, lossy=False):
 
86
        """Initiate a CommitBuilder.
 
87
 
 
88
        :param repository: Repository to commit to.
 
89
        :param parents: Revision ids of the parents of the new revision.
 
90
        :param timestamp: Optional timestamp recorded for commit.
 
91
        :param timezone: Optional timezone for timestamp.
 
92
        :param committer: Optional committer to set for commit.
 
93
        :param revprops: Optional dictionary of revision properties.
 
94
        :param revision_id: Optional revision id.
 
95
        :param lossy: Whether to discard data that can not be natively
 
96
            represented, when pushing to a foreign VCS 
 
97
        """
 
98
        self._config_stack = config_stack
 
99
        self._lossy = lossy
 
100
 
 
101
        if committer is None:
 
102
            self._committer = self._config_stack.get('email')
 
103
        elif not isinstance(committer, unicode):
 
104
            self._committer = committer.decode() # throw if non-ascii
 
105
        else:
 
106
            self._committer = committer
 
107
 
 
108
        self._new_revision_id = revision_id
 
109
        self.parents = parents
 
110
        self.repository = repository
 
111
 
 
112
        self._revprops = {}
 
113
        if revprops is not None:
 
114
            self._validate_revprops(revprops)
 
115
            self._revprops.update(revprops)
 
116
 
 
117
        if timestamp is None:
 
118
            timestamp = time.time()
 
119
        # Restrict resolution to 1ms
 
120
        self._timestamp = round(timestamp, 3)
 
121
 
 
122
        if timezone is None:
 
123
            self._timezone = osutils.local_time_offset()
 
124
        else:
 
125
            self._timezone = int(timezone)
 
126
 
 
127
        self._generate_revision_if_needed()
 
128
 
 
129
    def any_changes(self):
 
130
        """Return True if any entries were changed.
 
131
 
 
132
        This includes merge-only changes. It is the core for the --unchanged
 
133
        detection in commit.
 
134
 
 
135
        :return: True if any changes have occured.
 
136
        """
 
137
        raise NotImplementedError(self.any_changes)
 
138
 
 
139
    def _validate_unicode_text(self, text, context):
 
140
        """Verify things like commit messages don't have bogus characters."""
 
141
        if '\r' in text:
 
142
            raise ValueError('Invalid value for %s: %r' % (context, text))
 
143
 
 
144
    def _validate_revprops(self, revprops):
 
145
        for key, value in viewitems(revprops):
 
146
            # We know that the XML serializers do not round trip '\r'
 
147
            # correctly, so refuse to accept them
 
148
            if not isinstance(value, basestring):
 
149
                raise ValueError('revision property (%s) is not a valid'
 
150
                                 ' (unicode) string: %r' % (key, value))
 
151
            self._validate_unicode_text(value,
 
152
                                        'revision property (%s)' % (key,))
 
153
 
 
154
    def commit(self, message):
 
155
        """Make the actual commit.
 
156
 
 
157
        :return: The revision id of the recorded revision.
 
158
        """
 
159
        raise NotImplementedError(self.commit)
 
160
 
 
161
    def abort(self):
 
162
        """Abort the commit that is being built.
 
163
        """
 
164
        raise NotImplementedError(self.abort)
 
165
 
 
166
    def revision_tree(self):
 
167
        """Return the tree that was just committed.
 
168
 
 
169
        After calling commit() this can be called to get a
 
170
        RevisionTree representing the newly committed tree. This is
 
171
        preferred to calling Repository.revision_tree() because that may
 
172
        require deserializing the inventory, while we already have a copy in
 
173
        memory.
 
174
        """
 
175
        raise NotImplementedError(self.revision_tree)
 
176
 
 
177
    def finish_inventory(self):
 
178
        """Tell the builder that the inventory is finished.
 
179
 
 
180
        :return: The inventory id in the repository, which can be used with
 
181
            repository.get_inventory.
 
182
        """
 
183
        raise NotImplementedError(self.finish_inventory)
 
184
 
 
185
    def _gen_revision_id(self):
 
186
        """Return new revision-id."""
 
187
        return generate_ids.gen_revision_id(self._committer, self._timestamp)
 
188
 
 
189
    def _generate_revision_if_needed(self):
 
190
        """Create a revision id if None was supplied.
 
191
 
 
192
        If the repository can not support user-specified revision ids
 
193
        they should override this function and raise CannotSetRevisionId
 
194
        if _new_revision_id is not None.
 
195
 
 
196
        :raises: CannotSetRevisionId
 
197
        """
 
198
        if self._new_revision_id is None:
 
199
            self._new_revision_id = self._gen_revision_id()
 
200
            self.random_revid = True
 
201
        else:
 
202
            self.random_revid = False
 
203
 
 
204
    def will_record_deletes(self):
 
205
        """Tell the commit builder that deletes are being notified.
 
206
 
 
207
        This enables the accumulation of an inventory delta; for the resulting
 
208
        commit to be valid, deletes against the basis MUST be recorded via
 
209
        builder.record_delete().
 
210
        """
 
211
        raise NotImplementedError(self.will_record_deletes)
 
212
 
 
213
    def record_iter_changes(self, tree, basis_revision_id, iter_changes):
 
214
        """Record a new tree via iter_changes.
 
215
 
 
216
        :param tree: The tree to obtain text contents from for changed objects.
 
217
        :param basis_revision_id: The revision id of the tree the iter_changes
 
218
            has been generated against. Currently assumed to be the same
 
219
            as self.parents[0] - if it is not, errors may occur.
 
220
        :param iter_changes: An iter_changes iterator with the changes to apply
 
221
            to basis_revision_id. The iterator must not include any items with
 
222
            a current kind of None - missing items must be either filtered out
 
223
            or errored-on beefore record_iter_changes sees the item.
 
224
        :return: A generator of (file_id, relpath, fs_hash) tuples for use with
 
225
            tree._observed_sha1.
 
226
        """
 
227
        raise NotImplementedError(self.record_iter_changes)
 
228
 
 
229
 
 
230
class RepositoryWriteLockResult(LogicalLockResult):
 
231
    """The result of write locking a repository.
 
232
 
 
233
    :ivar repository_token: The token obtained from the underlying lock, or
 
234
        None.
 
235
    :ivar unlock: A callable which will unlock the lock.
 
236
    """
 
237
 
 
238
    def __init__(self, unlock, repository_token):
 
239
        LogicalLockResult.__init__(self, unlock)
 
240
        self.repository_token = repository_token
 
241
 
 
242
    def __repr__(self):
 
243
        return "RepositoryWriteLockResult(%s, %s)" % (self.repository_token,
 
244
            self.unlock)
 
245
 
 
246
 
 
247
######################################################################
 
248
# Repositories
 
249
 
 
250
 
 
251
class Repository(controldir.ControlComponent, _RelockDebugMixin):
 
252
    """Repository holding history for one or more branches.
 
253
 
 
254
    The repository holds and retrieves historical information including
 
255
    revisions and file history.  It's normally accessed only by the Branch,
 
256
    which views a particular line of development through that history.
 
257
 
 
258
    See VersionedFileRepository in breezy.vf_repository for the
 
259
    base class for most Bazaar repositories.
 
260
    """
 
261
 
 
262
    def abort_write_group(self, suppress_errors=False):
 
263
        """Commit the contents accrued within the current write group.
 
264
 
 
265
        :param suppress_errors: if true, abort_write_group will catch and log
 
266
            unexpected errors that happen during the abort, rather than
 
267
            allowing them to propagate.  Defaults to False.
 
268
 
 
269
        :seealso: start_write_group.
 
270
        """
 
271
        if self._write_group is not self.get_transaction():
 
272
            # has an unlock or relock occured ?
 
273
            if suppress_errors:
 
274
                mutter(
 
275
                '(suppressed) mismatched lock context and write group. %r, %r',
 
276
                self._write_group, self.get_transaction())
 
277
                return
 
278
            raise errors.BzrError(
 
279
                'mismatched lock context and write group. %r, %r' %
 
280
                (self._write_group, self.get_transaction()))
 
281
        try:
 
282
            self._abort_write_group()
 
283
        except Exception as exc:
 
284
            self._write_group = None
 
285
            if not suppress_errors:
 
286
                raise
 
287
            mutter('abort_write_group failed')
 
288
            log_exception_quietly()
 
289
            note(gettext('bzr: ERROR (ignored): %s'), exc)
 
290
        self._write_group = None
 
291
 
 
292
    def _abort_write_group(self):
 
293
        """Template method for per-repository write group cleanup.
 
294
 
 
295
        This is called during abort before the write group is considered to be
 
296
        finished and should cleanup any internal state accrued during the write
 
297
        group. There is no requirement that data handed to the repository be
 
298
        *not* made available - this is not a rollback - but neither should any
 
299
        attempt be made to ensure that data added is fully commited. Abort is
 
300
        invoked when an error has occured so futher disk or network operations
 
301
        may not be possible or may error and if possible should not be
 
302
        attempted.
 
303
        """
 
304
 
 
305
    def add_fallback_repository(self, repository):
 
306
        """Add a repository to use for looking up data not held locally.
 
307
 
 
308
        :param repository: A repository.
 
309
        """
 
310
        raise NotImplementedError(self.add_fallback_repository)
 
311
 
 
312
    def _check_fallback_repository(self, repository):
 
313
        """Check that this repository can fallback to repository safely.
 
314
 
 
315
        Raise an error if not.
 
316
 
 
317
        :param repository: A repository to fallback to.
 
318
        """
 
319
        return InterRepository._assert_same_model(self, repository)
 
320
 
 
321
    def all_revision_ids(self):
 
322
        """Returns a list of all the revision ids in the repository.
 
323
 
 
324
        This is conceptually deprecated because code should generally work on
 
325
        the graph reachable from a particular revision, and ignore any other
 
326
        revisions that might be present.  There is no direct replacement
 
327
        method.
 
328
        """
 
329
        if 'evil' in debug.debug_flags:
 
330
            mutter_callsite(2, "all_revision_ids is linear with history.")
 
331
        return self._all_revision_ids()
 
332
 
 
333
    def _all_revision_ids(self):
 
334
        """Returns a list of all the revision ids in the repository.
 
335
 
 
336
        These are in as much topological order as the underlying store can
 
337
        present.
 
338
        """
 
339
        raise NotImplementedError(self._all_revision_ids)
 
340
 
 
341
    def break_lock(self):
 
342
        """Break a lock if one is present from another instance.
 
343
 
 
344
        Uses the ui factory to ask for confirmation if the lock may be from
 
345
        an active process.
 
346
        """
 
347
        self.control_files.break_lock()
 
348
 
 
349
    @staticmethod
 
350
    def create(controldir):
 
351
        """Construct the current default format repository in controldir."""
 
352
        return RepositoryFormat.get_default_format().initialize(controldir)
 
353
 
 
354
    def __init__(self, _format, controldir, control_files):
 
355
        """instantiate a Repository.
 
356
 
 
357
        :param _format: The format of the repository on disk.
 
358
        :param controldir: The ControlDir of the repository.
 
359
        :param control_files: Control files to use for locking, etc.
 
360
        """
 
361
        # In the future we will have a single api for all stores for
 
362
        # getting file texts, inventories and revisions, then
 
363
        # this construct will accept instances of those things.
 
364
        super(Repository, self).__init__()
 
365
        self._format = _format
 
366
        # the following are part of the public API for Repository:
 
367
        self.bzrdir = controldir
 
368
        self.control_files = control_files
 
369
        # for tests
 
370
        self._write_group = None
 
371
        # Additional places to query for data.
 
372
        self._fallback_repositories = []
 
373
 
 
374
    @property
 
375
    def user_transport(self):
 
376
        return self.bzrdir.user_transport
 
377
 
 
378
    @property
 
379
    def control_transport(self):
 
380
        return self._transport
 
381
 
 
382
    def __repr__(self):
 
383
        if self._fallback_repositories:
 
384
            return '%s(%r, fallback_repositories=%r)' % (
 
385
                self.__class__.__name__,
 
386
                self.base,
 
387
                self._fallback_repositories)
 
388
        else:
 
389
            return '%s(%r)' % (self.__class__.__name__,
 
390
                               self.base)
 
391
 
 
392
    def _has_same_fallbacks(self, other_repo):
 
393
        """Returns true if the repositories have the same fallbacks."""
 
394
        my_fb = self._fallback_repositories
 
395
        other_fb = other_repo._fallback_repositories
 
396
        if len(my_fb) != len(other_fb):
 
397
            return False
 
398
        for f, g in zip(my_fb, other_fb):
 
399
            if not f.has_same_location(g):
 
400
                return False
 
401
        return True
 
402
 
 
403
    def has_same_location(self, other):
 
404
        """Returns a boolean indicating if this repository is at the same
 
405
        location as another repository.
 
406
 
 
407
        This might return False even when two repository objects are accessing
 
408
        the same physical repository via different URLs.
 
409
        """
 
410
        if self.__class__ is not other.__class__:
 
411
            return False
 
412
        return (self.control_url == other.control_url)
 
413
 
 
414
    def is_in_write_group(self):
 
415
        """Return True if there is an open write group.
 
416
 
 
417
        :seealso: start_write_group.
 
418
        """
 
419
        return self._write_group is not None
 
420
 
 
421
    def is_locked(self):
 
422
        return self.control_files.is_locked()
 
423
 
 
424
    def is_write_locked(self):
 
425
        """Return True if this object is write locked."""
 
426
        return self.is_locked() and self.control_files._lock_mode == 'w'
 
427
 
 
428
    def lock_write(self, token=None):
 
429
        """Lock this repository for writing.
 
430
 
 
431
        This causes caching within the repository obejct to start accumlating
 
432
        data during reads, and allows a 'write_group' to be obtained. Write
 
433
        groups must be used for actual data insertion.
 
434
 
 
435
        A token should be passed in if you know that you have locked the object
 
436
        some other way, and need to synchronise this object's state with that
 
437
        fact.
 
438
 
 
439
        XXX: this docstring is duplicated in many places, e.g. lockable_files.py
 
440
 
 
441
        :param token: if this is already locked, then lock_write will fail
 
442
            unless the token matches the existing lock.
 
443
        :returns: a token if this instance supports tokens, otherwise None.
 
444
        :raises TokenLockingNotSupported: when a token is given but this
 
445
            instance doesn't support using token locks.
 
446
        :raises MismatchedToken: if the specified token doesn't match the token
 
447
            of the existing lock.
 
448
        :seealso: start_write_group.
 
449
        :return: A RepositoryWriteLockResult.
 
450
        """
 
451
        locked = self.is_locked()
 
452
        token = self.control_files.lock_write(token=token)
 
453
        if not locked:
 
454
            self._warn_if_deprecated()
 
455
            self._note_lock('w')
 
456
            for repo in self._fallback_repositories:
 
457
                # Writes don't affect fallback repos
 
458
                repo.lock_read()
 
459
            self._refresh_data()
 
460
        return RepositoryWriteLockResult(self.unlock, token)
 
461
 
 
462
    def lock_read(self):
 
463
        """Lock the repository for read operations.
 
464
 
 
465
        :return: An object with an unlock method which will release the lock
 
466
            obtained.
 
467
        """
 
468
        locked = self.is_locked()
 
469
        self.control_files.lock_read()
 
470
        if not locked:
 
471
            self._warn_if_deprecated()
 
472
            self._note_lock('r')
 
473
            for repo in self._fallback_repositories:
 
474
                repo.lock_read()
 
475
            self._refresh_data()
 
476
        return LogicalLockResult(self.unlock)
 
477
 
 
478
    def get_physical_lock_status(self):
 
479
        return self.control_files.get_physical_lock_status()
 
480
 
 
481
    def leave_lock_in_place(self):
 
482
        """Tell this repository not to release the physical lock when this
 
483
        object is unlocked.
 
484
 
 
485
        If lock_write doesn't return a token, then this method is not supported.
 
486
        """
 
487
        self.control_files.leave_in_place()
 
488
 
 
489
    def dont_leave_lock_in_place(self):
 
490
        """Tell this repository to release the physical lock when this
 
491
        object is unlocked, even if it didn't originally acquire it.
 
492
 
 
493
        If lock_write doesn't return a token, then this method is not supported.
 
494
        """
 
495
        self.control_files.dont_leave_in_place()
 
496
 
 
497
    @needs_read_lock
 
498
    def gather_stats(self, revid=None, committers=None):
 
499
        """Gather statistics from a revision id.
 
500
 
 
501
        :param revid: The revision id to gather statistics from, if None, then
 
502
            no revision specific statistics are gathered.
 
503
        :param committers: Optional parameter controlling whether to grab
 
504
            a count of committers from the revision specific statistics.
 
505
        :return: A dictionary of statistics. Currently this contains:
 
506
            committers: The number of committers if requested.
 
507
            firstrev: A tuple with timestamp, timezone for the penultimate left
 
508
                most ancestor of revid, if revid is not the NULL_REVISION.
 
509
            latestrev: A tuple with timestamp, timezone for revid, if revid is
 
510
                not the NULL_REVISION.
 
511
            revisions: The total revision count in the repository.
 
512
            size: An estimate disk size of the repository in bytes.
 
513
        """
 
514
        result = {}
 
515
        if revid and committers:
 
516
            result['committers'] = 0
 
517
        if revid and revid != _mod_revision.NULL_REVISION:
 
518
            graph = self.get_graph()
 
519
            if committers:
 
520
                all_committers = set()
 
521
            revisions = [r for (r, p) in graph.iter_ancestry([revid])
 
522
                        if r != _mod_revision.NULL_REVISION]
 
523
            last_revision = None
 
524
            if not committers:
 
525
                # ignore the revisions in the middle - just grab first and last
 
526
                revisions = revisions[0], revisions[-1]
 
527
            for revision in self.get_revisions(revisions):
 
528
                if not last_revision:
 
529
                    last_revision = revision
 
530
                if committers:
 
531
                    all_committers.add(revision.committer)
 
532
            first_revision = revision
 
533
            if committers:
 
534
                result['committers'] = len(all_committers)
 
535
            result['firstrev'] = (first_revision.timestamp,
 
536
                first_revision.timezone)
 
537
            result['latestrev'] = (last_revision.timestamp,
 
538
                last_revision.timezone)
 
539
        return result
 
540
 
 
541
    def find_branches(self, using=False):
 
542
        """Find branches underneath this repository.
 
543
 
 
544
        This will include branches inside other branches.
 
545
 
 
546
        :param using: If True, list only branches using this repository.
 
547
        """
 
548
        if using and not self.is_shared():
 
549
            return self.bzrdir.list_branches()
 
550
        class Evaluator(object):
 
551
 
 
552
            def __init__(self):
 
553
                self.first_call = True
 
554
 
 
555
            def __call__(self, controldir):
 
556
                # On the first call, the parameter is always the controldir
 
557
                # containing the current repo.
 
558
                if not self.first_call:
 
559
                    try:
 
560
                        repository = controldir.open_repository()
 
561
                    except errors.NoRepositoryPresent:
 
562
                        pass
 
563
                    else:
 
564
                        return False, ([], repository)
 
565
                self.first_call = False
 
566
                value = (controldir.list_branches(), None)
 
567
                return True, value
 
568
 
 
569
        ret = []
 
570
        for branches, repository in controldir.ControlDir.find_bzrdirs(
 
571
                self.user_transport, evaluate=Evaluator()):
 
572
            if branches is not None:
 
573
                ret.extend(branches)
 
574
            if not using and repository is not None:
 
575
                ret.extend(repository.find_branches())
 
576
        return ret
 
577
 
 
578
    @needs_read_lock
 
579
    def search_missing_revision_ids(self, other,
 
580
            find_ghosts=True, revision_ids=None, if_present_ids=None,
 
581
            limit=None):
 
582
        """Return the revision ids that other has that this does not.
 
583
 
 
584
        These are returned in topological order.
 
585
 
 
586
        revision_ids: only return revision ids included by revision_id.
 
587
        """
 
588
        return InterRepository.get(other, self).search_missing_revision_ids(
 
589
            find_ghosts=find_ghosts, revision_ids=revision_ids,
 
590
            if_present_ids=if_present_ids, limit=limit)
 
591
 
 
592
    @staticmethod
 
593
    def open(base):
 
594
        """Open the repository rooted at base.
 
595
 
 
596
        For instance, if the repository is at URL/.bzr/repository,
 
597
        Repository.open(URL) -> a Repository instance.
 
598
        """
 
599
        control = controldir.ControlDir.open(base)
 
600
        return control.open_repository()
 
601
 
 
602
    def copy_content_into(self, destination, revision_id=None):
 
603
        """Make a complete copy of the content in self into destination.
 
604
 
 
605
        This is a destructive operation! Do not use it on existing
 
606
        repositories.
 
607
        """
 
608
        return InterRepository.get(self, destination).copy_content(revision_id)
 
609
 
 
610
    def commit_write_group(self):
 
611
        """Commit the contents accrued within the current write group.
 
612
 
 
613
        :seealso: start_write_group.
 
614
        
 
615
        :return: it may return an opaque hint that can be passed to 'pack'.
 
616
        """
 
617
        if self._write_group is not self.get_transaction():
 
618
            # has an unlock or relock occured ?
 
619
            raise errors.BzrError('mismatched lock context %r and '
 
620
                'write group %r.' %
 
621
                (self.get_transaction(), self._write_group))
 
622
        result = self._commit_write_group()
 
623
        self._write_group = None
 
624
        return result
 
625
 
 
626
    def _commit_write_group(self):
 
627
        """Template method for per-repository write group cleanup.
 
628
 
 
629
        This is called before the write group is considered to be
 
630
        finished and should ensure that all data handed to the repository
 
631
        for writing during the write group is safely committed (to the
 
632
        extent possible considering file system caching etc).
 
633
        """
 
634
 
 
635
    def suspend_write_group(self):
 
636
        """Suspend a write group.
 
637
 
 
638
        :raise UnsuspendableWriteGroup: If the write group can not be
 
639
            suspended.
 
640
        :return: List of tokens
 
641
        """
 
642
        raise errors.UnsuspendableWriteGroup(self)
 
643
 
 
644
    def refresh_data(self):
 
645
        """Re-read any data needed to synchronise with disk.
 
646
 
 
647
        This method is intended to be called after another repository instance
 
648
        (such as one used by a smart server) has inserted data into the
 
649
        repository. On all repositories this will work outside of write groups.
 
650
        Some repository formats (pack and newer for breezy native formats)
 
651
        support refresh_data inside write groups. If called inside a write
 
652
        group on a repository that does not support refreshing in a write group
 
653
        IsInWriteGroupError will be raised.
 
654
        """
 
655
        self._refresh_data()
 
656
 
 
657
    def resume_write_group(self, tokens):
 
658
        if not self.is_write_locked():
 
659
            raise errors.NotWriteLocked(self)
 
660
        if self._write_group:
 
661
            raise errors.BzrError('already in a write group')
 
662
        self._resume_write_group(tokens)
 
663
        # so we can detect unlock/relock - the write group is now entered.
 
664
        self._write_group = self.get_transaction()
 
665
 
 
666
    def _resume_write_group(self, tokens):
 
667
        raise errors.UnsuspendableWriteGroup(self)
 
668
 
 
669
    def fetch(self, source, revision_id=None, find_ghosts=False):
 
670
        """Fetch the content required to construct revision_id from source.
 
671
 
 
672
        If revision_id is None, then all content is copied.
 
673
 
 
674
        fetch() may not be used when the repository is in a write group -
 
675
        either finish the current write group before using fetch, or use
 
676
        fetch before starting the write group.
 
677
 
 
678
        :param find_ghosts: Find and copy revisions in the source that are
 
679
            ghosts in the target (and not reachable directly by walking out to
 
680
            the first-present revision in target from revision_id).
 
681
        :param revision_id: If specified, all the content needed for this
 
682
            revision ID will be copied to the target.  Fetch will determine for
 
683
            itself which content needs to be copied.
 
684
        """
 
685
        if self.is_in_write_group():
 
686
            raise errors.InternalBzrError(
 
687
                "May not fetch while in a write group.")
 
688
        # fast path same-url fetch operations
 
689
        # TODO: lift out to somewhere common with RemoteRepository
 
690
        # <https://bugs.launchpad.net/bzr/+bug/401646>
 
691
        if (self.has_same_location(source)
 
692
            and self._has_same_fallbacks(source)):
 
693
            # check that last_revision is in 'from' and then return a
 
694
            # no-operation.
 
695
            if (revision_id is not None and
 
696
                not _mod_revision.is_null(revision_id)):
 
697
                self.get_revision(revision_id)
 
698
            return 0, []
 
699
        inter = InterRepository.get(source, self)
 
700
        return inter.fetch(revision_id=revision_id, find_ghosts=find_ghosts)
 
701
 
 
702
    def create_bundle(self, target, base, fileobj, format=None):
 
703
        return serializer.write_bundle(self, target, base, fileobj, format)
 
704
 
 
705
    def get_commit_builder(self, branch, parents, config_stack, timestamp=None,
 
706
                           timezone=None, committer=None, revprops=None,
 
707
                           revision_id=None, lossy=False):
 
708
        """Obtain a CommitBuilder for this repository.
 
709
 
 
710
        :param branch: Branch to commit to.
 
711
        :param parents: Revision ids of the parents of the new revision.
 
712
        :param config_stack: Configuration stack to use.
 
713
        :param timestamp: Optional timestamp recorded for commit.
 
714
        :param timezone: Optional timezone for timestamp.
 
715
        :param committer: Optional committer to set for commit.
 
716
        :param revprops: Optional dictionary of revision properties.
 
717
        :param revision_id: Optional revision id.
 
718
        :param lossy: Whether to discard data that can not be natively
 
719
            represented, when pushing to a foreign VCS
 
720
        """
 
721
        raise NotImplementedError(self.get_commit_builder)
 
722
 
 
723
    @only_raises(errors.LockNotHeld, errors.LockBroken)
 
724
    def unlock(self):
 
725
        if (self.control_files._lock_count == 1 and
 
726
            self.control_files._lock_mode == 'w'):
 
727
            if self._write_group is not None:
 
728
                self.abort_write_group()
 
729
                self.control_files.unlock()
 
730
                raise errors.BzrError(
 
731
                    'Must end write groups before releasing write locks.')
 
732
        self.control_files.unlock()
 
733
        if self.control_files._lock_count == 0:
 
734
            for repo in self._fallback_repositories:
 
735
                repo.unlock()
 
736
 
 
737
    @needs_read_lock
 
738
    def clone(self, controldir, revision_id=None):
 
739
        """Clone this repository into controldir using the current format.
 
740
 
 
741
        Currently no check is made that the format of this repository and
 
742
        the bzrdir format are compatible. FIXME RBC 20060201.
 
743
 
 
744
        :return: The newly created destination repository.
 
745
        """
 
746
        # TODO: deprecate after 0.16; cloning this with all its settings is
 
747
        # probably not very useful -- mbp 20070423
 
748
        dest_repo = self._create_sprouting_repo(
 
749
            controldir, shared=self.is_shared())
 
750
        self.copy_content_into(dest_repo, revision_id)
 
751
        return dest_repo
 
752
 
 
753
    def start_write_group(self):
 
754
        """Start a write group in the repository.
 
755
 
 
756
        Write groups are used by repositories which do not have a 1:1 mapping
 
757
        between file ids and backend store to manage the insertion of data from
 
758
        both fetch and commit operations.
 
759
 
 
760
        A write lock is required around the start_write_group/commit_write_group
 
761
        for the support of lock-requiring repository formats.
 
762
 
 
763
        One can only insert data into a repository inside a write group.
 
764
 
 
765
        :return: None.
 
766
        """
 
767
        if not self.is_write_locked():
 
768
            raise errors.NotWriteLocked(self)
 
769
        if self._write_group:
 
770
            raise errors.BzrError('already in a write group')
 
771
        self._start_write_group()
 
772
        # so we can detect unlock/relock - the write group is now entered.
 
773
        self._write_group = self.get_transaction()
 
774
 
 
775
    def _start_write_group(self):
 
776
        """Template method for per-repository write group startup.
 
777
 
 
778
        This is called before the write group is considered to be
 
779
        entered.
 
780
        """
 
781
 
 
782
    @needs_read_lock
 
783
    def sprout(self, to_bzrdir, revision_id=None):
 
784
        """Create a descendent repository for new development.
 
785
 
 
786
        Unlike clone, this does not copy the settings of the repository.
 
787
        """
 
788
        dest_repo = self._create_sprouting_repo(to_bzrdir, shared=False)
 
789
        dest_repo.fetch(self, revision_id=revision_id)
 
790
        return dest_repo
 
791
 
 
792
    def _create_sprouting_repo(self, a_bzrdir, shared):
 
793
        if not isinstance(a_bzrdir._format, self.bzrdir._format.__class__):
 
794
            # use target default format.
 
795
            dest_repo = a_bzrdir.create_repository()
 
796
        else:
 
797
            # Most control formats need the repository to be specifically
 
798
            # created, but on some old all-in-one formats it's not needed
 
799
            try:
 
800
                dest_repo = self._format.initialize(a_bzrdir, shared=shared)
 
801
            except errors.UninitializableFormat:
 
802
                dest_repo = a_bzrdir.open_repository()
 
803
        return dest_repo
 
804
 
 
805
    @needs_read_lock
 
806
    def has_revision(self, revision_id):
 
807
        """True if this repository has a copy of the revision."""
 
808
        return revision_id in self.has_revisions((revision_id,))
 
809
 
 
810
    @needs_read_lock
 
811
    def has_revisions(self, revision_ids):
 
812
        """Probe to find out the presence of multiple revisions.
 
813
 
 
814
        :param revision_ids: An iterable of revision_ids.
 
815
        :return: A set of the revision_ids that were present.
 
816
        """
 
817
        raise NotImplementedError(self.has_revisions)
 
818
 
 
819
    @needs_read_lock
 
820
    def get_revision(self, revision_id):
 
821
        """Return the Revision object for a named revision."""
 
822
        return self.get_revisions([revision_id])[0]
 
823
 
 
824
    def get_revision_reconcile(self, revision_id):
 
825
        """'reconcile' helper routine that allows access to a revision always.
 
826
 
 
827
        This variant of get_revision does not cross check the weave graph
 
828
        against the revision one as get_revision does: but it should only
 
829
        be used by reconcile, or reconcile-alike commands that are correcting
 
830
        or testing the revision graph.
 
831
        """
 
832
        raise NotImplementedError(self.get_revision_reconcile)
 
833
 
 
834
    def get_revisions(self, revision_ids):
 
835
        """Get many revisions at once.
 
836
        
 
837
        Repositories that need to check data on every revision read should 
 
838
        subclass this method.
 
839
        """
 
840
        raise NotImplementedError(self.get_revisions)
 
841
 
 
842
    def get_deltas_for_revisions(self, revisions, specific_fileids=None):
 
843
        """Produce a generator of revision deltas.
 
844
 
 
845
        Note that the input is a sequence of REVISIONS, not revision_ids.
 
846
        Trees will be held in memory until the generator exits.
 
847
        Each delta is relative to the revision's lefthand predecessor.
 
848
 
 
849
        :param specific_fileids: if not None, the result is filtered
 
850
          so that only those file-ids, their parents and their
 
851
          children are included.
 
852
        """
 
853
        # Get the revision-ids of interest
 
854
        required_trees = set()
 
855
        for revision in revisions:
 
856
            required_trees.add(revision.revision_id)
 
857
            required_trees.update(revision.parent_ids[:1])
 
858
 
 
859
        # Get the matching filtered trees. Note that it's more
 
860
        # efficient to pass filtered trees to changes_from() rather
 
861
        # than doing the filtering afterwards. changes_from() could
 
862
        # arguably do the filtering itself but it's path-based, not
 
863
        # file-id based, so filtering before or afterwards is
 
864
        # currently easier.
 
865
        if specific_fileids is None:
 
866
            trees = dict((t.get_revision_id(), t) for
 
867
                t in self.revision_trees(required_trees))
 
868
        else:
 
869
            trees = dict((t.get_revision_id(), t) for
 
870
                t in self._filtered_revision_trees(required_trees,
 
871
                specific_fileids))
 
872
 
 
873
        # Calculate the deltas
 
874
        for revision in revisions:
 
875
            if not revision.parent_ids:
 
876
                old_tree = self.revision_tree(_mod_revision.NULL_REVISION)
 
877
            else:
 
878
                old_tree = trees[revision.parent_ids[0]]
 
879
            yield trees[revision.revision_id].changes_from(old_tree)
 
880
 
 
881
    @needs_read_lock
 
882
    def get_revision_delta(self, revision_id, specific_fileids=None):
 
883
        """Return the delta for one revision.
 
884
 
 
885
        The delta is relative to the left-hand predecessor of the
 
886
        revision.
 
887
 
 
888
        :param specific_fileids: if not None, the result is filtered
 
889
          so that only those file-ids, their parents and their
 
890
          children are included.
 
891
        """
 
892
        r = self.get_revision(revision_id)
 
893
        return list(self.get_deltas_for_revisions([r],
 
894
            specific_fileids=specific_fileids))[0]
 
895
 
 
896
    @needs_write_lock
 
897
    def store_revision_signature(self, gpg_strategy, plaintext, revision_id):
 
898
        signature = gpg_strategy.sign(plaintext)
 
899
        self.add_signature_text(revision_id, signature)
 
900
 
 
901
    def add_signature_text(self, revision_id, signature):
 
902
        """Store a signature text for a revision.
 
903
 
 
904
        :param revision_id: Revision id of the revision
 
905
        :param signature: Signature text.
 
906
        """
 
907
        raise NotImplementedError(self.add_signature_text)
 
908
 
 
909
    def iter_files_bytes(self, desired_files):
 
910
        """Iterate through file versions.
 
911
 
 
912
        Files will not necessarily be returned in the order they occur in
 
913
        desired_files.  No specific order is guaranteed.
 
914
 
 
915
        Yields pairs of identifier, bytes_iterator.  identifier is an opaque
 
916
        value supplied by the caller as part of desired_files.  It should
 
917
        uniquely identify the file version in the caller's context.  (Examples:
 
918
        an index number or a TreeTransform trans_id.)
 
919
 
 
920
        :param desired_files: a list of (file_id, revision_id, identifier)
 
921
            triples
 
922
        """
 
923
        raise NotImplementedError(self.iter_files_bytes)
 
924
 
 
925
    def get_rev_id_for_revno(self, revno, known_pair):
 
926
        """Return the revision id of a revno, given a later (revno, revid)
 
927
        pair in the same history.
 
928
 
 
929
        :return: if found (True, revid).  If the available history ran out
 
930
            before reaching the revno, then this returns
 
931
            (False, (closest_revno, closest_revid)).
 
932
        """
 
933
        known_revno, known_revid = known_pair
 
934
        partial_history = [known_revid]
 
935
        distance_from_known = known_revno - revno
 
936
        if distance_from_known < 0:
 
937
            raise ValueError(
 
938
                'requested revno (%d) is later than given known revno (%d)'
 
939
                % (revno, known_revno))
 
940
        try:
 
941
            _iter_for_revno(
 
942
                self, partial_history, stop_index=distance_from_known)
 
943
        except errors.RevisionNotPresent as err:
 
944
            if err.revision_id == known_revid:
 
945
                # The start revision (known_revid) wasn't found.
 
946
                raise
 
947
            # This is a stacked repository with no fallbacks, or a there's a
 
948
            # left-hand ghost.  Either way, even though the revision named in
 
949
            # the error isn't in this repo, we know it's the next step in this
 
950
            # left-hand history.
 
951
            partial_history.append(err.revision_id)
 
952
        if len(partial_history) <= distance_from_known:
 
953
            # Didn't find enough history to get a revid for the revno.
 
954
            earliest_revno = known_revno - len(partial_history) + 1
 
955
            return (False, (earliest_revno, partial_history[-1]))
 
956
        if len(partial_history) - 1 > distance_from_known:
 
957
            raise AssertionError('_iter_for_revno returned too much history')
 
958
        return (True, partial_history[-1])
 
959
 
 
960
    def is_shared(self):
 
961
        """Return True if this repository is flagged as a shared repository."""
 
962
        raise NotImplementedError(self.is_shared)
 
963
 
 
964
    @needs_write_lock
 
965
    def reconcile(self, other=None, thorough=False):
 
966
        """Reconcile this repository."""
 
967
        from .reconcile import RepoReconciler
 
968
        reconciler = RepoReconciler(self, thorough=thorough)
 
969
        reconciler.reconcile()
 
970
        return reconciler
 
971
 
 
972
    def _refresh_data(self):
 
973
        """Helper called from lock_* to ensure coherency with disk.
 
974
 
 
975
        The default implementation does nothing; it is however possible
 
976
        for repositories to maintain loaded indices across multiple locks
 
977
        by checking inside their implementation of this method to see
 
978
        whether their indices are still valid. This depends of course on
 
979
        the disk format being validatable in this manner. This method is
 
980
        also called by the refresh_data() public interface to cause a refresh
 
981
        to occur while in a write lock so that data inserted by a smart server
 
982
        push operation is visible on the client's instance of the physical
 
983
        repository.
 
984
        """
 
985
 
 
986
    @needs_read_lock
 
987
    def revision_tree(self, revision_id):
 
988
        """Return Tree for a revision on this branch.
 
989
 
 
990
        `revision_id` may be NULL_REVISION for the empty tree revision.
 
991
        """
 
992
        raise NotImplementedError(self.revision_tree)
 
993
 
 
994
    def revision_trees(self, revision_ids):
 
995
        """Return Trees for revisions in this repository.
 
996
 
 
997
        :param revision_ids: a sequence of revision-ids;
 
998
          a revision-id may not be None or 'null:'
 
999
        """
 
1000
        raise NotImplementedError(self.revision_trees)
 
1001
 
 
1002
    def pack(self, hint=None, clean_obsolete_packs=False):
 
1003
        """Compress the data within the repository.
 
1004
 
 
1005
        This operation only makes sense for some repository types. For other
 
1006
        types it should be a no-op that just returns.
 
1007
 
 
1008
        This stub method does not require a lock, but subclasses should use
 
1009
        @needs_write_lock as this is a long running call it's reasonable to
 
1010
        implicitly lock for the user.
 
1011
 
 
1012
        :param hint: If not supplied, the whole repository is packed.
 
1013
            If supplied, the repository may use the hint parameter as a
 
1014
            hint for the parts of the repository to pack. A hint can be
 
1015
            obtained from the result of commit_write_group(). Out of
 
1016
            date hints are simply ignored, because concurrent operations
 
1017
            can obsolete them rapidly.
 
1018
 
 
1019
        :param clean_obsolete_packs: Clean obsolete packs immediately after
 
1020
            the pack operation.
 
1021
        """
 
1022
 
 
1023
    def get_transaction(self):
 
1024
        return self.control_files.get_transaction()
 
1025
 
 
1026
    def get_parent_map(self, revision_ids):
 
1027
        """See graph.StackedParentsProvider.get_parent_map"""
 
1028
        raise NotImplementedError(self.get_parent_map)
 
1029
 
 
1030
    def _get_parent_map_no_fallbacks(self, revision_ids):
 
1031
        """Same as Repository.get_parent_map except doesn't query fallbacks."""
 
1032
        # revisions index works in keys; this just works in revisions
 
1033
        # therefore wrap and unwrap
 
1034
        query_keys = []
 
1035
        result = {}
 
1036
        for revision_id in revision_ids:
 
1037
            if revision_id == _mod_revision.NULL_REVISION:
 
1038
                result[revision_id] = ()
 
1039
            elif revision_id is None:
 
1040
                raise ValueError('get_parent_map(None) is not valid')
 
1041
            else:
 
1042
                query_keys.append((revision_id ,))
 
1043
        vf = self.revisions.without_fallbacks()
 
1044
        for (revision_id,), parent_keys in viewitems(
 
1045
                vf.get_parent_map(query_keys)):
 
1046
            if parent_keys:
 
1047
                result[revision_id] = tuple([parent_revid
 
1048
                    for (parent_revid,) in parent_keys])
 
1049
            else:
 
1050
                result[revision_id] = (_mod_revision.NULL_REVISION,)
 
1051
        return result
 
1052
 
 
1053
    def _make_parents_provider(self):
 
1054
        if not self._format.supports_external_lookups:
 
1055
            return self
 
1056
        return graph.StackedParentsProvider(_LazyListJoin(
 
1057
            [self._make_parents_provider_unstacked()],
 
1058
            self._fallback_repositories))
 
1059
 
 
1060
    def _make_parents_provider_unstacked(self):
 
1061
        return graph.CallableToParentsProviderAdapter(
 
1062
            self._get_parent_map_no_fallbacks)
 
1063
 
 
1064
    @needs_read_lock
 
1065
    def get_known_graph_ancestry(self, revision_ids):
 
1066
        """Return the known graph for a set of revision ids and their ancestors.
 
1067
        """
 
1068
        raise NotImplementedError(self.get_known_graph_ancestry)
 
1069
 
 
1070
    def get_file_graph(self):
 
1071
        """Return the graph walker for files."""
 
1072
        raise NotImplementedError(self.get_file_graph)
 
1073
 
 
1074
    def get_graph(self, other_repository=None):
 
1075
        """Return the graph walker for this repository format"""
 
1076
        parents_provider = self._make_parents_provider()
 
1077
        if (other_repository is not None and
 
1078
            not self.has_same_location(other_repository)):
 
1079
            parents_provider = graph.StackedParentsProvider(
 
1080
                [parents_provider, other_repository._make_parents_provider()])
 
1081
        return graph.Graph(parents_provider)
 
1082
 
 
1083
    @needs_write_lock
 
1084
    def set_make_working_trees(self, new_value):
 
1085
        """Set the policy flag for making working trees when creating branches.
 
1086
 
 
1087
        This only applies to branches that use this repository.
 
1088
 
 
1089
        The default is 'True'.
 
1090
        :param new_value: True to restore the default, False to disable making
 
1091
                          working trees.
 
1092
        """
 
1093
        raise NotImplementedError(self.set_make_working_trees)
 
1094
 
 
1095
    def make_working_trees(self):
 
1096
        """Returns the policy for making working trees on new branches."""
 
1097
        raise NotImplementedError(self.make_working_trees)
 
1098
 
 
1099
    @needs_write_lock
 
1100
    def sign_revision(self, revision_id, gpg_strategy):
 
1101
        testament = _mod_testament.Testament.from_revision(self, revision_id)
 
1102
        plaintext = testament.as_short_text()
 
1103
        self.store_revision_signature(gpg_strategy, plaintext, revision_id)
 
1104
 
 
1105
    @needs_read_lock
 
1106
    def verify_revision_signature(self, revision_id, gpg_strategy):
 
1107
        """Verify the signature on a revision.
 
1108
 
 
1109
        :param revision_id: the revision to verify
 
1110
        :gpg_strategy: the GPGStrategy object to used
 
1111
 
 
1112
        :return: gpg.SIGNATURE_VALID or a failed SIGNATURE_ value
 
1113
        """
 
1114
        if not self.has_signature_for_revision_id(revision_id):
 
1115
            return gpg.SIGNATURE_NOT_SIGNED, None
 
1116
        signature = self.get_signature_text(revision_id)
 
1117
 
 
1118
        testament = _mod_testament.Testament.from_revision(self, revision_id)
 
1119
        plaintext = testament.as_short_text()
 
1120
 
 
1121
        return gpg_strategy.verify(signature, plaintext)
 
1122
 
 
1123
    @needs_read_lock
 
1124
    def verify_revision_signatures(self, revision_ids, gpg_strategy):
 
1125
        """Verify revision signatures for a number of revisions.
 
1126
 
 
1127
        :param revision_id: the revision to verify
 
1128
        :gpg_strategy: the GPGStrategy object to used
 
1129
        :return: Iterator over tuples with revision id, result and keys
 
1130
        """
 
1131
        for revid in revision_ids:
 
1132
            (result, key) = self.verify_revision_signature(revid, gpg_strategy)
 
1133
            yield revid, result, key
 
1134
 
 
1135
    def has_signature_for_revision_id(self, revision_id):
 
1136
        """Query for a revision signature for revision_id in the repository."""
 
1137
        raise NotImplementedError(self.has_signature_for_revision_id)
 
1138
 
 
1139
    def get_signature_text(self, revision_id):
 
1140
        """Return the text for a signature."""
 
1141
        raise NotImplementedError(self.get_signature_text)
 
1142
 
 
1143
    def check(self, revision_ids=None, callback_refs=None, check_repo=True):
 
1144
        """Check consistency of all history of given revision_ids.
 
1145
 
 
1146
        Different repository implementations should override _check().
 
1147
 
 
1148
        :param revision_ids: A non-empty list of revision_ids whose ancestry
 
1149
             will be checked.  Typically the last revision_id of a branch.
 
1150
        :param callback_refs: A dict of check-refs to resolve and callback
 
1151
            the check/_check method on the items listed as wanting the ref.
 
1152
            see breezy.check.
 
1153
        :param check_repo: If False do not check the repository contents, just 
 
1154
            calculate the data callback_refs requires and call them back.
 
1155
        """
 
1156
        return self._check(revision_ids=revision_ids, callback_refs=callback_refs,
 
1157
            check_repo=check_repo)
 
1158
 
 
1159
    def _check(self, revision_ids=None, callback_refs=None, check_repo=True):
 
1160
        raise NotImplementedError(self.check)
 
1161
 
 
1162
    def _warn_if_deprecated(self, branch=None):
 
1163
        if not self._format.is_deprecated():
 
1164
            return
 
1165
        global _deprecation_warning_done
 
1166
        if _deprecation_warning_done:
 
1167
            return
 
1168
        try:
 
1169
            if branch is None:
 
1170
                conf = config.GlobalStack()
 
1171
            else:
 
1172
                conf = branch.get_config_stack()
 
1173
            if 'format_deprecation' in conf.get('suppress_warnings'):
 
1174
                return
 
1175
            warning("Format %s for %s is deprecated -"
 
1176
                    " please use 'brz upgrade' to get better performance"
 
1177
                    % (self._format, self.bzrdir.transport.base))
 
1178
        finally:
 
1179
            _deprecation_warning_done = True
 
1180
 
 
1181
    def supports_rich_root(self):
 
1182
        return self._format.rich_root_data
 
1183
 
 
1184
    def _check_ascii_revisionid(self, revision_id, method):
 
1185
        """Private helper for ascii-only repositories."""
 
1186
        # weave repositories refuse to store revisionids that are non-ascii.
 
1187
        if revision_id is not None:
 
1188
            # weaves require ascii revision ids.
 
1189
            if isinstance(revision_id, unicode):
 
1190
                try:
 
1191
                    revision_id.encode('ascii')
 
1192
                except UnicodeEncodeError:
 
1193
                    raise errors.NonAsciiRevisionId(method, self)
 
1194
            else:
 
1195
                try:
 
1196
                    revision_id.decode('ascii')
 
1197
                except UnicodeDecodeError:
 
1198
                    raise errors.NonAsciiRevisionId(method, self)
 
1199
 
 
1200
 
 
1201
class RepositoryFormatRegistry(controldir.ControlComponentFormatRegistry):
 
1202
    """Repository format registry."""
 
1203
 
 
1204
    def get_default(self):
 
1205
        """Return the current default format."""
 
1206
        return controldir.format_registry.make_bzrdir('default').repository_format
 
1207
 
 
1208
 
 
1209
network_format_registry = registry.FormatRegistry()
 
1210
"""Registry of formats indexed by their network name.
 
1211
 
 
1212
The network name for a repository format is an identifier that can be used when
 
1213
referring to formats with smart server operations. See
 
1214
RepositoryFormat.network_name() for more detail.
 
1215
"""
 
1216
 
 
1217
 
 
1218
format_registry = RepositoryFormatRegistry(network_format_registry)
 
1219
"""Registry of formats, indexed by their BzrDirMetaFormat format string.
 
1220
 
 
1221
This can contain either format instances themselves, or classes/factories that
 
1222
can be called to obtain one.
 
1223
"""
 
1224
 
 
1225
 
 
1226
#####################################################################
 
1227
# Repository Formats
 
1228
 
 
1229
class RepositoryFormat(controldir.ControlComponentFormat):
 
1230
    """A repository format.
 
1231
 
 
1232
    Formats provide four things:
 
1233
     * An initialization routine to construct repository data on disk.
 
1234
     * a optional format string which is used when the BzrDir supports
 
1235
       versioned children.
 
1236
     * an open routine which returns a Repository instance.
 
1237
     * A network name for referring to the format in smart server RPC
 
1238
       methods.
 
1239
 
 
1240
    There is one and only one Format subclass for each on-disk format. But
 
1241
    there can be one Repository subclass that is used for several different
 
1242
    formats. The _format attribute on a Repository instance can be used to
 
1243
    determine the disk format.
 
1244
 
 
1245
    Formats are placed in a registry by their format string for reference
 
1246
    during opening. These should be subclasses of RepositoryFormat for
 
1247
    consistency.
 
1248
 
 
1249
    Once a format is deprecated, just deprecate the initialize and open
 
1250
    methods on the format class. Do not deprecate the object, as the
 
1251
    object may be created even when a repository instance hasn't been
 
1252
    created.
 
1253
 
 
1254
    Common instance attributes:
 
1255
    _matchingbzrdir - the controldir format that the repository format was
 
1256
    originally written to work with. This can be used if manually
 
1257
    constructing a bzrdir and repository, or more commonly for test suite
 
1258
    parameterization.
 
1259
    """
 
1260
 
 
1261
    # Set to True or False in derived classes. True indicates that the format
 
1262
    # supports ghosts gracefully.
 
1263
    supports_ghosts = None
 
1264
    # Can this repository be given external locations to lookup additional
 
1265
    # data. Set to True or False in derived classes.
 
1266
    supports_external_lookups = None
 
1267
    # Does this format support CHK bytestring lookups. Set to True or False in
 
1268
    # derived classes.
 
1269
    supports_chks = None
 
1270
    # Should fetch trigger a reconcile after the fetch? Only needed for
 
1271
    # some repository formats that can suffer internal inconsistencies.
 
1272
    _fetch_reconcile = False
 
1273
    # Does this format have < O(tree_size) delta generation. Used to hint what
 
1274
    # code path for commit, amongst other things.
 
1275
    fast_deltas = None
 
1276
    # Does doing a pack operation compress data? Useful for the pack UI command
 
1277
    # (so if there is one pack, the operation can still proceed because it may
 
1278
    # help), and for fetching when data won't have come from the same
 
1279
    # compressor.
 
1280
    pack_compresses = False
 
1281
    # Does the repository storage understand references to trees?
 
1282
    supports_tree_reference = None
 
1283
    # Is the format experimental ?
 
1284
    experimental = False
 
1285
    # Does this repository format escape funky characters, or does it create
 
1286
    # files with similar names as the versioned files in its contents on disk
 
1287
    # ?
 
1288
    supports_funky_characters = None
 
1289
    # Does this repository format support leaving locks?
 
1290
    supports_leaving_lock = None
 
1291
    # Does this format support the full VersionedFiles interface?
 
1292
    supports_full_versioned_files = None
 
1293
    # Does this format support signing revision signatures?
 
1294
    supports_revision_signatures = True
 
1295
    # Can the revision graph have incorrect parents?
 
1296
    revision_graph_can_have_wrong_parents = None
 
1297
    # Does this format support rich root data?
 
1298
    rich_root_data = None
 
1299
    # Does this format support explicitly versioned directories?
 
1300
    supports_versioned_directories = None
 
1301
    # Can other repositories be nested into one of this format?
 
1302
    supports_nesting_repositories = None
 
1303
    # Is it possible for revisions to be present without being referenced
 
1304
    # somewhere ?
 
1305
    supports_unreferenced_revisions = None
 
1306
 
 
1307
    def __repr__(self):
 
1308
        return "%s()" % self.__class__.__name__
 
1309
 
 
1310
    def __eq__(self, other):
 
1311
        # format objects are generally stateless
 
1312
        return isinstance(other, self.__class__)
 
1313
 
 
1314
    def __ne__(self, other):
 
1315
        return not self == other
 
1316
 
 
1317
    def get_format_description(self):
 
1318
        """Return the short description for this format."""
 
1319
        raise NotImplementedError(self.get_format_description)
 
1320
 
 
1321
    def initialize(self, controldir, shared=False):
 
1322
        """Initialize a repository of this format in controldir.
 
1323
 
 
1324
        :param controldir: The controldir to put the new repository in it.
 
1325
        :param shared: The repository should be initialized as a sharable one.
 
1326
        :returns: The new repository object.
 
1327
 
 
1328
        This may raise UninitializableFormat if shared repository are not
 
1329
        compatible the controldir.
 
1330
        """
 
1331
        raise NotImplementedError(self.initialize)
 
1332
 
 
1333
    def is_supported(self):
 
1334
        """Is this format supported?
 
1335
 
 
1336
        Supported formats must be initializable and openable.
 
1337
        Unsupported formats may not support initialization or committing or
 
1338
        some other features depending on the reason for not being supported.
 
1339
        """
 
1340
        return True
 
1341
 
 
1342
    def is_deprecated(self):
 
1343
        """Is this format deprecated?
 
1344
 
 
1345
        Deprecated formats may trigger a user-visible warning recommending
 
1346
        the user to upgrade. They are still fully supported.
 
1347
        """
 
1348
        return False
 
1349
 
 
1350
    def network_name(self):
 
1351
        """A simple byte string uniquely identifying this format for RPC calls.
 
1352
 
 
1353
        MetaDir repository formats use their disk format string to identify the
 
1354
        repository over the wire. All in one formats such as bzr < 0.8, and
 
1355
        foreign formats like svn/git and hg should use some marker which is
 
1356
        unique and immutable.
 
1357
        """
 
1358
        raise NotImplementedError(self.network_name)
 
1359
 
 
1360
    def check_conversion_target(self, target_format):
 
1361
        if self.rich_root_data and not target_format.rich_root_data:
 
1362
            raise errors.BadConversionTarget(
 
1363
                'Does not support rich root data.', target_format,
 
1364
                from_format=self)
 
1365
        if (self.supports_tree_reference and 
 
1366
            not getattr(target_format, 'supports_tree_reference', False)):
 
1367
            raise errors.BadConversionTarget(
 
1368
                'Does not support nested trees', target_format,
 
1369
                from_format=self)
 
1370
 
 
1371
    def open(self, controldir, _found=False):
 
1372
        """Return an instance of this format for a controldir.
 
1373
 
 
1374
        _found is a private parameter, do not use it.
 
1375
        """
 
1376
        raise NotImplementedError(self.open)
 
1377
 
 
1378
    def _run_post_repo_init_hooks(self, repository, controldir, shared):
 
1379
        from .controldir import ControlDir, RepoInitHookParams
 
1380
        hooks = ControlDir.hooks['post_repo_init']
 
1381
        if not hooks:
 
1382
            return
 
1383
        params = RepoInitHookParams(repository, self, controldir, shared)
 
1384
        for hook in hooks:
 
1385
            hook(params)
 
1386
 
 
1387
 
 
1388
# formats which have no format string are not discoverable or independently
 
1389
# creatable on disk, so are not registered in format_registry.  They're
 
1390
# all in breezy.repofmt.knitreponow.  When an instance of one of these is
 
1391
# needed, it's constructed directly by the ControlDir.  Non-native formats where
 
1392
# the repository is not separately opened are similar.
 
1393
 
 
1394
format_registry.register_lazy(
 
1395
    'Bazaar-NG Knit Repository Format 1',
 
1396
    'breezy.repofmt.knitrepo',
 
1397
    'RepositoryFormatKnit1',
 
1398
    )
 
1399
 
 
1400
format_registry.register_lazy(
 
1401
    'Bazaar Knit Repository Format 3 (bzr 0.15)\n',
 
1402
    'breezy.repofmt.knitrepo',
 
1403
    'RepositoryFormatKnit3',
 
1404
    )
 
1405
 
 
1406
format_registry.register_lazy(
 
1407
    'Bazaar Knit Repository Format 4 (bzr 1.0)\n',
 
1408
    'breezy.repofmt.knitrepo',
 
1409
    'RepositoryFormatKnit4',
 
1410
    )
 
1411
 
 
1412
# Pack-based formats. There is one format for pre-subtrees, and one for
 
1413
# post-subtrees to allow ease of testing.
 
1414
# NOTE: These are experimental in 0.92. Stable in 1.0 and above
 
1415
format_registry.register_lazy(
 
1416
    'Bazaar pack repository format 1 (needs bzr 0.92)\n',
 
1417
    'breezy.repofmt.knitpack_repo',
 
1418
    'RepositoryFormatKnitPack1',
 
1419
    )
 
1420
format_registry.register_lazy(
 
1421
    'Bazaar pack repository format 1 with subtree support (needs bzr 0.92)\n',
 
1422
    'breezy.repofmt.knitpack_repo',
 
1423
    'RepositoryFormatKnitPack3',
 
1424
    )
 
1425
format_registry.register_lazy(
 
1426
    'Bazaar pack repository format 1 with rich root (needs bzr 1.0)\n',
 
1427
    'breezy.repofmt.knitpack_repo',
 
1428
    'RepositoryFormatKnitPack4',
 
1429
    )
 
1430
format_registry.register_lazy(
 
1431
    'Bazaar RepositoryFormatKnitPack5 (bzr 1.6)\n',
 
1432
    'breezy.repofmt.knitpack_repo',
 
1433
    'RepositoryFormatKnitPack5',
 
1434
    )
 
1435
format_registry.register_lazy(
 
1436
    'Bazaar RepositoryFormatKnitPack5RichRoot (bzr 1.6.1)\n',
 
1437
    'breezy.repofmt.knitpack_repo',
 
1438
    'RepositoryFormatKnitPack5RichRoot',
 
1439
    )
 
1440
format_registry.register_lazy(
 
1441
    'Bazaar RepositoryFormatKnitPack5RichRoot (bzr 1.6)\n',
 
1442
    'breezy.repofmt.knitpack_repo',
 
1443
    'RepositoryFormatKnitPack5RichRootBroken',
 
1444
    )
 
1445
format_registry.register_lazy(
 
1446
    'Bazaar RepositoryFormatKnitPack6 (bzr 1.9)\n',
 
1447
    'breezy.repofmt.knitpack_repo',
 
1448
    'RepositoryFormatKnitPack6',
 
1449
    )
 
1450
format_registry.register_lazy(
 
1451
    'Bazaar RepositoryFormatKnitPack6RichRoot (bzr 1.9)\n',
 
1452
    'breezy.repofmt.knitpack_repo',
 
1453
    'RepositoryFormatKnitPack6RichRoot',
 
1454
    )
 
1455
format_registry.register_lazy(
 
1456
    'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
 
1457
    'breezy.repofmt.groupcompress_repo',
 
1458
    'RepositoryFormat2a',
 
1459
    )
 
1460
 
 
1461
# Development formats.
 
1462
# Check their docstrings to see if/when they are obsolete.
 
1463
format_registry.register_lazy(
 
1464
    ("Bazaar development format 2 with subtree support "
 
1465
        "(needs bzr.dev from before 1.8)\n"),
 
1466
    'breezy.repofmt.knitpack_repo',
 
1467
    'RepositoryFormatPackDevelopment2Subtree',
 
1468
    )
 
1469
format_registry.register_lazy(
 
1470
    'Bazaar development format 8\n',
 
1471
    'breezy.repofmt.groupcompress_repo',
 
1472
    'RepositoryFormat2aSubtree',
 
1473
    )
 
1474
 
 
1475
 
 
1476
class InterRepository(InterObject):
 
1477
    """This class represents operations taking place between two repositories.
 
1478
 
 
1479
    Its instances have methods like copy_content and fetch, and contain
 
1480
    references to the source and target repositories these operations can be
 
1481
    carried out on.
 
1482
 
 
1483
    Often we will provide convenience methods on 'repository' which carry out
 
1484
    operations with another repository - they will always forward to
 
1485
    InterRepository.get(other).method_name(parameters).
 
1486
    """
 
1487
 
 
1488
    _optimisers = []
 
1489
    """The available optimised InterRepository types."""
 
1490
 
 
1491
    @needs_write_lock
 
1492
    def copy_content(self, revision_id=None):
 
1493
        """Make a complete copy of the content in self into destination.
 
1494
 
 
1495
        This is a destructive operation! Do not use it on existing
 
1496
        repositories.
 
1497
 
 
1498
        :param revision_id: Only copy the content needed to construct
 
1499
                            revision_id and its parents.
 
1500
        """
 
1501
        try:
 
1502
            self.target.set_make_working_trees(
 
1503
                self.source.make_working_trees())
 
1504
        except NotImplementedError:
 
1505
            pass
 
1506
        self.target.fetch(self.source, revision_id=revision_id)
 
1507
 
 
1508
    @needs_write_lock
 
1509
    def fetch(self, revision_id=None, find_ghosts=False):
 
1510
        """Fetch the content required to construct revision_id.
 
1511
 
 
1512
        The content is copied from self.source to self.target.
 
1513
 
 
1514
        :param revision_id: if None all content is copied, if NULL_REVISION no
 
1515
                            content is copied.
 
1516
        :return: None.
 
1517
        """
 
1518
        raise NotImplementedError(self.fetch)
 
1519
 
 
1520
    @needs_read_lock
 
1521
    def search_missing_revision_ids(
 
1522
            self, find_ghosts=True, revision_ids=None, if_present_ids=None,
 
1523
            limit=None):
 
1524
        """Return the revision ids that source has that target does not.
 
1525
 
 
1526
        :param revision_ids: return revision ids included by these
 
1527
            revision_ids.  NoSuchRevision will be raised if any of these
 
1528
            revisions are not present.
 
1529
        :param if_present_ids: like revision_ids, but will not cause
 
1530
            NoSuchRevision if any of these are absent, instead they will simply
 
1531
            not be in the result.  This is useful for e.g. finding revisions
 
1532
            to fetch for tags, which may reference absent revisions.
 
1533
        :param find_ghosts: If True find missing revisions in deep history
 
1534
            rather than just finding the surface difference.
 
1535
        :param limit: Maximum number of revisions to return, topologically
 
1536
            ordered
 
1537
        :return: A breezy.graph.SearchResult.
 
1538
        """
 
1539
        raise NotImplementedError(self.search_missing_revision_ids)
 
1540
 
 
1541
    @staticmethod
 
1542
    def _same_model(source, target):
 
1543
        """True if source and target have the same data representation.
 
1544
 
 
1545
        Note: this is always called on the base class; overriding it in a
 
1546
        subclass will have no effect.
 
1547
        """
 
1548
        try:
 
1549
            InterRepository._assert_same_model(source, target)
 
1550
            return True
 
1551
        except errors.IncompatibleRepositories as e:
 
1552
            return False
 
1553
 
 
1554
    @staticmethod
 
1555
    def _assert_same_model(source, target):
 
1556
        """Raise an exception if two repositories do not use the same model.
 
1557
        """
 
1558
        if source.supports_rich_root() != target.supports_rich_root():
 
1559
            raise errors.IncompatibleRepositories(source, target,
 
1560
                "different rich-root support")
 
1561
        if source._serializer != target._serializer:
 
1562
            raise errors.IncompatibleRepositories(source, target,
 
1563
                "different serializers")
 
1564
 
 
1565
 
 
1566
class CopyConverter(object):
 
1567
    """A repository conversion tool which just performs a copy of the content.
 
1568
 
 
1569
    This is slow but quite reliable.
 
1570
    """
 
1571
 
 
1572
    def __init__(self, target_format):
 
1573
        """Create a CopyConverter.
 
1574
 
 
1575
        :param target_format: The format the resulting repository should be.
 
1576
        """
 
1577
        self.target_format = target_format
 
1578
 
 
1579
    def convert(self, repo, pb):
 
1580
        """Perform the conversion of to_convert, giving feedback via pb.
 
1581
 
 
1582
        :param to_convert: The disk object to convert.
 
1583
        :param pb: a progress bar to use for progress information.
 
1584
        """
 
1585
        pb = ui.ui_factory.nested_progress_bar()
 
1586
        self.count = 0
 
1587
        self.total = 4
 
1588
        # this is only useful with metadir layouts - separated repo content.
 
1589
        # trigger an assertion if not such
 
1590
        repo._format.get_format_string()
 
1591
        self.repo_dir = repo.bzrdir
 
1592
        pb.update(gettext('Moving repository to repository.backup'))
 
1593
        self.repo_dir.transport.move('repository', 'repository.backup')
 
1594
        backup_transport =  self.repo_dir.transport.clone('repository.backup')
 
1595
        repo._format.check_conversion_target(self.target_format)
 
1596
        self.source_repo = repo._format.open(self.repo_dir,
 
1597
            _found=True,
 
1598
            _override_transport=backup_transport)
 
1599
        pb.update(gettext('Creating new repository'))
 
1600
        converted = self.target_format.initialize(self.repo_dir,
 
1601
                                                  self.source_repo.is_shared())
 
1602
        converted.lock_write()
 
1603
        try:
 
1604
            pb.update(gettext('Copying content'))
 
1605
            self.source_repo.copy_content_into(converted)
 
1606
        finally:
 
1607
            converted.unlock()
 
1608
        pb.update(gettext('Deleting old repository content'))
 
1609
        self.repo_dir.transport.delete_tree('repository.backup')
 
1610
        ui.ui_factory.note(gettext('repository converted'))
 
1611
        pb.finished()
 
1612
 
 
1613
 
 
1614
def _strip_NULL_ghosts(revision_graph):
 
1615
    """Also don't use this. more compatibility code for unmigrated clients."""
 
1616
    # Filter ghosts, and null:
 
1617
    if _mod_revision.NULL_REVISION in revision_graph:
 
1618
        del revision_graph[_mod_revision.NULL_REVISION]
 
1619
    for key, parents in viewitems(revision_graph):
 
1620
        revision_graph[key] = tuple(parent for parent in parents if parent
 
1621
            in revision_graph)
 
1622
    return revision_graph
 
1623
 
 
1624
 
 
1625
def _iter_for_revno(repo, partial_history_cache, stop_index=None,
 
1626
                    stop_revision=None):
 
1627
    """Extend the partial history to include a given index
 
1628
 
 
1629
    If a stop_index is supplied, stop when that index has been reached.
 
1630
    If a stop_revision is supplied, stop when that revision is
 
1631
    encountered.  Otherwise, stop when the beginning of history is
 
1632
    reached.
 
1633
 
 
1634
    :param stop_index: The index which should be present.  When it is
 
1635
        present, history extension will stop.
 
1636
    :param stop_revision: The revision id which should be present.  When
 
1637
        it is encountered, history extension will stop.
 
1638
    """
 
1639
    start_revision = partial_history_cache[-1]
 
1640
    graph = repo.get_graph()
 
1641
    iterator = graph.iter_lefthand_ancestry(start_revision,
 
1642
        (_mod_revision.NULL_REVISION,))
 
1643
    try:
 
1644
        # skip the last revision in the list
 
1645
        next(iterator)
 
1646
        while True:
 
1647
            if (stop_index is not None and
 
1648
                len(partial_history_cache) > stop_index):
 
1649
                break
 
1650
            if partial_history_cache[-1] == stop_revision:
 
1651
                break
 
1652
            revision_id = next(iterator)
 
1653
            partial_history_cache.append(revision_id)
 
1654
    except StopIteration:
 
1655
        # No more history
 
1656
        return
 
1657
 
 
1658
 
 
1659
class _LazyListJoin(object):
 
1660
    """An iterable yielding the contents of many lists as one list.
 
1661
 
 
1662
    Each iterator made from this will reflect the current contents of the lists
 
1663
    at the time the iterator is made.
 
1664
 
 
1665
    This is used by Repository's _make_parents_provider implementation so that
 
1666
    it is safe to do::
 
1667
 
 
1668
      pp = repo._make_parents_provider()      # uses a list of fallback repos
 
1669
      pp.add_fallback_repository(other_repo)  # appends to that list
 
1670
      result = pp.get_parent_map(...)
 
1671
      # The result will include revs from other_repo
 
1672
    """
 
1673
 
 
1674
    def __init__(self, *list_parts):
 
1675
        self.list_parts = list_parts
 
1676
 
 
1677
    def __iter__(self):
 
1678
        full_list = []
 
1679
        for list_part in self.list_parts:
 
1680
            full_list.extend(list_part)
 
1681
        return iter(full_list)
 
1682
 
 
1683
    def __repr__(self):
 
1684
        return "%s.%s(%s)" % (self.__module__, self.__class__.__name__,
 
1685
                              self.list_parts)