34
34
class MergeDirective(object):
36
"""A request to perform a merge into a branch.
38
Designed to be serialized and mailed. It provides all the information
39
needed to perform a merge automatically, by providing at minimum a revision
40
bundle or the location of a branch.
42
The serialization format is robust against certain common forms of
43
deterioration caused by mailing.
45
The format is also designed to be patch-compatible. If the directive
46
includes a diff or revision bundle, it should be possible to apply it
47
directly using the standard patch program.
36
50
_format_string = 'Bazaar merge directive format experimental-1'
38
52
def __init__(self, revision_id, testament_sha1, time, timezone,
39
53
target_branch, patch=None, patch_type=None,
40
54
source_branch=None, message=None):
57
:param revision_id: The revision to merge
58
:param testament_sha1: The sha1 of the testament of the revision to
60
:param time: The current POSIX timestamp time
61
:param timezone: The timezone offset
62
:param target_branch: The branch to apply the merge to
63
:param patch: The text of a diff or bundle
64
:param patch_type: None, "diff" or "bundle", depending on the contents
66
:param source_branch: A public location to merge the revision from
67
:param message: The message to use when committing this merge
41
69
assert patch_type in (None, 'diff', 'bundle')
42
70
if patch_type != 'bundle' and source_branch is None:
43
71
raise errors.NoMergeSource()
57
85
def from_lines(klass, lines):
86
"""Deserialize a MergeRequest from an iterable of lines
88
:param lines: An iterable of lines
89
:return: a MergeRequest
58
91
assert lines[0].startswith('# ' + klass._format_string + '\n')
59
92
line_iter = iter(lines[1:])
60
93
stanza = rio.read_patch_stanza(line_iter)
81
114
patch_type=patch_type, patch=patch, **kwargs)
83
116
def to_lines(self):
117
"""Serialize as a list of lines
119
:return: a list of lines
84
121
time_str = timestamp.format_patch_date(self.time, self.timezone)
85
122
stanza = rio.Stanza(revision_id=self.revision_id, timestamp=time_str,
86
123
target_branch=self.target_branch,
98
135
def to_signed(self, branch):
136
"""Serialize as a signed string.
138
:param branch: The source branch, to get the signing strategy
99
141
my_gpg = gpg.GPGStrategy(branch.get_config())
100
142
return my_gpg.sign(''.join(self.to_lines()))
102
144
def to_email(self, mail_to, branch, sign=False):
145
"""Serialize as an email message.
147
:param mail_to: The address to mail the message to
148
:param branch: The source branch, to get the signing strategy and
150
:param sign: If True, gpg-sign the email
151
:return: an email message
103
153
mail_from = branch.get_config().username()
104
154
message = Message.Message()
105
155
message['To'] = mail_to
120
170
def from_objects(klass, repository, revision_id, time, timezone,
121
171
target_branch, patch_type='bundle',
122
172
local_target_branch=None, public_branch=None, message=None):
173
"""Generate a merge directive from various objects
175
:param repository: The repository containing the revision
176
:param revision_id: The revision to merge
177
:param time: The POSIX timestamp of the date the request was issued.
178
:param timezone: The timezone of the request
179
:param target_branch: The url of the branch to merge into
180
:param patch_type: 'bundle', 'diff' or None, depending on the type of
182
:param local_target_branch: a local copy of the target branch
183
:param public_branch: location of a public branch containing the target
185
:param message: Message to use when committing the merge
186
:return: The merge directive
188
The public branch is always used if supplied. If the patch_type is
189
not 'bundle', the public branch must be supplied, and will be verified.
191
If the message is not supplied, the message from revision_id will be
123
194
t = testament.StrictTestament3.from_revision(repository, revision_id)
124
195
if patch_type is None: