##// END OF EJS Templates
doc: fix careless document miss in help of hgext/notify...
FUJIWARA Katsunori -
r16500:8436a4e2 stable
parent child Browse files
Show More
@@ -1,376 +1,376 b''
1 1 # notify.py - email notifications for mercurial
2 2 #
3 3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 '''hooks for sending email push notifications
9 9
10 10 This extension let you run hooks sending email notifications when
11 11 changesets are being pushed, from the sending or receiving side.
12 12
13 13 First, enable the extension as explained in :hg:`help extensions`, and
14 register the hook you want to run. ``incoming`` and ``outgoing`` hooks
14 register the hook you want to run. ``incoming`` and ``changegroup`` hooks
15 15 are run by the changesets receiver while the ``outgoing`` one is for
16 16 the sender::
17 17
18 18 [hooks]
19 19 # one email for each incoming changeset
20 20 incoming.notify = python:hgext.notify.hook
21 21 # one email for all incoming changesets
22 22 changegroup.notify = python:hgext.notify.hook
23 23
24 24 # one email for all outgoing changesets
25 25 outgoing.notify = python:hgext.notify.hook
26 26
27 27 Now the hooks are running, subscribers must be assigned to
28 28 repositories. Use the ``[usersubs]`` section to map repositories to a
29 29 given email or the ``[reposubs]`` section to map emails to a single
30 30 repository::
31 31
32 32 [usersubs]
33 33 # key is subscriber email, value is a comma-separated list of glob
34 34 # patterns
35 35 user@host = pattern
36 36
37 37 [reposubs]
38 38 # key is glob pattern, value is a comma-separated list of subscriber
39 39 # emails
40 40 pattern = user@host
41 41
42 42 Glob patterns are matched against absolute path to repository
43 43 root. The subscriptions can be defined in their own file and
44 44 referenced with::
45 45
46 46 [notify]
47 47 config = /path/to/subscriptionsfile
48 48
49 49 Alternatively, they can be added to Mercurial configuration files by
50 50 setting the previous entry to an empty value.
51 51
52 52 At this point, notifications should be generated but will not be sent until you
53 53 set the ``notify.test`` entry to ``False``.
54 54
55 55 Notifications content can be tweaked with the following configuration entries:
56 56
57 57 notify.test
58 58 If ``True``, print messages to stdout instead of sending them. Default: True.
59 59
60 60 notify.sources
61 61 Space separated list of change sources. Notifications are sent only
62 62 if it includes the incoming or outgoing changes source. Incoming
63 63 sources can be ``serve`` for changes coming from http or ssh,
64 64 ``pull`` for pulled changes, ``unbundle`` for changes added by
65 65 :hg:`unbundle` or ``push`` for changes being pushed
66 66 locally. Outgoing sources are the same except for ``unbundle`` which
67 67 is replaced by ``bundle``. Default: serve.
68 68
69 69 notify.strip
70 70 Number of leading slashes to strip from url paths. By default, notifications
71 71 references repositories with their absolute path. ``notify.strip`` let you
72 72 turn them into relative paths. For example, ``notify.strip=3`` will change
73 73 ``/long/path/repository`` into ``repository``. Default: 0.
74 74
75 75 notify.domain
76 76 If subscribers emails or the from email have no domain set, complete them
77 77 with this value.
78 78
79 79 notify.style
80 80 Style file to use when formatting emails.
81 81
82 82 notify.template
83 83 Template to use when formatting emails.
84 84
85 85 notify.incoming
86 86 Template to use when run as incoming hook, override ``notify.template``.
87 87
88 88 notify.outgoing
89 89 Template to use when run as outgoing hook, override ``notify.template``.
90 90
91 91 notify.changegroup
92 92 Template to use when running as changegroup hook, override
93 93 ``notify.template``.
94 94
95 95 notify.maxdiff
96 96 Maximum number of diff lines to include in notification email. Set to 0
97 97 to disable the diff, -1 to include all of it. Default: 300.
98 98
99 99 notify.maxsubject
100 100 Maximum number of characters in emails subject line. Default: 67.
101 101
102 102 notify.diffstat
103 103 Set to True to include a diffstat before diff content. Default: True.
104 104
105 105 notify.merge
106 106 If True, send notifications for merge changesets. Default: True.
107 107
108 108 notify.mbox
109 109 If set, append mails to this mbox file instead of sending. Default: None.
110 110
111 111 notify.fromauthor
112 112 If set, use the first committer of the changegroup for the "From" field of
113 113 the notification mail. If not set, take the user from the pushing repo.
114 114 Default: False.
115 115
116 116 If set, the following entries will also be used to customize the notifications:
117 117
118 118 email.from
119 119 Email ``From`` address to use if none can be found in generated email content.
120 120
121 121 web.baseurl
122 122 Root repository browsing URL to combine with repository paths when making
123 123 references. See also ``notify.strip``.
124 124
125 125 '''
126 126
127 127 from mercurial.i18n import _
128 128 from mercurial import patch, cmdutil, templater, util, mail
129 129 import email.Parser, email.Errors, fnmatch, socket, time
130 130
131 131 # template for single changeset can include email headers.
132 132 single_template = '''
133 133 Subject: changeset in {webroot}: {desc|firstline|strip}
134 134 From: {author}
135 135
136 136 changeset {node|short} in {root}
137 137 details: {baseurl}{webroot}?cmd=changeset;node={node|short}
138 138 description:
139 139 \t{desc|tabindent|strip}
140 140 '''.lstrip()
141 141
142 142 # template for multiple changesets should not contain email headers,
143 143 # because only first set of headers will be used and result will look
144 144 # strange.
145 145 multiple_template = '''
146 146 changeset {node|short} in {root}
147 147 details: {baseurl}{webroot}?cmd=changeset;node={node|short}
148 148 summary: {desc|firstline}
149 149 '''
150 150
151 151 deftemplates = {
152 152 'changegroup': multiple_template,
153 153 }
154 154
155 155 class notifier(object):
156 156 '''email notification class.'''
157 157
158 158 def __init__(self, ui, repo, hooktype):
159 159 self.ui = ui
160 160 cfg = self.ui.config('notify', 'config')
161 161 if cfg:
162 162 self.ui.readconfig(cfg, sections=['usersubs', 'reposubs'])
163 163 self.repo = repo
164 164 self.stripcount = int(self.ui.config('notify', 'strip', 0))
165 165 self.root = self.strip(self.repo.root)
166 166 self.domain = self.ui.config('notify', 'domain')
167 167 self.mbox = self.ui.config('notify', 'mbox')
168 168 self.test = self.ui.configbool('notify', 'test', True)
169 169 self.charsets = mail._charsets(self.ui)
170 170 self.subs = self.subscribers()
171 171 self.merge = self.ui.configbool('notify', 'merge', True)
172 172
173 173 mapfile = self.ui.config('notify', 'style')
174 174 template = (self.ui.config('notify', hooktype) or
175 175 self.ui.config('notify', 'template'))
176 176 self.t = cmdutil.changeset_templater(self.ui, self.repo,
177 177 False, None, mapfile, False)
178 178 if not mapfile and not template:
179 179 template = deftemplates.get(hooktype) or single_template
180 180 if template:
181 181 template = templater.parsestring(template, quoted=False)
182 182 self.t.use_template(template)
183 183
184 184 def strip(self, path):
185 185 '''strip leading slashes from local path, turn into web-safe path.'''
186 186
187 187 path = util.pconvert(path)
188 188 count = self.stripcount
189 189 while count > 0:
190 190 c = path.find('/')
191 191 if c == -1:
192 192 break
193 193 path = path[c + 1:]
194 194 count -= 1
195 195 return path
196 196
197 197 def fixmail(self, addr):
198 198 '''try to clean up email addresses.'''
199 199
200 200 addr = util.email(addr.strip())
201 201 if self.domain:
202 202 a = addr.find('@localhost')
203 203 if a != -1:
204 204 addr = addr[:a]
205 205 if '@' not in addr:
206 206 return addr + '@' + self.domain
207 207 return addr
208 208
209 209 def subscribers(self):
210 210 '''return list of email addresses of subscribers to this repo.'''
211 211 subs = set()
212 212 for user, pats in self.ui.configitems('usersubs'):
213 213 for pat in pats.split(','):
214 214 if fnmatch.fnmatch(self.repo.root, pat.strip()):
215 215 subs.add(self.fixmail(user))
216 216 for pat, users in self.ui.configitems('reposubs'):
217 217 if fnmatch.fnmatch(self.repo.root, pat):
218 218 for user in users.split(','):
219 219 subs.add(self.fixmail(user))
220 220 return [mail.addressencode(self.ui, s, self.charsets, self.test)
221 221 for s in sorted(subs)]
222 222
223 223 def node(self, ctx, **props):
224 224 '''format one changeset, unless it is a suppressed merge.'''
225 225 if not self.merge and len(ctx.parents()) > 1:
226 226 return False
227 227 self.t.show(ctx, changes=ctx.changeset(),
228 228 baseurl=self.ui.config('web', 'baseurl'),
229 229 root=self.repo.root, webroot=self.root, **props)
230 230 return True
231 231
232 232 def skipsource(self, source):
233 233 '''true if incoming changes from this source should be skipped.'''
234 234 ok_sources = self.ui.config('notify', 'sources', 'serve').split()
235 235 return source not in ok_sources
236 236
237 237 def send(self, ctx, count, data):
238 238 '''send message.'''
239 239
240 240 p = email.Parser.Parser()
241 241 try:
242 242 msg = p.parsestr(data)
243 243 except email.Errors.MessageParseError, inst:
244 244 raise util.Abort(inst)
245 245
246 246 # store sender and subject
247 247 sender, subject = msg['From'], msg['Subject']
248 248 del msg['From'], msg['Subject']
249 249
250 250 if not msg.is_multipart():
251 251 # create fresh mime message from scratch
252 252 # (multipart templates must take care of this themselves)
253 253 headers = msg.items()
254 254 payload = msg.get_payload()
255 255 # for notification prefer readability over data precision
256 256 msg = mail.mimeencode(self.ui, payload, self.charsets, self.test)
257 257 # reinstate custom headers
258 258 for k, v in headers:
259 259 msg[k] = v
260 260
261 261 msg['Date'] = util.datestr(format="%a, %d %b %Y %H:%M:%S %1%2")
262 262
263 263 # try to make subject line exist and be useful
264 264 if not subject:
265 265 if count > 1:
266 266 subject = _('%s: %d new changesets') % (self.root, count)
267 267 else:
268 268 s = ctx.description().lstrip().split('\n', 1)[0].rstrip()
269 269 subject = '%s: %s' % (self.root, s)
270 270 maxsubject = int(self.ui.config('notify', 'maxsubject', 67))
271 271 if maxsubject:
272 272 subject = util.ellipsis(subject, maxsubject)
273 273 msg['Subject'] = mail.headencode(self.ui, subject,
274 274 self.charsets, self.test)
275 275
276 276 # try to make message have proper sender
277 277 if not sender:
278 278 sender = self.ui.config('email', 'from') or self.ui.username()
279 279 if '@' not in sender or '@localhost' in sender:
280 280 sender = self.fixmail(sender)
281 281 msg['From'] = mail.addressencode(self.ui, sender,
282 282 self.charsets, self.test)
283 283
284 284 msg['X-Hg-Notification'] = 'changeset %s' % ctx
285 285 if not msg['Message-Id']:
286 286 msg['Message-Id'] = ('<hg.%s.%s.%s@%s>' %
287 287 (ctx, int(time.time()),
288 288 hash(self.repo.root), socket.getfqdn()))
289 289 msg['To'] = ', '.join(self.subs)
290 290
291 291 msgtext = msg.as_string()
292 292 if self.test:
293 293 self.ui.write(msgtext)
294 294 if not msgtext.endswith('\n'):
295 295 self.ui.write('\n')
296 296 else:
297 297 self.ui.status(_('notify: sending %d subscribers %d changes\n') %
298 298 (len(self.subs), count))
299 299 mail.sendmail(self.ui, util.email(msg['From']),
300 300 self.subs, msgtext, mbox=self.mbox)
301 301
302 302 def diff(self, ctx, ref=None):
303 303
304 304 maxdiff = int(self.ui.config('notify', 'maxdiff', 300))
305 305 prev = ctx.p1().node()
306 306 ref = ref and ref.node() or ctx.node()
307 307 chunks = patch.diff(self.repo, prev, ref, opts=patch.diffopts(self.ui))
308 308 difflines = ''.join(chunks).splitlines()
309 309
310 310 if self.ui.configbool('notify', 'diffstat', True):
311 311 s = patch.diffstat(difflines)
312 312 # s may be nil, don't include the header if it is
313 313 if s:
314 314 self.ui.write('\ndiffstat:\n\n%s' % s)
315 315
316 316 if maxdiff == 0:
317 317 return
318 318 elif maxdiff > 0 and len(difflines) > maxdiff:
319 319 msg = _('\ndiffs (truncated from %d to %d lines):\n\n')
320 320 self.ui.write(msg % (len(difflines), maxdiff))
321 321 difflines = difflines[:maxdiff]
322 322 elif difflines:
323 323 self.ui.write(_('\ndiffs (%d lines):\n\n') % len(difflines))
324 324
325 325 self.ui.write("\n".join(difflines))
326 326
327 327 def hook(ui, repo, hooktype, node=None, source=None, **kwargs):
328 328 '''send email notifications to interested subscribers.
329 329
330 330 if used as changegroup hook, send one email for all changesets in
331 331 changegroup. else send one email per changeset.'''
332 332
333 333 n = notifier(ui, repo, hooktype)
334 334 ctx = repo[node]
335 335
336 336 if not n.subs:
337 337 ui.debug('notify: no subscribers to repository %s\n' % n.root)
338 338 return
339 339 if n.skipsource(source):
340 340 ui.debug('notify: changes have source "%s" - skipping\n' % source)
341 341 return
342 342
343 343 ui.pushbuffer()
344 344 data = ''
345 345 count = 0
346 346 author = ''
347 347 if hooktype == 'changegroup' or hooktype == 'outgoing':
348 348 start, end = ctx.rev(), len(repo)
349 349 for rev in xrange(start, end):
350 350 if n.node(repo[rev]):
351 351 count += 1
352 352 if not author:
353 353 author = repo[rev].user()
354 354 else:
355 355 data += ui.popbuffer()
356 356 ui.note(_('notify: suppressing notification for merge %d:%s\n') %
357 357 (rev, repo[rev].hex()[:12]))
358 358 ui.pushbuffer()
359 359 if count:
360 360 n.diff(ctx, repo['tip'])
361 361 else:
362 362 if not n.node(ctx):
363 363 ui.popbuffer()
364 364 ui.note(_('notify: suppressing notification for merge %d:%s\n') %
365 365 (ctx.rev(), ctx.hex()[:12]))
366 366 return
367 367 count += 1
368 368 n.diff(ctx)
369 369
370 370 data += ui.popbuffer()
371 371 fromauthor = ui.config('notify', 'fromauthor')
372 372 if author and fromauthor:
373 373 data = '\n'.join(['From: %s' % author, data])
374 374
375 375 if count:
376 376 n.send(ctx, count, data)
@@ -1,469 +1,469 b''
1 1
2 2 $ cat <<EOF >> $HGRCPATH
3 3 > [extensions]
4 4 > notify=
5 5 >
6 6 > [hooks]
7 7 > incoming.notify = python:hgext.notify.hook
8 8 >
9 9 > [notify]
10 10 > sources = pull
11 11 > diffstat = False
12 12 >
13 13 > [usersubs]
14 14 > foo@bar = *
15 15 >
16 16 > [reposubs]
17 17 > * = baz
18 18 > EOF
19 19 $ hg help notify
20 20 notify extension - hooks for sending email push notifications
21 21
22 22 This extension let you run hooks sending email notifications when changesets
23 23 are being pushed, from the sending or receiving side.
24 24
25 25 First, enable the extension as explained in "hg help extensions", and register
26 the hook you want to run. "incoming" and "outgoing" hooks are run by the
26 the hook you want to run. "incoming" and "changegroup" hooks are run by the
27 27 changesets receiver while the "outgoing" one is for the sender:
28 28
29 29 [hooks]
30 30 # one email for each incoming changeset
31 31 incoming.notify = python:hgext.notify.hook
32 32 # one email for all incoming changesets
33 33 changegroup.notify = python:hgext.notify.hook
34 34
35 35 # one email for all outgoing changesets
36 36 outgoing.notify = python:hgext.notify.hook
37 37
38 38 Now the hooks are running, subscribers must be assigned to repositories. Use
39 39 the "[usersubs]" section to map repositories to a given email or the
40 40 "[reposubs]" section to map emails to a single repository:
41 41
42 42 [usersubs]
43 43 # key is subscriber email, value is a comma-separated list of glob
44 44 # patterns
45 45 user@host = pattern
46 46
47 47 [reposubs]
48 48 # key is glob pattern, value is a comma-separated list of subscriber
49 49 # emails
50 50 pattern = user@host
51 51
52 52 Glob patterns are matched against absolute path to repository root. The
53 53 subscriptions can be defined in their own file and referenced with:
54 54
55 55 [notify]
56 56 config = /path/to/subscriptionsfile
57 57
58 58 Alternatively, they can be added to Mercurial configuration files by setting
59 59 the previous entry to an empty value.
60 60
61 61 At this point, notifications should be generated but will not be sent until
62 62 you set the "notify.test" entry to "False".
63 63
64 64 Notifications content can be tweaked with the following configuration entries:
65 65
66 66 notify.test
67 67 If "True", print messages to stdout instead of sending them. Default: True.
68 68
69 69 notify.sources
70 70 Space separated list of change sources. Notifications are sent only if it
71 71 includes the incoming or outgoing changes source. Incoming sources can be
72 72 "serve" for changes coming from http or ssh, "pull" for pulled changes,
73 73 "unbundle" for changes added by "hg unbundle" or "push" for changes being
74 74 pushed locally. Outgoing sources are the same except for "unbundle" which is
75 75 replaced by "bundle". Default: serve.
76 76
77 77 notify.strip
78 78 Number of leading slashes to strip from url paths. By default, notifications
79 79 references repositories with their absolute path. "notify.strip" let you
80 80 turn them into relative paths. For example, "notify.strip=3" will change
81 81 "/long/path/repository" into "repository". Default: 0.
82 82
83 83 notify.domain
84 84 If subscribers emails or the from email have no domain set, complete them
85 85 with this value.
86 86
87 87 notify.style
88 88 Style file to use when formatting emails.
89 89
90 90 notify.template
91 91 Template to use when formatting emails.
92 92
93 93 notify.incoming
94 94 Template to use when run as incoming hook, override "notify.template".
95 95
96 96 notify.outgoing
97 97 Template to use when run as outgoing hook, override "notify.template".
98 98
99 99 notify.changegroup
100 100 Template to use when running as changegroup hook, override
101 101 "notify.template".
102 102
103 103 notify.maxdiff
104 104 Maximum number of diff lines to include in notification email. Set to 0 to
105 105 disable the diff, -1 to include all of it. Default: 300.
106 106
107 107 notify.maxsubject
108 108 Maximum number of characters in emails subject line. Default: 67.
109 109
110 110 notify.diffstat
111 111 Set to True to include a diffstat before diff content. Default: True.
112 112
113 113 notify.merge
114 114 If True, send notifications for merge changesets. Default: True.
115 115
116 116 notify.mbox
117 117 If set, append mails to this mbox file instead of sending. Default: None.
118 118
119 119 notify.fromauthor
120 120 If set, use the first committer of the changegroup for the "From" field of
121 121 the notification mail. If not set, take the user from the pushing repo.
122 122 Default: False.
123 123
124 124 If set, the following entries will also be used to customize the
125 125 notifications:
126 126
127 127 email.from
128 128 Email "From" address to use if none can be found in generated email content.
129 129
130 130 web.baseurl
131 131 Root repository browsing URL to combine with repository paths when making
132 132 references. See also "notify.strip".
133 133
134 134 no commands defined
135 135 $ hg init a
136 136 $ echo a > a/a
137 137
138 138 commit
139 139
140 140 $ hg --cwd a commit -Ama -d '0 0'
141 141 adding a
142 142
143 143
144 144 clone
145 145
146 146 $ hg --traceback clone a b
147 147 updating to branch default
148 148 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
149 149 $ echo a >> a/a
150 150
151 151 commit
152 152
153 153 $ hg --traceback --cwd a commit -Amb -d '1 0'
154 154
155 155 on Mac OS X 10.5 the tmp path is very long so would get stripped in the subject line
156 156
157 157 $ cat <<EOF >> $HGRCPATH
158 158 > [notify]
159 159 > maxsubject = 200
160 160 > EOF
161 161
162 162 the python call below wraps continuation lines, which appear on Mac OS X 10.5 because
163 163 of the very long subject line
164 164 pull (minimal config)
165 165
166 166 $ hg --traceback --cwd b pull ../a | \
167 167 > python -c 'import sys,re; print re.sub("\n[\t ]", " ", sys.stdin.read()),'
168 168 pulling from ../a
169 169 searching for changes
170 170 adding changesets
171 171 adding manifests
172 172 adding file changes
173 173 added 1 changesets with 1 changes to 1 files
174 174 Content-Type: text/plain; charset="us-ascii"
175 175 MIME-Version: 1.0
176 176 Content-Transfer-Encoding: 7bit
177 177 Date: * (glob)
178 178 Subject: changeset in $TESTTMP/b: b
179 179 From: test
180 180 X-Hg-Notification: changeset 0647d048b600
181 181 Message-Id: <*> (glob)
182 182 To: baz, foo@bar
183 183
184 184 changeset 0647d048b600 in $TESTTMP/b (glob)
185 185 details: $TESTTMP/b?cmd=changeset;node=0647d048b600
186 186 description: b
187 187
188 188 diffs (6 lines):
189 189
190 190 diff -r cb9a9f314b8b -r 0647d048b600 a
191 191 --- a/a Thu Jan 01 00:00:00 1970 +0000
192 192 +++ b/a Thu Jan 01 00:00:01 1970 +0000
193 193 @@ -1,1 +1,2 @@ a
194 194 +a
195 195 (run 'hg update' to get a working copy)
196 196 $ cat <<EOF >> $HGRCPATH
197 197 > [notify]
198 198 > config = `pwd`/.notify.conf
199 199 > domain = test.com
200 200 > strip = 42
201 201 > template = Subject: {desc|firstline|strip}\nFrom: {author}\nX-Test: foo\n\nchangeset {node|short} in {webroot}\ndescription:\n\t{desc|tabindent|strip}
202 202 >
203 203 > [web]
204 204 > baseurl = http://test/
205 205 > EOF
206 206
207 207 fail for config file is missing
208 208
209 209 $ hg --cwd b rollback
210 210 repository tip rolled back to revision 0 (undo pull)
211 211 $ hg --cwd b pull ../a 2>&1 | grep 'error.*\.notify\.conf' > /dev/null && echo pull failed
212 212 pull failed
213 213 $ touch ".notify.conf"
214 214
215 215 pull
216 216
217 217 $ hg --cwd b rollback
218 218 repository tip rolled back to revision 0 (undo pull)
219 219 $ hg --traceback --cwd b pull ../a | \
220 220 > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
221 221 pulling from ../a
222 222 searching for changes
223 223 adding changesets
224 224 adding manifests
225 225 adding file changes
226 226 added 1 changesets with 1 changes to 1 files
227 227 Content-Type: text/plain; charset="us-ascii"
228 228 MIME-Version: 1.0
229 229 Content-Transfer-Encoding: 7bit
230 230 X-Test: foo
231 231 Date: * (glob)
232 232 Subject: b
233 233 From: test@test.com
234 234 X-Hg-Notification: changeset 0647d048b600
235 235 Message-Id: <*> (glob)
236 236 To: baz@test.com, foo@bar
237 237
238 238 changeset 0647d048b600 in b
239 239 description: b
240 240 diffs (6 lines):
241 241
242 242 diff -r cb9a9f314b8b -r 0647d048b600 a
243 243 --- a/a Thu Jan 01 00:00:00 1970 +0000
244 244 +++ b/a Thu Jan 01 00:00:01 1970 +0000
245 245 @@ -1,1 +1,2 @@
246 246 a
247 247 +a
248 248 (run 'hg update' to get a working copy)
249 249
250 250 $ cat << EOF >> $HGRCPATH
251 251 > [hooks]
252 252 > incoming.notify = python:hgext.notify.hook
253 253 >
254 254 > [notify]
255 255 > sources = pull
256 256 > diffstat = True
257 257 > EOF
258 258
259 259 pull
260 260
261 261 $ hg --cwd b rollback
262 262 repository tip rolled back to revision 0 (undo pull)
263 263 $ hg --traceback --cwd b pull ../a | \
264 264 > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
265 265 pulling from ../a
266 266 searching for changes
267 267 adding changesets
268 268 adding manifests
269 269 adding file changes
270 270 added 1 changesets with 1 changes to 1 files
271 271 Content-Type: text/plain; charset="us-ascii"
272 272 MIME-Version: 1.0
273 273 Content-Transfer-Encoding: 7bit
274 274 X-Test: foo
275 275 Date: * (glob)
276 276 Subject: b
277 277 From: test@test.com
278 278 X-Hg-Notification: changeset 0647d048b600
279 279 Message-Id: <*> (glob)
280 280 To: baz@test.com, foo@bar
281 281
282 282 changeset 0647d048b600 in b
283 283 description: b
284 284 diffstat:
285 285
286 286 a | 1 +
287 287 1 files changed, 1 insertions(+), 0 deletions(-)
288 288
289 289 diffs (6 lines):
290 290
291 291 diff -r cb9a9f314b8b -r 0647d048b600 a
292 292 --- a/a Thu Jan 01 00:00:00 1970 +0000
293 293 +++ b/a Thu Jan 01 00:00:01 1970 +0000
294 294 @@ -1,1 +1,2 @@
295 295 a
296 296 +a
297 297 (run 'hg update' to get a working copy)
298 298
299 299 test merge
300 300
301 301 $ cd a
302 302 $ hg up -C 0
303 303 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
304 304 $ echo a >> a
305 305 $ hg ci -Am adda2 -d '2 0'
306 306 created new head
307 307 $ hg merge
308 308 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
309 309 (branch merge, don't forget to commit)
310 310 $ hg ci -m merge -d '3 0'
311 311 $ cd ..
312 312 $ hg --traceback --cwd b pull ../a | \
313 313 > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
314 314 pulling from ../a
315 315 searching for changes
316 316 adding changesets
317 317 adding manifests
318 318 adding file changes
319 319 added 2 changesets with 0 changes to 0 files
320 320 Content-Type: text/plain; charset="us-ascii"
321 321 MIME-Version: 1.0
322 322 Content-Transfer-Encoding: 7bit
323 323 X-Test: foo
324 324 Date: * (glob)
325 325 Subject: adda2
326 326 From: test@test.com
327 327 X-Hg-Notification: changeset 0a184ce6067f
328 328 Message-Id: <*> (glob)
329 329 To: baz@test.com, foo@bar
330 330
331 331 changeset 0a184ce6067f in b
332 332 description: adda2
333 333 diffstat:
334 334
335 335 a | 1 +
336 336 1 files changed, 1 insertions(+), 0 deletions(-)
337 337
338 338 diffs (6 lines):
339 339
340 340 diff -r cb9a9f314b8b -r 0a184ce6067f a
341 341 --- a/a Thu Jan 01 00:00:00 1970 +0000
342 342 +++ b/a Thu Jan 01 00:00:02 1970 +0000
343 343 @@ -1,1 +1,2 @@
344 344 a
345 345 +a
346 346 Content-Type: text/plain; charset="us-ascii"
347 347 MIME-Version: 1.0
348 348 Content-Transfer-Encoding: 7bit
349 349 X-Test: foo
350 350 Date: * (glob)
351 351 Subject: merge
352 352 From: test@test.com
353 353 X-Hg-Notification: changeset 6a0cf76b2701
354 354 Message-Id: <*> (glob)
355 355 To: baz@test.com, foo@bar
356 356
357 357 changeset 6a0cf76b2701 in b
358 358 description: merge
359 359 (run 'hg update' to get a working copy)
360 360
361 361 non-ascii content and truncation of multi-byte subject
362 362
363 363 $ cat <<EOF >> $HGRCPATH
364 364 > [notify]
365 365 > maxsubject = 4
366 366 > EOF
367 367 $ echo a >> a/a
368 368 $ hg --cwd a --encoding utf-8 commit -A -d '0 0' \
369 369 > -m `python -c 'print "\xc3\xa0\xc3\xa1\xc3\xa2\xc3\xa3\xc3\xa4"'`
370 370 $ hg --traceback --cwd b --encoding utf-8 pull ../a | \
371 371 > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
372 372 pulling from ../a
373 373 searching for changes
374 374 adding changesets
375 375 adding manifests
376 376 adding file changes
377 377 added 1 changesets with 1 changes to 1 files
378 378 Content-Type: text/plain; charset="us-ascii"
379 379 MIME-Version: 1.0
380 380 Content-Transfer-Encoding: 8bit
381 381 X-Test: foo
382 382 Date: * (glob)
383 383 Subject: \xc3\xa0... (esc)
384 384 From: test@test.com
385 385 X-Hg-Notification: changeset 7ea05ad269dc
386 386 Message-Id: <*> (glob)
387 387 To: baz@test.com, foo@bar
388 388
389 389 changeset 7ea05ad269dc in b
390 390 description: \xc3\xa0\xc3\xa1\xc3\xa2\xc3\xa3\xc3\xa4 (esc)
391 391 diffstat:
392 392
393 393 a | 1 +
394 394 1 files changed, 1 insertions(+), 0 deletions(-)
395 395
396 396 diffs (7 lines):
397 397
398 398 diff -r 6a0cf76b2701 -r 7ea05ad269dc a
399 399 --- a/a Thu Jan 01 00:00:03 1970 +0000
400 400 +++ b/a Thu Jan 01 00:00:00 1970 +0000
401 401 @@ -1,2 +1,3 @@
402 402 a
403 403 a
404 404 +a
405 405 (run 'hg update' to get a working copy)
406 406
407 407 long lines
408 408
409 409 $ cat <<EOF >> $HGRCPATH
410 410 > [notify]
411 411 > maxsubject = 67
412 412 > test = False
413 413 > mbox = mbox
414 414 > EOF
415 415 $ python -c 'file("a/a", "ab").write("no" * 500 + "\n")'
416 416 $ hg --cwd a commit -A -m "long line"
417 417 $ hg --traceback --cwd b pull ../a
418 418 pulling from ../a
419 419 searching for changes
420 420 adding changesets
421 421 adding manifests
422 422 adding file changes
423 423 added 1 changesets with 1 changes to 1 files
424 424 notify: sending 2 subscribers 1 changes
425 425 (run 'hg update' to get a working copy)
426 426 $ python -c 'import sys,re; print re.sub("\n\t", " ", file("b/mbox").read()),'
427 427 From test@test.com ... ... .. ..:..:.. .... (re)
428 428 Content-Type: text/plain; charset="us-ascii"
429 429 MIME-Version: 1.0
430 430 Content-Transfer-Encoding: quoted-printable
431 431 X-Test: foo
432 432 Date: * (glob)
433 433 Subject: long line
434 434 From: test@test.com
435 435 X-Hg-Notification: changeset e0be44cf638b
436 436 Message-Id: <hg.e0be44cf638b.*.*@*> (glob)
437 437 To: baz@test.com, foo@bar
438 438
439 439 changeset e0be44cf638b in b
440 440 description: long line
441 441 diffstat:
442 442
443 443 a | 1 +
444 444 1 files changed, 1 insertions(+), 0 deletions(-)
445 445
446 446 diffs (8 lines):
447 447
448 448 diff -r 7ea05ad269dc -r e0be44cf638b a
449 449 --- a/a Thu Jan 01 00:00:00 1970 +0000
450 450 +++ b/a Thu Jan 01 00:00:00 1970 +0000
451 451 @@ -1,3 +1,4 @@
452 452 a
453 453 a
454 454 a
455 455 +nonononononononononononononononononononononononononononononononononononono=
456 456 nononononononononononononononononononononononononononononononononononononon=
457 457 ononononononononononononononononononononononononononononononononononononono=
458 458 nononononononononononononononononononononononononononononononononononononon=
459 459 ononononononononononononononononononononononononononononononononononononono=
460 460 nononononononononononononononononononononononononononononononononononononon=
461 461 ononononononononononononononononononononononononononononononononononononono=
462 462 nononononononononononononononononononononononononononononononononononononon=
463 463 ononononononononononononononononononononononononononononononononononononono=
464 464 nononononononononononononononononononononononononononononononononononononon=
465 465 ononononononononononononononononononononononononononononononononononononono=
466 466 nononononononononononononononononononononononononononononononononononononon=
467 467 ononononononononononononononononononononononononononononononononononononono=
468 468 nonononononononononononono
469 469
General Comments 0
You need to be logged in to leave comments. Login now