mirror of
https://github.com/facebook/sapling.git
synced 2024-10-07 15:27:13 +03:00
Fix test-patchbomb for crew
This commit is contained in:
commit
6fae8c6b65
@ -250,6 +250,33 @@ enum cmdline {
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* attempt to verify that a directory is really a hg repo, by testing
|
||||
* for the existence of a subdirectory.
|
||||
*/
|
||||
static int validate_repo(const char *repo_root, const char *subdir)
|
||||
{
|
||||
char *abs_path;
|
||||
struct stat st;
|
||||
int ret;
|
||||
|
||||
if (asprintf(&abs_path, "%s.hg/%s", repo_root, subdir) == -1) {
|
||||
ret = -1;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* verify that we really are looking at valid repo. */
|
||||
|
||||
if (stat(abs_path, &st) == -1) {
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
bail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* paranoid wrapper, runs hg executable in server mode.
|
||||
*/
|
||||
@ -259,7 +286,6 @@ static void serve_data(int argc, char **argv)
|
||||
char *repo, *repo_root;
|
||||
enum cmdline cmd;
|
||||
char *nargv[6];
|
||||
struct stat st;
|
||||
size_t repolen;
|
||||
int i;
|
||||
|
||||
@ -315,15 +341,23 @@ static void serve_data(int argc, char **argv)
|
||||
/* only hg init expects no repo. */
|
||||
|
||||
if (cmd != hg_init) {
|
||||
char *abs_path;
|
||||
int valid;
|
||||
|
||||
if (asprintf(&abs_path, "%s.hg/data", repo_root) == -1) {
|
||||
valid = validate_repo(repo_root, "data");
|
||||
|
||||
if (valid == -1) {
|
||||
goto badargs;
|
||||
}
|
||||
|
||||
if (valid == 0) {
|
||||
valid = validate_repo(repo_root, "store");
|
||||
|
||||
/* verify that we really are looking at valid repo. */
|
||||
|
||||
if (stat(abs_path, &st) == -1) {
|
||||
if (valid == -1) {
|
||||
goto badargs;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid == 0) {
|
||||
perror(repo);
|
||||
exit(EX_DATAERR);
|
||||
}
|
||||
|
101
contrib/mq.el
101
contrib/mq.el
@ -36,6 +36,16 @@
|
||||
:type 'sexp
|
||||
:group 'mercurial)
|
||||
|
||||
(defcustom mq-edit-finish-hook nil
|
||||
"Hook run before a patch description is finished up with."
|
||||
:type 'sexp
|
||||
:group 'mercurial)
|
||||
|
||||
(defcustom mq-signoff-address nil
|
||||
"Address with which to sign off on a patch."
|
||||
:type 'string
|
||||
:group 'mercurial)
|
||||
|
||||
|
||||
;;; Internal variables.
|
||||
|
||||
@ -62,10 +72,14 @@
|
||||
(define-key mq-global-map ">" 'mq-push-all)
|
||||
(define-key mq-global-map "," 'mq-pop)
|
||||
(define-key mq-global-map "<" 'mq-pop-all)
|
||||
(define-key mq-global-map "=" 'mq-diff)
|
||||
(define-key mq-global-map "r" 'mq-refresh)
|
||||
(define-key mq-global-map "e" 'mq-refresh-edit)
|
||||
(define-key mq-global-map "i" 'mq-new)
|
||||
(define-key mq-global-map "n" 'mq-next)
|
||||
(define-key mq-global-map "o" 'mq-signoff)
|
||||
(define-key mq-global-map "p" 'mq-previous)
|
||||
(define-key mq-global-map "s" 'mq-edit-series)
|
||||
(define-key mq-global-map "t" 'mq-top)
|
||||
|
||||
(add-minor-mode 'mq-mode 'mq-mode)
|
||||
@ -76,16 +90,17 @@
|
||||
(defvar mq-edit-mode-map (make-sparse-keymap))
|
||||
(define-key mq-edit-mode-map "\C-c\C-c" 'mq-edit-finish)
|
||||
(define-key mq-edit-mode-map "\C-c\C-k" 'mq-edit-kill)
|
||||
(define-key mq-edit-mode-map "\C-c\C-s" 'mq-signoff)
|
||||
|
||||
|
||||
;;; Helper functions.
|
||||
|
||||
(defun mq-read-patch-name (&optional source prompt)
|
||||
(defun mq-read-patch-name (&optional source prompt force)
|
||||
"Read a patch name to use with a command.
|
||||
May return nil, meaning \"use the default\"."
|
||||
(let ((patches (split-string
|
||||
(hg-chomp (hg-run0 (or source "qseries"))) "\n")))
|
||||
(when current-prefix-arg
|
||||
(when force
|
||||
(completing-read (format "Patch%s: " (or prompt ""))
|
||||
(map 'list 'cons patches patches)
|
||||
nil
|
||||
@ -120,7 +135,8 @@ May return nil, meaning \"use the default\"."
|
||||
(defun mq-push (&optional patch)
|
||||
"Push patches until PATCH is reached.
|
||||
If PATCH is nil, push at most one patch."
|
||||
(interactive (list (mq-read-patch-name "qunapplied" " to push")))
|
||||
(interactive (list (mq-read-patch-name "qunapplied" " to push"
|
||||
current-prefix-arg)))
|
||||
(let ((root (hg-root))
|
||||
(prev-buf (current-buffer))
|
||||
last-line ok)
|
||||
@ -138,7 +154,8 @@ If PATCH is nil, push at most one patch."
|
||||
(if patch (list patch))))
|
||||
last-line (mq-last-line))
|
||||
(let ((lines (count-lines (point-min) (point-max))))
|
||||
(if (and (equal lines 2) (string-match "Now at:" last-line))
|
||||
(if (or (<= lines 1)
|
||||
(and (equal lines 2) (string-match "Now at:" last-line)))
|
||||
(progn
|
||||
(kill-buffer (current-buffer))
|
||||
(delete-window))
|
||||
@ -158,7 +175,8 @@ If PATCH is nil, push at most one patch."
|
||||
(defun mq-pop (&optional patch)
|
||||
"Pop patches until PATCH is reached.
|
||||
If PATCH is nil, pop at most one patch."
|
||||
(interactive (list (mq-read-patch-name "qapplied" " to pop to")))
|
||||
(interactive (list (mq-read-patch-name "qapplied" " to pop to"
|
||||
current-prefix-arg)))
|
||||
(let ((root (hg-root))
|
||||
last-line ok)
|
||||
(unless root
|
||||
@ -192,13 +210,14 @@ If PATCH is nil, pop at most one patch."
|
||||
(message "Refreshing %s... done." patch)
|
||||
(error "Refreshing %s... %s" patch (hg-chomp (cdr ret)))))))
|
||||
|
||||
(defun mq-refresh ()
|
||||
"Refresh the topmost applied patch."
|
||||
(interactive)
|
||||
(defun mq-refresh (&optional git)
|
||||
"Refresh the topmost applied patch.
|
||||
With a prefix argument, generate a git-compatible patch."
|
||||
(interactive "P")
|
||||
(let ((root (hg-root)))
|
||||
(unless root
|
||||
(error "Cannot refresh outside of a repository!"))
|
||||
(mq-refresh-internal root)))
|
||||
(apply 'mq-refresh-internal root (if git '("--git")))))
|
||||
|
||||
(defun mq-patch-info (cmd &optional msg)
|
||||
(let* ((ret (hg-run cmd))
|
||||
@ -231,6 +250,7 @@ This would become the active patch if popped to."
|
||||
(unless (equal (mq-patch-info "qtop") mq-top)
|
||||
(error "Topmost patch has changed!"))
|
||||
(hg-sync-buffers hg-root)
|
||||
(run-hooks 'mq-edit-finish-hook)
|
||||
(mq-refresh-internal hg-root "-m" (buffer-substring (point-min) (point-max)))
|
||||
(let ((buf mq-prev-buffer))
|
||||
(kill-buffer nil)
|
||||
@ -318,6 +338,69 @@ Key bindings
|
||||
(cd root)))
|
||||
(message "Type `C-c C-c' to finish editing and refresh the patch."))
|
||||
|
||||
(defun mq-new (name)
|
||||
"Create a new empty patch named NAME.
|
||||
The patch is applied on top of the current topmost patch.
|
||||
With a prefix argument, forcibly create the patch even if the working
|
||||
directory is modified."
|
||||
(interactive (list (mq-read-patch-name "qseries" " to create" t)))
|
||||
(message "Creating patch...")
|
||||
(let ((ret (if current-prefix-arg
|
||||
(hg-run "qnew" "-f" name)
|
||||
(hg-run "qnew" name))))
|
||||
(if (equal (car ret) 0)
|
||||
(progn
|
||||
(hg-update-mode-lines (buffer-file-name))
|
||||
(message "Creating patch... done."))
|
||||
(error "Creating patch... %s" (hg-chomp (cdr ret))))))
|
||||
|
||||
(defun mq-edit-series ()
|
||||
"Edit the MQ series file directly."
|
||||
(interactive)
|
||||
(let ((root (hg-root)))
|
||||
(unless root
|
||||
(error "Not in an MQ repository!"))
|
||||
(find-file (concat root ".hg/patches/series"))))
|
||||
|
||||
(defun mq-diff (&optional git)
|
||||
"Display a diff of the topmost applied patch.
|
||||
With a prefix argument, display a git-compatible diff."
|
||||
(interactive "P")
|
||||
(hg-view-output ((format "MQ: Diff of %s" (mq-patch-info "qtop")))
|
||||
(if git
|
||||
(call-process (hg-binary) nil t nil "qdiff" "--git")
|
||||
(call-process (hg-binary) nil t nil "qdiff"))
|
||||
(diff-mode)
|
||||
(font-lock-fontify-buffer)))
|
||||
|
||||
(defun mq-signoff ()
|
||||
"Sign off on the current patch, in the style used by the Linux kernel.
|
||||
If the variable mq-signoff-address is non-nil, it will be used, otherwise
|
||||
the value of the ui.username item from your hgrc will be used."
|
||||
(interactive)
|
||||
(let ((was-editing (eq major-mode 'mq-edit-mode))
|
||||
signed)
|
||||
(unless was-editing
|
||||
(mq-refresh-edit))
|
||||
(save-excursion
|
||||
(let* ((user (or mq-signoff-address
|
||||
(hg-run0 "debugconfig" "ui.username")))
|
||||
(signoff (concat "Signed-off-by: " user)))
|
||||
(if (search-forward signoff nil t)
|
||||
(message "You have already signed off on this patch.")
|
||||
(goto-char (point-max))
|
||||
(let ((case-fold-search t))
|
||||
(if (re-search-backward "^Signed-off-by: " nil t)
|
||||
(forward-line 1)
|
||||
(insert "\n")))
|
||||
(insert signoff)
|
||||
(message "%s" signoff)
|
||||
(setq signed t))))
|
||||
(unless was-editing
|
||||
(if signed
|
||||
(mq-edit-finish)
|
||||
(mq-edit-kill)))))
|
||||
|
||||
|
||||
(provide 'mq)
|
||||
|
||||
|
49
hgext/mq.py
49
hgext/mq.py
@ -435,7 +435,27 @@ class queue:
|
||||
return (True, files, fuzz)
|
||||
|
||||
def apply(self, repo, series, list=False, update_status=True,
|
||||
strict=False, patchdir=None, merge=None, wlock=None):
|
||||
strict=False, patchdir=None, merge=None, wlock=None,
|
||||
all_files={}):
|
||||
tr = repo.transaction()
|
||||
try:
|
||||
ret = self._apply(tr, repo, series, list, update_status,
|
||||
strict, patchdir, merge, wlock,
|
||||
all_files=all_files)
|
||||
tr.close()
|
||||
self.save_dirty()
|
||||
return ret
|
||||
except:
|
||||
try:
|
||||
tr.abort()
|
||||
finally:
|
||||
repo.reload()
|
||||
repo.wreload()
|
||||
raise
|
||||
|
||||
def _apply(self, tr, repo, series, list=False, update_status=True,
|
||||
strict=False, patchdir=None, merge=None, wlock=None,
|
||||
all_files={}):
|
||||
# TODO unify with commands.py
|
||||
if not patchdir:
|
||||
patchdir = self.path
|
||||
@ -443,7 +463,6 @@ class queue:
|
||||
if not wlock:
|
||||
wlock = repo.wlock()
|
||||
lock = repo.lock()
|
||||
tr = repo.transaction()
|
||||
n = None
|
||||
for patchname in series:
|
||||
pushable, reason = self.pushable(patchname)
|
||||
@ -468,6 +487,7 @@ class queue:
|
||||
message = '\n'.join(message)
|
||||
|
||||
(patcherr, files, fuzz) = self.patch(repo, pf)
|
||||
all_files.update(files)
|
||||
patcherr = not patcherr
|
||||
|
||||
if merge and files:
|
||||
@ -506,7 +526,6 @@ class queue:
|
||||
self.ui.warn("fuzz found when applying patch, stopping\n")
|
||||
err = 1
|
||||
break
|
||||
tr.close()
|
||||
self.removeundo(repo)
|
||||
return (err, n)
|
||||
|
||||
@ -860,10 +879,25 @@ class queue:
|
||||
else:
|
||||
end = self.series.index(patch, start) + 1
|
||||
s = self.series[start:end]
|
||||
if mergeq:
|
||||
ret = self.mergepatch(repo, mergeq, s, wlock)
|
||||
else:
|
||||
ret = self.apply(repo, s, list, wlock=wlock)
|
||||
all_files = {}
|
||||
try:
|
||||
if mergeq:
|
||||
ret = self.mergepatch(repo, mergeq, s, wlock)
|
||||
else:
|
||||
ret = self.apply(repo, s, list, wlock=wlock,
|
||||
all_files=all_files)
|
||||
except:
|
||||
self.ui.warn(_('cleaning up working directory...'))
|
||||
node = repo.dirstate.parents()[0]
|
||||
hg.revert(repo, node, None, wlock)
|
||||
unknown = repo.status(wlock=wlock)[4]
|
||||
# only remove unknown files that we know we touched or
|
||||
# created while patching
|
||||
for f in unknown:
|
||||
if f in all_files:
|
||||
util.unlink(repo.wjoin(f))
|
||||
self.ui.warn(_('done\n'))
|
||||
raise
|
||||
top = self.applied[-1].name
|
||||
if ret[0]:
|
||||
self.ui.write("Errors during apply, please fix and refresh %s\n" %
|
||||
@ -1837,7 +1871,6 @@ def push(ui, repo, patch=None, **opts):
|
||||
ui.warn("merging with queue at: %s\n" % mergeq.path)
|
||||
ret = q.push(repo, patch, force=opts['force'], list=opts['list'],
|
||||
mergeq=mergeq)
|
||||
q.save_dirty()
|
||||
return ret
|
||||
|
||||
def pop(ui, repo, patch=None, **opts):
|
||||
|
17
tests/test-patchbomb
Executable file
17
tests/test-patchbomb
Executable file
@ -0,0 +1,17 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "[extensions]" >> $HGRCPATH
|
||||
echo "patchbomb=" >> $HGRCPATH
|
||||
|
||||
hg init
|
||||
echo a > a
|
||||
hg commit -Ama -d '1 0'
|
||||
|
||||
hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar tip | \
|
||||
sed -e 's/\(Message-Id:.*@\).*/\1/'
|
||||
|
||||
echo b > b
|
||||
hg commit -Amb -d '2 0'
|
||||
|
||||
hg email --date '1970-1-1 0:2' -n -f quux -t foo -c bar -s test 0:tip | \
|
||||
sed -e 's/\(Message-Id:.*@\|In-Reply-To:.*@\).*/\1/'
|
134
tests/test-patchbomb.out
Normal file
134
tests/test-patchbomb.out
Normal file
@ -0,0 +1,134 @@
|
||||
adding a
|
||||
hg email: option --date not recognized
|
||||
hg email [OPTION]... [DEST]...
|
||||
|
||||
send changesets by email
|
||||
|
||||
By default, diffs are sent in the format generated by hg export,
|
||||
one per message. The series starts with a "[PATCH 0 of N]"
|
||||
introduction, which describes the series as a whole.
|
||||
|
||||
Each patch email has a Subject line of "[PATCH M of N] ...", using
|
||||
the first line of the changeset description as the subject text.
|
||||
The message contains two or three body parts. First, the rest of
|
||||
the changeset description. Next, (optionally) if the diffstat
|
||||
program is installed, the result of running diffstat on the patch.
|
||||
Finally, the patch itself, as generated by "hg export".
|
||||
|
||||
With --outgoing, emails will be generated for patches not
|
||||
found in the destination repository (or only those which are
|
||||
ancestors of the specified revisions if any are provided)
|
||||
|
||||
With --bundle, changesets are selected as for --outgoing,
|
||||
but a single email containing a binary Mercurial bundle as an
|
||||
attachment will be sent.
|
||||
|
||||
Examples:
|
||||
|
||||
hg email -r 3000 # send patch 3000 only
|
||||
hg email -r 3000 -r 3001 # send patches 3000 and 3001
|
||||
hg email -r 3000:3005 # send patches 3000 through 3005
|
||||
hg email 3000 # send patch 3000 (deprecated)
|
||||
|
||||
hg email -o # send all patches not in default
|
||||
hg email -o DEST # send all patches not in DEST
|
||||
hg email -o -r 3000 # send all ancestors of 3000 not in default
|
||||
hg email -o -r 3000 DEST # send all ancestors of 3000 not in DEST
|
||||
|
||||
hg email -b # send bundle of all patches not in default
|
||||
hg email -b DEST # send bundle of all patches not in DEST
|
||||
hg email -b -r 3000 # bundle of all ancestors of 3000 not in default
|
||||
hg email -b -r 3000 DEST # bundle of all ancestors of 3000 not in DEST
|
||||
|
||||
Before using this command, you will need to enable email in your hgrc.
|
||||
See the [email] section in hgrc(5) for details.
|
||||
|
||||
options:
|
||||
|
||||
-a --attach send patches as inline attachments
|
||||
--bcc email addresses of blind copy recipients
|
||||
-c --cc email addresses of copy recipients
|
||||
-d --diffstat add diffstat output to messages
|
||||
-g --git use git extended diff format
|
||||
-f --from email address of sender
|
||||
--plain omit hg patch header
|
||||
-n --test print messages that would be sent
|
||||
-m --mbox write messages to mbox file instead of sending them
|
||||
-o --outgoing send changes not found in the target repository
|
||||
-b --bundle send changes not in target as a binary bundle
|
||||
-r --rev a revision to send
|
||||
-s --subject subject of first message (intro or single patch)
|
||||
-t --to email addresses of recipients
|
||||
--force run even when remote repository is unrelated (with -b)
|
||||
--base a base changeset to specify instead of a destination (with -b)
|
||||
-e --ssh specify ssh command to use
|
||||
--remotecmd specify hg command to run on the remote side
|
||||
|
||||
use "hg -v help email" to show global options
|
||||
adding b
|
||||
hg email: option --date not recognized
|
||||
hg email [OPTION]... [DEST]...
|
||||
|
||||
send changesets by email
|
||||
|
||||
By default, diffs are sent in the format generated by hg export,
|
||||
one per message. The series starts with a "[PATCH 0 of N]"
|
||||
introduction, which describes the series as a whole.
|
||||
|
||||
Each patch email has a Subject line of "[PATCH M of N] ...", using
|
||||
the first line of the changeset description as the subject text.
|
||||
The message contains two or three body parts. First, the rest of
|
||||
the changeset description. Next, (optionally) if the diffstat
|
||||
program is installed, the result of running diffstat on the patch.
|
||||
Finally, the patch itself, as generated by "hg export".
|
||||
|
||||
With --outgoing, emails will be generated for patches not
|
||||
found in the destination repository (or only those which are
|
||||
ancestors of the specified revisions if any are provided)
|
||||
|
||||
With --bundle, changesets are selected as for --outgoing,
|
||||
but a single email containing a binary Mercurial bundle as an
|
||||
attachment will be sent.
|
||||
|
||||
Examples:
|
||||
|
||||
hg email -r 3000 # send patch 3000 only
|
||||
hg email -r 3000 -r 3001 # send patches 3000 and 3001
|
||||
hg email -r 3000:3005 # send patches 3000 through 3005
|
||||
hg email 3000 # send patch 3000 (deprecated)
|
||||
|
||||
hg email -o # send all patches not in default
|
||||
hg email -o DEST # send all patches not in DEST
|
||||
hg email -o -r 3000 # send all ancestors of 3000 not in default
|
||||
hg email -o -r 3000 DEST # send all ancestors of 3000 not in DEST
|
||||
|
||||
hg email -b # send bundle of all patches not in default
|
||||
hg email -b DEST # send bundle of all patches not in DEST
|
||||
hg email -b -r 3000 # bundle of all ancestors of 3000 not in default
|
||||
hg email -b -r 3000 DEST # bundle of all ancestors of 3000 not in DEST
|
||||
|
||||
Before using this command, you will need to enable email in your hgrc.
|
||||
See the [email] section in hgrc(5) for details.
|
||||
|
||||
options:
|
||||
|
||||
-a --attach send patches as inline attachments
|
||||
--bcc email addresses of blind copy recipients
|
||||
-c --cc email addresses of copy recipients
|
||||
-d --diffstat add diffstat output to messages
|
||||
-g --git use git extended diff format
|
||||
-f --from email address of sender
|
||||
--plain omit hg patch header
|
||||
-n --test print messages that would be sent
|
||||
-m --mbox write messages to mbox file instead of sending them
|
||||
-o --outgoing send changes not found in the target repository
|
||||
-b --bundle send changes not in target as a binary bundle
|
||||
-r --rev a revision to send
|
||||
-s --subject subject of first message (intro or single patch)
|
||||
-t --to email addresses of recipients
|
||||
--force run even when remote repository is unrelated (with -b)
|
||||
--base a base changeset to specify instead of a destination (with -b)
|
||||
-e --ssh specify ssh command to use
|
||||
--remotecmd specify hg command to run on the remote side
|
||||
|
||||
use "hg -v help email" to show global options
|
Loading…
Reference in New Issue
Block a user