##// END OF EJS Templates
Fix test-patchbomb for crew
Brendan Cully -
r4430:94cb7561 merge default
parent child Browse files
Show More
@@ -0,0 +1,17 b''
1 #!/bin/sh
2
3 echo "[extensions]" >> $HGRCPATH
4 echo "patchbomb=" >> $HGRCPATH
5
6 hg init
7 echo a > a
8 hg commit -Ama -d '1 0'
9
10 hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar tip | \
11 sed -e 's/\(Message-Id:.*@\).*/\1/'
12
13 echo b > b
14 hg commit -Amb -d '2 0'
15
16 hg email --date '1970-1-1 0:2' -n -f quux -t foo -c bar -s test 0:tip | \
17 sed -e 's/\(Message-Id:.*@\|In-Reply-To:.*@\).*/\1/'
@@ -0,0 +1,134 b''
1 adding a
2 hg email: option --date not recognized
3 hg email [OPTION]... [DEST]...
4
5 send changesets by email
6
7 By default, diffs are sent in the format generated by hg export,
8 one per message. The series starts with a "[PATCH 0 of N]"
9 introduction, which describes the series as a whole.
10
11 Each patch email has a Subject line of "[PATCH M of N] ...", using
12 the first line of the changeset description as the subject text.
13 The message contains two or three body parts. First, the rest of
14 the changeset description. Next, (optionally) if the diffstat
15 program is installed, the result of running diffstat on the patch.
16 Finally, the patch itself, as generated by "hg export".
17
18 With --outgoing, emails will be generated for patches not
19 found in the destination repository (or only those which are
20 ancestors of the specified revisions if any are provided)
21
22 With --bundle, changesets are selected as for --outgoing,
23 but a single email containing a binary Mercurial bundle as an
24 attachment will be sent.
25
26 Examples:
27
28 hg email -r 3000 # send patch 3000 only
29 hg email -r 3000 -r 3001 # send patches 3000 and 3001
30 hg email -r 3000:3005 # send patches 3000 through 3005
31 hg email 3000 # send patch 3000 (deprecated)
32
33 hg email -o # send all patches not in default
34 hg email -o DEST # send all patches not in DEST
35 hg email -o -r 3000 # send all ancestors of 3000 not in default
36 hg email -o -r 3000 DEST # send all ancestors of 3000 not in DEST
37
38 hg email -b # send bundle of all patches not in default
39 hg email -b DEST # send bundle of all patches not in DEST
40 hg email -b -r 3000 # bundle of all ancestors of 3000 not in default
41 hg email -b -r 3000 DEST # bundle of all ancestors of 3000 not in DEST
42
43 Before using this command, you will need to enable email in your hgrc.
44 See the [email] section in hgrc(5) for details.
45
46 options:
47
48 -a --attach send patches as inline attachments
49 --bcc email addresses of blind copy recipients
50 -c --cc email addresses of copy recipients
51 -d --diffstat add diffstat output to messages
52 -g --git use git extended diff format
53 -f --from email address of sender
54 --plain omit hg patch header
55 -n --test print messages that would be sent
56 -m --mbox write messages to mbox file instead of sending them
57 -o --outgoing send changes not found in the target repository
58 -b --bundle send changes not in target as a binary bundle
59 -r --rev a revision to send
60 -s --subject subject of first message (intro or single patch)
61 -t --to email addresses of recipients
62 --force run even when remote repository is unrelated (with -b)
63 --base a base changeset to specify instead of a destination (with -b)
64 -e --ssh specify ssh command to use
65 --remotecmd specify hg command to run on the remote side
66
67 use "hg -v help email" to show global options
68 adding b
69 hg email: option --date not recognized
70 hg email [OPTION]... [DEST]...
71
72 send changesets by email
73
74 By default, diffs are sent in the format generated by hg export,
75 one per message. The series starts with a "[PATCH 0 of N]"
76 introduction, which describes the series as a whole.
77
78 Each patch email has a Subject line of "[PATCH M of N] ...", using
79 the first line of the changeset description as the subject text.
80 The message contains two or three body parts. First, the rest of
81 the changeset description. Next, (optionally) if the diffstat
82 program is installed, the result of running diffstat on the patch.
83 Finally, the patch itself, as generated by "hg export".
84
85 With --outgoing, emails will be generated for patches not
86 found in the destination repository (or only those which are
87 ancestors of the specified revisions if any are provided)
88
89 With --bundle, changesets are selected as for --outgoing,
90 but a single email containing a binary Mercurial bundle as an
91 attachment will be sent.
92
93 Examples:
94
95 hg email -r 3000 # send patch 3000 only
96 hg email -r 3000 -r 3001 # send patches 3000 and 3001
97 hg email -r 3000:3005 # send patches 3000 through 3005
98 hg email 3000 # send patch 3000 (deprecated)
99
100 hg email -o # send all patches not in default
101 hg email -o DEST # send all patches not in DEST
102 hg email -o -r 3000 # send all ancestors of 3000 not in default
103 hg email -o -r 3000 DEST # send all ancestors of 3000 not in DEST
104
105 hg email -b # send bundle of all patches not in default
106 hg email -b DEST # send bundle of all patches not in DEST
107 hg email -b -r 3000 # bundle of all ancestors of 3000 not in default
108 hg email -b -r 3000 DEST # bundle of all ancestors of 3000 not in DEST
109
110 Before using this command, you will need to enable email in your hgrc.
111 See the [email] section in hgrc(5) for details.
112
113 options:
114
115 -a --attach send patches as inline attachments
116 --bcc email addresses of blind copy recipients
117 -c --cc email addresses of copy recipients
118 -d --diffstat add diffstat output to messages
119 -g --git use git extended diff format
120 -f --from email address of sender
121 --plain omit hg patch header
122 -n --test print messages that would be sent
123 -m --mbox write messages to mbox file instead of sending them
124 -o --outgoing send changes not found in the target repository
125 -b --bundle send changes not in target as a binary bundle
126 -r --rev a revision to send
127 -s --subject subject of first message (intro or single patch)
128 -t --to email addresses of recipients
129 --force run even when remote repository is unrelated (with -b)
130 --base a base changeset to specify instead of a destination (with -b)
131 -e --ssh specify ssh command to use
132 --remotecmd specify hg command to run on the remote side
133
134 use "hg -v help email" to show global options
@@ -251,6 +251,33 b' enum cmdline {'
251
251
252
252
253 /*
253 /*
254 * attempt to verify that a directory is really a hg repo, by testing
255 * for the existence of a subdirectory.
256 */
257 static int validate_repo(const char *repo_root, const char *subdir)
258 {
259 char *abs_path;
260 struct stat st;
261 int ret;
262
263 if (asprintf(&abs_path, "%s.hg/%s", repo_root, subdir) == -1) {
264 ret = -1;
265 goto bail;
266 }
267
268 /* verify that we really are looking at valid repo. */
269
270 if (stat(abs_path, &st) == -1) {
271 ret = 0;
272 } else {
273 ret = 1;
274 }
275
276 bail:
277 return ret;
278 }
279
280 /*
254 * paranoid wrapper, runs hg executable in server mode.
281 * paranoid wrapper, runs hg executable in server mode.
255 */
282 */
256 static void serve_data(int argc, char **argv)
283 static void serve_data(int argc, char **argv)
@@ -259,7 +286,6 b' static void serve_data(int argc, char **'
259 char *repo, *repo_root;
286 char *repo, *repo_root;
260 enum cmdline cmd;
287 enum cmdline cmd;
261 char *nargv[6];
288 char *nargv[6];
262 struct stat st;
263 size_t repolen;
289 size_t repolen;
264 int i;
290 int i;
265
291
@@ -315,15 +341,23 b' static void serve_data(int argc, char **'
315 /* only hg init expects no repo. */
341 /* only hg init expects no repo. */
316
342
317 if (cmd != hg_init) {
343 if (cmd != hg_init) {
318 char *abs_path;
344 int valid;
319
345
320 if (asprintf(&abs_path, "%s.hg/data", repo_root) == -1) {
346 valid = validate_repo(repo_root, "data");
347
348 if (valid == -1) {
321 goto badargs;
349 goto badargs;
322 }
350 }
351
352 if (valid == 0) {
353 valid = validate_repo(repo_root, "store");
323
354
324 /* verify that we really are looking at valid repo. */
355 if (valid == -1) {
325
356 goto badargs;
326 if (stat(abs_path, &st) == -1) {
357 }
358 }
359
360 if (valid == 0) {
327 perror(repo);
361 perror(repo);
328 exit(EX_DATAERR);
362 exit(EX_DATAERR);
329 }
363 }
@@ -36,6 +36,16 b''
36 :type 'sexp
36 :type 'sexp
37 :group 'mercurial)
37 :group 'mercurial)
38
38
39 (defcustom mq-edit-finish-hook nil
40 "Hook run before a patch description is finished up with."
41 :type 'sexp
42 :group 'mercurial)
43
44 (defcustom mq-signoff-address nil
45 "Address with which to sign off on a patch."
46 :type 'string
47 :group 'mercurial)
48
39
49
40 ;;; Internal variables.
50 ;;; Internal variables.
41
51
@@ -62,10 +72,14 b''
62 (define-key mq-global-map ">" 'mq-push-all)
72 (define-key mq-global-map ">" 'mq-push-all)
63 (define-key mq-global-map "," 'mq-pop)
73 (define-key mq-global-map "," 'mq-pop)
64 (define-key mq-global-map "<" 'mq-pop-all)
74 (define-key mq-global-map "<" 'mq-pop-all)
75 (define-key mq-global-map "=" 'mq-diff)
65 (define-key mq-global-map "r" 'mq-refresh)
76 (define-key mq-global-map "r" 'mq-refresh)
66 (define-key mq-global-map "e" 'mq-refresh-edit)
77 (define-key mq-global-map "e" 'mq-refresh-edit)
78 (define-key mq-global-map "i" 'mq-new)
67 (define-key mq-global-map "n" 'mq-next)
79 (define-key mq-global-map "n" 'mq-next)
80 (define-key mq-global-map "o" 'mq-signoff)
68 (define-key mq-global-map "p" 'mq-previous)
81 (define-key mq-global-map "p" 'mq-previous)
82 (define-key mq-global-map "s" 'mq-edit-series)
69 (define-key mq-global-map "t" 'mq-top)
83 (define-key mq-global-map "t" 'mq-top)
70
84
71 (add-minor-mode 'mq-mode 'mq-mode)
85 (add-minor-mode 'mq-mode 'mq-mode)
@@ -76,16 +90,17 b''
76 (defvar mq-edit-mode-map (make-sparse-keymap))
90 (defvar mq-edit-mode-map (make-sparse-keymap))
77 (define-key mq-edit-mode-map "\C-c\C-c" 'mq-edit-finish)
91 (define-key mq-edit-mode-map "\C-c\C-c" 'mq-edit-finish)
78 (define-key mq-edit-mode-map "\C-c\C-k" 'mq-edit-kill)
92 (define-key mq-edit-mode-map "\C-c\C-k" 'mq-edit-kill)
93 (define-key mq-edit-mode-map "\C-c\C-s" 'mq-signoff)
79
94
80
95
81 ;;; Helper functions.
96 ;;; Helper functions.
82
97
83 (defun mq-read-patch-name (&optional source prompt)
98 (defun mq-read-patch-name (&optional source prompt force)
84 "Read a patch name to use with a command.
99 "Read a patch name to use with a command.
85 May return nil, meaning \"use the default\"."
100 May return nil, meaning \"use the default\"."
86 (let ((patches (split-string
101 (let ((patches (split-string
87 (hg-chomp (hg-run0 (or source "qseries"))) "\n")))
102 (hg-chomp (hg-run0 (or source "qseries"))) "\n")))
88 (when current-prefix-arg
103 (when force
89 (completing-read (format "Patch%s: " (or prompt ""))
104 (completing-read (format "Patch%s: " (or prompt ""))
90 (map 'list 'cons patches patches)
105 (map 'list 'cons patches patches)
91 nil
106 nil
@@ -120,7 +135,8 b' May return nil, meaning \\"use the defaul'
120 (defun mq-push (&optional patch)
135 (defun mq-push (&optional patch)
121 "Push patches until PATCH is reached.
136 "Push patches until PATCH is reached.
122 If PATCH is nil, push at most one patch."
137 If PATCH is nil, push at most one patch."
123 (interactive (list (mq-read-patch-name "qunapplied" " to push")))
138 (interactive (list (mq-read-patch-name "qunapplied" " to push"
139 current-prefix-arg)))
124 (let ((root (hg-root))
140 (let ((root (hg-root))
125 (prev-buf (current-buffer))
141 (prev-buf (current-buffer))
126 last-line ok)
142 last-line ok)
@@ -138,7 +154,8 b' If PATCH is nil, push at most one patch.'
138 (if patch (list patch))))
154 (if patch (list patch))))
139 last-line (mq-last-line))
155 last-line (mq-last-line))
140 (let ((lines (count-lines (point-min) (point-max))))
156 (let ((lines (count-lines (point-min) (point-max))))
141 (if (and (equal lines 2) (string-match "Now at:" last-line))
157 (if (or (<= lines 1)
158 (and (equal lines 2) (string-match "Now at:" last-line)))
142 (progn
159 (progn
143 (kill-buffer (current-buffer))
160 (kill-buffer (current-buffer))
144 (delete-window))
161 (delete-window))
@@ -158,7 +175,8 b' If PATCH is nil, push at most one patch.'
158 (defun mq-pop (&optional patch)
175 (defun mq-pop (&optional patch)
159 "Pop patches until PATCH is reached.
176 "Pop patches until PATCH is reached.
160 If PATCH is nil, pop at most one patch."
177 If PATCH is nil, pop at most one patch."
161 (interactive (list (mq-read-patch-name "qapplied" " to pop to")))
178 (interactive (list (mq-read-patch-name "qapplied" " to pop to"
179 current-prefix-arg)))
162 (let ((root (hg-root))
180 (let ((root (hg-root))
163 last-line ok)
181 last-line ok)
164 (unless root
182 (unless root
@@ -192,13 +210,14 b' If PATCH is nil, pop at most one patch."'
192 (message "Refreshing %s... done." patch)
210 (message "Refreshing %s... done." patch)
193 (error "Refreshing %s... %s" patch (hg-chomp (cdr ret)))))))
211 (error "Refreshing %s... %s" patch (hg-chomp (cdr ret)))))))
194
212
195 (defun mq-refresh ()
213 (defun mq-refresh (&optional git)
196 "Refresh the topmost applied patch."
214 "Refresh the topmost applied patch.
197 (interactive)
215 With a prefix argument, generate a git-compatible patch."
216 (interactive "P")
198 (let ((root (hg-root)))
217 (let ((root (hg-root)))
199 (unless root
218 (unless root
200 (error "Cannot refresh outside of a repository!"))
219 (error "Cannot refresh outside of a repository!"))
201 (mq-refresh-internal root)))
220 (apply 'mq-refresh-internal root (if git '("--git")))))
202
221
203 (defun mq-patch-info (cmd &optional msg)
222 (defun mq-patch-info (cmd &optional msg)
204 (let* ((ret (hg-run cmd))
223 (let* ((ret (hg-run cmd))
@@ -231,6 +250,7 b' This would become the active patch if po'
231 (unless (equal (mq-patch-info "qtop") mq-top)
250 (unless (equal (mq-patch-info "qtop") mq-top)
232 (error "Topmost patch has changed!"))
251 (error "Topmost patch has changed!"))
233 (hg-sync-buffers hg-root)
252 (hg-sync-buffers hg-root)
253 (run-hooks 'mq-edit-finish-hook)
234 (mq-refresh-internal hg-root "-m" (buffer-substring (point-min) (point-max)))
254 (mq-refresh-internal hg-root "-m" (buffer-substring (point-min) (point-max)))
235 (let ((buf mq-prev-buffer))
255 (let ((buf mq-prev-buffer))
236 (kill-buffer nil)
256 (kill-buffer nil)
@@ -318,6 +338,69 b' Key bindings'
318 (cd root)))
338 (cd root)))
319 (message "Type `C-c C-c' to finish editing and refresh the patch."))
339 (message "Type `C-c C-c' to finish editing and refresh the patch."))
320
340
341 (defun mq-new (name)
342 "Create a new empty patch named NAME.
343 The patch is applied on top of the current topmost patch.
344 With a prefix argument, forcibly create the patch even if the working
345 directory is modified."
346 (interactive (list (mq-read-patch-name "qseries" " to create" t)))
347 (message "Creating patch...")
348 (let ((ret (if current-prefix-arg
349 (hg-run "qnew" "-f" name)
350 (hg-run "qnew" name))))
351 (if (equal (car ret) 0)
352 (progn
353 (hg-update-mode-lines (buffer-file-name))
354 (message "Creating patch... done."))
355 (error "Creating patch... %s" (hg-chomp (cdr ret))))))
356
357 (defun mq-edit-series ()
358 "Edit the MQ series file directly."
359 (interactive)
360 (let ((root (hg-root)))
361 (unless root
362 (error "Not in an MQ repository!"))
363 (find-file (concat root ".hg/patches/series"))))
364
365 (defun mq-diff (&optional git)
366 "Display a diff of the topmost applied patch.
367 With a prefix argument, display a git-compatible diff."
368 (interactive "P")
369 (hg-view-output ((format "MQ: Diff of %s" (mq-patch-info "qtop")))
370 (if git
371 (call-process (hg-binary) nil t nil "qdiff" "--git")
372 (call-process (hg-binary) nil t nil "qdiff"))
373 (diff-mode)
374 (font-lock-fontify-buffer)))
375
376 (defun mq-signoff ()
377 "Sign off on the current patch, in the style used by the Linux kernel.
378 If the variable mq-signoff-address is non-nil, it will be used, otherwise
379 the value of the ui.username item from your hgrc will be used."
380 (interactive)
381 (let ((was-editing (eq major-mode 'mq-edit-mode))
382 signed)
383 (unless was-editing
384 (mq-refresh-edit))
385 (save-excursion
386 (let* ((user (or mq-signoff-address
387 (hg-run0 "debugconfig" "ui.username")))
388 (signoff (concat "Signed-off-by: " user)))
389 (if (search-forward signoff nil t)
390 (message "You have already signed off on this patch.")
391 (goto-char (point-max))
392 (let ((case-fold-search t))
393 (if (re-search-backward "^Signed-off-by: " nil t)
394 (forward-line 1)
395 (insert "\n")))
396 (insert signoff)
397 (message "%s" signoff)
398 (setq signed t))))
399 (unless was-editing
400 (if signed
401 (mq-edit-finish)
402 (mq-edit-kill)))))
403
321
404
322 (provide 'mq)
405 (provide 'mq)
323
406
@@ -435,7 +435,27 b' class queue:'
435 return (True, files, fuzz)
435 return (True, files, fuzz)
436
436
437 def apply(self, repo, series, list=False, update_status=True,
437 def apply(self, repo, series, list=False, update_status=True,
438 strict=False, patchdir=None, merge=None, wlock=None):
438 strict=False, patchdir=None, merge=None, wlock=None,
439 all_files={}):
440 tr = repo.transaction()
441 try:
442 ret = self._apply(tr, repo, series, list, update_status,
443 strict, patchdir, merge, wlock,
444 all_files=all_files)
445 tr.close()
446 self.save_dirty()
447 return ret
448 except:
449 try:
450 tr.abort()
451 finally:
452 repo.reload()
453 repo.wreload()
454 raise
455
456 def _apply(self, tr, repo, series, list=False, update_status=True,
457 strict=False, patchdir=None, merge=None, wlock=None,
458 all_files={}):
439 # TODO unify with commands.py
459 # TODO unify with commands.py
440 if not patchdir:
460 if not patchdir:
441 patchdir = self.path
461 patchdir = self.path
@@ -443,7 +463,6 b' class queue:'
443 if not wlock:
463 if not wlock:
444 wlock = repo.wlock()
464 wlock = repo.wlock()
445 lock = repo.lock()
465 lock = repo.lock()
446 tr = repo.transaction()
447 n = None
466 n = None
448 for patchname in series:
467 for patchname in series:
449 pushable, reason = self.pushable(patchname)
468 pushable, reason = self.pushable(patchname)
@@ -468,6 +487,7 b' class queue:'
468 message = '\n'.join(message)
487 message = '\n'.join(message)
469
488
470 (patcherr, files, fuzz) = self.patch(repo, pf)
489 (patcherr, files, fuzz) = self.patch(repo, pf)
490 all_files.update(files)
471 patcherr = not patcherr
491 patcherr = not patcherr
472
492
473 if merge and files:
493 if merge and files:
@@ -506,7 +526,6 b' class queue:'
506 self.ui.warn("fuzz found when applying patch, stopping\n")
526 self.ui.warn("fuzz found when applying patch, stopping\n")
507 err = 1
527 err = 1
508 break
528 break
509 tr.close()
510 self.removeundo(repo)
529 self.removeundo(repo)
511 return (err, n)
530 return (err, n)
512
531
@@ -860,10 +879,25 b' class queue:'
860 else:
879 else:
861 end = self.series.index(patch, start) + 1
880 end = self.series.index(patch, start) + 1
862 s = self.series[start:end]
881 s = self.series[start:end]
863 if mergeq:
882 all_files = {}
864 ret = self.mergepatch(repo, mergeq, s, wlock)
883 try:
865 else:
884 if mergeq:
866 ret = self.apply(repo, s, list, wlock=wlock)
885 ret = self.mergepatch(repo, mergeq, s, wlock)
886 else:
887 ret = self.apply(repo, s, list, wlock=wlock,
888 all_files=all_files)
889 except:
890 self.ui.warn(_('cleaning up working directory...'))
891 node = repo.dirstate.parents()[0]
892 hg.revert(repo, node, None, wlock)
893 unknown = repo.status(wlock=wlock)[4]
894 # only remove unknown files that we know we touched or
895 # created while patching
896 for f in unknown:
897 if f in all_files:
898 util.unlink(repo.wjoin(f))
899 self.ui.warn(_('done\n'))
900 raise
867 top = self.applied[-1].name
901 top = self.applied[-1].name
868 if ret[0]:
902 if ret[0]:
869 self.ui.write("Errors during apply, please fix and refresh %s\n" %
903 self.ui.write("Errors during apply, please fix and refresh %s\n" %
@@ -1837,7 +1871,6 b' def push(ui, repo, patch=None, **opts):'
1837 ui.warn("merging with queue at: %s\n" % mergeq.path)
1871 ui.warn("merging with queue at: %s\n" % mergeq.path)
1838 ret = q.push(repo, patch, force=opts['force'], list=opts['list'],
1872 ret = q.push(repo, patch, force=opts['force'], list=opts['list'],
1839 mergeq=mergeq)
1873 mergeq=mergeq)
1840 q.save_dirty()
1841 return ret
1874 return ret
1842
1875
1843 def pop(ui, repo, patch=None, **opts):
1876 def pop(ui, repo, patch=None, **opts):
General Comments 0
You need to be logged in to leave comments. Login now