/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
5752.3.8 by John Arbash Meinel
Merge bzr.dev 5764 to resolve release-notes (aka NEWS) conflicts
1
# Copyright (C) 2007-2011 Canonical Ltd
1551.12.36 by Aaron Bentley
Fix failing tests
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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1551.12.36 by Aaron Bentley
Fix failing tests
16
6379.6.3 by Jelmer Vernooij
Use absolute_import.
17
from __future__ import absolute_import
1551.12.36 by Aaron Bentley
Fix failing tests
18
7029.4.1 by Jelmer Vernooij
Fix a bunch of merge tests.
19
import base64
2520.4.105 by Aaron Bentley
Implement patch verification
20
import re
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
21
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
22
from . import lazy_import
5671.1.1 by Jelmer Vernooij
Lazy import in bzrlib.merge_directive.
23
lazy_import.lazy_import(globals(), """
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
24
from breezy import (
1551.12.5 by Aaron Bentley
Get MergeDirective.from_objects working
25
    branch as _mod_branch,
7356.1.5 by Jelmer Vernooij
Use more ExitStacks.
26
    cleanup,
1551.12.5 by Aaron Bentley
Get MergeDirective.from_objects working
27
    diff,
5753.2.2 by Jelmer Vernooij
Remove some unnecessary imports, clean up lazy imports.
28
    email_message,
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
29
    errors,
1551.12.16 by Aaron Bentley
Enable signing merge directives
30
    gpg,
4098.5.16 by Aaron Bentley
Move hook to MergeDirective, implement MergeDirective.compose_merge_request.
31
    hooks,
2520.4.73 by Aaron Bentley
Implement new merge directive format
32
    registry,
1551.12.5 by Aaron Bentley
Get MergeDirective.from_objects working
33
    revision as _mod_revision,
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
34
    rio,
1551.12.30 by Aaron Bentley
Use patch-style dates for timestamps in merge directives
35
    timestamp,
4098.5.18 by Aaron Bentley
Gracefully handle mail clients that don't support bodies.
36
    trace,
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
37
    )
7206.4.1 by Jelmer Vernooij
Move breezy.testament to breezy.bzr.testament.
38
from breezy.bzr import (
39
    testament,
40
    )
7358.12.1 by Jelmer Vernooij
Move bundle code to breezy.bzr.
41
from breezy.bzr.bundle import (
1551.14.4 by Aaron Bentley
Change bundle reader and merge directive to both be 'mergeables'
42
    serializer as bundle_serializer,
43
    )
5671.1.1 by Jelmer Vernooij
Lazy import in bzrlib.merge_directive.
44
""")
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
45
from .sixish import (
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
46
    BytesIO,
47
    )
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
48
49
4098.5.16 by Aaron Bentley
Move hook to MergeDirective, implement MergeDirective.compose_merge_request.
50
class MergeRequestBodyParams(object):
4098.5.17 by Aaron Bentley
cleanup
51
    """Parameter object for the merge_request_body hook."""
4098.5.16 by Aaron Bentley
Move hook to MergeDirective, implement MergeDirective.compose_merge_request.
52
53
    def __init__(self, body, orig_body, directive, to, basename, subject,
54
                 branch, tree=None):
55
        self.body = body
56
        self.orig_body = orig_body
57
        self.directive = directive
58
        self.branch = branch
59
        self.tree = tree
60
        self.to = to
61
        self.basename = basename
62
        self.subject = subject
63
64
65
class MergeDirectiveHooks(hooks.Hooks):
4098.5.17 by Aaron Bentley
cleanup
66
    """Hooks for MergeDirective classes."""
4098.5.16 by Aaron Bentley
Move hook to MergeDirective, implement MergeDirective.compose_merge_request.
67
5622.3.10 by Jelmer Vernooij
Don't require arguments to hooks.
68
    def __init__(self):
7143.15.2 by Jelmer Vernooij
Run autopep8.
69
        hooks.Hooks.__init__(self, "breezy.merge_directive",
70
                             "BaseMergeDirective.hooks")
7143.15.5 by Jelmer Vernooij
More PEP8 fixes.
71
        self.add_hook(
72
            'merge_request_body',
73
            "Called with a MergeRequestBodyParams when a body is needed for"
74
            " a merge request.  Callbacks must return a body.  If more"
75
            " than one callback is registered, the output of one callback is"
76
            " provided to the next.", (1, 15, 0))
4098.5.16 by Aaron Bentley
Move hook to MergeDirective, implement MergeDirective.compose_merge_request.
77
78
5086.3.1 by Jelmer Vernooij
``bzrlib.merge_directive._BaseMergeDirective`` has been renamed to
79
class BaseMergeDirective(object):
5086.3.2 by Jelmer Vernooij
Add docstring.
80
    """A request to perform a merge into a branch.
81
7143.15.5 by Jelmer Vernooij
More PEP8 fixes.
82
    This is the base class that all merge directive implementations
5086.3.2 by Jelmer Vernooij
Add docstring.
83
    should derive from.
5086.3.3 by Jelmer Vernooij
Allow merge directives to output multiple patch files.
84
7143.15.5 by Jelmer Vernooij
More PEP8 fixes.
85
    :cvar multiple_output_files: Whether or not this merge directive
5086.3.3 by Jelmer Vernooij
Allow merge directives to output multiple patch files.
86
        stores a set of revisions in more than one file
5086.3.2 by Jelmer Vernooij
Add docstring.
87
    """
2520.4.73 by Aaron Bentley
Implement new merge directive format
88
5622.3.10 by Jelmer Vernooij
Don't require arguments to hooks.
89
    hooks = MergeDirectiveHooks()
4098.5.16 by Aaron Bentley
Move hook to MergeDirective, implement MergeDirective.compose_merge_request.
90
5086.3.3 by Jelmer Vernooij
Allow merge directives to output multiple patch files.
91
    multiple_output_files = False
