--- a/contrib/mercurial.spec Mon Jun 21 17:02:48 2010 -0300
+++ b/contrib/mercurial.spec Fri Jul 02 11:30:57 2010 +0200
@@ -41,7 +41,6 @@
make install DESTDIR=$RPM_BUILD_ROOT PREFIX=%{_prefix} MANDIR=%{_mandir}
install contrib/hgk $RPM_BUILD_ROOT%{_bindir}
-install contrib/convert-repo $RPM_BUILD_ROOT%{_bindir}/mercurial-convert-repo
install contrib/hg-ssh $RPM_BUILD_ROOT%{_bindir}
bash_completion_dir=$RPM_BUILD_ROOT%{_sysconfdir}/bash_completion.d
@@ -74,7 +73,6 @@
%{_bindir}/hg
%{_bindir}/hgk
%{_bindir}/hg-ssh
-%{_bindir}/mercurial-convert-repo
%dir %{_sysconfdir}/bash_completion.d/
%dir %{_datadir}/zsh/site-functions/
%dir %{_sysconfdir}/mercurial
--- a/contrib/tcsh_completion Mon Jun 21 17:02:48 2010 -0300
+++ b/contrib/tcsh_completion Fri Jul 02 11:30:57 2010 +0200
@@ -2,7 +2,7 @@
# tcsh completion for Mercurial
#
# This file has been auto-generated by tcsh_completion_build.sh for
-# Mercurial Distributed SCM (version 1.3.1+269-5d8125bbbbf4)
+# Mercurial Distributed SCM (version 1.5.4+154-8b452fe4bf50)
#
# Copyright (C) 2005 TK Soh.
#
@@ -32,18 +32,19 @@
'p/1/(add addremove annotate blame archive \
backout bisect branch branches bundle \
cat clone commit ci copy \
- cp debugancestor debugcheckstate debugcommands debugcomplete \
- debugdata debugdate debugfsinfo debugindex debugindexdot \
- debuginstall debugrebuildstate debugrename debugsetparents debugstate \
- debugsub debugwalk diff export forget \
- grep heads help identify id \
- import patch incoming in init \
- locate log history manifest merge \
- outgoing out parents paths pull \
- push recover remove rm rename \
- mv resolve revert rollback root \
- serve showconfig debugconfig status st \
- summary sum tag tags tip \
- unbundle update up checkout co \
- verify version)/'
+ cp debugancestor debugbuilddag debugcheckstate debugcommands \
+ debugcomplete debugdag debugdata debugdate debugfsinfo \
+ debugindex debugindexdot debuginstall debugpushkey debugrebuildstate \
+ debugrename debugrevspec debugsetparents debugstate debugsub \
+ debugwalk diff export forget grep \
+ heads help identify id import \
+ patch incoming in init locate \
+ log history manifest merge outgoing \
+ out parents paths pull push \
+ recover remove rm rename mv \
+ resolve revert rollback root serve \
+ showconfig debugconfig status st summary \
+ sum tag tags tip unbundle \
+ update up checkout co verify \
+ version)/'
--- a/hgext/bookmarks.py Mon Jun 21 17:02:48 2010 -0300
+++ b/hgext/bookmarks.py Fri Jul 02 11:30:57 2010 +0200
@@ -30,7 +30,7 @@
from mercurial.i18n import _
from mercurial.node import nullid, nullrev, hex, short
-from mercurial import util, commands, repair, extensions, pushkey, hg
+from mercurial import util, commands, repair, extensions, pushkey, hg, url
import os
def write(repo):
@@ -53,6 +53,13 @@
for refspec, node in refs.iteritems():
file.write("%s %s\n" % (hex(node), refspec))
file.rename()
+
+ # touch 00changelog.i so hgweb reloads bookmarks (no lock needed)
+ try:
+ os.utime(repo.sjoin('00changelog.i'), None)
+ except OSError:
+ pass
+
finally:
wlock.release()
@@ -327,16 +334,15 @@
if r:
self.ui.status(_("updating bookmark %s\n") % k)
else:
- self.ui.warn(_("failed to update bookmark"
- " %s!\n") % k)
+ self.ui.warn(_('updating bookmark %s'
+ ' failed!\n') % k)
return result
- def addchangegroup(self, source, srctype, url, emptyok=False):
+ def addchangegroup(self, *args, **kwargs):
parents = self.dirstate.parents()
- result = super(bookmark_repo, self).addchangegroup(
- source, srctype, url, emptyok)
+ result = super(bookmark_repo, self).addchangegroup(*args, **kwargs)
if result > 1:
# We have more heads than before
return result
@@ -445,6 +451,40 @@
return result
+def diffbookmarks(ui, repo, remote):
+ ui.status(_("searching for changes\n"))
+
+ lmarks = repo.listkeys('bookmarks')
+ rmarks = remote.listkeys('bookmarks')
+
+ diff = set(rmarks) - set(lmarks)
+ for k in diff:
+ ui.write(" %-25s %s\n" % (k, rmarks[k][:12]))
+
+ if len(diff) <= 0:
+ ui.status(_("no changes found\n"))
+ return 1
+ return 0
+
+def incoming(oldincoming, ui, repo, source="default", **opts):
+ if opts.get('bookmarks'):
+ source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
+ other = hg.repository(hg.remoteui(repo, opts), source)
+ ui.status(_('comparing with %s\n') % url.hidepassword(source))
+ return diffbookmarks(ui, repo, other)
+ else:
+ return oldincoming(ui, repo, source, **opts)
+
+def outgoing(oldoutgoing, ui, repo, dest=None, **opts):
+ if opts.get('bookmarks'):
+ dest = ui.expandpath(dest or 'default-push', dest or 'default')
+ dest, branches = hg.parseurl(dest, opts.get('branch'))
+ other = hg.repository(hg.remoteui(repo, opts), dest)
+ ui.status(_('comparing with %s\n') % url.hidepassword(dest))
+ return diffbookmarks(ui, other, repo)
+ else:
+ return oldoutgoing(ui, repo, dest, **opts)
+
def uisetup(ui):
extensions.wrapfunction(repair, "strip", strip)
if ui.configbool('bookmarks', 'track.current'):
@@ -456,6 +496,12 @@
entry = extensions.wrapcommand(commands.table, 'push', push)
entry[1].append(('B', 'bookmark', [],
_("bookmark to export")))
+ entry = extensions.wrapcommand(commands.table, 'incoming', incoming)
+ entry[1].append(('B', 'bookmarks', False,
+ _("compare bookmark")))
+ entry = extensions.wrapcommand(commands.table, 'outgoing', outgoing)
+ entry[1].append(('B', 'bookmarks', False,
+ _("compare bookmark")))
pushkey.register('bookmarks', pushbookmark, listbookmarks)
--- a/hgext/graphlog.py Mon Jun 21 17:02:48 2010 -0300
+++ b/hgext/graphlog.py Fri Jul 02 11:30:57 2010 +0200
@@ -209,6 +209,8 @@
def get_revs(repo, rev_opt):
if rev_opt:
revs = revrange(repo, rev_opt)
+ if len(revs) == 0:
+ return (nullrev, nullrev)
return (max(revs), min(revs))
else:
return (len(repo) - 1, 0)
--- a/hgext/mq.py Mon Jun 21 17:02:48 2010 -0300
+++ b/hgext/mq.py Fri Jul 02 11:30:57 2010 +0200
@@ -250,6 +250,7 @@
self.ui = ui
self.applied_dirty = 0
self.series_dirty = 0
+ self.added = []
self.series_path = "series"
self.status_path = "status"
self.guards_path = "guards"
@@ -1017,7 +1018,7 @@
_("cannot push to a previous patch: %s") % patch)
self.ui.warn(
_('qpush: %s is already at the top\n') % patch)
- return
+ return 0
pushable, reason = self.pushable(patch)
if not pushable:
if reason:
@@ -1046,10 +1047,12 @@
if move:
try:
- del self.full_series[self.full_series.index(patch, start)]
+ index = self.series.index(patch, start)
+ fullpatch = self.full_series[index]
+ del self.full_series[index]
except ValueError:
raise util.Abort(_("patch '%s' not found") % patch)
- self.full_series.insert(start, patch)
+ self.full_series.insert(start, fullpatch)
self.parse_series()
self.series_dirty = 1
@@ -1620,7 +1623,7 @@
if (len(files) > 1 or len(rev) > 1) and patchname:
raise util.Abort(_('option "-n" not valid when importing multiple '
'patches'))
- added = []
+ self.added = []
if rev:
# If mq patches are applied, we can only import revisions
# that form a linear path to qbase.
@@ -1670,10 +1673,11 @@
se = statusentry(n, patchname)
self.applied.insert(0, se)
- added.append(patchname)
+ self.added.append(patchname)
patchname = None
self.parse_series()
self.applied_dirty = 1
+ self.series_dirty = True
for i, filename in enumerate(files):
if existing:
@@ -1707,13 +1711,10 @@
index = self.full_series_end() + i
self.full_series[index:index] = [patchname]
self.parse_series()
+ self.series_dirty = True
self.ui.warn(_("adding %s to series file\n") % patchname)
- added.append(patchname)
+ self.added.append(patchname)
patchname = None
- self.series_dirty = 1
- qrepo = self.qrepo()
- if qrepo:
- qrepo[None].add(added)
def delete(ui, repo, *patches, **opts):
"""remove patches from queue
@@ -1803,10 +1804,15 @@
using the --name flag.
"""
q = repo.mq
- q.qimport(repo, filename, patchname=opts['name'],
+ try:
+ q.qimport(repo, filename, patchname=opts['name'],
existing=opts['existing'], force=opts['force'], rev=opts['rev'],
git=opts['git'])
- q.save_dirty()
+ finally:
+ q.save_dirty()
+ qrepo = q.qrepo()
+ if qrepo:
+ qrepo[None].add(q.added)
if opts.get('push') and not opts.get('rev'):
return q.push(repo, None)
--- a/hgext/progress.py Mon Jun 21 17:02:48 2010 -0300
+++ b/hgext/progress.py Fri Jul 02 11:30:57 2010 +0200
@@ -51,6 +51,9 @@
def spacejoin(*args):
return ' '.join(s for s in args if s)
+def shouldprint(ui):
+ return sys.stderr.isatty() or ui.configbool('progress', 'assume-tty')
+
class progbar(object):
def __init__(self, ui):
self.ui = ui
@@ -69,6 +72,8 @@
default=['topic', 'bar', 'number'])
def show(self, topic, pos, item, unit, total):
+ if not shouldprint(self.ui):
+ return
termwidth = self.width()
self.printed = True
head = ''
@@ -137,9 +142,13 @@
sys.stderr.flush()
def clear(self):
+ if not shouldprint(self.ui):
+ return
sys.stderr.write('\r%s\r' % (' ' * self.width()))
def complete(self):
+ if not shouldprint(self.ui):
+ return
if self.ui.configbool('progress', 'clear-complete', default=True):
self.clear()
else:
@@ -177,8 +186,7 @@
# setconfig('progress', 'disable', 'True') to disable this extension
if ui.configbool('progress', 'disable'):
return
- if ((sys.stderr.isatty() or ui.configbool('progress', 'assume-tty'))
- and not ui.debugflag and not ui.quiet):
+ if shouldprint(ui) and not ui.debugflag and not ui.quiet:
# we instantiate one globally shared progress bar to avoid
# competing progress bars when multiple UI objects get created
global sharedprog
--- a/hgext/zeroconf/Zeroconf.py Mon Jun 21 17:02:48 2010 -0300
+++ b/hgext/zeroconf/Zeroconf.py Fri Jul 02 11:30:57 2010 +0200
@@ -204,6 +204,13 @@
class BadTypeInNameException(Exception):
pass
+class BadDomainName(Exception):
+ def __init__(self, pos):
+ Exception.__init__(self, "at position %s" % pos)
+
+class BadDomainNameCircular(BadDomainName):
+ pass
+
# implementation classes
class DNSEntry(object):
@@ -598,10 +605,10 @@
next = off + 1
off = ((len & 0x3F) << 8) | ord(self.data[off])
if off >= first:
- raise "Bad domain name (circular) at " + str(off)
+ raise BadDomainNameCircular(off)
first = off
else:
- raise "Bad domain name at " + str(off)
+ raise BadDomainName(off)
if next >= 0:
self.offset = next
--- a/i18n/polib.py Mon Jun 21 17:02:48 2010 -0300
+++ b/i18n/polib.py Fri Jul 02 11:30:57 2010 +0200
@@ -1,5 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
+# no-check-code
#
# License: MIT (see LICENSE file provided)
# vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
--- a/mercurial/cmdutil.py Mon Jun 21 17:02:48 2010 -0300
+++ b/mercurial/cmdutil.py Fri Jul 02 11:30:57 2010 +0200
@@ -905,7 +905,9 @@
if self.buffered:
self.header[ctx.rev()] = h
else:
- self.ui.write(h)
+ if self.lastheader != h:
+ self.lastheader = h
+ self.ui.write(h)
# write changeset metadata, then patch if requested
key = types['changeset']
--- a/mercurial/commands.py Mon Jun 21 17:02:48 2010 -0300
+++ b/mercurial/commands.py Fri Jul 02 11:30:57 2010 +0200
@@ -2570,6 +2570,10 @@
head, the other head is merged with by default. Otherwise, an
explicit revision with which to merge with must be provided.
+ To undo an uncommitted merge, use :hg:`update --clean .` which
+ will check out a clean copy of the original merge parent, losing
+ all changes.
+
Returns 0 on success, 1 if there are unresolved files.
"""
@@ -3015,8 +3019,11 @@
def revert(ui, repo, *pats, **opts):
"""restore individual files or directories to an earlier state
- (Use update -r to check out earlier revisions, revert does not
- change the working directory parents.)
+ NOTE: This command is most likely not what you are looking for. revert
+ will partially overwrite content in the working directory without changing
+ the working directory parents. Use :hg:`update -r rev` to check out earlier
+ revisions, or :hg:`update --clean .` to undo a merge which has added
+ another parent.
With no revision specified, revert the named files or directories
to the contents they had in the parent of the working directory.
@@ -3745,7 +3752,8 @@
for fname in fnames:
f = url.open(ui, fname)
gen = changegroup.readbundle(f, fname)
- modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
+ modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
+ lock=lock)
finally:
lock.release()
--- a/mercurial/context.py Mon Jun 21 17:02:48 2010 -0300
+++ b/mercurial/context.py Fri Jul 02 11:30:57 2010 +0200
@@ -490,12 +490,16 @@
return zip(hist[f][0], hist[f][1].splitlines(True))
- def ancestor(self, fc2):
+ def ancestor(self, fc2, actx=None):
"""
find the common ancestor file context, if any, of self, and fc2
+
+ If actx is given, it must be the changectx of the common ancestor
+ of self's and fc2's respective changesets.
"""
- actx = self.changectx().ancestor(fc2.changectx())
+ if actx is None:
+ actx = self.changectx().ancestor(fc2.changectx())
# the trivial case: changesets are unrelated, files must be too
if not actx:
--- a/mercurial/discovery.py Mon Jun 21 17:02:48 2010 -0300
+++ b/mercurial/discovery.py Fri Jul 02 11:30:57 2010 +0200
@@ -280,7 +280,7 @@
remotemap = remote.branchmap()
newbranches = branches - set(remotemap)
if newbranches and not newbranch: # new branch requires --new-branch
- branchnames = ', '.join("%s" % b for b in newbranches)
+ branchnames = ', '.join(sorted(newbranches))
repo.ui.warn(_("abort: push creates "
"new remote branches: %s!\n")
% branchnames)
--- a/mercurial/help/glossary.txt Mon Jun 21 17:02:48 2010 -0300
+++ b/mercurial/help/glossary.txt Fri Jul 02 11:30:57 2010 +0200
@@ -8,7 +8,7 @@
Branch
(Noun) A child changeset that has been created from a parent that
is not a head. These are known as topological branches, see
- 'Branch, topological'.If a topological branch is named, it becomes
+ 'Branch, topological'. If a topological branch is named, it becomes
a named branch. If a topological branch is not named, it becomes
an anonymous branch. See 'Branch, anonymous' and 'Branch, named'.
@@ -55,8 +55,8 @@
collection of disjoint subsets. A named branch is not necessarily
a topological branch. If a new named branch is created from the
head of another named branch, or the default branch, but no
- further changesets are added to that previous branch, then the new
- named branch will be a branch in name only.
+ further changesets are added to that previous branch, then that
+ previous branch will be a branch in name only.
Branch tip
See 'Tip, branch'.
@@ -151,7 +151,7 @@
consisting of nodes and edges, where nodes correspond to
changesets and edges imply a parent -> child relation. This graph
can be visualized by graphical tools such as :hg:`glog`
- (graphlog). In mercurial, the DAG is limited by the requirement
+ (graphlog). In Mercurial, the DAG is limited by the requirement
for children to have at most two parents.
Default branch
@@ -322,7 +322,7 @@
pointing to the data.
Rewriting history
- See 'History, rewriting'.
+ See 'History, rewriting'.
Root
A changeset that has only the null changeset as its parent. Most
@@ -342,7 +342,7 @@
Update
(Noun) Another synonym of changeset.
- Example: "I've pushed an update".
+ Example: "I've pushed an update".
(Verb) This term is usually used to describe updating the state of
the working directory to that of a specific changeset. See
@@ -354,4 +354,4 @@
See 'Directory, working'.
Working directory parent
- See 'Parent, working directory'.
+ See 'Parent, working directory'.
--- a/mercurial/help/revsets.txt Mon Jun 21 17:02:48 2010 -0300
+++ b/mercurial/help/revsets.txt Fri Jul 02 11:30:57 2010 +0200
@@ -21,7 +21,7 @@
A DAG range, meaning all changesets that are descendants of x and
ancestors of y, including x and y themselves. If the first endpoint
is left out, this is equivalent to ``ancestors(y)``, if the second
- is left out it is equivalent to ``descendents(x)``.
+ is left out it is equivalent to ``descendants(x)``.
An alternative syntax is ``x..y``.
--- a/mercurial/hgweb/protocol.py Mon Jun 21 17:02:48 2010 -0300
+++ b/mercurial/hgweb/protocol.py Fri Jul 02 11:30:57 2010 +0200
@@ -164,7 +164,7 @@
urllib.quote(req.env.get('REMOTE_HOST', '')),
urllib.quote(req.env.get('REMOTE_USER', '')))
try:
- ret = repo.addchangegroup(gen, 'serve', url)
+ ret = repo.addchangegroup(gen, 'serve', url, lock=lock)
except util.Abort, inst:
sys.stdout.write("abort: %s\n" % inst)
ret = 0
--- a/mercurial/hook.py Mon Jun 21 17:02:48 2010 -0300
+++ b/mercurial/hook.py Fri Jul 02 11:30:57 2010 +0200
@@ -98,7 +98,10 @@
cwd = repo.root
else:
cwd = os.getcwd()
- r = util.system(cmd, environ=env, cwd=cwd)
+ if 'HG_URL' in env and env['HG_URL'].startswith('remote:http'):
+ r = util.system(cmd, environ=env, cwd=cwd, out=ui)
+ else:
+ r = util.system(cmd, environ=env, cwd=cwd)
if r:
desc, r = util.explain_exit(r)
if throw:
--- a/mercurial/localrepo.py Mon Jun 21 17:02:48 2010 -0300
+++ b/mercurial/localrepo.py Fri Jul 02 11:30:57 2010 +0200
@@ -1199,7 +1199,7 @@
"other repository doesn't support "
"changegroupsubset."))
cg = remote.changegroupsubset(fetch, heads, 'pull')
- return self.addchangegroup(cg, 'pull', remote.url())
+ return self.addchangegroup(cg, 'pull', remote.url(), lock=lock)
finally:
lock.release()
@@ -1233,8 +1233,8 @@
ret = discovery.prepush(self, remote, force, revs, newbranch)
if ret[0] is not None:
cg, remote_heads = ret
- # here, we return an integer indicating remote head count change
- return remote.addchangegroup(cg, 'push', self.url())
+ # we return an integer indicating remote head count change
+ return remote.addchangegroup(cg, 'push', self.url(), lock=lock)
# and here we return 0 for "nothing to push" or 1 for
# "something to push but I refuse"
return ret[1]
@@ -1620,7 +1620,7 @@
return util.chunkbuffer(gengroup())
- def addchangegroup(self, source, srctype, url, emptyok=False):
+ def addchangegroup(self, source, srctype, url, emptyok=False, lock=None):
"""Add the changegroup returned by source.read() to this repo.
srctype is a string like 'push', 'pull', or 'unbundle'. url is
the URL of the repo where this changegroup is coming from.
@@ -1760,6 +1760,8 @@
tr.close()
finally:
tr.release()
+ if lock:
+ lock.release()
if changesets > 0:
# forcefully update the on-disk branch cache
--- a/mercurial/merge.py Mon Jun 21 17:02:48 2010 -0300
+++ b/mercurial/merge.py Fri Jul 02 11:30:57 2010 +0200
@@ -23,15 +23,13 @@
def _read(self):
self._state = {}
try:
- localnode = None
f = self._repo.opener("merge/state")
for i, l in enumerate(f):
if i == 0:
- localnode = l[:-1]
+ self._local = bin(l[:-1])
else:
bits = l[:-1].split("\0")
self._state[bits[0]] = bits[1:]
- self._local = bin(localnode)
except IOError, err:
if err.errno != errno.ENOENT:
raise
@@ -184,7 +182,9 @@
rflags = fmerge(f, f, f)
a = ma.get(f, nullid)
if n == m2[f] or m2[f] == a: # same or local newer
- if m1.flags(f) != rflags:
+ # is file locally modified or flags need changing?
+ # dirstate flags may need to be made current
+ if m1.flags(f) != rflags or n[20:]:
act("update permissions", "e", f, rflags)
elif n == a: # remote newer
act("remote is newer", "g", f, rflags)
@@ -244,8 +244,13 @@
def actionkey(a):
return a[1] == 'r' and -1 or 0, a
-def applyupdates(repo, action, wctx, mctx):
- "apply the merge action list to the working directory"
+def applyupdates(repo, action, wctx, mctx, actx):
+ """apply the merge action list to the working directory
+
+ wctx is the working copy context
+ mctx is the context to be merged into the working copy
+ actx is the context of the common ancestor
+ """
updated, merged, removed, unresolved = 0, 0, 0, 0
ms = mergestate(repo)
@@ -265,7 +270,7 @@
repo.ui.debug("preserving %s for resolve of %s\n" % (f, fd))
fcl = wctx[f]
fco = mctx[f2]
- fca = fcl.ancestor(fco) or repo.filectx(f, fileid=nullrev)
+ fca = fcl.ancestor(fco, actx) or repo.filectx(f, fileid=nullrev)
ms.add(fcl, fco, fca, fd, flags)
if f != fd and move:
moves.append(f)
@@ -507,7 +512,7 @@
if not partial:
repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
- stats = applyupdates(repo, action, wc, p2)
+ stats = applyupdates(repo, action, wc, p2, pa)
if not partial:
repo.dirstate.setparents(fp1, fp2)
--- a/mercurial/minirst.py Mon Jun 21 17:02:48 2010 -0300
+++ b/mercurial/minirst.py Fri Jul 02 11:30:57 2010 +0200
@@ -36,7 +36,13 @@
"""
import re, sys
-import util
+import util, encoding
+
+def replace(text, substs):
+ utext = text.decode(encoding.encoding)
+ for f, t in substs:
+ utext = utext.replace(f, t)
+ return utext.encode(encoding.encoding)
def findblocks(text):
"""Find continuous blocks of lines in text.
@@ -251,21 +257,22 @@
def inlineliterals(blocks):
+ substs = [('``', '"')]
for b in blocks:
if b['type'] in ('paragraph', 'section'):
- b['lines'] = [l.replace('``', '"') for l in b['lines']]
+ b['lines'] = [replace(l, substs) for l in b['lines']]
return blocks
def hgrole(blocks):
+ substs = [(':hg:`', '"hg '), ('`', '"')]
for b in blocks:
if b['type'] in ('paragraph', 'section'):
# Turn :hg:`command` into "hg command". This also works
# when there is a line break in the command and relies on
# the fact that we have no stray back-quotes in the input
# (run the blocks through inlineliterals first).
- b['lines'] = [l.replace(':hg:`', '"hg ').replace('`', '"')
- for l in b['lines']]
+ b['lines'] = [replace(l, substs) for l in b['lines']]
return blocks
--- a/mercurial/parser.py Mon Jun 21 17:02:48 2010 -0300
+++ b/mercurial/parser.py Fri Jul 02 11:30:57 2010 +0200
@@ -5,7 +5,7 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-# see http://effbot.org/zone/simple-top-down-parsing.txt and
+# see http://effbot.org/zone/simple-top-down-parsing.htm and
# http://eli.thegreenplace.net/2010/01/02/top-down-operator-precedence-parsing/
# for background
--- a/mercurial/revset.py Mon Jun 21 17:02:48 2010 -0300
+++ b/mercurial/revset.py Fri Jul 02 11:30:57 2010 +0200
@@ -111,10 +111,6 @@
# operator methods
-def negate(repo, subset, x):
- return getset(repo, subset,
- ('string', '-' + getstring(x, _("can't negate that"))))
-
def stringset(repo, subset, x):
x = repo[x].rev()
if x == -1 and len(subset) == len(repo):
@@ -129,11 +125,24 @@
return stringset(repo, subset, x)
def rangeset(repo, subset, x, y):
- m = getset(repo, subset, x)[0]
- n = getset(repo, subset, y)[-1]
+ m = getset(repo, subset, x)
+ if not m:
+ m = getset(repo, range(len(repo)), x)
+
+ n = getset(repo, subset, y)
+ if not n:
+ n = getset(repo, range(len(repo)), y)
+
+ if not m or not n:
+ return []
+ m, n = m[0], n[-1]
+
if m < n:
- return range(m, n + 1)
- return range(m, n - 1, -1)
+ r = range(m, n + 1)
+ else:
+ r = range(m, n - 1, -1)
+ s = set(subset)
+ return [x for x in r if x in s]
def andset(repo, subset, x, y):
return getset(repo, getset(repo, subset, x), y)
@@ -222,11 +231,15 @@
def ancestors(repo, subset, x):
args = getset(repo, range(len(repo)), x)
+ if not args:
+ return []
s = set(repo.changelog.ancestors(*args)) | set(args)
return [r for r in subset if r in s]
def descendants(repo, subset, x):
args = getset(repo, range(len(repo)), x)
+ if not args:
+ return []
s = set(repo.changelog.descendants(*args)) | set(args)
return [r for r in subset if r in s]
@@ -422,7 +435,6 @@
repo.ui.popbuffer()
cl = repo.changelog
o = set([cl.rev(r) for r in repo.changelog.nodesbetween(o, None)[0]])
- print 'out', dest, o
return [r for r in subset if r in o]
def tagged(repo, subset, x):
@@ -466,7 +478,6 @@
}
methods = {
- "negate": negate,
"range": rangeset,
"string": stringset,
"symbol": symbolset,
@@ -499,6 +510,9 @@
return optimize(('range', ('string', '0'), x[1]), small)
elif op == 'rangepost':
return optimize(('range', x[1], ('string', 'tip')), small)
+ elif op == 'negate':
+ return optimize(('string',
+ '-' + getstring(x[1], _("can't negate that"))), small)
elif op in 'string symbol negate':
return smallbonus, x # single revisions are small
elif op == 'and' or op == 'dagrange':
--- a/mercurial/sshserver.py Mon Jun 21 17:02:48 2010 -0300
+++ b/mercurial/sshserver.py Fri Jul 02 11:30:57 2010 +0200
@@ -161,7 +161,8 @@
return
self.respond("")
- r = self.repo.addchangegroup(self.fin, 'serve', self.client_url())
+ r = self.repo.addchangegroup(self.fin, 'serve', self.client_url(),
+ lock=self.lock)
self.respond(str(r))
def client_url(self):
@@ -205,7 +206,8 @@
# push can proceed
fp.seek(0)
- r = self.repo.addchangegroup(fp, 'serve', self.client_url())
+ r = self.repo.addchangegroup(fp, 'serve', self.client_url(),
+ lock=self.lock)
self.respond(str(r))
finally:
if not was_locked:
--- a/mercurial/subrepo.py Mon Jun 21 17:02:48 2010 -0300
+++ b/mercurial/subrepo.py Fri Jul 02 11:30:57 2010 +0200
@@ -67,19 +67,21 @@
repo.ui.debug(" subrepo %s: %s %s\n" % (s, msg, r))
for s, l in s1.items():
+ ld = l # local state with possible dirty flag for compares
if wctx != actx and wctx.sub(s).dirty():
- l = (l[0], l[1] + "+")
+ ld = (l[0], l[1] + "+")
+
a = sa.get(s, nullstate)
if s in s2:
r = s2[s]
- if l == r or r == a: # no change or local is newer
+ if ld == r or r == a: # no change or local is newer
sm[s] = l
continue
- elif l == a: # other side changed
+ elif ld == a: # other side changed
debug(s, "other changed, get", r)
wctx.sub(s).get(r)
sm[s] = r
- elif l[0] != r[0]: # sources differ
+ elif ld[0] != r[0]: # sources differ
if repo.ui.promptchoice(
_(' subrepository sources for %s differ\n'
'use (l)ocal source (%s) or (r)emote source (%s)?')
@@ -88,7 +90,7 @@
debug(s, "prompt changed, get", r)
wctx.sub(s).get(r)
sm[s] = r
- elif l[1] == a[1]: # local side is unchanged
+ elif ld[1] == a[1]: # local side is unchanged
debug(s, "other side changed, get", r)
wctx.sub(s).get(r)
sm[s] = r
@@ -96,7 +98,7 @@
debug(s, "both sides changed, merge with", r)
wctx.sub(s).merge(r)
sm[s] = l
- elif l == a: # remote removed, local unchanged
+ elif ld == a: # remote removed, local unchanged
debug(s, "remote removed, remove")
wctx.sub(s).remove()
else:
@@ -379,8 +381,8 @@
self.get(state)
def push(self, force):
- # nothing for svn
- pass
+ # push is a no-op for SVN
+ return True
types = {
'hg': hgsubrepo,
--- a/mercurial/url.py Mon Jun 21 17:02:48 2010 -0300
+++ b/mercurial/url.py Fri Jul 02 11:30:57 2010 +0200
@@ -542,11 +542,25 @@
conn.ui = self.ui
return conn
-# In python < 2.5 AbstractDigestAuthHandler raises a ValueError if
-# it doesn't know about the auth type requested. This can happen if
-# somebody is using BasicAuth and types a bad password.
class httpdigestauthhandler(urllib2.HTTPDigestAuthHandler):
+ def __init__(self, *args, **kwargs):
+ urllib2.HTTPDigestAuthHandler.__init__(self, *args, **kwargs)
+ self.retried_req = None
+
+ def reset_retry_count(self):
+ # Python 2.6.5 will call this on 401 or 407 errors and thus loop
+ # forever. We disable reset_retry_count completely and reset in
+ # http_error_auth_reqed instead.
+ pass
+
def http_error_auth_reqed(self, auth_header, host, req, headers):
+ # Reset the retry counter once for each request.
+ if req is not self.retried_req:
+ self.retried_req = req
+ self.retried = 0
+ # In python < 2.5 AbstractDigestAuthHandler raises a ValueError if
+ # it doesn't know about the auth type requested. This can happen if
+ # somebody is using BasicAuth and types a bad password.
try:
return urllib2.HTTPDigestAuthHandler.http_error_auth_reqed(
self, auth_header, host, req, headers)
@@ -556,13 +570,6 @@
return
raise
- # Python 2.6.5 will keep resetting the retry count on redirects, for
- # example when the server returns 401 on failing auth (like google code
- # currently does). We stop the endless recursion by not resetting the
- # count.
- def reset_retry_count(self):
- pass
-
def getauthinfo(path):
scheme, netloc, urlpath, query, frag = urlparse.urlsplit(path)
if not urlpath:
--- a/mercurial/util.py Mon Jun 21 17:02:48 2010 -0300
+++ b/mercurial/util.py Fri Jul 02 11:30:57 2010 +0200
@@ -366,13 +366,16 @@
global _hgexecutable
_hgexecutable = path
-def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None):
+def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None, out=None):
'''enhanced shell command execution.
run with environment maybe modified, maybe in different dir.
if command fails and onerr is None, return status. if ui object,
print error message and return status, else raise onerr object as
- exception.'''
+ exception.
+
+ if out is specified, it is assumed to be a file-like object that has a
+ write() method. stdout and stderr will be redirected to out.'''
def py2shell(val):
'convert python object into string that is useful to shell'
if val is None or val is False:
@@ -386,8 +389,17 @@
env = dict(os.environ)
env.update((k, py2shell(v)) for k, v in environ.iteritems())
env['HG'] = hgexecutable()
- rc = subprocess.call(cmd, shell=True, close_fds=closefds,
- env=env, cwd=cwd)
+ if out is None:
+ rc = subprocess.call(cmd, shell=True, close_fds=closefds,
+ env=env, cwd=cwd)
+ else:
+ proc = subprocess.Popen(cmd, shell=True, close_fds=closefds,
+ env=env, cwd=cwd, stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ for line in proc.stdout:
+ out.write(line)
+ proc.wait()
+ rc = proc.returncode
if sys.platform == 'OpenVMS' and rc & 1:
rc = 0
if rc and onerr:
--- a/setup.py Mon Jun 21 17:02:48 2010 -0300
+++ b/setup.py Fri Jul 02 11:30:57 2010 +0200
@@ -35,12 +35,15 @@
import os, subprocess, time
import shutil
import tempfile
+from distutils import log
from distutils.core import setup, Extension
from distutils.dist import Distribution
from distutils.command.build import build
+from distutils.command.build_ext import build_ext
from distutils.command.build_py import build_py
from distutils.spawn import spawn, find_executable
from distutils.ccompiler import new_compiler
+from distutils.errors import CCompilerError
scripts = ['hg']
if os.name == 'nt':
@@ -209,6 +212,17 @@
Distribution.global_options.append(('pure', None, "use pure (slow) Python "
"code instead of C extensions"))
+class hgbuildext(build_ext):
+
+ def build_extension(self, ext):
+ try:
+ build_ext.build_extension(self, ext)
+ except CCompilerError:
+ if not hasattr(ext, 'optional') or not ext.optional:
+ raise
+ log.warn("Failed to build optional extension '%s' (skipping)",
+ ext.name)
+
class hgbuildpy(build_py):
def finalize_options(self):
@@ -232,6 +246,7 @@
yield module
cmdclass = {'build_mo': hgbuildmo,
+ 'build_ext': hgbuildext,
'build_py': hgbuildpy}
packages = ['mercurial', 'mercurial.hgweb', 'hgext', 'hgext.convert',
@@ -256,10 +271,13 @@
if sys.platform == 'linux2' and os.uname()[2] > '2.6':
# The inotify extension is only usable with Linux 2.6 kernels.
# You also need a reasonably recent C library.
+ # In any case, if it fails to build the error will be skipped ('optional').
cc = new_compiler()
if hasfunction(cc, 'inotify_add_watch'):
- extmodules.append(Extension('hgext.inotify.linux._inotify',
- ['hgext/inotify/linux/_inotify.c']))
+ inotify = Extension('hgext.inotify.linux._inotify',
+ ['hgext/inotify/linux/_inotify.c'])
+ inotify.optional = True
+ extmodules.append(inotify)
packages.extend(['hgext.inotify', 'hgext.inotify.linux'])
packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
--- a/tests/test-acl Mon Jun 21 17:02:48 2010 -0300
+++ b/tests/test-acl Fri Jul 02 11:30:57 2010 +0200
@@ -44,7 +44,7 @@
[acl]
sources = push
[extensions]
-f=$PWD/fakegroups.py
+f=`pwd`/fakegroups.py
EOF
}
--- a/tests/test-alias Mon Jun 21 17:02:48 2010 -0300
+++ b/tests/test-alias Fri Jul 02 11:30:57 2010 +0200
@@ -13,7 +13,7 @@
shortlog = log --template '{rev} {node|short} | {date|isodate}\n'
dln = lognull --debug
nousage = rollback
-put = export -r 0 -o "\$PWD/%R.diff"
+put = export -r 0 -o "\$FOO/%R.diff"
[defaults]
mylog = -q
@@ -62,5 +62,5 @@
hg dln
echo '% path expanding'
-hg put
+FOO=`pwd` hg put
cat 0.diff
--- a/tests/test-command-template Mon Jun 21 17:02:48 2010 -0300
+++ b/tests/test-command-template Fri Jul 02 11:30:57 2010 +0200
@@ -100,6 +100,9 @@
hg log --style=changelog > changelog
cat changelog
+echo '# issue 2130'
+hg heads --style changelog
+
echo "# keys work"
for key in author branches date desc file_adds file_dels file_mods \
file_copies file_copies_switch files \
--- a/tests/test-command-template.out Mon Jun 21 17:02:48 2010 -0300
+++ b/tests/test-command-template.out Fri Jul 02 11:30:57 2010 +0200
@@ -437,6 +437,23 @@
line 1 line 2
[1e4e1b8f71e0]
+# issue 2130
+2020-01-01 test <test>
+
+ * fourth, second, third:
+ third
+ [95c24699272e] [tip]
+
+1970-01-18 person <person>
+
+ * merge
+ [c7b487c6c50e]
+
+1970-01-17 person <person>
+
+ * new branch
+ [32a18f097fcc] <foo>
+
# keys work
author: test
author: User Name <user@hostname>
--- a/tests/test-glog Mon Jun 21 17:02:48 2010 -0300
+++ b/tests/test-glog Fri Jul 02 11:30:57 2010 +0200
@@ -146,6 +146,9 @@
echo % unused arguments
hg glog -q foo bar || echo failed
+echo % empty revision range - display nothing
+hg glog -r 1..0
+
echo % from outer space
cd ..
hg glog -l1 repo
--- a/tests/test-glog.out Mon Jun 21 17:02:48 2010 -0300
+++ b/tests/test-glog.out Fri Jul 02 11:30:57 2010 +0200
@@ -548,6 +548,7 @@
show revision history alongside an ASCII revision graph
failed
+% empty revision range - display nothing
% from outer space
@ changeset: 34:fea3ac5810e0
| tag: tip
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-mq-qimport-fail-cleanup Fri Jul 02 11:30:57 2010 +0200
@@ -0,0 +1,33 @@
+#!/bin/sh
+#failed qimport of patches from files should cleanup by recording successfully
+#imported patches in series file.
+
+echo "[extensions]" >> $HGRCPATH
+echo "mq=" >> $HGRCPATH
+
+hg init repo
+cd repo
+
+echo a > a
+hg ci -Am'add a'
+
+cat >b.patch<<EOF
+diff --git a/a b/a
+--- a/a
++++ b/a
+@@ -1,1 +1,2 @@
+ a
++b
+EOF
+
+echo
+echo '#empty series'
+hg qseries
+
+echo
+echo '#qimport valid patch followed by invalid patch'
+hg qimport b.patch fakepatch
+
+echo
+echo '#valid patches before fail added to series'
+hg qseries
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-mq-qimport-fail-cleanup.out Fri Jul 02 11:30:57 2010 +0200
@@ -0,0 +1,10 @@
+adding a
+
+#empty series
+
+#qimport valid patch followed by invalid patch
+adding b.patch to series file
+abort: unable to read fakepatch
+
+#valid patches before fail added to series
+b.patch
--- a/tests/test-push-http Mon Jun 21 17:02:48 2010 -0300
+++ b/tests/test-push-http Fri Jul 02 11:30:57 2010 +0200
@@ -39,11 +39,9 @@
echo % expect success
echo 'allow_push = *' >> .hg/hgrc
echo '[hooks]' >> .hg/hgrc
-echo 'changegroup = python ../printenv.py changegroup 0 ../urls' >> .hg/hgrc
+echo 'changegroup = python ../printenv.py changegroup 0' >> .hg/hgrc
req
-cat ../urls
-
hg rollback
echo % expect authorization error: all users denied
echo '[web]' > .hg/hgrc
--- a/tests/test-push-http.out Mon Jun 21 17:02:48 2010 -0300
+++ b/tests/test-push-http.out Fri Jul 02 11:30:57 2010 +0200
@@ -23,8 +23,8 @@
remote: adding manifests
remote: adding file changes
remote: added 1 changesets with 1 changes to 1 files
+remote: changegroup hook: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_URL=remote:http
% serve errors
-changegroup hook: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_URL=remote:http
rolling back to revision 0 (undo serve)
% expect authorization error: all users denied
abort: authorization failed
--- a/tests/test-resolve Mon Jun 21 17:02:48 2010 -0300
+++ b/tests/test-resolve Fri Jul 02 11:30:57 2010 +0200
@@ -25,3 +25,9 @@
echo % resolve -l, should be empty
hg resolve -l
+
+# test crashed merge with empty mergestate
+mkdir .hg/merge
+touch .hg/merge/state
+echo % resolve -l, should be empty
+hg resolve -l
--- a/tests/test-resolve.out Mon Jun 21 17:02:48 2010 -0300
+++ b/tests/test-resolve.out Fri Jul 02 11:30:57 2010 +0200
@@ -6,3 +6,4 @@
0 files updated, 0 files merged, 0 files removed, 1 files unresolved
use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
% resolve -l, should be empty
+% resolve -l, should be empty
--- a/tests/test-revset Mon Jun 21 17:02:48 2010 -0300
+++ b/tests/test-revset Fri Jul 02 11:30:57 2010 +0200
@@ -126,3 +126,11 @@
log '4:8'
log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
+
+log 'not 0 and 0:2'
+log 'not 1 and 0:2'
+log 'not 2 and 0:2'
+log '(1 and 2)::'
+log '(1 and 2):'
+log '(1 and 2):3'
+log 'sort(head(), -rev)'
--- a/tests/test-revset.out Mon Jun 21 17:02:48 2010 -0300
+++ b/tests/test-revset.out Fri Jul 02 11:30:57 2010 +0200
@@ -198,3 +198,25 @@
4
2
5
+% log 'not 0 and 0:2'
+1
+2
+% log 'not 1 and 0:2'
+0
+2
+% log 'not 2 and 0:2'
+0
+1
+% log '(1 and 2)::'
+% log '(1 and 2):'
+% log '(1 and 2):3'
+% log 'sort(head(), -rev)'
+9
+7
+6
+5
+4
+3
+2
+1
+0