--- a/hgext/mq.py
+++ b/hgext/mq.py
@@ -187,8 +187,7 @@ class queue:
return (err, n)
if n is None:
- self.ui.warn("apply failed for patch %s\n" % patch)
- sys.exit(1)
+ raise util.Abort(_("apply failed for patch %s") % patch)
self.ui.warn("patch didn't work out, merging %s\n" % patch)
@@ -199,17 +198,14 @@ class queue:
c = repo.changelog.read(rev)
ret = repo.update(rev, allow=True, wlock=wlock)
if ret:
- self.ui.warn("update returned %d\n" % ret)
- sys.exit(1)
+ raise util.Abort(_("update returned %d") % ret)
n = repo.commit(None, c[4], c[1], force=1, wlock=wlock)
if n == None:
- self.ui.warn("repo commit failed\n")
- sys.exit(1)
+ raise util.Abort(_("repo commit failed"))
try:
message, comments, user, date, patchfound = mergeq.readheaders(patch)
except:
- self.ui.warn("Unable to read %s\n" % patch)
- sys.exit(1)
+ raise util.Abort(_("unable to read %s") % patch)
patchf = self.opener(patch, "w")
if comments:
@@ -280,8 +276,6 @@ class queue:
# TODO unify with commands.py
if not patchdir:
patchdir = self.path
- pwd = os.getcwd()
- os.chdir(repo.root)
err = 0
if not wlock:
wlock = repo.wlock()
@@ -308,7 +302,8 @@ class queue:
try:
pp = util.find_in_path('gpatch', os.environ.get('PATH', ''), 'patch')
- f = os.popen("%s -p1 --no-backup-if-mismatch < '%s'" % (pp, pf))
+ f = os.popen("%s -d '%s' -p1 --no-backup-if-mismatch < '%s'" %
+ (pp, repo.root, pf))
except:
self.ui.warn("patch failed, unable to continue (try -v)\n")
err = 1
@@ -356,8 +351,7 @@ class queue:
wlock=wlock)
if n == None:
- self.ui.warn("repo commit failed\n")
- sys.exit(1)
+ raise util.Abort(_("repo commit failed"))
if update_status:
self.applied.append(revlog.hex(n) + ":" + patch)
@@ -376,18 +370,15 @@ class queue:
err = 1
break
tr.close()
- os.chdir(pwd)
return (err, n)
def delete(self, repo, patch):
patch = self.lookup(patch, strict=True)
info = self.isapplied(patch)
if info:
- self.ui.warn("cannot delete applied patch %s\n" % patch)
- sys.exit(1)
+ raise util.Abort(_("cannot delete applied patch %s") % patch)
if patch not in self.series:
- self.ui.warn("patch %s not in series file\n" % patch)
- sys.exit(1)
+ raise util.Abort(_("patch %s not in series file") % patch)
i = self.find_series(patch)
del self.full_series[i]
self.read_series(self.full_series)
@@ -399,23 +390,22 @@ class queue:
top = revlog.bin(top)
pp = repo.dirstate.parents()
if top not in pp:
- self.ui.warn("queue top not at dirstate parents. top %s dirstate %s %s\n" %( revlog.short(top), revlog.short(pp[0]), revlog.short(pp[1])))
- sys.exit(1)
+ raise util.Abort(_("queue top not at same revision as working directory"))
return top
return None
def check_localchanges(self, repo):
(c, a, r, d, u) = repo.changes(None, None)
if c or a or d or r:
- self.ui.write("Local changes found, refresh first\n")
- sys.exit(1)
+ raise util.Abort(_("local changes found, refresh first"))
def new(self, repo, patch, msg=None, force=None):
+ if os.path.exists(os.path.join(self.path, patch)):
+ raise util.Abort(_('patch "%s" already exists') % patch)
commitfiles = []
(c, a, r, d, u) = repo.changes(None, None)
if c or a or d or r:
if not force:
- raise util.Abort(_("Local changes found, refresh first"))
- else:
- commitfiles = c + a + r
+ raise util.Abort(_("local changes found, refresh first"))
+ commitfiles = c + a + r
self.check_toppatch(repo)
wlock = repo.wlock()
insert = self.full_series_end()
@@ -426,8 +416,7 @@ class queue:
n = repo.commit(commitfiles,
"New patch: %s" % patch, force=True, wlock=wlock)
if n == None:
- self.ui.warn("repo commit failed\n")
- sys.exit(1)
+ raise util.Abort(_("repo commit failed"))
self.full_series[insert:insert] = [patch]
self.applied.append(revlog.hex(n) + ":" + patch)
self.read_series(self.full_series)
@@ -532,7 +521,7 @@ class queue:
if update:
(c, a, r, d, u) = repo.changes(None, None)
if c or a or d or r:
- raise util.Abort(_("Local changes found"))
+ raise util.Abort(_("local changes found"))
urev = self.qparents(repo, rev)
repo.update(urev, allow=False, force=True, wlock=wlock)
repo.dirstate.write()
@@ -672,8 +661,7 @@ class queue:
else:
if i + off < len(self.series):
return self.series[i + off]
- self.ui.warn("patch %s not in series\n" % patch)
- sys.exit(1)
+ raise util.Abort(_("patch %s not in series") % patch)
def push(self, repo, patch=None, force=False, list=False,
mergeq=None, wlock=None):
@@ -681,10 +669,10 @@ class queue:
wlock = repo.wlock()
patch = self.lookup(patch)
if patch and self.isapplied(patch):
- self.ui.warn("patch %s is already applied\n" % patch)
+ self.ui.warn(_("patch %s is already applied\n") % patch)
sys.exit(1)
if self.series_end() == len(self.series):
- self.ui.warn("File series fully applied\n")
+ self.ui.warn(_("patch series fully applied\n"))
sys.exit(1)
if not force:
self.check_localchanges(repo)
@@ -733,10 +721,9 @@ class queue:
patch = self.lookup(patch)
info = self.isapplied(patch)
if not info:
- self.ui.warn("patch %s is not applied\n" % patch)
- sys.exit(1)
+ raise util.Abort(_("patch %s is not applied") % patch)
if len(self.applied) == 0:
- self.ui.warn("No patches applied\n")
+ self.ui.warn(_("no patches applied\n"))
sys.exit(1)
if not update:
@@ -910,15 +897,14 @@ class queue:
def init(self, repo, create=False):
if os.path.isdir(self.path):
- raise util.Abort("patch queue directory already exists")
+ raise util.Abort(_("patch queue directory already exists"))
os.mkdir(self.path)
if create:
return self.qrepo(create=True)
def unapplied(self, repo, patch=None):
if patch and patch not in self.series:
- self.ui.warn("%s not in the series file\n" % patch)
- sys.exit(1)
+ raise util.Abort(_("patch %s is not in series file") % patch)
if not patch:
start = self.series_end()
else:
@@ -1070,8 +1056,7 @@ class queue:
def qapplied(self, repo, patch=None):
if patch and patch not in self.series:
- self.ui.warn("%s not in the series file\n" % patch)
- sys.exit(1)
+ raise util.Abort(_("patch %s is not in series file") % patch)
if not patch:
end = len(self.applied)
else:
@@ -1117,8 +1102,8 @@ class queue:
def qimport(self, repo, files, patch=None, existing=None, force=None):
if len(files) > 1 and patch:
- self.ui.warn("-n option not valid when importing multiple files\n")
- sys.exit(1)
+ raise util.Abort(_('option "-n" not valid when importing multiple '
+ 'files'))
i = 0
added = []
for filename in files:
@@ -1126,24 +1111,21 @@ class queue:
if not patch:
patch = filename
if not os.path.isfile(os.path.join(self.path, patch)):
- self.ui.warn("patch %s does not exist\n" % patch)
- sys.exit(1)
+ raise util.Abort(_("patch %s does not exist") % patch)
else:
try:
text = file(filename).read()
except IOError:
- self.ui.warn("Unable to read %s\n" % patch)
- sys.exit(1)
+ raise util.Abort(_("unable to read %s") % patch)
if not patch:
patch = os.path.split(filename)[1]
- if not force and os.path.isfile(os.path.join(self.path, patch)):
- self.ui.warn("patch %s already exists\n" % patch)
- sys.exit(1)
+ if not force and os.path.exists(os.path.join(self.path, patch)):
+ raise util.Abort(_('patch "%s" already exists') % patch)
patchf = self.opener(patch, "w")
patchf.write(text)
if patch in self.series:
- self.ui.warn("patch %s is already in the series file\n" % patch)
- sys.exit(1)
+ raise util.Abort(_('patch %s is already in the series file')
+ % patch)
index = self.full_series_end() + i
self.full_series[index:index] = [patch]
self.read_series(self.full_series)
@@ -1326,13 +1308,11 @@ def save(ui, repo, **opts):
newpath = os.path.join(q.basepath, opts['name'])
if os.path.exists(newpath):
if not os.path.isdir(newpath):
- ui.warn("destination %s exists and is not a directory\n" %
- newpath)
- sys.exit(1)
+ raise util.Abort(_('destination %s exists and is not '
+ 'a directory') % newpath)
if not opts['force']:
- ui.warn("destination %s exists, use -f to force\n" %
- newpath)
- sys.exit(1)
+ raise util.Abort(_('destination %s exists, '
+ 'use -f to force') % newpath)
else:
newpath = savename(path)
ui.warn("copy %s to %s\n" % (path, newpath))
--- a/hgext/patchbomb.py
+++ b/hgext/patchbomb.py
@@ -45,6 +45,7 @@ demandload(globals(), '''email.MIMEMulti
mercurial:commands,hg,ui
os errno popen2 socket sys tempfile time''')
from mercurial.i18n import gettext as _
+from mercurial.node import *
try:
# readline gives raw_input editing capabilities, but is not
@@ -130,8 +131,26 @@ def patchbomb(ui, repo, *revs, **opts):
while patch and not patch[0].strip(): patch.pop(0)
if opts['diffstat']:
body += cdiffstat('\n'.join(desc), patch) + '\n\n'
- body += '\n'.join(patch)
- msg = email.MIMEText.MIMEText(body)
+ if opts['attach']:
+ msg = email.MIMEMultipart.MIMEMultipart()
+ if body: msg.attach(email.MIMEText.MIMEText(body, 'plain'))
+ p = email.MIMEText.MIMEText('\n'.join(patch), 'x-patch')
+ node = bin(node)
+ # if node is mq patch, it will have patch file name as tag
+ patchname = [t for t in repo.nodetags(node)
+ if t.endswith('.patch') or t.endswith('.diff')]
+ if patchname:
+ patchname = patchname[0]
+ elif total > 1:
+ patchname = commands.make_filename(repo, '%b-%n.patch',
+ node, idx, total)
+ else:
+ patchname = commands.make_filename(repo, '%b.patch', node)
+ p['Content-Disposition'] = 'inline; filename=' + patchname
+ msg.attach(p)
+ else:
+ body += '\n'.join(patch)
+ msg = email.MIMEText.MIMEText(body)
if total == 1:
subj = '[PATCH] ' + desc[0].strip()
else:
@@ -274,7 +293,8 @@ def patchbomb(ui, repo, *revs, **opts):
cmdtable = {
'email':
(patchbomb,
- [('', 'bcc', [], 'email addresses of blind copy recipients'),
+ [('a', 'attach', None, 'send patches as inline attachments'),
+ ('', 'bcc', [], 'email addresses of blind copy recipients'),
('c', 'cc', [], 'email addresses of copy recipients'),
('d', 'diffstat', None, 'add diffstat output to messages'),
('f', 'from', '', 'email address of sender'),
--- a/tests/run-tests.py
+++ b/tests/run-tests.py
@@ -201,6 +201,11 @@ def run(cmd):
return ret, splitnewlines(output)
def run_one(test):
+ '''tristate output:
+ None -> skipped
+ True -> passed
+ False -> failed'''
+
vlog("# Test", test)
if not verbose:
sys.stdout.write('.')
@@ -217,15 +222,28 @@ def run_one(test):
os.mkdir(tmpd)
os.chdir(tmpd)
- if test.endswith(".py"):
- cmd = '%s "%s"' % (sys.executable, os.path.join(TESTDIR, test))
- else:
- cmd = '"%s"' % (os.path.join(TESTDIR, test))
+ lctest = test.lower()
- # To reliably get the error code from batch files on WinXP,
- # the "cmd /c call" prefix is needed. Grrr
- if os.name == 'nt' and test.endswith(".bat"):
+ if lctest.endswith('.py'):
+ cmd = '%s "%s"' % (sys.executable, os.path.join(TESTDIR, test))
+ elif lctest.endswith('.bat'):
+ # do not run batch scripts on non-windows
+ if os.name != 'nt':
+ print '\nSkipping %s: batch script' % test
+ return None
+ # To reliably get the error code from batch files on WinXP,
+ # the "cmd /c call" prefix is needed. Grrr
cmd = 'cmd /c call "%s"' % (os.path.join(TESTDIR, test))
+ else:
+ # do not run shell scripts on windows
+ if os.name == 'nt':
+ print '\nSkipping %s: shell script' % test
+ return None
+ # do not try to run non-executable programs
+ if not os.access(os.path.join(TESTDIR, test), os.X_OK):
+ print '\nSkipping %s: not executable' % test
+ return None
+ cmd = '"%s"' % (os.path.join(TESTDIR, test))
if options.timeout > 0:
signal.alarm(options.timeout)
@@ -330,6 +348,7 @@ try:
tests = 0
failed = 0
+ skipped = 0
if len(args) == 0:
args = os.listdir(".")
@@ -337,11 +356,15 @@ try:
if (test.startswith("test-") and '~' not in test and
('.' not in test or test.endswith('.py') or
test.endswith('.bat'))):
- if not run_one(test):
+ ret = run_one(test)
+ if ret is None:
+ skipped += 1
+ elif not ret:
failed += 1
tests += 1
- print "\n# Ran %d tests, %d failed." % (tests, failed)
+ print "\n# Ran %d tests, %d skipped, %d failed." % (tests, skipped,
+ failed)
if coverage:
output_coverage()
except KeyboardInterrupt:
new file mode 100755
--- /dev/null
+++ b/tests/test-mq-qnew-twice
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
+echo "[extensions]" >> $HGTMP/.hgrc
+echo "mq=" >> $HGTMP/.hgrc
+
+hg init a
+cd a
+hg qnew first.patch
+hg qnew first.patch
+
+touch ../first.patch
+hg qimport ../first.patch
+
+exit 0
new file mode 100644
--- /dev/null
+++ b/tests/test-mq-qnew-twice.out
@@ -0,0 +1,2 @@
+abort: patch "first.patch" already exists
+abort: patch "first.patch" already exists
--- a/tests/test-mq-qrefresh-replace-log-message
+++ b/tests/test-mq-qrefresh-replace-log-message
@@ -1,9 +1,9 @@
#!/bin/sh
# Environement setup for MQ
-export HGRCPATH=./hgrc
-echo "[extensions]" >> ./hgrc
-echo "mq=" >> ./hgrc
+HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
+echo "[extensions]" >> $HGTMP/.hgrc
+echo "mq=" >> $HGTMP/.hgrc
#Repo init
hg init