Mercurial > hg
changeset 16800:ca025a920fa4
merge with crew
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Wed, 30 May 2012 14:31:39 -0500 |
parents | 977c80123835 (diff) e9ae770eff1c (current diff) |
children | f694ab54b660 |
files | |
diffstat | 9 files changed, 254 insertions(+), 115 deletions(-) [+] |
line wrap: on
line diff
--- a/contrib/hg-ssh Wed May 23 21:34:29 2012 +0200 +++ b/contrib/hg-ssh Wed May 30 14:31:39 2012 -0500 @@ -33,25 +33,31 @@ import sys, os, shlex -cwd = os.getcwd() -allowed_paths = [os.path.normpath(os.path.join(cwd, os.path.expanduser(path))) - for path in sys.argv[1:]] -orig_cmd = os.getenv('SSH_ORIGINAL_COMMAND', '?') -try: - cmdargv = shlex.split(orig_cmd) -except ValueError, e: - sys.stderr.write('Illegal command "%s": %s\n' % (orig_cmd, e)) - sys.exit(255) +def main(): + cwd = os.getcwd() + allowed_paths = [os.path.normpath(os.path.join(cwd, + os.path.expanduser(path))) + for path in sys.argv[1:]] + orig_cmd = os.getenv('SSH_ORIGINAL_COMMAND', '?') + try: + cmdargv = shlex.split(orig_cmd) + except ValueError, e: + sys.stderr.write('Illegal command "%s": %s\n' % (orig_cmd, e)) + sys.exit(255) -if cmdargv[:2] == ['hg', '-R'] and cmdargv[3:] == ['serve', '--stdio']: - path = cmdargv[2] - repo = os.path.normpath(os.path.join(cwd, os.path.expanduser(path))) - if repo in allowed_paths: - dispatch.dispatch(dispatch.request(['-R', repo, 'serve', '--stdio'])) + if cmdargv[:2] == ['hg', '-R'] and cmdargv[3:] == ['serve', '--stdio']: + path = cmdargv[2] + repo = os.path.normpath(os.path.join(cwd, os.path.expanduser(path))) + if repo in allowed_paths: + dispatch.dispatch(dispatch.request(['-R', repo, + 'serve', + '--stdio'])) + else: + sys.stderr.write('Illegal repository "%s"\n' % repo) + sys.exit(255) else: - sys.stderr.write('Illegal repository "%s"\n' % repo) + sys.stderr.write('Illegal command "%s"\n' % orig_cmd) sys.exit(255) -else: - sys.stderr.write('Illegal command "%s"\n' % orig_cmd) - sys.exit(255) +if __name__ == '__main__': + main()
--- a/contrib/perf.py Wed May 23 21:34:29 2012 +0200 +++ b/contrib/perf.py Wed May 30 14:31:39 2012 -0500 @@ -46,8 +46,21 @@ # False)))) timer(lambda: sum(map(len, repo.status()))) +def clearcaches(cl): + # behave somewhat consistently across internal API changes + if util.safehasattr(cl, 'clearcaches'): + cl.clearcaches() + elif util.safehasattr(cl, '_nodecache'): + from mercurial.node import nullid, nullrev + cl._nodecache = {nullid: nullrev} + cl._nodepos = None + def perfheads(ui, repo): - timer(lambda: len(repo.changelog.headrevs())) + cl = repo.changelog + def d(): + len(cl.headrevs()) + clearcaches(cl) + timer(d) def perftags(ui, repo): import mercurial.changelog, mercurial.manifest @@ -72,6 +85,14 @@ del repo.dirstate._dirs timer(d) +def perfdirstatewrite(ui, repo): + ds = repo.dirstate + "a" in ds + def d(): + ds._dirty = True + ds.write() + timer(d) + def perfmanifest(ui, repo): def d(): t = repo.manifest.tip() @@ -126,20 +147,9 @@ mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg n = repo[rev].node() cl = mercurial.revlog.revlog(repo.sopener, "00changelog.i") - # behave somewhat consistently across internal API changes - if util.safehasattr(cl, 'clearcaches'): - clearcaches = cl.clearcaches - elif util.safehasattr(cl, '_nodecache'): - from mercurial.node import nullid, nullrev - def clearcaches(): - cl._nodecache = {nullid: nullrev} - cl._nodepos = None - else: - def clearcaches(): - pass def d(): cl.rev(n) - clearcaches() + clearcaches(cl) timer(d) def perflog(ui, repo, **opts): @@ -218,6 +228,7 @@ 'perftags': (perftags, []), 'perfdirstate': (perfdirstate, []), 'perfdirstatedirs': (perfdirstate, []), + 'perfdirstatewrite': (perfdirstatewrite, []), 'perflog': (perflog, [('', 'rename', False, 'ask log to follow renames')]), 'perftemplating': (perftemplating, []),
--- a/mercurial/commands.py Wed May 23 21:34:29 2012 +0200 +++ b/mercurial/commands.py Wed May 30 14:31:39 2012 -0500 @@ -3089,78 +3089,6 @@ textwidth = min(ui.termwidth(), 80) - 2 - def optrst(options): - data = [] - multioccur = False - for option in options: - if len(option) == 5: - shortopt, longopt, default, desc, optlabel = option - else: - shortopt, longopt, default, desc = option - optlabel = _("VALUE") # default label - - if _("DEPRECATED") in desc and not ui.verbose: - continue - - so = '' - if shortopt: - so = '-' + shortopt - lo = '--' + longopt - if default: - desc += _(" (default: %s)") % default - - if isinstance(default, list): - lo += " %s [+]" % optlabel - multioccur = True - elif (default is not None) and not isinstance(default, bool): - lo += " %s" % optlabel - - data.append((so, lo, desc)) - - rst = minirst.maketable(data, 1) - - if multioccur: - rst += _("\n[+] marked option can be specified multiple times\n") - - return rst - - # list all option lists - def opttext(optlist, width): - rst = '' - if not optlist: - return '' - - for title, options in optlist: - rst += '\n%s\n' % title - if options: - rst += "\n" - rst += optrst(options) - rst += '\n' - - return '\n' + minirst.format(rst, width) - - def addglobalopts(optlist, aliases): - if ui.quiet: - return [] - - if ui.verbose: - optlist.append((_("global options:"), globalopts)) - if name == 'shortlist': - optlist.append((_('use "hg help" for the full list ' - 'of commands'), ())) - else: - if name == 'shortlist': - msg = _('use "hg help" for the full list of commands ' - 'or "hg -v" for details') - elif name and not full: - msg = _('use "hg help %s" to show the full help text') % name - elif aliases: - msg = _('use "hg -v help%s" to show builtin aliases and ' - 'global options') % (name and " " + name or "") - else: - msg = _('use "hg -v help %s" to show more info') % name - optlist.append((msg, ())) - def helpcmd(name): try: aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd) @@ -3223,13 +3151,13 @@ rst += '\n' rst += _("options:") rst += '\n\n' - rst += optrst(entry[1]) + rst += help.optrst(entry[1], ui.verbose) if ui.verbose: rst += '\n' rst += _("global options:") rst += '\n\n' - rst += optrst(globalopts) + rst += help.optrst(globalopts, ui.verbose) keep = ui.verbose and ['verbose'] or [] formatted, pruned = minirst.format(rst, textwidth, keep=keep) @@ -3303,8 +3231,25 @@ ui.write(" %-*s %s\n" % (topics_len, t, desc)) optlist = [] - addglobalopts(optlist, True) - ui.write(opttext(optlist, textwidth)) + if not ui.quiet: + if ui.verbose: + optlist.append((_("global options:"), globalopts)) + if name == 'shortlist': + optlist.append((_('use "hg help" for the full list ' + 'of commands'), ())) + else: + if name == 'shortlist': + msg = _('use "hg help" for the full list of commands ' + 'or "hg -v" for details') + elif name and not full: + msg = _('use "hg help %s" to show the full help ' + 'text') % name + else: + msg = _('use "hg -v help%s" to show builtin aliases and ' + 'global options') % (name and " " + name or "") + optlist.append((msg, ())) + + ui.write(help.opttext(optlist, textwidth, ui.verbose)) def helptopic(name): for names, header, doc in help.helptable:
--- a/mercurial/help.py Wed May 23 21:34:29 2012 +0200 +++ b/mercurial/help.py Wed May 30 14:31:39 2012 -0500 @@ -8,7 +8,7 @@ from i18n import gettext, _ import itertools, sys, os import extensions, revset, fileset, templatekw, templatefilters, filemerge -import encoding, util +import encoding, util, minirst def listexts(header, exts, indent=1): '''return a text listing of the given extensions''' @@ -27,6 +27,56 @@ doc += listexts(_('disabled extensions:'), extensions.disabled()) return doc +def optrst(options, verbose): + data = [] + multioccur = False + for option in options: + if len(option) == 5: + shortopt, longopt, default, desc, optlabel = option + else: + shortopt, longopt, default, desc = option + optlabel = _("VALUE") # default label + + if _("DEPRECATED") in desc and not verbose: + continue + + so = '' + if shortopt: + so = '-' + shortopt + lo = '--' + longopt + if default: + desc += _(" (default: %s)") % default + + if isinstance(default, list): + lo += " %s [+]" % optlabel + multioccur = True + elif (default is not None) and not isinstance(default, bool): + lo += " %s" % optlabel + + data.append((so, lo, desc)) + + rst = minirst.maketable(data, 1) + + if multioccur: + rst += _("\n[+] marked option can be specified multiple times\n") + + return rst + +# list all option lists +def opttext(optlist, width, verbose): + rst = '' + if not optlist: + return '' + + for title, options in optlist: + rst += '\n%s\n' % title + if options: + rst += "\n" + rst += optrst(options, verbose) + rst += '\n' + + return '\n' + minirst.format(rst, width) + def topicmatch(kw): """Return help topics matching kw.
--- a/mercurial/match.py Wed May 23 21:34:29 2012 +0200 +++ b/mercurial/match.py Wed May 30 14:31:39 2012 -0500 @@ -62,7 +62,10 @@ pats = _normalize(exclude, 'glob', root, cwd, auditor) self.excludepat, em = _buildmatch(ctx, pats, '(?:/|$)') if exact: - self._files = patterns + if isinstance(patterns, list): + self._files = patterns + else: + self._files = list(patterns) pm = self.exact elif patterns: pats = _normalize(patterns, default, root, cwd, auditor)
--- a/mercurial/parsers.c Wed May 23 21:34:29 2012 +0200 +++ b/mercurial/parsers.c Wed May 30 14:31:39 2012 -0500 @@ -246,6 +246,7 @@ Py_ssize_t raw_length; /* original number of elements */ Py_ssize_t length; /* current number of elements */ PyObject *added; /* populated on demand */ + PyObject *headrevs; /* cache, invalidated on changes */ nodetree *nt; /* base-16 trie */ int ntlength; /* # nodes in use */ int ntcapacity; /* # nodes allocated */ @@ -463,6 +464,7 @@ if (self->nt) nt_insert(self, node, (int)offset); + Py_CLEAR(self->headrevs); Py_RETURN_NONE; } @@ -484,6 +486,7 @@ free(self->nt); self->nt = NULL; } + Py_CLEAR(self->headrevs); } static PyObject *index_clearcaches(indexObject *self) @@ -534,6 +537,107 @@ return NULL; } +/* + * When we cache a list, we want to be sure the caller can't mutate + * the cached copy. + */ +static PyObject *list_copy(PyObject *list) +{ + Py_ssize_t len = PyList_GET_SIZE(list); + PyObject *newlist = PyList_New(len); + Py_ssize_t i; + + if (newlist == NULL) + return NULL; + + for (i = 0; i < len; i++) { + PyObject *obj = PyList_GET_ITEM(list, i); + Py_INCREF(obj); + PyList_SET_ITEM(newlist, i, obj); + } + + return newlist; +} + +static PyObject *index_headrevs(indexObject *self) +{ + Py_ssize_t i, len, addlen; + char *nothead = NULL; + PyObject *heads; + + if (self->headrevs) + return list_copy(self->headrevs); + + len = index_length(self) - 1; + heads = PyList_New(0); + if (heads == NULL) + goto bail; + if (len == 0) { + PyObject *nullid = PyInt_FromLong(-1); + if (nullid == NULL || PyList_Append(heads, nullid) == -1) { + Py_XDECREF(nullid); + goto bail; + } + goto done; + } + + nothead = calloc(len, 1); + if (nothead == NULL) + goto bail; + + for (i = 0; i < self->raw_length; i++) { + const char *data = index_deref(self, i); + int parent_1 = getbe32(data + 24); + int parent_2 = getbe32(data + 28); + if (parent_1 >= 0) + nothead[parent_1] = 1; + if (parent_2 >= 0) + nothead[parent_2] = 1; + } + + addlen = self->added ? PyList_GET_SIZE(self->added) : 0; + + for (i = 0; i < addlen; i++) { + PyObject *rev = PyList_GET_ITEM(self->added, i); + PyObject *p1 = PyTuple_GET_ITEM(rev, 5); + PyObject *p2 = PyTuple_GET_ITEM(rev, 6); + long parent_1, parent_2; + + if (!PyInt_Check(p1) || !PyInt_Check(p2)) { + PyErr_SetString(PyExc_TypeError, + "revlog parents are invalid"); + goto bail; + } + parent_1 = PyInt_AS_LONG(p1); + parent_2 = PyInt_AS_LONG(p2); + if (parent_1 >= 0) + nothead[parent_1] = 1; + if (parent_2 >= 0) + nothead[parent_2] = 1; + } + + for (i = 0; i < len; i++) { + PyObject *head; + + if (nothead[i]) + continue; + head = PyInt_FromLong(i); + if (head == NULL || PyList_Append(heads, head) == -1) { + Py_XDECREF(head); + goto bail; + } + } + +done: + self->headrevs = heads; + free(nothead); + return list_copy(self->headrevs); +bail: + Py_XDECREF(heads); + free(nothead); + return NULL; +} + static inline int nt_level(const char *node, Py_ssize_t level) { int v = node[level>>1]; @@ -930,6 +1034,7 @@ { Py_ssize_t start, stop, step, slicelength; Py_ssize_t length = index_length(self); + int ret = 0; if (PySlice_GetIndicesEx((PySliceObject*)item, length, &start, &stop, &step, &slicelength) < 0) @@ -975,7 +1080,9 @@ self->ntrev = (int)start; } self->length = start + 1; - return 0; + if (start < self->raw_length) + self->raw_length = start; + goto done; } if (self->nt) { @@ -983,10 +1090,12 @@ if (self->ntrev > start) self->ntrev = (int)start; } - return self->added - ? PyList_SetSlice(self->added, start - self->length + 1, - PyList_GET_SIZE(self->added), NULL) - : 0; + if (self->added) + ret = PyList_SetSlice(self->added, start - self->length + 1, + PyList_GET_SIZE(self->added), NULL); +done: + Py_CLEAR(self->headrevs); + return ret; } /* @@ -1076,6 +1185,7 @@ self->cache = NULL; self->added = NULL; + self->headrevs = NULL; self->offsets = NULL; self->nt = NULL; self->ntlength = self->ntcapacity = 0; @@ -1140,6 +1250,8 @@ "clear the index caches"}, {"get", (PyCFunction)index_m_get, METH_VARARGS, "get an index entry"}, + {"headrevs", (PyCFunction)index_headrevs, METH_NOARGS, + "get head revisions"}, {"insert", (PyCFunction)index_insert, METH_VARARGS, "insert an index entry"}, {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,
--- a/mercurial/revlog.py Wed May 23 21:34:29 2012 +0200 +++ b/mercurial/revlog.py Wed May 30 14:31:39 2012 -0500 @@ -635,6 +635,10 @@ return (orderedout, roots, heads) def headrevs(self): + try: + return self.index.headrevs() + except AttributeError: + pass count = len(self) if not count: return [nullrev]
--- a/mercurial/scmutil.py Wed May 23 21:34:29 2012 +0200 +++ b/mercurial/scmutil.py Wed May 30 14:31:39 2012 -0500 @@ -525,9 +525,11 @@ l = revrange(repo, revs) if len(l) == 0: + if revs: + raise util.Abort(_('empty revision range')) return repo.dirstate.p1(), None - if len(l) == 1: + if len(l) == 1 and len(revs) == 1 and _revrangesep not in revs[0]: return repo.lookup(l[0]), None return repo.lookup(l[0]), repo.lookup(l[-1])
--- a/tests/test-diff-change.t Wed May 23 21:34:29 2012 +0200 +++ b/tests/test-diff-change.t Wed May 30 14:31:39 2012 -0500 @@ -29,6 +29,12 @@ -first +second +Test dumb revspecs (issue3474) + + $ hg diff -r 2:2 + $ hg diff -r "2 and 1" + abort: empty revision range + [255] Testing diff --change when merge: