--- a/contrib/buildrpm Sat Jun 20 18:58:34 2009 +0200
+++ b/contrib/buildrpm Sun Jun 21 19:06:57 2009 +0200
@@ -1,19 +1,19 @@
#!/bin/sh
#
# Build a Mercurial RPM in place.
-# Known to work on:
-# - Fedora 9
-# - Fedora 10
#
# Bryan O'Sullivan <bos@serpentine.com>
+#
+# Tested on
+# - Fedora 10
+# - Fedora 11
+# - Centos 5.3 (with Fedora EPEL repo for asciidoc)
-if hg --version > /dev/null 2>&1; then :
-else
- echo 'hg command not available!' 1>&2
- exit 1
-fi
+HG="`dirname $0`/../hg"
+PYTHONPATH="`dirname $0`/../mercurial/pure"
+export PYTHONPATH
-root="`hg root 2>/dev/null`"
+root="`$HG root 2>/dev/null`"
specfile=contrib/mercurial.spec
if [ -z "$root" ]; then
@@ -26,7 +26,7 @@
cd "$root"
rm -rf $rpmdir
mkdir -p $rpmdir/RPMS
-hg clone "$root" $rpmdir/BUILD
+$HG clone "$root" $rpmdir/BUILD
if [ ! -f $specfile ]; then
echo "Cannot find $specfile!" 1>&2
@@ -35,11 +35,11 @@
tmpspec=/tmp/`basename "$specfile"`.$$ # FIXME: Insecure /tmp handling
# Use the most recent tag as the version.
-version=`hg tags | perl -e 'while(<STDIN>){if(/^(\d\S+)/){print$1;exit}}'`
+version=`$HG tags | python -c 'import sys; print [l for l in sys.stdin.readlines() if l[0].isdigit()][0].split()[0]'`
# Compute the release number as the difference in revision numbers
# between the tip and the most recent tag.
-release=`hg tags | perl -e 'while(<STDIN>){($tag,$id)=/^(\S+)\s+(\d+)/;if($tag eq "tip"){$tip = $id}elsif($tag=~/^\d/){print $tip-$id+1;exit}}'`
-tip=`hg -q tip`
+release=`$HG tags | python -c 'import sys; l = sys.stdin.readlines(); print int(l[0].split()[1].split(":")[0]) - int([x for x in l if x[0].isdigit()][0].split()[1].split(":")[0])'`
+tip=`$HG -q tip`
# Beat up the spec file
sed -e 's,^Source:.*,Source: /dev/null,' \
@@ -51,11 +51,11 @@
cat <<EOF >> $tmpspec
%changelog
-* `date +'%a %b %d %Y'` `hg showconfig ui.username` $version-$release
+* `date +'%a %b %d %Y'` `$HG showconfig ui.username` $version-$release
- Automatically built via $0
EOF
-hg log \
+$HG log \
--template '* {date|rfc822date} {author}\n- {desc|firstline}\n\n' \
.hgtags \
| sed -e 's/^\(\* [MTWFS][a-z][a-z]\), \([0-3][0-9]\) \([A-Z][a-z][a-z]\) /\1 \3 \2 /' \
--- a/contrib/mercurial.spec Sat Jun 20 18:58:34 2009 +0200
+++ b/contrib/mercurial.spec Sun Jun 21 19:06:57 2009 +0200
@@ -71,6 +71,8 @@
%{_bindir}/hg-viz
%{_bindir}/git-rev-tree
%{_bindir}/mercurial-convert-repo
-%{_libdir}/python%{pythonver}/site-packages/%{name}-*-py2.5.egg-info
+%if "%{?pythonver}" != "2.4"
+%{_libdir}/python%{pythonver}/site-packages/%{name}-*-py%{pythonver}.egg-info
+%endif
%{pythonlib}
%{hgext}
--- a/contrib/perf.py Sat Jun 20 18:58:34 2009 +0200
+++ b/contrib/perf.py Sun Jun 21 19:06:57 2009 +0200
@@ -1,4 +1,5 @@
# perf.py - performance test routines
+'''helper extension to measure performance'''
from mercurial import cmdutil, match, commands
import time, os, sys
--- a/doc/hgrc.5.txt Sat Jun 20 18:58:34 2009 +0200
+++ b/doc/hgrc.5.txt Sun Jun 21 19:06:57 2009 +0200
@@ -142,6 +142,11 @@
foo.password = bar
foo.schemes = http https
+ bar.prefix = secure.example.org
+ bar.key = path/to/file.key
+ bar.cert = path/to/file.cert
+ bar.schemes = https
+
Supported arguments:
prefix;;
@@ -152,10 +157,17 @@
against the URI with its scheme stripped as well, and the schemes
argument, q.v., is then subsequently consulted.
username;;
- Username to authenticate with.
+ Optional. Username to authenticate with. If not given, and the
+ remote site requires basic or digest authentication, the user
+ will be prompted for it.
password;;
- Optional. Password to authenticate with. If not given the user
+ Optional. Password to authenticate with. If not given, and the
+ remote site requires basic or digest authentication, the user
will be prompted for it.
+ key;;
+ Optional. PEM encoded client certificate key file.
+ cert;;
+ Optional. PEM encoded client certificate chain file.
schemes;;
Optional. Space separated list of URI schemes to use this
authentication entry with. Only used if the prefix doesn't include
--- a/hgext/acl.py Sat Jun 20 18:58:34 2009 +0200
+++ b/hgext/acl.py Sun Jun 21 19:06:57 2009 +0200
@@ -5,49 +5,49 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2, incorporated herein by reference.
#
-# this hook allows to allow or deny access to parts of a repo when
-# taking incoming changesets.
-#
-# authorization is against local user name on system where hook is
-# run, not committer of original changeset (since that is easy to
-# spoof).
-#
-# acl hook is best to use if you use hgsh to set up restricted shells
-# for authenticated users to only push to / pull from. not safe if
-# user has interactive shell access, because they can disable hook.
-# also not safe if remote users share one local account, because then
-# no way to tell remote users apart.
-#
-# to use, configure acl extension in hgrc like this:
-#
-# [extensions]
-# hgext.acl =
-#
-# [hooks]
-# pretxnchangegroup.acl = python:hgext.acl.hook
-#
-# [acl]
-# sources = serve # check if source of incoming changes in this list
-# # ("serve" == ssh or http, "push", "pull", "bundle")
-#
-# allow and deny lists have subtree pattern (default syntax is glob)
-# on left, user names on right. deny list checked before allow list.
-#
-# [acl.allow]
-# # if acl.allow not present, all users allowed by default
-# # empty acl.allow = no users allowed
-# docs/** = doc_writer
-# .hgtags = release_engineer
-#
-# [acl.deny]
-# # if acl.deny not present, no users denied by default
-# # empty acl.deny = all users allowed
-# glob pattern = user4, user5
-# ** = user6
+
+'''provide simple hooks for access control
+
+Authorization is against local user name on system where hook is run, not
+committer of original changeset (since that is easy to spoof).
+
+The acl hook is best to use if you use hgsh to set up restricted shells for
+authenticated users to only push to / pull from. It's not safe if user has
+interactive shell access, because they can disable the hook. It's also not
+safe if remote users share one local account, because then there's no way to
+tell remote users apart.
+
+To use, configure the acl extension in hgrc like this:
+
+ [extensions]
+ hgext.acl =
+
+ [hooks]
+ pretxnchangegroup.acl = python:hgext.acl.hook
+
+ [acl]
+ sources = serve # check if source of incoming changes in this list
+ # ("serve" == ssh or http, "push", "pull", "bundle")
+
+Allow and deny lists have a subtree pattern (default syntax is glob) on the
+left and user names on right. The deny list is checked before the allow list.
+
+ [acl.allow]
+ # if acl.allow not present, all users allowed by default
+ # empty acl.allow = no users allowed
+ docs/** = doc_writer
+ .hgtags = release_engineer
+
+ [acl.deny]
+ # if acl.deny not present, no users denied by default
+ # empty acl.deny = all users allowed
+ glob pattern = user4, user5
+ ** = user6
+'''
from mercurial.i18n import _
from mercurial import util, match
-import getpass
+import getpass, urllib
def buildmatch(ui, repo, user, key):
'''return tuple of (match function, list enabled).'''
@@ -72,7 +72,15 @@
ui.debug(_('acl: changes have source "%s" - skipping\n') % source)
return
- user = getpass.getuser()
+ user = None
+ if source == 'serve' and 'url' in kwargs:
+ url = kwargs['url'].split(':')
+ if url[0] == 'remote' and url[1].startswith('http'):
+ user = urllib.unquote(url[2])
+
+ if user is None:
+ user = getpass.getuser()
+
cfg = ui.config('acl', 'config')
if cfg:
ui.readconfig(cfg, sections = ['acl.allow', 'acl.deny'])
--- a/hgext/bookmarks.py Sat Jun 20 18:58:34 2009 +0200
+++ b/hgext/bookmarks.py Sun Jun 21 19:06:57 2009 +0200
@@ -64,10 +64,14 @@
util.copyfile(repo.join('bookmarks'), repo.join('undo.bookmarks'))
if current(repo) not in refs:
setcurrent(repo, None)
- file = repo.opener('bookmarks', 'w+')
- for refspec, node in refs.iteritems():
- file.write("%s %s\n" % (hex(node), refspec))
- file.close()
+ wlock = repo.wlock()
+ try:
+ file = repo.opener('bookmarks', 'w', atomictemp=True)
+ for refspec, node in refs.iteritems():
+ file.write("%s %s\n" % (hex(node), refspec))
+ file.rename()
+ finally:
+ wlock.release()
def current(repo):
'''Get the current bookmark
@@ -106,9 +110,13 @@
return
if mark not in refs:
mark = ''
- file = repo.opener('bookmarks.current', 'w+')
- file.write(mark)
- file.close()
+ wlock = repo.wlock()
+ try:
+ file = repo.opener('bookmarks.current', 'w', atomictemp=True)
+ file.write(mark)
+ file.rename()
+ finally:
+ wlock.release()
repo._bookmarkcurrent = mark
def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False, rename=None):
@@ -242,26 +250,30 @@
def commit(self, *k, **kw):
"""Add a revision to the repository and
move the bookmark"""
- node = super(bookmark_repo, self).commit(*k, **kw)
- if node is None:
- return None
- parents = repo.changelog.parents(node)
- if parents[1] == nullid:
- parents = (parents[0],)
- marks = parse(repo)
- update = False
- for mark, n in marks.items():
- if ui.configbool('bookmarks', 'track.current'):
- if mark == current(repo) and n in parents:
- marks[mark] = node
- update = True
- else:
- if n in parents:
- marks[mark] = node
- update = True
- if update:
- write(repo, marks)
- return node
+ wlock = self.wlock() # do both commit and bookmark with lock held
+ try:
+ node = super(bookmark_repo, self).commit(*k, **kw)
+ if node is None:
+ return None
+ parents = repo.changelog.parents(node)
+ if parents[1] == nullid:
+ parents = (parents[0],)
+ marks = parse(repo)
+ update = False
+ for mark, n in marks.items():
+ if ui.configbool('bookmarks', 'track.current'):
+ if mark == current(repo) and n in parents:
+ marks[mark] = node
+ update = True
+ else:
+ if n in parents:
+ marks[mark] = node
+ update = True
+ if update:
+ write(repo, marks)
+ return node
+ finally:
+ wlock.release()
def addchangegroup(self, source, srctype, url, emptyok=False):
parents = repo.dirstate.parents()
--- a/hgext/children.py Sat Jun 20 18:58:34 2009 +0200
+++ b/hgext/children.py Sun Jun 21 19:06:57 2009 +0200
@@ -8,6 +8,8 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2, incorporated herein by reference.
+'''provides children command to show children changesets'''
+
from mercurial import cmdutil
from mercurial.commands import templateopts
from mercurial.i18n import _
--- a/hgext/churn.py Sat Jun 20 18:58:34 2009 +0200
+++ b/hgext/churn.py Sun Jun 21 19:06:57 2009 +0200
@@ -120,7 +120,7 @@
It is possible to map alternate email addresses to a main address
by providing a file using the following format:
-
+
<alias email> <actual email>
Such a file may be specified with the --aliases option, otherwise a
--- a/hgext/color.py Sat Jun 20 18:58:34 2009 +0200
+++ b/hgext/color.py Sun Jun 21 19:06:57 2009 +0200
@@ -29,10 +29,6 @@
function (aka ANSI escape codes). This module also provides the
render_text function, which can be used to add effects to any text.
-To enable this extension, add this to your .hgrc file:
-[extensions]
-color =
-
Default effects may be overridden from the .hgrc file:
[color]
--- a/hgext/convert/convcmd.py Sat Jun 20 18:58:34 2009 +0200
+++ b/hgext/convert/convcmd.py Sun Jun 21 19:06:57 2009 +0200
@@ -80,7 +80,7 @@
self.authorfile = None
# Record converted revisions persistently: maps source revision
- # ID to target revision ID (both strings). (This is how
+ # ID to target revision ID (both strings). (This is how
# incremental conversions work.)
self.map = mapfile(ui, revmapfile)
@@ -297,7 +297,7 @@
parents = [self.map.get(p, p) for p in parents]
except KeyError:
parents = [b[0] for b in pbranches]
- newnode = self.dest.putcommit(files, copies, parents, commit,
+ newnode = self.dest.putcommit(files, copies, parents, commit,
self.source, self.map)
self.source.converted(rev, newnode)
self.map[rev] = newnode
--- a/hgext/convert/p4.py Sat Jun 20 18:58:34 2009 +0200
+++ b/hgext/convert/p4.py Sun Jun 21 19:06:57 2009 +0200
@@ -159,7 +159,7 @@
if code == "error":
raise IOError(d["generic"], data)
-
+
elif code == "stat":
p4type = self.re_type.match(d["type"])
if p4type:
@@ -173,7 +173,7 @@
keywords = self.re_keywords_old
elif "k" in flags:
keywords = self.re_keywords
-
+
elif code == "text" or code == "binary":
contents += data
--- a/hgext/convert/subversion.py Sat Jun 20 18:58:34 2009 +0200
+++ b/hgext/convert/subversion.py Sun Jun 21 19:06:57 2009 +0200
@@ -472,7 +472,7 @@
# Here/tags/tag.1 discarded as well as its children.
# It happens with tools like cvs2svn. Such tags cannot
# be represented in mercurial.
- addeds = dict((p, e.copyfrom_path) for p,e
+ addeds = dict((p, e.copyfrom_path) for p, e
in origpaths.iteritems() if e.action == 'A')
badroots = set()
for destroot in addeds:
@@ -484,7 +484,7 @@
break
for badroot in badroots:
- pendings = [p for p in pendings if p[2] != badroot
+ pendings = [p for p in pendings if p[2] != badroot
and not p[2].startswith(badroot + '/')]
# Tell tag renamings from tag creations
@@ -497,7 +497,7 @@
if tagname in tags:
# Keep the latest tag value
continue
- # From revision may be fake, get one with changes
+ # From revision may be fake, get one with changes
try:
tagid = self.latest(source, sourcerev)
if tagid and tagname not in tags:
--- a/hgext/extdiff.py Sat Jun 20 18:58:34 2009 +0200
+++ b/hgext/extdiff.py Sun Jun 21 19:06:57 2009 +0200
@@ -5,18 +5,14 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2, incorporated herein by reference.
-'''
+'''allow external programs to compare revisions
+
The `extdiff' Mercurial extension allows you to use external programs
to compare revisions, or revision with working directory. The external diff
programs are called with a configurable set of options and two
non-option arguments: paths to directories containing snapshots of
files to compare.
-To enable this extension:
-
- [extensions]
- hgext.extdiff =
-
The `extdiff' extension also allows to configure new diff commands, so
you do not need to type "hg extdiff -p kdiff3" always.
--- a/hgext/gpg.py Sat Jun 20 18:58:34 2009 +0200
+++ b/hgext/gpg.py Sun Jun 21 19:06:57 2009 +0200
@@ -1,10 +1,10 @@
-# GnuPG signing extension for Mercurial
-#
# Copyright 2005, 2006 Benoit Boissinot <benoit.boissinot@ens-lyon.org>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2, incorporated herein by reference.
+'''GnuPG signing extension for Mercurial'''
+
import os, tempfile, binascii
from mercurial import util, commands, match
from mercurial import node as hgnode
--- a/hgext/graphlog.py Sat Jun 20 18:58:34 2009 +0200
+++ b/hgext/graphlog.py Sun Jun 21 19:06:57 2009 +0200
@@ -12,59 +12,32 @@
revision graph is also shown.
'''
-import os
+import os, sys
from mercurial.cmdutil import revrange, show_changeset
from mercurial.commands import templateopts
from mercurial.i18n import _
from mercurial.node import nullrev
from mercurial import bundlerepo, changegroup, cmdutil, commands, extensions
-from mercurial import hg, url, util
-
-def revisions(repo, start, stop):
- """cset DAG generator yielding (rev, node, [parents]) tuples
+from mercurial import hg, url, util, graphmod
- This generator function walks through the revision history from revision
- start to revision stop (which must be less than or equal to start).
- """
- assert start >= stop
- cur = start
- while cur >= stop:
- ctx = repo[cur]
- parents = [p.rev() for p in ctx.parents() if p.rev() != nullrev]
- parents.sort()
- yield (ctx, parents)
- cur -= 1
-
-def filerevs(repo, path, start, stop):
- """file cset DAG generator yielding (rev, node, [parents]) tuples
+ASCIIDATA = 'ASC'
- This generator function walks through the revision history of a single
- file from revision start to revision stop (which must be less than or
- equal to start).
- """
- assert start >= stop
- filerev = len(repo.file(path)) - 1
- while filerev >= 0:
- fctx = repo.filectx(path, fileid=filerev)
- parents = [f.linkrev() for f in fctx.parents() if f.path() == path]
- parents.sort()
- if fctx.rev() <= start:
- yield (fctx, parents)
- if fctx.rev() <= stop:
- break
- filerev -= 1
+def asciiformat(ui, repo, revdag, opts):
+ """formats a changelog DAG walk for ASCII output"""
+ showparents = [ctx.node() for ctx in repo[None].parents()]
+ displayer = show_changeset(ui, repo, opts, buffered=True)
+ for (id, type, ctx, parentids) in revdag:
+ if type != graphmod.CHANGESET:
+ continue
+ displayer.show(ctx)
+ lines = displayer.hunk.pop(ctx.rev()).split('\n')[:-1]
+ char = ctx.node() in showparents and '@' or 'o'
+ yield (id, ASCIIDATA, (char, lines), parentids)
-def grapher(nodes):
- """grapher for asciigraph on a list of nodes and their parents
-
- nodes must generate tuples (node, parents, char, lines) where
- - parents must generate the parents of node, in sorted order,
- and max length 2,
- - char is the char to print as the node symbol, and
- - lines are the lines to display next to the node.
- """
+def asciiedges(nodes):
+ """adds edge info to changelog DAG walk suitable for ascii()"""
seen = []
- for node, parents, char, lines in nodes:
+ for node, type, data, parents in nodes:
if node not in seen:
seen.append(node)
nodeidx = seen.index(node)
@@ -88,7 +61,7 @@
edges.append((nodeidx, nodeidx + 1))
nmorecols = len(nextseen) - ncols
seen = nextseen
- yield (char, lines, nodeidx, edges, ncols, nmorecols)
+ yield (nodeidx, type, data, edges, ncols, nmorecols)
def fix_long_right_edges(edges):
for (i, (start, end)) in enumerate(edges):
@@ -142,14 +115,16 @@
line.extend(["|", " "] * (n_columns - ni - 1))
return line
-def ascii(ui, grapher):
- """prints an ASCII graph of the DAG returned by the grapher
+def ascii(ui, dag):
+ """prints an ASCII graph of the DAG
+
+ dag is a generator that emits tuples with the following elements:
- grapher is a generator that emits tuples with the following elements:
-
- - Character to use as node's symbol.
- - List of lines to display as the node's text.
- Column of the current node in the set of ongoing edges.
+ - Type indicator of node data == ASCIIDATA.
+ - Payload: (char, lines):
+ - Character to use as node's symbol.
+ - List of lines to display as the node's text.
- Edges; a list of (col, next_col) indicating the edges between
the current node and its parents.
- Number of columns (ongoing edges) in the current revision.
@@ -160,7 +135,7 @@
"""
prev_n_columns_diff = 0
prev_node_index = 0
- for (node_ch, node_lines, node_index, edges, n_columns, n_columns_diff) in grapher:
+ for (node_index, type, (node_ch, node_lines), edges, n_columns, n_columns_diff) in dag:
assert -2 < n_columns_diff < 2
if n_columns_diff == -1:
@@ -278,34 +253,19 @@
if path:
path = util.canonpath(repo.root, os.getcwd(), path)
if path: # could be reset in canonpath
- revdag = filerevs(repo, path, start, stop)
+ revdag = graphmod.filerevs(repo, path, start, stop)
else:
- revdag = revisions(repo, start, stop)
+ revdag = graphmod.revisions(repo, start, stop)
- graphdag = graphabledag(ui, repo, revdag, opts)
- ascii(ui, grapher(graphdag))
+ fmtdag = asciiformat(ui, repo, revdag, opts)
+ ascii(ui, asciiedges(fmtdag))
def graphrevs(repo, nodes, opts):
- include = set(nodes)
limit = cmdutil.loglimit(opts)
- count = 0
- for node in reversed(nodes):
- if count >= limit:
- break
- ctx = repo[node]
- parents = [p.rev() for p in ctx.parents() if p.node() in include]
- parents.sort()
- yield (ctx, parents)
- count += 1
-
-def graphabledag(ui, repo, revdag, opts):
- showparents = [ctx.node() for ctx in repo[None].parents()]
- displayer = show_changeset(ui, repo, opts, buffered=True)
- for (ctx, parents) in revdag:
- displayer.show(ctx)
- lines = displayer.hunk.pop(ctx.rev()).split('\n')[:-1]
- char = ctx.node() in showparents and '@' or 'o'
- yield (ctx.rev(), parents, char, lines)
+ nodes.reverse()
+ if limit < sys.maxint:
+ nodes = nodes[:limit]
+ return graphmod.nodes(repo, nodes)
def goutgoing(ui, repo, dest=None, **opts):
"""show the outgoing changesets alongside an ASCII revision graph
@@ -332,8 +292,8 @@
o = repo.changelog.nodesbetween(o, revs)[0]
revdag = graphrevs(repo, o, opts)
- graphdag = graphabledag(ui, repo, revdag, opts)
- ascii(ui, grapher(graphdag))
+ fmtdag = asciiformat(ui, repo, revdag, opts)
+ ascii(ui, asciiedges(fmtdag))
def gincoming(ui, repo, source="default", **opts):
"""show the incoming changesets alongside an ASCII revision graph
@@ -381,8 +341,8 @@
chlist = other.changelog.nodesbetween(incoming, revs)[0]
revdag = graphrevs(other, chlist, opts)
- graphdag = graphabledag(ui, repo, revdag, opts)
- ascii(ui, grapher(graphdag))
+ fmtdag = asciiformat(ui, repo, revdag, opts)
+ ascii(ui, asciiedges(fmtdag))
finally:
if hasattr(other, 'close'):
--- a/hgext/hgk.py Sat Jun 20 18:58:34 2009 +0200
+++ b/hgext/hgk.py Sun Jun 21 19:06:57 2009 +0200
@@ -14,20 +14,8 @@
hgk consists of two parts: a Tcl script that does the displaying and
querying of information, and an extension to Mercurial named hgk.py,
which provides hooks for hgk to get information. hgk can be found in
-the contrib directory, and hgk.py can be found in the hgext directory.
-
-To load the hgext.py extension, add it to your .hgrc file (you have to
-use your global $HOME/.hgrc file, not one in a repository). You can
-specify an absolute path:
-
- [extensions]
- hgk=/usr/local/lib/hgk.py
-
-Mercurial can also scan the default python library path for a file
-named 'hgk.py' if you set hgk empty:
-
- [extensions]
- hgk=
+the contrib directory, and the extension is shipped in the hgext
+repository, and needs to be enabled.
The hg view command will launch the hgk Tcl script. For this command
to work, hgk must be in your search path. Alternately, you can specify
--- a/hgext/highlight/__init__.py Sat Jun 20 18:58:34 2009 +0200
+++ b/hgext/highlight/__init__.py Sun Jun 21 19:06:57 2009 +0200
@@ -13,11 +13,6 @@
It depends on the Pygments syntax highlighting library:
http://pygments.org/
-To enable the extension add this to hgrc:
-
-[extensions]
-hgext.highlight =
-
There is a single configuration option:
[web]
@@ -30,10 +25,10 @@
import highlight
from mercurial.hgweb import webcommands, webutil, common
-from mercurial import extensions
+from mercurial import extensions, encoding
def filerevision_highlight(orig, web, tmpl, fctx):
- mt = ''.join(tmpl('mimetype', encoding=web.encoding))
+ mt = ''.join(tmpl('mimetype', encoding=encoding.encoding))
# only pygmentize for mimetype containing 'html' so we both match
# 'text/html' and possibly 'application/xhtml+xml' in the future
# so that we don't have to touch the extension when the mimetype
@@ -47,7 +42,7 @@
return orig(web, tmpl, fctx)
def annotate_highlight(orig, web, req, tmpl):
- mt = ''.join(tmpl('mimetype', encoding=web.encoding))
+ mt = ''.join(tmpl('mimetype', encoding=encoding.encoding))
if 'html' in mt:
fctx = webutil.filectx(web.repo, req)
style = web.config('web', 'pygments_style', 'colorful')
--- a/hgext/interhg.py Sat Jun 20 18:58:34 2009 +0200
+++ b/hgext/interhg.py Sun Jun 21 19:06:57 2009 +0200
@@ -14,12 +14,8 @@
which will be automatically expanded into links or any other
arbitrary expression, much like InterWiki does.
-To enable this extension, add the following lines to your hgrc:
-
- [extensions]
- interhg =
-
-A few example patterns (link to bug tracking, etc.):
+A few example patterns (link to bug tracking, etc.) that may
+be used in your hgrc:
[interhg]
issues = s!issue(\\d+)!<a href="http://bts/issue\\1">issue\\1</a>!
--- a/hgext/keyword.py Sat Jun 20 18:58:34 2009 +0200
+++ b/hgext/keyword.py Sun Jun 21 19:06:57 2009 +0200
@@ -21,12 +21,6 @@
#
# Binary files are not touched.
#
-# Setup in hgrc:
-#
-# [extensions]
-# # enable extension
-# hgext.keyword =
-#
# Files to act upon/ignore are specified in the [keyword] section.
# Customized keyword template mappings in the [keywordmaps] section.
#
--- a/hgext/mq.py Sat Jun 20 18:58:34 2009 +0200
+++ b/hgext/mq.py Sun Jun 21 19:06:57 2009 +0200
@@ -543,6 +543,8 @@
def _apply(self, repo, series, list=False, update_status=True,
strict=False, patchdir=None, merge=None, all_files={}):
+ '''returns (error, hash)
+ error = 1 for unable to read, 2 for patch failed, 3 for patch fuzz'''
# TODO unify with commands.py
if not patchdir:
patchdir = self.path
@@ -559,7 +561,7 @@
try:
ph = patchheader(self.join(patchname))
except:
- self.ui.warn(_("Unable to read %s\n") % patchname)
+ self.ui.warn(_("unable to read %s\n") % patchname)
err = 1
break
@@ -607,46 +609,60 @@
if patcherr:
self.ui.warn(_("patch failed, rejects left in working dir\n"))
- err = 1
+ err = 2
break
if fuzz and strict:
self.ui.warn(_("fuzz found when applying patch, stopping\n"))
- err = 1
+ err = 3
break
return (err, n)
- def _clean_series(self, patches):
+ def _cleanup(self, patches, numrevs, keep=False):
+ if not keep:
+ r = self.qrepo()
+ if r:
+ r.remove(patches, True)
+ else:
+ for p in patches:
+ os.unlink(self.join(p))
+
+ if numrevs:
+ del self.applied[:numrevs]
+ self.applied_dirty = 1
+
for i in sorted([self.find_series(p) for p in patches], reverse=True):
del self.full_series[i]
self.parse_series()
self.series_dirty = 1
- def finish(self, repo, revs):
+ def _revpatches(self, repo, revs):
firstrev = repo[self.applied[0].rev].rev()
- appliedbase = 0
patches = []
- for rev in sorted(revs):
+ for i, rev in enumerate(revs):
+
if rev < firstrev:
raise util.Abort(_('revision %d is not managed') % rev)
- base = bin(self.applied[appliedbase].rev)
- node = repo.changelog.node(rev)
- if node != base:
- raise util.Abort(_('cannot delete revision %d above '
- 'applied patches') % rev)
- patches.append(self.applied[appliedbase].name)
- appliedbase += 1
+
+ ctx = repo[rev]
+ base = bin(self.applied[i].rev)
+ if ctx.node() != base:
+ msg = _('cannot delete revision %d above applied patches')
+ raise util.Abort(msg % rev)
- r = self.qrepo()
- if r:
- r.remove(patches, True)
- else:
- for p in patches:
- os.unlink(self.join(p))
+ patch = self.applied[i].name
+ for fmt in ('[mq]: %s', 'imported patch %s'):
+ if ctx.description() == fmt % patch:
+ msg = _('patch %s finalized without changeset message\n')
+ repo.ui.status(msg % patch)
+ break
- del self.applied[:appliedbase]
- self.applied_dirty = 1
- self._clean_series(patches)
+ patches.append(patch)
+ return patches
+
+ def finish(self, repo, revs):
+ patches = self._revpatches(repo, sorted(revs))
+ self._cleanup(patches, len(patches))
def delete(self, repo, patches, opts):
if not patches and not opts.get('rev'):
@@ -663,37 +679,18 @@
raise util.Abort(_("patch %s not in series file") % patch)
realpatches.append(patch)
- appliedbase = 0
+ numrevs = 0
if opts.get('rev'):
if not self.applied:
raise util.Abort(_('no patches applied'))
revs = cmdutil.revrange(repo, opts['rev'])
if len(revs) > 1 and revs[0] > revs[1]:
revs.reverse()
- for rev in revs:
- if appliedbase >= len(self.applied):
- raise util.Abort(_("revision %d is not managed") % rev)
-
- base = bin(self.applied[appliedbase].rev)
- node = repo.changelog.node(rev)
- if node != base:
- raise util.Abort(_("cannot delete revision %d above "
- "applied patches") % rev)
- realpatches.append(self.applied[appliedbase].name)
- appliedbase += 1
+ revpatches = self._revpatches(repo, revs)
+ realpatches += revpatches
+ numrevs = len(revpatches)
- if not opts.get('keep'):
- r = self.qrepo()
- if r:
- r.remove(realpatches, True)
- else:
- for p in realpatches:
- os.unlink(self.join(p))
-
- if appliedbase:
- del self.applied[:appliedbase]
- self.applied_dirty = 1
- self._clean_series(realpatches)
+ self._cleanup(realpatches, numrevs, opts.get('keep'))
def check_toppatch(self, repo):
if len(self.applied) > 0:
@@ -958,6 +955,7 @@
end = start + 1
else:
end = self.series.index(patch, start) + 1
+
s = self.series[start:end]
all_files = {}
try:
@@ -977,13 +975,15 @@
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") % top)
+ if ret[0] and ret[0] > 1:
+ msg = _("errors during apply, please fix and refresh %s\n")
+ self.ui.write(msg % top)
else:
self.ui.write(_("now at: %s\n") % top)
return ret[0]
+
finally:
wlock.release()
--- a/hgext/parentrevspec.py Sat Jun 20 18:58:34 2009 +0200
+++ b/hgext/parentrevspec.py Sun Jun 21 19:06:57 2009 +0200
@@ -5,8 +5,7 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2, incorporated herein by reference.
-'''\
-use suffixes to refer to ancestor revisions
+'''use suffixes to refer to ancestor revisions
This extension allows you to use git-style suffixes to refer to the
ancestors of a specific revision.
--- a/hgext/patchbomb.py Sat Jun 20 18:58:34 2009 +0200
+++ b/hgext/patchbomb.py Sun Jun 21 19:06:57 2009 +0200
@@ -28,11 +28,6 @@
with a diffstat summary and the changeset summary, so you can be sure
you are sending the right changes.
-To enable this extension:
-
- [extensions]
- hgext.patchbomb =
-
To configure other defaults, add a section like this to your hgrc
file:
--- a/hgext/purge.py Sat Jun 20 18:58:34 2009 +0200
+++ b/hgext/purge.py Sun Jun 21 19:06:57 2009 +0200
@@ -6,10 +6,6 @@
# This program was inspired by the "cvspurge" script contained in CVS utilities
# (http://www.red-bean.com/cvsutils/).
#
-# To enable the "purge" extension put these lines in your ~/.hgrc:
-# [extensions]
-# hgext.purge =
-#
# For help on the usage of "hg purge" use:
# hg help purge
#
@@ -27,6 +23,8 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+'''enable removing untracked files only'''
+
from mercurial import util, commands, cmdutil
from mercurial.i18n import _
import os, stat
--- a/hgext/share.py Sat Jun 20 18:58:34 2009 +0200
+++ b/hgext/share.py Sun Jun 21 19:06:57 2009 +0200
@@ -1,10 +1,10 @@
-# Mercurial extension to provide the 'hg share' command
-#
# Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2, incorporated herein by reference.
+'''provides the hg share command'''
+
import os
from mercurial.i18n import _
from mercurial import hg, commands
--- a/hgext/win32mbcs.py Sat Jun 20 18:58:34 2009 +0200
+++ b/hgext/win32mbcs.py Sun Jun 21 19:06:57 2009 +0200
@@ -33,11 +33,6 @@
* You should set same encoding for the repository by locale or
HGENCODING.
-To use this extension, enable the extension in .hg/hgrc or ~/.hgrc:
-
- [extensions]
- hgext.win32mbcs =
-
Path encoding conversion are done between Unicode and
encoding.encoding which is decided by Mercurial from current locale
setting or HGENCODING.
--- a/hgext/win32text.py Sat Jun 20 18:58:34 2009 +0200
+++ b/hgext/win32text.py Sun Jun 21 19:06:57 2009 +0200
@@ -4,31 +4,34 @@
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2, incorporated herein by reference.
-#
-# To perform automatic newline conversion, use:
-#
-# [extensions]
-# hgext.win32text =
-# [encode]
-# ** = cleverencode:
-# # or ** = macencode:
-# [decode]
-# ** = cleverdecode:
-# # or ** = macdecode:
-#
-# If not doing conversion, to make sure you do not commit CRLF/CR by
-# accident:
-#
-# [hooks]
-# pretxncommit.crlf = python:hgext.win32text.forbidcrlf
-# # or pretxncommit.cr = python:hgext.win32text.forbidcr
-#
-# To do the same check on a server to prevent CRLF/CR from being
-# pushed or pulled:
-#
-# [hooks]
-# pretxnchangegroup.crlf = python:hgext.win32text.forbidcrlf
-# # or pretxnchangegroup.cr = python:hgext.win32text.forbidcr
+
+'''LF <-> CRLF/CR translation utilities
+
+To perform automatic newline conversion, use:
+
+[extensions]
+hgext.win32text =
+[encode]
+** = cleverencode:
+# or ** = macencode:
+
+[decode]
+** = cleverdecode:
+# or ** = macdecode:
+
+If not doing conversion, to make sure you do not commit CRLF/CR by accident:
+
+[hooks]
+pretxncommit.crlf = python:hgext.win32text.forbidcrlf
+# or pretxncommit.cr = python:hgext.win32text.forbidcr
+
+To do the same check on a server to prevent CRLF/CR from being
+pushed or pulled:
+
+[hooks]
+pretxnchangegroup.crlf = python:hgext.win32text.forbidcrlf
+# or pretxnchangegroup.cr = python:hgext.win32text.forbidcr
+'''
from mercurial.i18n import _
from mercurial.node import short
--- a/hgext/zeroconf/__init__.py Sat Jun 20 18:58:34 2009 +0200
+++ b/hgext/zeroconf/__init__.py Sun Jun 21 19:06:57 2009 +0200
@@ -11,12 +11,6 @@
the need to configure a server or a service. They can be discovered
without knowing their actual IP address.
-To use the zeroconf extension add the following entry to your hgrc
-file:
-
-[extensions]
-hgext.zeroconf =
-
To allow other people to discover your repository using run "hg serve"
in your repository.
--- a/mercurial/bdiff.c Sat Jun 20 18:58:34 2009 +0200
+++ b/mercurial/bdiff.c Sun Jun 21 19:06:57 2009 +0200
@@ -18,6 +18,10 @@
# define inline
#endif
+#ifdef __linux
+# define inline __inline
+#endif
+
#ifdef _WIN32
#ifdef _MSC_VER
#define inline __inline
--- a/mercurial/commands.py Sat Jun 20 18:58:34 2009 +0200
+++ b/mercurial/commands.py Sun Jun 21 19:06:57 2009 +0200
@@ -1230,16 +1230,14 @@
for i in xrange(blo, bhi):
yield ('+', b[i])
- prev = {}
- def display(fn, rev, states, prevstates):
+ def display(fn, r, pstates, states):
datefunc = ui.quiet and util.shortdate or util.datestr
found = False
filerevmatches = {}
- r = prev.get(fn, -1)
if opts.get('all'):
- iter = difflinestates(states, prevstates)
+ iter = difflinestates(pstates, states)
else:
- iter = [('', l) for l in prevstates]
+ iter = [('', l) for l in states]
for change, l in iter:
cols = [fn, str(r)]
if opts.get('line_number'):
@@ -1261,8 +1259,8 @@
found = True
return found
- fstate = {}
skip = {}
+ revfiles = {}
get = util.cachefunc(lambda r: repo[r].changeset())
changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
found = False
@@ -1270,46 +1268,58 @@
for st, rev, fns in changeiter:
if st == 'window':
matches.clear()
+ revfiles.clear()
elif st == 'add':
ctx = repo[rev]
- matches[rev] = {}
+ pctx = ctx.parents()[0]
+ parent = pctx.rev()
+ matches.setdefault(rev, {})
+ matches.setdefault(parent, {})
+ files = revfiles.setdefault(rev, [])
for fn in fns:
- if fn in skip:
- continue
+ flog = getfile(fn)
try:
- grepbody(fn, rev, getfile(fn).read(ctx.filenode(fn)))
- fstate.setdefault(fn, [])
- if follow:
- copied = getfile(fn).renamed(ctx.filenode(fn))
- if copied:
- copies.setdefault(rev, {})[fn] = copied[0]
+ fnode = ctx.filenode(fn)
except error.LookupError:
- pass
+ continue
+
+ copied = flog.renamed(fnode)
+ copy = follow and copied and copied[0]
+ if copy:
+ copies.setdefault(rev, {})[fn] = copy
+ if fn in skip:
+ if copy:
+ skip[copy] = True
+ continue
+ files.append(fn)
+
+ if not matches[rev].has_key(fn):
+ grepbody(fn, rev, flog.read(fnode))
+
+ pfn = copy or fn
+ if not matches[parent].has_key(pfn):
+ try:
+ fnode = pctx.filenode(pfn)
+ grepbody(pfn, parent, flog.read(fnode))
+ except error.LookupError:
+ pass
elif st == 'iter':
- for fn, m in sorted(matches[rev].items()):
+ parent = repo[rev].parents()[0].rev()
+ for fn in sorted(revfiles.get(rev, [])):
+ states = matches[rev][fn]
copy = copies.get(rev, {}).get(fn)
if fn in skip:
if copy:
skip[copy] = True
continue
- if fn in prev or fstate[fn]:
- r = display(fn, rev, m, fstate[fn])
+ pstates = matches.get(parent, {}).get(copy or fn, [])
+ if pstates or states:
+ r = display(fn, rev, pstates, states)
found = found or r
if r and not opts.get('all'):
skip[fn] = True
if copy:
skip[copy] = True
- fstate[fn] = m
- if copy:
- fstate[copy] = m
- prev[fn] = rev
-
- for fn, state in sorted(fstate.items()):
- if fn in skip:
- continue
- if fn not in copies.get(prev[fn], {}):
- found = display(fn, rev, {}, state) or found
- return (not found and 1) or 0
def heads(ui, repo, *branchrevs, **opts):
"""show current repository heads or show branch heads
@@ -1473,18 +1483,9 @@
else:
ui.write(' %-*s %s\n' % (m, f, h[f]))
- exts = list(extensions.extensions())
- if exts and name != 'shortlist':
- ui.write(_('\nenabled extensions:\n\n'))
- maxlength = 0
- exthelps = []
- for ename, ext in exts:
- doc = (gettext(ext.__doc__) or _('(no help text available)'))
- ename = ename.split('.')[-1]
- maxlength = max(len(ename), maxlength)
- exthelps.append((ename, doc.splitlines(0)[0].strip()))
- for ename, text in exthelps:
- ui.write(_(' %s %s\n') % (ename.ljust(maxlength), text))
+ if name != 'shortlist':
+ exts, maxlength = extensions.enabled()
+ ui.write(help.listexts(_('enabled extensions:'), exts, maxlength))
if not ui.quiet:
addglobalopts(True)
@@ -2108,7 +2109,7 @@
'use "hg update" or merge with an explicit rev'))
node = parent == bheads[0] and bheads[-1] or bheads[0]
- if opts.get('show'):
+ if opts.get('preview'):
p1 = repo['.']
p2 = repo[node]
common = p1.ancestor(p2)
@@ -2670,7 +2671,8 @@
This command should be used with care. There is only one level of
rollback, and there is no way to undo a rollback. It will also
restore the dirstate at the time of the last transaction, losing
- any dirstate changes since that time.
+ any dirstate changes since that time. This command does not alter
+ the working directory.
Transactions are used to encapsulate the effects of all commands
that create new changesets or propagate existing changesets into a
@@ -2718,9 +2720,9 @@
baseui = repo and repo.baseui or ui
optlist = ("name templates style address port prefix ipv6"
- " accesslog errorlog webdir_conf certificate")
+ " accesslog errorlog webdir_conf certificate encoding")
for o in optlist.split():
- if opts[o]:
+ if opts.get(o, None):
baseui.setconfig("web", o, str(opts[o]))
if (repo is not None) and (repo.ui != baseui):
repo.ui.setconfig("web", o, str(opts[o]))
@@ -2965,7 +2967,7 @@
return postincoming(ui, repo, modheads, opts.get('update'), None)
-def update(ui, repo, node=None, rev=None, clean=False, date=None):
+def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
"""update working directory
Update the repository's working directory to the specified
@@ -2981,7 +2983,8 @@
When there are uncommitted changes, use option -C/--clean to
discard them, forcibly replacing the state of the working
- directory with the requested revision.
+ directory with the requested revision. Alternately, use -c/--check
+ to abort.
When there are uncommitted changes and option -C/--clean is not
used, and the parent revision and requested revision are on the
@@ -3001,6 +3004,12 @@
if not rev:
rev = node
+ if not clean and check:
+ # we could use dirty() but we can ignore merge and branch trivia
+ c = repo[None]
+ if c.modified() or c.added() or c.removed():
+ raise util.Abort(_("uncommitted local changes"))
+
if date:
if rev:
raise util.Abort(_("you can't specify a revision and a date"))
@@ -3358,7 +3367,7 @@
(merge,
[('f', 'force', None, _('force a merge with outstanding changes')),
('r', 'rev', '', _('revision to merge')),
- ('S', 'show', None,
+ ('P', 'preview', None,
_('review revisions to merge (no merge is performed)'))],
_('[-f] [[-r] REV]')),
"outgoing|out":
@@ -3492,6 +3501,7 @@
"^update|up|checkout|co":
(update,
[('C', 'clean', None, _('overwrite locally modified files (no backup)')),
+ ('c', 'check', None, _('check for uncommitted changes')),
('d', 'date', '', _('tipmost revision matching date')),
('r', 'rev', '', _('revision'))],
_('[-C] [-d DATE] [[-r] REV]')),
--- a/mercurial/dispatch.py Sat Jun 20 18:58:34 2009 +0200
+++ b/mercurial/dispatch.py Sun Jun 21 19:06:57 2009 +0200
@@ -224,7 +224,6 @@
# but only if they have been defined prior to the current definition.
for alias, definition in ui.configitems('alias'):
aliasdef = cmdalias(alias, definition, cmdtable)
-
cmdtable[alias] = (aliasdef, aliasdef.opts, aliasdef.help)
if aliasdef.norepo:
commands.norepo += ' %s' % alias
--- a/mercurial/extensions.py Sat Jun 20 18:58:34 2009 +0200
+++ b/mercurial/extensions.py Sun Jun 21 19:06:57 2009 +0200
@@ -5,9 +5,9 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2, incorporated herein by reference.
-import imp, os
-import util, cmdutil
-from i18n import _
+import imp, os, sys
+import util, cmdutil, help
+from i18n import _, gettext
_extensions = {}
_order = []
@@ -117,3 +117,61 @@
origfn = getattr(container, funcname)
setattr(container, funcname, wrap)
return origfn
+
+def disabled():
+ '''find disabled extensions from hgext
+ returns a dict of {name: desc}, and the max name length'''
+
+ import hgext
+ extpath = os.path.dirname(os.path.abspath(hgext.__file__))
+
+ exts = {}
+ maxlength = 0
+ for e in os.listdir(extpath):
+
+ if e.endswith('.py'):
+ name = e.rsplit('.', 1)[0]
+ path = os.path.join(extpath, e)
+ else:
+ name = e
+ path = os.path.join(extpath, e, '__init__.py')
+ if not os.path.exists(path):
+ continue
+
+ if name in exts or name in _order or name == '__init__':
+ continue
+
+ try:
+ file = open(path)
+ except IOError:
+ continue
+ else:
+ doc = help.moduledoc(file)
+ file.close()
+
+ if doc: # extracting localized synopsis
+ exts[name] = gettext(doc).splitlines()[0]
+ else:
+ exts[name] = _('(no help text available)')
+
+ if len(name) > maxlength:
+ maxlength = len(name)
+
+ return exts, maxlength
+
+def enabled():
+ '''return a dict of {name: desc} of extensions, and the max name length'''
+
+ if not enabled:
+ return {}, 0
+
+ exts = {}
+ maxlength = 0
+ exthelps = []
+ for ename, ext in extensions():
+ doc = (gettext(ext.__doc__) or _('(no help text available)'))
+ ename = ename.split('.')[-1]
+ maxlength = max(len(ename), maxlength)
+ exts[ename] = doc.splitlines(0)[0].strip()
+
+ return exts, maxlength
--- a/mercurial/filemerge.py Sat Jun 20 18:58:34 2009 +0200
+++ b/mercurial/filemerge.py Sun Jun 21 19:06:57 2009 +0200
@@ -195,8 +195,8 @@
elif tool == 'internal:dump':
a = repo.wjoin(fd)
util.copyfile(a, a + ".local")
- repo.wwrite(a + ".other", fco.data(), fco.flags())
- repo.wwrite(a + ".base", fca.data(), fca.flags())
+ repo.wwrite(fd + ".other", fco.data(), fco.flags())
+ repo.wwrite(fd + ".base", fca.data(), fca.flags())
return 1 # unresolved
else:
args = _toolstr(ui, tool, "args", '$local $base $other')
--- a/mercurial/graphmod.py Sat Jun 20 18:58:34 2009 +0200
+++ b/mercurial/graphmod.py Sun Jun 21 19:06:57 2009 +0200
@@ -6,70 +6,114 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2, incorporated herein by reference.
-from node import nullrev
+"""supports walking the history as DAGs suitable for graphical output
-def graph(repo, start_rev, stop_rev):
- """incremental revision grapher
+The most basic format we use is that of::
+
+ (id, type, data, [parentids])
- This generator function walks through the revision history from
- revision start_rev to revision stop_rev (which must be less than
- or equal to start_rev) and for each revision emits tuples with the
- following elements:
+The node and parent ids are arbitrary integers which identify a node in the
+context of the graph returned. Type is a constant specifying the node type.
+Data depends on type.
+"""
+
+from mercurial.node import nullrev
+
+CHANGESET = 'C'
- - Current node
- - Column and color for the current node
- - Edges; a list of (col, next_col, color) indicating the edges between
- the current node and its parents.
- - First line of the changeset description
- - The changeset author
- - The changeset date/time
+def revisions(repo, start, stop):
+ """cset DAG generator yielding (id, CHANGESET, ctx, [parentids]) tuples
+
+ This generator function walks through the revision history from revision
+ start to revision stop (which must be less than or equal to start). It
+ returns a tuple for each node. The node and parent ids are arbitrary
+ integers which identify a node in the context of the graph returned.
"""
+ cur = start
+ while cur >= stop:
+ ctx = repo[cur]
+ parents = [p.rev() for p in ctx.parents() if p.rev() != nullrev]
+ yield (cur, CHANGESET, ctx, sorted(parents))
+ cur -= 1
- if start_rev == nullrev and not stop_rev:
- return
+def filerevs(repo, path, start, stop):
+ """file cset DAG generator yielding (id, CHANGESET, ctx, [parentids]) tuples
- assert start_rev >= stop_rev
- assert stop_rev >= 0
- curr_rev = start_rev
- revs = []
- cl = repo.changelog
- colors = {}
- new_color = 1
+ This generator function walks through the revision history of a single
+ file from revision start down to revision stop.
+ """
+ filerev = len(repo.file(path)) - 1
+ while filerev >= 0:
+ fctx = repo.filectx(path, fileid=filerev)
+ parents = [f.linkrev() for f in fctx.parents() if f.path() == path]
+ rev = fctx.rev()
+ if rev <= start:
+ yield (rev, CHANGESET, fctx, sorted(parents))
+ if rev <= stop:
+ break
+ filerev -= 1
+
+def nodes(repo, nodes):
+ """cset DAG generator yielding (id, CHANGESET, ctx, [parentids]) tuples
+
+ This generator function walks the given nodes. It only returns parents
+ that are in nodes, too.
+ """
+ include = set(nodes)
+ for node in nodes:
+ ctx = repo[node]
+ parents = [p.rev() for p in ctx.parents() if p.node() in include]
+ yield (ctx.rev(), CHANGESET, ctx, sorted(parents))
+
+def colored(dag):
+ """annotates a DAG with colored edge information
- while curr_rev >= stop_rev:
- # Compute revs and next_revs
- if curr_rev not in revs:
- revs.append(curr_rev) # new head
- colors[curr_rev] = new_color
- new_color += 1
+ For each DAG node this function emits tuples::
+
+ (id, type, data, (col, color), [(col, nextcol, color)])
+
+ with the following new elements:
- idx = revs.index(curr_rev)
- color = colors.pop(curr_rev)
- next = revs[:]
+ - Tuple (col, color) with column and color index for the current node
+ - A list of tuples indicating the edges between the current node and its
+ parents.
+ """
+ seen = []
+ colors = {}
+ newcolor = 1
+ for (cur, type, data, parents) in dag:
- # Add parents to next_revs
- parents = [x for x in cl.parentrevs(curr_rev) if x != nullrev]
+ # Compute seen and next
+ if cur not in seen:
+ seen.append(cur) # new head
+ colors[cur] = newcolor
+ newcolor += 1
+
+ col = seen.index(cur)
+ color = colors.pop(cur)
+ next = seen[:]
+
+ # Add parents to next
addparents = [p for p in parents if p not in next]
- next[idx:idx + 1] = addparents
+ next[col:col + 1] = addparents
# Set colors for the parents
for i, p in enumerate(addparents):
if not i:
colors[p] = color
else:
- colors[p] = new_color
- new_color += 1
+ colors[p] = newcolor
+ newcolor += 1
# Add edges to the graph
edges = []
- for col, r in enumerate(revs):
- if r in next:
- edges.append((col, next.index(r), colors[r]))
- elif r == curr_rev:
+ for ecol, eid in enumerate(seen):
+ if eid in next:
+ edges.append((ecol, next.index(eid), colors[eid]))
+ elif eid == cur:
for p in parents:
- edges.append((col, next.index(p), colors[p]))
+ edges.append((ecol, next.index(p), colors[p]))
# Yield and move on
- yield (repo[curr_rev], (idx, color), edges)
- revs = next
- curr_rev -= 1
+ yield (cur, type, data, (col, color), edges)
+ seen = next
--- a/mercurial/help.py Sat Jun 20 18:58:34 2009 +0200
+++ b/mercurial/help.py Sun Jun 21 19:06:57 2009 +0200
@@ -6,6 +6,90 @@
# GNU General Public License version 2, incorporated herein by reference.
from i18n import _
+import extensions
+
+
+def moduledoc(file):
+ '''return the top-level python documentation for the given file
+
+ Loosely inspired by pydoc.source_synopsis(), but rewritten to handle \'''
+ as well as """ and to return the whole text instead of just the synopsis'''
+ result = []
+
+ line = file.readline()
+ while line[:1] == '#' or not line.strip():
+ line = file.readline()
+ if not line: break
+
+ start = line[:3]
+ if start == '"""' or start == "'''":
+ line = line[3:]
+ while line:
+ if line.rstrip().endswith(start):
+ line = line.split(start)[0]
+ if line:
+ result.append(line)
+ break
+ elif not line:
+ return None # unmatched delimiter
+ result.append(line)
+ line = file.readline()
+ else:
+ return None
+
+ return ''.join(result)
+
+def listexts(header, exts, maxlength):
+ '''return a text listing of the given extensions'''
+ if not exts:
+ return ''
+ result = '\n%s\n\n' % header
+ for name, desc in sorted(exts.iteritems()):
+ result += ' %s %s\n' % (name.ljust(maxlength), desc)
+ return result
+
+def extshelp():
+ doc = _(r'''
+ Mercurial has a mechanism for adding new features through the
+ use of extensions. Extensions may bring new commands, or new
+ hooks, or change Mercurial's behavior.
+
+ Extensions are not loaded by default for a variety of reasons,
+ they may be meant for advanced users or provide potentially
+ dangerous commands (e.g. mq and rebase allow history to be
+ rewritten), they might not be ready for prime-time yet, or
+ they may alter Mercurial's behavior. It is thus up to the user
+ to activate extensions as desired.
+
+ To enable the "foo" extension, either shipped with Mercurial
+ or in the Python search path, create an entry for it in your
+ hgrc, like this:
+
+ [extensions]
+ foo =
+
+ You may also specify the full path to an extension:
+
+ [extensions]
+ myfeature = ~/.hgext/myfeature.py
+
+ To explicitly disable an extension enabled in an hgrc of broader
+ scope, prepend its path with !:
+
+ [extensions]
+ # disabling extension bar residing in /ext/path
+ hgext.bar = !/path/to/extension/bar.py
+ # ditto, but no path was supplied for extension baz
+ hgext.baz = !
+ ''')
+
+ exts, maxlength = extensions.enabled()
+ doc += listexts(_('enabled extensions:'), exts, maxlength)
+
+ exts, maxlength = extensions.disabled()
+ doc += listexts(_('disabled extensions:'), exts, maxlength)
+
+ return doc
helptable = (
(["dates"], _("Date Formats"),
@@ -418,4 +502,5 @@
The push command will look for a path named 'default-push', and
prefer it over 'default' if both are defined.
''')),
+ (["extensions"], _("Using additional features"), extshelp),
)
--- a/mercurial/hgweb/hgweb_mod.py Sat Jun 20 18:58:34 2009 +0200
+++ b/mercurial/hgweb/hgweb_mod.py Sun Jun 21 19:06:57 2009 +0200
@@ -64,7 +64,8 @@
self.maxshortchanges = int(self.config("web", "maxshortchanges", 60))
self.maxfiles = int(self.config("web", "maxfiles", 10))
self.allowpull = self.configbool("web", "allowpull", True)
- self.encoding = self.config("web", "encoding", encoding.encoding)
+ encoding.encoding = self.config("web", "encoding",
+ encoding.encoding)
def run(self):
if not os.environ.get('GATEWAY_INTERFACE', '').startswith("CGI/1."):
@@ -81,28 +82,6 @@
self.refresh()
- # process this if it's a protocol request
- # protocol bits don't need to create any URLs
- # and the clients always use the old URL structure
-
- cmd = req.form.get('cmd', [''])[0]
- if cmd and cmd in protocol.__all__:
- try:
- if cmd in perms:
- try:
- self.check_perm(req, perms[cmd])
- except ErrorResponse, inst:
- if cmd == 'unbundle':
- req.drain()
- raise
- method = getattr(protocol, cmd)
- return method(self.repo, req)
- except ErrorResponse, inst:
- req.respond(inst, protocol.HGTYPE)
- if not inst.message:
- return []
- return '0\n%s\n' % inst.message,
-
# work with CGI variables to create coherent structure
# use SCRIPT_NAME, PATH_INFO and QUERY_STRING as well as our REPO_NAME
@@ -122,6 +101,30 @@
query = req.env['QUERY_STRING'].split('&', 1)[0]
query = query.split(';', 1)[0]
+ # process this if it's a protocol request
+ # protocol bits don't need to create any URLs
+ # and the clients always use the old URL structure
+
+ cmd = req.form.get('cmd', [''])[0]
+ if cmd and cmd in protocol.__all__:
+ if query:
+ raise ErrorResponse(HTTP_NOT_FOUND)
+ try:
+ if cmd in perms:
+ try:
+ self.check_perm(req, perms[cmd])
+ except ErrorResponse, inst:
+ if cmd == 'unbundle':
+ req.drain()
+ raise
+ method = getattr(protocol, cmd)
+ return method(self.repo, req)
+ except ErrorResponse, inst:
+ req.respond(inst, protocol.HGTYPE)
+ if not inst.message:
+ return []
+ return '0\n%s\n' % inst.message,
+
# translate user-visible url structure to internal structure
args = query.split('/', 2)
@@ -160,7 +163,7 @@
try:
tmpl = self.templater(req)
- ctype = tmpl('mimetype', encoding=self.encoding)
+ ctype = tmpl('mimetype', encoding=encoding.encoding)
ctype = templater.stringify(ctype)
# check read permissions non-static content
@@ -219,7 +222,7 @@
# some functions for the templater
def header(**map):
- yield tmpl('header', encoding=self.encoding, **map)
+ yield tmpl('header', encoding=encoding.encoding, **map)
def footer(**map):
yield tmpl("footer", **map)
--- a/mercurial/hgweb/hgwebdir_mod.py Sat Jun 20 18:58:34 2009 +0200
+++ b/mercurial/hgweb/hgwebdir_mod.py Sun Jun 21 19:06:57 2009 +0200
@@ -70,6 +70,8 @@
elif isinstance(self.conf, dict):
paths = self.conf.items()
+ encoding.encoding = self.ui.config('web', 'encoding',
+ encoding.encoding)
self.motd = self.ui.config('web', 'motd')
self.style = self.ui.config('web', 'style', 'paper')
self.stripecount = self.ui.config('web', 'stripes', 1)
--- a/mercurial/hgweb/protocol.py Sat Jun 20 18:58:34 2009 +0200
+++ b/mercurial/hgweb/protocol.py Sun Jun 21 19:06:57 2009 +0200
@@ -162,8 +162,10 @@
sys.stderr = sys.stdout = cStringIO.StringIO()
try:
- url = 'remote:%s:%s' % (proto,
- req.env.get('REMOTE_HOST', ''))
+ url = 'remote:%s:%s:%s' % (
+ proto,
+ urllib.quote(req.env.get('REMOTE_HOST', '')),
+ urllib.quote(req.env.get('REMOTE_USER', '')))
try:
ret = repo.addchangegroup(gen, 'serve', url)
except util.Abort, inst:
--- a/mercurial/hgweb/webcommands.py Sat Jun 20 18:58:34 2009 +0200
+++ b/mercurial/hgweb/webcommands.py Sun Jun 21 19:06:57 2009 +0200
@@ -668,10 +668,13 @@
count = len(web.repo)
changenav = webutil.revnavgen(rev, revcount, count, web.repo.changectx)
- tree = list(graphmod.graph(web.repo, rev, downrev))
+ dag = graphmod.revisions(web.repo, rev, downrev)
+ tree = list(graphmod.colored(dag))
canvasheight = (len(tree) + 1) * bg_height - 27;
data = []
- for (ctx, vtx, edges) in tree:
+ for (id, type, ctx, vtx, edges) in tree:
+ if type != graphmod.CHANGESET:
+ continue
node = short(ctx.node())
age = templatefilters.age(ctx.date())
desc = templatefilters.firstline(ctx.description())
--- a/mercurial/localrepo.py Sat Jun 20 18:58:34 2009 +0200
+++ b/mercurial/localrepo.py Sun Jun 21 19:06:57 2009 +0200
@@ -262,7 +262,7 @@
warn(_("node '%s' is not well formed") % node)
continue
if bin_n not in self.changelog.nodemap:
- warn(_("tag '%s' refers to unknown node") % key)
+ # silently ignore as pull -r might cause this
continue
h = []
@@ -290,11 +290,24 @@
globaltags[k] = an, ah
tagtypes[k] = tagtype
- # read the tags file from each head, ending with the tip
+ seen = set()
f = None
- for rev, node, fnode in self._hgtagsnodes():
- f = (f and f.filectx(fnode) or
- self.filectx('.hgtags', fileid=fnode))
+ ctxs = []
+ for node in self.heads():
+ try:
+ fnode = self[node].filenode('.hgtags')
+ except error.LookupError:
+ continue
+ if fnode not in seen:
+ seen.add(fnode)
+ if not f:
+ f = self.filectx('.hgtags', fileid=fnode)
+ else:
+ f = f.filectx(fnode)
+ ctxs.append(f)
+
+ # read the tags file from each head, ending with the tip
+ for f in reversed(ctxs):
readtags(f.data().splitlines(), f, "global")
try:
@@ -328,22 +341,6 @@
return self._tagstypecache.get(tagname)
- def _hgtagsnodes(self):
- last = {}
- ret = []
- for node in reversed(self.heads()):
- c = self[node]
- rev = c.rev()
- try:
- fnode = c.filenode('.hgtags')
- except error.LookupError:
- continue
- ret.append((rev, node, fnode))
- if fnode in last:
- ret[last[fnode]] = None
- last[fnode] = len(ret) - 1
- return [item for item in ret if item]
-
def tagslist(self):
'''return a list of tags ordered by revision'''
l = []
--- a/mercurial/patch.py Sat Jun 20 18:58:34 2009 +0200
+++ b/mercurial/patch.py Sun Jun 21 19:06:57 2009 +0200
@@ -972,7 +972,7 @@
def applydiff(ui, fp, changed, strip=1, sourcefile=None, reverse=False,
eol=None):
"""
- Reads a patch from fp and tries to apply it.
+ Reads a patch from fp and tries to apply it.
The dict 'changed' is filled in with all of the filenames changed
by the patch. Returns 0 for a clean patch, -1 if any rejects were
@@ -1137,7 +1137,7 @@
eol = {'strict': None, 'crlf': '\r\n', 'lf': '\n'}[eolmode.lower()]
except KeyError:
raise util.Abort(_('Unsupported line endings type: %s') % eolmode)
-
+
try:
fp = file(patchobj, 'rb')
except TypeError:
--- a/mercurial/url.py Sat Jun 20 18:58:34 2009 +0200
+++ b/mercurial/url.py Sun Jun 21 19:06:57 2009 +0200
@@ -109,7 +109,9 @@
return (user, passwd)
if not user:
- user, passwd = self._readauthtoken(authuri)
+ auth = self.readauthtoken(authuri)
+ if auth:
+ user, passwd = auth.get('username'), auth.get('password')
if not user or not passwd:
if not self.ui.interactive():
raise util.Abort(_('http authorization required'))
@@ -132,7 +134,7 @@
msg = _('http auth: user %s, password %s\n')
self.ui.debug(msg % (user, passwd and '*' * len(passwd) or 'not set'))
- def _readauthtoken(self, uri):
+ def readauthtoken(self, uri):
# Read configuration
config = dict()
for key, val in self.ui.configitems('auth'):
@@ -143,7 +145,7 @@
# Find the best match
scheme, hostpath = uri.split('://', 1)
bestlen = 0
- bestauth = None, None
+ bestauth = None
for auth in config.itervalues():
prefix = auth.get('prefix')
if not prefix: continue
@@ -155,7 +157,7 @@
if (prefix == '*' or hostpath.startswith(prefix)) and \
len(prefix) > bestlen and scheme in schemes:
bestlen = len(prefix)
- bestauth = auth.get('username'), auth.get('password')
+ bestauth = auth
return bestauth
class proxyhandler(urllib2.ProxyHandler):
@@ -411,8 +413,38 @@
send = _gen_sendfile(httplib.HTTPSConnection)
class httpshandler(keepalive.KeepAliveHandler, urllib2.HTTPSHandler):
+ def __init__(self, ui):
+ keepalive.KeepAliveHandler.__init__(self)
+ urllib2.HTTPSHandler.__init__(self)
+ self.ui = ui
+ self.pwmgr = passwordmgr(self.ui)
+
def https_open(self, req):
- return self.do_open(httpsconnection, req)
+ self.auth = self.pwmgr.readauthtoken(req.get_full_url())
+ return self.do_open(self._makeconnection, req)
+
+ def _makeconnection(self, host, port=443, *args, **kwargs):
+ keyfile = None
+ certfile = None
+
+ if args: # key_file
+ keyfile = args.pop(0)
+ if args: # cert_file
+ certfile = args.pop(0)
+
+ # if the user has specified different key/cert files in
+ # hgrc, we prefer these
+ if self.auth and 'key' in self.auth and 'cert' in self.auth:
+ keyfile = self.auth['key']
+ certfile = self.auth['cert']
+
+ # let host port take precedence
+ if ':' in host and '[' not in host or ']:' in host:
+ host, port = host.rsplit(':', 1)
+ if '[' in host:
+ host = host[1:-1]
+
+ return httpsconnection(host, port, keyfile, certfile, *args, **kwargs)
# In python < 2.5 AbstractDigestAuthHandler raises a ValueError if
# it doesn't know about the auth type requested. This can happen if
@@ -460,7 +492,7 @@
'''
handlers = [httphandler()]
if has_https:
- handlers.append(httpshandler())
+ handlers.append(httpshandler(ui))
handlers.append(proxyhandler(ui))
--- a/tests/run-tests.py Sat Jun 20 18:58:34 2009 +0200
+++ b/tests/run-tests.py Sun Jun 21 19:06:57 2009 +0200
@@ -16,7 +16,7 @@
# If you change this script, it is recommended that you ensure you
# haven't broken it by running it in various modes with a representative
# sample of test scripts. For example:
-#
+#
# 1) serial, no coverage, temp install:
# ./run-tests.py test-s*
# 2) serial, no coverage, local hg:
--- a/tests/test-convert.out Sat Jun 20 18:58:34 2009 +0200
+++ b/tests/test-convert.out Sun Jun 21 19:06:57 2009 +0200
@@ -271,5 +271,5 @@
emptydir does not look like a monotone repo
emptydir does not look like a GNU Arch repo
emptydir does not look like a Bazaar repo
-emptydir does not look like a P4 repo
+cannot find required "p4" tool
abort: emptydir: missing or unsupported repository
--- a/tests/test-debugcomplete.out Sat Jun 20 18:58:34 2009 +0200
+++ b/tests/test-debugcomplete.out Sun Jun 21 19:06:57 2009 +0200
@@ -169,14 +169,14 @@
export: output, switch-parent, text, git, nodates
init: ssh, remotecmd
log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, prune, patch, git, limit, no-merges, style, template, include, exclude
-merge: force, rev, show
+merge: force, rev, preview
parents: rev, style, template
pull: update, force, rev, ssh, remotecmd
push: force, rev, ssh, remotecmd
remove: after, force, include, exclude
serve: accesslog, daemon, daemon-pipefds, errorlog, port, address, prefix, name, webdir-conf, pid-file, stdio, templates, style, ipv6, certificate
status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, include, exclude
-update: clean, date, rev
+update: clean, check, date, rev
addremove: similarity, include, exclude, dry-run
archive: no-decode, prefix, rev, type, include, exclude
backout: merge, parent, rev, include, exclude, message, logfile, date, user
--- a/tests/test-double-merge Sat Jun 20 18:58:34 2009 +0200
+++ b/tests/test-double-merge Sun Jun 21 19:06:57 2009 +0200
@@ -20,7 +20,7 @@
hg ci -m 'change foo' -d "1000000 0"
# we get conflicts that shouldn't be there
-hg merge -S
+hg merge -P
hg merge --debug
echo "-- foo --"
--- a/tests/test-globalopts.out Sat Jun 20 18:58:34 2009 +0200
+++ b/tests/test-globalopts.out Sun Jun 21 19:06:57 2009 +0200
@@ -208,6 +208,7 @@
diffs Diff Formats
templating Template Usage
urls URL Paths
+ extensions Using additional features
use "hg -v help" to show aliases and global options
Mercurial Distributed SCM
@@ -273,6 +274,7 @@
diffs Diff Formats
templating Template Usage
urls URL Paths
+ extensions Using additional features
use "hg -v help" to show aliases and global options
%% not tested: --debugger
--- a/tests/test-grep Sat Jun 20 18:58:34 2009 +0200
+++ b/tests/test-grep Sun Jun 21 19:06:57 2009 +0200
@@ -73,3 +73,25 @@
# Used to crash here
hg grep -r 1 octarine
+# Issue337: grep did not compared changesets by their revision numbers
+# instead of following parent-child relationships.
+cd ..
+echo % issue 337
+hg init issue337
+cd issue337
+
+echo white > color
+hg commit -A -m "0 white"
+
+echo red > color
+hg commit -A -m "1 red"
+
+hg update 0
+echo black > color
+hg commit -A -m "2 black"
+
+hg update --clean 1
+echo blue > color
+hg commit -A -m "3 blue"
+
+hg grep --all red
--- a/tests/test-grep.out Sat Jun 20 18:58:34 2009 +0200
+++ b/tests/test-grep.out Sun Jun 21 19:06:57 2009 +0200
@@ -38,6 +38,13 @@
noeol:4:no infinite loo
% issue 685
adding color
+colour:1:octarine
color:0:octarine
colour:1:octarine
-colour:1:octarine
+% issue 337
+adding color
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+created new head
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+color:3:-:red
+color:1:+:red
--- a/tests/test-hardlinks-safety.out Sat Jun 20 18:58:34 2009 +0200
+++ b/tests/test-hardlinks-safety.out Sun Jun 21 19:06:57 2009 +0200
@@ -15,6 +15,8 @@
430ed4828a74fa4047bc816a25500f7472ab4bfe:foo
%
foo
+patch foo finalized without changeset message
+patch bar finalized without changeset message
%%%
4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c foo
430ed4828a74fa4047bc816a25500f7472ab4bfe bar
--- a/tests/test-help.out Sat Jun 20 18:58:34 2009 +0200
+++ b/tests/test-help.out Sun Jun 21 19:06:57 2009 +0200
@@ -99,6 +99,7 @@
diffs Diff Formats
templating Template Usage
urls URL Paths
+ extensions Using additional features
use "hg -v help" to show aliases and global options
add add the specified files on the next commit
@@ -160,6 +161,7 @@
diffs Diff Formats
templating Template Usage
urls URL Paths
+ extensions Using additional features
hg add [OPTION]... [FILE]...
add the specified files on the next commit
--- a/tests/test-merge-default Sat Jun 20 18:58:34 2009 +0200
+++ b/tests/test-merge-default Sun Jun 21 19:06:57 2009 +0200
@@ -31,7 +31,7 @@
hg commit -mm1
echo % should succeed - 2 heads
-hg merge -S
+hg merge -P
hg merge
hg commit -mm2
--- a/tests/test-merge1 Sat Jun 20 18:58:34 2009 +0200
+++ b/tests/test-merge1 Sun Jun 21 19:06:57 2009 +0200
@@ -30,7 +30,7 @@
hg commit -m "commit #2" -d "1000000 0"
echo This is file b1 > b
echo %% no merges expected
-hg merge -S 1
+hg merge -P 1
hg merge 1
hg diff --nodates
hg status
--- a/tests/test-mq-qdelete.out Sat Jun 20 18:58:34 2009 +0200
+++ b/tests/test-mq-qdelete.out Sun Jun 21 19:06:57 2009 +0200
@@ -13,9 +13,12 @@
b
series
status
+patch a finalized without changeset message
1 [mq]: a
0 base
abort: cannot delete revision 3 above applied patches
+patch d finalized without changeset message
+patch e finalized without changeset message
f
4 [mq]: f
3 [mq]: e
@@ -32,11 +35,14 @@
applying c
patch c is empty
now at: c
+patch a finalized without changeset message
+patch b finalized without changeset message
c
3 imported patch c
2 [mq]: b
1 [mq]: a
0 base
+patch c finalized without changeset message
3 imported patch c
2 [mq]: b
1 [mq]: a
--- a/tests/test-mq-qimport.out Sat Jun 20 18:58:34 2009 +0200
+++ b/tests/test-mq-qimport.out Sun Jun 21 19:06:57 2009 +0200
@@ -27,3 +27,5 @@
adding another.diff to series file
applying another.diff
now at: another.diff
+patch b.diff finalized without changeset message
+patch another.diff finalized without changeset message
--- a/tests/test-mq-qpush-fail Sat Jun 20 18:58:34 2009 +0200
+++ b/tests/test-mq-qpush-fail Sun Jun 21 19:06:57 2009 +0200
@@ -45,3 +45,12 @@
echo '% bar should be gone; other unknown/ignored files should still be around'
hg status -A
+
+echo '% preparing qpush of a missing patch'
+hg qpop -a
+hg qpush
+rm .hg/patches/patch2
+echo '% now we expect the push to fail, but it should NOT complain about patch1'
+hg qpush
+
+true # happy ending
--- a/tests/test-mq-qpush-fail.out Sat Jun 20 18:58:34 2009 +0200
+++ b/tests/test-mq-qpush-fail.out Sun Jun 21 19:06:57 2009 +0200
@@ -19,3 +19,11 @@
? untracked-file
I .hgignore
C foo
+% preparing qpush of a missing patch
+no patches applied
+applying patch1
+now at: patch1
+% now we expect the push to fail, but it should NOT complain about patch1
+applying patch2
+unable to read patch2
+now at: patch1
--- a/tests/test-tags.out Sat Jun 20 18:58:34 2009 +0200
+++ b/tests/test-tags.out Sun Jun 21 19:06:57 2009 +0200
@@ -26,14 +26,12 @@
.hgtags@c071f74ab5eb, line 2: cannot parse entry
.hgtags@c071f74ab5eb, line 4: node 'foo' is not well formed
.hgtags@4ca6f1b1a68c, line 2: node 'x' is not well formed
-localtags, line 1: tag 'invalid' refers to unknown node
tip 8:4ca6f1b1a68c
first 0:0acdaf898367
changeset: 8:4ca6f1b1a68c
.hgtags@c071f74ab5eb, line 2: cannot parse entry
.hgtags@c071f74ab5eb, line 4: node 'foo' is not well formed
.hgtags@4ca6f1b1a68c, line 2: node 'x' is not well formed
-localtags, line 1: tag 'invalid' refers to unknown node
tag: tip
parent: 3:b2ef3841386b
user: test
--- a/tests/test-up-issue1456 Sat Jun 20 18:58:34 2009 +0200
+++ b/tests/test-up-issue1456 Sun Jun 21 19:06:57 2009 +0200
@@ -10,7 +10,7 @@
hg ci -m1
hg co -q 0
echo dirty > foo
-sleep 1
+hg up -c
hg up -q
cat foo
hg st -A
--- a/tests/test-up-issue1456.out Sat Jun 20 18:58:34 2009 +0200
+++ b/tests/test-up-issue1456.out Sun Jun 21 19:06:57 2009 +0200
@@ -1,3 +1,4 @@
+abort: uncommitted local changes
dirty
M foo
% validate update of standalone execute bit change