# HG changeset patch # User Matt Mackall # Date 1308343430 18000 # Node ID d89f8089817897b1cc3d032e4ba228499bb22319 # Parent 0ae98cd2a83f7879c47a54eb7421fc307380bf27# Parent 71b9c29eb44a13366cad95131415f710e848d641 merge with i18n diff -r 71b9c29eb44a -r d89f80898178 doc/hgmanpage.py --- a/doc/hgmanpage.py Wed Jun 15 10:40:23 2011 +0200 +++ b/doc/hgmanpage.py Fri Jun 17 15:43:50 2011 -0500 @@ -48,6 +48,7 @@ from docutils import nodes, writers, languages import roman +import inspect FIELD_LIST_INDENT = 7 DEFINITION_LIST_INDENT = 7 @@ -160,7 +161,12 @@ nodes.NodeVisitor.__init__(self, document) self.settings = settings = document.settings lcode = settings.language_code - self.language = languages.get_language(lcode) + arglen = len(inspect.getargspec(languages.get_language)[0]) + if arglen == 2: + self.language = languages.get_language(lcode, + self.document.reporter) + else: + self.language = languages.get_language(lcode) self.head = [] self.body = [] self.foot = [] diff -r 71b9c29eb44a -r d89f80898178 hgext/fetch.py --- a/hgext/fetch.py Wed Jun 15 10:40:23 2011 +0200 +++ b/hgext/fetch.py Fri Jun 17 15:43:50 2011 -0500 @@ -122,7 +122,7 @@ if not err: # we don't translate commit messages - message = (cmdutil.logmessage(opts) or + message = (cmdutil.logmessage(ui, opts) or ('Automated merge with %s' % util.removeauth(other.url()))) editor = cmdutil.commiteditor diff -r 71b9c29eb44a -r d89f80898178 hgext/mq.py --- a/hgext/mq.py Wed Jun 15 10:40:23 2011 +0200 +++ b/hgext/mq.py Fri Jun 17 15:43:50 2011 -0500 @@ -48,7 +48,7 @@ from mercurial import commands, cmdutil, hg, scmutil, util, revset from mercurial import repair, extensions, url, error from mercurial import patch as patchmod -import os, sys, re, errno, shutil +import os, re, errno, shutil commands.norepo += " qclone" @@ -1831,7 +1831,7 @@ self.checkpatchname(patchname, force) try: if filename == '-': - text = sys.stdin.read() + text = self.ui.fin.read() else: fp = url.open(self.ui, filename) text = fp.read() @@ -2211,7 +2211,7 @@ Returns 0 on successful creation of a new patch. """ - msg = cmdutil.logmessage(opts) + msg = cmdutil.logmessage(ui, opts) def getmsg(): return ui.edit(msg, opts.get('user') or ui.username()) q = repo.mq @@ -2262,7 +2262,7 @@ Returns 0 on success. """ q = repo.mq - message = cmdutil.logmessage(opts) + message = cmdutil.logmessage(ui, opts) if opts.get('edit'): if not q.applied: ui.write(_("no patches applied\n")) @@ -2332,7 +2332,7 @@ raise util.Abort(_('no patches applied')) q.checklocalchanges(repo) - message = cmdutil.logmessage(opts) + message = cmdutil.logmessage(ui, opts) if opts.get('edit'): if message: raise util.Abort(_('option "-e" incompatible with "-m" or "-l"')) @@ -2661,7 +2661,7 @@ This command is deprecated, use :hg:`rebase` instead.""" q = repo.mq - message = cmdutil.logmessage(opts) + message = cmdutil.logmessage(ui, opts) ret = q.save(repo, msg=message) if ret: return ret diff -r 71b9c29eb44a -r d89f80898178 hgext/rebase.py --- a/hgext/rebase.py Wed Jun 15 10:40:23 2011 +0200 +++ b/hgext/rebase.py Fri Jun 17 15:43:50 2011 -0500 @@ -117,7 +117,7 @@ contf = opts.get('continue') abortf = opts.get('abort') collapsef = opts.get('collapse', False) - collapsemsg = cmdutil.logmessage(opts) + collapsemsg = cmdutil.logmessage(ui, opts) extrafn = opts.get('extrafn') # internal, used by e.g. hgsubversion keepf = opts.get('keep', False) keepbranchesf = opts.get('keepbranches', False) diff -r 71b9c29eb44a -r d89f80898178 i18n/pt_BR.po --- a/i18n/pt_BR.po Wed Jun 15 10:40:23 2011 +0200 +++ b/i18n/pt_BR.po Fri Jun 17 15:43:50 2011 -0500 @@ -4817,8 +4817,8 @@ msgid "only a local queue repository may be initialized" msgstr "apenas um repositório de fila local pode ser inicializado" -msgid "there is no Mercurial repository here (.hg not found)" -msgstr "não há um repositório do Mercurial aqui (.hg não encontrado)" +msgid "no repository found in %r (.hg not found)" +msgstr "não foi encontrado um repositório em %r (.hg não encontrado)" msgid "no queue repository" msgstr "repositório da fila não existente" diff -r 71b9c29eb44a -r d89f80898178 mercurial/changelog.py --- a/mercurial/changelog.py Wed Jun 15 10:40:23 2011 +0200 +++ b/mercurial/changelog.py Fri Jun 17 15:43:50 2011 -0500 @@ -107,6 +107,8 @@ self._realopener = opener self._delayed = False self._divert = False + # hiddenrevs: revs that should be hidden by command and tools + self.hiddenrevs = set() def delayupdate(self): "delay visibility of index updates to other readers" diff -r 71b9c29eb44a -r d89f80898178 mercurial/cmdutil.py --- a/mercurial/cmdutil.py Wed Jun 15 10:40:23 2011 +0200 +++ b/mercurial/cmdutil.py Fri Jun 17 15:43:50 2011 -0500 @@ -76,7 +76,7 @@ if modified or added or removed or deleted: raise util.Abort(_("outstanding uncommitted changes")) -def logmessage(opts): +def logmessage(ui, opts): """ get the log message according to -m and -l option """ message = opts.get('message') logfile = opts.get('logfile') @@ -87,7 +87,7 @@ if not message and logfile: try: if logfile == '-': - message = sys.stdin.read() + message = ui.fin.read() else: message = '\n'.join(util.readfile(logfile).splitlines()) except IOError, inst: @@ -160,8 +160,23 @@ writable = mode not in ('r', 'rb') if not pat or pat == '-': - fp = writable and sys.stdout or sys.stdin - return os.fdopen(os.dup(fp.fileno()), mode) + fp = writable and repo.ui.fout or repo.ui.fin + if hasattr(fp, 'fileno'): + return os.fdopen(os.dup(fp.fileno()), mode) + else: + # if this fp can't be duped properly, return + # a dummy object that can be closed + class wrappedfileobj(object): + noop = lambda x: None + def __init__(self, f): + self.f = f + def __getattr__(self, attr): + if attr == 'close': + return self.noop + else: + return getattr(self.f, attr) + + return wrappedfileobj(fp) if hasattr(pat, 'write') and writable: return pat if hasattr(pat, 'read') and 'r' in mode: @@ -1163,7 +1178,7 @@ date = opts.get('date') if date: opts['date'] = util.parsedate(date) - message = logmessage(opts) + message = logmessage(ui, opts) # extract addremove carefully -- this function can be called from a command # that doesn't support addremove diff -r 71b9c29eb44a -r d89f80898178 mercurial/commands.py --- a/mercurial/commands.py Wed Jun 15 10:40:23 2011 +0200 +++ b/mercurial/commands.py Fri Jun 17 15:43:50 2011 -0500 @@ -8,10 +8,11 @@ from node import hex, bin, nullid, nullrev, short from lock import release from i18n import _, gettext -import os, re, sys, difflib, time, tempfile, errno +import os, re, difflib, time, tempfile, errno import hg, scmutil, util, revlog, extensions, copies, error, bookmarks import patch, help, url, encoding, templatekw, discovery -import archival, changegroup, cmdutil, sshserver, hbisect, hgweb, hgweb.server +import archival, changegroup, cmdutil, hbisect +import sshserver, hgweb, hgweb.server, commandserver import merge as mergemod import minirst, revset, fileset import dagparser, context, simplemerge @@ -336,7 +337,7 @@ if dest == '-': if kind == 'files': raise util.Abort(_('cannot archive plain files to stdout')) - dest = sys.stdout + dest = ui.fout if not prefix: prefix = os.path.basename(repo.root) + '-%h' @@ -765,6 +766,12 @@ Use the command :hg:`update` to switch to an existing branch. Use :hg:`commit --close-branch` to mark this branch as closed. + .. note:: + + Branch names are permanent. Use :hg:`bookmark` to create a + light-weight bookmark instead. See :hg:`help glossary` for more + information about named branches and bookmarks. + Returns 0 on success. """ @@ -1226,7 +1233,7 @@ if text is None: ui.status(_("reading DAG from stdin\n")) - text = sys.stdin.read() + text = ui.fin.read() cl = repo.changelog if len(cl) > 0: @@ -3091,7 +3098,7 @@ commitid = _('to working directory') try: - cmdline_message = cmdutil.logmessage(opts) + cmdline_message = cmdutil.logmessage(ui, opts) if cmdline_message: # pickup the cmdline msg message = cmdline_message @@ -3188,7 +3195,7 @@ if pf == '-': ui.status(_("applying patch from stdin\n")) - pf = sys.stdin + pf = ui.fin else: ui.status(_("applying %s\n") % p) pf = url.open(ui, pf) @@ -3339,6 +3346,7 @@ _('show changesets within the given named branch'), _('BRANCH')), ('P', 'prune', [], _('do not display revision or any of its ancestors'), _('REV')), + ('h', 'hidden', False, _('show hidden changesets')), ] + logopts + walkopts, _('[OPTION]... [FILE]')) def log(ui, repo, *pats, **opts): @@ -3400,6 +3408,8 @@ return if opts.get('branch') and ctx.branch() not in opts['branch']: return + if not opts.get('hidden') and ctx.hidden(): + return if df and not df(ctx.date()[0]): return if opts['user'] and not [k for k in opts['user'] @@ -4409,6 +4419,7 @@ _('FILE')), ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')), ('', 'stdio', None, _('for remote clients')), + ('', 'cmdserver', '', _('for remote clients'), _('MODE')), ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')), ('', 'style', '', _('template style to use'), _('STYLE')), ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')), @@ -4439,13 +4450,24 @@ Returns 0 on success. """ - if opts["stdio"]: + if opts["stdio"] and opts["cmdserver"]: + raise util.Abort(_("cannot use --stdio with --cmdserver")) + + def checkrepo(): if repo is None: raise error.RepoError(_("There is no Mercurial repository here" " (.hg not found)")) + + if opts["stdio"]: + checkrepo() s = sshserver.sshserver(ui, repo) s.serve_forever() + if opts["cmdserver"]: + checkrepo() + s = commandserver.server(ui, repo, opts["cmdserver"]) + return s.serve() + # this way we can check if something was given in the command-line if opts.get('port'): opts['port'] = util.getport(opts.get('port')) diff -r 71b9c29eb44a -r d89f80898178 mercurial/commandserver.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial/commandserver.py Fri Jun 17 15:43:50 2011 -0500 @@ -0,0 +1,213 @@ +# commandserver.py - communicate with Mercurial's API over a pipe +# +# Copyright Matt Mackall +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2 or any later version. + +from i18n import _ +import struct +import sys +import dispatch, encoding, util + +logfile = None + +def log(*args): + if not logfile: + return + + for a in args: + logfile.write(str(a)) + + logfile.flush() + +class channeledoutput(object): + """ + Write data from in_ to out in the following format: + + data length (unsigned int), + data + """ + def __init__(self, in_, out, channel): + self.in_ = in_ + self.out = out + self.channel = channel + + def write(self, data): + if not data: + return + self.out.write(struct.pack('>cI', self.channel, len(data))) + self.out.write(data) + self.out.flush() + + def __getattr__(self, attr): + if attr in ('isatty', 'fileno'): + raise AttributeError, attr + return getattr(self.in_, attr) + +class channeledinput(object): + """ + Read data from in_. + + Requests for input are written to out in the following format: + channel identifier - 'I' for plain input, 'L' line based (1 byte) + how many bytes to send at most (unsigned int), + + The client replies with: + data length (unsigned int), 0 meaning EOF + data + """ + + maxchunksize = 4 * 1024 + + def __init__(self, in_, out, channel): + self.in_ = in_ + self.out = out + self.channel = channel + + def read(self, size=-1): + if size < 0: + # if we need to consume all the clients input, ask for 4k chunks + # so the pipe doesn't fill up risking a deadlock + size = self.maxchunksize + s = self._read(size, self.channel) + buf = s + while s: + buf += s + s = self._read(size, self.channel) + + return buf + else: + return self._read(size, self.channel) + + def _read(self, size, channel): + if not size: + return '' + assert size > 0 + + # tell the client we need at most size bytes + self.out.write(struct.pack('>cI', channel, size)) + self.out.flush() + + length = self.in_.read(4) + length = struct.unpack('>I', length)[0] + if not length: + return '' + else: + return self.in_.read(length) + + def readline(self, size=-1): + if size < 0: + size = self.maxchunksize + s = self._read(size, 'L') + buf = s + # keep asking for more until there's either no more or + # we got a full line + while s and s[-1] != '\n': + buf += s + s = self._read(size, 'L') + + return buf + else: + return self._read(size, 'L') + + def __iter__(self): + return self + + def next(self): + l = self.readline() + if not l: + raise StopIteration + return l + + def __getattr__(self, attr): + if attr in ('isatty', 'fileno'): + raise AttributeError, attr + return getattr(self.in_, attr) + +class server(object): + """ + Listens for commands on stdin, runs them and writes the output on a channel + based stream to stdout. + """ + def __init__(self, ui, repo, mode): + self.ui = ui + + logpath = ui.config("cmdserver", "log", None) + if logpath: + global logfile + if logpath == '-': + # write log on a special 'd'ebug channel + logfile = channeledoutput(sys.stdout, sys.stdout, 'd') + else: + logfile = open(logpath, 'a') + + self.repo = repo + + if mode == 'pipe': + self.cerr = channeledoutput(sys.stderr, sys.stdout, 'e') + self.cout = channeledoutput(sys.stdout, sys.stdout, 'o') + self.cin = channeledinput(sys.stdin, sys.stdout, 'I') + self.cresult = channeledoutput(sys.stdout, sys.stdout, 'r') + + self.client = sys.stdin + else: + raise util.Abort(_('unknown mode %s') % mode) + + def _read(self, size): + data = self.client.read(size) + + # is the other end closed? + if not data: + raise EOFError() + + return data + + def runcommand(self): + """ reads a list of \0 terminated arguments, executes + and writes the return code to the result channel """ + + length = struct.unpack('>I', self._read(4))[0] + args = self._read(length).split('\0') + + # copy the ui so changes to it don't persist between requests + req = dispatch.request(args, self.ui.copy(), self.repo, self.cin, + self.cout, self.cerr) + + ret = dispatch.dispatch(req) or 0 # might return None + + self.cresult.write(struct.pack('>i', int(ret))) + + def getencoding(self): + """ writes the current encoding to the result channel """ + self.cresult.write(encoding.encoding) + + def serveone(self): + cmd = self.client.readline()[:-1] + if cmd: + handler = self.capabilities.get(cmd) + if handler: + handler(self) + else: + # clients are expected to check what commands are supported by + # looking at the servers capabilities + raise util.Abort(_('unknown command %s') % cmd) + + return cmd != '' + + capabilities = {'runcommand' : runcommand, + 'getencoding' : getencoding} + + def serve(self): + self.cout.write('capabilities: %s' % ' '.join(self.capabilities.keys())) + self.cout.write('encoding: %s' % encoding.encoding) + + try: + while self.serveone(): + pass + except EOFError: + # we'll get here if the client disconnected while we were reading + # its request + return 1 + + return 0 diff -r 71b9c29eb44a -r d89f80898178 mercurial/config.py --- a/mercurial/config.py Wed Jun 15 10:40:23 2011 +0200 +++ b/mercurial/config.py Fri Jun 17 15:43:50 2011 -0500 @@ -75,6 +75,7 @@ itemre = re.compile(r'([^=\s][^=]*?)\s*=\s*(.*\S|)') contre = re.compile(r'\s+(\S|\S.*\S)\s*$') emptyre = re.compile(r'(;|#|\s*$)') + commentre = re.compile(r'(;|#)') unsetre = re.compile(r'%unset\s+(\S+)') includere = re.compile(r'%include\s+(\S|\S.*\S)\s*$') section = "" @@ -85,6 +86,8 @@ for l in data.splitlines(True): line += 1 if cont: + if commentre.match(l): + continue m = contre.match(l) if m: if sections and section not in sections: diff -r 71b9c29eb44a -r d89f80898178 mercurial/context.py --- a/mercurial/context.py Wed Jun 15 10:40:23 2011 +0200 +++ b/mercurial/context.py Fri Jun 17 15:43:50 2011 -0500 @@ -116,6 +116,8 @@ return self._repo.nodetags(self._node) def bookmarks(self): return self._repo.nodebookmarks(self._node) + def hidden(self): + return self._rev in self._repo.changelog.hiddenrevs def parents(self): """return contexts for each parent changeset""" diff -r 71b9c29eb44a -r d89f80898178 mercurial/dagutil.py --- a/mercurial/dagutil.py Wed Jun 15 10:40:23 2011 +0200 +++ b/mercurial/dagutil.py Fri Jun 17 15:43:50 2011 -0500 @@ -7,6 +7,7 @@ # GNU General Public License version 2 or any later version. from node import nullrev +from i18n import _ class basedag(object): diff -r 71b9c29eb44a -r d89f80898178 mercurial/dispatch.py --- a/mercurial/dispatch.py Wed Jun 15 10:40:23 2011 +0200 +++ b/mercurial/dispatch.py Fri Jun 17 15:43:50 2011 -0500 @@ -276,7 +276,7 @@ replace['0'] = self.name replace['@'] = ' '.join(args) cmd = util.interpolate(r'\$', replace, cmd, escape_prefix=True) - return util.system(cmd, environ=env) + return util.system(cmd, environ=env, out=ui.fout) self.fn = fn return diff -r 71b9c29eb44a -r d89f80898178 mercurial/help/config.txt --- a/mercurial/help/config.txt Wed Jun 15 10:40:23 2011 +0200 +++ b/mercurial/help/config.txt Fri Jun 17 15:43:50 2011 -0500 @@ -36,7 +36,7 @@ this file override options in all other configuration files. On Unix, most of this file will be ignored if it doesn't belong to a trusted user or to a trusted group. See the documentation for the - Trusted section below for more details. + ``[trusted]`` section below for more details. | (Unix) ``$HOME/.hgrc`` | (Windows) ``%USERPROFILE%\.hgrc`` @@ -99,7 +99,7 @@ removed from values. Empty lines are skipped. Lines beginning with ``#`` or ``;`` are ignored and may be used to provide comments. -Configuration keys can be set multiple times, in which case mercurial +Configuration keys can be set multiple times, in which case Mercurial will use the value that was configured last. As an example:: [spam] @@ -110,7 +110,8 @@ This would set the configuration key named ``eggs`` to ``small``. It is also possible to define a section multiple times. A section can -be redefined on the same and/or on different hgrc files. For example:: +be redefined on the same and/or on different configuration files. For +example:: [foo] eggs=large @@ -170,8 +171,8 @@ -------- This section describes the different sections that may appear in a -Mercurial "hgrc" file, the purpose of each section, its possible keys, -and their possible values. +Mercurial configuration file, the purpose of each section, its possible +keys, and their possible values. ``alias`` """"""""" @@ -186,7 +187,7 @@ Alias definitions consist of lines of the form:: - = [ = []... For example, this definition:: @@ -227,8 +228,8 @@ Authentication credentials for HTTP authentication. This section allows you to store usernames and passwords for use when logging -*into* HTTP servers. See the web_ configuration section if you want to -configure *who* can login to your HTTP server. +*into* HTTP servers. See the ``[web]`` configuration section if +you want to configure *who* can login to your HTTP server. Each line has the following format:: @@ -403,7 +404,7 @@ ``method`` Optional. Method to use to send email messages. If value is ``smtp`` - (default), use SMTP (see the SMTP_ section for configuration). + (default), use SMTP (see the ``[smtp]`` section for configuration). Otherwise, use as name of program to run that acts like sendmail (takes ``-f`` option for sender, list of recipients on command line, message on stdin). Normally, setting this to ``sendmail`` or @@ -1016,7 +1017,7 @@ option supports hook syntax, so if you want to specify multiple ignore files, you can do so by setting something like ``ignore.other = ~/.hgignore2``. For details of the ignore file - format, see the |hgignore(5)|_ man page. + format, see the ``hgignore(5)`` man page. ``interactive`` Allow to prompt the user. True or False. Default is True. @@ -1027,7 +1028,7 @@ ``merge`` The conflict resolution program to use during a manual merge. For more information on merge tools see :hg:`help merge-tools`. - For configuring merge tools see the merge-tools_ section. + For configuring merge tools see the ``[merge-tools]`` section. ``portablefilenames`` Check for portable filenames. Can be ``warn``, ``ignore`` or ``abort``. diff -r 71b9c29eb44a -r d89f80898178 mercurial/help/glossary.txt --- a/mercurial/help/glossary.txt Wed Jun 15 10:40:23 2011 +0200 +++ b/mercurial/help/glossary.txt Fri Jun 17 15:43:50 2011 -0500 @@ -5,6 +5,18 @@ changeset is an ancestor, and a parent of an ancestor is an ancestor. See also: 'Descendant'. +Bookmark + Bookmarks are pointers to certain commits that move when + committing. They are similar to tags in that it is possible to use + bookmark names in all places where Mercurial expects a changeset + ID, e.g., with :hg:`update`. Unlike tags, bookmarks move along + when you make a commit. + + Bookmarks can be renamed, copied and deleted. Bookmarks are local, + unless they are explicitly pushed or pulled between repositories. + Pushing and pulling bookmarks allow you to collaborate with others + on a branch without creating a named branch. + Branch (Noun) A child changeset that has been created from a parent that is not a head. These are known as topological branches, see @@ -339,6 +351,12 @@ A changeset that has only the null changeset as its parent. Most repositories have only a single root changeset. +Tag + An alternative name given to a changeset. Tags can be used in all + places where Mercurial expects a changeset ID, e.g., with + :hg:`update`. The creation of a tag is stored in the history and + will thus automatically be shared with other using push and pull. + Tip The changeset with the highest revision number. It is the changeset most recently added in a repository. diff -r 71b9c29eb44a -r d89f80898178 mercurial/httprepo.py --- a/mercurial/httprepo.py Wed Jun 15 10:40:23 2011 +0200 +++ b/mercurial/httprepo.py Fri Jun 17 15:43:50 2011 -0500 @@ -191,7 +191,10 @@ try: try: r = self._call(cmd, data=fp, headers=headers, **args) - return r.split('\n', 1) + vals = r.split('\n', 1) + if len(vals) < 2: + raise error.ResponseError(_("unexpected response:"), r) + return vals except socket.error, err: if err.args[0] in (errno.ECONNRESET, errno.EPIPE): raise util.Abort(_('push failed: %s') % err.args[1]) diff -r 71b9c29eb44a -r d89f80898178 mercurial/localrepo.py --- a/mercurial/localrepo.py Wed Jun 15 10:40:23 2011 +0200 +++ b/mercurial/localrepo.py Fri Jun 17 15:43:50 2011 -0500 @@ -272,7 +272,9 @@ try: fp = self.wfile('.hgtags', 'rb+') - except IOError: + except IOError, e: + if e.errno != errno.ENOENT: + raise fp = self.wfile('.hgtags', 'ab') else: prevtags = fp.read() diff -r 71b9c29eb44a -r d89f80898178 mercurial/manifest.py --- a/mercurial/manifest.py Wed Jun 15 10:40:23 2011 +0200 +++ b/mercurial/manifest.py Fri Jun 17 15:43:50 2011 -0500 @@ -142,7 +142,7 @@ # if this is changed to support newlines in filenames, # be sure to check the templates/ dir again (especially *-raw.tmpl) hex, flags = revlog.hex, map.flags - text = ''.join("%s\000%s%s\n" % (f, hex(map[f]), flags(f)) + text = ''.join("%s\0%s%s\n" % (f, hex(map[f]), flags(f)) for f in files) arraytext = array.array('c', text) cachedelta = None @@ -172,7 +172,7 @@ # bs will either be the index of the item or the insert point start, end = self._search(addbuf, f, start) if not todelete: - l = "%s\000%s%s\n" % (f, revlog.hex(map[f]), map.flags(f)) + l = "%s\0%s%s\n" % (f, revlog.hex(map[f]), map.flags(f)) else: if start == end: # item we want to delete was not found, error out diff -r 71b9c29eb44a -r d89f80898178 mercurial/merge.py --- a/mercurial/merge.py Wed Jun 15 10:40:23 2011 +0200 +++ b/mercurial/merge.py Fri Jun 17 15:43:50 2011 -0500 @@ -525,7 +525,7 @@ elif not overwrite: if pa == p1 or pa == p2: # linear pass # all good - elif wc.files() or wc.deleted(): + elif wc.dirty(missing=True): raise util.Abort(_("crosses branches (merge branches or use" " --clean to discard changes)")) elif onode is None: diff -r 71b9c29eb44a -r d89f80898178 mercurial/patch.py --- a/mercurial/patch.py Wed Jun 15 10:40:23 2011 +0200 +++ b/mercurial/patch.py Fri Jun 17 15:43:50 2011 -0500 @@ -487,23 +487,34 @@ return sorted(self.changed) class filestore(object): - def __init__(self): + def __init__(self, maxsize=None): self.opener = None self.files = {} self.created = 0 + self.maxsize = maxsize + if self.maxsize is None: + self.maxsize = 4*(2**20) + self.size = 0 + self.data = {} def setfile(self, fname, data, mode, copied=None): - if self.opener is None: - root = tempfile.mkdtemp(prefix='hg-patch-') - self.opener = scmutil.opener(root) - # Avoid filename issues with these simple names - fn = str(self.created) - self.opener.write(fn, data) - self.created += 1 - self.files[fname] = (fn, mode, copied) + if self.maxsize < 0 or (len(data) + self.size) <= self.maxsize: + self.data[fname] = (data, mode, copied) + self.size += len(data) + else: + if self.opener is None: + root = tempfile.mkdtemp(prefix='hg-patch-') + self.opener = scmutil.opener(root) + # Avoid filename issues with these simple names + fn = str(self.created) + self.opener.write(fn, data) + self.created += 1 + self.files[fname] = (fn, mode, copied) def getfile(self, fname): - if fname not in self.files: + if fname in self.data: + return self.data[fname] + if not self.opener or fname not in self.files: raise IOError() fn, mode, copied = self.files[fname] return self.opener.read(fn), mode, copied diff -r 71b9c29eb44a -r d89f80898178 mercurial/revset.py --- a/mercurial/revset.py Wed Jun 15 10:40:23 2011 +0200 +++ b/mercurial/revset.py Fri Jun 17 15:43:50 2011 -0500 @@ -361,6 +361,19 @@ dm = util.matchdate(ds) return [r for r in subset if dm(repo[r].date()[0])] +def desc(repo, subset, x): + """``desc(string)`` + Search commit message for string. The match is case-insensitive. + """ + # i18n: "desc" is a keyword + ds = getstring(x, _("desc requires a string")).lower() + l = [] + for r in subset: + c = repo[r] + if ds in c.description().lower(): + l.append(r) + return l + def descendants(repo, subset, x): """``descendants(set)`` Changesets which are descendants of changesets in set. @@ -821,6 +834,7 @@ "closed": closed, "contains": contains, "date": date, + "desc": desc, "descendants": descendants, "file": hasfile, "filelog": filelog, @@ -828,22 +842,22 @@ "grep": grep, "head": head, "heads": heads, + "id": node, "keyword": keyword, "last": last, "limit": limit, "max": maxrev, + "merge": merge, "min": minrev, - "merge": merge, "modifies": modifies, - "id": node, "outgoing": outgoing, "p1": p1, "p2": p2, "parents": parents, "present": present, "removes": removes, + "rev": rev, "reverse": reverse, - "rev": rev, "roots": roots, "sort": sort, "tag": tag, @@ -920,7 +934,8 @@ elif op == 'func': f = getstring(x[1], _("not a symbol")) wa, ta = optimize(x[2], small) - if f in "grep date user author keyword branch file outgoing closed": + if f in ("author branch closed date desc file grep keyword " + "outgoing user"): w = 10 # slow elif f in "modifies adds removes": w = 30 # slower diff -r 71b9c29eb44a -r d89f80898178 mercurial/subrepo.py --- a/mercurial/subrepo.py Wed Jun 15 10:40:23 2011 +0200 +++ b/mercurial/subrepo.py Fri Jun 17 15:43:50 2011 -0500 @@ -526,7 +526,7 @@ self._ctx = ctx self._ui = ctx._repo.ui - def _svncommand(self, commands, filename=''): + def _svncommand(self, commands, filename='', failok=False): cmd = ['svn'] extrakw = {} if not self._ui.interactive(): @@ -551,15 +551,16 @@ universal_newlines=True, env=env, **extrakw) stdout, stderr = p.communicate() stderr = stderr.strip() - if p.returncode: - raise util.Abort(stderr or 'exited with code %d' % p.returncode) - if stderr: - self._ui.warn(stderr + '\n') - return stdout + if not failok: + if p.returncode: + raise util.Abort(stderr or 'exited with code %d' % p.returncode) + if stderr: + self._ui.warn(stderr + '\n') + return stdout, stderr @propertycache def _svnversion(self): - output = self._svncommand(['--version'], filename=None) + output, err = self._svncommand(['--version'], filename=None) m = re.search(r'^svn,\s+version\s+(\d+)\.(\d+)', output) if not m: raise util.Abort(_('cannot retrieve svn tool version')) @@ -569,7 +570,7 @@ # Get the working directory revision as well as the last # commit revision so we can compare the subrepo state with # both. We used to store the working directory one. - output = self._svncommand(['info', '--xml']) + output, err = self._svncommand(['info', '--xml']) doc = xml.dom.minidom.parseString(output) entries = doc.getElementsByTagName('entry') lastrev, rev = '0', '0' @@ -588,7 +589,7 @@ if the working directory was changed, and extchanges is True if any of these changes concern an external entry. """ - output = self._svncommand(['status', '--xml']) + output, err = self._svncommand(['status', '--xml']) externals, changes = [], [] doc = xml.dom.minidom.parseString(output) for e in doc.getElementsByTagName('entry'): @@ -623,13 +624,13 @@ if extchanged: # Do not try to commit externals raise util.Abort(_('cannot commit svn externals')) - commitinfo = self._svncommand(['commit', '-m', text]) + commitinfo, err = self._svncommand(['commit', '-m', text]) self._ui.status(commitinfo) newrev = re.search('Committed revision ([0-9]+).', commitinfo) if not newrev: raise util.Abort(commitinfo.splitlines()[-1]) newrev = newrev.groups()[0] - self._ui.status(self._svncommand(['update', '-r', newrev])) + self._ui.status(self._svncommand(['update', '-r', newrev])[0]) return newrev def remove(self): @@ -663,9 +664,15 @@ if self._svnversion >= (1, 5): args.append('--force') args.extend([state[0], '--revision', state[1]]) - status = self._svncommand(args) + status, err = self._svncommand(args, failok=True) if not re.search('Checked out revision [0-9]+.', status): - raise util.Abort(status.splitlines()[-1]) + if ('is already a working copy for a different URL' in err + and (self._wcchanged() == (False, False))): + # obstructed but clean working copy, so just blow it away. + self.remove() + self.get(state, overwrite=False) + return + raise util.Abort((status or err).splitlines()[-1]) self._ui.status(status) def merge(self, state): diff -r 71b9c29eb44a -r d89f80898178 mercurial/tags.py --- a/mercurial/tags.py Wed Jun 15 10:40:23 2011 +0200 +++ b/mercurial/tags.py Fri Jun 17 15:43:50 2011 -0500 @@ -286,4 +286,7 @@ for (name, (node, hist)) in cachetags.iteritems(): cachefile.write("%s %s\n" % (hex(node), name)) - cachefile.rename() + try: + cachefile.rename() + except (OSError, IOError): + pass diff -r 71b9c29eb44a -r d89f80898178 mercurial/util.py --- a/mercurial/util.py Wed Jun 15 10:40:23 2011 +0200 +++ b/mercurial/util.py Fri Jun 17 15:43:50 2011 -0500 @@ -354,7 +354,7 @@ env = dict(os.environ) env.update((k, py2shell(v)) for k, v in environ.iteritems()) env['HG'] = hgexecutable() - if out is None: + if out is None or out == sys.__stdout__: rc = subprocess.call(cmd, shell=True, close_fds=closefds, env=env, cwd=cwd) else: diff -r 71b9c29eb44a -r d89f80898178 tests/test-debugcomplete.t --- a/tests/test-debugcomplete.t Wed Jun 15 10:40:23 2011 +0200 +++ b/tests/test-debugcomplete.t Fri Jun 17 15:43:50 2011 -0500 @@ -137,6 +137,7 @@ --accesslog --address --certificate + --cmdserver --config --cwd --daemon @@ -194,12 +195,12 @@ export: output, switch-parent, rev, text, git, nodates forget: include, exclude init: ssh, remotecmd, insecure - log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, patch, git, limit, no-merges, stat, style, template, include, exclude + log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, hidden, patch, git, limit, no-merges, stat, style, template, include, exclude merge: force, tool, rev, preview pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure remove: after, force, include, exclude - serve: accesslog, daemon, daemon-pipefds, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, templates, style, ipv6, certificate + serve: accesslog, daemon, daemon-pipefds, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos summary: remote update: clean, check, date, rev diff -r 71b9c29eb44a -r d89f80898178 tests/test-http-branchmap.t --- a/tests/test-http-branchmap.t Wed Jun 15 10:40:23 2011 +0200 +++ b/tests/test-http-branchmap.t Fri Jun 17 15:43:50 2011 -0500 @@ -79,7 +79,7 @@ > > myui = ui.ui() > repo = hg.repository(myui, 'a') - > commands.serve(myui, repo, stdio=True) + > commands.serve(myui, repo, stdio=True, cmdserver=False) > EOF $ echo baz >> b/foo $ hg -R b ci -m baz diff -r 71b9c29eb44a -r d89f80898178 tests/test-i18n.t --- a/tests/test-i18n.t Wed Jun 15 10:40:23 2011 +0200 +++ b/tests/test-i18n.t Fri Jun 17 15:43:50 2011 -0500 @@ -8,17 +8,17 @@ using the "replace" error handler: $ LANGUAGE=pt_BR hg tip - abortado: no repository found in '$TESTTMP' (.hg not found)! + abortado: n?o foi encontrado um reposit?rio em '$TESTTMP' (.hg n?o encontrado)! [255] Using a more accomodating encoding: $ HGENCODING=UTF-8 LANGUAGE=pt_BR hg tip - abortado: no repository found in '$TESTTMP' (.hg not found)! + abortado: n\xc3\xa3o foi encontrado um reposit\xc3\xb3rio em '$TESTTMP' (.hg n\xc3\xa3o encontrado)! (esc) [255] Different encoding: $ HGENCODING=Latin-1 LANGUAGE=pt_BR hg tip - abortado: no repository found in '$TESTTMP' (.hg not found)! + abortado: n\xe3o foi encontrado um reposit\xf3rio em '$TESTTMP' (.hg n\xe3o encontrado)! (esc) [255] diff -r 71b9c29eb44a -r d89f80898178 tests/test-log.t --- a/tests/test-log.t Wed Jun 15 10:40:23 2011 +0200 +++ b/tests/test-log.t Fri Jun 17 15:43:50 2011 -0500 @@ -1138,3 +1138,21 @@ date: Thu Jan 01 00:00:00 1970 +0000 summary: a + $ cat > $HGTMP/testhidden.py << EOF + > def reposetup(ui, repo): + > for line in repo.opener('hidden'): + > ctx = repo[line.strip()] + > repo.changelog.hiddenrevs.add(ctx.rev()) + > EOF + $ echo '[extensions]' >> $HGRCPATH + $ echo "hidden=$HGTMP/testhidden.py" >> $HGRCPATH + $ touch .hg/hidden + $ hg log --template='{rev}:{node}\n' + 1:a765632148dc55d38c35c4f247c618701886cb2f + 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05 + $ echo a765632148dc55d38c35c4f247c618701886cb2f > .hg/hidden + $ hg log --template='{rev}:{node}\n' + 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05 + $ hg log --template='{rev}:{node}\n' --hidden + 1:a765632148dc55d38c35c4f247c618701886cb2f + 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05 diff -r 71b9c29eb44a -r d89f80898178 tests/test-revset.t --- a/tests/test-revset.t Wed Jun 15 10:40:23 2011 +0200 +++ b/tests/test-revset.t Fri Jun 17 15:43:50 2011 -0500 @@ -190,6 +190,8 @@ 1 3 5 + $ log 'desc(B)' + 5 $ log 'descendants(2 or 3)' 2 3 diff -r 71b9c29eb44a -r d89f80898178 tests/test-subrepo-svn.t --- a/tests/test-subrepo-svn.t Wed Jun 15 10:40:23 2011 +0200 +++ b/tests/test-subrepo-svn.t Fri Jun 17 15:43:50 2011 -0500 @@ -489,3 +489,33 @@ $ if "$TESTDIR/hghave" -q svn15; then > hg up 2 >/dev/null 2>&1 || echo update failed > fi + +Modify one of the externals to point to a different path so we can +test having obstructions when switching branches on checkout: + $ hg checkout tip + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ echo "obstruct = [svn] $SVNREPO/externals" >> .hgsub + $ svn co -r5 --quiet "$SVNREPO"/externals obstruct + $ hg commit -m 'Start making obstructed wc' + committing subrepository obstruct + $ hg book other + $ hg co -r 'p1(tip)' + 2 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ echo "obstruct = [svn] $SVNREPO/src" >> .hgsub + $ svn co -r5 --quiet "$SVNREPO"/src obstruct + $ hg commit -m 'Other branch which will be obstructed' + committing subrepository obstruct + created new head + +Switching back to the head where we have another path mapped to the +same subrepo should work if the subrepo is clean. + $ hg co other + A $TESTTMP/rebaserepo/obstruct/other + Checked out revision 1. + 2 files updated, 0 files merged, 0 files removed, 0 files unresolved + +This is surprising, but is also correct based on the current code: + $ echo "updating should (maybe) fail" > obstruct/other + $ hg co tip + abort: crosses branches (merge branches or use --clean to discard changes) + [255]