merge with tonfa
authorThomas Arendsen Hein <thomas@intevation.de>
Fri, 28 Jul 2006 09:01:13 +0200
changeset 2717 14ebe97542a7
parent 2715 79c31b6b9c83 (diff)
parent 2716 4af4e1870fa0 (current diff)
child 2718 a593813241e5
child 2719 532809ba1db5
merge with tonfa
mercurial/commands.py
--- a/contrib/bash_completion	Thu Jul 27 19:26:01 2006 +0200
+++ b/contrib/bash_completion	Fri Jul 28 09:01:13 2006 +0200
@@ -288,7 +288,7 @@
 
 _hg_cmd_qdelete()
 {
-    _hg_ext_mq_patchlist qseries
+    _hg_ext_mq_patchlist qunapplied
 }
 
 _hg_cmd_qsave()
@@ -313,6 +313,11 @@
     COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$files' -- "$cur"))
 }
 
+_hg_cmd_export()
+{
+    _hg_ext_mq_patchlist qapplied
+}
+
 
 # hbisect
 _hg_cmd_bisect()
--- a/hgext/mq.py	Thu Jul 27 19:26:01 2006 +0200
+++ b/hgext/mq.py	Fri Jul 28 09:01:13 2006 +0200
@@ -187,8 +187,7 @@
             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 @@
         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:
@@ -257,7 +253,7 @@
         head = self.qparents(repo)
 
         for patch in series:
-            patch = mergeq.lookup(patch)
+            patch = mergeq.lookup(patch, strict=True)
             if not patch:
                 self.ui.warn("patch %s does not exist\n" % patch)
                 return (1, None)
@@ -280,8 +276,6 @@
         # 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 @@
 
             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 @@
                             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 @@
                 err = 1
                 break
         tr.close()
-        os.chdir(pwd)
         return (err, n)
 
     def delete(self, repo, patch):
-        patch = self.lookup(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,26 +390,25 @@
             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.series_end()
+        insert = self.full_series_end()
         if msg:
             n = repo.commit(commitfiles, "[mq]: %s" % msg, force=True,
                             wlock=wlock)
@@ -426,8 +416,7 @@
             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)
@@ -442,7 +431,7 @@
         r = self.qrepo()
         if r: r.add([patch])
         if commitfiles:
-            self.refresh(repo, short=True)
+            self.refresh(repo, msg=None, short=True)
 
     def strip(self, repo, rev, update=True, backup="all", wlock=None):
         def limitheads(chlog, stop):
@@ -530,6 +519,9 @@
         revnum = chlog.rev(rev)
 
         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"))
             urev = self.qparents(repo, rev)
             repo.update(urev, allow=False, force=True, wlock=wlock)
             repo.dirstate.write()
@@ -598,25 +590,78 @@
                 return (i, a[0], a[1])
         return None
 
-    def lookup(self, patch):
+    # if the exact patch name does not exist, we try a few 
+    # variations.  If strict is passed, we try only #1
+    #
+    # 1) a number to indicate an offset in the series file
+    # 2) a unique substring of the patch name was given
+    # 3) patchname[-+]num to indicate an offset in the series file
+    def lookup(self, patch, strict=False):
+        def partial_name(s):
+            count = 0
+            if s in self.series:
+                return s
+            for x in self.series:
+                if s in x:
+                    count += 1
+                    last = x
+                if count > 1:
+                    return None
+            if count:
+                return last
+            if len(self.series) > 0 and len(self.applied) > 0:
+                if s == 'qtip':
+                    return self.series[self.series_end()-1]
+                if s == 'qbase':
+                    return self.series[0]
+            return None
         if patch == None:
             return None
-        if patch in self.series:
-            return patch
+
+        # we don't want to return a partial match until we make
+        # sure the file name passed in does not exist (checked below)
+        res = partial_name(patch)
+        if res and res == patch:
+            return res
+
         if not os.path.isfile(os.path.join(self.path, patch)):
             try:
                 sno = int(patch)
             except(ValueError, OverflowError):
-                self.ui.warn("patch %s not in series\n" % patch)
-                sys.exit(1)
-            if sno >= len(self.series):
-                self.ui.warn("patch number %d is out of range\n" % sno)
-                sys.exit(1)
-            patch = self.series[sno]
-        else:
-            self.ui.warn("patch %s not in series\n" % patch)
-            sys.exit(1)
-        return patch
+                pass
+            else:
+                if sno < len(self.series):
+                    patch = self.series[sno]
+                    return patch
+            if not strict:
+                # return any partial match made above
+                if res:
+                    return res
+                minus = patch.rsplit('-', 1)
+                if len(minus) > 1:
+                    res = partial_name(minus[0])
+                    if res:
+                        i = self.series.index(res)
+                        try:
+                            off = int(minus[1] or 1)
+                        except(ValueError, OverflowError):
+                            pass
+                        else:
+                            if i - off >= 0:
+                                return self.series[i - off]
+                plus = patch.rsplit('+', 1)
+                if len(plus) > 1:
+                    res = partial_name(plus[0])
+                    if res:
+                        i = self.series.index(res)
+                        try:
+                            off = int(plus[1] or 1)
+                        except(ValueError, OverflowError):
+                            pass
+                        else:
+                            if i + off < len(self.series):
+                                return self.series[i + off]
+        raise util.Abort(_("patch %s not in series") % patch)
 
     def push(self, repo, patch=None, force=False, list=False,
              mergeq=None, wlock=None):
@@ -624,10 +669,10 @@
             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)
@@ -654,7 +699,8 @@
             self.ui.write("Now at: %s\n" % top)
         return ret[0]
 
-    def pop(self, repo, patch=None, force=False, update=True, wlock=None):
+    def pop(self, repo, patch=None, force=False, update=True, all=False,
+            wlock=None):
         def getfile(f, rev):
             t = repo.file(f).read(rev)
             try:
@@ -675,10 +721,9 @@
                 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:
@@ -695,7 +740,17 @@
         self.applied_dirty = 1;
         end = len(self.applied)
         if not patch:
-            info = [len(self.applied) - 1] + self.applied[-1].split(':')
+            if all:
+                popi = 0
+            else:
+                popi = len(self.applied) - 1
+        else:
+            popi = info[0] + 1
+            if popi >= end:
+                self.ui.warn("qpop: %s is already at the top\n" % patch)
+                return
+        info = [ popi ] + self.applied[popi].split(':')
+
         start = info[0]
         rev = revlog.bin(info[1])
 
@@ -739,7 +794,7 @@
         qp = self.qparents(repo, top)
         commands.dodiff(sys.stdout, self.ui, repo, qp, None, files)
 
-    def refresh(self, repo, short=False):
+    def refresh(self, repo, msg=None, short=False):
         if len(self.applied) == 0:
             self.ui.write("No patches applied\n")
             return
@@ -822,10 +877,14 @@
             repo.dirstate.update(c, 'n')
             repo.dirstate.forget(forget)
 
-            if not message:
-                message = "patch queue: %s\n" % patch
+            if not msg:
+                if not message:
+                    message = "patch queue: %s\n" % patch
+                else:
+                    message = "\n".join(message)
             else:
-                message = "\n".join(message)
+                message = msg
+
             self.strip(repo, top, update=False, backup='strip', wlock=wlock)
             n = repo.commit(filelist, message, changes[1], force=1, wlock=wlock)
             self.applied[-1] = revlog.hex(n) + ':' + patch
@@ -838,15 +897,14 @@
 
     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:
@@ -976,6 +1034,15 @@
         self.applied.append(revlog.hex(n) + ":" + '.hg.patches.save.line')
         self.applied_dirty = 1
 
+    def full_series_end(self):
+        if len(self.applied) > 0:
+            (top, p) = self.applied[-1].split(':')
+            end = self.find_series(p)
+            if end == None:
+                return len(self.full_series)
+            return end + 1
+        return 0
+
     def series_end(self):
         end = 0
         if len(self.applied) > 0:
@@ -989,8 +1056,7 @@
 
     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:
@@ -1036,8 +1102,8 @@
 
     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:
@@ -1045,25 +1111,22 @@
                 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)
-            index = self.series_end() + i
+                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)
             self.ui.warn("adding %s to series file\n" % patch)
@@ -1144,14 +1207,16 @@
 def new(ui, repo, patch, **opts):
     """create a new patch"""
     q = repomap[repo]
-    q.new(repo, patch, msg=opts['message'], force=opts['force'])
+    message=commands.logmessage(**opts)
+    q.new(repo, patch, msg=message, force=opts['force'])
     q.save_dirty()
     return 0
 
 def refresh(ui, repo, **opts):
     """update the current patch"""
     q = repomap[repo]
-    q.refresh(repo, short=opts['short'])
+    message=commands.logmessage(**opts)
+    q.refresh(repo, msg=message, short=opts['short'])
     q.save_dirty()
     return 0
 
@@ -1216,9 +1281,7 @@
         localupdate = False
     else:
         q = repomap[repo]
