# HG changeset patch # User Vadim Gelfer # Date 1151392241 25200 # Node ID 6350b01d173fe812e3b620549975dc8e485fa9ec # Parent ab460a3f0e3a5690964263d2b9854acea7b6b021# Parent 158d3d2ae070c2197ec393c04a40156e8762669d merge with wsgi changes. diff -r ab460a3f0e3a -r 6350b01d173f hgext/mq.py --- 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""" diff -r ab460a3f0e3a -r 6350b01d173f mercurial/commands.py --- 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']) diff -r ab460a3f0e3a -r 6350b01d173f mercurial/hgweb/hgweb_mod.py --- 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): diff -r ab460a3f0e3a -r 6350b01d173f mercurial/hgweb/hgwebdir_mod.py --- 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} diff -r ab460a3f0e3a -r 6350b01d173f mercurial/httprepo.py --- 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()]) diff -r ab460a3f0e3a -r 6350b01d173f mercurial/localrepo.py --- 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: diff -r ab460a3f0e3a -r 6350b01d173f mercurial/lsprof.py --- 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'] diff -r ab460a3f0e3a -r 6350b01d173f mercurial/packagescan.py --- 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 """ + 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: diff -r ab460a3f0e3a -r 6350b01d173f mercurial/revlog.py --- 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""" diff -r ab460a3f0e3a -r 6350b01d173f mercurial/ui.py --- 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: diff -r ab460a3f0e3a -r 6350b01d173f tests/test-archive --- 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' '` diff -r ab460a3f0e3a -r 6350b01d173f tests/test-backout --- 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 diff -r ab460a3f0e3a -r 6350b01d173f tests/test-backout.out --- 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 diff -r ab460a3f0e3a -r 6350b01d173f tests/test-default-push --- /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/' diff -r ab460a3f0e3a -r 6350b01d173f tests/test-default-push.out --- /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 diff -r ab460a3f0e3a -r 6350b01d173f tests/test-ui-config --- /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 "---" diff -r ab460a3f0e3a -r 6350b01d173f tests/test-ui-config.out --- /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'] +---