92
2520.4.73 by Aaron Bentley
Implement new merge directive format
93
    def __init__(self, revision_id, testament_sha1, time, timezone,
6365.1.3 by Jelmer Vernooij
Pass local target branch along to merge directive handlers.
94
                 target_branch, patch=None, source_branch=None,
6365.1.5 by Jelmer Vernooij
Kill optional submit_branch argument to MergeDirective constructor.
95
                 message=None, bundle=None):
2520.4.73 by Aaron Bentley
Implement new merge directive format
96
        """Constructor.
97
98
        :param revision_id: The revision to merge
99
        :param testament_sha1: The sha1 of the testament of the revision to
100
            merge.
101
        :param time: The current POSIX timestamp time
102
        :param timezone: The timezone offset
6365.1.3 by Jelmer Vernooij
Pass local target branch along to merge directive handlers.
103
        :param target_branch: Location of branch to apply the merge to
2520.4.73 by Aaron Bentley
Implement new merge directive format
104
        :param patch: The text of a diff or bundle
105
        :param source_branch: A public location to merge the revision from
106
        :param message: The message to use when committing this merge
107
        """
108
        self.revision_id = revision_id
109
        self.testament_sha1 = testament_sha1
110
        self.time = time
111
        self.timezone = timezone
112
        self.target_branch = target_branch
113
        self.patch = patch
114
        self.source_branch = source_branch
115
        self.message = message
116
5086.3.1 by Jelmer Vernooij
``bzrlib.merge_directive._BaseMergeDirective`` has been renamed to
117
    def to_lines(self):
118
        """Serialize as a list of lines
119
120
        :return: a list of lines
121
        """
122
        raise NotImplementedError(self.to_lines)
123
5086.3.3 by Jelmer Vernooij
Allow merge directives to output multiple patch files.
124
    def to_files(self):
125
        """Serialize as a set of files.
126
127
        :return: List of tuples with filename and contents as lines
128
        """
129
        raise NotImplementedError(self.to_files)
130
5086.3.1 by Jelmer Vernooij
``bzrlib.merge_directive._BaseMergeDirective`` has been renamed to
131
    def get_raw_bundle(self):
132
        """Return the bundle for this merge directive.
133
134
        :return: bundle text or None if there is no bundle
135
        """
136
        return None
137
2520.4.105 by Aaron Bentley
Implement patch verification
138
    def _to_lines(self, base_revision=False):
2520.4.73 by Aaron Bentley
Implement new merge directive format
139
        """Serialize as a list of lines
140
141
        :return: a list of lines
142
        """
143
        time_str = timestamp.format_patch_date(self.time, self.timezone)
144
        stanza = rio.Stanza(revision_id=self.revision_id, timestamp=time_str,
145
                            target_branch=self.target_branch,
146
                            testament_sha1=self.testament_sha1)
147
        for key in ('source_branch', 'message'):
148
            if self.__dict__[key] is not None:
149
                stanza.add(key, self.__dict__[key])
2520.4.105 by Aaron Bentley
Implement patch verification
150
        if base_revision:
151
            stanza.add('base_revision_id', self.base_revision_id)
7029.4.1 by Jelmer Vernooij
Fix a bunch of merge tests.
152
        lines = [b'# ' + self._format_string + b'\n']
2520.4.73 by Aaron Bentley
Implement new merge directive format
153
        lines.extend(rio.to_patch_lines(stanza))
7029.4.1 by Jelmer Vernooij
Fix a bunch of merge tests.
154
        lines.append(b'# \n')
2520.4.73 by Aaron Bentley
Implement new merge directive format
155
        return lines
156
5086.3.3 by Jelmer Vernooij
Allow merge directives to output multiple patch files.
157
    def write_to_directory(self, path):
158
        """Write this merge directive to a series of files in a directory.
159
160
        :param path: Filesystem path to write to
161
        """
162
        raise NotImplementedError(self.write_to_directory)
163
2520.4.73 by Aaron Bentley
Implement new merge directive format
164
    @classmethod
165
    def from_objects(klass, repository, revision_id, time, timezone,
7143.15.2 by Jelmer Vernooij
Run autopep8.
166
                     target_branch, patch_type='bundle',
167
                     local_target_branch=None, public_branch=None, message=None):
2520.4.73 by Aaron Bentley
Implement new merge directive format
168
        """Generate a merge directive from various objects
169
170
        :param repository: The repository containing the revision
171
        :param revision_id: The revision to merge
172
        :param time: The POSIX timestamp of the date the request was issued.
173
        :param timezone: The timezone of the request
174
        :param target_branch: The url of the branch to merge into
175
        :param patch_type: 'bundle', 'diff' or None, depending on the type of
176
            patch desired.
6365.1.3 by Jelmer Vernooij
Pass local target branch along to merge directive handlers.
177
        :param local_target_branch: the submit branch, either itself or a local copy
178
        :param public_branch: location of a public branch containing
179
            the target revision.
2520.4.73 by Aaron Bentley
Implement new merge directive format
180
        :param message: Message to use when committing the merge
181
        :return: The merge directive
182
183
        The public branch is always used if supplied.  If the patch_type is
184
        not 'bundle', the public branch must be supplied, and will be verified.
185
186
        If the message is not supplied, the message from revision_id will be
187
        used for the commit.
188
        """
189
        t_revision_id = revision_id
2520.4.86 by Aaron Bentley
Improve locking in _BaseMergeDirective.from_object
190
        if revision_id == _mod_revision.NULL_REVISION:
2520.4.73 by Aaron Bentley
Implement new merge directive format
191
            t_revision_id = None
192
        t = testament.StrictTestament3.from_revision(repository, t_revision_id)
