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