--- a/contrib/check-code.py Sat Sep 07 15:07:10 2013 -0500
+++ b/contrib/check-code.py Fri Sep 20 11:47:03 2013 -0500
@@ -61,11 +61,13 @@
(r'pushd|popd', "don't use 'pushd' or 'popd', use 'cd'"),
(r'\W\$?\(\([^\)\n]*\)\)', "don't use (()) or $(()), use 'expr'"),
(r'grep.*-q', "don't use 'grep -q', redirect to /dev/null"),
+ (r'(?<!hg )grep.*-a', "don't use 'grep -a', use in-line python"),
(r'sed.*-i', "don't use 'sed -i', use a temporary file"),
(r'\becho\b.*\\n', "don't use 'echo \\n', use printf"),
(r'echo -n', "don't use 'echo -n', use printf"),
(r'(^| )wc[^|]*$\n(?!.*\(re\))', "filter wc output"),
(r'head -c', "don't use 'head -c', use 'dd'"),
+ (r'tail -n', "don't use the '-n' option to tail, just use '-<num>'"),
(r'sha1sum', "don't use sha1sum, use $TESTDIR/md5sum.py"),
(r'ls.*-\w*R', "don't use 'ls -R', use 'find'"),
(r'printf.*[^\\]\\([1-9]|0\d)', "don't use 'printf \NNN', use Python"),
@@ -285,8 +287,9 @@
(r'(while|if|do|for)\(', "use space after while/if/do/for"),
(r'return\(', "return is not a function"),
(r' ;', "no space before ;"),
+ (r'[)][{]', "space between ) and {"),
(r'\w+\* \w+', "use int *foo, not int* foo"),
- (r'\([^\)]+\) \w+', "use (int)foo, not (int) foo"),
+ (r'\W\([^\)]+\) \w+', "use (int)foo, not (int) foo"),
(r'\w+ (\+\+|--)', "use foo++, not foo ++"),
(r'\w,\w', "missing whitespace after ,"),
(r'^[^#]\w[+/*]\w', "missing whitespace in expression"),
@@ -324,7 +327,7 @@
checks = [
('python', r'.*\.(py|cgi)$', pyfilters, pypats),
('test script', r'(.*/)?test-[^.~]*$', testfilters, testpats),
- ('c', r'.*\.c$', cfilters, cpats),
+ ('c', r'.*\.[ch]$', cfilters, cpats),
('unified test', r'.*\.t$', utestfilters, utestpats),
('layering violation repo in revlog', r'mercurial/revlog\.py', pyfilters,
inrevlogpats),
--- a/contrib/perf.py Sat Sep 07 15:07:10 2013 -0500
+++ b/contrib/perf.py Fri Sep 20 11:47:03 2013 -0500
@@ -171,13 +171,14 @@
copies.pathcopies(ctx1, ctx2)
timer(d)
-@command('perfmanifest')
-def perfmanifest(ui, repo):
+@command('perfmanifest', [], 'REV')
+def perfmanifest(ui, repo, rev):
+ ctx = scmutil.revsingle(repo, rev, rev)
+ t = ctx.manifestnode()
def d():
- t = repo.manifest.tip()
+ repo.manifest._mancache.clear()
+ repo.manifest._cache = None
repo.manifest.read(t)
- repo.manifest.mapcache = None
- repo.manifest._cache = None
timer(d)
@command('perfchangeset')
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/plan9/9mail Fri Sep 20 11:47:03 2013 -0500
@@ -0,0 +1,26 @@
+#!/bin/rc
+# 9mail - Mercurial email wrapper for upas/marshal
+
+fn usage {
+ echo >[1=2] usage: mercurial/9mail -f from to [cc]
+ exit usage
+}
+
+from=()
+cc=()
+to=()
+
+switch($1){
+case -f
+ from=$2
+case *
+ usage
+}
+
+to=($3)
+if(~ $#* 4)
+ cc=(-C $4)
+
+upasname=$from
+upas/marshal $cc $to
+
--- a/contrib/plan9/hgrc.d/9diff.rc Sat Sep 07 15:07:10 2013 -0500
+++ b/contrib/plan9/hgrc.d/9diff.rc Fri Sep 20 11:47:03 2013 -0500
@@ -4,4 +4,4 @@
extdiff =
[extdiff]
-9diff = 9diff -cm $parent $child $root
+9diff = /bin/mercurial/9diff -cm $parent $child $root
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/plan9/hgrc.d/9mail.rc Fri Sep 20 11:47:03 2013 -0500
@@ -0,0 +1,4 @@
+# The 9mail to support patchbomb and other email wrappers
+[email]
+method = /bin/mercurial/9mail
+
--- a/hgext/factotum.py Sat Sep 07 15:07:10 2013 -0500
+++ b/hgext/factotum.py Fri Sep 20 11:47:03 2013 -0500
@@ -101,7 +101,7 @@
user, passwd = auth.get('username'), auth.get('password')
if not user or not passwd:
if not prefix:
- prefix = '*'
+ prefix = realm.split(' ')[0].lower()
params = 'service=%s prefix=%s' % (_service, prefix)
if user:
params = '%s user=%s' % (params, user)
--- a/hgext/histedit.py Sat Sep 07 15:07:10 2013 -0500
+++ b/hgext/histedit.py Fri Sep 20 11:47:03 2013 -0500
@@ -419,10 +419,6 @@
if revs:
revs = [repo.lookup(rev) for rev in revs]
- # hexlify nodes from outgoing, because we're going to parse
- # parent[0] using revsingle below, and if the binary hash
- # contains special revset characters like ":" the revset
- # parser can choke.
outgoing = discovery.findcommonoutgoing(repo, other, revs, force=force)
if not outgoing.missing:
raise util.Abort(_('no outgoing ancestors'))
--- a/hgext/largefiles/reposetup.py Sat Sep 07 15:07:10 2013 -0500
+++ b/hgext/largefiles/reposetup.py Fri Sep 20 11:47:03 2013 -0500
@@ -10,8 +10,7 @@
import copy
import os
-from mercurial import context, error, manifest, match as match_, util, \
- discovery
+from mercurial import error, manifest, match as match_, util, discovery
from mercurial import node as node_
from mercurial.i18n import _
from mercurial import localrepo
@@ -92,14 +91,8 @@
else:
# some calls in this function rely on the old version of status
self.lfstatus = False
- if isinstance(node1, context.changectx):
- ctx1 = node1
- else:
- ctx1 = self[node1]
- if isinstance(node2, context.changectx):
- ctx2 = node2
- else:
- ctx2 = self[node2]
+ ctx1 = self[node1]
+ ctx2 = self[node2]
working = ctx2.rev() is None
parentworking = working and ctx1 == self['.']
--- a/hgext/mq.py Sat Sep 07 15:07:10 2013 -0500
+++ b/hgext/mq.py Fri Sep 20 11:47:03 2013 -0500
@@ -66,6 +66,7 @@
from mercurial import repair, extensions, error, phases, bookmarks
from mercurial import patch as patchmod
from mercurial import localrepo
+from mercurial import subrepo
import os, re, errno, shutil
commands.norepo += " qclone"
@@ -282,15 +283,11 @@
phase = phases.secret
if phase is not None:
backup = repo.ui.backupconfig('phases', 'new-commit')
- # Marking the repository as committing an mq patch can be used
- # to optimize operations like branchtags().
- repo._committingpatch = True
try:
if phase is not None:
repo.ui.setconfig('phases', 'new-commit', phase)
return repo.commit(*args, **kwargs)
finally:
- repo._committingpatch = False
if phase is not None:
repo.ui.restoreconfig(backup)
@@ -800,6 +797,14 @@
p1, p2 = repo.dirstate.parents()
repo.setparents(p1, merge)
+ if all_files and '.hgsubstate' in all_files:
+ wctx = repo['.']
+ mctx = actx = repo[None]
+ overwrite = False
+ mergedsubstate = subrepo.submerge(repo, wctx, mctx, actx,
+ overwrite)
+ files += mergedsubstate.keys()
+
match = scmutil.matchfiles(repo, files or [])
oldtip = repo['tip']
n = newcommit(repo, None, message, ph.user, ph.date, match=match,
@@ -975,11 +980,20 @@
else:
raise util.Abort(_("local changes found"))
+ def localchangedsubreposfound(self, refresh=True):
+ if refresh:
+ raise util.Abort(_("local changed subrepos found, refresh first"))
+ else:
+ raise util.Abort(_("local changed subrepos found"))
+
def checklocalchanges(self, repo, force=False, refresh=True):
cmdutil.checkunfinished(repo)
m, a, r, d = repo.status()[:4]
- if (m or a or r or d) and not force:
- self.localchangesfound(refresh)
+ if not force:
+ if (m or a or r or d):
+ self.localchangesfound(refresh)
+ if self.checksubstate(repo):
+ self.localchangedsubreposfound(refresh)
return m, a, r, d
_reserved = ('series', 'status', 'guards', '.', '..')
@@ -1450,6 +1464,8 @@
self.ui.status(_("popping %s\n") % patch.name)
del self.applied[start:end]
self.strip(repo, [rev], update=False, backup='strip')
+ for s, state in repo['.'].substate.items():
+ repo['.'].sub(s).get(state)
if self.applied:
self.ui.write(_("now at: %s\n") % self.applied[-1].name)
else:
--- a/hgext/progress.py Sat Sep 07 15:07:10 2013 -0500
+++ b/hgext/progress.py Fri Sep 20 11:47:03 2013 -0500
@@ -239,6 +239,13 @@
# this one are also closed
if topic in self.topics:
self.topics = self.topics[:self.topics.index(topic)]
+ # reset the last topic to the one we just unwound to,
+ # so that higher-level topics will be stickier than
+ # lower-level topics
+ if self.topics:
+ self.lasttopic = self.topics[-1]
+ else:
+ self.lasttopic = None
else:
if topic not in self.topics:
self.starttimes[topic] = now
--- a/mercurial/bundlerepo.py Sat Sep 07 15:07:10 2013 -0500
+++ b/mercurial/bundlerepo.py Fri Sep 20 11:47:03 2013 -0500
@@ -120,7 +120,7 @@
chain.append(iterrev)
iterrev = self.index[iterrev][3]
if text is None:
- text = revlog.revlog.revision(self, iterrev)
+ text = self.baserevision(iterrev)
while chain:
delta = self._chunk(chain.pop())
@@ -130,6 +130,12 @@
self._cache = (node, rev, text)
return text
+ def baserevision(self, nodeorrev):
+ # Revlog subclasses may override 'revision' method to modify format of
+ # content retrieved from revlog. To use bundlerevlog with such class one
+ # needs to override 'baserevision' and make more specific call here.
+ return revlog.revlog.revision(self, nodeorrev)
+
def addrevision(self, text, transaction, link, p1=None, p2=None, d=None):
raise NotImplementedError
def addgroup(self, revs, linkmapper, transaction):
@@ -146,12 +152,21 @@
bundlerevlog.__init__(self, opener, self.indexfile, bundle,
linkmapper)
+ def baserevision(self, nodeorrev):
+ # Although changelog doesn't override 'revision' method, some extensions
+ # may replace this class with another that does. Same story with
+ # manifest and filelog classes.
+ return changelog.changelog.revision(self, nodeorrev)
+
class bundlemanifest(bundlerevlog, manifest.manifest):
def __init__(self, opener, bundle, linkmapper):
manifest.manifest.__init__(self, opener)
bundlerevlog.__init__(self, opener, self.indexfile, bundle,
linkmapper)
+ def baserevision(self, nodeorrev):
+ return manifest.manifest.revision(self, nodeorrev)
+
class bundlefilelog(bundlerevlog, filelog.filelog):
def __init__(self, opener, path, bundle, linkmapper, repo):
filelog.filelog.__init__(self, opener, path)
@@ -159,6 +174,9 @@
linkmapper)
self._repo = repo
+ def baserevision(self, nodeorrev):
+ return filelog.filelog.revision(self, nodeorrev)
+
def _file(self, f):
self._repo.file(f)
--- a/mercurial/cmdutil.py Sat Sep 07 15:07:10 2013 -0500
+++ b/mercurial/cmdutil.py Fri Sep 20 11:47:03 2013 -0500
@@ -1172,12 +1172,34 @@
'filenames'))
# The slow path checks files modified in every changeset.
- for i in sorted(revs):
- ctx = change(i)
- matches = filter(match, ctx.files())
- if matches:
- fncache[i] = matches
- wanted.add(i)
+ # This is really slow on large repos, so compute the set lazily.
+ class lazywantedset(object):
+ def __init__(self):
+ self.set = set()
+ self.revs = set(revs)
+
+ # No need to worry about locality here because it will be accessed
+ # in the same order as the increasing window below.
+ def __contains__(self, value):
+ if value in self.set:
+ return True
+ elif not value in self.revs:
+ return False
+ else:
+ self.revs.discard(value)
+ ctx = change(value)
+ matches = filter(match, ctx.files())
+ if matches:
+ fncache[value] = matches
+ self.set.add(value)
+ return True
+ return False
+
+ def discard(self, value):
+ self.revs.discard(value)
+ self.set.discard(value)
+
+ wanted = lazywantedset()
class followfilter(object):
def __init__(self, onlyfirst=False):
--- a/mercurial/commands.py Sat Sep 07 15:07:10 2013 -0500
+++ b/mercurial/commands.py Fri Sep 20 11:47:03 2013 -0500
@@ -12,7 +12,8 @@
import hg, scmutil, util, revlog, copies, error, bookmarks
import patch, help, encoding, templatekw, discovery
import archival, changegroup, cmdutil, hbisect
-import sshserver, hgweb, hgweb.server, commandserver
+import sshserver, hgweb, commandserver
+from hgweb import server as hgweb_server
import merge as mergemod
import minirst, revset, fileset
import dagparser, context, simplemerge, graphmod
@@ -1923,6 +1924,7 @@
util.writefile('.debugfsinfo', '')
ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
+ ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
and 'yes' or 'no'))
os.unlink('.debugfsinfo')
@@ -5182,7 +5184,7 @@
class service(object):
def init(self):
util.setsignalhandler()
- self.httpd = hgweb.server.create_server(ui, app)
+ self.httpd = hgweb_server.create_server(ui, app)
if opts['port'] and not ui.verbose:
return
--- a/mercurial/context.py Sat Sep 07 15:07:10 2013 -0500
+++ b/mercurial/context.py Fri Sep 20 11:47:03 2013 -0500
@@ -16,11 +16,197 @@
propertycache = util.propertycache
-class changectx(object):
+class basectx(object):
+ """A basectx object represents the common logic for its children:
+ changectx: read-only context that is already present in the repo,
+ workingctx: a context that represents the working directory and can
+ be committed,
+ memctx: a context that represents changes in-memory and can also
+ be committed."""
+ def __new__(cls, repo, changeid='', *args, **kwargs):
+ if isinstance(changeid, basectx):
+ return changeid
+
+ o = super(basectx, cls).__new__(cls)
+
+ o._repo = repo
+ o._rev = nullrev
+ o._node = nullid
+
+ return o
+
+ def __str__(self):
+ return short(self.node())
+
+ def __int__(self):
+ return self.rev()
+
+ def __repr__(self):
+ return "<%s %s>" % (type(self).__name__, str(self))
+
+ def __eq__(self, other):
+ try:
+ return type(self) == type(other) and self._rev == other._rev
+ except AttributeError:
+ return False
+
+ def __ne__(self, other):
+ return not (self == other)
+
+ def __contains__(self, key):
+ return key in self._manifest
+
+ def __getitem__(self, key):
+ return self.filectx(key)
+
+ def __iter__(self):
+ for f in sorted(self._manifest):
+ yield f
+
+ @propertycache
+ def substate(self):
+ return subrepo.state(self, self._repo.ui)
+
+ def rev(self):
+ return self._rev
+ def node(self):
+ return self._node
+ def hex(self):
+ return hex(self.node())
+ def manifest(self):
+ return self._manifest
+ def phasestr(self):
+ return phases.phasenames[self.phase()]
+ def mutable(self):
+ return self.phase() > phases.public
+
+ def obsolete(self):
+ """True if the changeset is obsolete"""
+ return self.rev() in obsmod.getrevs(self._repo, 'obsolete')
+
+ def extinct(self):
+ """True if the changeset is extinct"""
+ return self.rev() in obsmod.getrevs(self._repo, 'extinct')
+
+ def unstable(self):
+ """True if the changeset is not obsolete but it's ancestor are"""
+ return self.rev() in obsmod.getrevs(self._repo, 'unstable')
+
+ def bumped(self):
+ """True if the changeset try to be a successor of a public changeset
+
+ Only non-public and non-obsolete changesets may be bumped.
+ """
+ return self.rev() in obsmod.getrevs(self._repo, 'bumped')
+
+ def divergent(self):
+ """Is a successors of a changeset with multiple possible successors set
+
+ Only non-public and non-obsolete changesets may be divergent.
+ """
+ return self.rev() in obsmod.getrevs(self._repo, 'divergent')
+
+ def troubled(self):
+ """True if the changeset is either unstable, bumped or divergent"""
+ return self.unstable() or self.bumped() or self.divergent()
+
+ def troubles(self):
+ """return the list of troubles affecting this changesets.
+
+ Troubles are returned as strings. possible values are:
+ - unstable,
+ - bumped,
+ - divergent.
+ """
+ troubles = []
+ if self.unstable():
+ troubles.append('unstable')
+ if self.bumped():
+ troubles.append('bumped')
+ if self.divergent():
+ troubles.append('divergent')
+ return troubles
+
+ def parents(self):
+ """return contexts for each parent changeset"""
+ return self._parents
+
+ def p1(self):
+ return self._parents[0]
+
+ def p2(self):
+ if len(self._parents) == 2:
+ return self._parents[1]
+ return changectx(self._repo, -1)
+
+ def _fileinfo(self, path):
+ if '_manifest' in self.__dict__:
+ try:
+ return self._manifest[path], self._manifest.flags(path)
+ except KeyError:
+ raise error.ManifestLookupError(self._node, path,
+ _('not found in manifest'))
+ if '_manifestdelta' in self.__dict__ or path in self.files():
+ if path in self._manifestdelta:
+ return (self._manifestdelta[path],
+ self._manifestdelta.flags(path))
+ node, flag = self._repo.manifest.find(self._changeset[0], path)
+ if not node:
+ raise error.ManifestLookupError(self._node, path,
+ _('not found in manifest'))
+
+ return node, flag
+
+ def filenode(self, path):
+ return self._fileinfo(path)[0]
+
+ def flags(self, path):
+ try:
+ return self._fileinfo(path)[1]
+ except error.LookupError:
+ return ''
+
+ def sub(self, path):
+ return subrepo.subrepo(self, path)
+
+ def match(self, pats=[], include=None, exclude=None, default='glob'):
+ r = self._repo
+ return matchmod.match(r.root, r.getcwd(), pats,
+ include, exclude, default,
+ auditor=r.auditor, ctx=self)
+
+ def diff(self, ctx2=None, match=None, **opts):
+ """Returns a diff generator for the given contexts and matcher"""
+ if ctx2 is None:
+ ctx2 = self.p1()
+ if ctx2 is not None:
+ ctx2 = self._repo[ctx2]
+ diffopts = patch.diffopts(self._repo.ui, opts)
+ return patch.diff(self._repo, ctx2.node(), self.node(),
+ match=match, opts=diffopts)
+
+ @propertycache
+ def _dirs(self):
+ return scmutil.dirs(self._manifest)
+
+ def dirs(self):
+ return self._dirs
+
+ def dirty(self):
+ return False
+
+class changectx(basectx):
"""A changecontext object makes access to data related to a particular
- changeset convenient."""
+ changeset convenient. It represents a read-only context already presnt in
+ the repo."""
def __init__(self, repo, changeid=''):
"""changeid is a revision number, node, or tag"""
+
+ # since basectx.__new__ already took care of copying the object, we
+ # don't need to do anything in __init__, so we just exit here
+ if isinstance(changeid, basectx):
+ return
+
if changeid == '':
changeid = '.'
self._repo = repo
@@ -114,30 +300,12 @@
raise error.RepoLookupError(
_("unknown revision '%s'") % changeid)
- def __str__(self):
- return short(self.node())
-
- def __int__(self):
- return self.rev()
-
- def __repr__(self):
- return "<changectx %s>" % str(self)
-
def __hash__(self):
try:
return hash(self._rev)
except AttributeError:
return id(self)
- def __eq__(self, other):
- try:
- return self._rev == other._rev
- except AttributeError:
- return False
-
- def __ne__(self, other):
- return not (self == other)
-
def __nonzero__(self):
return self._rev != nullrev
@@ -160,33 +328,11 @@
p = p[:-1]
return [changectx(self._repo, x) for x in p]
- @propertycache
- def substate(self):
- return subrepo.state(self, self._repo.ui)
-
- def __contains__(self, key):
- return key in self._manifest
-
- def __getitem__(self, key):
- return self.filectx(key)
-
- def __iter__(self):
- for f in sorted(self._manifest):
- yield f
-
def changeset(self):
return self._changeset
- def manifest(self):
- return self._manifest
def manifestnode(self):
return self._changeset[0]
- def rev(self):
- return self._rev
- def node(self):
- return self._node
- def hex(self):
- return hex(self._node)
def user(self):
return self._changeset[1]
def date(self):
@@ -207,25 +353,9 @@
return self._repo.nodebookmarks(self._node)
def phase(self):
return self._repo._phasecache.phase(self._repo, self._rev)
- def phasestr(self):
- return phases.phasenames[self.phase()]
- def mutable(self):
- return self.phase() > phases.public
def hidden(self):
return self._rev in repoview.filterrevs(self._repo, 'visible')
- def parents(self):
- """return contexts for each parent changeset"""
- return self._parents
-
- def p1(self):
- return self._parents[0]
-
- def p2(self):
- if len(self._parents) == 2:
- return self._parents[1]
- return changectx(self._repo, -1)
-
def children(self):
"""return contexts for each child changeset"""
c = self._repo.changelog.children(self._node)
@@ -239,80 +369,6 @@
for d in self._repo.changelog.descendants([self._rev]):
yield changectx(self._repo, d)
- def obsolete(self):
- """True if the changeset is obsolete"""
- return self.rev() in obsmod.getrevs(self._repo, 'obsolete')
-
- def extinct(self):
- """True if the changeset is extinct"""
- return self.rev() in obsmod.getrevs(self._repo, 'extinct')
-
- def unstable(self):
- """True if the changeset is not obsolete but it's ancestor are"""
- return self.rev() in obsmod.getrevs(self._repo, 'unstable')
-
- def bumped(self):
- """True if the changeset try to be a successor of a public changeset
-
- Only non-public and non-obsolete changesets may be bumped.
- """
- return self.rev() in obsmod.getrevs(self._repo, 'bumped')
-
- def divergent(self):
- """Is a successors of a changeset with multiple possible successors set
-
- Only non-public and non-obsolete changesets may be divergent.
- """
- return self.rev() in obsmod.getrevs(self._repo, 'divergent')
-
- def troubled(self):
- """True if the changeset is either unstable, bumped or divergent"""
- return self.unstable() or self.bumped() or self.divergent()
-
- def troubles(self):
- """return the list of troubles affecting this changesets.
-
- Troubles are returned as strings. possible values are:
- - unstable,
- - bumped,
- - divergent.
- """
- troubles = []
- if self.unstable():
- troubles.append('unstable')
- if self.bumped():
- troubles.append('bumped')
- if self.divergent():
- troubles.append('divergent')
- return troubles
-
- def _fileinfo(self, path):
- if '_manifest' in self.__dict__:
- try:
- return self._manifest[path], self._manifest.flags(path)
- except KeyError:
- raise error.ManifestLookupError(self._node, path,
- _('not found in manifest'))
- if '_manifestdelta' in self.__dict__ or path in self.files():
- if path in self._manifestdelta:
- return (self._manifestdelta[path],
- self._manifestdelta.flags(path))
- node, flag = self._repo.manifest.find(self._changeset[0], path)
- if not node:
- raise error.ManifestLookupError(self._node, path,
- _('not found in manifest'))
-
- return node, flag
-
- def filenode(self, path):
- return self._fileinfo(path)[0]
-
- def flags(self, path):
- try:
- return self._fileinfo(path)[1]
- except error.LookupError:
- return ''
-
def filectx(self, path, fileid=None, filelog=None):
"""get a file context from this changeset"""
if fileid is None:
@@ -353,83 +409,15 @@
if match.bad(fn, _('no such file in rev %s') % self) and match(fn):
yield fn
- def sub(self, path):
- return subrepo.subrepo(self, path)
-
- def match(self, pats=[], include=None, exclude=None, default='glob'):
- r = self._repo
- return matchmod.match(r.root, r.getcwd(), pats,
- include, exclude, default,
- auditor=r.auditor, ctx=self)
-
- def diff(self, ctx2=None, match=None, **opts):
- """Returns a diff generator for the given contexts and matcher"""
- if ctx2 is None:
- ctx2 = self.p1()
- if ctx2 is not None and not isinstance(ctx2, changectx):
- ctx2 = self._repo[ctx2]
- diffopts = patch.diffopts(self._repo.ui, opts)
- return patch.diff(self._repo, ctx2.node(), self.node(),
- match=match, opts=diffopts)
-
- @propertycache
- def _dirs(self):
- return scmutil.dirs(self._manifest)
-
- def dirs(self):
- return self._dirs
-
- def dirty(self):
- return False
-
-class filectx(object):
- """A filecontext object makes access to data related to a particular
- filerevision convenient."""
- def __init__(self, repo, path, changeid=None, fileid=None,
- filelog=None, changectx=None):
- """changeid can be a changeset revision, node, or tag.
- fileid can be a file revision or node."""
- self._repo = repo
- self._path = path
-
- assert (changeid is not None
- or fileid is not None
- or changectx is not None), \
- ("bad args: changeid=%r, fileid=%r, changectx=%r"
- % (changeid, fileid, changectx))
-
- if filelog is not None:
- self._filelog = filelog
-
- if changeid is not None:
- self._changeid = changeid
- if changectx is not None:
- self._changectx = changectx
- if fileid is not None:
- self._fileid = fileid
-
- @propertycache
- def _changectx(self):
- try:
- return changectx(self._repo, self._changeid)
- except error.RepoLookupError:
- # Linkrev may point to any revision in the repository. When the
- # repository is filtered this may lead to `filectx` trying to build
- # `changectx` for filtered revision. In such case we fallback to
- # creating `changectx` on the unfiltered version of the reposition.
- # This fallback should not be an issue because `changectx` from
- # `filectx` are not used in complex operations that care about
- # filtering.
- #
- # This fallback is a cheap and dirty fix that prevent several
- # crashes. It does not ensure the behavior is correct. However the
- # behavior was not correct before filtering either and "incorrect
- # behavior" is seen as better as "crash"
- #
- # Linkrevs have several serious troubles with filtering that are
- # complicated to solve. Proper handling of the issue here should be
- # considered when solving linkrev issue are on the table.
- return changectx(self._repo.unfiltered(), self._changeid)
+class basefilectx(object):
+ """A filecontext object represents the common logic for its children:
+ filectx: read-only access to a filerevision that is already present
+ in the repo,
+ workingfilectx: a filecontext that represents files from the working
+ directory,
+ memfilectx: a filecontext that represents files in-memory."""
+ def __new__(cls, repo, path, *args, **kwargs):
+ return super(basefilectx, cls).__new__(cls)
@propertycache
def _filelog(self):
@@ -468,10 +456,10 @@
return False
def __str__(self):
- return "%s@%s" % (self.path(), short(self.node()))
+ return "%s@%s" % (self.path(), self._changectx)
def __repr__(self):
- return "<filectx %s>" % str(self)
+ return "<%s %s>" % (type(self).__name__, str(self))
def __hash__(self):
try:
@@ -481,7 +469,7 @@
def __eq__(self, other):
try:
- return (self._path == other._path
+ return (type(self) == type(other) and self._path == other._path
and self._filenode == other._filenode)
except AttributeError:
return False
@@ -489,12 +477,6 @@
def __ne__(self, other):
return not (self == other)
- def filectx(self, fileid):
- '''opens an arbitrary revision of the file without
- opening a new filelog'''
- return filectx(self._repo, self._path, fileid=fileid,
- filelog=self._filelog)
-
def filerev(self):
return self._filerev
def filenode(self):
@@ -510,7 +492,7 @@
def node(self):
return self._changectx.node()
def hex(self):
- return hex(self.node())
+ return self._changectx.hex()
def user(self):
return self._changectx.user()
def date(self):
@@ -532,12 +514,8 @@
def changectx(self):
return self._changectx
- def data(self):
- return self._filelog.read(self._filenode)
def path(self):
return self._path
- def size(self):
- return self._filelog.size(self._filerev)
def isbinary(self):
try:
@@ -560,31 +538,6 @@
return True
- def renamed(self):
- """check if file was actually renamed in this changeset revision
-
- If rename logged in file revision, we report copy for changeset only
- if file revisions linkrev points back to the changeset in question
- or both changeset parents contain different file revisions.
- """
-
- renamed = self._filelog.renamed(self._filenode)
- if not renamed:
- return renamed
-
- if self.rev() == self.linkrev():
- return renamed
-
- name = self.path()
- fnode = self._filenode
- for p in self._changectx.parents():
- try:
- if fnode == p.filenode(name):
- return None
- except error.LookupError:
- pass
- return renamed
-
def parents(self):
p = self._path
fl = self._filelog
@@ -606,12 +559,6 @@
return p[1]
return filectx(self._repo, self._path, fileid=-1, filelog=self._filelog)
- def children(self):
- # hard for renames
- c = self._filelog.children(self._filenode)
- return [filectx(self._repo, self._path, fileid=x,
- filelog=self._filelog) for x in c]
-
def annotate(self, follow=False, linenumber=None, diffopts=None):
'''returns a list of tuples of (ctx, line) for each line
in the file, where ctx is the filectx of the node where
@@ -783,15 +730,100 @@
self._copycache[sc2] = copies.pathcopies(c2)
return self._copycache[sc2]
-class workingctx(changectx):
- """A workingctx object makes access to data related to
- the current working directory convenient.
- date - any valid date string or (unixtime, offset), or None.
- user - username string, or None.
- extra - a dictionary of extra values, or None.
- changes - a list of file lists as returned by localrepo.status()
- or None to use the repository status.
- """
+class filectx(basefilectx):
+ """A filecontext object makes access to data related to a particular
+ filerevision convenient."""
+ def __init__(self, repo, path, changeid=None, fileid=None,
+ filelog=None, changectx=None):
+ """changeid can be a changeset revision, node, or tag.
+ fileid can be a file revision or node."""
+ self._repo = repo
+ self._path = path
+
+ assert (changeid is not None
+ or fileid is not None
+ or changectx is not None), \
+ ("bad args: changeid=%r, fileid=%r, changectx=%r"
+ % (changeid, fileid, changectx))
+
+ if filelog is not None:
+ self._filelog = filelog
+
+ if changeid is not None:
+ self._changeid = changeid
+ if changectx is not None:
+ self._changectx = changectx
+ if fileid is not None:
+ self._fileid = fileid
+
+ @propertycache
+ def _changectx(self):
+ try:
+ return changectx(self._repo, self._changeid)
+ except error.RepoLookupError:
+ # Linkrev may point to any revision in the repository. When the
+ # repository is filtered this may lead to `filectx` trying to build
+ # `changectx` for filtered revision. In such case we fallback to
+ # creating `changectx` on the unfiltered version of the reposition.
+ # This fallback should not be an issue because `changectx` from
+ # `filectx` are not used in complex operations that care about
+ # filtering.
+ #
+ # This fallback is a cheap and dirty fix that prevent several
+ # crashes. It does not ensure the behavior is correct. However the
+ # behavior was not correct before filtering either and "incorrect
+ # behavior" is seen as better as "crash"
+ #
+ # Linkrevs have several serious troubles with filtering that are
+ # complicated to solve. Proper handling of the issue here should be
+ # considered when solving linkrev issue are on the table.
+ return changectx(self._repo.unfiltered(), self._changeid)
+
+ def filectx(self, fileid):
+ '''opens an arbitrary revision of the file without
+ opening a new filelog'''
+ return filectx(self._repo, self._path, fileid=fileid,
+ filelog=self._filelog)
+
+ def data(self):
+ return self._filelog.read(self._filenode)
+ def size(self):
+ return self._filelog.size(self._filerev)
+
+ def renamed(self):
+ """check if file was actually renamed in this changeset revision
+
+ If rename logged in file revision, we report copy for changeset only
+ if file revisions linkrev points back to the changeset in question
+ or both changeset parents contain different file revisions.
+ """
+
+ renamed = self._filelog.renamed(self._filenode)
+ if not renamed:
+ return renamed
+
+ if self.rev() == self.linkrev():
+ return renamed
+
+ name = self.path()
+ fnode = self._filenode
+ for p in self._changectx.parents():
+ try:
+ if fnode == p.filenode(name):
+ return None
+ except error.LookupError:
+ pass
+ return renamed
+
+ def children(self):
+ # hard for renames
+ c = self._filelog.children(self._filenode)
+ return [filectx(self._repo, self._path, fileid=x,
+ filelog=self._filelog) for x in c]
+
+class committablectx(basectx):
+ """A committablectx object provides common functionality for a context that
+ wants the ability to commit, e.g. workingctx or memctx."""
def __init__(self, repo, text="", user=None, date=None, extra=None,
changes=None):
self._repo = repo
@@ -827,9 +859,6 @@
def __str__(self):
return str(self._parents[0]) + "+"
- def __repr__(self):
- return "<workingctx %s>" % str(self)
-
def __nonzero__(self):
return True
@@ -904,12 +933,6 @@
return man
- def __iter__(self):
- d = self._repo.dirstate
- for f in d:
- if d[f] != 'r':
- yield f
-
@propertycache
def _status(self):
return self._repo.status()[:4]
@@ -922,13 +945,6 @@
def _date(self):
return util.makedate()
- @propertycache
- def _parents(self):
- p = self._repo.dirstate.parents()
- if p[1] == nullid:
- p = p[:-1]
- return [changectx(self._repo, x) for x in p]
-
def status(self, ignored=False, clean=False, unknown=False):
"""Explicit status query
Unless this method is used to query the working copy status, the
@@ -945,8 +961,6 @@
self._status = stat[:4]
return stat
- def manifest(self):
- return self._manifest
def user(self):
return self._user or self._repo.ui.username()
def date(self):
@@ -1016,11 +1030,6 @@
except OSError:
return ''
- def filectx(self, path, filelog=None):
- """get a file context from the working directory"""
- return workingfilectx(self._repo, path, workingctx=self,
- filelog=filelog)
-
def ancestor(self, c2):
"""return the ancestor context of self and c2"""
return self._parents[0].ancestor(c2) # punt on two parents for now
@@ -1029,6 +1038,61 @@
return sorted(self._repo.dirstate.walk(match, sorted(self.substate),
True, False))
+ def ancestors(self):
+ for a in self._repo.changelog.ancestors(
+ [p.rev() for p in self._parents]):
+ yield changectx(self._repo, a)
+
+ def markcommitted(self, node):
+ """Perform post-commit cleanup necessary after committing this ctx
+
+ Specifically, this updates backing stores this working context
+ wraps to reflect the fact that the changes reflected by this
+ workingctx have been committed. For example, it marks
+ modified and added files as normal in the dirstate.
+
+ """
+
+ for f in self.modified() + self.added():
+ self._repo.dirstate.normal(f)
+ for f in self.removed():
+ self._repo.dirstate.drop(f)
+ self._repo.dirstate.setparents(node)
+
+ def dirs(self):
+ return self._repo.dirstate.dirs()
+
+class workingctx(committablectx):
+ """A workingctx object makes access to data related to
+ the current working directory convenient.
+ date - any valid date string or (unixtime, offset), or None.
+ user - username string, or None.
+ extra - a dictionary of extra values, or None.
+ changes - a list of file lists as returned by localrepo.status()
+ or None to use the repository status.
+ """
+ def __init__(self, repo, text="", user=None, date=None, extra=None,
+ changes=None):
+ super(workingctx, self).__init__(repo, text, user, date, extra, changes)
+
+ def __iter__(self):
+ d = self._repo.dirstate
+ for f in d:
+ if d[f] != 'r':
+ yield f
+
+ @propertycache
+ def _parents(self):
+ p = self._repo.dirstate.parents()
+ if p[1] == nullid:
+ p = p[:-1]
+ return [changectx(self._repo, x) for x in p]
+
+ def filectx(self, path, filelog=None):
+ """get a file context from the working directory"""
+ return workingfilectx(self._repo, path, workingctx=self,
+ filelog=filelog)
+
def dirty(self, missing=False, merge=True, branch=True):
"check whether a working directory is modified"
# check subrepos first
@@ -1093,11 +1157,6 @@
finally:
wlock.release()
- def ancestors(self):
- for a in self._repo.changelog.ancestors(
- [p.rev() for p in self._parents]):
- yield changectx(self._repo, a)
-
def undelete(self, list):
pctxs = self.parents()
wlock = self._repo.wlock()
@@ -1129,31 +1188,10 @@
finally:
wlock.release()
- def markcommitted(self, node):
- """Perform post-commit cleanup necessary after committing this ctx
-
- Specifically, this updates backing stores this working context
- wraps to reflect the fact that the changes reflected by this
- workingctx have been committed. For example, it marks
- modified and added files as normal in the dirstate.
-
- """
-
- for f in self.modified() + self.added():
- self._repo.dirstate.normal(f)
- for f in self.removed():
- self._repo.dirstate.drop(f)
- self._repo.dirstate.setparents(node)
-
- def dirs(self):
- return self._repo.dirstate.dirs()
-
-class workingfilectx(filectx):
- """A workingfilectx object makes access to data related to a particular
- file in the working directory convenient."""
- def __init__(self, repo, path, filelog=None, workingctx=None):
- """changeid can be a changeset revision, node, or tag.
- fileid can be a file revision or node."""
+class committablefilectx(basefilectx):
+ """A committablefilectx provides common functionality for a file context
+ that wants the ability to commit, e.g. workingfilectx or memfilectx."""
+ def __init__(self, repo, path, filelog=None, ctx=None):
self._repo = repo
self._path = path
self._changeid = None
@@ -1161,30 +1199,12 @@
if filelog is not None:
self._filelog = filelog
- if workingctx:
- self._changectx = workingctx
-
- @propertycache
- def _changectx(self):
- return workingctx(self._repo)
+ if ctx:
+ self._changectx = ctx
def __nonzero__(self):
return True
- def __str__(self):
- return "%s@%s" % (self.path(), self._changectx)
-
- def __repr__(self):
- return "<workingfilectx %s>" % str(self)
-
- def data(self):
- return self._repo.wread(self._path)
- def renamed(self):
- rp = self._repo.dirstate.copied(self._path)
- if not rp:
- return None
- return rp, self._changectx._parents[0]._manifest.get(rp, nullid)
-
def parents(self):
'''return parent filectxs, following copies if necessary'''
def filenode(ctx, path):
@@ -1209,6 +1229,24 @@
def children(self):
return []
+class workingfilectx(committablefilectx):
+ """A workingfilectx object makes access to data related to a particular
+ file in the working directory convenient."""
+ def __init__(self, repo, path, filelog=None, workingctx=None):
+ super(workingfilectx, self).__init__(repo, path, filelog, workingctx)
+
+ @propertycache
+ def _changectx(self):
+ return workingctx(self._repo)
+
+ def data(self):
+ return self._repo.wread(self._path)
+ def renamed(self):
+ rp = self._repo.dirstate.copied(self._path)
+ if not rp:
+ return None
+ return rp, self._changectx._parents[0]._manifest.get(rp, nullid)
+
def size(self):
return os.lstat(self._repo.wjoin(self._path)).st_size
def date(self):
--- a/mercurial/dirstate.py Sat Sep 07 15:07:10 2013 -0500
+++ b/mercurial/dirstate.py Fri Sep 20 11:47:03 2013 -0500
@@ -801,12 +801,9 @@
mexact = match.exact
dirignore = self._dirignore
checkexec = self._checkexec
- checklink = self._checklink
copymap = self._copymap
lastnormaltime = self._lastnormaltime
- lnkkind = stat.S_IFLNK
-
# We need to do full walks when either
# - we're listing all clean files, or
# - match.traversedir does something, because match.traversedir should
@@ -827,20 +824,14 @@
if not st and state in "nma":
dadd(fn)
elif state == 'n':
- # The "mode & lnkkind != lnkkind or self._checklink"
- # lines are an expansion of "islink => checklink"
- # where islink means "is this a link?" and checklink
- # means "can we check links?".
mtime = int(st.st_mtime)
if (size >= 0 and
((size != st.st_size and size != st.st_size & _rangemask)
or ((mode ^ st.st_mode) & 0100 and checkexec))
- and (mode & lnkkind != lnkkind or checklink)
or size == -2 # other parent
or fn in copymap):
madd(fn)
- elif ((time != mtime and time != mtime & _rangemask)
- and (mode & lnkkind != lnkkind or checklink)):
+ elif time != mtime and time != mtime & _rangemask:
ladd(fn)
elif mtime == lastnormaltime:
# fn may have been changed in the same timeslot without
--- a/mercurial/dispatch.py Sat Sep 07 15:07:10 2013 -0500
+++ b/mercurial/dispatch.py Fri Sep 20 11:47:03 2013 -0500
@@ -88,11 +88,47 @@
try:
try:
+ debugger = 'pdb'
+ debugtrace = {
+ 'pdb' : pdb.set_trace
+ }
+ debugmortem = {
+ 'pdb' : pdb.post_mortem
+ }
+
+ # read --config before doing anything else
+ # (e.g. to change trust settings for reading .hg/hgrc)
+ cfgs = _parseconfig(req.ui, _earlygetopt(['--config'], req.args))
+
+ if req.repo:
+ # copy configs that were passed on the cmdline (--config) to
+ # the repo ui
+ for cfg in cfgs:
+ req.repo.ui.setconfig(*cfg)
+
+ debugger = ui.config("ui", "debugger")
+ if not debugger:
+ debugger = 'pdb'
+
+ try:
+ debugmod = __import__(debugger)
+ except ImportError:
+ debugmod = pdb
+
+ debugtrace[debugger] = debugmod.set_trace
+ debugmortem[debugger] = debugmod.post_mortem
+
# enter the debugger before command execution
if '--debugger' in req.args:
ui.warn(_("entering debugger - "
"type c to continue starting hg or h for help\n"))
- pdb.set_trace()
+
+ if (debugger != 'pdb' and
+ debugtrace[debugger] == debugtrace['pdb']):
+ ui.warn(_("%s debugger specified "
+ "but its module was not found\n") % debugger)
+
+ debugtrace[debugger]()
try:
return _dispatch(req)
finally:
@@ -101,7 +137,7 @@
# enter the debugger when we hit an exception
if '--debugger' in req.args:
traceback.print_exc()
- pdb.post_mortem(sys.exc_info()[2])
+ debugmortem[debugger](sys.exc_info()[2])
ui.traceback()
raise
@@ -619,10 +655,6 @@
args = req.args
ui = req.ui
- # read --config before doing anything else
- # (e.g. to change trust settings for reading .hg/hgrc)
- cfgs = _parseconfig(ui, _earlygetopt(['--config'], args))
-
# check for cwd
cwd = _earlygetopt(['--cwd'], args)
if cwd:
@@ -699,10 +731,6 @@
if req.repo:
uis.add(req.repo.ui)
- # copy configs that were passed on the cmdline (--config) to the repo ui
- for cfg in cfgs:
- req.repo.ui.setconfig(*cfg)
-
if options['verbose'] or options['debug'] or options['quiet']:
for opt in ('verbose', 'debug', 'quiet'):
val = str(bool(options[opt]))
--- a/mercurial/hgweb/webcommands.py Sat Sep 07 15:07:10 2013 -0500
+++ b/mercurial/hgweb/webcommands.py Fri Sep 20 11:47:03 2013 -0500
@@ -9,13 +9,15 @@
import webutil
from mercurial import error, encoding, archival, templater, templatefilters
from mercurial.node import short, hex, nullid
-from mercurial.util import binary
+from mercurial import util
from common import paritygen, staticfile, get_contact, ErrorResponse
from common import HTTP_OK, HTTP_FORBIDDEN, HTTP_NOT_FOUND
from mercurial import graphmod, patch
from mercurial import help as helpmod
from mercurial import scmutil
from mercurial.i18n import _
+from mercurial.error import ParseError, RepoLookupError, Abort
+from mercurial import revset
# __all__ is populated with the allowed commands. Be sure to add to it if
# you're adding a new command, or the new command won't work.
@@ -57,7 +59,7 @@
if guessmime:
mt = mimetypes.guess_type(path)[0]
if mt is None:
- mt = binary(text) and 'application/binary' or 'text/plain'
+ mt = util.binary(text) and 'application/binary' or 'text/plain'
if mt.startswith('text/'):
mt += '; charset="%s"' % encoding.encoding
@@ -69,7 +71,7 @@
text = fctx.data()
parity = paritygen(web.stripecount)
- if binary(text):
+ if util.binary(text):
mt = mimetypes.guess_type(f)[0] or 'application/octet-stream'
text = '(binary:%s)' % mt
@@ -109,9 +111,14 @@
raise inst
def _search(web, req, tmpl):
+ MODE_REVISION = 'rev'
+ MODE_KEYWORD = 'keyword'
+ MODE_REVSET = 'revset'
- def changelist(**map):
- count = 0
+ def revsearch(ctx):
+ yield ctx
+
+ def keywordsearch(query):
lower = encoding.lower
qw = lower(query).split()
@@ -137,6 +144,62 @@
if miss:
continue
+ yield ctx
+
+ def revsetsearch(revs):
+ for r in revs:
+ yield web.repo[r]
+
+ searchfuncs = {
+ MODE_REVISION: revsearch,
+ MODE_KEYWORD: keywordsearch,
+ MODE_REVSET: revsetsearch,
+ }
+
+ def getsearchmode(query):
+ try:
+ ctx = web.repo[query]
+ except (error.RepoError, error.LookupError):
+ # query is not an exact revision pointer, need to
+ # decide if it's a revset expession or keywords
+ pass
+ else:
+ return MODE_REVISION, ctx
+
+ revdef = 'reverse(%s)' % query
+ try:
+ tree, pos = revset.parse(revdef)
+ except ParseError:
+ # can't parse to a revset tree
+ return MODE_KEYWORD, query
+
+ if revset.depth(tree) <= 2:
+ # no revset syntax used
+ return MODE_KEYWORD, query
+
+ if util.any((token, (value or '')[:3]) == ('string', 're:')
+ for token, value, pos in revset.tokenize(revdef)):
+ return MODE_KEYWORD, query
+
+ funcsused = revset.funcsused(tree)
+ if not funcsused.issubset(revset.safesymbols):
+ return MODE_KEYWORD, query
+
+ mfunc = revset.match(web.repo.ui, revdef)
+ try:
+ revs = mfunc(web.repo, list(web.repo))
+ return MODE_REVSET, revs
+ # ParseError: wrongly placed tokens, wrongs arguments, etc
+ # RepoLookupError: no such revision, e.g. in 'revision:'
+ # Abort: bookmark/tag not exists
+ # LookupError: ambiguous identifier, e.g. in '(bc)' on a large repo
+ except (ParseError, RepoLookupError, Abort, LookupError):
+ return MODE_KEYWORD, query
+
+ def changelist(**map):
+ count = 0
+
+ for ctx in searchfunc(funcarg):
count += 1
n = ctx.node()
showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
@@ -176,6 +239,9 @@
morevars['revcount'] = revcount * 2
morevars['rev'] = query
+ mode, funcarg = getsearchmode(query)
+ searchfunc = searchfuncs[mode]
+
tip = web.repo['tip']
parity = paritygen(web.stripecount)
@@ -188,23 +254,15 @@
query = ''
if 'node' in req.form:
ctx = webutil.changectx(web.repo, req)
+ elif 'rev' in req.form:
+ return _search(web, req, tmpl)
else:
- if 'rev' in req.form:
- query = req.form['rev'][0]
- hi = query
- else:
- hi = 'tip'
- try:
- ctx = web.repo[hi]
- except (error.RepoError, error.LookupError):
- return _search(web, req, tmpl) # XXX redirect to 404 page?
+ ctx = web.repo['tip']
- def changelist(latestonly, **map):
+ def changelist():
revs = []
if pos != -1:
revs = web.repo.changelog.revs(pos, 0)
- if latestonly:
- revs = (revs.next(),)
curcount = 0
for i in revs:
ctx = web.repo[i]
@@ -213,7 +271,7 @@
files = webutil.listfilediffs(tmpl, ctx.files(), n, web.maxfiles)
curcount += 1
- if curcount > revcount:
+ if curcount > revcount + 1:
break
yield {"parity": parity.next(),
"author": ctx.user(),
@@ -249,10 +307,18 @@
changenav = webutil.revnav(web.repo).gen(pos, revcount, count)
+ entries = list(changelist())
+ latestentry = entries[:1]
+ if len(entries) > revcount:
+ nextentry = entries[-1:]
+ entries = entries[:-1]
+ else:
+ nextentry = []
+
return tmpl(shortlog and 'shortlog' or 'changelog', changenav=changenav,
node=ctx.hex(), rev=pos, changesets=count,
- entries=lambda **x: changelist(latestonly=False, **x),
- latestentry=lambda **x: changelist(latestonly=True, **x),
+ entries=entries,
+ latestentry=latestentry, nextentry=nextentry,
archives=web.archivelist("tip"), revcount=revcount,
morevars=morevars, lessvars=lessvars, query=query)
@@ -617,7 +683,7 @@
context = parsecontext(web.config('web', 'comparisoncontext', '5'))
def filelines(f):
- if binary(f.data()):
+ if util.binary(f.data()):
mt = mimetypes.guess_type(f.path())[0]
if not mt:
mt = 'application/octet-stream'
@@ -675,7 +741,7 @@
def annotate(**map):
last = None
- if binary(fctx.data()):
+ if util.binary(fctx.data()):
mt = (mimetypes.guess_type(fctx.path())[0]
or 'application/octet-stream')
lines = enumerate([((fctx.filectx(fctx.filerev()), 1),
--- a/mercurial/httpclient/__init__.py Sat Sep 07 15:07:10 2013 -0500
+++ b/mercurial/httpclient/__init__.py Fri Sep 20 11:47:03 2013 -0500
@@ -495,6 +495,10 @@
else:
raise BadRequestData('body has no __len__() nor read()')
+ # If we're reusing the underlying socket, there are some
+ # conditions where we'll want to retry, so make a note of the
+ # state of self.sock
+ fresh_socket = self.sock is None
self._connect()
outgoing_headers = self._buildheaders(
method, path, hdrs, self.http_version)
@@ -640,6 +644,26 @@
# the whole request
if response is None:
response = self.response_class(self.sock, self.timeout, method)
+ if not fresh_socket:
+ if not response._select():
+ # This means the response failed to get any response
+ # data at all, and in all probability the socket was
+ # closed before the server even saw our request. Try
+ # the request again on a fresh socket.
+ logging.debug('response._select() failed during request().'
+ ' Assuming request needs to be retried.')
+ self.sock = None
+ # Call this method explicitly to re-try the
+ # request. We don't use self.request() because
+ # some tools (notably Mercurial) expect to be able
+ # to subclass and redefine request(), and they
+ # don't have the same argspec as we do.
+ #
+ # TODO restructure sending of requests to avoid
+ # this recursion
+ return HTTPConnection.request(
+ self, method, path, body=body, headers=headers,
+ expect_continue=expect_continue)
data_left = bool(outgoing_headers or body)
if data_left:
logger.info('stopped sending request early, '
--- a/mercurial/localrepo.py Sat Sep 07 15:07:10 2013 -0500
+++ b/mercurial/localrepo.py Fri Sep 20 11:47:03 2013 -0500
@@ -39,6 +39,8 @@
"""propertycache that apply to unfiltered repo only"""
def __get__(self, repo, type=None):
+ if hasunfilteredcache(repo, self.name):
+ return getattr(repo.unfiltered(), self.name)
return super(unfilteredpropertycache, self).__get__(repo.unfiltered())
class filteredpropertycache(propertycache):
@@ -1457,14 +1459,8 @@
del mf[fn]
return mf
- if isinstance(node1, context.changectx):
- ctx1 = node1
- else:
- ctx1 = self[node1]
- if isinstance(node2, context.changectx):
- ctx2 = node2
- else:
- ctx2 = self[node2]
+ ctx1 = self[node1]
+ ctx2 = self[node2]
working = ctx2.rev() is None
parentworking = working and ctx1 == self['.']
@@ -1561,7 +1557,7 @@
for f in modified:
if ctx2.flags(f) == 'l':
d = ctx2[f].data()
- if len(d) >= 1024 or '\n' in d or util.binary(d):
+ if d == '' or len(d) >= 1024 or '\n' in d or util.binary(d):
self.ui.debug('ignoring suspect symlink placeholder'
' "%s"\n' % f)
continue
--- a/mercurial/obsolete.py Sat Sep 07 15:07:10 2013 -0500
+++ b/mercurial/obsolete.py Fri Sep 20 11:47:03 2013 -0500
@@ -371,7 +371,7 @@
lock.release()
def syncpush(repo, remote):
- """utility function to push bookmark to a remote
+ """utility function to push obsolete markers to a remote
Exist mostly to allow overridding for experimentation purpose"""
if (_enabled and repo.obsstore and
@@ -387,7 +387,7 @@
repo.ui.warn(msg)
def syncpull(repo, remote, gettransaction):
- """utility function to pull bookmark to a remote
+ """utility function to pull obsolete markers from a remote
The `gettransaction` is function that return the pull transaction, creating
one if necessary. We return the transaction to inform the calling code that
--- a/mercurial/parsers.c Sat Sep 07 15:07:10 2013 -0500
+++ b/mercurial/parsers.c Fri Sep 20 11:47:03 2013 -0500
@@ -14,16 +14,32 @@
#include "util.h"
+static int8_t hextable[256] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0-9 */
+ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* A-F */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a-f */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+};
+
static inline int hexdigit(const char *p, Py_ssize_t off)
{
- char c = p[off];
+ int8_t val = hextable[(unsigned char)p[off]];
- if (c >= '0' && c <= '9')
- return c - '0';
- if (c >= 'a' && c <= 'f')
- return c - 'a' + 10;
- if (c >= 'A' && c <= 'F')
- return c - 'A' + 10;
+ if (val >= 0) {
+ return val;
+ }
PyErr_SetString(PyExc_ValueError, "input contains non-hex character");
return 0;
@@ -61,7 +77,7 @@
static PyObject *parse_manifest(PyObject *self, PyObject *args)
{
PyObject *mfdict, *fdict;
- char *str, *cur, *start, *zero;
+ char *str, *start, *end;
int len;
if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest",
@@ -70,30 +86,34 @@
&str, &len))
goto quit;
- for (start = cur = str, zero = NULL; cur < str + len; cur++) {
+ start = str;
+ end = str + len;
+ while (start < end) {
PyObject *file = NULL, *node = NULL;
PyObject *flags = NULL;
+ char *zero = NULL, *newline = NULL;
ptrdiff_t nlen;
- if (!*cur) {
- zero = cur;
- continue;
- }
- else if (*cur != '\n')
- continue;
-
+ zero = memchr(start, '\0', end - start);
if (!zero) {
PyErr_SetString(PyExc_ValueError,
"manifest entry has no separator");
goto quit;
}
+ newline = memchr(zero + 1, '\n', end - (zero + 1));
+ if (!newline) {
+ PyErr_SetString(PyExc_ValueError,
+ "manifest contains trailing garbage");
+ goto quit;
+ }
+
file = PyBytes_FromStringAndSize(start, zero - start);
if (!file)
goto bail;
- nlen = cur - zero - 1;
+ nlen = newline - zero - 1;
node = unhexlify(zero + 1, nlen > 40 ? 40 : (int)nlen);
if (!node)
@@ -112,8 +132,7 @@
if (PyDict_SetItem(mfdict, file, node) == -1)
goto bail;
- start = cur + 1;
- zero = NULL;
+ start = newline + 1;
Py_XDECREF(flags);
Py_XDECREF(node);
@@ -126,12 +145,6 @@
goto quit;
}
- if (len > 0 && *(cur - 1) != '\n') {
- PyErr_SetString(PyExc_ValueError,
- "manifest contains trailing garbage");
- goto quit;
- }
-
Py_INCREF(Py_None);
return Py_None;
quit:
@@ -142,8 +155,8 @@
{
PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
PyObject *fname = NULL, *cname = NULL, *entry = NULL;
- char *str, *cur, *end, *cpos;
- int state, mode, size, mtime;
+ char state, *str, *cur, *end, *cpos;
+ int mode, size, mtime;
unsigned int flen;
int len;
@@ -330,7 +343,7 @@
* this. */
if (PyDict_SetItem(map, k, dirstate_unset) == -1)
goto bail;
- mode = 0, size = -1, mtime = -1;
+ mtime = -1;
}
putbe32(mode, p);
putbe32(size, p + 4);
@@ -524,11 +537,12 @@
uncomp_len, base_rev, link_rev,
parent_1, parent_2, c_node_id, 20);
- if (entry)
+ if (entry) {
PyObject_GC_UnTrack(entry);
+ Py_INCREF(entry);
+ }
self->cache[pos] = entry;
- Py_INCREF(entry);
return entry;
}
@@ -1195,14 +1209,19 @@
long sp;
bitmask *seen;
+ if (gca == NULL)
+ return PyErr_NoMemory();
+
for (i = 0; i < revcount; i++) {
if (revs[i] > maxrev)
maxrev = revs[i];
}
seen = calloc(sizeof(*seen), maxrev + 1);
- if (seen == NULL)
+ if (seen == NULL) {
+ Py_DECREF(gca);
return PyErr_NoMemory();
+ }
for (i = 0; i < revcount; i++)
seen[revs[i]] = 1ull << i;
--- a/mercurial/pure/parsers.py Sat Sep 07 15:07:10 2013 -0500
+++ b/mercurial/pure/parsers.py Fri Sep 20 11:47:03 2013 -0500
@@ -100,11 +100,11 @@
# systems with a granularity of 1 sec). This commonly happens
# for at least a couple of files on 'update'.
# The user could change the file without changing its size
- # within the same second. Invalidate the file's stat data in
+ # within the same second. Invalidate the file's mtime in
# dirstate, forcing future 'status' calls to compare the
- # contents of the file. This prevents mistakenly treating such
- # files as clean.
- e = (e[0], 0, -1, -1) # mark entry as 'unset'
+ # contents of the file if the size is the same. This prevents
+ # mistakenly treating such files as clean.
+ e = (e[0], e[1], e[2], -1)
dmap[f] = e
if f in copymap:
--- a/mercurial/revlog.py Sat Sep 07 15:07:10 2013 -0500
+++ b/mercurial/revlog.py Fri Sep 20 11:47:03 2013 -0500
@@ -14,7 +14,7 @@
# import stuff from node for others to import from revlog
from node import bin, hex, nullid, nullrev
from i18n import _
-import ancestor, mdiff, parsers, error, util
+import ancestor, mdiff, parsers, error, util, templatefilters
import struct, zlib, errno
_pack = struct.pack
@@ -845,16 +845,43 @@
def _chunkraw(self, startrev, endrev):
start = self.start(startrev)
- length = self.end(endrev) - start
+ end = self.end(endrev)
if self._inline:
start += (startrev + 1) * self._io.size
+ end += (endrev + 1) * self._io.size
+ length = end - start
return self._getchunk(start, length)
def _chunk(self, rev):
return decompress(self._chunkraw(rev, rev))
- def _chunkbase(self, rev):
- return self._chunk(rev)
+ def _chunks(self, revs):
+ '''faster version of [self._chunk(rev) for rev in revs]
+
+ Assumes that revs is in ascending order.'''
+ if not revs:
+ return []
+ start = self.start
+ length = self.length
+ inline = self._inline
+ iosize = self._io.size
+ buffer = util.buffer
+
+ l = []
+ ladd = l.append
+
+ # preload the cache
+ self._chunkraw(revs[0], revs[-1])
+ offset, data = self._chunkcache
+
+ for rev in revs:
+ chunkstart = start(rev)
+ if inline:
+ chunkstart += (rev + 1) * iosize
+ chunklength = length(rev)
+ ladd(decompress(buffer(data, chunkstart - offset, chunklength)))
+
+ return l
def _chunkclear(self):
self._chunkcache = (0, '')
@@ -919,21 +946,22 @@
else:
iterrev -= 1
e = index[iterrev]
- chain.reverse()
- base = iterrev
if iterrev == cachedrev:
# cache hit
text = self._cache[2]
+ else:
+ chain.append(iterrev)
+ chain.reverse()
# drop cache to save memory
self._cache = None
- self._chunkraw(base, rev)
+ bins = self._chunks(chain)
if text is None:
- text = str(self._chunkbase(base))
+ text = str(bins[0])
+ bins = bins[1:]
- bins = [self._chunk(r) for r in chain]
text = mdiff.patches(text, bins)
text = self._checkhash(text, node, rev)
@@ -943,10 +971,16 @@
def _checkhash(self, text, node, rev):
p1, p2 = self.parents(node)
+ self.checkhash(text, p1, p2, node, rev)
+ return text
+
+ def checkhash(self, text, p1, p2, node, rev=None):
if node != hash(text, p1, p2):
- raise RevlogError(_("integrity check failed on %s:%d")
- % (self.indexfile, rev))
- return text
+ revornode = rev
+ if revornode is None:
+ revornode = templatefilters.short(hex(node))
+ raise RevlogError(_("integrity check failed on %s:%s")
+ % (self.indexfile, revornode))
def checkinlinesize(self, tr, fp=None):
if not self._inline or (self.start(-2) + self.length(-2)) < _maxinline:
@@ -987,7 +1021,8 @@
tr.replace(self.indexfile, trindex * self._io.size)
self._chunkclear()
- def addrevision(self, text, transaction, link, p1, p2, cachedelta=None):
+ def addrevision(self, text, transaction, link, p1, p2, cachedelta=None,
+ node=None):
"""add a revision to the log
text - the revision data to add
@@ -995,11 +1030,14 @@
link - the linkrev data to add
p1, p2 - the parent nodeids of the revision
cachedelta - an optional precomputed delta
+ node - nodeid of revision; typically node is not specified, and it is
+ computed by default as hash(text, p1, p2), however subclasses might
+ use different hashing method (and override checkhash() in such case)
"""
if link == nullrev:
raise RevlogError(_("attempted to add linkrev -1 to %s")
% self.indexfile)
- node = hash(text, p1, p2)
+ node = node or hash(text, p1, p2)
if node in self.nodemap:
return node
@@ -1063,9 +1101,7 @@
ifh.flush()
basetext = self.revision(self.node(cachedelta[0]))
btext[0] = mdiff.patch(basetext, cachedelta[1])
- chk = hash(btext[0], p1, p2)
- if chk != node:
- raise RevlogError(_("consistency error in delta"))
+ self.checkhash(btext[0], p1, p2, node)
return btext[0]
def builddelta(rev):
--- a/mercurial/revset.py Sat Sep 07 15:07:10 2013 -0500
+++ b/mercurial/revset.py Fri Sep 20 11:47:03 2013 -0500
@@ -1599,6 +1599,75 @@
"_list": _list,
}
+# symbols which can't be used for a DoS attack for any given input
+# (e.g. those which accept regexes as plain strings shouldn't be included)
+# functions that just return a lot of changesets (like all) don't count here
+safesymbols = set([
+ "adds",
+ "all",
+ "ancestor",
+ "ancestors",
+ "_firstancestors",
+ "author",
+ "bisect",
+ "bisected",
+ "bookmark",
+ "branch",
+ "branchpoint",
+ "bumped",
+ "bundle",
+ "children",
+ "closed",
+ "converted",
+ "date",
+ "desc",
+ "descendants",
+ "_firstdescendants",
+ "destination",
+ "divergent",
+ "draft",
+ "extinct",
+ "extra",
+ "file",
+ "filelog",
+ "first",
+ "follow",
+ "_followfirst",
+ "head",
+ "heads",
+ "hidden",
+ "id",
+ "keyword",
+ "last",
+ "limit",
+ "_matchfiles",
+ "max",
+ "merge",
+ "min",
+ "modifies",
+ "obsolete",
+ "origin",
+ "outgoing",
+ "p1",
+ "p2",
+ "parents",
+ "present",
+ "public",
+ "remote",
+ "removes",
+ "rev",
+ "reverse",
+ "roots",
+ "sort",
+ "secret",
+ "matching",
+ "tag",
+ "tagged",
+ "user",
+ "unstable",
+ "_list",
+])
+
methods = {
"range": rangeset,
"dagrange": dagrange,
@@ -1935,5 +2004,22 @@
output = '\n'.join((' '*l + s) for l, s in lines)
return output
+def depth(tree):
+ if isinstance(tree, tuple):
+ return max(map(depth, tree)) + 1
+ else:
+ return 0
+
+def funcsused(tree):
+ if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'):
+ return set()
+ else:
+ funcs = set()
+ for s in tree[1:]:
+ funcs |= funcsused(s)
+ if tree[0] == 'func':
+ funcs.add(tree[1][1])
+ return funcs
+
# tell hggettext to extract docstrings from these functions:
i18nfunctions = symbols.values()
--- a/mercurial/scmutil.py Sat Sep 07 15:07:10 2013 -0500
+++ b/mercurial/scmutil.py Fri Sep 20 11:47:03 2013 -0500
@@ -755,7 +755,8 @@
ctx = repo[None]
dirstate = repo.dirstate
- walkresults = dirstate.walk(matcher, sorted(ctx.substate), True, False)
+ walkresults = dirstate.walk(matcher, sorted(ctx.substate), True, False,
+ full=False)
for abs, st in walkresults.iteritems():
dstate = dirstate[abs]
if dstate == '?' and audit_path.check(abs):
--- a/mercurial/subrepo.py Sat Sep 07 15:07:10 2013 -0500
+++ b/mercurial/subrepo.py Fri Sep 20 11:47:03 2013 -0500
@@ -237,6 +237,7 @@
# record merged .hgsubstate
writestate(repo, sm)
+ return sm
def _updateprompt(ui, sub, dirty, local, remote):
if dirty:
--- a/mercurial/templatefilters.py Sat Sep 07 15:07:10 2013 -0500
+++ b/mercurial/templatefilters.py Fri Sep 20 11:47:03 2013 -0500
@@ -15,15 +15,15 @@
"""
return text.replace('\n', '<br/>\n')
-agescales = [("year", 3600 * 24 * 365),
- ("month", 3600 * 24 * 30),
- ("week", 3600 * 24 * 7),
- ("day", 3600 * 24),
- ("hour", 3600),
- ("minute", 60),
- ("second", 1)]
+agescales = [("year", 3600 * 24 * 365, 'Y'),
+ ("month", 3600 * 24 * 30, 'M'),
+ ("week", 3600 * 24 * 7, 'W'),
+ ("day", 3600 * 24, 'd'),
+ ("hour", 3600, 'h'),
+ ("minute", 60, 'm'),
+ ("second", 1, 's')]
-def age(date):
+def age(date, abbrev=False):
""":age: Date. Returns a human-readable date/time difference between the
given date/time and the current date/time.
"""
@@ -32,7 +32,9 @@
if c == 1:
return t
return t + "s"
- def fmt(t, c):
+ def fmt(t, c, a):
+ if abbrev:
+ return "%d%s" % (c, a)
return "%d %s" % (c, plural(t, c))
now = time.time()
@@ -48,12 +50,12 @@
if delta > agescales[0][1] * 2:
return util.shortdate(date)
- for t, s in agescales:
+ for t, s, a in agescales:
n = delta // s
if n >= 2 or s == 1:
if future:
- return '%s from now' % fmt(t, n)
- return '%s ago' % fmt(t, n)
+ return '%s from now' % fmt(t, n, a)
+ return '%s ago' % fmt(t, n, a)
def basename(path):
""":basename: Any text. Treats the text as a path, and returns the last
--- a/mercurial/templates/paper/fileannotate.tmpl Sat Sep 07 15:07:10 2013 -0500
+++ b/mercurial/templates/paper/fileannotate.tmpl Fri Sep 20 11:47:03 2013 -0500
@@ -65,7 +65,6 @@
<th class="author">children</th>
<td class="author">{child%filerevchild}</td>
</tr>
-{changesettag}
</table>
<div class="overflow">
--- a/mercurial/templates/paper/filecomparison.tmpl Sat Sep 07 15:07:10 2013 -0500
+++ b/mercurial/templates/paper/filecomparison.tmpl Fri Sep 20 11:47:03 2013 -0500
@@ -64,7 +64,6 @@
<th>children</th>
<td>{child%filerevchild}</td>
</tr>
-{changesettag}
</table>
<div class="overflow">
--- a/mercurial/templates/paper/filediff.tmpl Sat Sep 07 15:07:10 2013 -0500
+++ b/mercurial/templates/paper/filediff.tmpl Fri Sep 20 11:47:03 2013 -0500
@@ -64,7 +64,6 @@
<th>children</th>
<td>{child%filerevchild}</td>
</tr>
-{changesettag}
</table>
<div class="overflow">
--- a/mercurial/templates/paper/filerevision.tmpl Sat Sep 07 15:07:10 2013 -0500
+++ b/mercurial/templates/paper/filerevision.tmpl Fri Sep 20 11:47:03 2013 -0500
@@ -63,7 +63,6 @@
<th class="author">children</th>
<td class="author">{child%filerevchild}</td>
</tr>
-{changesettag}
</table>
<div class="overflow">
--- a/mercurial/templates/paper/shortlog.tmpl Sat Sep 07 15:07:10 2013 -0500
+++ b/mercurial/templates/paper/shortlog.tmpl Fri Sep 20 11:47:03 2013 -0500
@@ -72,6 +72,18 @@
| rev {rev}: {changenav%navshort}
</div>
+<script type="text/javascript">
+ ajaxScrollInit(
+ '{url|urlescape}shortlog/%hash%',
+ '{nextentry%"{node}"}', <!-- NEXTHASH
+ /'(\w+)', <!-- NEXTHASH/,
+ '.bigtable > tbody:nth-of-type(2)',
+ '<tr class="%class%">\
+ <td colspan="3" style="text-align: center;">%text%</td>\
+ </tr>'
+ );
+</script>
+
</div>
</div>
--- a/mercurial/templates/paper/shortlogentry.tmpl Sat Sep 07 15:07:10 2013 -0500
+++ b/mercurial/templates/paper/shortlogentry.tmpl Fri Sep 20 11:47:03 2013 -0500
@@ -1,5 +1,5 @@
<tr>
<td class="age">{date|rfc822date}</td>
<td class="author">{author|person}</td>
- <td class="description"><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{desc|strip|firstline|escape|nonempty}</a>{inbranch%changelogbranchname}{branches%changelogbranchhead}{tags % '<span class="tag">{name|escape}</span> '}{bookmarks % '<span class="tag">{name|escape}</span> '}</td>
+ <td class="description"><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{desc|strip|firstline|escape|nonempty}</a>{inbranch%changelogbranchname}{branches%changelogbranchhead}{tags%changelogtag}{bookmarks%changelogtag}</td>
</tr>
--- a/mercurial/templates/static/mercurial.js Sat Sep 07 15:07:10 2013 -0500
+++ b/mercurial/templates/static/mercurial.js Fri Sep 20 11:47:03 2013 -0500
@@ -23,7 +23,7 @@
];
function Graph() {
-
+
this.canvas = document.getElementById('graph');
if (window.G_vmlCanvasManager) this.canvas = window.G_vmlCanvasManager.initElement(this.canvas);
this.ctx = this.canvas.getContext('2d');
@@ -35,13 +35,13 @@
this.cell = [2, 0];
this.columns = 0;
this.revlink = '';
-
+
this.scale = function(height) {
this.bg_height = height;
this.box_size = Math.floor(this.bg_height / 1.2);
this.cell_height = this.box_size;
}
-
+
function colorPart(num) {
num *= 255
num = num < 0 ? 0 : num;
@@ -55,7 +55,7 @@
}
this.setColor = function(color, bg, fg) {
-
+
// Set the colour.
//
// If color is a string, expect an hexadecimal RGB
@@ -81,11 +81,11 @@
this.ctx.strokeStyle = s;
this.ctx.fillStyle = s;
return s;
-
+
}
this.edge = function(x0, y0, x1, y1, color, width) {
-
+
this.setColor(color, 0.0, 0.65);
if(width >= 0)
this.ctx.lineWidth = width;
@@ -93,28 +93,28 @@
this.ctx.moveTo(x0, y0);
this.ctx.lineTo(x1, y1);
this.ctx.stroke();
-
+
}
this.render = function(data) {
-
+
var backgrounds = '';
var nodedata = '';
-
+
for (var i in data) {
-
+
var parity = i % 2;
this.cell[1] += this.bg_height;
this.bg[1] += this.bg_height;
-
+
var cur = data[i];
var node = cur[1];
var edges = cur[2];
var fold = false;
-
+
var prevWidth = this.ctx.lineWidth;
for (var j in edges) {
-
+
line = edges[j];
start = line[0];
end = line[1];
@@ -125,44 +125,44 @@
var branchcolor = line[4];
if(branchcolor)
color = branchcolor;
-
+
if (end > this.columns || start > this.columns) {
this.columns += 1;
}
-
+
if (start == this.columns && start > end) {
var fold = true;
}
-
+
x0 = this.cell[0] + this.box_size * start + this.box_size / 2;
y0 = this.bg[1] - this.bg_height / 2;
x1 = this.cell[0] + this.box_size * end + this.box_size / 2;
y1 = this.bg[1] + this.bg_height / 2;
-
+
this.edge(x0, y0, x1, y1, color, width);
-
+
}
this.ctx.lineWidth = prevWidth;
-
+
// Draw the revision node in the right column
-
+
column = node[0]
color = node[1]
-
+
radius = this.box_size / 8;
x = this.cell[0] + this.box_size * column + this.box_size / 2;
y = this.bg[1] - this.bg_height / 2;
var add = this.vertex(x, y, color, parity, cur);
backgrounds += add[0];
nodedata += add[1];
-
+
if (fold) this.columns -= 1;
-
+
}
-
+
document.getElementById('nodebgs').innerHTML += backgrounds;
document.getElementById('graphnodes').innerHTML += nodedata;
-
+
}
}
@@ -258,6 +258,7 @@
// We want both: date + (age)
node.textContent += ' ('+agevalue+')';
} else {
+ node.title = node.textContent;
node.textContent = agevalue;
}
}
@@ -297,3 +298,126 @@
setLinewrap(!getLinewrap());
}
+
+function format(str, replacements) {
+ return str.replace(/%(\w+)%/g, function(match, p1) {
+ return String(replacements[p1]);
+ });
+}
+
+function makeRequest(url, method, onstart, onsuccess, onerror, oncomplete) {
+ xfr = new XMLHttpRequest();
+ xfr.onreadystatechange = function() {
+ if (xfr.readyState === 4) {
+ try {
+ if (xfr.status === 200) {
+ onsuccess(xfr.responseText);
+ } else {
+ throw 'server error';
+ }
+ } catch (e) {
+ onerror(e);
+ } finally {
+ oncomplete();
+ }
+ }
+ };
+
+ xfr.open(method, url);
+ xfr.send();
+ onstart();
+ return xfr;
+}
+
+function removeByClassName(className) {
+ var nodes = document.getElementsByClassName(className);
+ while (nodes.length) {
+ nodes[0].parentNode.removeChild(nodes[0]);
+ }
+}
+
+function docFromHTML(html) {
+ var doc = document.implementation.createHTMLDocument('');
+ doc.documentElement.innerHTML = html;
+ return doc;
+}
+
+function appendFormatHTML(element, formatStr, replacements) {
+ element.insertAdjacentHTML('beforeend', format(formatStr, replacements));
+}
+
+function ajaxScrollInit(urlFormat,
+ nextHash,
+ nextHashRegex,
+ containerSelector,
+ messageFormat) {
+ updateInitiated = false;
+ container = document.querySelector(containerSelector);
+
+ function scrollHandler() {
+ if (updateInitiated) {
+ return;
+ }
+
+ var scrollHeight = document.documentElement.scrollHeight;
+ var clientHeight = document.documentElement.clientHeight;
+ var scrollTop = document.body.scrollTop
+ || document.documentElement.scrollTop;
+
+ if (scrollHeight - (scrollTop + clientHeight) < 50) {
+ updateInitiated = true;
+ removeByClassName('scroll-loading-error');
+ container.lastElementChild.classList.add('scroll-separator');
+
+ if (!nextHash) {
+ var message = {
+ class: 'scroll-loading-info',
+ text: 'No more entries'
+ };
+ appendFormatHTML(container, messageFormat, message);
+ return;
+ }
+
+ makeRequest(
+ format(urlFormat, {hash: nextHash}),
+ 'GET',
+ function onstart() {
+ var message = {
+ class: 'scroll-loading',
+ text: 'Loading...'
+ };
+ appendFormatHTML(container, messageFormat, message);
+ },
+ function onsuccess(htmlText) {
+ var m = htmlText.match(nextHashRegex);
+ nextHash = m ? m[1] : null;
+
+ var doc = docFromHTML(htmlText);
+ var nodes = doc.querySelector(containerSelector).children;
+ while (nodes.length) {
+ var node = nodes[0];
+ node = document.adoptNode(node);
+ container.appendChild(node);
+ }
+ process_dates();
+ },
+ function onerror(errorText) {
+ var message = {
+ class: 'scroll-loading-error',
+ text: 'Error: ' + errorText
+ };
+ appendFormatHTML(container, messageFormat, message);
+ },
+ function oncomplete() {
+ removeByClassName('scroll-loading');
+ updateInitiated = false;
+ scrollHandler();
+ }
+ );
+ }
+ }
+
+ window.addEventListener('scroll', scrollHandler);
+ window.addEventListener('resize', scrollHandler);
+ scrollHandler();
+}
--- a/mercurial/templates/static/style-paper.css Sat Sep 07 15:07:10 2013 -0500
+++ b/mercurial/templates/static/style-paper.css Fri Sep 20 11:47:03 2013 -0500
@@ -382,3 +382,27 @@
.breadcrumb a {
color: blue;
}
+
+.scroll-loading {
+ -webkit-animation: change_color 1s linear 0s infinite alternate;
+ -moz-animation: change_color 1s linear 0s infinite alternate;
+ -o-animation: change_color 1s linear 0s infinite alternate;
+ animation: change_color 1s linear 0s infinite alternate;
+}
+
+@-webkit-keyframes change_color {
+ from { background-color: #A0CEFF; } to { }
+}
+@-moz-keyframes change_color {
+ from { background-color: #A0CEFF; } to { }
+}
+@-o-keyframes change_color {
+ from { background-color: #A0CEFF; } to { }
+}
+@keyframes change_color {
+ from { background-color: #A0CEFF; } to { }
+}
+
+.scroll-loading-error {
+ background-color: #FFCCCC !important;
+}
--- a/mercurial/ui.py Sat Sep 07 15:07:10 2013 -0500
+++ b/mercurial/ui.py Fri Sep 20 11:47:03 2013 -0500
@@ -176,7 +176,7 @@
alternates = [name]
for n in alternates:
- value = self._data(untrusted).get(section, name, None)
+ value = self._data(untrusted).get(section, n, None)
if value is not None:
name = n
break
@@ -184,10 +184,11 @@
value = default
if self.debugflag and not untrusted and self._reportuntrusted:
- uvalue = self._ucfg.get(section, name)
- if uvalue is not None and uvalue != value:
- self.debug("ignoring untrusted configuration option "
- "%s.%s = %s\n" % (section, name, uvalue))
+ for n in alternates:
+ uvalue = self._ucfg.get(section, n)
+ if uvalue is not None and uvalue != value:
+ self.debug("ignoring untrusted configuration option "
+ "%s.%s = %s\n" % (section, n, uvalue))
return value
def configpath(self, section, name, default=None, untrusted=False):
--- a/mercurial/unionrepo.py Sat Sep 07 15:07:10 2013 -0500
+++ b/mercurial/unionrepo.py Fri Sep 20 11:47:03 2013 -0500
@@ -70,7 +70,7 @@
self.revlog2.rev(self.node(rev1)),
self.revlog2.rev(self.node(rev2)))
elif rev1 <= self.repotiprev and rev2 <= self.repotiprev:
- return revlog.revlog.revdiff(self, rev1, rev2)
+ return self.baserevdiff(rev1, rev2)
return mdiff.textdiff(self.revision(self.node(rev1)),
self.revision(self.node(rev2)))
@@ -93,10 +93,20 @@
text = self.revlog2.revision(node)
self._cache = (node, rev, text)
else:
- text = revlog.revlog.revision(self, rev)
+ text = self.baserevision(rev)
# already cached
return text
+ def baserevision(self, nodeorrev):
+ # Revlog subclasses may override 'revision' method to modify format of
+ # content retrieved from revlog. To use unionrevlog with such class one
+ # needs to override 'baserevision' and make more specific call here.
+ return revlog.revlog.revision(self, nodeorrev)
+
+ def baserevdiff(self, rev1, rev2):
+ # Exists for the same purpose as baserevision.
+ return revlog.revlog.revdiff(self, rev1, rev2)
+
def addrevision(self, text, transaction, link, p1=None, p2=None, d=None):
raise NotImplementedError
def addgroup(self, revs, linkmapper, transaction):
@@ -114,6 +124,15 @@
unionrevlog.__init__(self, opener, self.indexfile, changelog2,
linkmapper)
+ def baserevision(self, nodeorrev):
+ # Although changelog doesn't override 'revision' method, some extensions
+ # may replace this class with another that does. Same story with
+ # manifest and filelog classes.
+ return changelog.changelog.revision(self, nodeorrev)
+
+ def baserevdiff(self, rev1, rev2):
+ return changelog.changelog.revdiff(self, rev1, rev2)
+
class unionmanifest(unionrevlog, manifest.manifest):
def __init__(self, opener, opener2, linkmapper):
manifest.manifest.__init__(self, opener)
@@ -121,6 +140,12 @@
unionrevlog.__init__(self, opener, self.indexfile, manifest2,
linkmapper)
+ def baserevision(self, nodeorrev):
+ return manifest.manifest.revision(self, nodeorrev)
+
+ def baserevdiff(self, rev1, rev2):
+ return manifest.manifest.revdiff(self, rev1, rev2)
+
class unionfilelog(unionrevlog, filelog.filelog):
def __init__(self, opener, path, opener2, linkmapper, repo):
filelog.filelog.__init__(self, opener, path)
@@ -129,6 +154,12 @@
linkmapper)
self._repo = repo
+ def baserevision(self, nodeorrev):
+ return filelog.filelog.revision(self, nodeorrev)
+
+ def baserevdiff(self, rev1, rev2):
+ return filelog.filelog.revdiff(self, rev1, rev2)
+
def _file(self, f):
self._repo.file(f)
--- a/mercurial/url.py Sat Sep 07 15:07:10 2013 -0500
+++ b/mercurial/url.py Fri Sep 20 11:47:03 2013 -0500
@@ -108,8 +108,13 @@
def proxy_open(self, req, proxy, type_):
host = req.get_host().split(':')[0]
- if host in self.no_list:
- return None
+ for e in self.no_list:
+ if host == e:
+ return None
+ if e.startswith('*.') and host.endswith(e[2:]):
+ return None
+ if e.startswith('.') and host.endswith(e[1:]):
+ return None
# work around a bug in Python < 2.4.2
# (it leaves a "\n" at the end of Proxy-authorization headers)
--- a/mercurial/util.h Sat Sep 07 15:07:10 2013 -0500
+++ b/mercurial/util.h Fri Sep 20 11:47:03 2013 -0500
@@ -121,7 +121,12 @@
#ifdef _MSC_VER
/* msvc 6.0 has problems */
#define inline __inline
+typedef signed char int8_t;
+typedef short int16_t;
+typedef long int32_t;
+typedef __int64 int64_t;
typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
typedef unsigned long uint32_t;
typedef unsigned __int64 uint64_t;
#else
@@ -146,6 +151,17 @@
#define inline __inline
#endif
+#if defined(_MSC_VER) && (_MSC_VER >= 1300)
+static inline uint32_t getbe32(const char *c)
+{
+ return _byteswap_ulong(*(uint32_t *)c);
+}
+#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
+static inline uint32_t getbe32(const char *c)
+{
+ return __builtin_bswap32(*(uint32_t *)c);
+}
+#else
static inline uint32_t getbe32(const char *c)
{
const unsigned char *d = (const unsigned char *)c;
@@ -155,7 +171,21 @@
(d[2] << 8) |
(d[3]));
}
+#endif
+#if defined(_MSC_VER) && (_MSC_VER >= 1300)
+static inline void putbe32(uint32_t x, char *c)
+{
+ x = _byteswap_ulong(x);
+ *(uint32_t *)c = x;
+}
+#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
+static inline void putbe32(uint32_t x, char *c)
+{
+ x = __builtin_bswap32(x);
+ *(uint32_t *)c = x;
+}
+#else
static inline void putbe32(uint32_t x, char *c)
{
c[0] = (x >> 24) & 0xff;
@@ -163,5 +193,6 @@
c[2] = (x >> 8) & 0xff;
c[3] = (x) & 0xff;
}
+#endif
#endif /* _HG_UTIL_H_ */
--- a/mercurial/util.py Sat Sep 07 15:07:10 2013 -0500
+++ b/mercurial/util.py Fri Sep 20 11:47:03 2013 -0500
@@ -242,6 +242,10 @@
def __contains__(self, key):
return key in self._cache
+ def clear(self):
+ self._cache.clear()
+ self._order = deque()
+
def lrucachefunc(func):
'''cache most recent results of function calls'''
cache = {}
@@ -465,7 +469,8 @@
return str(val)
origcmd = cmd
cmd = quotecommand(cmd)
- if sys.platform == 'plan9':
+ if sys.platform == 'plan9' and (sys.version_info[0] == 2
+ and sys.version_info[1] < 7):
# subprocess kludge to work around issues in half-baked Python
# ports, notably bichued/python:
if not cwd is None:
--- a/setup.py Sat Sep 07 15:07:10 2013 -0500
+++ b/setup.py Fri Sep 20 11:47:03 2013 -0500
@@ -423,14 +423,21 @@
pymodules = []
+common_depends = ['mercurial/util.h']
+
extmodules = [
- Extension('mercurial.base85', ['mercurial/base85.c']),
- Extension('mercurial.bdiff', ['mercurial/bdiff.c']),
- Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c']),
- Extension('mercurial.mpatch', ['mercurial/mpatch.c']),
+ Extension('mercurial.base85', ['mercurial/base85.c'],
+ depends=common_depends),
+ Extension('mercurial.bdiff', ['mercurial/bdiff.c'],
+ depends=common_depends),
+ Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c'],
+ depends=common_depends),
+ Extension('mercurial.mpatch', ['mercurial/mpatch.c'],
+ depends=common_depends),
Extension('mercurial.parsers', ['mercurial/dirs.c',
'mercurial/parsers.c',
- 'mercurial/pathencode.c']),
+ 'mercurial/pathencode.c'],
+ depends=common_depends),
]
osutil_ldflags = []
@@ -443,7 +450,8 @@
pymodules.append('mercurial.pure.osutil')
else:
extmodules.append(Extension('mercurial.osutil', ['mercurial/osutil.c'],
- extra_link_args=osutil_ldflags))
+ extra_link_args=osutil_ldflags,
+ depends=common_depends))
# the -mno-cygwin option has been deprecated for years
Mingw32CCompiler = cygwinccompiler.Mingw32CCompiler
@@ -467,7 +475,8 @@
if hasfunction(cc, 'inotify_add_watch'):
inotify = Extension('hgext.inotify.linux._inotify',
['hgext/inotify/linux/_inotify.c'],
- ['mercurial'])
+ ['mercurial'],
+ depends=common_depends)
inotify.optional = True
extmodules.append(inotify)
packages.extend(['hgext.inotify', 'hgext.inotify.linux'])
--- a/tests/run-tests.py Sat Sep 07 15:07:10 2013 -0500
+++ b/tests/run-tests.py Fri Sep 20 11:47:03 2013 -0500
@@ -460,6 +460,9 @@
if options.compiler:
compiler = '--compiler ' + options.compiler
pure = options.pure and "--pure" or ""
+ py3 = ''
+ if sys.version_info[0] == 3:
+ py3 = '--c2to3'
# Run installer in hg root
script = os.path.realpath(sys.argv[0])
@@ -472,11 +475,11 @@
# least on Windows for now, deal with .pydistutils.cfg bugs
# when they happen.
nohome = ''
- cmd = ('%(exe)s setup.py %(pure)s clean --all'
+ cmd = ('%(exe)s setup.py %(py3)s %(pure)s clean --all'
' build %(compiler)s --build-base="%(base)s"'
' install --force --prefix="%(prefix)s" --install-lib="%(libdir)s"'
' --install-scripts="%(bindir)s" %(nohome)s >%(logfile)s 2>&1'
- % dict(exe=sys.executable, pure=pure, compiler=compiler,
+ % dict(exe=sys.executable, py3=py3, pure=pure, compiler=compiler,
base=os.path.join(HGTMP, "build"),
prefix=INST, libdir=PYTHONDIR, bindir=BINDIR,
nohome=nohome, logfile=installerrs))
@@ -921,8 +924,10 @@
else:
return ignore("doesn't match keyword")
+ if not lctest.startswith("test-"):
+ return skip("not a test file")
for ext, func, out in testtypes:
- if lctest.startswith("test-") and lctest.endswith(ext):
+ if lctest.endswith(ext):
runner = func
ref = os.path.join(TESTDIR, test + out)
break
@@ -1043,7 +1048,7 @@
if _hgpath is not None:
return _hgpath
- cmd = '%s -c "import mercurial; print mercurial.__path__[0]"'
+ cmd = '%s -c "import mercurial; print (mercurial.__path__[0])"'
pipe = os.popen(cmd % PYTHON)
try:
_hgpath = pipe.read().strip()
--- a/tests/test-hgweb-commands.t Sat Sep 07 15:07:10 2013 -0500
+++ b/tests/test-hgweb-commands.t Fri Sep 20 11:47:03 2013 -0500
@@ -305,6 +305,18 @@
| rev 3: <a href="/shortlog/2ef0ac749a14">(0)</a> <a href="/shortlog/tip">tip</a>
</div>
+ <script type="text/javascript">
+ ajaxScrollInit(
+ '/shortlog/%hash%',
+ '', <!-- NEXTHASH
+ /'(\w+)', <!-- NEXTHASH/,
+ '.bigtable > tbody:nth-of-type(2)',
+ '<tr class="%class%">\
+ <td colspan="3" style="text-align: center;">%text%</td>\
+ </tr>'
+ );
+ </script>
+
</div>
</div>
@@ -537,6 +549,153 @@
</body>
</html>
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=stable&style=raw' | grep 'revision:'
+ revision: 2
+
+Search with revset syntax
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=tip^&style=raw'
+ 200 Script output follows
+
+
+ # HG changesets search
+ # Node ID cad8025a2e87f88c06259790adfa15acb4080123
+ # Query "tip^"
+
+ changeset: 1d22e65f027e5a0609357e7d8e7508cd2ba5d2fe
+ revision: 2
+ user: test
+ date: Thu, 01 Jan 1970 00:00:00 +0000
+ summary: branch
+ branch: stable
+
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=last(all(),2)^&style=raw'
+ 200 Script output follows
+
+
+ # HG changesets search
+ # Node ID cad8025a2e87f88c06259790adfa15acb4080123
+ # Query "last(all(),2)^"
+
+ changeset: 1d22e65f027e5a0609357e7d8e7508cd2ba5d2fe
+ revision: 2
+ user: test
+ date: Thu, 01 Jan 1970 00:00:00 +0000
+ summary: branch
+ branch: stable
+
+ changeset: a4f92ed23982be056b9852de5dfe873eaac7f0de
+ revision: 1
+ user: test
+ date: Thu, 01 Jan 1970 00:00:00 +0000
+ summary: Added tag 1.0 for changeset 2ef0ac749a14
+ branch: default
+
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=last(all(,2)^&style=raw'
+ 200 Script output follows
+
+
+ # HG changesets search
+ # Node ID cad8025a2e87f88c06259790adfa15acb4080123
+ # Query "last(all(,2)^"
+
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=last(al(),2)^&style=raw'
+ 200 Script output follows
+
+
+ # HG changesets search
+ # Node ID cad8025a2e87f88c06259790adfa15acb4080123
+ # Query "last(al(),2)^"
+
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=bookmark(anotherthing)&style=raw'
+ 200 Script output follows
+
+
+ # HG changesets search
+ # Node ID cad8025a2e87f88c06259790adfa15acb4080123
+ # Query "bookmark(anotherthing)"
+
+ changeset: 2ef0ac749a14e4f57a5a822464a0902c6f7f448f
+ revision: 0
+ user: test
+ date: Thu, 01 Jan 1970 00:00:00 +0000
+ summary: base
+ tag: 1.0
+ bookmark: anotherthing
+
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=bookmark(abc)&style=raw'
+ 200 Script output follows
+
+
+ # HG changesets search
+ # Node ID cad8025a2e87f88c06259790adfa15acb4080123
+ # Query "bookmark(abc)"
+
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=deadbeef:&style=raw'
+ 200 Script output follows
+
+
+ # HG changesets search
+ # Node ID cad8025a2e87f88c06259790adfa15acb4080123
+ # Query "deadbeef:"
+
+
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=user("test")&style=raw'
+ 200 Script output follows
+
+
+ # HG changesets search
+ # Node ID cad8025a2e87f88c06259790adfa15acb4080123
+ # Query "user("test")"
+
+ changeset: cad8025a2e87f88c06259790adfa15acb4080123
+ revision: 3
+ user: test
+ date: Thu, 01 Jan 1970 00:00:00 +0000
+ summary: branch commit with null character: \x00 (esc)
+ branch: unstable
+ tag: tip
+ bookmark: something
+
+ changeset: 1d22e65f027e5a0609357e7d8e7508cd2ba5d2fe
+ revision: 2
+ user: test
+ date: Thu, 01 Jan 1970 00:00:00 +0000
+ summary: branch
+ branch: stable
+
+ changeset: a4f92ed23982be056b9852de5dfe873eaac7f0de
+ revision: 1
+ user: test
+ date: Thu, 01 Jan 1970 00:00:00 +0000
+ summary: Added tag 1.0 for changeset 2ef0ac749a14
+ branch: default
+
+ changeset: 2ef0ac749a14e4f57a5a822464a0902c6f7f448f
+ revision: 0
+ user: test
+ date: Thu, 01 Jan 1970 00:00:00 +0000
+ summary: base
+ tag: 1.0
+ bookmark: anotherthing
+
+
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=user("re:test")&style=raw'
+ 200 Script output follows
+
+
+ # HG changesets search
+ # Node ID cad8025a2e87f88c06259790adfa15acb4080123
+ # Query "user("re:test")"
+
+
File-related
@@ -637,7 +796,6 @@
<th class="author">children</th>
<td class="author"><a href="/file/1d22e65f027e/foo">1d22e65f027e</a> </td>
</tr>
-
</table>
<div class="overflow">
@@ -1256,8 +1414,10 @@
Graph json escape of multibyte character
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'graph/' \
- > | grep -a '^var data ='
+ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'graph/' > out
+ >>> for line in open("out"):
+ ... if line.startswith("var data ="):
+ ... print line,
var data = [["061dd13ba3c3", [0, 1], [[0, 0, 1, -1, ""]], "\\u80fd", "test", "1970-01-01", ["unstable", true], ["tip"], ["something"]], ["cad8025a2e87", [0, 1], [[0, 0, 1, 3, "FF0000"]], "branch commit with null character: \x00", "test", "1970-01-01", ["unstable", false], [], []], ["1d22e65f027e", [0, 1], [[0, 0, 1, 3, ""]], "branch", "test", "1970-01-01", ["stable", true], [], []], ["a4f92ed23982", [0, 1], [[0, 0, 1, 3, ""]], "Added tag 1.0 for changeset 2ef0ac749a14", "test", "1970-01-01", ["default", true], [], []], ["2ef0ac749a14", [0, 1], [], "base", "test", "1970-01-01", ["default", false], ["1.0"], ["anotherthing"]]]; (esc)
capabilities
--- a/tests/test-hgweb-diffs.t Sat Sep 07 15:07:10 2013 -0500
+++ b/tests/test-hgweb-diffs.t Fri Sep 20 11:47:03 2013 -0500
@@ -269,7 +269,6 @@
<th>children</th>
<td></td>
</tr>
-
</table>
<div class="overflow">
@@ -538,7 +537,6 @@
<th>children</th>
<td></td>
</tr>
-
</table>
<div class="overflow">
@@ -638,7 +636,6 @@
<th>children</th>
<td></td>
</tr>
-
</table>
<div class="overflow">
@@ -760,7 +757,6 @@
<th>children</th>
<td></td>
</tr>
-
</table>
<div class="overflow">
@@ -884,7 +880,6 @@
<th>children</th>
<td></td>
</tr>
-
</table>
<div class="overflow">
--- a/tests/test-hgweb-empty.t Sat Sep 07 15:07:10 2013 -0500
+++ b/tests/test-hgweb-empty.t Fri Sep 20 11:47:03 2013 -0500
@@ -90,6 +90,18 @@
| rev -1:
</div>
+ <script type="text/javascript">
+ ajaxScrollInit(
+ '/shortlog/%hash%',
+ '', <!-- NEXTHASH
+ /'(\w+)', <!-- NEXTHASH/,
+ '.bigtable > tbody:nth-of-type(2)',
+ '<tr class="%class%">\
+ <td colspan="3" style="text-align: center;">%text%</td>\
+ </tr>'
+ );
+ </script>
+
</div>
</div>
@@ -185,6 +197,18 @@
| rev -1:
</div>
+ <script type="text/javascript">
+ ajaxScrollInit(
+ '/shortlog/%hash%',
+ '', <!-- NEXTHASH
+ /'(\w+)', <!-- NEXTHASH/,
+ '.bigtable > tbody:nth-of-type(2)',
+ '<tr class="%class%">\
+ <td colspan="3" style="text-align: center;">%text%</td>\
+ </tr>'
+ );
+ </script>
+
</div>
</div>
--- a/tests/test-hgweb-removed.t Sat Sep 07 15:07:10 2013 -0500
+++ b/tests/test-hgweb-removed.t Fri Sep 20 11:47:03 2013 -0500
@@ -213,7 +213,6 @@
<th>children</th>
<td></td>
</tr>
-
</table>
<div class="overflow">
--- a/tests/test-highlight.t Sat Sep 07 15:07:10 2013 -0500
+++ b/tests/test-highlight.t Fri Sep 20 11:47:03 2013 -0500
@@ -132,7 +132,6 @@
<th class="author">children</th>
<td class="author"></td>
</tr>
-
</table>
<div class="overflow">
@@ -264,7 +263,6 @@
<th class="author">children</th>
<td class="author"></td>
</tr>
-
</table>
<div class="overflow">
--- a/tests/test-import-merge.t Sat Sep 07 15:07:10 2013 -0500
+++ b/tests/test-import-merge.t Fri Sep 20 11:47:03 2013 -0500
@@ -129,7 +129,9 @@
$ echo a>>a
$ hg ci -m3
$ hg export 2 | head -7 > ../a.patch
- $ hg export tip | tail -n +8 >> ../a.patch
+ $ hg export tip > out
+ >>> apatch = open("../a.patch", "a")
+ >>> apatch.write("".join(open("out").readlines()[7:]))
$ cd ..
$ hg clone -qr0 repo3 repo3-clone
--- a/tests/test-lrucachedict.py Sat Sep 07 15:07:10 2013 -0500
+++ b/tests/test-lrucachedict.py Fri Sep 20 11:47:03 2013 -0500
@@ -31,5 +31,8 @@
d['f'] = 'vf'
printifpresent(d, ['b', 'c', 'd', 'e', 'f'])
+ d.clear()
+ printifpresent(d, ['b', 'c', 'd', 'e', 'f'])
+
if __name__ == '__main__':
test_lrucachedict()
--- a/tests/test-lrucachedict.py.out Sat Sep 07 15:07:10 2013 -0500
+++ b/tests/test-lrucachedict.py.out Fri Sep 20 11:47:03 2013 -0500
@@ -24,3 +24,8 @@
'e' in d: False
'f' in d: True
d['f']: vf
+'b' in d: False
+'c' in d: False
+'d' in d: False
+'e' in d: False
+'f' in d: False
--- a/tests/test-mq-subrepo.t Sat Sep 07 15:07:10 2013 -0500
+++ b/tests/test-mq-subrepo.t Fri Sep 20 11:47:03 2013 -0500
@@ -213,6 +213,7 @@
handle subrepos safely on qpush/qpop
+(and we cannot qpop / qpush with a modified subrepo)
$ mkrepo repo-2499-qpush
$ mksubrepo sub
@@ -220,31 +221,56 @@
$ hg -R sub ci -m0sub
$ echo sub = sub > .hgsub
$ hg add .hgsub
- $ hg qnew -m0 0.diff
+ $ hg commit -m0
$ hg debugsub
path sub
source sub
revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
+ $ echo foo > ./sub/a
+ $ hg -R sub commit -m foo
+ $ hg commit -m1
+ $ hg qimport -r "0:tip"
+ $ hg -R sub id --id
+ aa037b301eba
qpop
+ $ hg -R sub update 0000
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
$ hg qpop
- popping 0.diff
- patch queue now empty
- $ hg status -AS
- $ hg debugsub
-
-qpush
- $ hg qpush
- applying 0.diff
+ abort: local changed subrepos found, refresh first
+ [255]
+ $ hg revert sub
+ reverting subrepo sub
+ adding sub/a
+ $ hg qpop
+ popping 1.diff
now at: 0.diff
$ hg status -AS
C .hgsub
C .hgsubstate
C sub/a
- $ hg debugsub
- path sub
- source sub
- revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
+ $ hg -R sub id --id
+ b2fdb12cd82b
+
+qpush
+ $ hg -R sub update 0000
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg qpush
+ abort: local changed subrepos found, refresh first
+ [255]
+ $ hg revert sub
+ reverting subrepo sub
+ adding sub/a
+ $ hg qpush
+ applying 1.diff
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ now at: 1.diff
+ $ hg status -AS
+ C .hgsub
+ C .hgsubstate
+ C sub/a
+ $ hg -R sub id --id
+ aa037b301eba
$ cd ..
--- a/tests/test-parse-date.t Sat Sep 07 15:07:10 2013 -0500
+++ b/tests/test-parse-date.t Fri Sep 20 11:47:03 2013 -0500
@@ -242,7 +242,7 @@
>>> yesterday = (datetime.date.today() - datetime.timedelta(days=1)).strftime("%b %d")
>>> dates = open('dates', 'w')
>>> dates.write(today + '\n')
- >>> dates.write(yesterday)
+ >>> dates.write(yesterday + '\n')
>>> dates.close()
$ hg ci -d "`sed -n '1p' dates`" -m "today is a good day to code"
$ hg log -d today --template '{desc}\n'
--- a/tests/test-progress.t Sat Sep 07 15:07:10 2013 -0500
+++ b/tests/test-progress.t Fri Sep 20 11:47:03 2013 -0500
@@ -1,6 +1,14 @@
$ cat > loop.py <<EOF
> from mercurial import commands
+ > import time
+ > class incrementingtime(object):
+ > def __init__(self):
+ > self._time = 0.0
+ > def __call__(self):
+ > self._time += 0.25
+ > return self._time
+ > time.time = incrementingtime()
>
> def loop(ui, loops, **opts):
> loops = int(loops)
@@ -19,9 +27,14 @@
> if opts.get('parallel'):
> ui.progress('other', i, 'other.%d' % i, 'othernum', total)
> if nested:
- > for j in range(2):
- > ui.progress('nested', j, 'nested.%d' % j, 'nestnum', 2)
- > ui.progress('nested', None, 'nested.done', 'nestnum', 2)
+ > nested_steps = 2
+ > if i and i % 4 == 0:
+ > nested_steps = 5
+ > for j in range(nested_steps):
+ > ui.progress(
+ > 'nested', j, 'nested.%d' % j, 'nestnum', nested_steps)
+ > ui.progress(
+ > 'nested', None, 'nested.done', 'nestnum', nested_steps)
> ui.progress('loop', None, 'loop.done', 'loopnum', total)
>
> commands.norepo += " loop"
@@ -69,6 +82,24 @@
loop [===============================> ] 2/3\r (no-eol) (esc)
\r (no-eol) (esc)
+Test nested long-lived topic which has the same name as a short-lived
+peer. We shouldn't get stuck showing the short-lived inner steps, and
+should go back to skipping the inner steps when the slow nested step
+finishes.
+
+ $ hg -y loop 7 --nested
+ \r (no-eol) (esc)
+ loop [ ] 0/7\r (no-eol) (esc)
+ loop [=====> ] 1/7\r (no-eol) (esc)
+ loop [============> ] 2/7\r (no-eol) (esc)
+ loop [===================> ] 3/7\r (no-eol) (esc)
+ loop [==========================> ] 4/7\r (no-eol) (esc)
+ nested [==========================> ] 3/5\r (no-eol) (esc)
+ nested [===================================> ] 4/5\r (no-eol) (esc)
+ loop [=================================> ] 5/7\r (no-eol) (esc)
+ loop [========================================> ] 6/7\r (no-eol) (esc)
+ \r (no-eol) (esc)
+
$ hg --config progress.changedelay=0 -y loop 3 --nested
\r (no-eol) (esc)
--- a/tests/test-symlink-placeholder.t Sat Sep 07 15:07:10 2013 -0500
+++ b/tests/test-symlink-placeholder.t Fri Sep 20 11:47:03 2013 -0500
@@ -41,6 +41,13 @@
a (no-eol)
$ hg --config extensions.n=$TESTTMP/nolink.py st --debug
+Empty placeholder:
+
+ $ rm b
+ $ touch b
+ $ hg --config extensions.n=$TESTTMP/nolink.py st --debug
+ ignoring suspect symlink placeholder "b"
+
Write binary data to the placeholder:
>>> open('b', 'w').write('this is a binary\0')