6365.1.3 by Jelmer Vernooij
Pass local target branch along to merge directive handlers.
193
        if local_target_branch is None:
194
            submit_branch = _mod_branch.Branch.open(target_branch)
195
        else:
196
            submit_branch = local_target_branch
2520.4.73 by Aaron Bentley
Implement new merge directive format
197
        if submit_branch.get_public_branch() is not None:
198
            target_branch = submit_branch.get_public_branch()
199
        if patch_type is None:
200
            patch = None
201
        else:
202
            submit_revision_id = submit_branch.last_revision()
203
            submit_revision_id = _mod_revision.ensure_null(submit_revision_id)
204
            repository.fetch(submit_branch.repository, submit_revision_id)
205
            graph = repository.get_graph()
206
            ancestor_id = graph.find_unique_lca(revision_id,
207
                                                submit_revision_id)
208
            type_handler = {'bundle': klass._generate_bundle,
209
                            'diff': klass._generate_diff,
7143.15.2 by Jelmer Vernooij
Run autopep8.
210
                            None: lambda x, y, z: None}
2520.4.73 by Aaron Bentley
Implement new merge directive format
211
            patch = type_handler[patch_type](repository, revision_id,
212
                                             ancestor_id)
213
2520.5.4 by Aaron Bentley
Replace 'bundle-revisions' with 'submit' command
214
        if public_branch is not None and patch_type != 'bundle':
6365.1.4 by Jelmer Vernooij
Fix some tests.
215
            public_branch_obj = _mod_branch.Branch.open(public_branch)
216
            if not public_branch_obj.repository.has_revision(revision_id):
2520.5.4 by Aaron Bentley
Replace 'bundle-revisions' with 'submit' command
217
                raise errors.PublicBranchOutOfDate(public_branch,
218
                                                   revision_id)
2520.4.73 by Aaron Bentley
Implement new merge directive format
219
6365.1.6 by Jelmer Vernooij
revert some unnecessary changes.
220
        return klass(revision_id, t.as_sha1(), time, timezone, target_branch,
7143.15.2 by Jelmer Vernooij
Run autopep8.
221
                     patch, patch_type, public_branch, message)
2520.4.73 by Aaron Bentley
Implement new merge directive format
222
3251.2.1 by Aaron Bentley
Use nick/revno-based names for merge directives
223
    def get_disk_name(self, branch):
224
        """Generate a suitable basename for storing this directive on disk
225
226
        :param branch: The Branch this merge directive was generated fro
227
        :return: A string
228
        """
229
        revno, revision_id = branch.last_revision_info()
230
        if self.revision_id == revision_id:
3251.2.2 by Aaron Bentley
Fix bug in last revno handling
231
            revno = [revno]
3251.2.1 by Aaron Bentley
Use nick/revno-based names for merge directives
232
        else:
6997.7.1 by Jelmer Vernooij
Avoid using get_revision_id_to_revno_map
233
            try:
6997.6.10 by Jelmer Vernooij
fix merge directive test.
234
                revno = branch.revision_id_to_dotted_revno(self.revision_id)
6997.7.1 by Jelmer Vernooij
Avoid using get_revision_id_to_revno_map
235
            except errors.NoSuchRevision:
236
                revno = ['merge']
6798.1.1 by Jelmer Vernooij
Properly escape backslashes.
237
        nick = re.sub('(\\W+)', '-', branch.nick).strip('-')
3449.4.1 by Lukáš Lalinský
Sanitize branch nick before using it as an attachment filename in ``bzr send``
238
        return '%s-%s' % (nick, '.'.join(str(n) for n in revno))
3251.2.1 by Aaron Bentley
Use nick/revno-based names for merge directives
239
2520.4.73 by Aaron Bentley
Implement new merge directive format
240
    @staticmethod
241
    def _generate_diff(repository, revision_id, ancestor_id):
242
        tree_1 = repository.revision_tree(ancestor_id)
243
        tree_2 = repository.revision_tree(revision_id)
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
244
        s = BytesIO()
7031.1.2 by Jelmer Vernooij
Port diff/merge_directive to Python3.
245
        diff.show_diff_trees(tree_1, tree_2, s, old_label='', new_label='')
2520.4.73 by Aaron Bentley
Implement new merge directive format
246
        return s.getvalue()
247
248
    @staticmethod
249
    def _generate_bundle(repository, revision_id, ancestor_id):
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
250
        s = BytesIO()
2520.4.73 by Aaron Bentley
Implement new merge directive format
251
        bundle_serializer.write_bundle(repository, revision_id,
252
                                       ancestor_id, s)
253
        return s.getvalue()
254
2520.4.80 by Aaron Bentley
Improve merge directive tests
255
    def to_signed(self, branch):
256
        """Serialize as a signed string.
257
258
        :param branch: The source branch, to get the signing strategy
259
        :return: a string
260
        """
6351.3.2 by Jelmer Vernooij
Convert some gpg options to config stacks.
261
        my_gpg = gpg.GPGStrategy(branch.get_config_stack())
6973.11.9 by Jelmer Vernooij
Fix tests.
262
        return my_gpg.sign(b''.join(self.to_lines()), gpg.MODE_CLEAR)
2520.4.80 by Aaron Bentley
Improve merge directive tests
263
264
    def to_email(self, mail_to, branch, sign=False):
265
        """Serialize as an email message.
266
267
        :param mail_to: The address to mail the message to
268
        :param branch: The source branch, to get the signing strategy and
269
            source email address
270
        :param sign: If True, gpg-sign the email
271
        :return: an email message
272
        """
6463.1.1 by Jelmer Vernooij
Migrate 'bugtracker' setting to config stacks.
273
        mail_from = branch.get_config_stack().get('email')
2520.4.80 by Aaron Bentley
Improve merge directive tests
274
        if self.message is not None:
