[PATCH 1 of 2] cat: record the current behavior of wildcard matches in subrepos
# HG changeset patch # User Yuya Nishihara # Date 1511591374 -32400 # Sat Nov 25 15:29:34 2017 +0900 # Node ID 38e952030f0c4746257280d47f0f94b6cb9ddb41 # Parent 8287df8b7be545fdafa22b771012ac65f6264d12 cat: record the current behavior of wildcard matches in subrepos It appears that Mercurial subrepo supports any match patterns. diff --git a/mercurial/help/subrepos.txt b/mercurial/help/subrepos.txt --- a/mercurial/help/subrepos.txt +++ b/mercurial/help/subrepos.txt @@ -90,7 +90,7 @@ Interaction with Mercurial Commands :archive: archive does not recurse in subrepositories unless -S/--subrepos is specified. -:cat: cat currently only handles exact file matches in subrepos. +:cat: cat currently only handles exact file matches in Git subrepos. Subversion subrepositories are currently ignored. :commit: commit creates a consistent snapshot of the state of the diff --git a/tests/test-subrepo.t b/tests/test-subrepo.t --- a/tests/test-subrepo.t +++ b/tests/test-subrepo.t @@ -1071,6 +1071,18 @@ Prepare a repo with subrepo "path": "sub/repo/foo" } ] + + non-exact match: + + $ hg cat -T '{path}\n' 'glob:**' + .hgsub + .hgsubstate + sub/repo/foo (glob) + $ hg cat -T '{path}\n' 're:^sub' + sub/repo/foo (glob) + + missing subrepos in working directory: + $ mkdir -p tmp/sub/repo $ hg cat -r 0 --output tmp/%p_p sub/repo/foo $ cat tmp/sub/repo/foo_p ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 2 of 2] cat: do not instantiate subrepo if no potential match in it
# HG changeset patch # User Yuya Nishihara # Date 1511593310 -32400 # Sat Nov 25 16:01:50 2017 +0900 # Node ID b6e526ee5d2662ca30a555ca51264b3e371fe44e # Parent 38e952030f0c4746257280d47f0f94b6cb9ddb41 cat: do not instantiate subrepo if no potential match in it This fixes the test failure in hg-git. https://bitbucket.org/durin42/hg-git/issues/227/ diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py --- a/mercurial/cmdutil.py +++ b/mercurial/cmdutil.py @@ -3068,6 +3068,8 @@ def cat(ui, repo, ctx, matcher, basefm, err = 0 for subpath in sorted(ctx.substate): +if not matcher.visitdir(subpath): +continue sub = ctx.sub(subpath) try: submatch = matchmod.subdirmatcher(subpath, matcher) diff --git a/tests/test-subrepo.t b/tests/test-subrepo.t --- a/tests/test-subrepo.t +++ b/tests/test-subrepo.t @@ -1081,6 +1081,36 @@ Prepare a repo with subrepo $ hg cat -T '{path}\n' 're:^sub' sub/repo/foo (glob) + inaccessible subrepos: + + $ mv sub sub_ + $ touch sub + $ hg cat .hgsub .hgsubstate + sub/repo = sub/repo + f42d5c7504a811dda50f5cf3e5e16c3330b87172 sub/repo + $ hg cat sub/repo/foo + abort: *: '$TESTTMP/issue1852a/sub/repo' (glob) + [255] + $ rm sub + $ mv sub_ sub + + symlink traversal: + +#if symlink + + $ mv sub/repo sub/repo_ + $ ln -s repo_ sub/repo + $ hg cat .hgsub .hgsubstate + sub/repo = sub/repo + f42d5c7504a811dda50f5cf3e5e16c3330b87172 sub/repo + $ hg cat sub/repo/foo + abort: subrepo 'sub/repo' traverses symbolic link + [255] + $ rm sub/repo + $ mv sub/repo_ sub/repo + +#endif + missing subrepos in working directory: $ mkdir -p tmp/sub/repo ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1498: hbisect: use a revset for ancestor calculation
This revision was automatically updated to reflect the committed changes. Closed by commit rHGec25c8275cfa: hbisect: use a revset for ancestor calculation (authored by dsp, committed by ). REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D1498?vs=3804&id=3857 REVISION DETAIL https://phab.mercurial-scm.org/D1498 AFFECTED FILES mercurial/hbisect.py CHANGE DETAILS diff --git a/mercurial/hbisect.py b/mercurial/hbisect.py --- a/mercurial/hbisect.py +++ b/mercurial/hbisect.py @@ -37,29 +37,10 @@ skip = set([changelog.rev(n) for n in state['skip']]) def buildancestors(bad, good): -# only the earliest bad revision matters badrev = min([changelog.rev(n) for n in bad]) -goodrevs = [changelog.rev(n) for n in good] -goodrev = min(goodrevs) -# build visit array -ancestors = [None] * (len(changelog) + 1) # an extra for [-1] - -# set nodes descended from goodrevs -for rev in goodrevs: +ancestors = [None] * (len(changelog) + 1) +for rev in repo.revs("descendants(%ln) - ancestors(%ln)", good, good): ancestors[rev] = [] -for rev in changelog.revs(goodrev + 1): -for prev in clparents(rev): -if ancestors[prev] == []: -ancestors[rev] = [] - -# clear good revs from array -for rev in goodrevs: -ancestors[rev] = None -for rev in changelog.revs(len(changelog), goodrev): -if ancestors[rev] is None: -for prev in clparents(rev): -ancestors[prev] = None - if ancestors[badrev] is None: return badrev, None return badrev, ancestors To: dsp, #hg-reviewers, yuja Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1494: develwarn: do not emit warning if "config" is unspecified
This revision was automatically updated to reflect the committed changes. Closed by commit rHGfa2395db68c6: develwarn: do not emit warning if "config" is unspecified (authored by spectral, committed by ). REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D1494?vs=3798&id=3855 REVISION DETAIL https://phab.mercurial-scm.org/D1494 AFFECTED FILES mercurial/ui.py CHANGE DETAILS diff --git a/mercurial/ui.py b/mercurial/ui.py --- a/mercurial/ui.py +++ b/mercurial/ui.py @@ -1603,7 +1603,7 @@ stack. """ if not self.configbool('devel', 'all-warnings'): -if config is not None and not self.configbool('devel', config): +if config is None or not self.configbool('devel', config): return msg = 'devel-warn: ' + msg stacklevel += 1 # get in develwarn To: spectral, yuja, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1499: hbisect: use a defaultdict to avoid large allocations for a large changelogs
This revision was automatically updated to reflect the committed changes. Closed by commit rHG8287df8b7be5: hbisect: use a defaultdict to avoid large allocations for a large changelogs (authored by dsp, committed by ). REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D1499?vs=3805&id=3858 REVISION DETAIL https://phab.mercurial-scm.org/D1499 AFFECTED FILES mercurial/hbisect.py CHANGE DETAILS diff --git a/mercurial/hbisect.py b/mercurial/hbisect.py --- a/mercurial/hbisect.py +++ b/mercurial/hbisect.py @@ -38,7 +38,7 @@ def buildancestors(bad, good): badrev = min([changelog.rev(n) for n in bad]) -ancestors = [None] * (len(changelog) + 1) +ancestors = collections.defaultdict(lambda: None) for rev in repo.revs("descendants(%ln) - ancestors(%ln)", good, good): ancestors[rev] = [] if ancestors[badrev] is None: To: dsp, #hg-reviewers, yuja Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1497: hbisect: pass repo into hbisect.bisect
This revision was automatically updated to reflect the committed changes. Closed by commit rHGfd8b6b183073: hbisect: pass repo into hbisect.bisect (authored by dsp, committed by ). REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D1497?vs=3803&id=3856 REVISION DETAIL https://phab.mercurial-scm.org/D1497 AFFECTED FILES mercurial/commands.py mercurial/hbisect.py CHANGE DETAILS diff --git a/mercurial/hbisect.py b/mercurial/hbisect.py --- a/mercurial/hbisect.py +++ b/mercurial/hbisect.py @@ -21,7 +21,7 @@ error, ) -def bisect(changelog, state): +def bisect(repo, state): """find the next node (if any) for testing during a bisect search. returns a (nodes, number, good) tuple. @@ -32,6 +32,7 @@ if searching for a first bad one. """ +changelog = repo.changelog clparents = changelog.parentrevs skip = set([changelog.rev(n) for n in state['skip']]) diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -854,7 +854,7 @@ ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition)) hbisect.checkstate(state) # bisect -nodes, changesets, bgood = hbisect.bisect(repo.changelog, state) +nodes, changesets, bgood = hbisect.bisect(repo, state) # update to next check node = nodes[0] mayupdate(repo, node, show_stats=False) @@ -867,7 +867,7 @@ hbisect.checkstate(state) # actually bisect -nodes, changesets, good = hbisect.bisect(repo.changelog, state) +nodes, changesets, good = hbisect.bisect(repo, state) if extend: if not changesets: extendnode = hbisect.extendrange(repo, state, nodes, good) To: dsp, #hg-reviewers, yuja Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1348: histedit: add support to output nodechanges using formatter
This revision was automatically updated to reflect the committed changes. Closed by commit rHGa9cc233de513: histedit: add support to output nodechanges using formatter (authored by pulkit, committed by ). CHANGED PRIOR TO COMMIT https://phab.mercurial-scm.org/D1348?vs=3783&id=3854#toc REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D1348?vs=3783&id=3854 REVISION DETAIL https://phab.mercurial-scm.org/D1348 AFFECTED FILES hgext/histedit.py tests/test-histedit-templates.t CHANGE DETAILS diff --git a/tests/test-histedit-templates.t b/tests/test-histedit-templates.t new file mode 100644 --- /dev/null +++ b/tests/test-histedit-templates.t @@ -0,0 +1,54 @@ +Testing templating for histedit command + +Setup + + $ cat >> $HGRCPATH < [extensions] + > histedit= + > [experimental] + > evolution=createmarkers + > EOF + + $ hg init repo + $ cd repo + $ for ch in a b c d; do echo foo > $ch; hg commit -Aqm "Added "$ch; done + + $ hg log -G -T "{rev}:{node|short} {desc}" + @ 3:62615734edd5 Added d + | + o 2:28ad74487de9 Added c + | + o 1:29becc82797a Added b + | + o 0:18d04c59bb5d Added a + +Getting the JSON output for nodechanges + + $ hg histedit -Tjson --commands - 2>&1 < pick 28ad74487de9 Added c + > pick 62615734edd5 Added d + > pick 18d04c59bb5d Added a + > pick 29becc82797a Added b + > EOF + [ + { +"nodechanges": {"18d04c59bb5d2d4090ad9a5b59bd6274adb63add": ["109f8ec895447f81b380ba8d4d8b66539ccdcb94"], "28ad74487de9599d00d81085be739c61fc340652": ["bff9e07c1807942b161dab768aa793b48e9a7f9d"], "29becc82797a4bc11ec8880b58eaecd2ab3e7760": ["f5dcf3b4db23f31f1aacf46c33d1393de303d26f"], "62615734edd52f06b6fb9c2beb429e4fe30d57b8": ["201423b441c84d9e6858daed653e0d22485c1cfa"]} + } + ] + + $ hg log -G -T "{rev}:{node|short} {desc}" + @ 7:f5dcf3b4db23 Added b + | + o 6:109f8ec89544 Added a + | + o 5:201423b441c8 Added d + | + o 4:bff9e07c1807 Added c + + $ hg histedit -T "{nodechanges|json}" --commands - 2>&1 < pick bff9e07c1807 Added c + > pick 201423b441c8 Added d + > pick 109f8ec89544 Added a + > roll f5dcf3b4db23 Added b + > EOF + {"109f8ec895447f81b380ba8d4d8b66539ccdcb94": ["8d01470bfeab64d3de13c49adb79d88790d38396"], "f3ec56a374bdbdf1953cacca505161442c6f3a3e": [], "f5dcf3b4db23f31f1aacf46c33d1393de303d26f": ["8d01470bfeab64d3de13c49adb79d88790d38396"]} (no-eol) diff --git a/hgext/histedit.py b/hgext/histedit.py --- a/hgext/histedit.py +++ b/hgext/histedit.py @@ -917,7 +917,8 @@ ('o', 'outgoing', False, _('changesets not found in destination')), ('f', 'force', False, _('force outgoing even for unrelated repositories')), - ('r', 'rev', [], _('first revision to be edited'), _('REV'))], + ('r', 'rev', [], _('first revision to be edited'), _('REV'))] + +cmdutil.formatteropts, _("[OPTIONS] ([ANCESTOR] | --outgoing [URL])")) def histedit(ui, repo, *freeargs, **opts): """interactively edit changeset history @@ -1095,6 +1096,8 @@ def _histedit(ui, repo, state, *freeargs, **opts): opts = pycompat.byteskwargs(opts) +fm = ui.formatter('histedit', opts) +fm.startitem() goal = _getgoal(opts) revs = opts.get('rev', []) rules = opts.get('commands', '') @@ -1117,7 +1120,8 @@ _newhistedit(ui, repo, state, revs, freeargs, opts) _continuehistedit(ui, repo, state) -_finishhistedit(ui, repo, state) +_finishhistedit(ui, repo, state, fm) +fm.end() def _continuehistedit(ui, repo, state): """This function runs after either: @@ -1164,7 +1168,7 @@ state.write() ui.progress(_("editing"), None) -def _finishhistedit(ui, repo, state): +def _finishhistedit(ui, repo, state, fm): """This action runs when histedit is finishing its session""" repo.ui.pushbuffer() hg.update(repo, state.parentctxnode, quietempty=True) @@ -1198,6 +1202,13 @@ mapping = {k: v for k, v in mapping.items() if k in nodemap and all(n in nodemap for n in v)} scmutil.cleanupnodes(repo, mapping, 'histedit') +hf = fm.hexfunc +fl = fm.formatlist +fd = fm.formatdict +nodechanges = fd({hf(oldn): fl([hf(n) for n in newn], name='node') + for oldn, newn in mapping.iteritems()}, + key="oldnode", value="newnodes") +fm.data(nodechanges=nodechanges) state.clear() if os.path.exists(repo.sjoin('undo')): To: pulkit, durin42, #hg-reviewers, dlax, yuja Cc: yuja, dlax, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1494: develwarn: do not emit warning if "config" is unspecified
yuja added a comment. > (Specifically picked yuja as reviewer since they reviewed the original > https://www.mercurial-scm.org/repo/hg/rev/3f33831a9202, > so hopefully can tell me whether this was intentional I think it was intentional during the migration to the config gating API, i.e. no gating unless `config=` is specified, but the current behavior is weird, and should be worth breaking the old API. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D1494 To: spectral, yuja, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1506: dagop: handle IndexError when using wdir() in dag range
yuja requested changes to this revision. yuja added a comment. This revision now requires changes to proceed. I think it's better to fail fast instead of trying the slow path which is supposed to raise WdirUnsupported exception. > $ hg status --rev '.::wdir()' > abort: working directory revision cannot be specified Can you add test? REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D1506 To: swhitaker, #hg-reviewers, mbthomas, yuja Cc: yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1499: hbisect: use a defaultdict to avoid large allocations for a large changelogs
yuja added a comment. Queued, thanks. I don't have any number, but this seems good for a common scenario in which a small part of a large repository will be bisected. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D1499 To: dsp, #hg-reviewers, yuja Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1494: develwarn: do not emit warning if "config" is unspecified
yuja accepted this revision. yuja added a comment. This revision is now accepted and ready to land. Makes sense. Queued, thanks. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D1494 To: spectral, yuja, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1348: histedit: add support to output nodechanges using formatter
yuja accepted this revision. yuja added a comment. This revision is now accepted and ready to land. Queued, thanks. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D1348 To: pulkit, durin42, #hg-reviewers, dlax, yuja Cc: yuja, dlax, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 2 of 2] obsolete: drop usage of changectx in '_computecontentdivergentset'
# HG changeset patch # User Boris Feld # Date 1511066090 -3600 # Sun Nov 19 05:34:50 2017 +0100 # Node ID 15d0adf567fa66fbc33146e296fbc293bb507663 # Parent b76ac906d1ecea6bcac489834699d01273112fc8 # EXP-Topic instability-speed # Available At https://bitbucket.org/octobus/mercurial-devel/ # hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 15d0adf567fa obsolete: drop usage of changectx in '_computecontentdivergentset' Changectx are expensive and not needed there. The use of `repo.set` denote old code that predate the introduction of `repo.revs` that we now use. On my mercurial repository 495 draft: before: 0.054239 second after: 0.046935 second On a mercurial repository with 115973 draft: before: 0.564548 second after: 0.130534 second diff --git a/mercurial/obsolete.py b/mercurial/obsolete.py --- a/mercurial/obsolete.py +++ b/mercurial/obsolete.py @@ -1023,8 +1023,10 @@ def _computecontentdivergentset(repo): divergent = set() obsstore = repo.obsstore newermap = {} -for ctx in repo.set('(not public()) - obsolete()'): -mark = obsstore.predecessors.get(ctx.node(), ()) +tonode = repo.changelog.node +for rev in repo.revs('(not public()) - obsolete()'): +node = tonode(rev) +mark = obsstore.predecessors.get(node, ()) toprocess = set(mark) seen = set() while toprocess: @@ -1036,7 +1038,7 @@ def _computecontentdivergentset(repo): obsutil.successorssets(repo, prec, cache=newermap) newer = [n for n in newermap[prec] if n] if len(newer) > 1: -divergent.add(ctx.rev()) +divergent.add(rev) break toprocess.update(obsstore.predecessors.get(prec, ())) return divergent ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 1 of 2] obsolete: drop usage of changectx in '_computephasedivergentset'
# HG changeset patch # User Boris Feld # Date 1511065392 -3600 # Sun Nov 19 05:23:12 2017 +0100 # Node ID b76ac906d1ecea6bcac489834699d01273112fc8 # Parent 75013952d8d9608f73cd45f68405fbd6ec112bf2 # EXP-Topic instability-speed # Available At https://bitbucket.org/octobus/mercurial-devel/ # hg pull https://bitbucket.org/octobus/mercurial-devel/ -r b76ac906d1ec obsolete: drop usage of changectx in '_computephasedivergentset' Changectx are expensive and not needed there. The use of `repo.set` denote old code that predate the introduction of `repo.revs` that we now use. On my mercurial repository 495 draft: before: 0.010275 second after: 0.008832 second On a mercurial repository with 115973 draft: before: 0.899255 second after: 0.397131 second diff --git a/mercurial/obsolete.py b/mercurial/obsolete.py --- a/mercurial/obsolete.py +++ b/mercurial/obsolete.py @@ -994,10 +994,10 @@ def _computephasedivergentset(repo): public = phases.public cl = repo.changelog torev = cl.nodemap.get -for ctx in repo.set('(not public()) and (not obsolete())'): -rev = ctx.rev() +tonode = cl.node +for rev in repo.revs('(not public()) and (not obsolete())'): # We only evaluate mutable, non-obsolete revision -node = ctx.node() +node = tonode(rev) # (future) A cache of predecessors may worth if split is very common for pnode in obsutil.allpredecessors(repo.obsstore, [node], ignoreflags=bumpedfix): ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 1 of 2 STABLE V2] fancyopts: add early-options parser compatible with getopt()
# HG changeset patch # User Yuya Nishihara # Date 1511442293 -32400 # Thu Nov 23 22:04:53 2017 +0900 # Branch stable # Node ID 78d25e7afffe6ce150da8b1ca32418d6394b0442 # Parent 02845f7441aff30bc01975a5881cabfa922c12d4 fancyopts: add early-options parser compatible with getopt() The next patch will add a flag for strict parsing of early options, where we'll have to parse all early options at once instead of processing them one-by-one by dispatch._earlygetopt(). That's why I decided to hook fancyopts(). All dispatch._early*opt() functions is planned to be replaced with this function. But in this stable series, only the strict mode will be handled by fancyopts.earlygetopt(). diff --git a/mercurial/fancyopts.py b/mercurial/fancyopts.py --- a/mercurial/fancyopts.py +++ b/mercurial/fancyopts.py @@ -7,6 +7,8 @@ from __future__ import absolute_import +import functools + from .i18n import _ from . import ( error, @@ -24,6 +26,179 @@ nevernegate = { 'version', } +def _earlyoptarg(arg, shortlist, namelist): +"""Check if the given arg is a valid unabbreviated option + +Returns (flag_str, has_embedded_value?, embedded_value, takes_value?) + +>>> def opt(arg): +... return _earlyoptarg(arg, b'R:q', [b'cwd=', b'debugger']) + +long form: + +>>> opt(b'--cwd') +('--cwd', False, '', True) +>>> opt(b'--cwd=') +('--cwd', True, '', True) +>>> opt(b'--cwd=foo') +('--cwd', True, 'foo', True) +>>> opt(b'--debugger') +('--debugger', False, '', False) +>>> opt(b'--debugger=') # invalid but parsable +('--debugger', True, '', False) + +short form: + +>>> opt(b'-R') +('-R', False, '', True) +>>> opt(b'-Rfoo') +('-R', True, 'foo', True) +>>> opt(b'-q') +('-q', False, '', False) +>>> opt(b'-qfoo') # invalid but parsable +('-q', True, 'foo', False) + +unknown or invalid: + +>>> opt(b'--unknown') +('', False, '', False) +>>> opt(b'-u') +('', False, '', False) +>>> opt(b'-ufoo') +('', False, '', False) +>>> opt(b'--') +('', False, '', False) +>>> opt(b'-') +('', False, '', False) +>>> opt(b'-:') +('', False, '', False) +>>> opt(b'-:foo') +('', False, '', False) +""" +if arg.startswith('--'): +flag, eq, val = arg.partition('=') +if flag[2:] in namelist: +return flag, bool(eq), val, False +if flag[2:] + '=' in namelist: +return flag, bool(eq), val, True +elif arg.startswith('-') and arg != '-' and not arg.startswith('-:'): +flag, val = arg[:2], arg[2:] +i = shortlist.find(flag[1:]) +if i >= 0: +return flag, bool(val), val, shortlist.startswith(':', i + 1) +return '', False, '', False + +def earlygetopt(args, shortlist, namelist, gnu=False, keepsep=False): +"""Parse options like getopt, but ignores unknown options and abbreviated +forms + +If gnu=False, this stops processing options as soon as a non/unknown-option +argument is encountered. Otherwise, option and non-option arguments may be +intermixed, and unknown-option arguments are taken as non-option. + +If keepsep=True, '--' won't be removed from the list of arguments left. +This is useful for stripping early options from a full command arguments. + +>>> def get(args, gnu=False, keepsep=False): +... return earlygetopt(args, b'R:q', [b'cwd=', b'debugger'], +...gnu=gnu, keepsep=keepsep) + +default parsing rules for early options: + +>>> get([b'x', b'--cwd', b'foo', b'-Rbar', b'-q', b'y'], gnu=True) +([('--cwd', 'foo'), ('-R', 'bar'), ('-q', '')], ['x', 'y']) +>>> get([b'x', b'--cwd=foo', b'y', b'-R', b'bar', b'--debugger'], gnu=True) +([('--cwd', 'foo'), ('-R', 'bar'), ('--debugger', '')], ['x', 'y']) +>>> get([b'--unknown', b'--cwd=foo', b'--', '--debugger'], gnu=True) +([('--cwd', 'foo')], ['--unknown', '--debugger']) + +restricted parsing rules (early options must come first): + +>>> get([b'--cwd', b'foo', b'-Rbar', b'x', b'-q', b'y'], gnu=False) +([('--cwd', 'foo'), ('-R', 'bar')], ['x', '-q', 'y']) +>>> get([b'--cwd=foo', b'x', b'y', b'-R', b'bar', b'--debugger'], gnu=False) +([('--cwd', 'foo')], ['x', 'y', '-R', 'bar', '--debugger']) +>>> get([b'--unknown', b'--cwd=foo', b'--', '--debugger'], gnu=False) +([], ['--unknown', '--cwd=foo', '--debugger']) + +stripping early options (without loosing '--'): + +>>> get([b'x', b'-Rbar', b'--', '--debugger'], gnu=True, keepsep=True)[1] +['x', '--', '--debugger'] + +last argument: + +>>> get([b'--cwd']) +([], ['--cwd']) +>>> get([b'--cwd=foo']) +([('--cwd', 'foo')], []) +>>> get([b'-R']) +([], ['-R']) +>>> get([b'-Rbar']) +([('-R', 'bar')], []) +>>> get([b'-q']) +([('-q', '')], []) +>>> get([b'-q', b'--']) +([('-q', '')], []) + +value passed to bool options: + +>>> ge
[PATCH 2 of 2 STABLE V2] dispatch: add HGPLAIN=+strictflags to restrict early parsing of global options
# HG changeset patch # User Yuya Nishihara # Date 1511443023 -32400 # Thu Nov 23 22:17:03 2017 +0900 # Branch stable # Node ID 54e6e3b35ea5a96d2d822ac23d44b4d105178c05 # Parent 78d25e7afffe6ce150da8b1ca32418d6394b0442 dispatch: add HGPLAIN=+strictflags to restrict early parsing of global options If this feature is enabled, early options are parsed using the global options table. As the parser stops processing options when non/unknown option is encountered, it won't mistakenly take an option value as a new early option. Still "--" can be injected to terminate the parsing (e.g. "hg -R -- log"), I think it's unlikely to lead to an RCE. To minimize a risk of this change, new fancyopts.earlygetopt() path is enabled only when +strictflags is set. Also the strict parser doesn't support '--repo', a short for '--repository' yet. This limitation will be removed later. As this feature is backward incompatible, I decided to add a new opt-in mechanism to HGPLAIN. I'm not pretty sure if this is the right choice, but I'm thinking of adding +feature/-feature syntax to HGPLAIN. Alternatively, we could add a new environment variable. Any bikeshedding is welcome. Note that HGPLAIN=+strictflags doesn't work correctly in chg session since command arguments are pre-processed in C. This wouldn't be easily fixed. diff --git a/mercurial/chgserver.py b/mercurial/chgserver.py --- a/mercurial/chgserver.py +++ b/mercurial/chgserver.py @@ -220,8 +220,17 @@ def _loadnewui(srcui, args): newui._csystem = srcui._csystem # command line args -args = args[:] -dispatch._parseconfig(newui, dispatch._earlygetopt(['--config'], args)) +options = {} +if srcui.plain('strictflags'): +options.update(dispatch._earlyparseopts(args)) +else: +args = args[:] +options['config'] = dispatch._earlygetopt(['--config'], args) +cwds = dispatch._earlygetopt(['--cwd'], args) +options['cwd'] = cwds and cwds[-1] or '' +rpath = dispatch._earlygetopt(["-R", "--repository", "--repo"], args) +options['repository'] = rpath and rpath[-1] or '' +dispatch._parseconfig(newui, options['config']) # stolen from tortoisehg.util.copydynamicconfig() for section, name, value in srcui.walkconfig(): @@ -232,10 +241,9 @@ def _loadnewui(srcui, args): newui.setconfig(section, name, value, source) # load wd and repo config, copied from dispatch.py -cwds = dispatch._earlygetopt(['--cwd'], args) -cwd = cwds and os.path.realpath(cwds[-1]) or None -rpath = dispatch._earlygetopt(["-R", "--repository", "--repo"], args) -rpath = rpath and rpath[-1] or '' +cwd = options['cwd'] +cwd = cwd and os.path.realpath(cwd) or None +rpath = options['repository'] path, newlui = dispatch._getlocal(newui, rpath, wd=cwd) return (newui, newlui) diff --git a/mercurial/dispatch.py b/mercurial/dispatch.py --- a/mercurial/dispatch.py +++ b/mercurial/dispatch.py @@ -150,6 +150,8 @@ def dispatch(req): try: if not req.ui: req.ui = uimod.ui.load() +if req.ui.plain('strictflags'): +req.earlyoptions.update(_earlyparseopts(req.args)) if _earlyreqoptbool(req, 'traceback', ['--traceback']): req.ui.setconfig('ui', 'traceback', 'on', '--traceback') @@ -644,6 +646,12 @@ def _parseconfig(ui, config): return configs +def _earlyparseopts(args): +options = {} +fancyopts.fancyopts(args, commands.globalopts, options, +gnu=False, early=True) +return options + def _earlygetopt(aliases, args, strip=True): """Return list of values for an option (or aliases). @@ -732,12 +740,16 @@ def _earlygetopt(aliases, args, strip=Tr def _earlyreqopt(req, name, aliases): """Peek a list option without using a full options table""" +if req.ui.plain('strictflags'): +return req.earlyoptions[name] values = _earlygetopt(aliases, req.args, strip=False) req.earlyoptions[name] = values return values def _earlyreqoptstr(req, name, aliases): """Peek a string option without using a full options table""" +if req.ui.plain('strictflags'): +return req.earlyoptions[name] value = (_earlygetopt(aliases, req.args, strip=False) or [''])[-1] req.earlyoptions[name] = value return value @@ -745,13 +757,15 @@ def _earlyreqoptstr(req, name, aliases): def _earlyreqoptbool(req, name, aliases): """Peek a boolean option without using a full options table ->>> req = request([b'x', b'--debugger']) +>>> req = request([b'x', b'--debugger'], uimod.ui()) >>> _earlyreqoptbool(req, b'debugger', [b'--debugger']) True ->>> req = request([b'x', b'--', b'--debugger']) +>>> req = request([b'x', b'--', b'--debugger'], uimod.ui()) >>> _earlyreqoptbool(req, b'debugger', [b'--debugger']) """ +if req.ui.plain('strictflags'): +return req.earlyoptions[name] try: argc
D1506: dagop: handle IndexError when using wdir() in dag range
swhitaker created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY Using wdir() in a dag range revset can crash Mercurial. For example: hg status --rev '.^::wdir() revlog.c reports an IndexError in this instance, but it isn't caught by the calling code. This change adds IndexError to the set of exception types the calling code catches. When an IndexError is caught, the code falls back to calling the pure Python implementation of reachableroots, which fails gracefully. TEST PLAN $ hg status --rev '.::wdir()' abort: working directory revision cannot be specified REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D1506 AFFECTED FILES mercurial/dagop.py CHANGE DETAILS diff --git a/mercurial/dagop.py b/mercurial/dagop.py --- a/mercurial/dagop.py +++ b/mercurial/dagop.py @@ -230,7 +230,7 @@ heads = list(heads) try: revs = repo.changelog.reachableroots(minroot, heads, roots, includepath) -except AttributeError: +except (AttributeError, IndexError): revs = _reachablerootspure(repo, minroot, roots, heads, includepath) revs = baseset(revs) revs.sort() To: swhitaker, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1502: rewriteutil: add utility function to check if we can create new unstable cset
dlax added a comment. > This rewriteutil.py introduced in this patch and the utility functions added in the upcoming patches exists in the evolve extension are being ported from there. Is it worth porting this alone if nothing in core makes use of this module? Or is there a larger plan? REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D1502 To: pulkit, #hg-reviewers Cc: dlax, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel