--- a/contrib/hbisect.py Tue Feb 14 21:11:57 2006 +0100
+++ b/contrib/hbisect.py Tue Feb 21 16:46:38 2006 +0100
@@ -187,7 +187,7 @@
check_clean(self.ui, self.repo)
rev = self.next()
self.ui.write("Now testing %s\n" % hg.hex(rev))
- return self.repo.update(rev, allow=True, force=True)
+ return self.repo.update(rev, force=True)
def good(self, rev):
self.goodrevs.append(rev)
@@ -232,7 +232,7 @@
b.good(new_rev)
ui.write("it is good\n")
anc = b.ancestors()
- repo.update(new_rev, allow=True, force=True)
+ repo.update(new_rev, force=True)
for v in anc:
if v != rev:
ui.warn("fail to found cset! :(\n")
--- a/doc/hg.1.txt Tue Feb 14 21:11:57 2006 +0100
+++ b/doc/hg.1.txt Tue Feb 21 16:46:38 2006 +0100
@@ -223,9 +223,11 @@
probably with undesirable results.
options:
- -a, --text treat all files as text
- -I, --include <pat> include names matching the given patterns
- -X, --exclude <pat> exclude names matching the given patterns
+ -a, --text treat all files as text
+ -I, --include <pat> include names matching the given patterns
+ -p, --show-function show which function each change is in
+ -X, --exclude <pat> exclude names matching the given patterns
+ -w, --ignore-all-space ignore white space when comparing lines
export [-o filespec] [revision] ...::
Print the changeset header and diffs for one or more revisions.
@@ -374,6 +376,11 @@
options:
-I, --include <pat> include names matching the given patterns
-X, --exclude <pat> exclude names matching the given patterns
+ -b, --branch show branches
+ -k, --keyword <str> search for keywords
+ -l, --limit <num> print no more than this many changes
+ -M, --no-merges do not show merges
+ -m, --only-merges only show merges
-r, --rev <A> show the specified revision or range
-p, --patch show patch
@@ -541,10 +548,12 @@
options:
-A, --accesslog <file> name of access log file to write to
+ -d, --daemon run server in background, as a daemon
-E, --errorlog <file> name of error log file to write to
-a, --address <addr> address to use
-p, --port <n> port to use (default: 8000)
-n, --name <name> name to show in web pages (default: working dir)
+ --pid-file <file> write server process ID to given file
-t, --templatedir <path> web templates to use
-6, --ipv6 use IPv6 in addition to IPv4
@@ -600,9 +609,12 @@
This lists both regular and local tags.
-tip::
+tip [-p]::
Show the tip revision.
+ options:
+ -p, --patch show patch
+
unbundle <file>::
(EXPERIMENTAL)
--- a/doc/hgrc.5.txt Tue Feb 14 21:11:57 2006 +0100
+++ b/doc/hgrc.5.txt Tue Feb 21 16:46:38 2006 +0100
@@ -145,20 +145,71 @@
incoming.email = /my/email/hook
incoming.autobuild = /my/build/hook
+ Most hooks are run with environment variables set that give added
+ useful information. For each hook below, the environment variables
+ it is passed are listed with names of the form "$HG_foo".
+
changegroup;;
- Run after a changegroup has been added via push or pull. Passed
- the ID of the first new changeset in $NODE.
+ Run after a changegroup has been added via push, pull or
+ unbundle. ID of the first new changeset is in $HG_NODE.
commit;;
Run after a changeset has been created in the local repository.
- Passed the ID of the newly created changeset in environment
- variable $NODE.
+ ID of the newly created changeset is in $HG_NODE. Parent
+ changeset IDs are in $HG_PARENT1 and $HG_PARENT2.
incoming;;
Run after a changeset has been pulled, pushed, or unbundled into
- the local repository. Passed the ID of the newly arrived
- changeset in environment variable $NODE.
+ the local repository. The ID of the newly arrived changeset is in
+ $HG_NODE.
+ outgoing;;
+ Run after sending changes from local repository to another. ID of
+ first changeset sent is in $HG_NODE. Source of operation is in
+ $HG_SOURCE; see "preoutgoing" hook for description.
+ prechangegroup;;
+ Run before a changegroup is added via push, pull or unbundle.
+ Exit status 0 allows the changegroup to proceed. Non-zero status
+ will cause the push, pull or unbundle to fail.
precommit;;
- Run before starting a commit. Exit status 0 allows the commit to
- proceed. Non-zero status will cause the commit to fail.
+ Run before starting a local commit. Exit status 0 allows the
+ commit to proceed. Non-zero status will cause the commit to fail.
+ Parent changeset IDs are in $HG_PARENT1 and $HG_PARENT2.
+ preoutgoing;;
+ Run before computing changes to send from the local repository to
+ another. Non-zero status will cause failure. This lets you
+ prevent pull over http or ssh. Also prevents against local pull,
+ push (outbound) or bundle commands, but not effective, since you
+ can just copy files instead then. Source of operation is in
+ $HG_SOURCE. If "serve", operation is happening on behalf of
+ remote ssh or http repository. If "push", "pull" or "bundle",
+ operation is happening on behalf of repository on same system.
+ pretag;;
+ Run before creating a tag. Exit status 0 allows the tag to be
+ created. Non-zero status will cause the tag to fail. ID of
+ changeset to tag is in $HG_NODE. Name of tag is in $HG_TAG. Tag
+ is local if $HG_LOCAL=1, in repo if $HG_LOCAL=0.
+ pretxnchangegroup;;
+ Run after a changegroup has been added via push, pull or unbundle,
+ but before the transaction has been committed. Changegroup is
+ visible to hook program. This lets you validate incoming changes
+ before accepting them. Passed the ID of the first new changeset
+ in $HG_NODE. Exit status 0 allows the transaction to commit.
+ Non-zero status will cause the transaction to be rolled back and
+ the push, pull or unbundle will fail.
+ pretxncommit;;
+ Run after a changeset has been created but the transaction not yet
+ committed. Changeset is visible to hook program. This lets you
+ validate commit message and changes. Exit status 0 allows the
+ commit to proceed. Non-zero status will cause the transaction to
+ be rolled back. ID of changeset is in $HG_NODE. Parent changeset
+ IDs are in $HG_PARENT1 and $HG_PARENT2.
+ tag;;
+ Run after a tag is created. ID of tagged changeset is in
+ $HG_NODE. Name of tag is in $HG_TAG. Tag is local if
+ $HG_LOCAL=1, in repo if $HG_LOCAL=0.
+
+ In earlier releases, the names of hook environment variables did not
+ have a "HG_" prefix. These unprefixed names are still provided in
+ the environment for backwards compatibility, but their use is
+ deprecated, and they will be removed in a future release.
http_proxy::
Used to access web-based Mercurial repositories through a HTTP
--- a/mercurial/commands.py Tue Feb 14 21:11:57 2006 +0100
+++ b/mercurial/commands.py Tue Feb 21 16:46:38 2006 +0100
@@ -115,8 +115,8 @@
yield rev
minrev, maxrev = min(revs), max(revs)
- for file in files:
- filelog = repo.file(file)
+ for file_ in files:
+ filelog = repo.file(file_)
# A zero count may be a directory or deleted file, so
# try to find matching entries on the slow path.
if filelog.count() == 0:
@@ -127,7 +127,7 @@
if rev < minrev:
break
fncache.setdefault(rev, [])
- fncache[rev].append(file)
+ fncache[rev].append(file_)
wanted[rev] = 1
if slowpath:
# The slow path checks files modified in every changeset.
@@ -261,7 +261,7 @@
mode)
def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
- changes=None, text=False):
+ changes=None, text=False, opts={}):
if not changes:
changes = repo.changes(node1, node2, files, match=match)
modified, added, removed, deleted, unknown = changes
@@ -296,8 +296,8 @@
date1 = util.datestr(change[2])
diffopts = ui.diffopts()
- showfunc = diffopts['showfunc']
- ignorews = diffopts['ignorews']
+ showfunc = opts.get('show_function') or diffopts['showfunc']
+ ignorews = opts.get('ignore_all_space') or diffopts['ignorews']
for f in modified:
to = None
if f in mmap:
@@ -447,7 +447,6 @@
f = f.lstrip("^")
if not ui.debugflag and f.startswith("debug"):
continue
- d = ""
doc = e[0].__doc__
if not doc:
doc = _("(No help text available)")
@@ -622,7 +621,7 @@
dest = ui.expandpath(dest, repo.root)
other = hg.repository(ui, dest)
o = repo.findoutgoing(other)
- cg = repo.changegroup(o)
+ cg = repo.changegroup(o, 'bundle')
try:
f.write("HG10")
@@ -725,8 +724,8 @@
# can end up with extra data in the cloned revlogs that's
# not pointed to by changesets, thus causing verify to
# fail
- l1 = lock.lock(os.path.join(source, ".hg", "lock"))
- except OSError:
+ l1 = other.lock()
+ except lock.LockException:
copy = False
if copy:
@@ -818,14 +817,19 @@
reasons = {'?': _('is not managed'),
'a': _('has been marked for add'),
'r': _('has been marked for remove')}
- reason = reasons.get(repo.dirstate.state(abs))
+ state = repo.dirstate.state(abs)
+ reason = reasons.get(state)
if reason:
+ if state == 'a':
+ origsrc = repo.dirstate.copied(abs)
+ if origsrc is not None:
+ return origsrc
if exact:
ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
else:
- return True
-
- def copy(abssrc, relsrc, target, exact):
+ return abs
+
+ def copy(origsrc, abssrc, relsrc, target, exact):
abstarget = util.canonpath(repo.root, cwd, target)
reltarget = util.pathto(cwd, abstarget)
prevsrc = targets.get(abstarget)
@@ -864,7 +868,7 @@
if ui.verbose or not exact:
ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
targets[abstarget] = abssrc
- repo.copy(abssrc, abstarget)
+ repo.copy(origsrc, abstarget)
copied.append((abssrc, relsrc, exact))
def targetpathfn(pat, dest, srcs):
@@ -938,8 +942,9 @@
for pat in pats:
srcs = []
for tag, abssrc, relsrc, exact in walk(repo, [pat], opts):
- if okaytocopy(abssrc, relsrc, exact):
- srcs.append((abssrc, relsrc, exact))
+ origsrc = okaytocopy(abssrc, relsrc, exact)
+ if origsrc:
+ srcs.append((origsrc, abssrc, relsrc, exact))
if not srcs:
continue
copylist.append((tfn(pat, dest, srcs), srcs))
@@ -947,8 +952,8 @@
raise util.Abort(_('no files to copy'))
for targetpath, srcs in copylist:
- for abssrc, relsrc, exact in srcs:
- copy(abssrc, relsrc, targetpath(abssrc), exact)
+ for origsrc, abssrc, relsrc, exact in srcs:
+ copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
if errors:
ui.warn(_('(consider using --after)\n'))
@@ -980,6 +985,18 @@
a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
ui.write("%d:%s\n" % (r.rev(a), hex(a)))
+def debugrebuildstate(ui, repo, rev=None):
+ """rebuild the dirstate as it would look like for the given revision"""
+ if not rev:
+ rev = repo.changelog.tip()
+ else:
+ rev = repo.lookup(rev)
+ change = repo.changelog.read(rev)
+ n = change[0]
+ files = repo.manifest.readflags(n)
+ wlock = repo.wlock()
+ repo.dirstate.rebuild(rev, files.iteritems())
+
def debugcheckstate(ui, repo):
"""validate the correctness of the current dirstate"""
parent1, parent2 = repo.dirstate.parents()
@@ -1140,7 +1157,7 @@
fns, matchfn, anypats = matchpats(repo, pats, opts)
dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn,
- text=opts['text'])
+ text=opts['text'], opts=opts)
def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
node = repo.lookup(changeset)
@@ -1284,6 +1301,7 @@
s = linestate(line, lnum, cstart, cend)
m[s] = s
+ # FIXME: prev isn't used, why ?
prev = {}
ucache = {}
def display(fn, rev, states, prevstates):
@@ -1593,7 +1611,19 @@
self.write(*args)
def __getattr__(self, key):
return getattr(self.ui, key)
+
changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
+
+ if opts['limit']:
+ try:
+ limit = int(opts['limit'])
+ except ValueError:
+ raise util.Abort(_('limit must be a positive integer'))
+ if limit <= 0: raise util.Abort(_('limit must be positive'))
+ else:
+ limit = sys.maxint
+ count = 0
+
for st, rev, fns in changeiter:
if st == 'window':
du = dui(ui)
@@ -1607,7 +1637,6 @@
if opts['only_merges'] and len(parents) != 2:
continue
- br = None
if opts['keyword']:
changes = getchange(rev)
miss = 0
@@ -1620,7 +1649,8 @@
if miss:
continue
- if opts['branch']:
+ br = None
+ if opts['branches']:
br = repo.branchlookup([repo.changelog.node(rev)])
show_changeset(du, repo, rev, brinfo=br)
@@ -1629,8 +1659,11 @@
dodiff(du, du, repo, prev, changenode, match=matchfn)
du.write("\n\n")
elif st == 'iter':
- for args in du.hunk[rev]:
- ui.write(*args)
+ if count == limit: break
+ if du.hunk[rev]:
+ count += 1
+ for args in du.hunk[rev]:
+ ui.write(*args)
def manifest(ui, repo, rev=None):
"""output the latest or given revision of the project manifest
@@ -1681,7 +1714,7 @@
dodiff(ui, ui, repo, prev, n)
ui.write("\n")
-def parents(ui, repo, rev=None):
+def parents(ui, repo, rev=None, branches=None):
"""show the parents of the working dir or revision
Print the working directory's parent revisions.
@@ -1691,9 +1724,12 @@
else:
p = repo.dirstate.parents()
+ br = None
+ if branches is not None:
+ br = repo.branchlookup(p)
for n in p:
if n != nullid:
- show_changeset(ui, repo, changenode=n)
+ show_changeset(ui, repo, changenode=n, brinfo=br)
def paths(ui, search=None):
"""show definition of symbolic path names
@@ -1999,7 +2035,7 @@
arg, roots = getarg()
nodes = map(bin, roots.split(" "))
- cg = repo.changegroup(nodes)
+ cg = repo.changegroup(nodes, 'serve')
while 1:
d = cg.read(4096)
if not d:
@@ -2022,6 +2058,16 @@
if opts[o]:
ui.setconfig("web", o, opts[o])
+ if opts['daemon'] and not opts['daemon_pipefds']:
+ rfd, wfd = os.pipe()
+ args = sys.argv[:]
+ args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
+ pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
+ args[0], args)
+ os.close(wfd)
+ os.read(rfd, 1)
+ os._exit(0)
+
try:
httpd = hgweb.create_server(repo)
except socket.error, inst:
@@ -2040,6 +2086,25 @@
ui.status(_('listening at http://%s:%d/\n') % (addr, port))
else:
ui.status(_('listening at http://%s/\n') % addr)
+
+ if opts['pid_file']:
+ fp = open(opts['pid_file'], 'w')
+ fp.write(str(os.getpid()))
+ fp.close()
+
+ if opts['daemon_pipefds']:
+ rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
+ os.close(rfd)
+ os.write(wfd, 'y')
+ os.close(wfd)
+ sys.stdout.flush()
+ sys.stderr.flush()
+ fd = os.open(util.nulldev, os.O_RDWR)
+ if fd != 0: os.dup2(fd, 0)
+ if fd != 1: os.dup2(fd, 1)
+ if fd != 2: os.dup2(fd, 2)
+ if fd not in (0, 1, 2): os.close(fd)
+
httpd.serve_forever()
def status(ui, repo, *pats, **opts):
@@ -2116,8 +2181,12 @@
if name.find(c) >= 0:
raise util.Abort(_("%s cannot be used in a tag name") % repr(c))
+ repo.hook('pretag', throw=True, node=r, tag=name,
+ local=int(not not opts['local']))
+
if opts['local']:
repo.opener("localtags", "a").write("%s %s\n" % (r, name))
+ repo.hook('tag', node=r, tag=name, local=1)
return
for x in repo.changes():
@@ -2133,6 +2202,7 @@
_("Added tag %s for changeset %s") % (name, r))
try:
repo.commit([".hgtags"], message, opts['user'], opts['date'])
+ repo.hook('tag', node=r, tag=name, local=0)
except ValueError, inst:
raise util.Abort(str(inst))
@@ -2153,13 +2223,18 @@
r = " ?:?"
ui.write("%-30s %s\n" % (t, r))
-def tip(ui, repo):
+def tip(ui, repo, **opts):
"""show the tip revision
Show the tip revision.
"""
n = repo.changelog.tip()
- show_changeset(ui, repo, changenode=n)
+ br = None
+ if opts['branches']:
+ br = repo.branchlookup([n])
+ show_changeset(ui, repo, changenode=n, brinfo=br)
+ if opts['patch']:
+ dodiff(ui, ui, repo, repo.changelog.parents(n)[0], n)
def unbundle(ui, repo, fname, **opts):
"""apply a changegroup file
@@ -2317,6 +2392,10 @@
_('forcibly copy over an existing managed file'))],
_('hg copy [OPTION]... [SOURCE]... DEST')),
"debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
+ "debugrebuildstate":
+ (debugrebuildstate,
+ [('r', 'rev', "", _("revision to rebuild to"))],
+ _('debugrebuildstate [-r REV] [REV]')),
"debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
"debugconfig": (debugconfig, [], _('debugconfig')),
"debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
@@ -2335,7 +2414,12 @@
[('r', 'rev', [], _('revision')),
('a', 'text', None, _('treat all files as text')),
('I', 'include', [], _('include names matching the given patterns')),
- ('X', 'exclude', [], _('exclude names matching the given patterns'))],
+ ('p', 'show-function', None,
+ _('show which function each change is in')),
+ ('w', 'ignore-all-space', None,
+ _('ignore white space when comparing lines')),
+ ('X', 'exclude', [],
+ _('exclude names matching the given patterns'))],
_('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
"^export":
(export,
@@ -2363,7 +2447,7 @@
_('hg grep [OPTION]... PATTERN [FILE]...')),
"heads":
(heads,
- [('b', 'branches', None, _('find branch info')),
+ [('b', 'branches', None, _('show branches')),
('r', 'rev', '', _('show only heads which are descendants of rev'))],
_('hg heads [-b] [-r <rev>]')),
"help": (help_, [], _('hg help [COMMAND]')),
@@ -2397,8 +2481,9 @@
(log,
[('I', 'include', [], _('include names matching the given patterns')),
('X', 'exclude', [], _('exclude names matching the given patterns')),
- ('b', 'branch', None, _('show branches')),
+ ('b', 'branches', None, _('show branches')),
('k', 'keyword', [], _('search for a keyword')),
+ ('l', 'limit', '', _('limit number of changes displayed')),
('r', 'rev', [], _('show the specified revision or range')),
('M', 'no-merges', None, _('do not show merges')),
('m', 'only-merges', None, _('show only merges')),
@@ -2410,7 +2495,10 @@
('p', 'patch', None, _('show patch')),
('n', 'newest-first', None, _('show newest record first'))],
_('hg outgoing [-p] [-n] [-M] [DEST]')),
- "^parents": (parents, [], _('hg parents [REV]')),
+ "^parents":
+ (parents,
+ [('b', 'branches', None, _('show branches'))],
+ _('hg parents [-b] [REV]')),
"paths": (paths, [], _('hg paths [NAME]')),
"^pull":
(pull,
@@ -2462,11 +2550,14 @@
"^serve":
(serve,
[('A', 'accesslog', '', _('name of access log file to write to')),
+ ('d', 'daemon', None, _('run server in background')),
+ ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
('E', 'errorlog', '', _('name of error log file to write to')),
('p', 'port', 0, _('port to use (default: 8000)')),
('a', 'address', '', _('address to use')),
('n', 'name', '',
_('name to show in web pages (default: working dir)')),
+ ('', 'pid-file', '', _('name of file to write process ID to')),
('', 'stdio', None, _('for remote clients')),
('t', 'templates', '', _('web templates to use')),
('', 'style', '', _('template style to use')),
@@ -2494,7 +2585,11 @@
('r', 'rev', '', _('revision to tag'))],
_('hg tag [-r REV] [OPTION]... NAME')),
"tags": (tags, [], _('hg tags')),
- "tip": (tip, [], _('hg tip')),
+ "tip":
+ (tip,
+ [('b', 'branches', None, _('show branches')),
+ ('p', 'patch', None, _('show patch'))],
+ _('hg [-b] [-p] tip')),
"unbundle":
(unbundle,
[('u', 'update', None,
@@ -2534,17 +2629,20 @@
def find(cmd):
"""Return (aliases, command table entry) for command string."""
choice = None
+ count = 0
for e in table.keys():
aliases = e.lstrip("^").split("|")
if cmd in aliases:
return aliases, table[e]
for a in aliases:
if a.startswith(cmd):
- if choice:
- raise AmbiguousCommand(cmd)
- else:
- choice = aliases, table[e]
- break
+ count += 1
+ choice = aliases, table[e]
+ break
+
+ if count > 1:
+ raise AmbiguousCommand(cmd)
+
if choice:
return choice
--- a/mercurial/dirstate.py Tue Feb 14 21:11:57 2006 +0100
+++ b/mercurial/dirstate.py Tue Feb 21 16:46:38 2006 +0100
@@ -197,6 +197,19 @@
def clear(self):
self.map = {}
+ self.copies = {}
+ self.markdirty()
+
+ def rebuild(self, parent, files):
+ self.clear()
+ umask = os.umask(0)
+ os.umask(umask)
+ for f, mode in files:
+ if mode:
+ self.map[f] = ('n', ~umask, -1, 0)
+ else:
+ self.map[f] = ('n', ~umask & 0666, -1, 0)
+ self.pl = (parent, nullid)
self.markdirty()
def write(self):
@@ -270,11 +283,11 @@
elif not dc:
dc = self.filterfiles(files)
- def statmatch(file, stat):
- file = util.pconvert(file)
- if file not in dc and self.ignore(file):
+ def statmatch(file_, stat):
+ file_ = util.pconvert(file_)
+ if file_ not in dc and self.ignore(file_):
return False
- return match(file)
+ return match(file_)
return self.walkhelper(files=files, statmatch=statmatch, dc=dc)
@@ -350,9 +363,9 @@
continue
if stat.S_ISDIR(st.st_mode):
cmp1 = (lambda x, y: cmp(x[1], y[1]))
- sorted = [ x for x in findfiles(f) ]
- sorted.sort(cmp1)
- for e in sorted:
+ sorted_ = [ x for x in findfiles(f) ]
+ sorted_.sort(cmp1)
+ for e in sorted_:
yield e
else:
ff = util.normpath(ff)
@@ -380,7 +393,7 @@
for src, fn, st in self.statwalk(files, match):
try:
- type, mode, size, time = self[fn]
+ type_, mode, size, time = self[fn]
except KeyError:
unknown.append(fn)
continue
@@ -399,22 +412,23 @@
nonexistent = False
# XXX: what to do with file no longer present in the fs
# who are not removed in the dirstate ?
- if nonexistent and type in "nm":
+ if nonexistent and type_ in "nm":
deleted.append(fn)
continue
# check the common case first
- if type == 'n':
+ if type_ == 'n':
if not st:
st = os.stat(fn)
- if size != st.st_size or (mode ^ st.st_mode) & 0100:
+ if size >= 0 and (size != st.st_size
+ or (mode ^ st.st_mode) & 0100):
modified.append(fn)
elif time != st.st_mtime:
lookup.append(fn)
- elif type == 'm':
+ elif type_ == 'm':
modified.append(fn)
- elif type == 'a':
+ elif type_ == 'a':
added.append(fn)
- elif type == 'r':
+ elif type_ == 'r':
removed.append(fn)
return (lookup, modified, added, removed, deleted, unknown)
--- a/mercurial/hgweb.py Tue Feb 14 21:11:57 2006 +0100
+++ b/mercurial/hgweb.py Tue Feb 21 16:46:38 2006 +0100
@@ -660,9 +660,10 @@
i = self.repo.tagslist()
i.reverse()
- def entries(**map):
+ def entries(notip=False, **map):
parity = 0
for k,n in i:
+ if notip and k == "tip": continue
yield {"parity": parity,
"tag": k,
"tagmanifest": hex(cl.read(n)[0]),
@@ -672,7 +673,8 @@
yield self.t("tags",
manifest=hex(mf),
- entries=entries)
+ entries=lambda **x: entries(False, **x),
+ entriesnotip=lambda **x: entries(True, **x))
def summary(self):
cl = self.repo.changelog
@@ -962,7 +964,7 @@
nodes = map(bin, req.form['roots'][0].split(" "))
z = zlib.compressobj()
- f = self.repo.changegroup(nodes)
+ f = self.repo.changegroup(nodes, 'serve')
while 1:
chunk = f.read(4096)
if not chunk:
--- a/mercurial/httprepo.py Tue Feb 14 21:11:57 2006 +0100
+++ b/mercurial/httprepo.py Tue Feb 21 16:46:38 2006 +0100
@@ -119,7 +119,7 @@
self.ui.warn(_("unexpected response:\n") + d[:400] + "\n...\n")
raise
- def changegroup(self, nodes):
+ def changegroup(self, nodes, kind):
n = " ".join(map(hex, nodes))
f = self.do_cmd("changegroup", roots=n)
bytes = 0
--- a/mercurial/localrepo.py Tue Feb 14 21:11:57 2006 +0100
+++ b/mercurial/localrepo.py Tue Feb 21 16:46:38 2006 +0100
@@ -48,30 +48,36 @@
except IOError:
pass
- def hook(self, name, **args):
+ def hook(self, name, throw=False, **args):
def runhook(name, cmd):
self.ui.note(_("running hook %s: %s\n") % (name, cmd))
old = {}
for k, v in args.items():
k = k.upper()
+ old['HG_' + k] = os.environ.get(k, None)
old[k] = os.environ.get(k, None)
- os.environ[k] = v
+ os.environ['HG_' + k] = str(v)
+ os.environ[k] = str(v)
- # Hooks run in the repository root
- olddir = os.getcwd()
- os.chdir(self.root)
- r = os.system(cmd)
- os.chdir(olddir)
+ try:
+ # Hooks run in the repository root
+ olddir = os.getcwd()
+ os.chdir(self.root)
+ r = os.system(cmd)
+ finally:
+ for k, v in old.items():
+ if v is not None:
+ os.environ[k] = v
+ else:
+ del os.environ[k]
- for k, v in old.items():
- if v != None:
- os.environ[k] = v
- else:
- del os.environ[k]
+ os.chdir(olddir)
if r:
- self.ui.warn(_("abort: %s hook failed with status %d!\n") %
- (name, r))
+ desc, r = util.explain_exit(r)
+ if throw:
+ raise util.Abort(_('%s hook %s') % (name, desc))
+ self.ui.warn(_('error: %s hook %s\n') % (name, desc))
return False
return True
@@ -225,7 +231,7 @@
self.join("journal"), after)
def recover(self):
- lock = self.lock()
+ l = self.lock()
if os.path.exists(self.join("journal")):
self.ui.status(_("rolling back interrupted transaction\n"))
transaction.rollback(self.opener, self.join("journal"))
@@ -239,7 +245,7 @@
def undo(self, wlock=None):
if not wlock:
wlock = self.wlock()
- lock = self.lock()
+ l = self.lock()
if os.path.exists(self.join("undo")):
self.ui.status(_("rolling back last transaction\n"))
transaction.rollback(self.opener, self.join("undo"))
@@ -248,25 +254,44 @@
else:
self.ui.warn(_("no undo information available\n"))
- def lock(self, wait=1):
+ def do_lock(self, lockname, wait, releasefn=None, acquirefn=None):
try:
- return lock.lock(self.join("lock"), 0)
- except lock.LockHeld, inst:
- if wait:
- self.ui.warn(_("waiting for lock held by %s\n") % inst.args[0])
- return lock.lock(self.join("lock"), wait)
- raise inst
-
- def wlock(self, wait=1):
- try:
- wlock = lock.lock(self.join("wlock"), 0, self.dirstate.write)
+ l = lock.lock(self.join(lockname), 0, releasefn)
except lock.LockHeld, inst:
if not wait:
raise inst
self.ui.warn(_("waiting for lock held by %s\n") % inst.args[0])
- wlock = lock.lock(self.join("wlock"), wait, self.dirstate.write)
- self.dirstate.read()
- return wlock
+ l = lock.lock(self.join(lockname), wait, releasefn)
+ if acquirefn:
+ acquirefn()
+ return l
+
+ def lock(self, wait=1):
+ return self.do_lock("lock", wait)
+
+ def wlock(self, wait=1):
+ return self.do_lock("wlock", wait,
+ self.dirstate.write,
+ self.dirstate.read)
+
+ def checkfilemerge(self, filename, text, filelog, manifest1, manifest2):
+ "determine whether a new filenode is needed"
+ fp1 = manifest1.get(filename, nullid)
+ fp2 = manifest2.get(filename, nullid)
+
+ if fp2 != nullid:
+ # is one parent an ancestor of the other?
+ fpa = filelog.ancestor(fp1, fp2)
+ if fpa == fp1:
+ fp1, fp2 = fp2, nullid
+ elif fpa == fp2:
+ fp2 = nullid
+
+ # is the file unmodified from the parent? report existing entry
+ if fp2 == nullid and text == filelog.read(fp1):
+ return (fp1, None, None)
+
+ return (None, fp1, fp2)
def rawcommit(self, files, text, user, date, p1=None, p2=None, wlock=None):
orig_parent = self.dirstate.parents()[0] or nullid
@@ -286,7 +311,7 @@
if not wlock:
wlock = self.wlock()
- lock = self.lock()
+ l = self.lock()
tr = self.transaction()
mm = m1.copy()
mfm = mf1.copy()
@@ -298,27 +323,10 @@
r = self.file(f)
mfm[f] = tm
- fp1 = m1.get(f, nullid)
- fp2 = m2.get(f, nullid)
-
- # is the same revision on two branches of a merge?
- if fp2 == fp1:
- fp2 = nullid
-
- if fp2 != nullid:
- # is one parent an ancestor of the other?
- fpa = r.ancestor(fp1, fp2)
- if fpa == fp1:
- fp1, fp2 = fp2, nullid
- elif fpa == fp2:
- fp2 = nullid
-
- # is the file unmodified from the parent?
- if t == r.read(fp1):
- # record the proper existing parent in manifest
- # no need to add a revision
- mm[f] = fp1
- continue
+ (entry, fp1, fp2) = self.checkfilemerge(f, t, r, m1, m2)
+ if entry:
+ mm[f] = entry
+ continue
mm[f] = r.add(t, {}, tr, linkrev, fp1, fp2)
changed.append(f)
@@ -372,12 +380,15 @@
self.ui.status(_("nothing changed\n"))
return None
- if not self.hook("precommit"):
- return None
+ xp1 = hex(p1)
+ if p2 == nullid: xp2 = ''
+ else: xp2 = hex(p2)
+
+ self.hook("precommit", throw=True, parent1=xp1, parent2=xp2)
if not wlock:
wlock = self.wlock()
- lock = self.lock()
+ l = self.lock()
tr = self.transaction()
# check in files
@@ -403,22 +414,9 @@
self.ui.debug(_(" %s: copy %s:%s\n") % (f, cp, meta["copyrev"]))
fp1, fp2 = nullid, nullid
else:
- fp1 = m1.get(f, nullid)
- fp2 = m2.get(f, nullid)
-
- if fp2 != nullid:
- # is one parent an ancestor of the other?
- fpa = r.ancestor(fp1, fp2)
- if fpa == fp1:
- fp1, fp2 = fp2, nullid
- elif fpa == fp2:
- fp2 = nullid
-
- # is the file unmodified from the parent?
- if not meta and t == r.read(fp1) and fp2 == nullid:
- # record the proper existing parent in manifest
- # no need to add a revision
- new[f] = fp1
+ entry, fp1, fp2 = self.checkfilemerge(f, t, r, m1, m2)
+ if entry:
+ new[f] = entry
continue
new[f] = r.add(t, meta, tr, linkrev, fp1, fp2)
@@ -459,14 +457,15 @@
user = user or self.ui.username()
n = self.changelog.add(mn, changed + remove, text, tr, p1, p2, user, date)
+ self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1,
+ parent2=xp2)
tr.close()
self.dirstate.setparents(n)
self.dirstate.update(new, "n")
self.dirstate.forget(remove)
- if not self.hook("commit", node=hex(n)):
- return None
+ self.hook("commit", node=hex(n), parent1=xp1, parent2=xp2)
return n
def walk(self, node=None, files=[], match=util.always):
@@ -509,7 +508,7 @@
if not wlock:
try:
wlock = self.wlock(wait=0)
- except lock.LockHeld:
+ except lock.LockException:
wlock = None
lookup, modified, added, removed, deleted, unknown = (
self.dirstate.changes(files, match))
@@ -598,7 +597,6 @@
if os.path.exists(p):
self.ui.warn(_("%s still exists!\n") % f)
elif self.dirstate.state(f) == 'a':
- self.ui.warn(_("%s never committed!\n") % f)
self.dirstate.forget([f])
elif f not in self.dirstate:
self.ui.warn(_("%s not tracked!\n") % f)
@@ -933,7 +931,7 @@
return subset
def pull(self, remote, heads=None):
- lock = self.lock()
+ l = self.lock()
# if we have an empty repo, fetch everything
if self.changelog.tip() == nullid:
@@ -947,9 +945,9 @@
return 1
if heads is None:
- cg = remote.changegroup(fetch)
+ cg = remote.changegroup(fetch, 'pull')
else:
- cg = remote.changegroupsubset(fetch, heads)
+ cg = remote.changegroupsubset(fetch, heads, 'pull')
return self.addchangegroup(cg)
def push(self, remote, force=False, revs=None):
@@ -980,12 +978,12 @@
return 1
if revs is None:
- cg = self.changegroup(update)
+ cg = self.changegroup(update, 'push')
else:
- cg = self.changegroupsubset(update, revs)
+ cg = self.changegroupsubset(update, revs, 'push')
return remote.addchangegroup(cg)
- def changegroupsubset(self, bases, heads):
+ def changegroupsubset(self, bases, heads, source):
"""This function generates a changegroup consisting of all the nodes
that are descendents of any of the bases, and ancestors of any of
the heads.
@@ -997,6 +995,8 @@
Another wrinkle is doing the reverse, figuring out which changeset in
the changegroup a particular filenode or manifestnode belongs to."""
+ self.hook('preoutgoing', throw=True, source=source)
+
# Set up some initial variables
# Make it easy to refer to self.changelog
cl = self.changelog
@@ -1249,14 +1249,19 @@
# Signal that no more groups are left.
yield struct.pack(">l", 0)
+ self.hook('outgoing', node=hex(msng_cl_lst[0]), source=source)
+
return util.chunkbuffer(gengroup())
- def changegroup(self, basenodes):
+ def changegroup(self, basenodes, source):
"""Generate a changegroup of all nodes that we have that a recipient
doesn't.
This is much easier than the previous function as we can assume that
the recipient has any changenode we aren't sending them."""
+
+ self.hook('preoutgoing', throw=True, source=source)
+
cl = self.changelog
nodes = cl.nodesbetween(basenodes, None)[0]
revset = dict.fromkeys([cl.rev(n) for n in nodes])
@@ -1308,6 +1313,7 @@
yield chnk
yield struct.pack(">l", 0)
+ self.hook('outgoing', node=hex(nodes[0]), source=source)
return util.chunkbuffer(gengroup())
@@ -1343,6 +1349,9 @@
if not source:
return
+
+ self.hook('prechangegroup', throw=True)
+
changesets = files = revisions = 0
tr = self.transaction()
@@ -1385,19 +1394,17 @@
" with %d changes to %d files%s\n")
% (changesets, revisions, files, heads))
+ self.hook('pretxnchangegroup', throw=True,
+ node=hex(self.changelog.node(cor+1)))
+
tr.close()
if changesets > 0:
- if not self.hook("changegroup",
- node=hex(self.changelog.node(cor+1))):
- self.ui.warn(_("abort: changegroup hook returned failure!\n"))
- return 1
+ self.hook("changegroup", node=hex(self.changelog.node(cor+1)))
for i in range(cor + 1, cnr + 1):
self.hook("incoming", node=hex(self.changelog.node(i)))
- return
-
def update(self, node, allow=False, force=False, choose=None,
moddirstate=True, forcemerge=False, wlock=None):
pl = self.dirstate.parents()
--- a/mercurial/lock.py Tue Feb 14 21:11:57 2006 +0100
+++ b/mercurial/lock.py Tue Feb 21 16:46:38 2006 +0100
@@ -5,10 +5,14 @@
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
-import os, time
+import errno, os, time
import util
-class LockHeld(Exception):
+class LockException(Exception):
+ pass
+class LockHeld(LockException):
+ pass
+class LockUnavailable(LockException):
pass
class lock(object):
@@ -38,8 +42,11 @@
try:
util.makelock(str(pid), self.f)
self.held = 1
- except (OSError, IOError):
- raise LockHeld(util.readlock(self.f))
+ except (OSError, IOError), why:
+ if why.errno == errno.EEXIST:
+ raise LockHeld(util.readlock(self.f))
+ else:
+ raise LockUnavailable(why)
def release(self):
if self.held:
--- a/mercurial/mdiff.py Tue Feb 14 21:11:57 2006 +0100
+++ b/mercurial/mdiff.py Tue Feb 21 16:46:38 2006 +0100
@@ -18,16 +18,22 @@
if not text and (util.binary(a) or util.binary(b)):
l = ['Binary file %s has changed\n' % fn]
- elif a == None:
+ elif not a:
b = b.splitlines(1)
- l1 = "--- %s\t%s\n" % ("/dev/null", epoch)
+ if a is None:
+ l1 = "--- %s\t%s\n" % ("/dev/null", epoch)
+ else:
+ l1 = "--- %s\t%s\n" % ("a/" + fn, ad)
l2 = "+++ %s\t%s\n" % ("b/" + fn, bd)
l3 = "@@ -0,0 +1,%d @@\n" % len(b)
l = [l1, l2, l3] + ["+" + e for e in b]
- elif b == None:
+ elif not b:
a = a.splitlines(1)
l1 = "--- %s\t%s\n" % ("a/" + fn, ad)
- l2 = "+++ %s\t%s\n" % ("/dev/null", epoch)
+ if b is None:
+ l2 = "+++ %s\t%s\n" % ("/dev/null", epoch)
+ else:
+ l2 = "+++ %s\t%s\n" % ("b/" + fn, bd)
l3 = "@@ -1,%d +0,0 @@\n" % len(a)
l = [l1, l2, l3] + ["-" + e for e in a]
else:
--- a/mercurial/mpatch.c Tue Feb 14 21:11:57 2006 +0100
+++ b/mercurial/mpatch.c Tue Feb 21 16:46:38 2006 +0100
@@ -43,6 +43,7 @@
#endif
static char mpatch_doc[] = "Efficient binary patching.";
+static PyObject *mpatch_Error;
struct frag {
int start, end, len;
@@ -65,8 +66,11 @@
a = NULL;
} else
a->head = a->tail = a->base;
+ return a;
}
- return a;
+ if (!PyErr_Occurred())
+ PyErr_NoMemory();
+ return NULL;
}
static void lfree(struct flist *a)
@@ -215,6 +219,9 @@
/* assume worst case size, we won't have many of these lists */
l = lalloc(len / 12);
+ if (!l)
+ return NULL;
+
lt = l->tail;
while (bin < end) {
@@ -227,6 +234,13 @@
lt++;
}
+ if (bin != end) {
+ if (!PyErr_Occurred())
+ PyErr_SetString(mpatch_Error, "patch cannot be decoded");
+ lfree(l);
+ return NULL;
+ }
+
l->tail = lt;
return l;
}
@@ -238,6 +252,12 @@
struct frag *f = l->head;
while (f != l->tail) {
+ if (f->start < last || f->end > len) {
+ if (!PyErr_Occurred())
+ PyErr_SetString(mpatch_Error,
+ "invalid patch");
+ return -1;
+ }
outlen += f->start - last;
last = f->end;
outlen += f->len;
@@ -248,13 +268,19 @@
return outlen;
}
-static void apply(char *buf, char *orig, int len, struct flist *l)
+static int apply(char *buf, char *orig, int len, struct flist *l)
{
struct frag *f = l->head;
int last = 0;
char *p = buf;
while (f != l->tail) {
+ if (f->start < last || f->end > len) {
+ if (!PyErr_Occurred())
+ PyErr_SetString(mpatch_Error,
+ "invalid patch");
+ return 0;
+ }
memcpy(p, orig + last, f->start - last);
p += f->start - last;
memcpy(p, f->data, f->len);
@@ -263,6 +289,7 @@
f++;
}
memcpy(p, orig + last, len - last);
+ return 1;
}
/* recursively generate a patch of all bins between start and end */
@@ -304,16 +331,25 @@
patch = fold(bins, 0, len);
if (!patch)
- return PyErr_NoMemory();
+ return NULL;
outlen = calcsize(PyString_Size(text), patch);
+ if (outlen < 0) {
+ result = NULL;
+ goto cleanup;
+ }
result = PyString_FromStringAndSize(NULL, outlen);
- if (result) {
- in = PyString_AsString(text);
- out = PyString_AsString(result);
- apply(out, in, PyString_Size(text), patch);
+ if (!result) {
+ result = NULL;
+ goto cleanup;
}
-
+ in = PyString_AsString(text);
+ out = PyString_AsString(result);
+ if (!apply(out, in, PyString_Size(text), patch)) {
+ Py_DECREF(result);
+ result = NULL;
+ }
+cleanup:
lfree(patch);
return result;
}
@@ -327,5 +363,6 @@
initmpatch(void)
{
Py_InitModule3("mpatch", methods, mpatch_doc);
+ mpatch_Error = PyErr_NewException("mpatch.mpatchError", NULL, NULL);
}
--- a/mercurial/revlog.py Tue Feb 14 21:11:57 2006 +0100
+++ b/mercurial/revlog.py Tue Feb 21 16:46:38 2006 +0100
@@ -624,12 +624,10 @@
# we store negative distances because heap returns smallest member
h = [(-dist[node], node)]
seen = {}
- earliest = self.count()
while h:
d, n = heapq.heappop(h)
if n not in seen:
seen[n] = 1
- r = self.rev(n)
yield (-d, n)
for p in self.parents(n):
heapq.heappush(h, (-dist[p], p))
@@ -690,11 +688,6 @@
p = self.parents(self.node(revs[0]))[0]
revs.insert(0, self.rev(p))
- # helper to reconstruct intermediate versions
- def construct(text, base, rev):
- bins = [self.chunk(r) for r in xrange(base + 1, rev + 1)]
- return mdiff.patches(text, bins)
-
# build deltas
for d in xrange(0, len(revs) - 1):
a, b = revs[d], revs[d + 1]
@@ -738,10 +731,10 @@
base = prev = -1
start = end = measure = 0
if r:
- start = self.start(self.base(t))
+ base = self.base(t)
+ start = self.start(base)
end = self.end(t)
- measure = self.length(self.base(t))
- base = self.base(t)
+ measure = self.length(base)
prev = self.tip()
transaction.add(self.datafile, end)
@@ -793,14 +786,15 @@
raise RevlogError(_("consistency error adding group"))
measure = len(text)
else:
- e = (end, len(cdelta), self.base(t), link, p1, p2, node)
+ e = (end, len(cdelta), base, link, p1, p2, node)
self.index.append(e)
self.nodemap[node] = r
dfh.write(cdelta)
ifh.write(struct.pack(indexformat, *e))
t, r, chain, prev = r, r + 1, node, node
- start = self.start(self.base(t))
+ base = self.base(t)
+ start = self.start(base)
end = self.end(t)
dfh.close()
--- a/mercurial/sshrepo.py Tue Feb 14 21:11:57 2006 +0100
+++ b/mercurial/sshrepo.py Tue Feb 21 16:46:38 2006 +0100
@@ -110,7 +110,7 @@
except:
raise hg.RepoError(_("unexpected response '%s'") % (d[:400] + "..."))
- def changegroup(self, nodes):
+ def changegroup(self, nodes, kind):
n = " ".join(map(hex, nodes))
f = self.do_cmd("changegroup", roots=n)
return self.pipei
--- a/templates/map-rss Tue Feb 14 21:11:57 2006 +0100
+++ b/templates/map-rss Tue Feb 21 16:46:38 2006 +0100
@@ -4,3 +4,5 @@
changelogentry = changelogentry-rss.tmpl
filelog = filelog-rss.tmpl
filelogentry = filelogentry-rss.tmpl
+tags = tags-rss.tmpl
+tagentry = tagentry-rss.tmpl
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/tagentry-rss.tmpl Tue Feb 21 16:46:38 2006 +0100
@@ -0,0 +1,6 @@
+<item>
+ <title>#tag|escape#</title>
+ <link>#url#?cs=#node|short#</link>
+ <description><![CDATA[#tag|strip|escape|addbreaks#]]></description>
+ <pubDate>#date|rfc822date#</pubDate>
+</item>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/tags-rss.tmpl Tue Feb 21 16:46:38 2006 +0100
@@ -0,0 +1,6 @@
+#header#
+ <title>#repo|escape#: tags </title>
+ <description>#repo|escape# tag history</description>
+ #entriesnotip%tagentry#
+ </channel>
+</rss>
--- a/templates/tags.tmpl Tue Feb 14 21:11:57 2006 +0100
+++ b/templates/tags.tmpl Tue Feb 21 16:46:38 2006 +0100
@@ -1,11 +1,14 @@
#header#
<title>#repo|escape#: tags</title>
+<link rel="alternate" type="application/rss+xml"
+ href="?cmd=tags;style=rss" title="RSS feed for #repo|escape#: tags">
</head>
<body>
<div class="buttons">
<a href="?cl=tip">changelog</a>
<a href="?mf=#manifest|short#;path=/">manifest</a>
+<a type="application/rss+xml" href="?cmd=tags;style=rss">rss</a>
</div>
<h2>tags:</h2>
--- a/tests/test-archive Tue Feb 14 21:11:57 2006 +0100
+++ b/tests/test-archive Tue Feb 21 16:46:38 2006 +0100
@@ -18,8 +18,8 @@
echo "allowzip = true" >> .hg/hgrc
echo "allowgz = true" >> .hg/hgrc
echo "allowbz2 = true" >> .hg/hgrc
-hg serve -p 20059 > /dev/null &
-sleep 1 # wait for server to be started
+serverpid=`mktemp`
+hg serve -p 20059 -d --pid-file=$serverpid
TIP=`hg id -v | cut -f1 -d' '`
QTIP=`hg id -q`
@@ -35,4 +35,5 @@
http_proxy= python getarchive.py "$TIP" zip > archive.zip
unzip -t archive.zip | sed "s/$QTIP/TIP/"
-kill $!
+kill `cat $serverpid`
+rm $serverpid
--- a/tests/test-archive.out Tue Feb 14 21:11:57 2006 +0100
+++ b/tests/test-archive.out Tue Feb 21 16:46:38 2006 +0100
@@ -12,4 +12,3 @@
testing: test-archive-TIP/baz/bletch OK
testing: test-archive-TIP/foo OK
No errors detected in compressed data of archive.zip.
-killed!
--- a/tests/test-diffdir Tue Feb 14 21:11:57 2006 +0100
+++ b/tests/test-diffdir Tue Feb 21 16:46:38 2006 +0100
@@ -12,3 +12,7 @@
hg diff -r tip | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
-e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
+
+echo foo > a
+hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+ -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
--- a/tests/test-diffdir.out Tue Feb 14 21:11:57 2006 +0100
+++ b/tests/test-diffdir.out Tue Feb 21 16:46:38 2006 +0100
@@ -8,3 +8,13 @@
+++ b/b
@@ -0,0 +1,1 @@
+123
+diff -r 3903775176ed a
+--- a/a
++++ b/a
+@@ -0,0 +1,1 @@
++foo
+diff -r 3903775176ed b
+--- /dev/null
++++ b/b
+@@ -0,0 +1,1 @@
++123
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-excessive-merge Tue Feb 21 16:46:38 2006 +0100
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+hg init
+
+echo foo > a
+echo foo > b
+hg add a b
+
+hg ci -m "test" -d "0 0"
+
+echo blah > a
+
+hg ci -m "branch a" -d "0 0"
+
+hg co 0
+
+echo blah > b
+
+hg ci -m "branch b" -d "0 0"
+HGMERGE=true hg up -m 1
+
+hg ci -m "merge b/a -> blah" -d "0 0"
+
+hg co 1
+HGMERGE=true hg up -m 2
+hg ci -m "merge a/b -> blah" -d "0 0"
+
+hg log
+hg debugindex .hg/00changelog.i
+
+echo
+
+echo 1
+hg manifest 1
+echo 2
+hg manifest 2
+echo 3
+hg manifest 3
+echo 4
+hg manifest 4
+
+echo
+
+hg debugindex .hg/data/a.i
+
+hg verify
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-excessive-merge.out Tue Feb 21 16:46:38 2006 +0100
@@ -0,0 +1,59 @@
+changeset: 4:2ee31f665a86
+tag: tip
+parent: 1:96155394af80
+parent: 2:92cc4c306b19
+user: test
+date: Thu Jan 1 00:00:00 1970 +0000
+summary: merge a/b -> blah
+
+changeset: 3:e16a66a37edd
+parent: 2:92cc4c306b19
+parent: 1:96155394af80
+user: test
+date: Thu Jan 1 00:00:00 1970 +0000
+summary: merge b/a -> blah
+
+changeset: 2:92cc4c306b19
+parent: 0:5e0375449e74
+user: test
+date: Thu Jan 1 00:00:00 1970 +0000
+summary: branch b
+
+changeset: 1:96155394af80
+user: test
+date: Thu Jan 1 00:00:00 1970 +0000
+summary: branch a
+
+changeset: 0:5e0375449e74
+user: test
+date: Thu Jan 1 00:00:00 1970 +0000
+summary: test
+
+ rev offset length base linkrev nodeid p1 p2
+ 0 0 60 0 0 5e0375449e74 000000000000 000000000000
+ 1 60 62 1 1 96155394af80 5e0375449e74 000000000000
+ 2 122 62 2 2 92cc4c306b19 5e0375449e74 000000000000
+ 3 184 69 3 3 e16a66a37edd 92cc4c306b19 96155394af80
+ 4 253 29 3 4 2ee31f665a86 96155394af80 92cc4c306b19
+
+1
+79d7492df40aa0fa093ec4209be78043c181f094 644 a
+2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 b
+2
+2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 a
+79d7492df40aa0fa093ec4209be78043c181f094 644 b
+3
+79d7492df40aa0fa093ec4209be78043c181f094 644 a
+79d7492df40aa0fa093ec4209be78043c181f094 644 b
+4
+79d7492df40aa0fa093ec4209be78043c181f094 644 a
+79d7492df40aa0fa093ec4209be78043c181f094 644 b
+
+ rev offset length base linkrev nodeid p1 p2
+ 0 0 5 0 0 2ed2a3912a0b 000000000000 000000000000
+ 1 5 6 1 1 79d7492df40a 2ed2a3912a0b 000000000000
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+2 files, 5 changesets, 4 total revisions
--- a/tests/test-help.out Tue Feb 14 21:11:57 2006 +0100
+++ b/tests/test-help.out Tue Feb 21 16:46:38 2006 +0100
@@ -171,10 +171,12 @@
options:
- -r --rev revision
- -a --text treat all files as text
- -I --include include names matching the given patterns
- -X --exclude exclude names matching the given patterns
+ -r --rev revision
+ -a --text treat all files as text
+ -I --include include names matching the given patterns
+ -p --show-function show which function each change is in
+ -w --ignore-all-space ignore white space when comparing lines
+ -X --exclude exclude names matching the given patterns
hg status [OPTION]... [FILE]...
show changed files in the working directory
--- a/tests/test-hook Tue Feb 14 21:11:57 2006 +0100
+++ b/tests/test-hook Tue Feb 21 16:46:38 2006 +0100
@@ -1,10 +1,90 @@
#!/bin/sh
-hg init
+# commit hooks can see env vars
+hg init a
+cd a
echo "[hooks]" > .hg/hgrc
-echo 'precommit = echo precommit hook' >> .hg/hgrc
-echo 'commit = echo commit hook: $NODE' >> .hg/hgrc
+echo 'commit = echo commit hook: n=$HG_NODE p1=$HG_PARENT1 p2=$HG_PARENT2' >> .hg/hgrc
echo 'commit.b = echo commit hook b' >> .hg/hgrc
+echo 'precommit = echo precommit hook: p1=$HG_PARENT1 p2=$HG_PARENT2' >> .hg/hgrc
+echo 'pretxncommit = echo pretxncommit hook: n=$HG_NODE p1=$HG_PARENT1 p2=$HG_PARENT2; hg -q tip' >> .hg/hgrc
echo a > a
hg add a
-hg commit -m "test" -d "0 0"
+hg commit -m a -d "0 0"
+
+hg clone . ../b
+cd ../b
+
+# changegroup hooks can see env vars
+echo '[hooks]' > .hg/hgrc
+echo 'prechangegroup = echo prechangegroup hook' >> .hg/hgrc
+echo 'changegroup = echo changegroup hook: n=$HG_NODE' >> .hg/hgrc
+echo 'incoming = echo incoming hook: n=$HG_NODE' >> .hg/hgrc
+
+# pretxncommit and commit hooks can see both parents of merge
+cd ../a
+echo b >> a
+hg commit -m a1 -d "1 0"
+hg update -C 0
+echo b > b
+hg add b
+hg commit -m b -d '1 0'
+hg update -m 1
+hg commit -m merge -d '2 0'
+
+cd ../b
+hg pull ../a
+
+# tag hooks can see env vars
+cd ../a
+echo 'pretag = echo pretag hook: t=$HG_TAG n=$HG_NODE l=$HG_LOCAL' >> .hg/hgrc
+echo 'tag = echo tag hook: t=$HG_TAG n=$HG_NODE l=$HG_LOCAL' >> .hg/hgrc
+hg tag -d '3 0' a
+hg tag -l la
+
+# pretag hook can forbid tagging
+echo 'pretag.forbid = echo pretag.forbid hook; exit 1' >> .hg/hgrc
+hg tag -d '4 0' fa
+hg tag -l fla
+
+# pretxncommit hook can see changeset, can roll back txn, changeset
+# no more there after
+echo 'pretxncommit.forbid = echo pretxncommit.forbid hook: tip=`hg -q tip`; exit 1' >> .hg/hgrc
+echo z > z
+hg add z
+hg -q tip
+hg commit -m 'fail' -d '4 0'
+hg -q tip
+
+# precommit hook can prevent commit
+echo 'precommit.forbid = echo precommit.forbid hook; exit 1' >> .hg/hgrc
+hg commit -m 'fail' -d '4 0'
+hg -q tip
+
+# prechangegroup hook can prevent incoming changes
+cd ../b
+hg -q tip
+echo '[hooks]' > .hg/hgrc
+echo 'prechangegroup.forbid = echo prechangegroup.forbid hook; exit 1' >> .hg/hgrc
+hg pull ../a
+
+# pretxnchangegroup hook can see incoming changes, can roll back txn,
+# incoming changes no longer there after
+echo '[hooks]' > .hg/hgrc
+echo 'pretxnchangegroup.forbid = echo pretxnchangegroup.forbid hook: tip=`hg -q tip`; exit 1' >> .hg/hgrc
+hg pull ../a
+hg -q tip
+
+# outgoing hooks can see env vars
+rm .hg/hgrc
+echo '[hooks]' > ../a/.hg/hgrc
+echo 'preoutgoing = echo preoutgoing hook: s=$HG_SOURCE' >> ../a/.hg/hgrc
+echo 'outgoing = echo outgoing hook: n=$HG_NODE s=$HG_SOURCE' >> ../a/.hg/hgrc
+hg pull ../a
+hg undo
+
+# preoutgoing hook can prevent outgoing changes
+echo 'preoutgoing.forbid = echo preoutgoing.forbid hook; exit 1' >> ../a/.hg/hgrc
+hg pull ../a
+
+exit 0
--- a/tests/test-hook.out Tue Feb 14 21:11:57 2006 +0100
+++ b/tests/test-hook.out Tue Feb 21 16:46:38 2006 +0100
@@ -1,3 +1,88 @@
-precommit hook
+precommit hook: p1=0000000000000000000000000000000000000000 p2=
+pretxncommit hook: n=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b p1=0000000000000000000000000000000000000000 p2=
+0:cb9a9f314b8b
+commit hook b
+commit hook: n=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b p1=0000000000000000000000000000000000000000 p2=
+precommit hook: p1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b p2=
+pretxncommit hook: n=ab228980c14deea8b9555d91c9581127383e40fd p1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b p2=
+1:ab228980c14d
+commit hook b
+commit hook: n=ab228980c14deea8b9555d91c9581127383e40fd p1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b p2=
+precommit hook: p1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b p2=
+pretxncommit hook: n=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 p1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b p2=
+2:ee9deb46ab31
+commit hook b
+commit hook: n=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 p1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b p2=
+precommit hook: p1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 p2=ab228980c14deea8b9555d91c9581127383e40fd
+pretxncommit hook: n=07f3376c1e655977439df2a814e3cc14b27abac2 p1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 p2=ab228980c14deea8b9555d91c9581127383e40fd
+3:07f3376c1e65
+commit hook b
+commit hook: n=07f3376c1e655977439df2a814e3cc14b27abac2 p1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 p2=ab228980c14deea8b9555d91c9581127383e40fd
+prechangegroup hook
+changegroup hook: n=ab228980c14deea8b9555d91c9581127383e40fd
+incoming hook: n=ab228980c14deea8b9555d91c9581127383e40fd
+incoming hook: n=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
+incoming hook: n=07f3376c1e655977439df2a814e3cc14b27abac2
+pulling from ../a
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 3 changesets with 2 changes to 2 files
+(run 'hg update' to get a working copy)
+pretag hook: t=a n=07f3376c1e655977439df2a814e3cc14b27abac2 l=0
+precommit hook: p1=07f3376c1e655977439df2a814e3cc14b27abac2 p2=
+pretxncommit hook: n=3cd2c6a5a36c5908aad3bc0d717c29873a05dfc2 p1=07f3376c1e655977439df2a814e3cc14b27abac2 p2=
+4:3cd2c6a5a36c
commit hook b
-commit hook: acb14030fe0a21b60322c440ad2d20cf7685a376
+commit hook: n=3cd2c6a5a36c5908aad3bc0d717c29873a05dfc2 p1=07f3376c1e655977439df2a814e3cc14b27abac2 p2=
+tag hook: t=a n=07f3376c1e655977439df2a814e3cc14b27abac2 l=0
+pretag hook: t=la n=3cd2c6a5a36c5908aad3bc0d717c29873a05dfc2 l=1
+tag hook: t=la n=3cd2c6a5a36c5908aad3bc0d717c29873a05dfc2 l=1
+pretag hook: t=fa n=3cd2c6a5a36c5908aad3bc0d717c29873a05dfc2 l=0
+pretag.forbid hook
+abort: pretag.forbid hook exited with status 1
+pretag hook: t=fla n=3cd2c6a5a36c5908aad3bc0d717c29873a05dfc2 l=1
+pretag.forbid hook
+abort: pretag.forbid hook exited with status 1
+4:3cd2c6a5a36c
+precommit hook: p1=3cd2c6a5a36c5908aad3bc0d717c29873a05dfc2 p2=
+pretxncommit.forbid hook: tip=5:469a61fe67d6
+abort: pretxncommit.forbid hook exited with status 1
+transaction abort!
+rollback completed
+4:3cd2c6a5a36c
+precommit.forbid hook
+abort: precommit.forbid hook exited with status 1
+4:3cd2c6a5a36c
+3:07f3376c1e65
+prechangegroup.forbid hook
+pulling from ../a
+searching for changes
+abort: prechangegroup.forbid hook exited with status 1
+pretxnchangegroup.forbid hook: tip=4:3cd2c6a5a36c
+pulling from ../a
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 1 changes to 1 files
+abort: pretxnchangegroup.forbid hook exited with status 1
+transaction abort!
+rollback completed
+3:07f3376c1e65
+preoutgoing hook: s=pull
+outgoing hook: n=3cd2c6a5a36c5908aad3bc0d717c29873a05dfc2 s=pull
+pulling from ../a
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 1 changes to 1 files
+(run 'hg update' to get a working copy)
+rolling back last transaction
+preoutgoing hook: s=pull
+preoutgoing.forbid hook
+pulling from ../a
+searching for changes
+abort: preoutgoing.forbid hook exited with status 1
--- a/tests/test-merge3.out Tue Feb 14 21:11:57 2006 +0100
+++ b/tests/test-merge3.out Tue Feb 21 16:46:38 2006 +0100
@@ -1,3 +1,2 @@
removing b
-b never committed!
nothing changed
--- a/tests/test-pull Tue Feb 14 21:11:57 2006 +0100
+++ b/tests/test-pull Tue Feb 21 16:46:38 2006 +0100
@@ -7,8 +7,8 @@
hg addremove
hg commit -m 1
hg verify
-hg serve -p 20059 > /dev/null &
-sleep 1 # wait for server to be started
+serverpid=`mktemp`
+hg serve -p 20059 -d --pid-file=$serverpid
cd ..
hg clone http://localhost:20059/ copy
@@ -19,4 +19,5 @@
hg manifest
hg pull
-kill $!
+kill `cat $serverpid`
+rm $serverpid
--- a/tests/test-pull-permission Tue Feb 14 21:11:57 2006 +0100
+++ b/tests/test-pull-permission Tue Feb 21 16:46:38 2006 +0100
@@ -12,9 +12,8 @@
cd ..
hg clone a b
+
+chmod +w a/.hg # let test clean up
+
cd b
hg verify
-
-cd ..
-
-chmod +w a/.hg # let test clean up
--- a/tests/test-pull.out Tue Feb 14 21:11:57 2006 +0100
+++ b/tests/test-pull.out Tue Feb 21 16:46:38 2006 +0100
@@ -19,4 +19,3 @@
pulling from http://localhost:20059/
searching for changes
no changes found
-killed!
--- a/tests/test-rename Tue Feb 14 21:11:57 2006 +0100
+++ b/tests/test-rename Tue Feb 21 16:46:38 2006 +0100
@@ -158,3 +158,16 @@
hg rename d1 d3
hg status
hg update -C
+
+echo "# transitive rename"
+hg rename d1/b d1/bb
+hg rename d1/bb d1/bc
+hg status
+hg update -C
+
+echo "# transitive rename --after"
+hg rename d1/b d1/bb
+mv d1/bb d1/bc
+hg rename --after d1/bb d1/bc
+hg status
+hg update -C
--- a/tests/test-rename.out Tue Feb 14 21:11:57 2006 +0100
+++ b/tests/test-rename.out Tue Feb 21 16:46:38 2006 +0100
@@ -246,3 +246,9 @@
R d1/b
R d1/ba
R d1/d11/a1
+# transitive rename
+A d1/bc
+R d1/b
+# transitive rename --after
+A d1/bc
+R d1/b
--- a/tests/test-ro-message Tue Feb 14 21:11:57 2006 +0100
+++ b/tests/test-ro-message Tue Feb 21 16:46:38 2006 +0100
@@ -14,4 +14,4 @@
"$HG" commit -m 'Clarifying the vehicle.'
"$HG" update -C 1
chmod a-w b/vehicle
-"$HG" update -m 2 2>&1 | sed 's|^\(.*[ ]\)/tmp/[^/]*/\(.*\)$|\1\2|g'
+"$HG" update -m 2 2>&1 | sed 's|^\(.*[ ]\).*/\([^/]*/[^/]*/[^/]*\)$|\1\2|g'