2625.6.2 by Adeodato Simó
Merge bzr.dev, resolving conflicts and updating test_merge_directive.py.
275
            subject = self.message
2520.4.80 by Aaron Bentley
Improve merge directive tests
276
        else:
277
            revision = branch.repository.get_revision(self.revision_id)
2625.6.2 by Adeodato Simó
Merge bzr.dev, resolving conflicts and updating test_merge_directive.py.
278
            subject = revision.message
2520.4.80 by Aaron Bentley
Improve merge directive tests
279
        if sign:
280
            body = self.to_signed(branch)
281
        else:
6973.11.5 by Jelmer Vernooij
Update python3.passing.
282
            body = b''.join(self.to_lines())
5753.2.2 by Jelmer Vernooij
Remove some unnecessary imports, clean up lazy imports.
283
        message = email_message.EmailMessage(mail_from, mail_to, subject,
7143.15.2 by Jelmer Vernooij
Run autopep8.
284
                                             body)
2520.4.80 by Aaron Bentley
Improve merge directive tests
285
        return message
286
287
    def install_revisions(self, target_repo):
288
        """Install revisions and return the target revision"""
289
        if not target_repo.has_revision(self.revision_id):
290
            if self.patch_type == 'bundle':
291
                info = bundle_serializer.read_bundle(
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
292
                    BytesIO(self.get_raw_bundle()))
2520.4.80 by Aaron Bentley
Improve merge directive tests
293
                # We don't use the bundle's target revision, because
294
                # MergeDirective.revision_id is authoritative.
1551.19.19 by Aaron Bentley
Merge directives can now fetch prerequisites from the target branch
295
                try:
296
                    info.install_revisions(target_repo, stream_input=False)
297
                except errors.RevisionNotPresent:
298
                    # At least one dependency isn't present.  Try installing
299
                    # missing revisions from the submit branch
3535.8.1 by James Westby
Handle something that isn't a branch being specified in target_branch.
300
                    try:
301
                        submit_branch = \
302
                            _mod_branch.Branch.open(self.target_branch)
303
                    except errors.NotBranchError:
304
                        raise errors.TargetNotBranch(self.target_branch)
1551.19.20 by Aaron Bentley
Updates from review
305
                    missing_revisions = []
306
                    bundle_revisions = set(r.revision_id for r in
307
                                           info.real_revisions)
1551.19.19 by Aaron Bentley
Merge directives can now fetch prerequisites from the target branch
308
                    for revision in info.real_revisions:
309
                        for parent_id in revision.parent_ids:
7143.15.2 by Jelmer Vernooij
Run autopep8.
310
                            if (parent_id not in bundle_revisions
311
                                    and not target_repo.has_revision(parent_id)):
1551.19.19 by Aaron Bentley
Merge directives can now fetch prerequisites from the target branch
312
                                missing_revisions.append(parent_id)
1551.19.20 by Aaron Bentley
Updates from review
313
                    # reverse missing revisions to try to get heads first
314
                    unique_missing = []
315
                    unique_missing_set = set()
316
                    for revision in reversed(missing_revisions):
317
                        if revision in unique_missing_set:
318
                            continue
319
                        unique_missing.append(revision)
320
                        unique_missing_set.add(revision)
321
                    for missing_revision in unique_missing:
1551.19.19 by Aaron Bentley
Merge directives can now fetch prerequisites from the target branch
322
                        target_repo.fetch(submit_branch.repository,
323
                                          missing_revision)
324
                    info.install_revisions(target_repo, stream_input=False)
2520.4.80 by Aaron Bentley
Improve merge directive tests
325
            else:
326
                source_branch = _mod_branch.Branch.open(self.source_branch)
327
                target_repo.fetch(source_branch.repository, self.revision_id)
328
        return self.revision_id
329
4098.5.16 by Aaron Bentley
Move hook to MergeDirective, implement MergeDirective.compose_merge_request.
330
    def compose_merge_request(self, mail_client, to, body, branch, tree=None):
4098.5.17 by Aaron Bentley
cleanup
331
        """Compose a request to merge this directive.
332
333
        :param mail_client: The mail client to use for composing this request.
334
        :param to: The address to compose the request to.
335
        :param branch: The Branch that was used to produce this directive.
336
        :param tree: The Tree (if any) for the Branch used to produce this
337
            directive.
338
        """
4098.5.16 by Aaron Bentley
Move hook to MergeDirective, implement MergeDirective.compose_merge_request.
339
        basename = self.get_disk_name(branch)
340
        subject = '[MERGE] '
341
        if self.message is not None:
342
            subject += self.message
343
        else:
344
            revision = branch.repository.get_revision(self.revision_id)
345
            subject += revision.get_summary()
4098.5.18 by Aaron Bentley
Gracefully handle mail clients that don't support bodies.
346
        if getattr(mail_client, 'supports_body', False):
347
            orig_body = body
348
            for hook in self.hooks['merge_request_body']:
349
                params = MergeRequestBodyParams(body, orig_body, self,
350
                                                to, basename, subject, branch,
351
                                                tree)
352
                body = hook(params)
353
        elif len(self.hooks['merge_request_body']) > 0:
354
            trace.warning('Cannot run merge_request_body hooks because mail'
355
                          ' client %s does not support message bodies.',
7143.15.2 by Jelmer Vernooij
Run autopep8.
356
                          mail_client.__class__.__name__)
4098.5.16 by Aaron Bentley
Move hook to MergeDirective, implement MergeDirective.compose_merge_request.
357
        mail_client.compose_merge_request(to, subject,
6973.11.5 by Jelmer Vernooij
Update python3.passing.
358
                                          b''.join(self.to_lines()),
4098.5.16 by Aaron Bentley
Move hook to MergeDirective, implement MergeDirective.compose_merge_request.
359
                                          basename, body)