-    if opts['all'] and len(q.applied) > 0:
-        patch = q.applied[0].split(':')[1]
-    q.pop(repo, patch, force=opts['force'], update=localupdate)
+    q.pop(repo, patch, force=opts['force'], update=localupdate, all=opts['all'])
     q.save_dirty()
     return 0
 
@@ -1234,7 +1297,8 @@
 def save(ui, repo, **opts):
     """save current queue state"""
     q = repomap[repo]
-    ret = q.save(repo, msg=opts['message'])
+    message=commands.logmessage(**opts)
+    ret = q.save(repo, msg=message)
     if ret:
         return ret
     q.save_dirty()
@@ -1244,13 +1308,11 @@
             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))
@@ -1325,9 +1387,10 @@
          'hg qinit [-c]'),
     "qnew":
         (new,
-         [('m', 'message', '', 'commit message'),
+         [('m', 'message', '', _('use <text> as commit message')),
+          ('l', 'logfile', '', _('read the commit message from <file>')),
           ('f', 'force', None, 'force')],
-         'hg qnew [-m TEXT] [-f] PATCH'),
+         'hg qnew [-m TEXT] [-l FILE] [-f] PATCH'),
     "qnext": (next, [], 'hg qnext'),
     "qprev": (prev, [], 'hg qprev'),
     "^qpop":
