merge with wsgi changes.
--- a/hgext/mq.py Tue Jun 27 00:09:37 2006 -0700
+++ b/hgext/mq.py Tue Jun 27 00:10:41 2006 -0700
@@ -1000,6 +1000,7 @@
self.ui.warn("-n option not valid when importing multiple files\n")
sys.exit(1)
i = 0
+ added = []
for filename in files:
if existing:
if not patch:
@@ -1028,8 +1029,12 @@
self.read_series(self.full_series)
self.ui.warn("adding %s to series file\n" % patch)
i += 1
+ added.append(patch)
patch = None
self.series_dirty = 1
+ qrepo = self.qrepo()
+ if qrepo:
+ qrepo.add(added)
def delete(ui, repo, patch, **opts):
"""remove a patch from the series file"""
--- a/mercurial/commands.py Tue Jun 27 00:09:37 2006 -0700
+++ b/mercurial/commands.py Tue Jun 27 00:10:41 2006 -0700
@@ -12,7 +12,7 @@
demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo")
demandload(globals(), "fnmatch mdiff random signal tempfile time")
demandload(globals(), "traceback errno socket version struct atexit sets bz2")
-demandload(globals(), "archival changegroup")
+demandload(globals(), "archival cStringIO changegroup email.Parser")
demandload(globals(), "hgweb.server sshserver")
class UnknownCommand(Exception):
@@ -836,11 +836,16 @@
return '%d:%s' % (repo.changelog.rev(node), short(node))
ui.status(_('changeset %s backs out changeset %s\n') %
(nice(repo.changelog.tip()), nice(node)))
- if opts['merge'] and op1 != node:
- ui.status(_('merging with changeset %s\n') % nice(op1))
- doupdate(ui, repo, hex(op1), **opts)
-
-def bundle(ui, repo, fname, dest="default-push", **opts):
+ if op1 != node:
+ if opts['merge']:
+ ui.status(_('merging with changeset %s\n') % nice(op1))
+ doupdate(ui, repo, hex(op1), **opts)
+ else:
+ ui.status(_('the backout changeset is a new head - '
+ 'do not forget to merge\n'))
+ ui.status(_('(use "backout -m" if you want to auto-merge)\n'))
+
+def bundle(ui, repo, fname, dest=None, **opts):
"""create a changegroup file
Generate a compressed changegroup file collecting all changesets
@@ -855,7 +860,7 @@
Unlike import/export, this exactly preserves all changeset
contents including permissions, rename data, and revision history.
"""
- dest = ui.expandpath(dest)
+ dest = ui.expandpath(dest or 'default-push', dest or 'default')
other = hg.repository(ui, dest)
o = repo.findoutgoing(other, force=opts['force'])
cg = repo.changegroup(o, 'bundle')
@@ -1714,11 +1719,15 @@
If there are outstanding changes in the working directory, import
will abort unless given the -f flag.
- If a patch looks like a mail message (its first line starts with
- "From " or looks like an RFC822 header), it will not be applied
- unless the -f option is used. The importer neither parses nor
- discards mail headers, so use -f only to override the "mailness"
- safety check, not to import a real mail message.
+ You can import a patch straight from a mail message. Even patches
+ as attachments work (body part must be type text/plain or
+ text/x-patch to be used). Sender and subject line of email
+ message are used as default committer and commit message. Any
+ text/plain body part before first diff is added to commit message.
+
+ If imported patch was generated by hg export, user and description
+ from patch override values from message headers and body. Values
+ given on command line with -m and -u override these.
To read a patch from standard input, use patch name "-".
"""
@@ -1734,79 +1743,93 @@
# attempt to detect the start of a patch
# (this heuristic is borrowed from quilt)
- diffre = re.compile(r'(?:Index:[ \t]|diff[ \t]|RCS file: |' +
+ diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' +
'retrieving revision [0-9]+(\.[0-9]+)*$|' +
- '(---|\*\*\*)[ \t])')
+ '(---|\*\*\*)[ \t])', re.MULTILINE)
for patch in patches:
pf = os.path.join(d, patch)
- message = []
+ message = None
user = None
date = None
hgpatch = False
+
+ p = email.Parser.Parser()
if pf == '-':
- f = sys.stdin
- fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
- pf = tmpname
- tmpfp = os.fdopen(fd, 'w')
+ msg = p.parse(sys.stdin)
ui.status(_("applying patch from stdin\n"))
else:
- f = open(pf)
- tmpfp, tmpname = None, None
+ msg = p.parse(file(pf))
ui.status(_("applying %s\n") % patch)
+
+ fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
+ tmpfp = os.fdopen(fd, 'w')
try:
- while True:
- line = f.readline()
- if not line: break
- if tmpfp: tmpfp.write(line)
- line = line.rstrip()
- if (not message and not hgpatch and
- mailre.match(line) and not opts['force']):
- if len(line) > 35:
- line = line[:32] + '...'
- raise util.Abort(_('first line looks like a '
- 'mail header: ') + line)
- if diffre.match(line):
+ message = msg['Subject']
+ if message:
+ message = message.replace('\n\t', ' ')
+ ui.debug('Subject: %s\n' % message)
+ user = msg['From']
+ if user:
+ ui.debug('From: %s\n' % user)
+ diffs_seen = 0
+ ok_types = ('text/plain', 'text/x-patch')
+ for part in msg.walk():
+ content_type = part.get_content_type()
+ ui.debug('Content-Type: %s\n' % content_type)
+ if content_type not in ok_types:
+ continue
+ payload = part.get_payload(decode=True)
+ m = diffre.search(payload)
+ if m:
+ ui.debug(_('found patch at byte %d\n') % m.start(0))
+ diffs_seen += 1
+ hgpatch = False
+ fp = cStringIO.StringIO()
+ for line in payload[:m.start(0)].splitlines():
+ if line.startswith('# HG changeset patch'):
+ ui.debug(_('patch generated by hg export\n'))
+ hgpatch = True
+ elif hgpatch:
+ if line.startswith('# User '):
+ user = line[7:]
+ ui.debug('From: %s\n' % user)
+ elif line.startswith("# Date "):
+ date = line[7:]
+ if not line.startswith('# '):
+ fp.write(line)
+ fp.write('\n')
+ hgpatch = False
+ message = fp.getvalue() or message
if tmpfp:
- for chunk in util.filechunkiter(f):
- tmpfp.write(chunk)
- break
- elif hgpatch:
- # parse values when importing the result of an hg export
- if line.startswith("# User "):
- user = line[7:]
- ui.debug(_('User: %s\n') % user)
- elif line.startswith("# Date "):
- date = line[7:]
- elif not line.startswith("# ") and line:
- message.append(line)
- hgpatch = False
- elif line == '# HG changeset patch':
- hgpatch = True
- message = [] # We may have collected garbage
- elif message or line:
- message.append(line)
+ tmpfp.write(payload)
+ if not payload.endswith('\n'):
+ tmpfp.write('\n')
+ elif not diffs_seen and message and content_type == 'text/plain':
+ message += '\n' + payload
if opts['message']:
# pickup the cmdline msg
message = opts['message']
elif message:
# pickup the patch msg
- message = '\n'.join(message).rstrip()
+ message = message.strip()
else:
# launch the editor
message = None
ui.debug(_('message:\n%s\n') % message)
- if tmpfp: tmpfp.close()
- files = util.patch(strip, pf, ui)
-
+ tmpfp.close()
+ if not diffs_seen:
+ raise util.Abort(_('no diffs found'))
+
+ files = util.patch(strip, tmpname, ui)
if len(files) > 0:
addremove_lock(ui, repo, files, {})
repo.commit(files, message, user, date)
finally:
- if tmpname: os.unlink(tmpname)
+ os.unlink(tmpname)
def incoming(ui, repo, source="default", **opts):
"""show new changesets found in source
@@ -2042,7 +2065,7 @@
"""
return doupdate(ui, repo, node=node, merge=True, **opts)
-def outgoing(ui, repo, dest="default-push", **opts):
+def outgoing(ui, repo, dest=None, **opts):
"""show changesets not found in destination
Show changesets not found in the specified destination repository or
@@ -2051,7 +2074,7 @@
See pull for valid destination format details.
"""
- dest = ui.expandpath(dest)
+ dest = ui.expandpath(dest or 'default-push', dest or 'default')
if opts['ssh']:
ui.setconfig("ui", "ssh", opts['ssh'])
if opts['remotecmd']:
@@ -2174,7 +2197,7 @@
modheads = repo.pull(other, heads=revs, force=opts['force'])
return postincoming(ui, repo, modheads, opts['update'])
-def push(ui, repo, dest="default-push", **opts):
+def push(ui, repo, dest=None, **opts):
"""push changes to the specified destination
Push changes from the local repository to the given destination.
@@ -2196,7 +2219,7 @@
Look at the help text for the pull command for important details
about ssh:// URLs.
"""
- dest = ui.expandpath(dest)
+ dest = ui.expandpath(dest or 'default-push', dest or 'default')
if opts['ssh']:
ui.setconfig("ui", "ssh", opts['ssh'])
--- a/mercurial/hgweb/hgweb_mod.py Tue Jun 27 00:09:37 2006 -0700
+++ b/mercurial/hgweb/hgweb_mod.py Tue Jun 27 00:10:41 2006 -0700
@@ -49,8 +49,7 @@
self.allowpull = self.repo.ui.configbool("web", "allowpull", True)
def archivelist(self, nodeid):
- allowed = (self.repo.ui.config("web", "allow_archive", "")
- .replace(",", " ").split())
+ allowed = self.repo.ui.configlist("web", "allow_archive")
for i in self.archives:
if i in allowed or self.repo.ui.configbool("web", "allow" + i):
yield {"type" : i, "node" : nodeid, "url": ""}
@@ -816,7 +815,7 @@
def do_archive(self, req):
changeset = self.repo.lookup(req.form['node'][0])
type_ = req.form['type'][0]
- allowed = self.repo.ui.config("web", "allow_archive", "").split()
+ allowed = self.repo.ui.configlist("web", "allow_archive")
if (type_ in self.archives and (type_ in allowed or
self.repo.ui.configbool("web", "allow" + type_, False))):
self.archive(req, changeset, type_)
@@ -844,15 +843,11 @@
user = req.env.get('REMOTE_USER')
- deny = self.repo.ui.config('web', 'deny_' + op, '')
- deny = deny.replace(',', ' ').split()
-
+ deny = self.repo.ui.configlist('web', 'deny_' + op)
if deny and (not user or deny == ['*'] or user in deny):
return False
- allow = self.repo.ui.config('web', 'allow_' + op, '')
- allow = allow.replace(',', ' ').split()
-
+ allow = self.repo.ui.configlist('web', 'allow_' + op)
return (allow and (allow == ['*'] or user in allow)) or default
def do_unbundle(self, req):
--- a/mercurial/hgweb/hgwebdir_mod.py Tue Jun 27 00:09:37 2006 -0700
+++ b/mercurial/hgweb/hgwebdir_mod.py Tue Jun 27 00:10:41 2006 -0700
@@ -59,8 +59,7 @@
"footer": footer})
def archivelist(ui, nodeid, url):
- allowed = (ui.config("web", "allow_archive", "")
- .replace(",", " ").split())
+ allowed = ui.configlist("web", "allow_archive")
for i in ['zip', 'gz', 'bz2']:
if i in allowed or ui.configbool("web", "allow" + i):
yield {"type" : i, "node": nodeid, "url": url}
--- a/mercurial/httprepo.py Tue Jun 27 00:09:37 2006 -0700
+++ b/mercurial/httprepo.py Tue Jun 27 00:10:41 2006 -0700
@@ -120,9 +120,8 @@
# see if we should use a proxy for this url
no_list = [ "localhost", "127.0.0.1" ]
- no_list.extend([p.strip().lower() for
- p in ui.config("http_proxy", "no", '').split(',')
- if p.strip()])
+ no_list.extend([p.lower() for
+ p in ui.configlist("http_proxy", "no")])
no_list.extend([p.strip().lower() for
p in os.getenv("no_proxy", '').split(',')
if p.strip()])
--- a/mercurial/localrepo.py Tue Jun 27 00:09:37 2006 -0700
+++ b/mercurial/localrepo.py Tue Jun 27 00:10:41 2006 -0700
@@ -619,7 +619,7 @@
modified, added, removed, deleted, unknown, ignored = [],[],[],[],[],[]
compareworking = False
- if not node1 or node1 == self.dirstate.parents()[0]:
+ if not node1 or (not node2 and node1 == self.dirstate.parents()[0]):
compareworking = True
if not compareworking:
--- a/mercurial/lsprof.py Tue Jun 27 00:09:37 2006 -0700
+++ b/mercurial/lsprof.py Tue Jun 27 00:10:41 2006 -0700
@@ -4,7 +4,13 @@
# small modifications made
import sys
-from _lsprof import Profiler, profiler_entry, profiler_subentry
+try:
+ from _lsprof import Profiler, profiler_entry, profiler_subentry
+except ImportError, inst:
+ import packagescan
+ if packagescan.scan_in_progress:
+ raise packagescan.SkipPackage('_lsprof not available')
+ raise
__all__ = ['profile', 'Stats']
--- a/mercurial/packagescan.py Tue Jun 27 00:09:37 2006 -0700
+++ b/mercurial/packagescan.py Tue Jun 27 00:10:41 2006 -0700
@@ -60,8 +60,16 @@
if type(scope[f]) == types.ModuleType:
requiredmodules[scope[f].__name__] = 1
+class SkipPackage(Exception):
+ def __init__(self, reason):
+ self.reason = reason
+
+scan_in_progress = False
+
def scan(libpath,packagename):
""" helper for finding all required modules of package <packagename> """
+ global scan_in_progress
+ scan_in_progress = True
# Use the package in the build directory
libpath = os.path.abspath(libpath)
sys.path.insert(0,libpath)
@@ -85,7 +93,11 @@
tmp = {}
mname,ext = os.path.splitext(m)
fullname = packagename+'.'+mname
- __import__(fullname,tmp,tmp)
+ try:
+ __import__(fullname,tmp,tmp)
+ except SkipPackage, inst:
+ print >> sys.stderr, 'skipping %s: %s' % (fullname, inst.reason)
+ continue
requiredmodules[fullname] = 1
# Import all extension modules and by that run the fake demandload
for m in extmodulefiles:
--- a/mercurial/revlog.py Tue Jun 27 00:09:37 2006 -0700
+++ b/mercurial/revlog.py Tue Jun 27 00:10:41 2006 -0700
@@ -477,6 +477,13 @@
if self.version == REVLOGV0:
return d
return [ self.node(x) for x in d ]
+ def parentrevs(self, rev):
+ if rev == -1:
+ return (-1, -1)
+ d = self.index[rev][-3:-1]
+ if self.version == REVLOGV0:
+ return [ self.rev(x) for x in d ]
+ return d
def start(self, rev):
if rev < 0:
return -1
@@ -706,19 +713,19 @@
"""
if start is None:
start = nullid
- reachable = {start: 1}
- heads = {start: 1}
startrev = self.rev(start)
+ reachable = {startrev: 1}
+ heads = {startrev: 1}
+ parentrevs = self.parentrevs
for r in xrange(startrev + 1, self.count()):
- n = self.node(r)
- for pn in self.parents(n):
- if pn in reachable:
- reachable[n] = 1
- heads[n] = 1
- if pn in heads:
- del heads[pn]
- return heads.keys()
+ for p in parentrevs(r):
+ if p in reachable:
+ reachable[r] = 1
+ heads[r] = 1
+ if p in heads:
+ del heads[p]
+ return [self.node(r) for r in heads]
def children(self, node):
"""find the children of a given node"""
--- a/mercurial/ui.py Tue Jun 27 00:09:37 2006 -0700
+++ b/mercurial/ui.py Tue Jun 27 00:10:41 2006 -0700
@@ -95,6 +95,15 @@
else:
return self.parentui.config(section, name, default)
+ def configlist(self, section, name, default=None):
+ """Return a list of comma/space separated strings"""
+ result = self.config(section, name)
+ if result is None:
+ result = default or []
+ if isinstance(result, basestring):
+ result = result.replace(",", " ").split()
+ return result
+
def configbool(self, section, name, default=False):
if self.overlay.has_key((section, name)):
return self.overlay[(section, name)]
@@ -197,12 +206,15 @@
if not self.verbose: user = util.shortuser(user)
return user
- def expandpath(self, loc):
+ def expandpath(self, loc, default=None):
"""Return repository location relative to cwd or from [paths]"""
if loc.find("://") != -1 or os.path.exists(loc):
return loc
- return self.config("paths", loc, loc)
+ path = self.config("paths", loc)
+ if not path and default is not None:
+ path = self.config("paths", default)
+ return path or loc
def write(self, *args):
if self.header:
--- a/tests/test-archive Tue Jun 27 00:09:37 2006 -0700
+++ b/tests/test-archive Tue Jun 27 00:10:41 2006 -0700
@@ -15,9 +15,7 @@
hg commit -m 3
echo "[web]" >> .hg/hgrc
echo "name = test-archive" >> .hg/hgrc
-echo "allowzip = true" >> .hg/hgrc
-echo "allowgz = true" >> .hg/hgrc
-echo "allowbz2 = true" >> .hg/hgrc
+echo "allow_archive = gz bz2, zip" >> .hg/hgrc
hg serve -p 20059 -d --pid-file=hg.pid
TIP=`hg id -v | cut -f1 -d' '`
--- a/tests/test-backout Tue Jun 27 00:09:37 2006 -0700
+++ b/tests/test-backout Tue Jun 27 00:10:41 2006 -0700
@@ -48,4 +48,16 @@
hg commit -d '4 0' -m d
cat a
+echo '# backout should not back out subsequent changesets'
+hg init onecs
+cd onecs
+echo 1 > a
+hg commit -d '0 0' -A -m a
+echo 2 >> a
+hg commit -d '1 0' -m b
+echo 1 > b
+hg commit -d '2 0' -A -m c
+hg backout -d '3 0' 1
+hg locate b
+
exit 0
--- a/tests/test-backout.out Tue Jun 27 00:09:37 2006 -0700
+++ b/tests/test-backout.out Tue Jun 27 00:10:41 2006 -0700
@@ -21,3 +21,11 @@
0 files updated, 1 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
line 1
+# backout should not back out subsequent changesets
+adding a
+adding b
+reverting a
+changeset 3:4cbb1e70196a backs out changeset 1:22bca4c721e5
+the backout changeset is a new head - do not forget to merge
+(use "backout -m" if you want to auto-merge)
+b: No such file or directory
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-default-push Tue Jun 27 00:10:41 2006 -0700
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+hg init a
+echo a > a/a
+hg --cwd a ci -Ama
+
+hg clone a c
+
+hg clone a b
+echo b >> b/a
+hg --cwd b ci -mb
+
+echo % push should push to default when default-push not set
+hg --cwd b push | sed 's/pushing to.*/pushing/'
+
+echo % push should push to default-push when set
+echo 'default-push = ../c' >> b/.hg/hgrc
+hg --cwd b push | sed 's/pushing to.*/pushing/'
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-default-push.out Tue Jun 27 00:10:41 2006 -0700
@@ -0,0 +1,17 @@
+adding a
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% push should push to default when default-push not set
+pushing
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 1 changes to 1 files
+% push should push to default-push when set
+pushing
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 1 changes to 1 files
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-ui-config Tue Jun 27 00:10:41 2006 -0700
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+
+from mercurial import ui
+
+testui = ui.ui()
+testui.updateopts(config=[
+ 'values.string=string value',
+ 'values.bool1=true',
+ 'values.bool2=false',
+ 'lists.list1=foo',
+ 'lists.list2=foo bar baz',
+ 'lists.list3=alice, bob',
+ 'lists.list4=foo bar baz alice, bob',
+])
+
+print repr(testui.configitems('values'))
+print repr(testui.configitems('lists'))
+print "---"
+print repr(testui.config('values', 'string'))
+print repr(testui.config('values', 'bool1'))
+print repr(testui.config('values', 'bool2'))
+print repr(testui.config('values', 'unknown'))
+print "---"
+try:
+ print repr(testui.configbool('values', 'string'))
+except ValueError, why:
+ print why
+print repr(testui.configbool('values', 'bool1'))
+print repr(testui.configbool('values', 'bool2'))
+print repr(testui.configbool('values', 'bool2', True))
+print repr(testui.configbool('values', 'unknown'))
+print repr(testui.configbool('values', 'unknown', True))
+print "---"
+print repr(testui.configlist('lists', 'list1'))
+print repr(testui.configlist('lists', 'list2'))
+print repr(testui.configlist('lists', 'list3'))
+print repr(testui.configlist('lists', 'list4'))
+print repr(testui.configlist('lists', 'list4', ['foo']))
+print repr(testui.configlist('lists', 'unknown'))
+print repr(testui.configlist('lists', 'unknown', ''))
+print repr(testui.configlist('lists', 'unknown', 'foo'))
+print repr(testui.configlist('lists', 'unknown', ['foo']))
+print repr(testui.configlist('lists', 'unknown', 'foo bar'))
+print repr(testui.configlist('lists', 'unknown', 'foo, bar'))
+print repr(testui.configlist('lists', 'unknown', ['foo bar']))
+print repr(testui.configlist('lists', 'unknown', ['foo', 'bar']))
+print "---"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-ui-config.out Tue Jun 27 00:10:41 2006 -0700
@@ -0,0 +1,29 @@
+[('bool1', 'true'), ('bool2', 'false'), ('string', 'string value')]
+[('list1', 'foo'), ('list2', 'foo bar baz'), ('list3', 'alice, bob'), ('list4', 'foo bar baz alice, bob')]
+---
+'string value'
+'true'
+'false'
+None
+---
+Not a boolean: string value
+True
+False
+False
+False
+True
+---
+['foo']
+['foo', 'bar', 'baz']
+['alice', 'bob']
+['foo', 'bar', 'baz', 'alice', 'bob']
+['foo', 'bar', 'baz', 'alice', 'bob']
+[]
+[]
+['foo']
+['foo']
+['foo', 'bar']
+['foo', 'bar']
+['foo bar']
+['foo', 'bar']
+---