360
2520.4.73 by Aaron Bentley
Implement new merge directive format
361
5086.3.1 by Jelmer Vernooij
``bzrlib.merge_directive._BaseMergeDirective`` has been renamed to
362
class MergeDirective(BaseMergeDirective):
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
363
1551.12.38 by Aaron Bentley
Add docs for MergeDirective and RIO-patch functions
364
    """A request to perform a merge into a branch.
365
366
    Designed to be serialized and mailed.  It provides all the information
367
    needed to perform a merge automatically, by providing at minimum a revision
368
    bundle or the location of a branch.
369
370
    The serialization format is robust against certain common forms of
371
    deterioration caused by mailing.
372
373
    The format is also designed to be patch-compatible.  If the directive
374
    includes a diff or revision bundle, it should be possible to apply it
375
    directly using the standard patch program.
376
    """
377
7029.4.1 by Jelmer Vernooij
Fix a bunch of merge tests.
378
    _format_string = b'Bazaar merge directive format 1'
1551.12.12 by Aaron Bentley
Add format header
379
1551.12.4 by Aaron Bentley
Add failing test
380
    def __init__(self, revision_id, testament_sha1, time, timezone,
6365.1.6 by Jelmer Vernooij
revert some unnecessary changes.
381
                 target_branch, patch=None, patch_type=None,
6365.1.5 by Jelmer Vernooij
Kill optional submit_branch argument to MergeDirective constructor.
382
                 source_branch=None, message=None, bundle=None):
1551.12.38 by Aaron Bentley
Add docs for MergeDirective and RIO-patch functions
383
        """Constructor.
384
385
        :param revision_id: The revision to merge
386
        :param testament_sha1: The sha1 of the testament of the revision to
387
            merge.
388
        :param time: The current POSIX timestamp time
389
        :param timezone: The timezone offset
6365.1.3 by Jelmer Vernooij
Pass local target branch along to merge directive handlers.
390
        :param target_branch: Location of the branch to apply the merge to
1551.12.38 by Aaron Bentley
Add docs for MergeDirective and RIO-patch functions
391
        :param patch: The text of a diff or bundle
392
        :param patch_type: None, "diff" or "bundle", depending on the contents
393
            of patch
394
        :param source_branch: A public location to merge the revision from
395
        :param message: The message to use when committing this merge
396
        """
5086.3.1 by Jelmer Vernooij
``bzrlib.merge_directive._BaseMergeDirective`` has been renamed to
397
        BaseMergeDirective.__init__(self, revision_id, testament_sha1, time,
7143.15.2 by Jelmer Vernooij
Run autopep8.
398
                                    timezone, target_branch, patch, source_branch, message)
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
399
        if patch_type not in (None, 'diff', 'bundle'):
400
            raise ValueError(patch_type)
1551.12.13 by Aaron Bentley
Rename fields
401
        if patch_type != 'bundle' and source_branch is None:
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
402
            raise errors.NoMergeSource()
403
        if patch_type is not None and patch is None:
404
            raise errors.PatchMissing(patch_type)
405
        self.patch_type = patch_type
2520.4.73 by Aaron Bentley
Implement new merge directive format
406
407
    def clear_payload(self):
408
        self.patch = None
409
        self.patch_type = None
410
2520.4.80 by Aaron Bentley
Improve merge directive tests
411
    def get_raw_bundle(self):
412
        return self.bundle
413
2520.4.73 by Aaron Bentley
Implement new merge directive format
414
    def _bundle(self):
415
        if self.patch_type == 'bundle':
416
            return self.patch
417
        else:
418
            return None
419
420
    bundle = property(_bundle)
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
421
1551.12.12 by Aaron Bentley
Add format header
422
    @classmethod
423
    def from_lines(klass, lines):
1551.12.38 by Aaron Bentley
Add docs for MergeDirective and RIO-patch functions
424
        """Deserialize a MergeRequest from an iterable of lines
425
426
        :param lines: An iterable of lines
427
        :return: a MergeRequest
428
        """
1551.12.51 by Aaron Bentley
Allow leading junk before merge directive header
429
        line_iter = iter(lines)
6973.13.2 by Jelmer Vernooij
Fix some more tests.
430
        firstline = b""
1551.12.51 by Aaron Bentley
Allow leading junk before merge directive header
431
        for line in line_iter:
6973.13.2 by Jelmer Vernooij
Fix some more tests.
432
            if line.startswith(b'# Bazaar merge directive format '):
7029.4.1 by Jelmer Vernooij
Fix a bunch of merge tests.
433
                return _format_registry.get(line[2:].rstrip())._from_lines(
4792.7.3 by Martin
MergeDirective.from_lines claims to want an iterable but currently requires a list, rewrite so it really wants an iterable
434
                    line_iter)
435
            firstline = firstline or line.strip()
436
        raise errors.NotAMergeDirective(firstline)
2520.4.73 by Aaron Bentley
Implement new merge directive format
437
438
    @classmethod
439
    def _from_lines(klass, line_iter):
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
440
        stanza = rio.read_patch_stanza(line_iter)
441
        patch_lines = list(line_iter)
442
        if len(patch_lines) == 0:
443
            patch = None
1551.12.53 by Aaron Bentley
Fix deserialization of merge directives with no patch
444
            patch_type = None
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
445
        else:
6973.11.5 by Jelmer Vernooij
Update python3.passing.
446
            patch = b''.join(patch_lines)
1551.12.53 by Aaron Bentley
Fix deserialization of merge directives with no patch
447
            try:
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
448
                bundle_serializer.read_bundle(BytesIO(patch))
1551.15.29 by Aaron Bentley
Make merge directives robust against broken bundles
449
            except (errors.NotABundle, errors.BundleNotSupported,
450
                    errors.BadBundle):