@@ -1346,8 +1409,10 @@
          'hg qpush [-f] [-l] [-a] [-m] [-n NAME] [PATCH | INDEX]'),
     "^qrefresh":
         (refresh,
-         [('s', 'short', None, 'short refresh')],
-         'hg qrefresh [-s]'),
+         [('m', 'message', '', _('change commit message with <text>')),
+          ('l', 'logfile', '', _('change commit message with <file> content')),
+          ('s', 'short', None, 'short refresh')],
+         'hg qrefresh [-m TEXT] [-l FILE] [-s]'),
     "qrestore":
         (restore,
          [('d', 'delete', None, 'delete save entry'),
@@ -1355,12 +1420,13 @@
          'hg qrestore [-d] [-u] REV'),
     "qsave":
         (save,
-         [('m', 'message', '', 'commit message'),
+         [('m', 'message', '', _('use <text> as commit message')),
+          ('l', 'logfile', '', _('read the commit message from <file>')),
           ('c', 'copy', None, 'copy patch directory'),
           ('n', 'name', '', 'copy directory name'),
           ('e', 'empty', None, 'clear queue status file'),
           ('f', 'force', None, 'force copy')],
-         'hg qsave [-m TEXT] [-c] [-n NAME] [-e] [-f]'),
+         'hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]'),
     "qseries":
         (series,
          [('m', 'missing', None, 'print patches not in series')],
--- a/hgext/patchbomb.py	Thu Jul 27 19:26:01 2006 +0200
+++ b/hgext/patchbomb.py	Fri Jul 28 09:01:13 2006 +0200
@@ -45,6 +45,7 @@
                          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 @@
             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:
@@ -193,8 +212,7 @@
     if len(patches) > 1:
         ui.write(_('\nWrite the introductory message for the patch series.\n\n'))
 
-        msg = email.MIMEMultipart.MIMEMultipart()
-        msg['Subject'] = '[PATCH 0 of %d] %s' % (
+        subj = '[PATCH 0 of %d] %s' % (
             len(patches),
             opts['subject'] or
             prompt('Subject:', rest = ' [PATCH 0 of %d] ' % len(patches)))
@@ -209,11 +227,14 @@
             if l == '.': break
             body.append(l)
 
-        msg.attach(email.MIMEText.MIMEText('\n'.join(body) + '\n'))
-
         if opts['diffstat']:
             d = cdiffstat(_('Final summary:\n'), jumbo)
-            if d: msg.attach(email.MIMEText.MIMEText(d))
+            if d: body.append('\n' + d)
+
+        body = '\n'.join(body) + '\n'
+
+        msg = email.MIMEText.MIMEText(body)
+        msg['Subject'] = subj
 
         msgs.insert(0, msg)
 
@@ -272,7 +293,8 @@
 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/mercurial/commands.py	Thu Jul 27 19:26:01 2006 +0200
+++ b/mercurial/commands.py	Fri Jul 28 09:01:13 2006 +0200
@@ -40,6 +40,25 @@
         return [util.normpath(os.path.join(cwd, x)) for x in args]
     return args
 
+def logmessage(**opts):
+    """ get the log message according to -m and -l option """
+    message = opts['message']
+    logfile = opts['logfile']
+
+    if message and logfile:
+        raise util.Abort(_('options --message and --logfile are mutually '
+                           'exclusive'))
+    if not message and logfile:
+        try:
+            if logfile == '-':
+                message = sys.stdin.read()
+            else:
+                message = open(logfile).read()
+        except IOError, inst:
+            raise util.Abort(_("can't read commit message '%s': %s") %
+                             (logfile, inst.strerror))
+    return message
+
 def matchpats(repo, pats=[], opts={}, head=''):
     cwd = repo.getcwd()
     if not pats and cwd:
@@ -989,21 +1008,7 @@
     If no commit message is specified, the editor configured in your hgrc
     or in the EDITOR environment variable is started to enter a message.
     """
-    message = opts['message']
-    logfile = opts['logfile']
-
-    if message and logfile:
-        raise util.Abort(_('options --message and --logfile are mutually '
-                           'exclusive'))
-    if not message and logfile:
-        try:
-            if logfile == '-':
-                message = sys.stdin.read()
-            else:
-                message = open(logfile).read()
-        except IOError, inst:
-            raise util.Abort(_("can't read commit message '%s': %s") %
-                             (logfile, inst.strerror))
+    message = logmessage(**opts)
 
     if opts['addremove']:
         addremove_lock(ui, repo, pats, opts)
--- a/tests/run-tests.py	Thu Jul 27 19:26:01 2006 +0200
+++ b/tests/run-tests.py	Fri Jul 28 09:01:13 2006 +0200
@@ -201,6 +201,11 @@
     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 @@
     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)
@@ -244,7 +262,7 @@
         ref_out = splitnewlines(f.read())
         f.close()
     else:
-        ref_out = ['']
+        ref_out = []
     if out != ref_out:
         diffret = 1
         print "\nERROR: %s output changed" % (test)
@@ -330,16 +348,23 @@
 
         tests = 0
         failed = 0
+        skipped = 0
 
         if len(args) == 0:
             args = os.listdir(".")
         for test in args:
-            if test.startswith("test-") and not '~' in test and not '.' in test:
-                if not run_one(test):
+            if (test.startswith("test-") and '~' not in test and
+                ('.' not in test or test.endswith('.py') or 
+                 test.endswith('.bat'))):
+                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:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-mq-qnew-twice	Fri Jul 28 09:01:13 2006 +0200
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-mq-qnew-twice.out	Fri Jul 28 09:01:13 2006 +0200
@@ -0,0 +1,2 @@
+abort: patch "first.patch" already exists
+abort: patch "first.patch" already exists
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-mq-qrefresh-replace-log-message	Fri Jul 28 09:01:13 2006 +0200
@@ -0,0 +1,51 @@
+#!/bin/sh
+
+# Environement setup for MQ
+HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
+echo "[extensions]" >> $HGTMP/.hgrc
+echo "mq=" >> $HGTMP/.hgrc
+
+#Repo init
+hg init
+hg qinit
+
+hg qnew -m "First commit message" first-patch
+echo aaaa > file
+hg add file
+hg qrefresh
+echo =======================
+echo "Should display 'First commit message'"
+hg log -l1 -v | sed -n '/description/,$p'
+echo
+
+# Testing changing message with -m
+echo bbbb > file
+hg qrefresh -m "Second commit message" 
+echo =======================
+echo "Should display 'Second commit message'"
+hg log -l1 -v | sed -n '/description/,$p'
+echo
+
+
+# Testing changing message with -l
+echo "Third commit message" > logfile
+echo " This is the 3rd log message" >> logfile
+echo bbbb > file
+hg qrefresh -l logfile
+echo =======================
+echo "Should display 'Third commit message\n This is the 3rd log message'"
+hg log -l1 -v | sed -n '/description/,$p'
+echo
+
+# Testing changing message with -l-
+hg qnew -m "First commit message" second-patch
+echo aaaa > file2
+hg add file2
+echo bbbb > file2
+(echo "Fifth commit message" 
+echo " This is the 5th log message" >> logfile) |\
+hg qrefresh -l-
+echo =======================
+echo "Should display 'Fifth commit message\n This is the 5th log message'"
+hg log -l1 -v | sed -n '/description/,$p'
+echo
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-mq-qrefresh-replace-log-message.out	Fri Jul 28 09:01:13 2006 +0200
@@ -0,0 +1,29 @@
+=======================
+Should display 'First commit message'
+description:
+First commit message
+
+
+
+=======================
+Should display 'Second commit message'
+description:
+Second commit message
+
+
+
+=======================
+Should display 'Third commit message\n This is the 3rd log message'
+description:
+Third commit message
+ This is the 3rd log message
+
+
+
+=======================
+Should display 'Fifth commit message\n This is the 5th log message'
+description:
+Fifth commit message
+
+
+