1551.12.53 by Aaron Bentley
Fix deserialization of merge directives with no patch
451
                patch_type = 'diff'
452
            else:
453
                patch_type = 'bundle'
1551.12.30 by Aaron Bentley
Use patch-style dates for timestamps in merge directives
454
        time, timezone = timestamp.parse_patch_date(stanza.get('timestamp'))
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
455
        kwargs = {}
1551.12.13 by Aaron Bentley
Rename fields
456
        for key in ('revision_id', 'testament_sha1', 'target_branch',
1551.12.26 by Aaron Bentley
Get email working, with optional message
457
                    'source_branch', 'message'):
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
458
            try:
459
                kwargs[key] = stanza.get(key)
460
            except KeyError:
461
                pass
1551.12.54 by Aaron Bentley
Decoded revision ids are utf-8
462
        kwargs['revision_id'] = kwargs['revision_id'].encode('utf-8')
7029.4.2 by Jelmer Vernooij
Fix more merge tests.
463
        if 'testament_sha1' in kwargs:
464
            kwargs['testament_sha1'] = kwargs['testament_sha1'].encode('ascii')
1551.12.3 by Aaron Bentley
Add timestamps to merge directives
465
        return MergeDirective(time=time, timezone=timezone,
466
                              patch_type=patch_type, patch=patch, **kwargs)
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
467
468
    def to_lines(self):
2520.4.73 by Aaron Bentley
Implement new merge directive format
469
        lines = self._to_lines()
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
470
        if self.patch is not None:
471
            lines.extend(self.patch.splitlines(True))
472
        return lines
473
2520.4.73 by Aaron Bentley
Implement new merge directive format
474
    @staticmethod
475
    def _generate_bundle(repository, revision_id, ancestor_id):
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
476
        s = BytesIO()
2520.4.73 by Aaron Bentley
Implement new merge directive format
477
        bundle_serializer.write_bundle(repository, revision_id,
478
                                       ancestor_id, s, '0.9')
479
        return s.getvalue()
480
2520.4.109 by Aaron Bentley
start work on directive cherry-picking
481
    def get_merge_request(self, repository):
482
        """Provide data for performing a merge
483
484
        Returns suggested base, suggested target, and patch verification status
485
        """
486
        return None, self.revision_id, 'inapplicable'
487
2520.4.76 by Aaron Bentley
Move base64-encoding into merge directives
488
5086.3.1 by Jelmer Vernooij
``bzrlib.merge_directive._BaseMergeDirective`` has been renamed to
489
class MergeDirective2(BaseMergeDirective):
2520.4.73 by Aaron Bentley
Implement new merge directive format
490
7029.4.1 by Jelmer Vernooij
Fix a bunch of merge tests.
491
    _format_string = b'Bazaar merge directive format 2 (Bazaar 0.90)'
2520.4.73 by Aaron Bentley
Implement new merge directive format
492
493
    def __init__(self, revision_id, testament_sha1, time, timezone,
6365.1.6 by Jelmer Vernooij
revert some unnecessary changes.
494
                 target_branch, patch=None, source_branch=None, message=None,
495
                 bundle=None, base_revision_id=None):
2520.4.73 by Aaron Bentley
Implement new merge directive format
496
        if source_branch is None and bundle is None:
497
            raise errors.NoMergeSource()
5086.3.1 by Jelmer Vernooij
``bzrlib.merge_directive._BaseMergeDirective`` has been renamed to
498
        BaseMergeDirective.__init__(self, revision_id, testament_sha1, time,
7143.15.2 by Jelmer Vernooij
Run autopep8.
499
                                    timezone, target_branch, patch, source_branch, message)
2520.4.73 by Aaron Bentley
Implement new merge directive format
500
        self.bundle = bundle
2520.4.105 by Aaron Bentley
Implement patch verification
501
        self.base_revision_id = base_revision_id
2520.4.73 by Aaron Bentley
Implement new merge directive format
502
503
    def _patch_type(self):
504
        if self.bundle is not None:
505
            return 'bundle'
506
        elif self.patch is not None:
507
            return 'diff'
508
        else:
509
            return None
510
511
    patch_type = property(_patch_type)
512
513
    def clear_payload(self):
514
        self.patch = None
515
        self.bundle = None
516
2520.4.80 by Aaron Bentley
Improve merge directive tests
517
    def get_raw_bundle(self):
518
        if self.bundle is None:
519
            return None
520
        else:
7029.4.1 by Jelmer Vernooij
Fix a bunch of merge tests.
521
            return base64.b64decode(self.bundle)
2520.4.80 by Aaron Bentley
Improve merge directive tests
522
2520.4.73 by Aaron Bentley
Implement new merge directive format
523
    @classmethod
524
    def _from_lines(klass, line_iter):
525
        stanza = rio.read_patch_stanza(line_iter)
526
        patch = None
527
        bundle = None
528
        try:
6634.2.1 by Martin
Apply 2to3 next fixer and make compatible
529
            start = next(line_iter)
2520.4.73 by Aaron Bentley
Implement new merge directive format
530
        except StopIteration:
531
            pass
532
        else:
6973.11.5 by Jelmer Vernooij
Update python3.passing.
533
            if start.startswith(b'# Begin patch'):
2520.4.73 by Aaron Bentley
Implement new merge directive format
534
                patch_lines = []
535
                for line in line_iter:
6973.11.5 by Jelmer Vernooij
Update python3.passing.
536
                    if line.startswith(b'# Begin bundle'):
2520.4.73 by Aaron Bentley
Implement new merge directive format
537
                        start = line
538
                        break
539
                    patch_lines.append(line)
540
                else:
541
                    start = None
6973.11.5 by Jelmer Vernooij
Update python3.passing.
542
                patch = b''.join(patch_lines)
2520.4.73 by Aaron Bentley
Implement new merge directive format
543
            if start is not None:
6973.11.5 by Jelmer Vernooij
Update python3.passing.
544
                if start.startswith(b'# Begin bundle'):
545
                    bundle = b''.join(line_iter)
2520.4.73 by Aaron Bentley
Implement new merge directive format
546
                else:
547
                    raise errors.IllegalMergeDirectivePayload(start)
548
        time, timezone = timestamp.parse_patch_date(stanza.get('timestamp'))
549
        kwargs = {}
550
        for key in ('revision_id', 'testament_sha1', 'target_branch',
2520.4.105 by Aaron Bentley
Implement patch verification
551
                    'source_branch', 'message', 'base_revision_id'):
2520.4.73 by Aaron Bentley
Implement new merge directive format
552
            try:
553
                kwargs[key] = stanza.get(key)
554
            except KeyError:
555
                pass
556
        kwargs['revision_id'] = kwargs['revision_id'].encode('utf-8')
2520.4.105 by Aaron Bentley
Implement patch verification
557
        kwargs['base_revision_id'] =\
558
            kwargs['base_revision_id'].encode('utf-8')
7031.1.2 by Jelmer Vernooij
Port diff/merge_directive to Python3.
559
        if 'testament_sha1' in kwargs:
560
            kwargs['testament_sha1'] = kwargs['testament_sha1'].encode('ascii')
2520.4.73 by Aaron Bentley
Implement new merge directive format
561
        return klass(time=time, timezone=timezone, patch=patch, bundle=bundle,
562
                     **kwargs)
563
564
    def to_lines(self):
2520.4.105 by Aaron Bentley
Implement patch verification
565
        lines = self._to_lines(base_revision=True)
2520.4.73 by Aaron Bentley
Implement new merge directive format
566
        if self.patch is not None:
7029.4.1 by Jelmer Vernooij
Fix a bunch of merge tests.
567
            lines.append(b'# Begin patch\n')
2520.4.73 by Aaron Bentley
Implement new merge directive format
568
            lines.extend(self.patch.splitlines(True))
569
        if self.bundle is not None:
7029.4.1 by Jelmer Vernooij
Fix a bunch of merge tests.
570
            lines.append(b'# Begin bundle\n')
2520.4.73 by Aaron Bentley
Implement new merge directive format
571
            lines.extend(self.bundle.splitlines(True))
572
        return lines
573
574
    @classmethod
575
    def from_objects(klass, repository, revision_id, time, timezone,
7143.15.2 by Jelmer Vernooij
Run autopep8.
576
                     target_branch, include_patch=True, include_bundle=True,
577
                     local_target_branch=None, public_branch=None, message=None,
578
                     base_revision_id=None):
2520.4.73 by Aaron Bentley
Implement new merge directive format
579
        """Generate a merge directive from various objects
580
581
        :param repository: The repository containing the revision
582
        :param revision_id: The revision to merge
583
        :param time: The POSIX timestamp of the date the request was issued.
584
        :param timezone: The timezone of the request
585
        :param target_branch: The url of the branch to merge into
2520.5.4 by Aaron Bentley
Replace 'bundle-revisions' with 'submit' command
586
        :param include_patch: If true, include a preview patch
587
        :param include_bundle: If true, include a bundle
6365.1.3 by Jelmer Vernooij
Pass local target branch along to merge directive handlers.
588
        :param local_target_branch: the target branch, either itself or a local copy
589
        :param public_branch: location of a public branch containing
590
            the target revision.
2520.4.73 by Aaron Bentley
Implement new merge directive format
591
        :param message: Message to use when committing the merge
592
        :return: The merge directive
593
2520.5.4 by Aaron Bentley
Replace 'bundle-revisions' with 'submit' command
594
        The public branch is always used if supplied.  If no bundle is
595
        included, the public branch must be supplied, and will be verified.
2520.4.73 by Aaron Bentley
Implement new merge directive format
596
597
        If the message is not supplied, the message from revision_id will be
598
        used for the commit.
599
        """
7356.1.5 by Jelmer Vernooij
Use more ExitStacks.
600
        with cleanup.ExitStack() as exit_stack:
601
            exit_stack.enter_context(repository.lock_write())
2520.4.86 by Aaron Bentley
Improve locking in _BaseMergeDirective.from_object
602
            t_revision_id = revision_id
6973.13.2 by Jelmer Vernooij
Fix some more tests.
603
            if revision_id == b'null:':
2520.4.86 by Aaron Bentley
Improve locking in _BaseMergeDirective.from_object
604
                t_revision_id = None
605
            t = testament.StrictTestament3.from_revision(repository,
7143.15.2 by Jelmer Vernooij
Run autopep8.
606
                                                         t_revision_id)
6365.1.3 by Jelmer Vernooij
Pass local target branch along to merge directive handlers.
607
            if local_target_branch is None:
608
                submit_branch = _mod_branch.Branch.open(target_branch)
609
            else:
610
                submit_branch = local_target_branch
7356.1.5 by Jelmer Vernooij
Use more ExitStacks.
611
            exit_stack.enter_context(submit_branch.lock_read())
2520.4.86 by Aaron Bentley
Improve locking in _BaseMergeDirective.from_object
612
            if submit_branch.get_public_branch() is not None:
613
                target_branch = submit_branch.get_public_branch()
2520.4.105 by Aaron Bentley
Implement patch verification
614
            submit_revision_id = submit_branch.last_revision()
615
            submit_revision_id = _mod_revision.ensure_null(submit_revision_id)
616
            graph = repository.get_graph(submit_branch.repository)
617
            ancestor_id = graph.find_unique_lca(revision_id,
618
                                                submit_revision_id)
2520.4.112 by Aaron Bentley
Make cherry-pick merge directives possible
619
            if base_revision_id is None:
620
                base_revision_id = ancestor_id
2520.5.4 by Aaron Bentley
Replace 'bundle-revisions' with 'submit' command
621
            if (include_patch, include_bundle) != (False, False):
622
                repository.fetch(submit_branch.repository, submit_revision_id)
623
            if include_patch:
624
                patch = klass._generate_diff(repository, revision_id,
625
                                             base_revision_id)
626
            else:
2520.4.86 by Aaron Bentley
Improve locking in _BaseMergeDirective.from_object
627
                patch = None
2520.5.4 by Aaron Bentley
Replace 'bundle-revisions' with 'submit' command
628
629
            if include_bundle:
7029.4.1 by Jelmer Vernooij
Fix a bunch of merge tests.
630
                bundle = base64.b64encode(klass._generate_bundle(repository, revision_id,
7143.15.2 by Jelmer Vernooij
Run autopep8.
631
                                                                 ancestor_id))
2520.5.4 by Aaron Bentley
Replace 'bundle-revisions' with 'submit' command
632
            else:
2520.4.73 by Aaron Bentley
Implement new merge directive format
633
                bundle = None
2520.4.86 by Aaron Bentley
Improve locking in _BaseMergeDirective.from_object
634
2520.5.4 by Aaron Bentley
Replace 'bundle-revisions' with 'submit' command
635
            if public_branch is not None and not include_bundle:
636
                public_branch_obj = _mod_branch.Branch.open(public_branch)
7356.1.5 by Jelmer Vernooij
Use more ExitStacks.
637
                exit_stack.enter_context(public_branch_obj.lock_read())
2520.5.4 by Aaron Bentley
Replace 'bundle-revisions' with 'submit' command
638
                if not public_branch_obj.repository.has_revision(
7143.15.2 by Jelmer Vernooij
Run autopep8.
639
                        revision_id):
2520.5.4 by Aaron Bentley
Replace 'bundle-revisions' with 'submit' command
640
                    raise errors.PublicBranchOutOfDate(public_branch,
641
                                                       revision_id)
4634.90.3 by Andrew Bennetts
Fix other bugs revealed by clearing chk_map page cache during blackbox tests.
642
            testament_sha1 = t.as_sha1()
643
        return klass(revision_id, testament_sha1, time, timezone,
7143.15.2 by Jelmer Vernooij
Run autopep8.
644
                     target_branch, patch, public_branch, message, bundle,
645
                     base_revision_id)
2520.4.105 by Aaron Bentley
Implement patch verification
646
647
    def _verify_patch(self, repository):
648
        calculated_patch = self._generate_diff(repository, self.revision_id,
649
                                               self.base_revision_id)
650
        # Convert line-endings to UNIX
7029.4.1 by Jelmer Vernooij
Fix a bunch of merge tests.
651
        stored_patch = re.sub(b'\r\n?', b'\n', self.patch)
652
        calculated_patch = re.sub(b'\r\n?', b'\n', calculated_patch)
2520.4.105 by Aaron Bentley
Implement patch verification
653
        # Strip trailing whitespace
7029.4.1 by Jelmer Vernooij
Fix a bunch of merge tests.
654
        calculated_patch = re.sub(b' *\n', b'\n', calculated_patch)
655
        stored_patch = re.sub(b' *\n', b'\n', stored_patch)
2520.4.108 by Aaron Bentley
Start work on using merge base from directives
656
        return (calculated_patch == stored_patch)
657
2520.4.109 by Aaron Bentley
start work on directive cherry-picking
658
    def get_merge_request(self, repository):
659
        """Provide data for performing a merge
2520.4.108 by Aaron Bentley
Start work on using merge base from directives
660
2520.4.109 by Aaron Bentley
start work on directive cherry-picking
661
        Returns suggested base, suggested target, and patch verification status
662
        """
2520.4.108 by Aaron Bentley
Start work on using merge base from directives
663
        verified = self._maybe_verify(repository)
2520.4.109 by Aaron Bentley
start work on directive cherry-picking
664
        return self.base_revision_id, self.revision_id, verified
2520.4.105 by Aaron Bentley
Implement patch verification
665
2520.4.108 by Aaron Bentley
Start work on using merge base from directives
666
    def _maybe_verify(self, repository):
667
        if self.patch is not None:
668
            if self._verify_patch(repository):
669
                return 'verified'
670
            else:
671
                return 'failed'
672
        else:
673
            return 'inapplicable'
674
2520.4.73 by Aaron Bentley
Implement new merge directive format
675
676
class MergeDirectiveFormatRegistry(registry.Registry):
677
2694.1.1 by Aaron Bentley
Restore support for Merge directive 2 / 0.19
678
    def register(self, directive, format_string=None):
679
        if format_string is None:
2694.1.3 by Aaron Bentley
Fix whitespace
680
            format_string = directive._format_string
2694.1.1 by Aaron Bentley
Restore support for Merge directive 2 / 0.19
681
        registry.Registry.register(self, format_string, directive)
2520.4.73 by Aaron Bentley
Implement new merge directive format
682
683
684
_format_registry = MergeDirectiveFormatRegistry()
685
_format_registry.register(MergeDirective)
686
_format_registry.register(MergeDirective2)
4241.14.12 by Vincent Ladeuil
Far too many modifications for a single commit, need to restart.
687
# 0.19 never existed.  It got renamed to 0.90.  But by that point, there were
688
# already merge directives in the wild that used 0.19. Registering with the old
689
# format string to retain compatibility with those merge directives.
2694.1.1 by Aaron Bentley
Restore support for Merge directive 2 / 0.19
690
_format_registry.register(MergeDirective2,
7029.4.1 by Jelmer Vernooij
Fix a bunch of merge tests.
691
                          b'Bazaar merge directive format 2 (Bazaar 0.19)')