Re: [PATCH 6 of 6 py3] commands: make sure using byteschr rather than ascii values
On Thu, Mar 16, 2017 at 10:14 AM, Martin von Zweigbergk < martinv...@google.com> wrote: > On Wed, Mar 15, 2017 at 9:13 PM, Pulkit Goyal <7895pul...@gmail.com> > wrote: > > # HG changeset patch > > # User Pulkit Goyal <7895pul...@gmail.com> > > # Date 1489635793 -19800 > > # Thu Mar 16 09:13:13 2017 +0530 > > # Node ID 63aeb39b5802644ae99eaa5cf0666f3bf5cc4e90 > > # Parent b5673a08993652a92c0e20a4e24d842194872454 > > commands: make sure using byteschr rather than ascii values > > > > 'MAR!?IC' is converted to their ascii values when slicing through it. > This > > patch converts them back to bytes string. > > > > diff -r b5673a089936 -r 63aeb39b5802 mercurial/commands.py > > --- a/mercurial/commands.py Thu Mar 16 09:00:27 2017 +0530 > > +++ b/mercurial/commands.py Thu Mar 16 09:13:13 2017 +0530 > > @@ -4768,6 +4768,8 @@ > > showchar = not opts.get('no_status') > > > > for state, char, files in changestates: > > +if pycompat.ispy3: > > +char = bytes([char]) > > I'd prefer to wrap 'MAR!?C' in pycompat.iterbytestr() to avoid the > conditional here. What do you think?. Would that work? I am not sure about how you are saying to that. Using pycompat.iterbytes() we can iterate on 'MAR!?C', but in these we are iterating over three things at once. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 3 of 3 py3] context: explicitly evaluate list returned by map
# HG changeset patch # User Pulkit Goyal <7895pul...@gmail.com> # Date 1489639281 -19800 # Thu Mar 16 10:11:21 2017 +0530 # Node ID 8d85d7ca9fd3eea90a2f09c7d471fc3f3c78d430 # Parent de18c43f8ce17d52542e6df233e809b6a6ee0a07 context: explicitly evaluate list returned by map On python 3, map returns an iterator so we need to convert it to list before finding the len or subscripting it. After this `hg status --all` works on Python 3. diff -r de18c43f8ce1 -r 8d85d7ca9fd3 mercurial/context.py --- a/mercurial/context.py Thu Mar 16 10:10:00 2017 +0530 +++ b/mercurial/context.py Thu Mar 16 10:11:21 2017 +0530 @@ -622,7 +622,7 @@ n2 = c2._node if n2 is None: n2 = c2._parents[0]._node -cahs = self._repo.changelog.commonancestorsheads(self._node, n2) +cahs = list(self._repo.changelog.commonancestorsheads(self._node, n2)) if not cahs: anc = nullid elif len(cahs) == 1: diff -r de18c43f8ce1 -r 8d85d7ca9fd3 mercurial/util.py --- a/mercurial/util.py Thu Mar 16 10:10:00 2017 +0530 +++ b/mercurial/util.py Thu Mar 16 10:11:21 2017 +0530 @@ -2920,7 +2920,7 @@ del dirs[base] def __iter__(self): -return self._dirs.iterkeys() +return iter(self._dirs) def __contains__(self, d): return d in self._dirs ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 2 of 3 py3] commands: convert opts back to bytes for status
# HG changeset patch # User Pulkit Goyal <7895pul...@gmail.com> # Date 1489639200 -19800 # Thu Mar 16 10:10:00 2017 +0530 # Node ID de18c43f8ce17d52542e6df233e809b6a6ee0a07 # Parent 47dae3bbf8560824743293870aab601da2d1ed6c commands: convert opts back to bytes for status diff -r 47dae3bbf856 -r de18c43f8ce1 mercurial/commands.py --- a/mercurial/commands.py Thu Mar 16 10:01:12 2017 +0530 +++ b/mercurial/commands.py Thu Mar 16 10:10:00 2017 +0530 @@ -4720,6 +4720,7 @@ Returns 0 on success. """ +opts = pycompat.byteskwargs(opts) revs = opts.get('rev') change = opts.get('change') ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 1 of 3 py3] error: convert the error into strings to pass into ui.warn()
# HG changeset patch # User Pulkit Goyal <7895pul...@gmail.com> # Date 1489638672 -19800 # Thu Mar 16 10:01:12 2017 +0530 # Node ID 47dae3bbf8560824743293870aab601da2d1ed6c # Parent 63aeb39b5802644ae99eaa5cf0666f3bf5cc4e90 error: convert the error into strings to pass into ui.warn() diff -r 63aeb39b5802 -r 47dae3bbf856 mercurial/scmutil.py --- a/mercurial/scmutil.py Thu Mar 16 09:13:13 2017 +0530 +++ b/mercurial/scmutil.py Thu Mar 16 10:01:12 2017 +0530 @@ -168,7 +168,8 @@ if inst.hint: ui.warn('(%s)\n' % inst.hint) except error.RepoError as inst: -ui.warn(_("abort: %s!\n") % inst) +if inst.args: +ui.warn(_("abort: %s!\n") % ''.join(inst.args)) if inst.hint: ui.warn(_("(%s)\n") % inst.hint) except error.ResponseError as inst: ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 7 of 7] test: add a basic 'test-check-pylint.t'
On 03/15/2017 10:13 AM, Kevin Bullock wrote: On Mar 15, 2017, at 11:35, Gregory Szorc wrote: On Mar 15, 2017, at 07:56, Kevin Bullock wrote: On Mar 15, 2017, at 02:01, Pierre-Yves David wrote: # HG changeset patch # User Pierre-Yves David # Date 1482964970 -3600 # Wed Dec 28 23:42:50 2016 +0100 # Node ID e1b0b1909c43858ff4b4e1821afbee9626c4cf0f # Parent b24451e8f9a6beee5501e9bedc47af7edc283ea4 # EXP-Topic check-pylint # Available At https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ # hg pull https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ -r e1b0b1909c43 test: add a basic 'test-check-pylint.t' We add a minimal check using pylint for one case we knows we care about: "mutable default" argument. We'll likely extend this over time to cover other useful checks but this is a good starting point. I had to dig a bit to convince myself that pyflakes, which we already integrated, won't catch this. It indeed will not, so this LGTM. Copy-edited the new test and pushed. We may want to look into flake8. It wraps the popular linters in a single interface and is quite nice. The downside for our use case is that output will be different unless all the linters it wraps are present. Will flake8 also run pylint? I thought it was only pep8 + pyflakes. There are also a number of ways our style differs from PEP8, so that piece in particular wouldn't get us much over this one, where we now have both test-check-pyflakes.t and test-check-pylint.t. Worth considering, though, in the (very likely) case others know more than I do about flake8's capabilities. flake8 is run on the evolve extension (I think credit goes to Sean for the initial idea). Our style is quite far away from PEP8 so I've disabled a fair amount of message, but it still catch many useful thing. * evolve flake8 tests: https://www.mercurial-scm.org/repo/evolve/file/tip/tests/test-check-flake8.t * evolve flake8 config: https://www.mercurial-scm.org/repo/evolve/file/tip/setup.cfg Cheers, -- Pierre-Yves David ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 5 of 8] hgweb: explicitly tests for None in webutil
# HG changeset patch # User Pierre-Yves David # Date 1489615809 25200 # Wed Mar 15 15:10:09 2017 -0700 # Node ID 1596b4613bec63db08c0d4d10e3f26f5635ce21b # Parent 83112ff862072df863540c8c9356f64eb26faa41 # EXP-Topic mutable-default # Available At https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ # hg pull https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ -r 1596b4613bec hgweb: explicitly tests for None in webutil Changeset d2878bec55bd removed the mutable default value, but did not explicitly tested for None. Such implicit testing can introduce semantic and performance issue. We move to an explicit testing for None as recommended by PEP8: https://www.python.org/dev/peps/pep-0008/#programming-recommendations diff --git a/mercurial/hgweb/webutil.py b/mercurial/hgweb/webutil.py --- a/mercurial/hgweb/webutil.py +++ b/mercurial/hgweb/webutil.py @@ -143,7 +143,9 @@ class filerevnav(revnav): class _siblings(object): def __init__(self, siblings=None, hiderev=None): -self.siblings = [s for s in siblings or [] if s.node() != nullid] +if siblings is None: +siblings = [] +self.siblings = [s for s in siblings if s.node() != nullid] if len(self.siblings) == 1 and self.siblings[0].rev() == hiderev: self.siblings = [] ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 1 of 8] rebase: explicitly tests for None
# HG changeset patch # User Pierre-Yves David # Date 1489615423 25200 # Wed Mar 15 15:03:43 2017 -0700 # Node ID 6c6d8c0cc67de1ecd744a30889419510aa2064d2 # Parent 361bccce566afe250c8d258f770a908713b2d13f # EXP-Topic mutable-default # Available At https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ # hg pull https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ -r 6c6d8c0cc67d rebase: explicitly tests for None Changeset 361bccce566a removed the mutable default value, but did not explicitly tested for None. Such implicit checking can introduce semantic and performance issue. We move to an explicit check for None as recommended by PEP8: https://www.python.org/dev/peps/pep-0008/#programming-recommendations diff --git a/hgext/rebase.py b/hgext/rebase.py --- a/hgext/rebase.py +++ b/hgext/rebase.py @@ -725,7 +725,8 @@ def _definesets(ui, repo, destf=None, sr destspace=None): """use revisions argument to define destination and rebase set """ -revf = revf or [] +if revf is None: +revf = [] # destspace is here to work around issues with `hg pull --rebase` see # issue5214 for details ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 3 of 8] mq: explicitly tests for None
# HG changeset patch # User Pierre-Yves David # Date 1489615554 25200 # Wed Mar 15 15:05:54 2017 -0700 # Node ID 27d5ab143c3344006509c5a3b29e2cb66445aa04 # Parent 6d73a06abb85612fca7231fb71f245f82f7d6863 # EXP-Topic mutable-default # Available At https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ # hg pull https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ -r 27d5ab143c33 mq: explicitly tests for None Changeset fd3d8eb7f545 removed the mutable default value, but did not explicitly tested for None. Such implicit testing can introduce semantic and performance issue. We move to an explicit testing for None as recommended by PEP8: https://www.python.org/dev/peps/pep-0008/#programming-recommendations diff --git a/hgext/mq.py b/hgext/mq.py --- a/hgext/mq.py +++ b/hgext/mq.py @@ -722,7 +722,8 @@ class queue(object): def printdiff(self, repo, diffopts, node1, node2=None, files=None, fp=None, changes=None, opts=None): -opts = opts or {} +if opts is None: +opts = {} stat = opts.get('stat') m = scmutil.match(repo[node1], files, opts) cmdutil.diffordiffstat(self.ui, repo, diffopts, node1, node2, m, ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 6 of 8] hgweb: explicitly tests for None
# HG changeset patch # User Pierre-Yves David # Date 1489615864 25200 # Wed Mar 15 15:11:04 2017 -0700 # Node ID 28093cead8791382a984b4c80dcedbe529ea7c41 # Parent 1596b4613bec63db08c0d4d10e3f26f5635ce21b # EXP-Topic mutable-default # Available At https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ # hg pull https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ -r 28093cead879 hgweb: explicitly tests for None Changeset 7dafa8d0e006 removed the mutable default value, but did not explicitly tested for None. Such implicit testing can introduce semantic and performance issue. We move to an explicit testing for None as recommended by PEP8: https://www.python.org/dev/peps/pep-0008/#programming-recommendations diff --git a/mercurial/hgweb/common.py b/mercurial/hgweb/common.py --- a/mercurial/hgweb/common.py +++ b/mercurial/hgweb/common.py @@ -96,7 +96,9 @@ class ErrorResponse(Exception): message = _statusmessage(code) Exception.__init__(self, message) self.code = code -self.headers = headers or [] +if headers is None: +headers = [] +self.headers = headers class continuereader(object): def __init__(self, f, write): ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 2 of 8] util: explicitly tests for None
# HG changeset patch # User Pierre-Yves David # Date 1489615634 25200 # Wed Mar 15 15:07:14 2017 -0700 # Node ID 6d73a06abb85612fca7231fb71f245f82f7d6863 # Parent 6c6d8c0cc67de1ecd744a30889419510aa2064d2 # EXP-Topic mutable-default # Available At https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ # hg pull https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ -r 6d73a06abb85 util: explicitly tests for None Changeset 8b6927eb7efd removed the mutable default value, but did not explicitly tested for None. Such implicit checking can introduce semantic and performance issue. We move to an explicit check for None as recommended by PEP8: https://www.python.org/dev/peps/pep-0008/#programming-recommendations diff --git a/mercurial/util.py b/mercurial/util.py --- a/mercurial/util.py +++ b/mercurial/util.py @@ -1830,7 +1830,8 @@ def parsetimezone(s): def strdate(string, format, defaults=None): """parse a localized time string and return a (unixtime, offset) tuple. if the string cannot be parsed, ValueError is raised.""" -defaults = defaults or [] +if defaults is None: +defaults = [] # NOTE: unixtime = localunixtime + offset offset, date = parsetimezone(string) ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 7 of 8] filemerge: explicitly tests for None
# HG changeset patch # User Pierre-Yves David # Date 1489615912 25200 # Wed Mar 15 15:11:52 2017 -0700 # Node ID 414372f08c44186c8dad9dea46d617ab61412503 # Parent 28093cead8791382a984b4c80dcedbe529ea7c41 # EXP-Topic mutable-default # Available At https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ # hg pull https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ -r 414372f08c44 filemerge: explicitly tests for None Changeset 758526333dec removed the mutable default value, but did not explicitly tested for None. Such implicit testing can introduce semantic and performance issue. We move to an explicit testing for None as recommended by PEP8: https://www.python.org/dev/peps/pep-0008/#programming-recommendations diff --git a/mercurial/filemerge.py b/mercurial/filemerge.py --- a/mercurial/filemerge.py +++ b/mercurial/filemerge.py @@ -36,7 +36,9 @@ def _toolbool(ui, tool, part, default=Fa return ui.configbool("merge-tools", tool + "." + part, default) def _toollist(ui, tool, part, default=None): -return ui.configlist("merge-tools", tool + "." + part, default or []) +if default is None: +default = [] +return ui.configlist("merge-tools", tool + "." + part, default) internals = {} # Merge tools to document. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 4 of 8] match: explicitly tests for None
# HG changeset patch # User Pierre-Yves David # Date 1489615725 25200 # Wed Mar 15 15:08:45 2017 -0700 # Node ID 83112ff862072df863540c8c9356f64eb26faa41 # Parent 27d5ab143c3344006509c5a3b29e2cb66445aa04 # EXP-Topic mutable-default # Available At https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ # hg pull https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ -r 83112ff86207 match: explicitly tests for None Changeset 6168d4b93634 removed the mutable default value, but did not explicitly tested for None. Such implicit testing can introduce semantic and performance issue. We move to an explicit testing for None as recommended by PEP8: https://www.python.org/dev/peps/pep-0008/#programming-recommendations diff --git a/mercurial/match.py b/mercurial/match.py --- a/mercurial/match.py +++ b/mercurial/match.py @@ -117,8 +117,10 @@ class match(object): the same directory '' - a pattern of the specified default type """ -include = include or [] -exclude = exclude or [] +if include is None: +include = [] +if exclude is None: +exclude = [] self._root = root self._cwd = cwd ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 8 of 8] context: explicitly tests for None
# HG changeset patch # User Pierre-Yves David # Date 1489617204 25200 # Wed Mar 15 15:33:24 2017 -0700 # Node ID d912b21f4721d399fd327b6bb7179de7e2a614b6 # Parent 414372f08c44186c8dad9dea46d617ab61412503 # EXP-Topic mutable-default # Available At https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ # hg pull https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ -r d912b21f4721 context: explicitly tests for None Changeset 9e57033fec0c removed the mutable default value, but did not explicitly tested for None. Such implicit testing can introduce semantic and performance issue. We move to an explicit testing for None as recommended by PEP8: https://www.python.org/dev/peps/pep-0008/#programming-recommendations diff --git a/mercurial/context.py b/mercurial/context.py --- a/mercurial/context.py +++ b/mercurial/context.py @@ -300,8 +300,10 @@ class basectx(object): def match(self, pats=None, include=None, exclude=None, default='glob', listsubrepos=False, badfn=None): +if pats is None: +pats = [] r = self._repo -return matchmod.match(r.root, r.getcwd(), pats or [], +return matchmod.match(r.root, r.getcwd(), pats, include, exclude, default, auditor=r.nofsauditor, ctx=self, listsubrepos=listsubrepos, badfn=badfn) @@ -1517,16 +1519,18 @@ class workingctx(committablectx): def match(self, pats=None, include=None, exclude=None, default='glob', listsubrepos=False, badfn=None): +if pats is None: +pats = [] r = self._repo # Only a case insensitive filesystem needs magic to translate user input # to actual case in the filesystem. if not util.fscasesensitive(r.root): -return matchmod.icasefsmatcher(r.root, r.getcwd(), pats or [], +return matchmod.icasefsmatcher(r.root, r.getcwd(), pats, include, exclude, default, r.auditor, self, listsubrepos=listsubrepos, badfn=badfn) -return matchmod.match(r.root, r.getcwd(), pats or [], +return matchmod.match(r.root, r.getcwd(), pats, include, exclude, default, auditor=r.auditor, ctx=self, listsubrepos=listsubrepos, badfn=badfn) ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 6 of 6 py3] commands: make sure using byteschr rather than ascii values
On Mar 16, 2017 00:18, "Pulkit Goyal" <7895pul...@gmail.com> wrote: On Thu, Mar 16, 2017 at 10:14 AM, Martin von Zweigbergk < martinv...@google.com> wrote: > On Wed, Mar 15, 2017 at 9:13 PM, Pulkit Goyal <7895pul...@gmail.com> > wrote: > > # HG changeset patch > > # User Pulkit Goyal <7895pul...@gmail.com> > > # Date 1489635793 -19800 > > # Thu Mar 16 09:13:13 2017 +0530 > > # Node ID 63aeb39b5802644ae99eaa5cf0666f3bf5cc4e90 > > # Parent b5673a08993652a92c0e20a4e24d842194872454 <(219)%20487-2454> > > commands: make sure using byteschr rather than ascii values > > > > 'MAR!?IC' is converted to their ascii values when slicing through it. > This > > patch converts them back to bytes string. > > > > diff -r b5673a089936 -r 63aeb39b5802 mercurial/commands.py > > --- a/mercurial/commands.py Thu Mar 16 09:00:27 2017 +0530 > > +++ b/mercurial/commands.py Thu Mar 16 09:13:13 2017 +0530 > > @@ -4768,6 +4768,8 @@ > > showchar = not opts.get('no_status') > > > > for state, char, files in changestates: > > +if pycompat.ispy3: > > +char = bytes([char]) > > I'd prefer to wrap 'MAR!?C' in pycompat.iterbytestr() to avoid the > conditional here. What do you think?. Would that work? I am not sure about how you are saying to that. Using pycompat.iterbytes() we can iterate on 'MAR!?C', but in these we are iterating over three things at once. I mean to wrap it in the call to zip, so zip(x, iterbytes(y), z). ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 1 of 2 V2] py3: optimize py3 compat.bytechr using Struct.pack
On Wed, 15 Mar 2017 10:33:11 -0700, Martin von Zweigbergk via Mercurial-devel wrote: > # HG changeset patch > # User Martin von Zweigbergk > # Date 1489595450 25200 > # Wed Mar 15 09:30:50 2017 -0700 > # Node ID db74b2599efc1997b0e7e6bb7b699717029c11d8 > # Parent e83302d437485620c9bc25921f724af34cd5dd55 > py3: optimize py3 compat.bytechr using Struct.pack Nice. Queued these, thanks. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
mercurial@31423: 5 new changesets
5 new changesets in mercurial: https://www.mercurial-scm.org/repo/hg/rev/1fc3d1f02865 changeset: 31419:1fc3d1f02865 user:Pulkit Goyal <7895pul...@gmail.com> date:Thu Mar 16 06:32:33 2017 +0530 summary: scmutil: make function name bytes in class filecache https://www.mercurial-scm.org/repo/hg/rev/40704098853f changeset: 31420:40704098853f user:Pulkit Goyal <7895pul...@gmail.com> date:Thu Mar 16 07:52:47 2017 +0530 summary: match: make regular expression bytes to prevent TypeError https://www.mercurial-scm.org/repo/hg/rev/5c9cda37d7f6 changeset: 31421:5c9cda37d7f6 user:Pulkit Goyal <7895pul...@gmail.com> date:Thu Mar 16 08:03:51 2017 +0530 summary: match: slice over bytes to get the byteschr instead of ascii value https://www.mercurial-scm.org/repo/hg/rev/2e38a88bbc6c changeset: 31422:2e38a88bbc6c user:Pulkit Goyal <7895pul...@gmail.com> date:Thu Mar 16 09:00:27 2017 +0530 summary: dirstate: use list comprehension to get a list of keys https://www.mercurial-scm.org/repo/hg/rev/568d80b24b3a changeset: 31423:568d80b24b3a bookmark:@ tag: tip user:Ryan McElroy date:Wed Mar 15 19:26:20 2017 -0700 summary: tests: properly drop back to root dir in test-status.t -- Repository URL: https://www.mercurial-scm.org/repo/hg ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 3 of 7] parsers: avoid PyList_Append when parsing obs markers
On Mon, 13 Mar 2017 22:15:45 -0700, Gregory Szorc wrote: > # HG changeset patch > # User Gregory Szorc > # Date 1489454332 25200 > # Mon Mar 13 18:18:52 2017 -0700 > # Node ID 6d3b13f243bea2c9200eecb827d7ec0ea771fc54 > # Parent 3b997adb7efece7395fb585a70b2d70522626648 > parsers: avoid PyList_Append when parsing obs markers > > PyList_Append() has to continuously grow the underlying list as > available storage is exhausted. This adds overhead within tight > loops. > > It is better to create a new list of known size then use the > PyList_SET_ITEM macro to populate each element of the list > without error checking. This commit switches us to that > mechanism. > > The new code establishes an array to hold PyObject* instances > then iterates the array at the end. The bulk of the new code > is for memory management of the new array. There are some > inline comments explaining how the array is sized. > > `hg perfloadmarkers` show an improvement with this change: > > ! result: 130264 > ! wall 0.125479 comb 0.13 user 0.12 sys 0.01 (best of 76) > ! wall 0.120487 comb 0.13 user 0.12 sys 0.01 (best of 79) I'm not so enthusiastic about this perf number compared to the complexity of additional memory management. Does this contribute to the net perf win? > --- a/mercurial/parsers.c > +++ b/mercurial/parsers.c > @@ -2792,33 +2792,77 @@ static PyObject *fm1readmarkers(PyObject > int datalen; > Py_ssize_t offset, stop; > PyObject *markers = NULL; > + PyObject **tmpmarkers = NULL; > + Py_ssize_t tmpmarkerssize; > + Py_ssize_t tmpmarkersoffset = 0; > > if (!PyArg_ParseTuple(args, "s#nn", &data, &datalen, &offset, &stop)) { > return NULL; > } > dataend = data + datalen; > data += offset; > - markers = PyList_New(0); > - if (!markers) { > + > + /* > +We store an array of pointers to markers then build a list from > +it at the end. This is faster than appending to a PyList for each > +element. > + > +Reallocating the array constantly could be expensive. We estimate > +the size of the array by assuming 90 bytes per marker, which is > +based on data seen in the wild. > + */ > + tmpmarkerssize = datalen / 90; > + /* Handle datalen < 90 */ > + tmpmarkerssize = tmpmarkerssize ? tmpmarkerssize : 10; > + > + tmpmarkers = (PyObject **)PyMem_Malloc( > + tmpmarkerssize * sizeof(PyObject *)); > + if (!tmpmarkers) { > + PyErr_NoMemory(); > return NULL; > } Maybe we could do PyList_New(estimated_capacity) and shrink it at the end by PyList_SetSlice(). The API doc doesn't state that PyList_SetSlice() can handle NULL items, but builtin_zip() appears to do that. Python/bltinmodule.c:builtin_zip() > + free(tmpmarkers); This should be PyMem_Free() for consistency. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 4 of 7] parsers: handle refcounting of "parents" consistently
On Mon, 13 Mar 2017 22:15:46 -0700, Gregory Szorc wrote: > # HG changeset patch > # User Gregory Szorc > # Date 1489452553 25200 > # Mon Mar 13 17:49:13 2017 -0700 > # Node ID d600bd4edd62b3ee74730f1282e53b9d596bbaec > # Parent 6d3b13f243bea2c9200eecb827d7ec0ea771fc54 > parsers: handle refcounting of "parents" consistently > > Py_None can be refcounted like any other Python object. So > do that. Sure, queued this, thanks. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 5 of 7] [RFC] parsers: create a dedicated type for an obs marker
On Mon, 13 Mar 2017 22:15:47 -0700, Gregory Szorc wrote: > # HG changeset patch > # User Gregory Szorc > # Date 1489467734 25200 > # Mon Mar 13 22:02:14 2017 -0700 > # Node ID b4159d4c3683f03b6962991f318b080d849d6ba3 > # Parent d600bd4edd62b3ee74730f1282e53b9d596bbaec > [RFC] parsers: create a dedicated type for an obs marker I haven't reviewed these carefully, but I like the direction. fm1readmarkers() creates a bunch of boxed objects, which would have somewhat significant cost. Can we split obsmarker handling to new module? It's getting bigger. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 3 of 3 py3] context: explicitly evaluate list returned by map
On Thu, 16 Mar 2017 13:23:25 +0530, Pulkit Goyal wrote: > # HG changeset patch > # User Pulkit Goyal <7895pul...@gmail.com> > # Date 1489639281 -19800 > # Thu Mar 16 10:11:21 2017 +0530 > # Node ID 8d85d7ca9fd3eea90a2f09c7d471fc3f3c78d430 > # Parent de18c43f8ce17d52542e6df233e809b6a6ee0a07 > context: explicitly evaluate list returned by map > > On python 3, map returns an iterator so we need to convert it to list before > finding the len or subscripting it. > > After this `hg status --all` works on Python 3. > > diff -r de18c43f8ce1 -r 8d85d7ca9fd3 mercurial/context.py > --- a/mercurial/context.pyThu Mar 16 10:10:00 2017 +0530 > +++ b/mercurial/context.pyThu Mar 16 10:11:21 2017 +0530 > @@ -622,7 +622,7 @@ > n2 = c2._node > if n2 is None: > n2 = c2._parents[0]._node > -cahs = self._repo.changelog.commonancestorsheads(self._node, n2) > +cahs = list(self._repo.changelog.commonancestorsheads(self._node, > n2)) Perhaps we should make commonancestorsheads() return a list so we'll never have another iterator-vs-list bug. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 2 of 3 py3] commands: convert opts back to bytes for status
On Thu, 16 Mar 2017 13:23:24 +0530, Pulkit Goyal wrote: > # HG changeset patch > # User Pulkit Goyal <7895pul...@gmail.com> > # Date 1489639200 -19800 > # Thu Mar 16 10:10:00 2017 +0530 > # Node ID de18c43f8ce17d52542e6df233e809b6a6ee0a07 > # Parent 47dae3bbf8560824743293870aab601da2d1ed6c > commands: convert opts back to bytes for status > > diff -r 47dae3bbf856 -r de18c43f8ce1 mercurial/commands.py > --- a/mercurial/commands.py Thu Mar 16 10:01:12 2017 +0530 > +++ b/mercurial/commands.py Thu Mar 16 10:10:00 2017 +0530 > @@ -4720,6 +4720,7 @@ > Returns 0 on success. > """ > > +opts = pycompat.byteskwargs(opts) > revs = opts.get('rev') > change = opts.get('change') Queued this, thanks. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 1 of 3 py3] error: convert the error into strings to pass into ui.warn()
On Thu, 16 Mar 2017 13:23:23 +0530, Pulkit Goyal wrote: > # HG changeset patch > # User Pulkit Goyal <7895pul...@gmail.com> > # Date 1489638672 -19800 > # Thu Mar 16 10:01:12 2017 +0530 > # Node ID 47dae3bbf8560824743293870aab601da2d1ed6c > # Parent 63aeb39b5802644ae99eaa5cf0666f3bf5cc4e90 > error: convert the error into strings to pass into ui.warn() > > diff -r 63aeb39b5802 -r 47dae3bbf856 mercurial/scmutil.py > --- a/mercurial/scmutil.pyThu Mar 16 09:13:13 2017 +0530 > +++ b/mercurial/scmutil.pyThu Mar 16 10:01:12 2017 +0530 > @@ -168,7 +168,8 @@ > if inst.hint: > ui.warn('(%s)\n' % inst.hint) > except error.RepoError as inst: > -ui.warn(_("abort: %s!\n") % inst) > +if inst.args: > +ui.warn(_("abort: %s!\n") % ''.join(inst.args)) Maybe we'll need to implement __bytes__() in our exception classes? ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 1 of 4] tests: allow running doctests selectively on Python 3
# HG changeset patch # User Yuya Nishihara # Date 1488978812 -32400 # Wed Mar 08 22:13:32 2017 +0900 # Node ID f39291c08d86082579b891e844cbd56752b44a59 # Parent 63a39d64788872a5742f8e3143b7ddd603e3af13 tests: allow running doctests selectively on Python 3 Currently most doctests fail on Python 3, but I want to add some. diff --git a/tests/test-doctest.py b/tests/test-doctest.py --- a/tests/test-doctest.py +++ b/tests/test-doctest.py @@ -5,10 +5,16 @@ from __future__ import absolute_import import doctest import os import sys + +ispy3 = (sys.version_info[0] >= 3) + if 'TERM' in os.environ: del os.environ['TERM'] -def testmod(name, optionflags=0, testtarget=None): +# TODO: migrate doctests to py3 and enable them on both versions +def testmod(name, optionflags=0, testtarget=None, py2=True, py3=False): +if not (not ispy3 and py2 or ispy3 and py3): +return __import__(name) mod = sys.modules[name] if testtarget is not None: ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 4 of 4] py3: use bytestr wrapper in revsetlang.tokenize()
# HG changeset patch # User Yuya Nishihara # Date 1489667781 -32400 # Thu Mar 16 21:36:21 2017 +0900 # Node ID d21fd508342b1d43ebefaac65f1d6e2e5ca60704 # Parent 649866574c86bae35ab8143c50af72bee7fef810 py3: use bytestr wrapper in revsetlang.tokenize() This backs out 77270ec0cdd9 and wraps program by bytestr() instead. diff --git a/mercurial/revsetlang.py b/mercurial/revsetlang.py --- a/mercurial/revsetlang.py +++ b/mercurial/revsetlang.py @@ -78,6 +78,7 @@ def tokenize(program, lookup=None, symin [('symbol', '@', 0), ('::', None, 1), ('end', None, 3)] ''' +program = pycompat.bytestr(program) if syminitletters is None: syminitletters = _syminitletters if symletters is None: @@ -100,7 +101,7 @@ def tokenize(program, lookup=None, symin pos, l = 0, len(program) while pos < l: -c = program[pos:pos + 1] +c = program[pos] if c.isspace(): # skip inter-token whitespace pass elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully @@ -118,14 +119,14 @@ def tokenize(program, lookup=None, symin program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings if c == 'r': pos += 1 -c = program[pos:pos + 1] +c = program[pos] decode = lambda x: x else: decode = parser.unescapestr pos += 1 s = pos while pos < l: # find closing quote -d = program[pos:pos + 1] +d = program[pos] if d == '\\': # skip over escaped characters pos += 2 continue @@ -140,11 +141,10 @@ def tokenize(program, lookup=None, symin s = pos pos += 1 while pos < l: # find end of symbol -d = program[pos:pos + 1] +d = program[pos] if d not in symletters: break -if (d == '.' -and program[pos - 1:pos] == '.'): # special case for .. +if d == '.' and program[pos - 1] == '.': # special case for .. pos -= 1 break pos += 1 ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 3 of 4] py3: use bytestr wrapper in revsetlang.formatspec()
# HG changeset patch # User Yuya Nishihara # Date 1489667605 -32400 # Thu Mar 16 21:33:25 2017 +0900 # Node ID 649866574c86bae35ab8143c50af72bee7fef810 # Parent aae1bd4b8a03ffe6cb47c23da55b2f70ff5607ef py3: use bytestr wrapper in revsetlang.formatspec() This backs out 1c48a8278b2f and wraps expr by bytestr() instead. diff --git a/mercurial/revsetlang.py b/mercurial/revsetlang.py --- a/mercurial/revsetlang.py +++ b/mercurial/revsetlang.py @@ -640,14 +640,15 @@ def formatspec(expr, *args): m = l // 2 return '(%s or %s)' % (listexp(s[:m], t), listexp(s[m:], t)) +expr = pycompat.bytestr(expr) ret = '' pos = 0 arg = 0 while pos < len(expr): -c = expr[pos:pos + 1] +c = expr[pos] if c == '%': pos += 1 -d = expr[pos:pos + 1] +d = expr[pos] if d == '%': ret += d elif d in 'dsnbr': @@ -656,7 +657,7 @@ def formatspec(expr, *args): elif d == 'l': # a list of some type pos += 1 -d = expr[pos:pos + 1] +d = expr[pos] ret += listexp(list(args[arg]), d) arg += 1 else: ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 2 of 4] pycompat: add bytestr wrapper which mostly acts as a Python 2 str
# HG changeset patch # User Yuya Nishihara # Date 1488980906 -32400 # Wed Mar 08 22:48:26 2017 +0900 # Node ID aae1bd4b8a03ffe6cb47c23da55b2f70ff5607ef # Parent f39291c08d86082579b891e844cbd56752b44a59 pycompat: add bytestr wrapper which mostly acts as a Python 2 str This allows us to handle bytes in mostly the same manner as Python 2 str, so we can get rid of ugly s[i:i + 1] hacks: s = bytestr(s) while i < len(s): c = s[i] ... This is the simpler version of the previous RFC patch which tried to preserve the bytestr type if possible. New version simply drops the bytestr wrapping so we aren't likely to pass a bytestr to a function that expects Python 3 bytes. diff --git a/mercurial/pycompat.py b/mercurial/pycompat.py --- a/mercurial/pycompat.py +++ b/mercurial/pycompat.py @@ -76,6 +76,67 @@ if ispy3: bytechr = struct.Struct('>B').pack +class bytestr(bytes): +"""A bytes which mostly acts as a Python 2 str + +>>> bytestr(), bytestr(bytearray(b'foo')), bytestr(u'ascii'), bytestr(1) +(b'', b'foo', b'ascii', b'1') +>>> s = bytestr(b'foo') +>>> assert s is bytestr(s) + +There's no implicit conversion from non-ascii str as its encoding is +unknown: + +>>> bytestr(chr(0x80)) # doctest: +ELLIPSIS +Traceback (most recent call last): + ... +UnicodeEncodeError: ... + +Comparison between bytestr and bytes should work: + +>>> assert bytestr(b'foo') == b'foo' +>>> assert b'foo' == bytestr(b'foo') +>>> assert b'f' in bytestr(b'foo') +>>> assert bytestr(b'f') in b'foo' + +Sliced elements should be bytes, not integer: + +>>> s[1], s[:2] +(b'o', b'fo') +>>> list(s), list(reversed(s)) +([b'f', b'o', b'o'], [b'o', b'o', b'f']) + +As bytestr type isn't propagated across operations, you need to cast +bytes to bytestr explicitly: + +>>> s = bytestr(b'foo').upper() +>>> t = bytestr(s) +>>> s[0], t[0] +(70, b'F') + +Be careful to not pass a bytestr object to a function which expects +bytearray-like behavior. + +>>> t = bytes(t) # cast to bytes +>>> assert type(t) is bytes +""" + +def __new__(cls, s=b''): +if isinstance(s, bytestr): +return s +if not isinstance(s, (bytes, bytearray)): +s = str(s).encode(u'ascii') +return bytes.__new__(cls, s) + +def __getitem__(self, key): +s = bytes.__getitem__(self, key) +if not isinstance(s, bytes): +s = bytechr(s) +return s + +def __iter__(self): +return iterbytestr(bytes.__iter__(self)) + def iterbytestr(s): """Iterate bytes as if it were a str object of Python 2""" return map(bytechr, s) @@ -146,6 +207,7 @@ else: import cStringIO bytechr = chr +bytestr = str iterbytestr = iter def sysstr(s): diff --git a/tests/test-doctest.py b/tests/test-doctest.py --- a/tests/test-doctest.py +++ b/tests/test-doctest.py @@ -34,6 +34,7 @@ testmod('mercurial.minirst') testmod('mercurial.patch') testmod('mercurial.pathutil') testmod('mercurial.parser') +testmod('mercurial.pycompat', py3=True) testmod('mercurial.revsetlang') testmod('mercurial.smartset') testmod('mercurial.store') ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 5 of 7] [RFC] parsers: create a dedicated type for an obs marker
On Thu, Mar 16, 2017 at 7:34 AM, Yuya Nishihara wrote: > On Mon, 13 Mar 2017 22:15:47 -0700, Gregory Szorc wrote: > > # HG changeset patch > > # User Gregory Szorc > > # Date 1489467734 25200 > > # Mon Mar 13 22:02:14 2017 -0700 > > # Node ID b4159d4c3683f03b6962991f318b080d849d6ba3 > > # Parent d600bd4edd62b3ee74730f1282e53b9d596bbaec > > [RFC] parsers: create a dedicated type for an obs marker > > I haven't reviewed these carefully, but I like the direction. > fm1readmarkers() > creates a bunch of boxed objects, which would have somewhat significant > cost. > > Can we split obsmarker handling to new module? It's getting bigger. > Yes, I was considering that. But instead of creating N+1 Python modules, I'd like to move us in the direction of a single module built from multiple .c files. This is the approach I've taken in python-zstandard, for example. I believe this approach is superior because having a single compilation unit facilitates code reuse, inlining between source files, smaller binaries, and better performance. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 01 of 11] bdiff: use Python memory allocator in fixws
On Wed, Mar 15, 2017 at 11:16 PM, Jun Wu wrote: > Excerpts from Jun Wu's message of 2017-03-15 23:15:13 -0700: > > I think it makes sense to migrate Python modules to PyMem_*. > > > > However, I'm also a bit conservative about the "calloc" perf issue > mentioned > > by Yuya. I think it's safe to take Patch 1, 2, 4, 5 where there is no > calloc > > Sorry, it should be "Patch 1, 2, 4, and 6", not 5. I cannot count. > I agree with not taking the patches that remove calloc(). I'm pretty sure we don't actually need to zero the memory in some (all?) of those instances. But I can deal with that in a follow-up series. > > > change for now. We can figure out what to do with calloc / pure C code > > later. > > > > Excerpts from Gregory Szorc's message of 2017-03-09 13:59:09 -0800: > > > # HG changeset patch > > > # User Gregory Szorc > > > # Date 1489089265 28800 > > > # Thu Mar 09 11:54:25 2017 -0800 > > > # Node ID 7a8ce919a13a9ff6e73f391fe14d228e18387f15 > > > # Parent 1871a1ee64ed49172b1568b89cdbab126284b309 > > > bdiff: use Python memory allocator in fixws > > > > > > Python has its own memory allocation APIs. For allocations > > > <= 512 bytes, it allocates memory from arenas. This means that > > > average small allocations don't call the system allocator, which > > > makes them faster. Also, arena allocations cut down on memory > > > fragmentation, which can matter for performance in long-running > > > processes. > > > > > > Another advantage of using the Python memory allocator is that > > > allocations are tracked by Python. This is a bigger deal in > > > Python 3, as modern versions of Python have some decent built-in > > > tools for examining memory usage, leaks, etc. > > > > > > This patch converts a trivial malloc() + free() in the bdiff code > > > to use the Python allocator APIs. Since the object being > > > operated on is a line, chances are it will use an arena. So, > > > this could have a net positive impact on performance (although > > > I didn't measure it). > > > > > > diff --git a/mercurial/bdiff_module.c b/mercurial/bdiff_module.c > > > --- a/mercurial/bdiff_module.c > > > +++ b/mercurial/bdiff_module.c > > > @@ -158,7 +158,7 @@ static PyObject *fixws(PyObject *self, P > > > r = PyBytes_AsString(s); > > > rlen = PyBytes_Size(s); > > > > > > -w = (char *)malloc(rlen ? rlen : 1); > > > +w = (char *)PyMem_Malloc(rlen ? rlen : 1); > > > if (!w) > > > goto nomem; > > > > > > @@ -178,7 +178,7 @@ static PyObject *fixws(PyObject *self, P > > > result = PyBytes_FromStringAndSize(w, wlen); > > > > > > nomem: > > > -free(w); > > > +PyMem_Free(w); > > > return result ? result : PyErr_NoMemory(); > > > } > > > > ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 1 of 8] rebase: explicitly tests for None
On Thu, Mar 16, 2017 at 4:28 AM, Pierre-Yves David < pierre-yves.da...@ens-lyon.org> wrote: > # HG changeset patch > # User Pierre-Yves David > # Date 1489615423 25200 > # Wed Mar 15 15:03:43 2017 -0700 > # Node ID 6c6d8c0cc67de1ecd744a30889419510aa2064d2 > # Parent 361bccce566afe250c8d258f770a908713b2d13f > # EXP-Topic mutable-default > # Available At https://www.mercurial-scm.org/ > repo/users/marmoute/mercurial/ > # hg pull https://www.mercurial-scm.org/ > repo/users/marmoute/mercurial/ -r 6c6d8c0cc67d > rebase: explicitly tests for None > > Changeset 361bccce566a removed the mutable default value, but did not > explicitly > tested for None. Such implicit checking can introduce semantic and > performance > issue. We move to an explicit check for None as recommended by PEP8: > > https://www.python.org/dev/peps/pep-0008/#programming-recommendations I generally disagree with this series on the grounds that it doesn't matter in these use cases. Yes, there are times where this matters for performance or because we're leveraging dynamic programming to pass in different types that can all be empty. These are not those times. Also, if others insist on the "is None" check, I prefer the inline form (`revf = revf if revf is not None else []`) because I don't like wasting lines on type validation... because Python. > > > diff --git a/hgext/rebase.py b/hgext/rebase.py > --- a/hgext/rebase.py > +++ b/hgext/rebase.py > @@ -725,7 +725,8 @@ def _definesets(ui, repo, destf=None, sr > destspace=None): > """use revisions argument to define destination and rebase set > """ > -revf = revf or [] > +if revf is None: > +revf = [] > > # destspace is here to work around issues with `hg pull --rebase` see > # issue5214 for details > ___ > Mercurial-devel mailing list > Mercurial-devel@mercurial-scm.org > https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel > ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[Bug 5505] New: UnboundLocalError: local variable 'prompts' referenced before assignment
https://bz.mercurial-scm.org/show_bug.cgi?id=5505 Bug ID: 5505 Summary: UnboundLocalError: local variable 'prompts' referenced before assignment Product: Mercurial Version: 4.1.1 Hardware: PC OS: Windows Status: UNCONFIRMED Severity: bug Priority: wish Component: Mercurial Assignee: bugzi...@mercurial-scm.org Reporter: m...@michaelbaur.de CC: mercurial-devel@mercurial-scm.org I get this error during a large merge. ** Python 2.7.10 (default, May 23 2015, 09:44:00) [MSC v ** Mercurial Distributed SCM (version 4.1.1) ** Extensions loaded: transplant, rebase, extdiff, strip Traceback (most recent call last): File "hg", line 49, in File "mercurial\dispatch.pyo", line 63, in run File "mercurial\dispatch.pyo", line 129, in dispatch File "mercurial\dispatch.pyo", line 219, in _runcatch File "mercurial\dispatch.pyo", line 227, in callcatch File "mercurial\scmutil.pyo", line 152, in callcatch File "mercurial\dispatch.pyo", line 208, in _runcatchf File "mercurial\dispatch.pyo", line 811, in _dispatch File "mercurial\dispatch.pyo", line 563, in runcommand File "mercurial\extensions.pyo", line 223, in closure File "hgext\color.pyo", line 460, in colorcmd File "mercurial\dispatch.pyo", line 819, in _runcomman File "mercurial\dispatch.pyo", line 808, in File "mercurial\util.pyo", line 1051, in check File "mercurial\extensions.pyo", line 223, in closure File "mercurial\util.pyo", line 1051, in check File "hgext\mq.pyo", line 3541, in mqcommand File "mercurial\util.pyo", line 1051, in check File "mercurial\commands.pyo", line 4757, in merge File "mercurial\hg.pyo", line 775, in merge File "mercurial\merge.pyo", line 1660, in update File "mercurial\merge.pyo", line 1301, in applyupdates File "mercurial\subrepo.pyo", line 265, in submerge -- You are receiving this mail because: You are on the CC list for the bug. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 2 of 2] pager: skip running the pager if it's set to 'cat'
> On Mar 15, 2017, at 21:12, Jun Wu wrote: > > Another thing that git does (reasonably, I think) is to set default > environment variable. Say if we decide to go with shell=False, set LESS=FRX > so people using pager.pager=less will have a better experience. We should add that environment variable iff it's not already set in the user's environment, of course.___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 1 of 8] rebase: explicitly tests for None
On Thu, Mar 16, 2017 at 09:35:12AM -0700, Gregory Szorc wrote: > On Thu, Mar 16, 2017 at 4:28 AM, Pierre-Yves David < > pierre-yves.da...@ens-lyon.org> wrote: > > > # HG changeset patch > > # User Pierre-Yves David > > # Date 1489615423 25200 > > # Wed Mar 15 15:03:43 2017 -0700 > > # Node ID 6c6d8c0cc67de1ecd744a30889419510aa2064d2 > > # Parent 361bccce566afe250c8d258f770a908713b2d13f > > # EXP-Topic mutable-default > > # Available At https://www.mercurial-scm.org/ > > repo/users/marmoute/mercurial/ > > # hg pull https://www.mercurial-scm.org/ > > repo/users/marmoute/mercurial/ -r 6c6d8c0cc67d > > rebase: explicitly tests for None > > > > Changeset 361bccce566a removed the mutable default value, but did not > > explicitly > > tested for None. Such implicit checking can introduce semantic and > > performance > > issue. We move to an explicit check for None as recommended by PEP8: > > > > https://www.python.org/dev/peps/pep-0008/#programming-recommendations > > > I generally disagree with this series on the grounds that it doesn't matter > in these use cases. Yes, there are times where this matters for performance > or because we're leveraging dynamic programming to pass in different types > that can all be empty. These are not those times. > > Also, if others insist on the "is None" check, I prefer the inline form > (`revf = revf if revf is not None else []`) because I don't like wasting > lines on type validation... because Python. It's a minor change, but on the whole it's more idiomatic, so I'm in favor of it. Queued (I don't object to the one-line form, but given that this series is here and done, I'm too lazy to re-do all the work.) > > > > > > > > diff --git a/hgext/rebase.py b/hgext/rebase.py > > --- a/hgext/rebase.py > > +++ b/hgext/rebase.py > > @@ -725,7 +725,8 @@ def _definesets(ui, repo, destf=None, sr > > destspace=None): > > """use revisions argument to define destination and rebase set > > """ > > -revf = revf or [] > > +if revf is None: > > +revf = [] > > > > # destspace is here to work around issues with `hg pull --rebase` see > > # issue5214 for details > > ___ > > Mercurial-devel mailing list > > Mercurial-devel@mercurial-scm.org > > https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel > > > ___ > Mercurial-devel mailing list > Mercurial-devel@mercurial-scm.org > https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 3 of 7] parsers: avoid PyList_Append when parsing obs markers
On Mon, Mar 13, 2017 at 10:24:21PM -0700, Gregory Szorc wrote: > On Mon, Mar 13, 2017 at 10:15 PM, Gregory Szorc > wrote: > Assuming there is some truth to the numbers, holy cow the overhead of > PyObject creation is crazy. I suddenly feel like auditing the C code for > everywhere we're instantiating PyObjects before it is necessary. I know we > do this in the revlog index. I wonder if dirstate is impacted... Yeah, PyObject allocation can be pretty nasty. In my toy rust version of fm1readmarkers, it's 100x faster than the C code was, then 3x slower overall due to time spent copying data into PyObjects. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 5 of 7] [RFC] parsers: create a dedicated type for an obs marker
On Thu, Mar 16, 2017 at 09:17:05AM -0700, Gregory Szorc wrote: > On Thu, Mar 16, 2017 at 7:34 AM, Yuya Nishihara wrote: > > > On Mon, 13 Mar 2017 22:15:47 -0700, Gregory Szorc wrote: > > > # HG changeset patch > > > # User Gregory Szorc > > > # Date 1489467734 25200 > > > # Mon Mar 13 22:02:14 2017 -0700 > > > # Node ID b4159d4c3683f03b6962991f318b080d849d6ba3 > > > # Parent d600bd4edd62b3ee74730f1282e53b9d596bbaec > > > [RFC] parsers: create a dedicated type for an obs marker > > > > I haven't reviewed these carefully, but I like the direction. > > fm1readmarkers() > > creates a bunch of boxed objects, which would have somewhat significant > > cost. > > > > Can we split obsmarker handling to new module? It's getting bigger. > > > > Yes, I was considering that. > > But instead of creating N+1 Python modules, I'd like to move us in the > direction of a single module built from multiple .c files. This is the > approach I've taken in python-zstandard, for example. I believe this > approach is superior because having a single compilation unit facilitates > code reuse, inlining between source files, smaller binaries, and better > performance. > +1 for multiple .c files that compile into parsers.so for this. Also, making a type in C is probably unambiguously the right thing for handling our data formats anyplace it's viable, for exactly this reason. > ___ > Mercurial-devel mailing list > Mercurial-devel@mercurial-scm.org > https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Dropping support for Python 2.6 on Windows
There is a brewing discussion about the future of Python 2.6 in Mercurial. I'd like to start with what I think will be an easy proposal: officially dropping support for 2.6 on Windows. First, I think dropping 2.6 on Windows doesn't really buy us anything significant. 2.6 and 2.7 build with the same (ancient) Visual Studio toolchain. So it isn't like 2.6 is holding us back on C primitives we can use or anything. Also, I'm pretty sure none of the Mercurial on Windows packages we (or others) distribute use Python 2.6. So I don't think we save packagers any work. My main reason for dropping 2.6 on Windows is to get the policy change out of the way. Supporting this proposal is the fact that (correct me if I'm wrong) Mercurial with 2.6 on Windows is not tested nor widely used (see previous point about no packages targeting it). The only way (I think) people can get Mercurial running with 2.6 on Windows is if they download the source and compile it locally (possibly via pip). I think that's generally a small set of all Mercurial users on Windows and Python 2.6 users are a sliver of that population. Furthermore, I'm not aware of anyone in the Mercurial project doing Python 2.6 development on Windows. Linux and 2.6, yes. Windows and 2.7, yes. But not 2.6 on Windows. If we can't adequately test and support Mercurial with Python 2.6 on Windows, I argue it shouldn't be supported. My formal proposal is: a) establish a policy that Mercurial with Python 2.6 is not supported on Windows starting in the 4.2 release b) setup.py and `hg` reject Python 2.6 on Windows ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH V2] py3: use iter() instead of iterkeys()
On Thu, Mar 16, 2017 at 09:44:54AM +0530, Pulkit Goyal wrote: > On Thu, Mar 16, 2017 at 4:58 AM, Rishabh Madan > wrote: > > > # HG changeset patch > > # User Rishabh Madan > > # Date 1489620203 -19800 > > # Thu Mar 16 04:53:23 2017 +0530 > > # Node ID aab99adf3fd2f100f134ef7378faf4367550a4eb > > # Parent 1c48a8278b2f015fca607dfc652823560a5ac580 > > py3: use iter() instead of iterkeys() > > > > Once this and my current series is pushed, `hg status` works on Python 3. This is queued, thanks. > ___ > Mercurial-devel mailing list > Mercurial-devel@mercurial-scm.org > https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 2 of 2] localrepo: deprecated '_link'
On Wed, Mar 15, 2017 at 08:25:16AM -0700, Pierre-Yves David wrote: > # HG changeset patch > # User Pierre-Yves David > # Date 1470399345 -7200 > # Fri Aug 05 14:15:45 2016 +0200 > # Node ID c94039261ff0af3bcc5f7ff060d43eaf36a135f8 > # Parent 91ac4c04240637400bb3f172fc80ff011acfcfb7 > # EXP-Topic vfs.cleanup > # Available At https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ > # hg pull > https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ -r c94039261ff0 > localrepo: deprecated '_link' queued, thanks > > That method had a total on 1 internal user... > > > G: changed mercurial/localrepo.py > > diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py > --- a/mercurial/localrepo.py > +++ b/mercurial/localrepo.py > @@ -981,6 +981,8 @@ class localrepository(object): > return self.wvfs(f, mode) > > def _link(self, f): > +self.ui.deprecwarn("use 'repo.wvfs.islink' instead of 'repo._link'", > + '4.0') > return self.wvfs.islink(f) > > def _loadfilter(self, filter): > ___ > Mercurial-devel mailing list > Mercurial-devel@mercurial-scm.org > https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 4 of 4] py3: use bytestr wrapper in revsetlang.tokenize()
On Fri, Mar 17, 2017 at 12:31:13AM +0900, Yuya Nishihara wrote: > # HG changeset patch > # User Yuya Nishihara > # Date 1489667781 -32400 > # Thu Mar 16 21:36:21 2017 +0900 > # Node ID d21fd508342b1d43ebefaac65f1d6e2e5ca60704 > # Parent 649866574c86bae35ab8143c50af72bee7fef810 > py3: use bytestr wrapper in revsetlang.tokenize() Sure, queued, thanks. Much cleaner IMO. > > This backs out 77270ec0cdd9 and wraps program by bytestr() instead. > > diff --git a/mercurial/revsetlang.py b/mercurial/revsetlang.py > --- a/mercurial/revsetlang.py > +++ b/mercurial/revsetlang.py > @@ -78,6 +78,7 @@ def tokenize(program, lookup=None, symin > [('symbol', '@', 0), ('::', None, 1), ('end', None, 3)] > > ''' > +program = pycompat.bytestr(program) > if syminitletters is None: > syminitletters = _syminitletters > if symletters is None: > @@ -100,7 +101,7 @@ def tokenize(program, lookup=None, symin > > pos, l = 0, len(program) > while pos < l: > -c = program[pos:pos + 1] > +c = program[pos] > if c.isspace(): # skip inter-token whitespace > pass > elif c == ':' and program[pos:pos + 2] == '::': # look ahead > carefully > @@ -118,14 +119,14 @@ def tokenize(program, lookup=None, symin >program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings > if c == 'r': > pos += 1 > -c = program[pos:pos + 1] > +c = program[pos] > decode = lambda x: x > else: > decode = parser.unescapestr > pos += 1 > s = pos > while pos < l: # find closing quote > -d = program[pos:pos + 1] > +d = program[pos] > if d == '\\': # skip over escaped characters > pos += 2 > continue > @@ -140,11 +141,10 @@ def tokenize(program, lookup=None, symin > s = pos > pos += 1 > while pos < l: # find end of symbol > -d = program[pos:pos + 1] > +d = program[pos] > if d not in symletters: > break > -if (d == '.' > -and program[pos - 1:pos] == '.'): # special case for .. > +if d == '.' and program[pos - 1] == '.': # special case for > .. > pos -= 1 > break > pos += 1 > ___ > Mercurial-devel mailing list > Mercurial-devel@mercurial-scm.org > https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 2 of 8] util: explicitly tests for None
On Thu, Mar 16, 2017 at 04:28:06AM -0700, Pierre-Yves David wrote: > # HG changeset patch > # User Pierre-Yves David > # Date 1489615634 25200 > # Wed Mar 15 15:07:14 2017 -0700 > # Node ID 6d73a06abb85612fca7231fb71f245f82f7d6863 > # Parent 6c6d8c0cc67de1ecd744a30889419510aa2064d2 > # EXP-Topic mutable-default > # Available At https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ > # hg pull > https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ -r 6d73a06abb85 > util: explicitly tests for None FYI, this one failed to apply, but I didn't investigate due to time constraints on my end. > > Changeset 8b6927eb7efd removed the mutable default value, but did not > explicitly > tested for None. Such implicit checking can introduce semantic and performance > issue. We move to an explicit check for None as recommended by PEP8: > > https://www.python.org/dev/peps/pep-0008/#programming-recommendations > > diff --git a/mercurial/util.py b/mercurial/util.py > --- a/mercurial/util.py > +++ b/mercurial/util.py > @@ -1830,7 +1830,8 @@ def parsetimezone(s): > def strdate(string, format, defaults=None): > """parse a localized time string and return a (unixtime, offset) tuple. > if the string cannot be parsed, ValueError is raised.""" > -defaults = defaults or [] > +if defaults is None: > +defaults = [] > > # NOTE: unixtime = localunixtime + offset > offset, date = parsetimezone(string) > ___ > Mercurial-devel mailing list > Mercurial-devel@mercurial-scm.org > https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH] import-checkers: split tests of the tool from running it on the source
On Tue, Mar 14, 2017 at 11:16:36PM -0700, Pierre-Yves David wrote: > # HG changeset patch > # User Pierre-Yves David > # Date 1489558028 25200 > # Tue Mar 14 23:07:08 2017 -0700 > # Node ID 6e53450f1d41962edb5df6c2ff35d79adc04c775 > # Parent ed23f929af38e3249a4c0b258939e89782b20795 > # EXP-Topic import-checkers > # Available At https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ > # hg pull > https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ -r 6e53450f1d41 > import-checkers: split tests of the tool from running it on the source Sure, queued, thanks. > > We did such splits for other tools already. The 'test-check-*.t' performs the > check of the source code while the regular tests verifies the tools works. > > One of the benefit is that is provides a simple file to reuse in third party > extensions. > > diff --git a/tests/test-check-module-imports.t > b/tests/test-check-module-imports.t > --- a/tests/test-check-module-imports.t > +++ b/tests/test-check-module-imports.t > @@ -3,148 +3,6 @@ >$ . "$TESTDIR/helpers-testrepo.sh" >$ import_checker="$TESTDIR"/../contrib/import-checker.py > > -Run the doctests from the import checker, and make sure > -it's working correctly. > - $ TERM=dumb > - $ export TERM > - $ python -m doctest $import_checker > - > -Run additional tests for the import checker > - > - $ mkdir testpackage > - $ touch testpackage/__init__.py > - > - $ cat > testpackage/multiple.py << EOF > - > from __future__ import absolute_import > - > import os, sys > - > EOF > - > - $ cat > testpackage/unsorted.py << EOF > - > from __future__ import absolute_import > - > import sys > - > import os > - > EOF > - > - $ cat > testpackage/stdafterlocal.py << EOF > - > from __future__ import absolute_import > - > from . import unsorted > - > import os > - > EOF > - > - $ cat > testpackage/requirerelative.py << EOF > - > from __future__ import absolute_import > - > import testpackage.unsorted > - > EOF > - > - $ cat > testpackage/importalias.py << EOF > - > from __future__ import absolute_import > - > import ui > - > EOF > - > - $ cat > testpackage/relativestdlib.py << EOF > - > from __future__ import absolute_import > - > from .. import os > - > EOF > - > - $ cat > testpackage/symbolimport.py << EOF > - > from __future__ import absolute_import > - > from .unsorted import foo > - > EOF > - > - $ cat > testpackage/latesymbolimport.py << EOF > - > from __future__ import absolute_import > - > from . import unsorted > - > from mercurial.node import hex > - > EOF > - > - $ cat > testpackage/multiplegroups.py << EOF > - > from __future__ import absolute_import > - > from . import unsorted > - > from . import more > - > EOF > - > - $ mkdir testpackage/subpackage > - $ cat > testpackage/subpackage/levelpriority.py << EOF > - > from __future__ import absolute_import > - > from . import foo > - > from .. import parent > - > EOF > - > - $ touch testpackage/subpackage/foo.py > - $ cat > testpackage/subpackage/__init__.py << EOF > - > from __future__ import absolute_import > - > from . import levelpriority # should not cause cycle > - > EOF > - > - $ cat > testpackage/subpackage/localimport.py << EOF > - > from __future__ import absolute_import > - > from . import foo > - > def bar(): > - > # should not cause "higher-level import should come first" > - > from .. import unsorted > - > # but other errors should be detected > - > from .. import more > - > import testpackage.subpackage.levelpriority > - > EOF > - > - $ cat > testpackage/importmodulefromsub.py << EOF > - > from __future__ import absolute_import > - > from .subpackage import foo # not a "direct symbol import" > - > EOF > - > - $ cat > testpackage/importsymbolfromsub.py << EOF > - > from __future__ import absolute_import > - > from .subpackage import foo, nonmodule > - > EOF > - > - $ cat > testpackage/sortedentries.py << EOF > - > from __future__ import absolute_import > - > from . import ( > - > foo, > - > bar, > - > ) > - > EOF > - > - $ cat > testpackage/importfromalias.py << EOF > - > from __future__ import absolute_import > - > from . import ui > - > EOF > - > - $ cat > testpackage/importfromrelative.py << EOF > - > from __future__ import absolute_import > - > from testpackage.unsorted import foo > - > EOF > - > - $ mkdir testpackage2 > - $ touch testpackage2/__init__.py > - > - $ cat > testpackage2/latesymbolimport.py << EOF > - > from __future__ import absolute_import > - > from testpackage import unsorted > - > from mercurial.node import hex > - > EOF > - > - $ python "$import_checker" testpackage*/*.py testpackage/subpackage/*.py > - testpackage/importalias.py:2: ui module must be "as" aliased to uimod > - testpackage/importfromalias.py:2: ui from testpackage must be "as" aliased > to uimod > - testpackage/importfromrelative.py:2: import should be relative: > testpackage.unsor
Re: [PATCH 3 of 7] parsers: avoid PyList_Append when parsing obs markers
On Thu, Mar 16, 2017 at 9:50 AM, Augie Fackler wrote: > On Mon, Mar 13, 2017 at 10:24:21PM -0700, Gregory Szorc wrote: > > On Mon, Mar 13, 2017 at 10:15 PM, Gregory Szorc > > > wrote: > > Assuming there is some truth to the numbers, holy cow the overhead of > > PyObject creation is crazy. I suddenly feel like auditing the C code for > > everywhere we're instantiating PyObjects before it is necessary. I know > we > > do this in the revlog index. I wonder if dirstate is impacted... > > Yeah, PyObject allocation can be pretty nasty. In my toy rust version > of fm1readmarkers, it's 100x faster than the C code was, then 3x > slower overall due to time spent copying data into PyObjects. > !!! If it is 3x slower in the end, I highly suspect something sub-optimal with the Rust -> PyObject code path. My guess would be having to allocate memory and copy data for the hashes into PyBytes instances. We can leverage memoryview or any object implementing the buffer protocol so we can avoid that copy. You still pay for the PyObject overhead. But at least you aren't making extra copies of data. Also, I'm really curious when obs markers actually need to be realized. There is validation after parsing that successors aren't nullid. That can easily be inlined into C or deferred until first access. In theory, we could create our own Python type behaving as a sequence that turned C structs to PyObjects on demand. I'm just not sure if that buys us anything. The second you iterate over markers from Python, you throw away that optimization. Perhaps it would be better for the obs marker API to conceptually be a black box store that exposed primitives like "find X for ." That way, all the expensive computation can be done in C on raw data structures and we only realize PyObjects as needed. For cases where you are dealing with lists of fixed-width values, you could return an array of packed data instead of N PyObjects. Come to think of it, the computation of just hidden nodes might be the only super critical part to be all in Python. If we can do that in C without realizing tons PyObjects, I think a lot of read-only operations/commands just got a lot faster. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 3 of 7] parsers: avoid PyList_Append when parsing obs markers
> On Mar 16, 2017, at 10:09, Gregory Szorc wrote: > >> On Thu, Mar 16, 2017 at 9:50 AM, Augie Fackler wrote: >> On Mon, Mar 13, 2017 at 10:24:21PM -0700, Gregory Szorc wrote: >> > On Mon, Mar 13, 2017 at 10:15 PM, Gregory Szorc >> > wrote: >> > Assuming there is some truth to the numbers, holy cow the overhead of >> > PyObject creation is crazy. I suddenly feel like auditing the C code for >> > everywhere we're instantiating PyObjects before it is necessary. I know we >> > do this in the revlog index. I wonder if dirstate is impacted... >> >> Yeah, PyObject allocation can be pretty nasty. In my toy rust version >> of fm1readmarkers, it's 100x faster than the C code was, then 3x >> slower overall due to time spent copying data into PyObjects. >> > !!! Yeah, the actual parsing step was so fast I almost didn't believe it. Zero-copy parsers are pretty great. > > If it is 3x slower in the end, I highly suspect something sub-optimal with > the Rust -> PyObject code path. My guess would be having to allocate memory > and copy data for the hashes into PyBytes instances. We can leverage > memoryview or any object implementing the buffer protocol so we can avoid > that copy. You still pay for the PyObject overhead. But at least you aren't > making extra copies of data. My suspicion is that it's all the string copies, yeah. I also have wondered about the bindings I'm using doing something suboptimal with the GIL, but I haven't had time to wade through it or try and profile it. > > Also, I'm really curious when obs markers actually need to be realized. There > is validation after parsing that successors aren't nullid. That can easily be > inlined into C or deferred until first access. In theory, we could create our > own Python type behaving as a sequence that turned C structs to PyObjects on > demand. I'm just not sure if that buys us anything. The second you iterate > over markers from Python, you throw away that optimization. > > Perhaps it would be better for the obs marker API to conceptually be a black > box store that exposed primitives like "find X for ." That way, all the > expensive computation can be done in C on raw data structures and we only > realize PyObjects as needed. For cases where you are dealing with lists of > fixed-width values, you could return an array of packed data instead of N > PyObjects. Come to think of it, the computation of just hidden nodes might be > the only super critical part to be all in Python. If we can do that in C > without realizing tons PyObjects, I think a lot of read-only > operations/commands just got a lot faster. If we build that interface, the rust code I've got sitting around (using nom) is probably actually worth exploring in more detail. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: Dropping support for Python 2.6 on Windows
On Thu, Mar 16, 2017 at 09:54:27AM -0700, Gregory Szorc wrote: > There is a brewing discussion about the future of Python 2.6 in Mercurial. > I'd like to start with what I think will be an easy proposal: officially > dropping support for 2.6 on Windows. I'm in favor of this. Perhaps also sound the alarm that 2.6 will be dropped either in 4.3 or 4.4, since we keep accidentally breaking it, and dropping it entirely would be a nice quality of life improvement for the devs. Also, there's some work afoot in service of pypi and pip that should let us get cffi'd SecureTransport bindings on OS X, and probably also a nicer http client I don't have to write, but thoes are all unlikely to support 2.6. > > First, I think dropping 2.6 on Windows doesn't really buy us anything > significant. 2.6 and 2.7 build with the same (ancient) Visual Studio > toolchain. So it isn't like 2.6 is holding us back on C primitives we can > use or anything. Also, I'm pretty sure none of the Mercurial on Windows > packages we (or others) distribute use Python 2.6. So I don't think we save > packagers any work. > > My main reason for dropping 2.6 on Windows is to get the policy change out > of the way. > > Supporting this proposal is the fact that (correct me if I'm wrong) > Mercurial with 2.6 on Windows is not tested nor widely used (see previous > point about no packages targeting it). The only way (I think) people can > get Mercurial running with 2.6 on Windows is if they download the source > and compile it locally (possibly via pip). I think that's generally a small > set of all Mercurial users on Windows and Python 2.6 users are a sliver of > that population. > > Furthermore, I'm not aware of anyone in the Mercurial project doing Python > 2.6 development on Windows. Linux and 2.6, yes. Windows and 2.7, yes. But > not 2.6 on Windows. > > If we can't adequately test and support Mercurial with Python 2.6 on > Windows, I argue it shouldn't be supported. > > My formal proposal is: > > a) establish a policy that Mercurial with Python 2.6 is not supported on > Windows starting in the 4.2 release > b) setup.py and `hg` reject Python 2.6 on Windows > ___ > Mercurial-devel mailing list > Mercurial-devel@mercurial-scm.org > https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH v2] exewrapper: prefer HackableMercurial python if availbale
On Mon, Mar 13, 2017 at 01:06:41PM -0700, Kostia Balytskyi wrote: > # HG changeset patch > # User Kostia Balytskyi > # Date 1489434253 25200 > # Mon Mar 13 12:44:13 2017 -0700 > # Node ID 83925d3a3306e7023b4b43757812285b40fcd90b > # Parent 7548522742b5f4f9f5c0881ae4a2783ecda2f969 > exewrapper: prefer HackableMercurial python if availbale Sure, queued. Seems like the right choice. > > Currently hg.exe will only try to load python27.dll from hg-python > subdir if PYTHONHOME environment variable is not set. I think that > it is better to check whether 'hg-python' subdir exists and load > python from it in that case, regardless of environment. This allows > for reliable approach of distributing Mercurial with its own Python. > > diff --git a/mercurial/exewrapper.c b/mercurial/exewrapper.c > --- a/mercurial/exewrapper.c > +++ b/mercurial/exewrapper.c > @@ -67,51 +67,35 @@ int main(int argc, char *argv[]) > } > > pydll = NULL; > - /* > - We first check, that environment variable PYTHONHOME is *not* set. > - This just mimicks the behavior of the regular python.exe, which uses > - PYTHONHOME to find its installation directory (if it has been set). > - Note: Users of HackableMercurial are expected to *not* set PYTHONHOME! > - */ > - if (GetEnvironmentVariable("PYTHONHOME", envpyhome, > -sizeof(envpyhome)) == 0) > - { > - /* > - Environment var PYTHONHOME is *not* set. Let's see if we are > - running inside a HackableMercurial. > - */ > + > + p = strrchr(pyhome, '\\'); > + if (p == NULL) { > + err = "can't find backslash in module filename"; > + goto bail; > + } > + *p = 0; /* cut at directory */ > + > + /* check for private Python of HackableMercurial */ > + strcat_s(pyhome, sizeof(pyhome), "\\hg-python"); > > - p = strrchr(pyhome, '\\'); > - if (p == NULL) { > - err = "can't find backslash in module filename"; > + hfind = FindFirstFile(pyhome, &fdata); > + if (hfind != INVALID_HANDLE_VALUE) { > + /* Path .\hg-python exists. We are probably in HackableMercurial > + scenario, so let's load python dll from this dir. */ > + FindClose(hfind); > + strcpy_s(pydllfile, sizeof(pydllfile), pyhome); > + strcat_s(pydllfile, sizeof(pydllfile), "\\" HGPYTHONLIB ".dll"); > + pydll = LoadLibrary(pydllfile); > + if (pydll == NULL) { > + err = "failed to load private Python DLL " HGPYTHONLIB > ".dll"; > goto bail; > } > - *p = 0; /* cut at directory */ > - > - /* check for private Python of HackableMercurial */ > - strcat_s(pyhome, sizeof(pyhome), "\\hg-python"); > - > - hfind = FindFirstFile(pyhome, &fdata); > - if (hfind != INVALID_HANDLE_VALUE) { > - /* path pyhome exists, let's use it */ > - FindClose(hfind); > - strcpy_s(pydllfile, sizeof(pydllfile), pyhome); > - strcat_s(pydllfile, sizeof(pydllfile), > - "\\" HGPYTHONLIB ".dll"); > - pydll = LoadLibrary(pydllfile); > - if (pydll == NULL) { > - err = "failed to load private Python DLL " > - HGPYTHONLIB ".dll"; > - goto bail; > - } > - Py_SetPythonHome = (void*)GetProcAddress(pydll, > - "Py_SetPythonHome"); > - if (Py_SetPythonHome == NULL) { > - err = "failed to get Py_SetPythonHome"; > - goto bail; > - } > - Py_SetPythonHome(pyhome); > + Py_SetPythonHome = (void*)GetProcAddress(pydll, > "Py_SetPythonHome"); > + if (Py_SetPythonHome == NULL) { > + err = "failed to get Py_SetPythonHome"; > + goto bail; > } > + Py_SetPythonHome(pyhome); > } > > if (pydll == NULL) { > ___ > Mercurial-devel mailing list > Mercurial-devel@mercurial-scm.org > https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: Dropping support for Python 2.6 on Windows
On 3/16/17 09:54, Gregory Szorc wrote: There is a brewing discussion about the future of Python 2.6 in Mercurial. I'd like to start with what I think will be an easy proposal: officially dropping support for 2.6 on Windows. Sounds reasonable to me. First, I think dropping 2.6 on Windows doesn't really buy us anything significant. 2.6 and 2.7 build with the same (ancient) Visual Studio toolchain. So it isn't like 2.6 is holding us back on C primitives we can use or anything. Also, I'm pretty sure none of the Mercurial on Windows packages we (or others) distribute use Python 2.6. So I don't think we save packagers any work. My main reason for dropping 2.6 on Windows is to get the policy change out of the way. Supporting this proposal is the fact that (correct me if I'm wrong) Mercurial with 2.6 on Windows is not tested nor widely used (see previous point about no packages targeting it). The only way (I think) people can get Mercurial running with 2.6 on Windows is if they download the source and compile it locally (possibly via pip). I think that's generally a small set of all Mercurial users on Windows and Python 2.6 users are a sliver of that population. Furthermore, I'm not aware of anyone in the Mercurial project doing Python 2.6 development on Windows. Linux and 2.6, yes. Windows and 2.7, yes. But not 2.6 on Windows. If we can't adequately test and support Mercurial with Python 2.6 on Windows, I argue it shouldn't be supported. My formal proposal is: a) establish a policy that Mercurial with Python 2.6 is not supported on Windows starting in the 4.2 release b) setup.py and `hg` reject Python 2.6 on Windows ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 7 of 7] py3: prove hg tip works
On Mon, Mar 13, 2017 at 11:59:08AM -0700, Yuya Nishihara wrote: > # HG changeset patch > # User Yuya Nishihara > # Date 1489422293 25200 > # Mon Mar 13 09:24:53 2017 -0700 > # Node ID f414ec9383e4c4dde3cbede18ef6afd71a78b474 > # Parent 2657aad32bdde8ab6225d988a0a5cd979f6834d1 > py3: prove hg tip works Very nice. Queued. > > diff --git a/tests/test-check-py3-commands.t b/tests/test-check-py3-commands.t > --- a/tests/test-check-py3-commands.t > +++ b/tests/test-check-py3-commands.t > @@ -51,6 +51,17 @@ out some potential warnings that come fr >\s*14 (re) >$ $PYTHON3 $HGBIN files | wc -l >\s*15 (re) > + > +Test if `hg tip` works: > + > + $ $PYTHON3 $HGBIN tip > + changeset: 10:e76ed1e480ef > + tag: tip > + user:oxymo...@cinder.waste.org > + date:Tue May 03 23:37:43 2005 -0800 > + summary: Fix linking of changeset revs when merging > + > + >$ cd .. > #endif > > ___ > Mercurial-devel mailing list > Mercurial-devel@mercurial-scm.org > https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 3 of 3] py3: call codecs.escape_encode() directly
On Thu, Mar 16, 2017 at 12:09:50AM +0900, Yuya Nishihara wrote: > # HG changeset patch > # User Yuya Nishihara > # Date 1489588119 -32400 > # Wed Mar 15 23:28:39 2017 +0900 > # Node ID fb6b172146566c203a18113536002a6f4b296879 > # Parent 8b8d561c82ee5c11827674dfff2866067d034eea > py3: call codecs.escape_encode() directly Queued, thanks. > > string_escape doesn't exist on Python 3, but fortunately the undocumented > codecs.escape_encode() function exists on CPython 2.6, 2.7, 3.5 and PyPy 5.6. > So let's use it for now. > > http://stackoverflow.com/a/23151714 > > diff --git a/mercurial/util.py b/mercurial/util.py > --- a/mercurial/util.py > +++ b/mercurial/util.py > @@ -17,6 +17,7 @@ from __future__ import absolute_import > > import bz2 > import calendar > +import codecs > import collections > import datetime > import errno > @@ -2131,7 +2132,9 @@ bytecount = unitcountfn( > ) > > def escapestr(s): > -return s.encode('string_escape') > +# call underlying function of s.encode('string_escape') directly for > +# Python 3 compatibility > +return codecs.escape_encode(s)[0] > > def uirepr(s): > # Avoid double backslash in Windows path repr() > ___ > Mercurial-devel mailing list > Mercurial-devel@mercurial-scm.org > https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH] branchmap: handle nullrev in setcachedata
On Wed, Mar 15, 2017 at 03:51:27PM -0700, Durham Goode wrote: > # HG changeset patch > # User Durham Goode > # Date 1489618137 25200 > # Wed Mar 15 15:48:57 2017 -0700 > # Node ID 6257ea07d629e83e85f68d0c83202b4111f6d4fd > # Parent e83302d437485620c9bc25921f724af34cd5dd55 > branchmap: handle nullrev in setcachedata Queued, thanks. > > 906be86990 recently changed to switch from: > > self._rbcrevs[rbcrevidx:rbcrevidx + _rbcrecsize] = rec > > to > > pack_into(_rbcrecfmt, self._rbcrevs, rbcrevidx, node, branchidx) > > This causes an exception if rbcrevidx is -1 (i.e. the nullrev). The old code > handled this because python handles out of bound sets to arrays gracefully. > The > new code throws because the self._rbcrevs buffer isn't long enough to write 8 > bytes to. Normally it would've been resized by the immediately preceding > line, > but because the 0 length buffer is greater than the idx (-1) times the size, > no > resize happens. > > Setting the branch for the nullrev doesn't make sense anyway, so let's skip > it. > This was caught by external tests in the Facebook extensions repo, but I've > added a test here that catches the issue. > > diff --git a/mercurial/branchmap.py b/mercurial/branchmap.py > --- a/mercurial/branchmap.py > +++ b/mercurial/branchmap.py > @@ -452,6 +452,8 @@ class revbranchcache(object): > > def _setcachedata(self, rev, node, branchidx): > """Writes the node's branch data to the in-memory cache data.""" > +if rev == nullrev: > +return > rbcrevidx = rev * _rbcrecsize > if len(self._rbcrevs) < rbcrevidx + _rbcrecsize: > self._rbcrevs.extend('\0' * > diff --git a/tests/test-branches.t b/tests/test-branches.t > --- a/tests/test-branches.t > +++ b/tests/test-branches.t > @@ -1,5 +1,10 @@ >$ hg init a >$ cd a > + > +Verify checking branch of nullrev before the cache is created doesnt crash > + $ hg log -r 'branch(.)' -T '{branch}\n' > + > +Basic test >$ echo 'root' >root >$ hg add root >$ hg commit -d '0 0' -m "Adding root node" > ___ > Mercurial-devel mailing list > Mercurial-devel@mercurial-scm.org > https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 3 of 7] parsers: avoid PyList_Append when parsing obs markers
On Thu, Mar 16, 2017 at 10:12 AM, Augie Fackler wrote: > > > On Mar 16, 2017, at 10:09, Gregory Szorc > wrote: > > > >> On Thu, Mar 16, 2017 at 9:50 AM, Augie Fackler wrote: > >> On Mon, Mar 13, 2017 at 10:24:21PM -0700, Gregory Szorc wrote: > >> > On Mon, Mar 13, 2017 at 10:15 PM, Gregory Szorc < > gregory.sz...@gmail.com> > >> > wrote: > >> > Assuming there is some truth to the numbers, holy cow the overhead of > >> > PyObject creation is crazy. I suddenly feel like auditing the C code > for > >> > everywhere we're instantiating PyObjects before it is necessary. I > know we > >> > do this in the revlog index. I wonder if dirstate is impacted... > >> > >> Yeah, PyObject allocation can be pretty nasty. In my toy rust version > >> of fm1readmarkers, it's 100x faster than the C code was, then 3x > >> slower overall due to time spent copying data into PyObjects. > >> > > !!! > > Yeah, the actual parsing step was so fast I almost didn't believe it. > Zero-copy parsers are pretty great. > > > > > If it is 3x slower in the end, I highly suspect something sub-optimal > with the Rust -> PyObject code path. My guess would be having to allocate > memory and copy data for the hashes into PyBytes instances. We can leverage > memoryview or any object implementing the buffer protocol so we can avoid > that copy. You still pay for the PyObject overhead. But at least you aren't > making extra copies of data. > > My suspicion is that it's all the string copies, yeah. I also have > wondered about the bindings I'm using doing something suboptimal with the > GIL, but I haven't had time to wade through it or try and profile it. > > > > > Also, I'm really curious when obs markers actually need to be realized. > There is validation after parsing that successors aren't nullid. That can > easily be inlined into C or deferred until first access. In theory, we > could create our own Python type behaving as a sequence that turned C > structs to PyObjects on demand. I'm just not sure if that buys us anything. > The second you iterate over markers from Python, you throw away that > optimization. > > > > Perhaps it would be better for the obs marker API to conceptually be a > black box store that exposed primitives like "find X for ." That way, > all the expensive computation can be done in C on raw data structures and > we only realize PyObjects as needed. For cases where you are dealing with > lists of fixed-width values, you could return an array of packed data > instead of N PyObjects. Come to think of it, the computation of just hidden > nodes might be the only super critical part to be all in Python. If we can > do that in C without realizing tons PyObjects, I think a lot of read-only > operations/commands just got a lot faster. > > If we build that interface, the rust code I've got sitting around (using > nom) is probably actually worth exploring in more detail. Last time we had the Rust discussion, we couldn't ship Rust due to distro packaging support. Has that changed? FWIW, Firefox appears to be driving a lot of distro support for Rust. Firefox 54+ now require Rust to build. Furthermore, Firefox is pretty aggressive about adopting new versions of Rust. What this means is that the next Firefox ESR (after 52, which was released last week) will effectively require distros to support whatever version of Rust that ESR is using. I'm not exactly where distros are w.r.t. Rust support today. But the major ones all know they need to get their Rust story in order for the next Firefox ESR, which I think is sometime in 2018. Ask me over beers what those conversations were like :) ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 3 of 7] parsers: avoid PyList_Append when parsing obs markers
> On Mar 16, 2017, at 10:43, Gregory Szorc wrote: > > Last time we had the Rust discussion, we couldn't ship Rust due to distro > packaging support. Has that changed? My gut feeling with my maintainer hat on is that any rust speedups would need to be opt-in, much like today's C speedups. My understanding of Rust is that it'll have significantly fewer ABI woes for our needs than C++ might. > FWIW, Firefox appears to be driving a lot of distro support for Rust. Firefox > 54+ now require Rust to build. Furthermore, Firefox is pretty aggressive > about adopting new versions of Rust. What this means is that the next Firefox > ESR (after 52, which was released last week) will effectively require distros > to support whatever version of Rust that ESR is using. I'm not exactly where > distros are w.r.t. Rust support today. But the major ones all know they need > to get their Rust story in order for the next Firefox ESR, which I think is > sometime in 2018. Ask me over beers what those conversations were like :) ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: Dropping support for Python 2.6 on Windows
On 16/03/2017 10:14, Augie Fackler wrote: On Thu, Mar 16, 2017 at 09:54:27AM -0700, Gregory Szorc wrote: There is a brewing discussion about the future of Python 2.6 in Mercurial. I'd like to start with what I think will be an easy proposal: officially dropping support for 2.6 on Windows. I'm in favor of this. Perhaps also sound the alarm that 2.6 will be dropped either in 4.3 or 4.4, since we keep accidentally breaking it, and dropping it entirely would be a nice quality of life improvement for the devs. Also, there's some work afoot in service of pypi and pip that should let us get cffi'd SecureTransport bindings on OS X, and probably also a nicer http client I don't have to write, but thoes are all unlikely to support 2.6. Just as added data for this decision, we (Facebook) will stop shipping and testing Mercurial built against Python 2.6 no later than 2017-04-30 (when we lose internal security support for our Python 2.6 systems). So the 4.3 release is likely to be the last release where we provide Python 2.6 testing during the freeze. We're hoping that our last consumers of Python 2.6 Mercurial will move onto Python 2.7 before 2017-03-31, so for the 4.3 freeze we're likely to only be running the test suite, not also getting feedback from real users. -- Simon Farnsworth ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH] util: explicitly tests for None
# HG changeset patch # User Pierre-Yves David # Date 1489615634 25200 # Wed Mar 15 15:07:14 2017 -0700 # Node ID 4f99a4fb0482a44178f96c29678ef4630056ff4e # Parent a5bad127128d8f60060be53d161acfa7a32a17d5 # EXP-Topic mutable-default # Available At https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ # hg pull https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ -r 4f99a4fb0482 util: explicitly tests for None Changeset 8b6927eb7efd removed the mutable default value, but did not explicitly tested for None. Such implicit checking can introduce semantic and performance issue. We move to an explicit check for None as recommended by PEP8: https://www.python.org/dev/peps/pep-0008/#programming-recommendations diff --git a/mercurial/util.py b/mercurial/util.py --- a/mercurial/util.py +++ b/mercurial/util.py @@ -1831,7 +1831,8 @@ def parsetimezone(s): def strdate(string, format, defaults=None): """parse a localized time string and return a (unixtime, offset) tuple. if the string cannot be parsed, ValueError is raised.""" -defaults = defaults or {} +if defaults is None: +defaults = {} # NOTE: unixtime = localunixtime + offset offset, date = parsetimezone(string) ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
mercurial@31427: 4 new changesets
4 new changesets in mercurial: https://www.mercurial-scm.org/repo/hg/rev/4acc49335a6e changeset: 31424:4acc49335a6e user:Martin von Zweigbergk date:Wed Mar 15 09:30:50 2017 -0700 summary: py3: optimize py3 compat.bytechr using Struct.pack https://www.mercurial-scm.org/repo/hg/rev/63a39d647888 changeset: 31425:63a39d647888 user:Martin von Zweigbergk date:Wed Mar 15 09:32:18 2017 -0700 summary: py3: make py3 compat.iterbytestr simpler and faster https://www.mercurial-scm.org/repo/hg/rev/43a7dfbead0c changeset: 31426:43a7dfbead0c user:Gregory Szorc date:Mon Mar 13 17:49:13 2017 -0700 summary: parsers: handle refcounting of "parents" consistently https://www.mercurial-scm.org/repo/hg/rev/b2fb0fd239b8 changeset: 31427:b2fb0fd239b8 bookmark:@ tag: tip user:Pulkit Goyal <7895pul...@gmail.com> date:Thu Mar 16 10:10:00 2017 +0530 summary: py3: convert opts back to bytes for status -- Repository URL: https://www.mercurial-scm.org/repo/hg ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH] wfile: fix deprecation warning version
# HG changeset patch # User Pierre-Yves David # Date 1489688275 25200 # Thu Mar 16 11:17:55 2017 -0700 # Node ID d26d5987f6ef6a8a260f2aef67838a66b9fe # Parent b2fb0fd239b88f0f9ec70c43f30d2f1ef0cb1049 # EXP-Topic fix-depr # Available At https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ # hg pull https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ -r d26d5987f6ef wfile: fix deprecation warning version The patch lingered a bit too long in my local clone and I messed up when I updated the version number. Since nobody caught it, I'm fixing the version after the fact. diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py --- a/mercurial/localrepo.py +++ b/mercurial/localrepo.py @@ -977,7 +977,7 @@ class localrepository(object): return self.dirstate.pathto(f, cwd) def wfile(self, f, mode='r'): -self.ui.deprecwarn("use 'repo.wvfs' instead of 'repo.wfile'", '4.1') +self.ui.deprecwarn("use 'repo.wvfs' instead of 'repo.wfile'", '4.2') return self.wvfs(f, mode) def _link(self, f): ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH] util: explicitly tests for None
That one is a V2, but I failed to invoque `hg email` correctly :-( On 03/16/2017 11:16 AM, Pierre-Yves David wrote: # HG changeset patch # User Pierre-Yves David # Date 1489615634 25200 # Wed Mar 15 15:07:14 2017 -0700 # Node ID 4f99a4fb0482a44178f96c29678ef4630056ff4e # Parent a5bad127128d8f60060be53d161acfa7a32a17d5 # EXP-Topic mutable-default # Available At https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ # hg pull https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ -r 4f99a4fb0482 util: explicitly tests for None Changeset 8b6927eb7efd removed the mutable default value, but did not explicitly tested for None. Such implicit checking can introduce semantic and performance issue. We move to an explicit check for None as recommended by PEP8: https://www.python.org/dev/peps/pep-0008/#programming-recommendations diff --git a/mercurial/util.py b/mercurial/util.py --- a/mercurial/util.py +++ b/mercurial/util.py @@ -1831,7 +1831,8 @@ def parsetimezone(s): def strdate(string, format, defaults=None): """parse a localized time string and return a (unixtime, offset) tuple. if the string cannot be parsed, ValueError is raised.""" -defaults = defaults or {} +if defaults is None: +defaults = {} # NOTE: unixtime = localunixtime + offset offset, date = parsetimezone(string) ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel -- Pierre-Yves David ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH] context: simplify call to icase matcher in 'match()'
# HG changeset patch # User Pierre-Yves David # Date 1489617482 25200 # Wed Mar 15 15:38:02 2017 -0700 # Node ID d980847dfbb24f63306441d86a75741df851d3ee # Parent a5bad127128d8f60060be53d161acfa7a32a17d5 # EXP-Topic cleanup # Available At https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ # hg pull https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ -r d980847dfbb2 context: simplify call to icase matcher in 'match()' The two function takes the very same arguments. We make this clearer and less error prone by dispatching on the function only and having a single call point in the code. diff --git a/mercurial/context.py b/mercurial/context.py --- a/mercurial/context.py +++ b/mercurial/context.py @@ -1525,15 +1525,13 @@ class workingctx(committablectx): # Only a case insensitive filesystem needs magic to translate user input # to actual case in the filesystem. +matcherfunc = matchmod.match if not util.fscasesensitive(r.root): -return matchmod.icasefsmatcher(r.root, r.getcwd(), pats, - include, exclude, default, r.auditor, - self, listsubrepos=listsubrepos, - badfn=badfn) -return matchmod.match(r.root, r.getcwd(), pats, - include, exclude, default, - auditor=r.auditor, ctx=self, - listsubrepos=listsubrepos, badfn=badfn) +matcherfunc = matchmod.icasefsmatcher +return matcherfunc(r.root, r.getcwd(), pats, + include, exclude, default, + auditor=r.auditor, ctx=self, + listsubrepos=listsubrepos, badfn=badfn) def _filtersuspectsymlink(self, files): if not files or self._repo.dirstate._checklink: ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[Bug 5506] New: bundle -t zstd fails on long-lived repository
https://bz.mercurial-scm.org/show_bug.cgi?id=5506 Bug ID: 5506 Summary: bundle -t zstd fails on long-lived repository Product: Mercurial Version: 4.1.1 Hardware: All OS: All Status: UNCONFIRMED Severity: bug Priority: wish Component: bundle2 Assignee: bugzi...@mercurial-scm.org Reporter: fo...@lares.dti.ne.jp CC: mercurial-devel@mercurial-scm.org, pierre-yves.da...@ens-lyon.org On long-lived repository (5.5 years or so, or one created with usegeneraldelta=no, explicitly), "hg bundle --type zstd" fails with error below. File "/mercurial/bundle2.py", line 1320, in writebundle header, comp = bundletypes[bundletype] KeyError: 'HG10ZS' If current repository doesn't have "generaldelta" in its requirements, parsebundlespec() in exchange.py returns "v1" as "appropriate bundle version". This causes unknown bundle type name "HG10ZS" for "hg bundle --type zstd". This issue can be reproduced by steps below. $ hg --config format.usegeneraldelta=no init repo $ echo a > repo/a $ hg -R repo commit -Am '#0' $ hg -R repo bundle --all --type zstd bundle.zstd -- You are receiving this mail because: You are on the CC list for the bug. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 2 of 2 STABLE] exchange: use v2 bundles for modern compression engines (issue5506)
# HG changeset patch # User Gregory Szorc # Date 1489692795 25200 # Thu Mar 16 12:33:15 2017 -0700 # Branch stable # Node ID 35019434aad6952ee9b3b41ee78a5a3efea9a0ab # Parent 8fed20619acd7a4346408e5819a1c91c52a39ed2 exchange: use v2 bundles for modern compression engines (issue5506) Previously, `hg bundle zstd` on a non-generaldelta repo would attempt to use a v1 bundle. This would fail because zstd is not supported on v1 bundles. This patch changes the behavior to automatically use a v2 bundle when the user explicitly requests a bundlespec that is a compression engine not supported on v1. If the bundlespec is -v1, it is still explicitly rejected because that request cannot be fulfilled. diff --git a/mercurial/exchange.py b/mercurial/exchange.py --- a/mercurial/exchange.py +++ b/mercurial/exchange.py @@ -130,8 +130,12 @@ def parsebundlespec(repo, spec, strict=T if spec in util.compengines.supportedbundlenames: compression = spec version = 'v1' +# Generaldelta repos require v2. if 'generaldelta' in repo.requirements: version = 'v2' +# Modern compression engines require v2. +if compression not in _bundlespecv1compengines: +version = 'v2' elif spec in _bundlespeccgversions: if spec == 'packed1': compression = 'none' diff --git a/tests/test-bundle-type.t b/tests/test-bundle-type.t --- a/tests/test-bundle-type.t +++ b/tests/test-bundle-type.t @@ -187,9 +187,7 @@ Explicit request for zstd on non-general $ hg --config format.usegeneraldelta=false init nogd $ hg -q -R nogd pull t1 $ hg -R nogd bundle -a -t zstd nogd-zstd - abort: compression engine zstd is not supported on v1 bundles - (see 'hg help bundle' for supported values for --type) - [255] + 1 changesets found zstd-v1 always fails ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 1 of 2 STABLE] exchange: reject new compression engines for v1 bundles (issue5506)
# HG changeset patch # User Gregory Szorc # Date 1489692236 25200 # Thu Mar 16 12:23:56 2017 -0700 # Branch stable # Node ID 8fed20619acd7a4346408e5819a1c91c52a39ed2 # Parent 86cd1f2cfff5d5f5ebda227b147ad71a59058323 exchange: reject new compression engines for v1 bundles (issue5506) Version 1 bundles only support a fixed set of compression engines. Before this change, we would accept any compression engine for v1 bundles, even those that may not work on v1. This could lead to an error. We define a fixed set of compression engines known to work with v1 bundles and we add checking to ensure a newer engine (like zstd) won't work with v1 bundles. I also took the liberty of adding test coverage for unknown compression names because I noticed we didn't have coverage of it before. diff --git a/mercurial/exchange.py b/mercurial/exchange.py --- a/mercurial/exchange.py +++ b/mercurial/exchange.py @@ -44,6 +44,9 @@ urlreq = util.urlreq 'bundle2': '02', #legacy } +# Compression engines allowed in version 1. THIS SHOULD NEVER CHANGE. +_bundlespecv1compengines = set(['gzip', 'bzip2', 'none']) + def parsebundlespec(repo, spec, strict=True, externalnames=False): """Parse a bundle string specification into parts. @@ -139,6 +142,12 @@ def parsebundlespec(repo, spec, strict=T raise error.UnsupportedBundleSpecification( _('%s is not a recognized bundle specification') % spec) +# Bundle version 1 only supports a known set of compression engines. +if version == 'v1' and compression not in _bundlespecv1compengines: +raise error.UnsupportedBundleSpecification( +_('compression engine %s is not supported on v1 bundles') % +compression) + # The specification for packed1 can optionally declare the data formats # required to apply it. If we see this metadata, compare against what the # repo supports and error if the bundle isn't compatible. diff --git a/tests/test-bundle-type.t b/tests/test-bundle-type.t --- a/tests/test-bundle-type.t +++ b/tests/test-bundle-type.t @@ -33,6 +33,23 @@ bundle w/o type option summary: a $ cd .. +Unknown compression type is rejected + + $ hg init t3 + $ cd t3 + $ hg -q pull ../b1 + $ hg bundle -a -t unknown out.hg + abort: unknown is not a recognized bundle specification + (see 'hg help bundle' for supported values for --type) + [255] + + $ hg bundle -a -t unknown-v2 out.hg + abort: unknown compression is not supported + (see 'hg help bundle' for supported values for --type) + [255] + + $ cd .. + test bundle types $ testbundle() { @@ -164,6 +181,23 @@ Compression level can be adjusted for bu c35a0f9217e65d1fdb90c936ffa7dbe679f83ddf zstd-v2 + +Explicit request for zstd on non-generaldelta repos + + $ hg --config format.usegeneraldelta=false init nogd + $ hg -q -R nogd pull t1 + $ hg -R nogd bundle -a -t zstd nogd-zstd + abort: compression engine zstd is not supported on v1 bundles + (see 'hg help bundle' for supported values for --type) + [255] + +zstd-v1 always fails + + $ hg -R tzstd bundle -a -t zstd-v1 zstd-v1 + abort: compression engine zstd is not supported on v1 bundles + (see 'hg help bundle' for supported values for --type) + [255] + #else zstd is a valid engine but isn't available ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
hg-git and round-tripping (and file copies?)
In trying to convert https://hg.java.net/hg/solaris-userland~gate to a git repo and back, I'm seeing issues at changeset 34, where the hash changes for reasons I can't see. If I do a diff of the debug log, I see it's due to the manifest: $ diff -u =(hg log -R userland-more --debug -r 34) =(hg log -R userland-more.hgagain --debug -r 34 | grep -v "^phase:") --- /tmp/zshhHyEIb 2017-03-16 11:37:57.601340643 -0700 +++ /tmp/zshlyqHbd 2017-03-16 11:37:57.793642372 -0700 @@ -1,12 +1,10 @@ no terminfo entry for sitm -changeset: 34:d20b10eba31725ad8954aa6d20374da512f0e636 -tag: build-149 +changeset: 34:2ccb817b85926f410df2a6bd23000265805088df parent: 33:371c8e56136d19872ae7db8d273f9de78c8fa783 parent: -1: -manifest:34:e031f26e68549dadb3dfb4705d429c75622a58b4 +manifest:34:5a12a2a1bf3e7c0f7c30d01bd09a2e37185bcfb6 user:Norm Jacobs date:Sun Sep 19 13:50:53 2010 -0700 -phase: public files: components/Makefile make-rules/prep.mk and if I use debugdata to look at the manifest at changeset 34, I see: $ gdiff -a -u =(hg -R userland-more debugdata -m 34) =(hg -R userland-more.hgagain debugdata -m 34) --- /tmp/zshOdnjza 2017-03-16 11:53:16.971130878 + +++ /tmp/zshzoTzmc 2017-03-16 11:53:17.118194061 + @@ -24,12 +24,12 @@ make-rules/setup.py.mk302733d738cc7c6cceb63457442f24f931867472 make-rules/shared-macros.mk03dd5df583b6e39a17ba66fc6ed6205df7f6be49 tools/Makefilecc964766028e3b963b4a321c88815d211415006b -tools/bass-o-matica618ef38ceda467b9a09680dd8b94debcd303037x +tools/bass-o-matic349f9611499fddf1a110f9488a84fb110c90b7bfx tools/build-watch.df69b9a2b6a265c06268733430bbf3f9aa7d5e160x tools/build-watch.pl5e23340c7a84ac555e630a5ccdc28eceda95f4b6x tools/time.ca0a1f64ff8ac947ce9d045e0448f8ee72f9fd273 -tools/userland-fetch851170bb5cebf2648c53d4909eac26ac2055cdd3x -tools/userland-unpack0977e35fa356d4cfab889b93613dc75d90d89b6bx +tools/userland-fetchbae023e70db29fd07f6f989aaa858cfaed09238ax +tools/userland-unpackb3800b9db86df38a644a653b3095805b269b6ac6x transforms/actuatorsc9d84677229efde5f89b1d985de5cd1b09267b56 transforms/archive-libraries-drop5b346a0133242f460ff66f6689790da094ce27f6 transforms/comparison-cleanupde1288c586594a171d43a3da5234cb920be408cc Now, those three files were copied in that changeset, but they're not the first to be copied, so it's not that, strictly. But it is the first changeset in which files were copied without being modified. The index data is off-by-one, if that makes any difference: $ hg -R userland-more debugrevlog -d tools/bass-o-matic # rev p1rev p2rev start end deltastart base p1 p2 rawsize totalsize compression heads chainlen 0-1-1 0 2175 00006005 6005 2 10 1 0-1 2175 2228 00005929 11934 5 11 $ hg -R userland-more.hgagain debugrevlog -d tools/bass-o-matic # rev p1rev p2rev start end deltastart base p1 p2 rawsize totalsize compression heads chainlen 0-1-1 0 2174 00006005 6005 2 10 1 0-1 2174 2227 00005929 11934 5 11 Any thoughts on how to further debug this? Or is this just https://bitbucket.org/durin42/hg-git/issues/46 and I'm out of luck? Thanks, Danek ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: hg-git and round-tripping (and file copies?)
On Thu, Mar 16, 2017 at 1:05 PM, Danek Duvall wrote: > In trying to convert > > https://hg.java.net/hg/solaris-userland~gate > > to a git repo and back, I'm seeing issues at changeset 34, where the hash > changes for reasons I can't see. If I do a diff of the debug log, I see > it's due to the manifest: > > $ diff -u =(hg log -R userland-more --debug -r 34) =(hg log -R > userland-more.hgagain --debug -r 34 | grep -v "^phase:") > --- /tmp/zshhHyEIb 2017-03-16 11:37:57.601340643 -0700 > +++ /tmp/zshlyqHbd 2017-03-16 11:37:57.793642372 -0700 > @@ -1,12 +1,10 @@ > no terminfo entry for sitm > -changeset: 34:d20b10eba31725ad8954aa6d20374da512f0e636 > -tag: build-149 > +changeset: 34:2ccb817b85926f410df2a6bd23000265805088df > parent: 33:371c8e56136d19872ae7db8d273f9de78c8fa783 > parent: -1: > -manifest:34:e031f26e68549dadb3dfb4705d429c75622a58b4 > +manifest:34:5a12a2a1bf3e7c0f7c30d01bd09a2e37185bcfb6 > user:Norm Jacobs > date:Sun Sep 19 13:50:53 2010 -0700 > -phase: public > files: > components/Makefile > make-rules/prep.mk > > and if I use debugdata to look at the manifest at changeset 34, I see: > > $ gdiff -a -u =(hg -R userland-more debugdata -m 34) =(hg -R > userland-more.hgagain debugdata -m 34) > --- /tmp/zshOdnjza 2017-03-16 11:53:16.971130878 + > +++ /tmp/zshzoTzmc 2017-03-16 11:53:17.118194061 + > @@ -24,12 +24,12 @@ > make-rules/setup.py.mk302733d738cc7c6cceb63457442f24f931867472 > make-rules/shared-macros.mk03dd5df583b6e39a17ba66fc6ed6205df7f6be49 > tools/Makefilecc964766028e3b963b4a321c88815d211415006b > -tools/bass-o-matica618ef38ceda467b9a09680dd8b94debcd303037x > +tools/bass-o-matic349f9611499fddf1a110f9488a84fb110c90b7bfx > tools/build-watch.df69b9a2b6a265c06268733430bbf3f9aa7d5e160x > tools/build-watch.pl5e23340c7a84ac555e630a5ccdc28eceda95f4b6x > tools/time.ca0a1f64ff8ac947ce9d045e0448f8ee72f9fd273 > -tools/userland-fetch851170bb5cebf2648c53d4909eac26ac2055cdd3x > -tools/userland-unpack0977e35fa356d4cfab889b93613dc75d90d89b6bx > +tools/userland-fetchbae023e70db29fd07f6f989aaa858cfaed09238ax > +tools/userland-unpackb3800b9db86df38a644a653b3095805b269b6ac6x > transforms/actuatorsc9d84677229efde5f89b1d985de5cd1b09267b56 > transforms/archive-libraries-drop5b346a0133242f460ff66f6689 > 790da094ce27f6 > transforms/comparison-cleanupde1288c586594a171d43a3da5234cb920be408cc > > Now, those three files were copied in that changeset, but they're not the > first to be copied, so it's not that, strictly. But it is the first > changeset in which files were copied without being modified. > > The index data is off-by-one, if that makes any difference: > > $ hg -R userland-more debugrevlog -d tools/bass-o-matic > # rev p1rev p2rev start end deltastart base p1 p2 rawsize > totalsize compression heads chainlen > 0-1-1 0 2175 00006005 > 6005 2 10 > 1 0-1 2175 2228 00005929 > 11934 5 11 > > $ hg -R userland-more.hgagain debugrevlog -d tools/bass-o-matic > # rev p1rev p2rev start end deltastart base p1 p2 rawsize > totalsize compression heads chainlen > 0-1-1 0 2174 00006005 > 6005 2 10 > 1 0-1 2174 2227 00005929 > 11934 5 11 > > Any thoughts on how to further debug this? > > Or is this just > > https://bitbucket.org/durin42/hg-git/issues/46 > > and I'm out of luck? > It is effectively impossible to round-trip between Git and Mercurial when file copies are involved. This is because Mercurial's filelog hashes include copy metadata and the parent nodes. Git's blob hashes, by contrast, are effectively content only. When you convert from Mercurial to Git, it will drop copy metadata (because Git doesn't track it explicitly). Then when you convert back to Mercurial, the copies have to be detected "just right" by hg-git for the hashes to align. Furthermore, the files have to be reintroduced in the same order, or the filelog parents may not align and the hashes may diverge. If a repo isn't linear, there's a non-zero chance of that happening. It is best to have a single canonical repo and replicate from that. Attempting "syncing" from multiple discrete repos will only lead to divergence. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 2 of 4] pycompat: add bytestr wrapper which mostly acts as a Python 2 str
On Thu, Mar 16, 2017 at 8:31 AM, Yuya Nishihara wrote: > # HG changeset patch > # User Yuya Nishihara > # Date 1488980906 -32400 > # Wed Mar 08 22:48:26 2017 +0900 > # Node ID aae1bd4b8a03ffe6cb47c23da55b2f70ff5607ef > # Parent f39291c08d86082579b891e844cbd56752b44a59 > pycompat: add bytestr wrapper which mostly acts as a Python 2 str > > This allows us to handle bytes in mostly the same manner as Python 2 str, > so we can get rid of ugly s[i:i + 1] hacks: > > s = bytestr(s) > while i < len(s): > c = s[i] > ... > > This is the simpler version of the previous RFC patch which tried to preserve > the bytestr type if possible. New version simply drops the bytestr wrapping > so we aren't likely to pass a bytestr to a function that expects Python 3 > bytes. > > diff --git a/mercurial/pycompat.py b/mercurial/pycompat.py > --- a/mercurial/pycompat.py > +++ b/mercurial/pycompat.py > @@ -76,6 +76,67 @@ if ispy3: > > bytechr = struct.Struct('>B').pack > > +class bytestr(bytes): > +"""A bytes which mostly acts as a Python 2 str > + > +>>> bytestr(), bytestr(bytearray(b'foo')), bytestr(u'ascii'), > bytestr(1) > +(b'', b'foo', b'ascii', b'1') > +>>> s = bytestr(b'foo') > +>>> assert s is bytestr(s) > + > +There's no implicit conversion from non-ascii str as its encoding is > +unknown: > + > +>>> bytestr(chr(0x80)) # doctest: +ELLIPSIS > +Traceback (most recent call last): > + ... > +UnicodeEncodeError: ... > + > +Comparison between bytestr and bytes should work: > + > +>>> assert bytestr(b'foo') == b'foo' > +>>> assert b'foo' == bytestr(b'foo') > +>>> assert b'f' in bytestr(b'foo') > +>>> assert bytestr(b'f') in b'foo' > + > +Sliced elements should be bytes, not integer: > + > +>>> s[1], s[:2] > +(b'o', b'fo') > +>>> list(s), list(reversed(s)) > +([b'f', b'o', b'o'], [b'o', b'o', b'f']) > + > +As bytestr type isn't propagated across operations, you need to cast > +bytes to bytestr explicitly: > + > +>>> s = bytestr(b'foo').upper() > +>>> t = bytestr(s) > +>>> s[0], t[0] > +(70, b'F') > + > +Be careful to not pass a bytestr object to a function which expects > +bytearray-like behavior. > + > +>>> t = bytes(t) # cast to bytes > +>>> assert type(t) is bytes > +""" > + > +def __new__(cls, s=b''): > +if isinstance(s, bytestr): > +return s > +if not isinstance(s, (bytes, bytearray)): > +s = str(s).encode(u'ascii') > +return bytes.__new__(cls, s) > + > +def __getitem__(self, key): > +s = bytes.__getitem__(self, key) > +if not isinstance(s, bytes): > +s = bytechr(s) > +return s > + > +def __iter__(self): > +return iterbytestr(bytes.__iter__(self)) > + > def iterbytestr(s): > """Iterate bytes as if it were a str object of Python 2""" > return map(bytechr, s) > @@ -146,6 +207,7 @@ else: > import cStringIO > > bytechr = chr > +bytestr = str Could this even be 'identity' (which apparently doesn't exist, so would be 'lambda s: s' or something)? Will str(a) create a copy of the underlying buffer too. I think I know that strings are immutable, so it shouldn't have to? > iterbytestr = iter > > def sysstr(s): > diff --git a/tests/test-doctest.py b/tests/test-doctest.py > --- a/tests/test-doctest.py > +++ b/tests/test-doctest.py > @@ -34,6 +34,7 @@ testmod('mercurial.minirst') > testmod('mercurial.patch') > testmod('mercurial.pathutil') > testmod('mercurial.parser') > +testmod('mercurial.pycompat', py3=True) > testmod('mercurial.revsetlang') > testmod('mercurial.smartset') > testmod('mercurial.store') > ___ > Mercurial-devel mailing list > Mercurial-devel@mercurial-scm.org > https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 2 of 4] pycompat: add bytestr wrapper which mostly acts as a Python 2 str
On Thu, Mar 16, 2017 at 1:47 PM, Martin von Zweigbergk wrote: > On Thu, Mar 16, 2017 at 8:31 AM, Yuya Nishihara wrote: >> # HG changeset patch >> # User Yuya Nishihara >> # Date 1488980906 -32400 >> # Wed Mar 08 22:48:26 2017 +0900 >> # Node ID aae1bd4b8a03ffe6cb47c23da55b2f70ff5607ef >> # Parent f39291c08d86082579b891e844cbd56752b44a59 >> pycompat: add bytestr wrapper which mostly acts as a Python 2 str >> >> This allows us to handle bytes in mostly the same manner as Python 2 str, >> so we can get rid of ugly s[i:i + 1] hacks: >> >> s = bytestr(s) >> while i < len(s): >> c = s[i] >> ... >> >> This is the simpler version of the previous RFC patch which tried to preserve >> the bytestr type if possible. New version simply drops the bytestr wrapping >> so we aren't likely to pass a bytestr to a function that expects Python 3 >> bytes. >> >> diff --git a/mercurial/pycompat.py b/mercurial/pycompat.py >> --- a/mercurial/pycompat.py >> +++ b/mercurial/pycompat.py >> @@ -76,6 +76,67 @@ if ispy3: >> >> bytechr = struct.Struct('>B').pack >> >> +class bytestr(bytes): >> +"""A bytes which mostly acts as a Python 2 str >> + >> +>>> bytestr(), bytestr(bytearray(b'foo')), bytestr(u'ascii'), >> bytestr(1) >> +(b'', b'foo', b'ascii', b'1') >> +>>> s = bytestr(b'foo') >> +>>> assert s is bytestr(s) >> + >> +There's no implicit conversion from non-ascii str as its encoding is >> +unknown: >> + >> +>>> bytestr(chr(0x80)) # doctest: +ELLIPSIS >> +Traceback (most recent call last): >> + ... >> +UnicodeEncodeError: ... >> + >> +Comparison between bytestr and bytes should work: >> + >> +>>> assert bytestr(b'foo') == b'foo' >> +>>> assert b'foo' == bytestr(b'foo') >> +>>> assert b'f' in bytestr(b'foo') >> +>>> assert bytestr(b'f') in b'foo' >> + >> +Sliced elements should be bytes, not integer: >> + >> +>>> s[1], s[:2] >> +(b'o', b'fo') >> +>>> list(s), list(reversed(s)) >> +([b'f', b'o', b'o'], [b'o', b'o', b'f']) >> + >> +As bytestr type isn't propagated across operations, you need to cast >> +bytes to bytestr explicitly: >> + >> +>>> s = bytestr(b'foo').upper() >> +>>> t = bytestr(s) >> +>>> s[0], t[0] >> +(70, b'F') >> + >> +Be careful to not pass a bytestr object to a function which expects >> +bytearray-like behavior. >> + >> +>>> t = bytes(t) # cast to bytes >> +>>> assert type(t) is bytes >> +""" >> + >> +def __new__(cls, s=b''): >> +if isinstance(s, bytestr): >> +return s >> +if not isinstance(s, (bytes, bytearray)): >> +s = str(s).encode(u'ascii') >> +return bytes.__new__(cls, s) >> + >> +def __getitem__(self, key): >> +s = bytes.__getitem__(self, key) >> +if not isinstance(s, bytes): >> +s = bytechr(s) >> +return s >> + >> +def __iter__(self): >> +return iterbytestr(bytes.__iter__(self)) >> + >> def iterbytestr(s): >> """Iterate bytes as if it were a str object of Python 2""" >> return map(bytechr, s) >> @@ -146,6 +207,7 @@ else: >> import cStringIO >> >> bytechr = chr >> +bytestr = str > > Could this even be 'identity' (which apparently doesn't exist, so > would be 'lambda s: s' or something)? Will str(a) create a copy of the > underlying buffer too. I think I know that strings are immutable, so > it shouldn't have to? The answer seems to be "no, nothing is copied". I could have sworn that when I first tested it, "str(a) is b" was False, but I must have been blind. Sorry about the noise. > > >> iterbytestr = iter >> >> def sysstr(s): >> diff --git a/tests/test-doctest.py b/tests/test-doctest.py >> --- a/tests/test-doctest.py >> +++ b/tests/test-doctest.py >> @@ -34,6 +34,7 @@ testmod('mercurial.minirst') >> testmod('mercurial.patch') >> testmod('mercurial.pathutil') >> testmod('mercurial.parser') >> +testmod('mercurial.pycompat', py3=True) >> testmod('mercurial.revsetlang') >> testmod('mercurial.smartset') >> testmod('mercurial.store') >> ___ >> Mercurial-devel mailing list >> Mercurial-devel@mercurial-scm.org >> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: hg-git and round-tripping (and file copies?)
Gregory Szorc wrote: > It is effectively impossible to round-trip between Git and Mercurial when > file copies are involved. This is because Mercurial's filelog hashes > include copy metadata and the parent nodes. Git's blob hashes, by contrast, > are effectively content only. When you convert from Mercurial to Git, it > will drop copy metadata (because Git doesn't track it explicitly). Then > when you convert back to Mercurial, the copies have to be detected "just > right" by hg-git for the hashes to align. Furthermore, the files have to be > reintroduced in the same order, or the filelog parents may not align and > the hashes may diverge. If a repo isn't linear, there's a non-zero chance > of that happening. Got it. > It is best to have a single canonical repo and replicate from that. > Attempting "syncing" from multiple discrete repos will only lead to > divergence. Sadly, that's not an option. We're just going to have to deal with the breakage, until such time as we can avoid the git intermediary. Thanks, Danek ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 1 of 2 py3 V2] dirstate: use next(iter) instead of iter.next
# HG changeset patch # User Pulkit Goyal <7895pul...@gmail.com> # Date 1489634873 -19800 # Thu Mar 16 08:57:53 2017 +0530 # Node ID c894bad6625973565b21f556896527141f123dd5 # Parent a5bad127128d8f60060be53d161acfa7a32a17d5 dirstate: use next(iter) instead of iter.next In Python 3 world, iter.next() is renamed to iter.__next__(). But next(iter) has the same behaviour. So let's replace iter.next() with next(iter). diff -r a5bad127128d -r c894bad66259 mercurial/dirstate.py --- a/mercurial/dirstate.py Wed Mar 15 15:48:57 2017 -0700 +++ b/mercurial/dirstate.py Thu Mar 16 08:57:53 2017 +0530 @@ -1115,9 +1115,8 @@ else: # We may not have walked the full directory tree above, # so stat and check everything we missed. -nf = iter(visit).next for st in util.statfiles([join(i) for i in visit]): -results[nf()] = st +results[next(iter(visit))] = st return results def status(self, match, subrepos, ignored, clean, unknown): ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 2 of 2 py3 V2] commands: make sure using byteschr rather than ascii values
# HG changeset patch # User Pulkit Goyal <7895pul...@gmail.com> # Date 1489635793 -19800 # Thu Mar 16 09:13:13 2017 +0530 # Node ID ec82445ccda47996e58a0c33fbbe8dbd7be0d2aa # Parent c894bad6625973565b21f556896527141f123dd5 commands: make sure using byteschr rather than ascii values 'MAR!?IC' is converted to their ascii values when slicing through it. This patch uses pycompat.iterbytestr() to get bytes value. diff -r c894bad66259 -r ec82445ccda4 mercurial/commands.py --- a/mercurial/commands.py Thu Mar 16 08:57:53 2017 +0530 +++ b/mercurial/commands.py Thu Mar 16 09:13:13 2017 +0530 @@ -4757,7 +4757,7 @@ stat = repo.status(node1, node2, m, 'ignored' in show, 'clean' in show, 'unknown' in show, opts.get('subrepos')) -changestates = zip(states, 'MAR!?IC', stat) +changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat) if (opts.get('all') or opts.get('copies') or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'): ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 1 of 2 py3 V2] dirstate: use next(iter) instead of iter.next
On Thu, Mar 16, 2017 at 2:24 PM, Pulkit Goyal <7895pul...@gmail.com> wrote: > # HG changeset patch > # User Pulkit Goyal <7895pul...@gmail.com> > # Date 1489634873 -19800 > # Thu Mar 16 08:57:53 2017 +0530 > # Node ID c894bad6625973565b21f556896527141f123dd5 > # Parent a5bad127128d8f60060be53d161acfa7a32a17d5 > dirstate: use next(iter) instead of iter.next > > In Python 3 world, iter.next() is renamed to iter.__next__(). But next(iter) > has the same behaviour. So let's replace iter.next() with next(iter). > > diff -r a5bad127128d -r c894bad66259 mercurial/dirstate.py > --- a/mercurial/dirstate.py Wed Mar 15 15:48:57 2017 -0700 > +++ b/mercurial/dirstate.py Thu Mar 16 08:57:53 2017 +0530 > @@ -1115,9 +1115,8 @@ > else: > # We may not have walked the full directory tree above, > # so stat and check everything we missed. > -nf = iter(visit).next > for st in util.statfiles([join(i) for i in visit]): > -results[nf()] = st > +results[next(iter(visit))] = st Won't "next(iter(visit))" get the first element of "visit" every time? Also, since we can no longer cache the .next function itself, and it seemed like the old version tried to care about that optimization, does this make a noticeable difference? Can you try to figure out under what circumstances nf() (in the old version) gets called very many times and see if you can measure a difference between the old version and the new version? Thanks. > return results > > def status(self, match, subrepos, ignored, clean, unknown): > ___ > Mercurial-devel mailing list > Mercurial-devel@mercurial-scm.org > https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH py3 V2] revlog: explicitly evaluate list to return
# HG changeset patch # User Pulkit Goyal <7895pul...@gmail.com> # Date 1489639281 -19800 # Thu Mar 16 10:11:21 2017 +0530 # Node ID 16e1d9557dcebfe827060a4d31781cb7498c2c45 # Parent e082ef765e4112ef69d3345369b142c87f1da3f4 revlog: explicitly evaluate list to return On python 3, map returns an iterator so we need to convert it to list before finding the len or subscripting it. After this `hg status --all` works on Python 3. diff -r e082ef765e41 -r 16e1d9557dce mercurial/revlog.py --- a/mercurial/revlog.py Thu Mar 16 10:01:12 2017 +0530 +++ b/mercurial/revlog.py Thu Mar 16 10:11:21 2017 +0530 @@ -943,7 +943,7 @@ ancs = self.index.commonancestorsheads(a, b) except (AttributeError, OverflowError): # C implementation failed ancs = ancestor.commonancestorsheads(self.parentrevs, a, b) -return map(self.node, ancs) +return list(map(self.node, ancs)) def isancestor(self, a, b): """return True if node a is an ancestor of node b ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 1 of 8] commit: get rid of ui.backupconfig
# HG changeset patch # User Jun Wu # Date 1489698920 25200 # Thu Mar 16 14:15:20 2017 -0700 # Node ID def9b72933ce717a48e3cc8fa4934bd3459b9479 # Parent 5c9cda37d7f6b181ab604c8d5a7592b5553f886b # Available At https://bitbucket.org/quark-zju/hg-draft # hg pull https://bitbucket.org/quark-zju/hg-draft -r def9b72933ce commit: get rid of ui.backupconfig diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -1703,23 +1703,19 @@ def _docommit(ui, repo, *pats, **opts): else: def commitfunc(ui, repo, message, match, opts): -backup = ui.backupconfig('phases', 'new-commit') +configoverride = {} +if opts.get('secret'): +configoverride[('phases', 'new-commit')] = 'secret' + baseui = repo.baseui -basebackup = baseui.backupconfig('phases', 'new-commit') -try: -if opts.get('secret'): -ui.setconfig('phases', 'new-commit', 'secret', 'commit') -# Propagate to subrepos -baseui.setconfig('phases', 'new-commit', 'secret', 'commit') - -editform = cmdutil.mergeeditform(repo[None], 'commit.normal') -editor = cmdutil.getcommiteditor(editform=editform, **opts) -return repo.commit(message, opts.get('user'), opts.get('date'), - match, - editor=editor, - extra=extra) -finally: -ui.restoreconfig(backup) -repo.baseui.restoreconfig(basebackup) - +with baseui.configoverride(configoverride, 'commit'): +with ui.configoverride(configoverride, 'commit'): +editform = cmdutil.mergeeditform(repo[None], + 'commit.normal') +editor = cmdutil.getcommiteditor(editform=editform, **opts) +return repo.commit(message, opts.get('user'), + opts.get('date'), + match, + editor=editor, + extra=extra) node = cmdutil.commit(ui, repo, commitfunc, pats, opts) ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 4 of 8] record: get rid of ui.backupconfig
# HG changeset patch # User Jun Wu # Date 1489700075 25200 # Thu Mar 16 14:34:35 2017 -0700 # Node ID 4ff0515eaa03cf3fdd2b19a3444eb9c2cebdbcea # Parent 01931210cd8d62aa56447843c096ea57bdf03889 # Available At https://bitbucket.org/quark-zju/hg-draft # hg pull https://bitbucket.org/quark-zju/hg-draft -r 4ff0515eaa03 record: get rid of ui.backupconfig diff --git a/hgext/record.py b/hgext/record.py --- a/hgext/record.py +++ b/hgext/record.py @@ -69,10 +69,7 @@ def record(ui, repo, *pats, **opts): opts["interactive"] = True -backup = ui.backupconfig('experimental', 'crecord') -try: -ui.setconfig('experimental', 'crecord', False, 'record') +override = {('experimental', 'crecord'): False} +with ui.configoverride(override, 'record'): return commands.commit(ui, repo, *pats, **opts) -finally: -ui.restoreconfig(backup) def qrefresh(origfn, ui, repo, *pats, **opts): @@ -118,11 +115,8 @@ def _qrecord(cmdsuggest, ui, repo, patch mq.new(ui, repo, patch, *pats, **opts) -backup = ui.backupconfig('experimental', 'crecord') -try: -ui.setconfig('experimental', 'crecord', False, 'record') +override = {('experimental', 'crecord'): False} +with ui.configoverride(override, 'record'): cmdutil.dorecord(ui, repo, committomq, cmdsuggest, False, cmdutil.recordfilter, *pats, **opts) -finally: -ui.restoreconfig(backup) def qnew(origfn, ui, repo, patch, *args, **opts): ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 6 of 8] mq: get rid of ui.backupconfig
# HG changeset patch # User Jun Wu # Date 1489700358 25200 # Thu Mar 16 14:39:18 2017 -0700 # Node ID 8b086a28d1b605d6c0726d77c21f8d13188691fa # Parent 93772a7ad2c443b7c92d0d23e85405f5b0d1a800 # Available At https://bitbucket.org/quark-zju/hg-draft # hg pull https://bitbucket.org/quark-zju/hg-draft -r 8b086a28d1b6 mq: get rid of ui.backupconfig diff --git a/hgext/mq.py b/hgext/mq.py --- a/hgext/mq.py +++ b/hgext/mq.py @@ -406,16 +406,10 @@ def newcommit(repo, phase, *args, **kwar if repo.ui.configbool('mq', 'secret', False): phase = phases.secret +override = {('ui', 'allowemptycommit'): True} if phase is not None: -phasebackup = repo.ui.backupconfig('phases', 'new-commit') -allowemptybackup = repo.ui.backupconfig('ui', 'allowemptycommit') -try: -if phase is not None: -repo.ui.setconfig('phases', 'new-commit', phase, 'mq') +override[('phases', 'new-commit')] = phase +with repo.ui.configoverride(override, 'mq'): repo.ui.setconfig('ui', 'allowemptycommit', True) return repo.commit(*args, **kwargs) -finally: -repo.ui.restoreconfig(allowemptybackup) -if phase is not None: -repo.ui.restoreconfig(phasebackup) class AbortNoCleanup(error.Abort): ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 2 of 8] clone: get rid of ui.backupconfig
# HG changeset patch # User Jun Wu # Date 1489699130 25200 # Thu Mar 16 14:18:50 2017 -0700 # Node ID 7b575fd8a7a1e9a96cd79352351d87ac69479270 # Parent def9b72933ce717a48e3cc8fa4934bd3459b9479 # Available At https://bitbucket.org/quark-zju/hg-draft # hg pull https://bitbucket.org/quark-zju/hg-draft -r 7b575fd8a7a1 clone: get rid of ui.backupconfig diff --git a/mercurial/hg.py b/mercurial/hg.py --- a/mercurial/hg.py +++ b/mercurial/hg.py @@ -614,12 +614,8 @@ def clone(ui, peeropts, source, dest=Non stream = None # internal config: ui.quietbookmarkmove -quiet = local.ui.backupconfig('ui', 'quietbookmarkmove') -try: -local.ui.setconfig( -'ui', 'quietbookmarkmove', True, 'clone') +override = {('ui', 'quietbookmarkmove'): True} +with local.ui.configoverride(override, 'clone'): exchange.pull(local, srcpeer, revs, streamclonerequested=stream) -finally: -local.ui.restoreconfig(quiet) elif srcrepo: exchange.push(srcrepo, destpeer, revs=revs, ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 5 of 8] histedit: get rid of ui.backupconfig
# HG changeset patch # User Jun Wu # Date 1489700195 25200 # Thu Mar 16 14:36:35 2017 -0700 # Node ID 93772a7ad2c443b7c92d0d23e85405f5b0d1a800 # Parent 4ff0515eaa03cf3fdd2b19a3444eb9c2cebdbcea # Available At https://bitbucket.org/quark-zju/hg-draft # hg pull https://bitbucket.org/quark-zju/hg-draft -r 93772a7ad2c4 histedit: get rid of ui.backupconfig diff --git a/hgext/histedit.py b/hgext/histedit.py --- a/hgext/histedit.py +++ b/hgext/histedit.py @@ -503,14 +503,10 @@ def commitfuncfor(repo, src): phasemin = src.phase() def commitfunc(**kwargs): -phasebackup = repo.ui.backupconfig('phases', 'new-commit') -try: -repo.ui.setconfig('phases', 'new-commit', phasemin, - 'histedit') +override = {('phases', 'new-commit'): phasemin} +with repo.ui.configoverride(override, 'histedit'): extra = kwargs.get('extra', {}).copy() extra['histedit_source'] = src.hex() kwargs['extra'] = extra return repo.commit(**kwargs) -finally: -repo.ui.restoreconfig(phasebackup) return commitfunc @@ -763,12 +759,9 @@ class fold(histeditaction): extra['histedit_source'] = '%s,%s' % (ctx.hex(), oldctx.hex()) commitopts['extra'] = extra -phasebackup = repo.ui.backupconfig('phases', 'new-commit') -try: -phasemin = max(ctx.phase(), oldctx.phase()) -repo.ui.setconfig('phases', 'new-commit', phasemin, 'histedit') +phasemin = max(ctx.phase(), oldctx.phase()) +override = {('phases', 'new-commit'): phasemin} +with repo.ui.configoverride(override, 'histedit'): n = collapse(repo, ctx, repo[newnode], commitopts, skipprompt=self.skipprompt()) -finally: -repo.ui.restoreconfig(phasebackup) if n is None: return ctx, [] ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 8 of 8] shelve: get rid of ui.backupconfig
# HG changeset patch # User Jun Wu # Date 1489699661 25200 # Thu Mar 16 14:27:41 2017 -0700 # Node ID 4f98fa7baebed161fe94c98661a8c404dd82a87d # Parent 8f87b407da24ee802e271f517dbc96ad32f21779 # Available At https://bitbucket.org/quark-zju/hg-draft # hg pull https://bitbucket.org/quark-zju/hg-draft -r 4f98fa7baebe shelve: get rid of ui.backupconfig diff --git a/hgext/shelve.py b/hgext/shelve.py --- a/hgext/shelve.py +++ b/hgext/shelve.py @@ -315,15 +315,14 @@ def getcommitfunc(extra, interactive, ed if hasmq: saved, repo.mq.checkapplied = repo.mq.checkapplied, False -backup = repo.ui.backupconfig('phases', 'new-commit') +override = {('phases', 'new-commit'): phases.secret} try: -repo.ui.setconfig('phases', 'new-commit', phases.secret) editor_ = False if editor: editor_ = cmdutil.getcommiteditor(editform='shelve.shelve', **opts) -return repo.commit(message, shelveuser, opts.get('date'), match, - editor=editor_, extra=extra) +with repo.ui.configoverride(override): +return repo.commit(message, shelveuser, opts.get('date'), + match, editor=editor_, extra=extra) finally: -repo.ui.restoreconfig(backup) if hasmq: repo.mq.checkapplied = saved @@ -851,7 +850,5 @@ def _dounshelve(ui, repo, *shelved, **op oldquiet = ui.quiet lock = tr = None -forcemerge = ui.backupconfig('ui', 'forcemerge') try: -ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'unshelve') lock = repo.lock() @@ -867,23 +864,26 @@ def _dounshelve(ui, repo, *shelved, **op # to the original pctx. -tmpwctx, addedbefore = _commitworkingcopychanges(ui, repo, opts, - tmpwctx) - -repo, shelvectx = _unshelverestorecommit(ui, repo, basename, oldquiet) -_checkunshelveuntrackedproblems(ui, repo, shelvectx) -branchtorestore = '' -if shelvectx.branch() != shelvectx.p1().branch(): -branchtorestore = shelvectx.branch() +override = {('ui', 'forcemerge'): opts.get('tool', '')} +with ui.configoverride(override, 'unshelve'): +tmpwctx, addedbefore = _commitworkingcopychanges(ui, repo, opts, + tmpwctx) -shelvectx = _rebaserestoredcommit(ui, repo, opts, tr, oldtiprev, - basename, pctx, tmpwctx, shelvectx, - branchtorestore) -mergefiles(ui, repo, pctx, shelvectx) -restorebranch(ui, repo, branchtorestore) -_forgetunknownfiles(repo, shelvectx, addedbefore) +repo, shelvectx = _unshelverestorecommit(ui, repo, basename, + oldquiet) +_checkunshelveuntrackedproblems(ui, repo, shelvectx) +branchtorestore = '' +if shelvectx.branch() != shelvectx.p1().branch(): +branchtorestore = shelvectx.branch() -shelvedstate.clear(repo) -_finishunshelve(repo, oldtiprev, tr) -unshelvecleanup(ui, repo, basename, opts) +shelvectx = _rebaserestoredcommit(ui, repo, opts, tr, oldtiprev, + basename, pctx, tmpwctx, + shelvectx, branchtorestore) +mergefiles(ui, repo, pctx, shelvectx) +restorebranch(ui, repo, branchtorestore) +_forgetunknownfiles(repo, shelvectx, addedbefore) + +shelvedstate.clear(repo) +_finishunshelve(repo, oldtiprev, tr) +unshelvecleanup(ui, repo, basename, opts) finally: ui.quiet = oldquiet @@ -891,5 +891,4 @@ def _dounshelve(ui, repo, *shelved, **op tr.release() lockmod.release(lock) -ui.restoreconfig(forcemerge) @command('shelve', ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 3 of 8] import: get rid of ui.backupconfig
# HG changeset patch # User Jun Wu # Date 1489699429 25200 # Thu Mar 16 14:23:49 2017 -0700 # Node ID 01931210cd8d62aa56447843c096ea57bdf03889 # Parent 7b575fd8a7a1e9a96cd79352351d87ac69479270 # Available At https://bitbucket.org/quark-zju/hg-draft # hg pull https://bitbucket.org/quark-zju/hg-draft -r 01931210cd8d import: get rid of ui.backupconfig diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py --- a/mercurial/cmdutil.py +++ b/mercurial/cmdutil.py @@ -972,11 +972,11 @@ def tryimportone(ui, repo, hunk, parents else: editor = getcommiteditor(editform=editform, **opts) -allowemptyback = repo.ui.backupconfig('ui', 'allowemptycommit') extra = {} for idfunc in extrapreimport: extrapreimportmap[idfunc](repo, extractdata, extra, opts) -try: -if partial: -repo.ui.setconfig('ui', 'allowemptycommit', True) +override = {} +if partial: +override[('ui', 'allowemptycommit')] = True +with repo.ui.configoverride(override, 'import'): n = repo.commit(message, user, date, match=m, @@ -984,6 +984,4 @@ def tryimportone(ui, repo, hunk, parents for idfunc in extrapostimport: extrapostimportmap[idfunc](repo[n]) -finally: -repo.ui.restoreconfig(allowemptyback) else: if opts.get('exact') or importbranch: ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 7 of 8] rebase: get rid of ui.backupconfig
# HG changeset patch # User Jun Wu # Date 1489700434 25200 # Thu Mar 16 14:40:34 2017 -0700 # Node ID 8f87b407da24ee802e271f517dbc96ad32f21779 # Parent 8b086a28d1b605d6c0726d77c21f8d13188691fa # Available At https://bitbucket.org/quark-zju/hg-draft # hg pull https://bitbucket.org/quark-zju/hg-draft -r 8f87b407da24 rebase: get rid of ui.backupconfig diff --git a/hgext/rebase.py b/hgext/rebase.py --- a/hgext/rebase.py +++ b/hgext/rebase.py @@ -851,8 +851,7 @@ def concludenode(repo, rev, p1, p2, comm extrafn(ctx, extra) -backup = repo.ui.backupconfig('phases', 'new-commit') -try: -targetphase = max(ctx.phase(), phases.draft) -repo.ui.setconfig('phases', 'new-commit', targetphase, 'rebase') +targetphase = max(ctx.phase(), phases.draft) +override = {('phases', 'new-commit'): targetphase} +with repo.ui.configoverride(override, 'rebase'): if keepbranch: repo.ui.setconfig('ui', 'allowemptycommit', True) @@ -862,6 +861,4 @@ def concludenode(repo, rev, p1, p2, comm newnode = repo.commit(text=commitmsg, user=ctx.user(), date=date, extra=extra, editor=editor) -finally: -repo.ui.restoreconfig(backup) repo.dirstate.setbranch(repo[newnode].branch()) ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
mercurial@31454: 27 new changesets
27 new changesets in mercurial: https://www.mercurial-scm.org/repo/hg/rev/9b361478b03a changeset: 31428:9b361478b03a user:Pierre-Yves David date:Fri Aug 05 14:19:31 2016 +0200 summary: localrepo: use self.wvfs.islink directly https://www.mercurial-scm.org/repo/hg/rev/2471368281d1 changeset: 31429:2471368281d1 user:Pierre-Yves David date:Fri Aug 05 14:15:45 2016 +0200 summary: localrepo: deprecated '_link' https://www.mercurial-scm.org/repo/hg/rev/807387581d89 changeset: 31430:807387581d89 user:Rishabh Madan date:Thu Mar 16 04:53:23 2017 +0530 summary: py3: use iter() instead of iterkeys() https://www.mercurial-scm.org/repo/hg/rev/406705701c2d changeset: 31431:406705701c2d user:Pierre-Yves David date:Wed Mar 15 15:03:43 2017 -0700 summary: rebase: explicitly tests for None https://www.mercurial-scm.org/repo/hg/rev/6e1c79578e5c changeset: 31432:6e1c79578e5c user:Pierre-Yves David date:Wed Mar 15 15:05:54 2017 -0700 summary: mq: explicitly tests for None https://www.mercurial-scm.org/repo/hg/rev/7aac35ada1cb changeset: 31433:7aac35ada1cb user:Pierre-Yves David date:Wed Mar 15 15:08:45 2017 -0700 summary: match: explicitly tests for None https://www.mercurial-scm.org/repo/hg/rev/d4645ae6ba15 changeset: 31434:d4645ae6ba15 user:Pierre-Yves David date:Wed Mar 15 15:10:09 2017 -0700 summary: hgweb: explicitly tests for None in webutil https://www.mercurial-scm.org/repo/hg/rev/2daeab02b4b1 changeset: 31435:2daeab02b4b1 user:Pierre-Yves David date:Wed Mar 15 15:11:04 2017 -0700 summary: hgweb: explicitly tests for None https://www.mercurial-scm.org/repo/hg/rev/ac7aa96e4cd8 changeset: 31436:ac7aa96e4cd8 user:Pierre-Yves David date:Wed Mar 15 15:11:52 2017 -0700 summary: filemerge: explicitly tests for None https://www.mercurial-scm.org/repo/hg/rev/084050d76e4f changeset: 31437:084050d76e4f user:Pierre-Yves David date:Wed Mar 15 15:33:24 2017 -0700 summary: context: explicitly tests for None https://www.mercurial-scm.org/repo/hg/rev/82350f7fa56c changeset: 31438:82350f7fa56c user:Yuya Nishihara date:Wed Mar 08 22:13:32 2017 +0900 summary: tests: allow running doctests selectively on Python 3 https://www.mercurial-scm.org/repo/hg/rev/b70407bd84d5 changeset: 31439:b70407bd84d5 user:Yuya Nishihara date:Wed Mar 08 22:48:26 2017 +0900 summary: pycompat: add bytestr wrapper which mostly acts as a Python 2 str https://www.mercurial-scm.org/repo/hg/rev/f784ba187089 changeset: 31440:f784ba187089 user:Yuya Nishihara date:Thu Mar 16 21:33:25 2017 +0900 summary: py3: use bytestr wrapper in revsetlang.formatspec() https://www.mercurial-scm.org/repo/hg/rev/80c8a6db450d changeset: 31441:80c8a6db450d user:Yuya Nishihara date:Thu Mar 16 21:36:21 2017 +0900 summary: py3: use bytestr wrapper in revsetlang.tokenize() https://www.mercurial-scm.org/repo/hg/rev/d3a56bb268ee changeset: 31442:d3a56bb268ee user:Pierre-Yves David date:Tue Mar 14 23:07:08 2017 -0700 summary: import-checkers: split tests of the tool from running it on the source https://www.mercurial-scm.org/repo/hg/rev/0241dd94ed38 changeset: 31443:0241dd94ed38 user:Kostia Balytskyi date:Mon Mar 13 12:44:13 2017 -0700 summary: exewrapper: prefer HackableMercurial python if availbale https://www.mercurial-scm.org/repo/hg/rev/55390e97fdd2 changeset: 31444:55390e97fdd2 user:Yuya Nishihara date:Sun Mar 12 17:20:42 2017 -0700 summary: py3: use portable way to stringify cache key of repoview https://www.mercurial-scm.org/repo/hg/rev/83e080144faf changeset: 31445:83e080144faf user:Yuya Nishihara date:Mon Mar 13 08:44:57 2017 -0700 summary: py3: rewrite itervalues() as values() by importer https://www.mercurial-scm.org/repo/hg/rev/9a94239e4f12 changeset: 31446:9a94239e4f12 user:Yuya Nishihara date:Mon Mar 13 08:53:31 2017 -0700 summary: py3: use next() to obtain next item from inner generator of generatorset https://www.mercurial-scm.org/repo/hg/rev/067add650129 changeset: 31447:067add650129 user:Yuya Nishihara date:Mon Mar 13 09:11:08 2017 -0700 summary: encoding: factor out unicode variants of from/tolocal() https://www.mercurial-scm.org/repo/hg/rev/6419cd243017 changeset: 31448:6419cd243017 user:Yuya Nishihara date:Mon Mar 13 09:12:56 2017 -0700 summary: encoding: add converter between native str and byte string https://www.mercurial-scm.org/repo/hg/rev/756175623f2e changeset: 31449:756175623f2e user:Yuya Nishihara date:Mon Mar 13 09:19:07 2017 -0700 summary: py3: call strftime() with native str type https://www.mercurial-scm.org/repo/hg/rev/b3b4c487707c changese
Re: [PATCH py3 V2] revlog: explicitly evaluate list to return
On Thu, Mar 16, 2017 at 2:51 PM, Pulkit Goyal <7895pul...@gmail.com> wrote: > # HG changeset patch > # User Pulkit Goyal <7895pul...@gmail.com> > # Date 1489639281 -19800 > # Thu Mar 16 10:11:21 2017 +0530 > # Node ID 16e1d9557dcebfe827060a4d31781cb7498c2c45 > # Parent e082ef765e4112ef69d3345369b142c87f1da3f4 > revlog: explicitly evaluate list to return > > On python 3, map returns an iterator so we need to convert it to list > before > finding the len or subscripting it. > > After this `hg status --all` works on Python 3. > > diff -r e082ef765e41 -r 16e1d9557dce mercurial/revlog.py > --- a/mercurial/revlog.py Thu Mar 16 10:01:12 2017 +0530 > +++ b/mercurial/revlog.py Thu Mar 16 10:11:21 2017 +0530 > @@ -943,7 +943,7 @@ > ancs = self.index.commonancestorsheads(a, b) > except (AttributeError, OverflowError): # C implementation failed > ancs = ancestor.commonancestorsheads(self.parentrevs, a, b) > -return map(self.node, ancs) > +return list(map(self.node, ancs)) > > This will create a list copy in Python 2, which could have performance implications. But for this function, the list shouldn't have many elements, so it is probably OK. Something to watch out for when doing other porting work. It /might/ be worthwhile to have a pycompat.maplist() wrapper or some such. > def isancestor(self, a, b): > """return True if node a is an ancestor of node b > ___ > Mercurial-devel mailing list > Mercurial-devel@mercurial-scm.org > https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel > ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: hg-git and round-tripping (and file copies?)
On Thu, Mar 16, 2017 at 01:38:18PM -0700, Gregory Szorc wrote: > On Thu, Mar 16, 2017 at 1:05 PM, Danek Duvall > wrote: > > > In trying to convert > > > > https://hg.java.net/hg/solaris-userland~gate > > > > to a git repo and back, I'm seeing issues at changeset 34, where the hash > > changes for reasons I can't see. If I do a diff of the debug log, I see > > it's due to the manifest: > > > > $ diff -u =(hg log -R userland-more --debug -r 34) =(hg log -R > > userland-more.hgagain --debug -r 34 | grep -v "^phase:") > > --- /tmp/zshhHyEIb 2017-03-16 11:37:57.601340643 -0700 > > +++ /tmp/zshlyqHbd 2017-03-16 11:37:57.793642372 -0700 > > @@ -1,12 +1,10 @@ > > no terminfo entry for sitm > > -changeset: 34:d20b10eba31725ad8954aa6d20374da512f0e636 > > -tag: build-149 > > +changeset: 34:2ccb817b85926f410df2a6bd23000265805088df > > parent: 33:371c8e56136d19872ae7db8d273f9de78c8fa783 > > parent: -1: > > -manifest:34:e031f26e68549dadb3dfb4705d429c75622a58b4 > > +manifest:34:5a12a2a1bf3e7c0f7c30d01bd09a2e37185bcfb6 > > user:Norm Jacobs > > date:Sun Sep 19 13:50:53 2010 -0700 > > -phase: public > > files: > > components/Makefile > > make-rules/prep.mk > > > > and if I use debugdata to look at the manifest at changeset 34, I see: > > > > $ gdiff -a -u =(hg -R userland-more debugdata -m 34) =(hg -R > > userland-more.hgagain debugdata -m 34) > > --- /tmp/zshOdnjza 2017-03-16 11:53:16.971130878 + > > +++ /tmp/zshzoTzmc 2017-03-16 11:53:17.118194061 + > > @@ -24,12 +24,12 @@ > > make-rules/setup.py.mk302733d738cc7c6cceb63457442f24f931867472 > > make-rules/shared-macros.mk03dd5df583b6e39a17ba66fc6ed6205df7f6be49 > > tools/Makefilecc964766028e3b963b4a321c88815d211415006b > > -tools/bass-o-matica618ef38ceda467b9a09680dd8b94debcd303037x > > +tools/bass-o-matic349f9611499fddf1a110f9488a84fb110c90b7bfx > > tools/build-watch.df69b9a2b6a265c06268733430bbf3f9aa7d5e160x > > tools/build-watch.pl5e23340c7a84ac555e630a5ccdc28eceda95f4b6x > > tools/time.ca0a1f64ff8ac947ce9d045e0448f8ee72f9fd273 > > -tools/userland-fetch851170bb5cebf2648c53d4909eac26ac2055cdd3x > > -tools/userland-unpack0977e35fa356d4cfab889b93613dc75d90d89b6bx > > +tools/userland-fetchbae023e70db29fd07f6f989aaa858cfaed09238ax > > +tools/userland-unpackb3800b9db86df38a644a653b3095805b269b6ac6x > > transforms/actuatorsc9d84677229efde5f89b1d985de5cd1b09267b56 > > transforms/archive-libraries-drop5b346a0133242f460ff66f6689 > > 790da094ce27f6 > > transforms/comparison-cleanupde1288c586594a171d43a3da5234cb920be408cc > > > > Now, those three files were copied in that changeset, but they're not the > > first to be copied, so it's not that, strictly. But it is the first > > changeset in which files were copied without being modified. > > > > The index data is off-by-one, if that makes any difference: > > > > $ hg -R userland-more debugrevlog -d tools/bass-o-matic > > # rev p1rev p2rev start end deltastart base p1 p2 rawsize > > totalsize compression heads chainlen > > 0-1-1 0 2175 00006005 > > 6005 2 10 > > 1 0-1 2175 2228 00005929 > > 11934 5 11 > > > > $ hg -R userland-more.hgagain debugrevlog -d tools/bass-o-matic > > # rev p1rev p2rev start end deltastart base p1 p2 rawsize > > totalsize compression heads chainlen > > 0-1-1 0 2174 00006005 > > 6005 2 10 > > 1 0-1 2174 2227 00005929 > > 11934 5 11 > > > > Any thoughts on how to further debug this? > > > > Or is this just > > > > https://bitbucket.org/durin42/hg-git/issues/46 Note that bug is about git->hg conversion where the original repository is git. > > > > and I'm out of luck? > > > > It is effectively impossible to round-trip between Git and Mercurial when > file copies are involved. This is because Mercurial's filelog hashes > include copy metadata and the parent nodes. Git's blob hashes, by contrast, > are effectively content only. When you convert from Mercurial to Git, it > will drop copy metadata (because Git doesn't track it explicitly). Then > when you convert back to Mercurial, the copies have to be detected "just > right" by hg-git for the hashes to align. Furthermore, the files have to be > reintroduced in the same order, or the filelog parents may not align and > the hashes may diverge. If a repo isn't linear, there's a non-zero chance > of that happening. hg-git actually "stores" copy/rename in the commit messages, but that's assuming the commit was done in mercurial and pushed to git with hg-git in the first place.
Re: hg-git and round-tripping (and file copies?)
Mike Hommey wrote: > If your goal trying to round-trip between mercurial and git is to > provide developers with the possibility to use mercurial or git as they > like, and somehow make it work with developers pushing on both ends, you > should instead use a single source of truth (mercurial or git, whichever > you prefer keeping a server for), and let developers use conversion tools > on their end. hg-git can be used by developers who prefer mercurial when > the server is git (although it annoyingly adds visible metadata to git > commits in that case). git-cinnabar or git-remote-hg can be used by > developers who prefer git when the server is mercurial. (full > disclosure, I'm the author of git-cinnabar) Our source of truth is mercurial. But our (Oracle Solaris) external, read-only mirror is being moved from a mercurial repo on java.net to github. I would like for people who might have had clones of the mercurial repo to be able to use hg-git to pull from the github repo and get the same changeset IDs as they had before (and as we have internally), but that looks like it's not possible. Danek ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 1 of 2 py3 V2] dirstate: use next(iter) instead of iter.next
On Fri, Mar 17, 2017 at 3:17 AM, Martin von Zweigbergk < martinv...@google.com> wrote: > On Thu, Mar 16, 2017 at 2:24 PM, Pulkit Goyal <7895pul...@gmail.com> > wrote: > > # HG changeset patch > > # User Pulkit Goyal <7895pul...@gmail.com> > > # Date 1489634873 -19800 > > # Thu Mar 16 08:57:53 2017 +0530 > > # Node ID c894bad6625973565b21f556896527141f123dd5 > > # Parent a5bad127128d8f60060be53d161acfa7a32a17d5 > > dirstate: use next(iter) instead of iter.next > > > > In Python 3 world, iter.next() is renamed to iter.__next__(). But > next(iter) > > has the same behaviour. So let's replace iter.next() with next(iter). > > > > diff -r a5bad127128d -r c894bad66259 mercurial/dirstate.py > > --- a/mercurial/dirstate.py Wed Mar 15 15:48:57 2017 -0700 > > +++ b/mercurial/dirstate.py Thu Mar 16 08:57:53 2017 +0530 > > @@ -1115,9 +1115,8 @@ > > else: > > # We may not have walked the full directory tree above, > > # so stat and check everything we missed. > > -nf = iter(visit).next > > for st in util.statfiles([join(i) for i in visit]): > > -results[nf()] = st > > +results[next(iter(visit))] = st > > Won't "next(iter(visit))" get the first element of "visit" every time? > Also, since we can no longer cache the .next function itself, and it > seemed like the old version tried to care about that optimization, > does this make a noticeable difference? Can you try to figure out > under what circumstances nf() (in the old version) gets called very > many times and see if you can measure a difference between the old > version and the new version? Thanks. > This one is breaking the tests (sorry for not checking before sending). I guess we need to switch to the V1 of this patch. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 7 of 8] rebase: get rid of ui.backupconfig
On Thu, Mar 16, 2017 at 2:57 PM, Jun Wu wrote: > # HG changeset patch > # User Jun Wu > # Date 1489700434 25200 > # Thu Mar 16 14:40:34 2017 -0700 > # Node ID 8f87b407da24ee802e271f517dbc96ad32f21779 > # Parent 8b086a28d1b605d6c0726d77c21f8d13188691fa > # Available At https://bitbucket.org/quark-zju/hg-draft > # hg pull https://bitbucket.org/quark-zju/hg-draft -r > 8f87b407da24 > rebase: get rid of ui.backupconfig > > diff --git a/hgext/rebase.py b/hgext/rebase.py > --- a/hgext/rebase.py > +++ b/hgext/rebase.py > @@ -851,8 +851,7 @@ def concludenode(repo, rev, p1, p2, comm > extrafn(ctx, extra) > > -backup = repo.ui.backupconfig('phases', 'new-commit') > -try: > -targetphase = max(ctx.phase(), phases.draft) > -repo.ui.setconfig('phases', 'new-commit', targetphase, 'rebase') > +targetphase = max(ctx.phase(), phases.draft) > +override = {('phases', 'new-commit'): targetphase} > +with repo.ui.configoverride(override, 'rebase'): > if keepbranch: > repo.ui.setconfig('ui', 'allowemptycommit', True) I *think* this is unrelated to this patch, but should this line also be restored (i.e. part of the overrides)? > @@ -862,6 +861,4 @@ def concludenode(repo, rev, p1, p2, comm > newnode = repo.commit(text=commitmsg, user=ctx.user(), >date=date, extra=extra, editor=editor) > -finally: > -repo.ui.restoreconfig(backup) > > repo.dirstate.setbranch(repo[newnode].branch()) > ___ > Mercurial-devel mailing list > Mercurial-devel@mercurial-scm.org > https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 7 of 8] rebase: get rid of ui.backupconfig
Excerpts from Martin von Zweigbergk's message of 2017-03-16 17:14:33 -0700: > On Thu, Mar 16, 2017 at 2:57 PM, Jun Wu wrote: > > # HG changeset patch > > # User Jun Wu > > # Date 1489700434 25200 > > # Thu Mar 16 14:40:34 2017 -0700 > > # Node ID 8f87b407da24ee802e271f517dbc96ad32f21779 > > # Parent 8b086a28d1b605d6c0726d77c21f8d13188691fa > > # Available At https://bitbucket.org/quark-zju/hg-draft > > # hg pull https://bitbucket.org/quark-zju/hg-draft -r > > 8f87b407da24 > > rebase: get rid of ui.backupconfig > > > > diff --git a/hgext/rebase.py b/hgext/rebase.py > > --- a/hgext/rebase.py > > +++ b/hgext/rebase.py > > @@ -851,8 +851,7 @@ def concludenode(repo, rev, p1, p2, comm > > extrafn(ctx, extra) > > > > -backup = repo.ui.backupconfig('phases', 'new-commit') > > -try: > > -targetphase = max(ctx.phase(), phases.draft) > > -repo.ui.setconfig('phases', 'new-commit', targetphase, > > 'rebase') > > +targetphase = max(ctx.phase(), phases.draft) > > +override = {('phases', 'new-commit'): targetphase} > > +with repo.ui.configoverride(override, 'rebase'): > > if keepbranch: > > repo.ui.setconfig('ui', 'allowemptycommit', True) > > I *think* this is unrelated to this patch, but should this line also > be restored (i.e. part of the overrides)? Good catch. I think it should. It looks like a bug. > > > @@ -862,6 +861,4 @@ def concludenode(repo, rev, p1, p2, comm > > newnode = repo.commit(text=commitmsg, user=ctx.user(), > >date=date, extra=extra, editor=editor) > > -finally: > > -repo.ui.restoreconfig(backup) > > > > repo.dirstate.setbranch(repo[newnode].branch()) > > ___ > > Mercurial-devel mailing list > > Mercurial-devel@mercurial-scm.org > > https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 1 of 8] commit: get rid of ui.backupconfig
On Thu, Mar 16, 2017 at 2:56 PM, Jun Wu wrote: > # HG changeset patch > # User Jun Wu > # Date 1489698920 25200 > # Thu Mar 16 14:15:20 2017 -0700 > # Node ID def9b72933ce717a48e3cc8fa4934bd3459b9479 > # Parent 5c9cda37d7f6b181ab604c8d5a7592b5553f886b > # Available At https://bitbucket.org/quark-zju/hg-draft > # hg pull https://bitbucket.org/quark-zju/hg-draft -r > def9b72933ce > commit: get rid of ui.backupconfig Queuing this series with some small changes mentioned below. Thanks. I will not have time to run tests on all commits before I leave for home, but I'll push anyway, and will update later tonight if tests fail. > > diff --git a/mercurial/commands.py b/mercurial/commands.py > --- a/mercurial/commands.py > +++ b/mercurial/commands.py > @@ -1703,23 +1703,19 @@ def _docommit(ui, repo, *pats, **opts): > else: > def commitfunc(ui, repo, message, match, opts): > -backup = ui.backupconfig('phases', 'new-commit') > +configoverride = {} The name confused me for a while because it's the same as the method on ui, but it's not even a function here. I renamed them throughout the series to "overrides" (plural and no "config" prefix), which seems more consistent with the rest of the series and with how we usually pluralize dict-type variables. > +if opts.get('secret'): > +configoverride[('phases', 'new-commit')] = 'secret' > + > baseui = repo.baseui > -basebackup = baseui.backupconfig('phases', 'new-commit') > -try: > -if opts.get('secret'): > -ui.setconfig('phases', 'new-commit', 'secret', 'commit') > -# Propagate to subrepos > -baseui.setconfig('phases', 'new-commit', 'secret', > 'commit') > - > -editform = cmdutil.mergeeditform(repo[None], 'commit.normal') > -editor = cmdutil.getcommiteditor(editform=editform, **opts) > -return repo.commit(message, opts.get('user'), > opts.get('date'), > - match, > - editor=editor, > - extra=extra) > -finally: > -ui.restoreconfig(backup) > -repo.baseui.restoreconfig(basebackup) > - > +with baseui.configoverride(configoverride, 'commit'): > +with ui.configoverride(configoverride, 'commit'): > +editform = cmdutil.mergeeditform(repo[None], > + 'commit.normal') > +editor = cmdutil.getcommiteditor(editform=editform, > **opts) > +return repo.commit(message, opts.get('user'), I wrapped after the first argument too (yes, I know it was inconsistent before too). > + opts.get('date'), > + match, > + editor=editor, > + extra=extra) > > node = cmdutil.commit(ui, repo, commitfunc, pats, opts) > ___ > Mercurial-devel mailing list > Mercurial-devel@mercurial-scm.org > https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 1 of 8] commit: get rid of ui.backupconfig
Thanks! Excerpts from Martin von Zweigbergk's message of 2017-03-16 17:19:15 -0700: > On Thu, Mar 16, 2017 at 2:56 PM, Jun Wu wrote: > > # HG changeset patch > > # User Jun Wu > > # Date 1489698920 25200 > > # Thu Mar 16 14:15:20 2017 -0700 > > # Node ID def9b72933ce717a48e3cc8fa4934bd3459b9479 > > # Parent 5c9cda37d7f6b181ab604c8d5a7592b5553f886b > > # Available At https://bitbucket.org/quark-zju/hg-draft > > # hg pull https://bitbucket.org/quark-zju/hg-draft -r > > def9b72933ce > > commit: get rid of ui.backupconfig > > Queuing this series with some small changes mentioned below. Thanks. I > will not have time to run tests on all commits before I leave for > home, but I'll push anyway, and will update later tonight if tests > fail. > > > > > diff --git a/mercurial/commands.py b/mercurial/commands.py > > --- a/mercurial/commands.py > > +++ b/mercurial/commands.py > > @@ -1703,23 +1703,19 @@ def _docommit(ui, repo, *pats, **opts): > > else: > > def commitfunc(ui, repo, message, match, opts): > > -backup = ui.backupconfig('phases', 'new-commit') > > +configoverride = {} > > The name confused me for a while because it's the same as the method > on ui, but it's not even a function here. I renamed them throughout > the series to "overrides" (plural and no "config" prefix), which seems > more consistent with the rest of the series and with how we usually > pluralize dict-type variables. > > > +if opts.get('secret'): > > +configoverride[('phases', 'new-commit')] = 'secret' > > + > > baseui = repo.baseui > > -basebackup = baseui.backupconfig('phases', 'new-commit') > > -try: > > -if opts.get('secret'): > > -ui.setconfig('phases', 'new-commit', 'secret', > > 'commit') > > -# Propagate to subrepos > > -baseui.setconfig('phases', 'new-commit', 'secret', > > 'commit') > > - > > -editform = cmdutil.mergeeditform(repo[None], > > 'commit.normal') > > -editor = cmdutil.getcommiteditor(editform=editform, **opts) > > -return repo.commit(message, opts.get('user'), > > opts.get('date'), > > - match, > > - editor=editor, > > - extra=extra) > > -finally: > > -ui.restoreconfig(backup) > > -repo.baseui.restoreconfig(basebackup) > > - > > +with baseui.configoverride(configoverride, 'commit'): > > +with ui.configoverride(configoverride, 'commit'): > > +editform = cmdutil.mergeeditform(repo[None], > > + 'commit.normal') > > +editor = cmdutil.getcommiteditor(editform=editform, > > **opts) > > +return repo.commit(message, opts.get('user'), > > I wrapped after the first argument too (yes, I know it was > inconsistent before too). > > > + opts.get('date'), > > + match, > > + editor=editor, > > + extra=extra) > > > > node = cmdutil.commit(ui, repo, commitfunc, pats, opts) > > ___ > > Mercurial-devel mailing list > > Mercurial-devel@mercurial-scm.org > > https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH evolve-ext] checks: correct the shebang line filtering for python files
# HG changeset patch # User Matt Harbison # Date 1489713417 14400 # Thu Mar 16 21:16:57 2017 -0400 # Node ID 6a3248558b6929378450b572bb27406afe703ffd # Parent e9d5f54765a27e09d35f48dda23db7e6f5b8320a checks: correct the shebang line filtering for python files As it is, the only related file is docs/test2rst.py, which was covered by **.py. Not sure if it matters, but most patterns in core tests are for "#!.*?python". (Though there are a couple "#!.*python" tests.) diff --git a/tests/test-check-flake8.t b/tests/test-check-flake8.t --- a/tests/test-check-flake8.t +++ b/tests/test-check-flake8.t @@ -14,5 +14,5 @@ run flake8 if it exists; if it doesn't, then just skip - $ hg files -0 'set:(**.py or grep("^!#.*python")) - removed()' 2>/dev/null \ + $ hg files -0 'set:(**.py or grep("^#!.*python")) - removed()' 2>/dev/null \ > | xargs -0 flake8 diff --git a/tests/test-check-pyflakes.t b/tests/test-check-pyflakes.t --- a/tests/test-check-pyflakes.t +++ b/tests/test-check-pyflakes.t @@ -7,5 +7,5 @@ run pyflakes on all tracked files ending in .py or without a file ending (skipping binary file random-seed) - $ hg locate 'set:(**.py or grep("^!#.*python")) - removed()' 2>/dev/null \ + $ hg locate 'set:(**.py or grep("^#!.*python")) - removed()' 2>/dev/null \ > | xargs pyflakes 2>/dev/null ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 1 of 4 V3] filemerge: add `summarize()`
# HG changeset patch # User Phil Cohen # Date 1489716177 25200 # Thu Mar 16 19:02:57 2017 -0700 # Node ID ad81d182e88ffd3da20364f18204facf6e7750a3 # Parent 568d80b24b3a3e4e6874ac0d95ddee056fef14e4 filemerge: add `summarize()` returns a dictionary of each version of a conflict, given the contexts diff --git a/mercurial/filemerge.py b/mercurial/filemerge.py --- a/mercurial/filemerge.py +++ b/mercurial/filemerge.py @@ -7,6 +7,7 @@ from __future__ import absolute_import +import copy import filecmp import os import re @@ -567,6 +568,60 @@ "o": " [%s]" % labels[1], } +def summarize(repo, workingfilectx, otherctx, basectx): +origfile = None if workingfilectx.isabsent() else \ +scmutil.origpath(repo.ui, repo, repo.wjoin(workingfilectx.path())) + +def flags(context): +if isinstance(context, absentfilectx): +return {'exists': False} +return { +'contents': context.data(), +'exists': True, +'isexec': context.isexec(), +'issymlink': context.islink(), +} + +output = flags(workingfilectx) + +if origfile and util.filestat(origfile).stat: +# Since you can start a merge with a dirty working copy (either via +# `up -n` or `merge -f`), "local" must reflect that, not the underlying +# commit. Those contents are available in the .orig version, so we look +# there and mock up the schema to look like the other contexts. +local = { +'contents': util.readfile(origfile), +'exists': True, +'isexec': util.isexec(origfile), +'issymlink': util.statislink(util.filestat(origfile).stat), +} +else: +# No backup file. This happens whenever the merge was esoteric enough +# that we didn't launch a merge tool*, and instead prompted the user to +# "use (c)hanged version, (d)elete, or leave (u)nresolved". +# +# The only way to exit that prompt with a conflict is to choose "u", +# which leaves the local version in the working copy (with all its +# pre-merge properties including any local changes), so we can reuse +# that. +# +# Another alternative might be to use repo['.'][path] but that wouldn't +# have any dirty pre-merge changes. +# +# *If we had, we'd've we would've overwritten the working copy, made a +# backup and hit the above case. +local = copy.copy(output) + +output['path'] = repo.wjoin(workingfilectx.path()) + +return { +'base': flags(basectx), +'local': local, +'other': flags(otherctx), +'output': output, +'path': workingfilectx.path(), +} + def _filemerge(premerge, repo, mynode, orig, fcd, fco, fca, labels=None): """perform a 3-way merge in the working directory ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 4 of 4 V3] filemerge: add test cases for corner cases using internal:dumpjson
# HG changeset patch # User Phil Cohen # Date 1489716623 25200 # Thu Mar 16 19:10:23 2017 -0700 # Node ID 62ab2ddcf1683c3bf2e4dbb21dbe11d065bff93b # Parent 36d378ac43dbbf559655c70b7cad873768a0e794 filemerge: add test cases for corner cases using internal:dumpjson diff --git a/mercurial/filemerge.py b/mercurial/filemerge.py --- a/mercurial/filemerge.py +++ b/mercurial/filemerge.py @@ -589,6 +589,8 @@ # `up -n` or `merge -f`), "local" must reflect that, not the underlying # commit. Those contents are available in the .orig version, so we look # there and mock up the schema to look like the other contexts. +# +# Test cases affected in test-merge-conflict-cornercases.t: #0 local = { 'contents': util.readfile(origfile), 'exists': True, @@ -605,6 +607,8 @@ # pre-merge properties including any local changes), so we can reuse # that. # +# Affected test cases: #0b, #1, #6, #11, and #12. +# # Another alternative might be to use repo['.'][path] but that wouldn't # have any dirty pre-merge changes. # diff --git a/tests/test-merge-conflict-cornercases.t b/tests/test-merge-conflict-cornercases.t new file mode 100644 --- /dev/null +++ b/tests/test-merge-conflict-cornercases.t @@ -0,0 +1,575 @@ +Tests merge conflict corner cases (file-to-directory, binary-to-symlink, etc.) +"other" == source +"local" == dest + +Setup + $ cat >> $HGRCPATH < [extensions] + > rebase= + > EOF + + $ reset() { + > rm -rf foo + > mkdir foo + > cd foo + > hg init + > echo "base" > file + > hg commit -Aqm "base" + > } + $ logg() { + > hg log -G -T '({rev}) {desc}\naffected: {files}\ndeleted: {file_dels}\n\n' + > } + +Test case 0: A merge of just contents conflicts (not usually a corner case), +but the user had local changes and ran `merge -f`. + +tldr: Since we can premerge, the working copy is backed up to an origfile. + $ reset + $ echo "change" > file + $ hg commit -Aqm "dest" + $ hg up -q 0 + $ echo "other change" > file + $ hg commit -Aqm "source" + $ hg up -q 1 + $ logg + o (2) source + | affected: file + | deleted: + | + | @ (1) dest + |/ affected: file + |deleted: + | + o (0) base + affected: file + deleted: + + $ echo "some local changes" > file + $ hg merge 2 -f + merging file + warning: conflicts while merging file! (edit, then use 'hg resolve --mark') + 0 files updated, 0 files merged, 0 files removed, 1 files unresolved + use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon + [1] + + $ hg resolve --tool=internal:dumpjson --all + [ + { +"conflicts": [{"base": {"contents": "base\n", "exists": true, "isexec": false, "issymlink": false}, "local": {"contents": "some local changes\n", "exists": true, "isexec": false, "issymlink": false}, "other": {"contents": "other change\n", "exists": true, "isexec": false, "issymlink": false}, "output": {"contents": "<<< working copy: fd7d10c36158 - test: dest\nsome local changes\n===\nother change\n>>> merge rev:9b65ba2922f0 - test: source\n", "exists": true, "isexec": false, "issymlink": false, "path": "$TESTTMP/foo/file"}, "path": "file"}] + } + ] + +Test case 0b: Like #0 but with a corner case: source deleted, local changed +*and* had local changes using merge -f. + +tldr: Since we couldn't premerge, the working copy is left alone. + $ reset + $ echo "change" > file + $ hg commit -Aqm "dest" + $ hg up -q 0 + $ hg rm file + $ hg commit -Aqm "source" + $ hg up -q 1 + $ logg + o (2) source + | affected: file + | deleted: file + | + | @ (1) dest + |/ affected: file + |deleted: + | + o (0) base + affected: file + deleted: + + $ echo "some local changes" > file + $ chmod +x file + $ hg merge 2 -f + local [working copy] changed file which other [merge rev] deleted + use (c)hanged version, (d)elete, or leave (u)nresolved? u + 0 files updated, 0 files merged, 0 files removed, 1 files unresolved + use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon + [1] + + $ hg resolve --tool=internal:dumpjson --all + [ + { +"conflicts": [{"base": {"contents": "base\n", "exists": true, "isexec": false, "issymlink": false}, "local": {"contents": "some local changes\n", "exists": true, "isexec": true, "issymlink": false}, "other": {"exists": false}, "output": {"contents": "some local changes\n", "exists": true, "isexec": true, "issymlink": false, "path": "$TESTTMP/foo/foo/file"}, "path": "file"}] + } + ] + +Test case 1: Source deleted, dest changed + $ reset + $ echo "change" > file + $ hg commit -Aqm "dest" + $ hg up -q 0 + $ hg rm file + $ hg commit -Aqm "source" + $ hg up -q 1 + $ logg + o (2) source + | affected: file + | deleted: file + | + | @ (1) dest + |/ affected: file + |deleted: + | + o (0) base + affected:
[PATCH 3 of 4 V3] commands: add --tool=internal:dumpjson to resolve
# HG changeset patch # User Phil Cohen # Date 1489716587 25200 # Thu Mar 16 19:09:47 2017 -0700 # Node ID 36d378ac43dbbf559655c70b7cad873768a0e794 # Parent 864def5028681cdffeaf5b440ff4753e1389f453 commands: add --tool=internal:dumpjson to resolve diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -33,6 +33,7 @@ error, exchange, extensions, +formatter, graphmod, hbisect, help, @@ -4287,6 +4288,26 @@ fm.end() return 0 +if opts.get('tool', '') == "internal:dumpjson": +formatter = ui.formatter('resolve', {'template': 'json'}) +mergestate = mergemod.mergestate.read(repo) +matcher = scmutil.match(repo[None], pats, opts) +workingctx = repo[None] + +paths = [] +for filename in mergestate: +if not matcher(filename): +continue + +val = mergestate.summarizeconflicts(filename, workingctx) +if val is not None: +paths.append(val) + +formatter.startitem() +formatter.write('conflicts', '%s\n', paths) +formatter.end() +return 0 + with repo.wlock(): ms = mergemod.mergestate.read(repo) diff --git a/tests/test-resolve-dumpjson.t b/tests/test-resolve-dumpjson.t new file mode 100644 --- /dev/null +++ b/tests/test-resolve-dumpjson.t @@ -0,0 +1,83 @@ +1) Make the repo + $ hg init + +2) Can't run dumpjson outside a conflict + $ hg resolve --tool internal:dumpjson + abort: no files or directories specified + (use --all to re-merge all unresolved files) + [255] + +3) Make a simple conflict + $ echo "Unconflicted base, F1" > F1 + $ echo "Unconflicted base, F2" > F2 + $ hg commit -Aqm "initial commit" + $ echo "First conflicted version, F1" > F1 + $ echo "First conflicted version, F2" > F2 + $ hg commit -m "first version, a" + $ hg bookmark a + $ hg checkout .~1 + 2 files updated, 0 files merged, 0 files removed, 0 files unresolved + (leaving bookmark a) + $ echo "Second conflicted version, F1" > F1 + $ echo "Second conflicted version, F2" > F2 + $ hg commit -m "second version, b" + created new head + $ hg bookmark b + $ hg log -G -T '({rev}) {desc}\nbookmark: {bookmarks}\nfiles: {files}\n\n' + @ (2) second version, b + | bookmark: b + | files: F1 F2 + | + | o (1) first version, a + |/ bookmark: a + |files: F1 F2 + | + o (0) initial commit + bookmark: + files: F1 F2 + + + + $ hg merge a + merging F1 + merging F2 + warning: conflicts while merging F1! (edit, then use 'hg resolve --mark') + warning: conflicts while merging F2! (edit, then use 'hg resolve --mark') + 0 files updated, 0 files merged, 0 files removed, 2 files unresolved + use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon + [1] + +5) Get the paths: + $ hg resolve --tool internal:dumpjson --all + [ + { +"conflicts": [{"base": {"contents": "Unconflicted base, F1\n", "isexec": false, "issymlink": false}, "local": {"contents": "Second conflicted version, F1\n", "isexec": false, "issymlink": false}, "other": {"contents": "First conflicted version, F1\n", "isexec": false, "issymlink": false}, "output": {"contents": "<<< working copy: 13124abb51b9 b - test: second version, b\nSecond conflicted version, F1\n===\nFirst conflicted version, F1\n>>> merge rev:6dd692b7db4a a - test: first version, a\n", "isexec": false, "issymlink": false, "path": "$TESTTMP/F1"}, "path": "F1"}, {"base": {"contents": "Unconflicted base, F2\n", "isexec": false, "issymlink": false}, "local": {"contents": "Second conflicted version, F2\n", "isexec": false, "issymlink": false}, "other": {"contents": "First conflicted version, F2\n", "isexec": false, "issymlink": false}, "output": {"contents": "<<< working copy: 13124abb51b9 b - test: second version, b\nSecond conflicted version, F2\n===\nFirst conflicted version, F2\n>>> merge rev:6dd692b7db4a a - test: first version, a\n", "isexec": false, "issymlink": false, "path": "$TESTTMP/F2"}, "path": "F2"}] + } + ] + +6) Only requested paths get dumped + $ hg resolve --tool internal:dumpjson F2 + [ + { +"conflicts": [{"base": {"contents": "Unconflicted base, F2\n", "isexec": false, "issymlink": false}, "local": {"contents": "Second conflicted version, F2\n", "isexec": false, "issymlink": false}, "other": {"contents": "First conflicted version, F2\n", "isexec": false, "issymlink": false}, "output": {"contents": "<<< working copy: 13124abb51b9 b - test: second version, b\nSecond conflicted version, F2\n===\nFirst conflicted version, F2\n>>> merge rev:6dd692b7db4a a - test: first version, a\n", "isexec": false, "issymlink": false, "path": "$TESTTMP/F2"}, "path": "F2"}] + } + ] + +7) Ensure the paths point to the right contents: + $ getcontents() { # Usage: getcontents + > local script="import sy
[PATCH 2 of 4 V3] merge: add summarizeconflicts()
# HG changeset patch # User Phil Cohen # Date 1489716532 25200 # Thu Mar 16 19:08:52 2017 -0700 # Node ID 864def5028681cdffeaf5b440ff4753e1389f453 # Parent ad81d182e88ffd3da20364f18204facf6e7750a3 merge: add summarizeconflicts() calls `filemerge.summarize()` but only requires a workingctx and a path diff --git a/mercurial/merge.py b/mercurial/merge.py --- a/mercurial/merge.py +++ b/mercurial/merge.py @@ -544,6 +544,25 @@ Returns whether the merge is complete, and the exit code.""" return self._resolve(True, dfile, wctx) +def summarizeconflicts(self, path, workingctx): +if self[path] in 'rd': +return None +stateentry = self._state[path] +state, hash, lfile, afile, anode, ofile, onode, flags = stateentry +octx = self._repo[self._other] +extras = self.extras(path) +anccommitnode = extras.get('ancestorlinknode') +if anccommitnode: +ancestorctx = self._repo[anccommitnode] +else: +ancestorctx = None +workingctx = self._filectxorabsent(hash, workingctx, path) +otherctx = self._filectxorabsent(onode, octx, ofile) +basectx = self._repo.filectx(afile, fileid=anode, + changeid=ancestorctx) + +return filemerge.summarize(self._repo, workingctx, otherctx, basectx) + def resolve(self, dfile, wctx): """run merge process (assuming premerge was run) for dfile ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 1 of 4 V3] filemerge: add `summarize()`
Two things are new here since last time -- detecting absentfilectxs and the 'else' case that runs when the origfile is missing. Let me know if the assumption there holds. The "look at the origfile" behavior (the "if" branch) came from the original code that launches the merge tool. On 3/16/17 7:17 PM, Phil Cohen wrote: # HG changeset patch # User Phil Cohen # Date 1489716177 25200 # Thu Mar 16 19:02:57 2017 -0700 # Node ID ad81d182e88ffd3da20364f18204facf6e7750a3 # Parent 568d80b24b3a3e4e6874ac0d95ddee056fef14e4 filemerge: add `summarize()` returns a dictionary of each version of a conflict, given the contexts diff --git a/mercurial/filemerge.py b/mercurial/filemerge.py --- a/mercurial/filemerge.py +++ b/mercurial/filemerge.py @@ -7,6 +7,7 @@ from __future__ import absolute_import +import copy import filecmp import os import re @@ -567,6 +568,60 @@ "o": " [%s]" % labels[1], } +def summarize(repo, workingfilectx, otherctx, basectx): +origfile = None if workingfilectx.isabsent() else \ +scmutil.origpath(repo.ui, repo, repo.wjoin(workingfilectx.path())) + +def flags(context): +if isinstance(context, absentfilectx): +return {'exists': False} +return { +'contents': context.data(), +'exists': True, +'isexec': context.isexec(), +'issymlink': context.islink(), +} + +output = flags(workingfilectx) + +if origfile and util.filestat(origfile).stat: +# Since you can start a merge with a dirty working copy (either via +# `up -n` or `merge -f`), "local" must reflect that, not the underlying +# commit. Those contents are available in the .orig version, so we look +# there and mock up the schema to look like the other contexts. +local = { +'contents': util.readfile(origfile), +'exists': True, +'isexec': util.isexec(origfile), +'issymlink': util.statislink(util.filestat(origfile).stat), +} +else: +# No backup file. This happens whenever the merge was esoteric enough +# that we didn't launch a merge tool*, and instead prompted the user to +# "use (c)hanged version, (d)elete, or leave (u)nresolved". +# +# The only way to exit that prompt with a conflict is to choose "u", +# which leaves the local version in the working copy (with all its +# pre-merge properties including any local changes), so we can reuse +# that. +# +# Another alternative might be to use repo['.'][path] but that wouldn't +# have any dirty pre-merge changes. +# +# *If we had, we'd've we would've overwritten the working copy, made a +# backup and hit the above case. +local = copy.copy(output) + +output['path'] = repo.wjoin(workingfilectx.path()) + +return { +'base': flags(basectx), +'local': local, +'other': flags(otherctx), +'output': output, +'path': workingfilectx.path(), +} + def _filemerge(premerge, repo, mynode, orig, fcd, fco, fca, labels=None): """perform a 3-way merge in the working directory ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://urldefense.proofpoint.com/v2/url?u=https-3A__www.mercurial-2Dscm.org_mailman_listinfo_mercurial-2Ddevel&d=DwIGaQ&c=5VD0RTtNlTh3ycd41b3MUw&r=mx0opQh0kf4fCU4SUKtQ-w&m=zNEo24XeGP6uuFpeTZpDknUXdTs3odSRA4zQ58SSUxo&s=lmzkUhUGn-ONxybCITeUUIp5zDxXPo-qLupBGN19eGA&e= ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH V2] merge: add `internal:dumpjson` tool to `resolve`, which outputs conflict state
Thanks a lot for the points re: variable names! I'm actually really happy to hear that -- these names were taken from elsewhere in the codebase, and they were very confusing. I have forgotten/had to relearn the difference between fcd/fca/fco/etc several times. Glad to hear that slightly longer/clearer names are encouraged. On 3/15/17 11:20 PM, Ryan McElroy wrote: More nits inline to consider since you're looking into a v3 anyway... On 3/15/17 10:48 AM, Durham Goode wrote: On 3/7/17 11:40 AM, Phil Cohen wrote: # HG changeset patch # User Phil Cohen # Date 1488915535 28800 # Tue Mar 07 11:38:55 2017 -0800 # Node ID bbce62e3790220f19e7b37160a2f8351b7461272 # Parent 91e86a6c61c0c6a3b554eefeba906311aa29 merge: add `internal:dumpjson` tool to `resolve`, which outputs conflict state This supersedes a previous change which added a --prep option. Generally we don't reference previous iterations of the patch in the commit message, since those previous iterations wont' show up in the repo after this is pushed. Normally, `hg resolve` takes the user on a whistle-stop tour of each conflicted file, pausing to launch the editor to resolve the conflicts. This is an alternative workflow for resolving many conflicts in a random-access fashion. It doesn't change/replace the default behavior. This commit adds `--tool=internal:dumpjson`. It prints, for each conflict, the "base", "other", and "ours" versions (the contents, as well as their exec/link flags), and where the user/tool should write a resolved version (i.e., the working copy) as JSON. The user will then resolve the conflicts at their leisure and run `hg resolve --mark`. Overall I think it looks good. Some minor comments inline, but I'd be ok having this queued (since it's been sitting here a while) and addressing the nits in a follow up. diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -33,6 +33,7 @@ error, exchange, extensions, +formatter, graphmod, hbisect, help, @@ -4284,6 +4285,26 @@ fm.end() return 0 +if opts.get('tool', '') == "internal:dumpjson": +fm = ui.formatter('resolve', {'template': 'json'}) +ms = mergemod.mergestate.read(repo) I don't love the short name style hg uses, and I don't see a godo reason to use it unless there's already a strong-established precedent in the file. We've been calling formatters 'fm' for a long time, but 'ms' as mergestate seems like a new one (to me at least). I'd love a more descriptive variable name since we have the option right now +m = scmutil.match(repo[None], pats, opts) Would prefer this be called 'matcher' +wctx = repo[None] + +paths = [] +for f in ms: Then this could become: for filename in mergestate: And then it's obvious from just reading the loop what it is doing +if not m(f): And this would become: if not matcher(filename): Which is also much more clear to me at least. +continue + +val = ms.internaldump(f, wctx) +if val is not None: +paths.append(val) + +fm.startitem() +fm.write('conflicts', '%s\n', paths) +fm.end() +return 0 + with repo.wlock(): ms = mergemod.mergestate.read(repo) diff --git a/mercurial/filemerge.py b/mercurial/filemerge.py --- a/mercurial/filemerge.py +++ b/mercurial/filemerge.py @@ -567,6 +567,40 @@ "o": " [%s]" % labels[1], } +def summarize(repo, fcd, fco, fca): I'm sure we can come up with better parameter names here too. fca is probably the "file context ancestor", but I have no idea what fcd and fco are without diving deep into the code. +back = None if fcd.isabsent() else \ +scmutil.origpath(repo.ui, repo, repo.wjoin(fcd.path())) It's unclear to me what 'back' will be used for. Can you add a comment? (is it the "back"up -- the .orig file?) + +def sum(ctx): I'd name this flags() instead of sum +return { +'contents': ctx.data(), +'isexec': ctx.isexec(), +'issymlink': ctx.islink(), +} + +ours = None 'ours' is a git thing, not a mercurial thing. Let's use consitent hg-internal naming if possible: * local * other * base +if back and util.filestat(back).stat: +# Replicate the schema of `base` and `other` for `ours`. Since you can +# start a merge with a dirty working copy, `ours` must reflect that, +# not the underlying commit. That's why we look at .orig version. +ours = { +'path': back, +'contents': util.readfile(back), +'isexec': util.isexec(back), +'issymlink': util.statislink(util.filestat(back).stat) +} + +output = sum(fcd) +output['path'] = repo.wjoin(fcd.path()) + +return { +'path': fcd.path(), +'base': sum(fca), +'other'
Re: [PATCH V2] merge: add `internal:dumpjson` tool to `resolve`, which outputs conflict state
Just to add some notes on variable names. There are some very common short names. Like "p1" representing "parent1". And "p1" should be preferred. An incomplete list is at [1]. It's okay to use "fname" hetlridvnvrtrtf "filename". FWIW, Ruby community standard prefers longer names while Golang explicitly prefers shorter names [2]. I think both are reasonable, as long as the code is consistent. For less-common things like "fca", "fco", etc. Longer names are definitely better. For common objects like "matcher", "manifest", I think either is okay. Since we are unlikely to rename "p1" to "parent1", I personally prefer shorter ones for unambiguous common objects, especially when it can reduce line wraps. [1]: https://www.mercurial-scm.org/wiki/CodingStyle [2]: https://github.com/golang/go/wiki/CodeReviewComments#variable-names Excerpts from Phil Cohen's message of 2017-03-16 19:32:44 -0700: > Thanks a lot for the points re: variable names! I'm actually really > happy to hear that -- these names were taken from elsewhere in the > codebase, and they were very confusing. I have forgotten/had to relearn > the difference between fcd/fca/fco/etc several times. Glad to hear that > slightly longer/clearer names are encouraged. > > On 3/15/17 11:20 PM, Ryan McElroy wrote: > > More nits inline to consider since you're looking into a v3 anyway... > > > > > > On 3/15/17 10:48 AM, Durham Goode wrote: > >> > >> > >> On 3/7/17 11:40 AM, Phil Cohen wrote: > >>> # HG changeset patch > >>> # User Phil Cohen > >>> # Date 1488915535 28800 > >>> # Tue Mar 07 11:38:55 2017 -0800 > >>> # Node ID bbce62e3790220f19e7b37160a2f8351b7461272 > >>> # Parent 91e86a6c61c0c6a3b554eefeba906311aa29 > >>> merge: add `internal:dumpjson` tool to `resolve`, which outputs > >>> conflict state > >>> > >>> This supersedes a previous change which added a --prep option. > >> > >> Generally we don't reference previous iterations of the patch in the > >> commit message, since those previous iterations wont' show up in the > >> repo after this is pushed. > >> > >>> Normally, `hg resolve` takes the user on a whistle-stop tour of each > >>> conflicted > >>> file, pausing to launch the editor to resolve the conflicts. This is an > >>> alternative workflow for resolving many conflicts in a random-access > >>> fashion. It > >>> doesn't change/replace the default behavior. > >>> > >>> This commit adds `--tool=internal:dumpjson`. It prints, for each > >>> conflict, the > >>> "base", "other", and "ours" versions (the contents, as well as their > >>> exec/link > >>> flags), and where the user/tool should write a resolved version > >>> (i.e., the > >>> working copy) as JSON. The user will then resolve the conflicts at > >>> their leisure > >>> and run `hg resolve --mark`. > >> > >> Overall I think it looks good. Some minor comments inline, but I'd be > >> ok having this queued (since it's been sitting here a while) and > >> addressing the nits in a follow up. > >> > >>> diff --git a/mercurial/commands.py b/mercurial/commands.py > >>> --- a/mercurial/commands.py > >>> +++ b/mercurial/commands.py > >>> @@ -33,6 +33,7 @@ > >>> error, > >>> exchange, > >>> extensions, > >>> +formatter, > >>> graphmod, > >>> hbisect, > >>> help, > >>> @@ -4284,6 +4285,26 @@ > >>> fm.end() > >>> return 0 > >>> > >>> +if opts.get('tool', '') == "internal:dumpjson": > >>> +fm = ui.formatter('resolve', {'template': 'json'}) > >>> +ms = mergemod.mergestate.read(repo) > > > > I don't love the short name style hg uses, and I don't see a godo reason > > to use it unless there's already a strong-established precedent in the > > file. > > > > We've been calling formatters 'fm' for a long time, but 'ms' as > > mergestate seems like a new one (to me at least). I'd love a more > > descriptive variable name since we have the option right now > > > >>> +m = scmutil.match(repo[None], pats, opts) > > > > Would prefer this be called 'matcher' > > > >>> +wctx = repo[None] > >>> + > >>> +paths = [] > >>> +for f in ms: > > > > Then this could become: > > > > for filename in mergestate: > > > > And then it's obvious from just reading the loop what it is doing > > > >>> +if not m(f): > > > > And this would become: > > > > if not matcher(filename): > > > > Which is also much more clear to me at least. > > > >>> +continue > >>> + > >>> +val = ms.internaldump(f, wctx) > >>> +if val is not None: > >>> +paths.append(val) > >>> + > >>> +fm.startitem() > >>> +fm.write('conflicts', '%s\n', paths) > >>> +fm.end() > >>> +return 0 > >>> + > >>> with repo.wlock(): > >>> ms = mergemod.mergestate.read(repo) > >>> > >>> diff --git a/mercurial/filemerge.py b/mercurial/filemerge.py > >>> --- a/mercurial/filemerge.py > >>> +++ b/mercurial/filemerge.py > >>> @@ -567,6 +567,40 @@ > >>> "o
Re: [PATCH V2] merge: add `internal:dumpjson` tool to `resolve`, which outputs conflict state
Fix a cat typing. Excerpts from Jun Wu's message of 2017-03-16 20:12:28 -0700: > Just to add some notes on variable names. There are some very common short > names. Like "p1" representing "parent1". And "p1" should be preferred. An > incomplete list is at [1]. It's okay to use "fname" hetlridvnvrtrtf ^^^ or "fn" instead of > "filename". > > FWIW, Ruby community standard prefers longer names while Golang explicitly > prefers shorter names [2]. I think both are reasonable, as long as the code > is consistent. > > For less-common things like "fca", "fco", etc. Longer names are definitely > better. For common objects like "matcher", "manifest", I think either is > okay. Since we are unlikely to rename "p1" to "parent1", I personally prefer > shorter ones for unambiguous common objects, especially when it can reduce > line wraps. > > [1]: https://www.mercurial-scm.org/wiki/CodingStyle > [2]: https://github.com/golang/go/wiki/CodeReviewComments#variable-names > > Excerpts from Phil Cohen's message of 2017-03-16 19:32:44 -0700: > > Thanks a lot for the points re: variable names! I'm actually really > > happy to hear that -- these names were taken from elsewhere in the > > codebase, and they were very confusing. I have forgotten/had to relearn > > the difference between fcd/fca/fco/etc several times. Glad to hear that > > slightly longer/clearer names are encouraged. > > > > On 3/15/17 11:20 PM, Ryan McElroy wrote: > > > More nits inline to consider since you're looking into a v3 anyway... > > > > > > > > > On 3/15/17 10:48 AM, Durham Goode wrote: > > >> > > >> > > >> On 3/7/17 11:40 AM, Phil Cohen wrote: > > >>> # HG changeset patch > > >>> # User Phil Cohen > > >>> # Date 1488915535 28800 > > >>> # Tue Mar 07 11:38:55 2017 -0800 > > >>> # Node ID bbce62e3790220f19e7b37160a2f8351b7461272 > > >>> # Parent 91e86a6c61c0c6a3b554eefeba906311aa29 > > >>> merge: add `internal:dumpjson` tool to `resolve`, which outputs > > >>> conflict state > > >>> > > >>> This supersedes a previous change which added a --prep option. > > >> > > >> Generally we don't reference previous iterations of the patch in the > > >> commit message, since those previous iterations wont' show up in the > > >> repo after this is pushed. > > >> > > >>> Normally, `hg resolve` takes the user on a whistle-stop tour of each > > >>> conflicted > > >>> file, pausing to launch the editor to resolve the conflicts. This is an > > >>> alternative workflow for resolving many conflicts in a random-access > > >>> fashion. It > > >>> doesn't change/replace the default behavior. > > >>> > > >>> This commit adds `--tool=internal:dumpjson`. It prints, for each > > >>> conflict, the > > >>> "base", "other", and "ours" versions (the contents, as well as their > > >>> exec/link > > >>> flags), and where the user/tool should write a resolved version > > >>> (i.e., the > > >>> working copy) as JSON. The user will then resolve the conflicts at > > >>> their leisure > > >>> and run `hg resolve --mark`. > > >> > > >> Overall I think it looks good. Some minor comments inline, but I'd be > > >> ok having this queued (since it's been sitting here a while) and > > >> addressing the nits in a follow up. > > >> > > >>> diff --git a/mercurial/commands.py b/mercurial/commands.py > > >>> --- a/mercurial/commands.py > > >>> +++ b/mercurial/commands.py > > >>> @@ -33,6 +33,7 @@ > > >>> error, > > >>> exchange, > > >>> extensions, > > >>> +formatter, > > >>> graphmod, > > >>> hbisect, > > >>> help, > > >>> @@ -4284,6 +4285,26 @@ > > >>> fm.end() > > >>> return 0 > > >>> > > >>> +if opts.get('tool', '') == "internal:dumpjson": > > >>> +fm = ui.formatter('resolve', {'template': 'json'}) > > >>> +ms = mergemod.mergestate.read(repo) > > > > > > I don't love the short name style hg uses, and I don't see a godo reason > > > to use it unless there's already a strong-established precedent in the > > > file. > > > > > > We've been calling formatters 'fm' for a long time, but 'ms' as > > > mergestate seems like a new one (to me at least). I'd love a more > > > descriptive variable name since we have the option right now > > > > > >>> +m = scmutil.match(repo[None], pats, opts) > > > > > > Would prefer this be called 'matcher' > > > > > >>> +wctx = repo[None] > > >>> + > > >>> +paths = [] > > >>> +for f in ms: > > > > > > Then this could become: > > > > > > for filename in mergestate: > > > > > > And then it's obvious from just reading the loop what it is doing > > > > > >>> +if not m(f): > > > > > > And this would become: > > > > > > if not matcher(filename): > > > > > > Which is also much more clear to me at least. > > > > > >>> +continue > > >>> + > > >>> +val = ms.internaldump(f, wctx) > > >>> +if val
[PATCH evolve-ext] tests: add glob for Windows
# HG changeset patch # User Matt Harbison # Date 1489720627 14400 # Thu Mar 16 23:17:07 2017 -0400 # Node ID ab5c2bef148bfb60e1956a55de4b7ba00ebe1817 # Parent 6a3248558b6929378450b572bb27406afe703ffd tests: add glob for Windows diff --git a/tests/test-inhibit.t b/tests/test-inhibit.t --- a/tests/test-inhibit.t +++ b/tests/test-inhibit.t @@ -911,7 +911,7 @@ $ cd not-inhibit $ hg book -d foo $ hg pull - pulling from $TESTTMP/inhibit + pulling from $TESTTMP/inhibit (glob) searching for changes no changes found adding remote bookmark foo diff --git a/tests/test-stablesort.t b/tests/test-stablesort.t --- a/tests/test-stablesort.t +++ b/tests/test-stablesort.t @@ -138,7 +138,7 @@ updating to branch default 0 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg -R repo_B pull --rev 13 - pulling from $TESTTMP/repo_A + pulling from $TESTTMP/repo_A (glob) searching for changes adding changesets adding manifests @@ -146,7 +146,7 @@ added 4 changesets with 0 changes to 0 files (+1 heads) (run 'hg heads' to see heads, 'hg merge' to merge) $ hg -R repo_B pull --rev 14 - pulling from $TESTTMP/repo_A + pulling from $TESTTMP/repo_A (glob) searching for changes adding changesets adding manifests @@ -154,7 +154,7 @@ added 1 changesets with 0 changes to 0 files (+1 heads) (run 'hg heads .' to see heads, 'hg merge' to merge) $ hg -R repo_B pull - pulling from $TESTTMP/repo_A + pulling from $TESTTMP/repo_A (glob) searching for changes adding changesets adding manifests @@ -204,7 +204,7 @@ updating to branch default 0 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg -R repo_C pull --rev 12 - pulling from $TESTTMP/repo_A + pulling from $TESTTMP/repo_A (glob) searching for changes adding changesets adding manifests @@ -212,7 +212,7 @@ added 2 changesets with 0 changes to 0 files (+1 heads) (run 'hg heads' to see heads, 'hg merge' to merge) $ hg -R repo_C pull --rev 15 - pulling from $TESTTMP/repo_A + pulling from $TESTTMP/repo_A (glob) searching for changes adding changesets adding manifests @@ -220,7 +220,7 @@ added 4 changesets with 0 changes to 0 files (+1 heads) (run 'hg heads .' to see heads, 'hg merge' to merge) $ hg -R repo_C pull - pulling from $TESTTMP/repo_A + pulling from $TESTTMP/repo_A (glob) searching for changes adding changesets adding manifests @@ -270,7 +270,7 @@ updating to branch default 0 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg -R repo_D pull --rev 10 - pulling from $TESTTMP/repo_A + pulling from $TESTTMP/repo_A (glob) searching for changes adding changesets adding manifests @@ -278,7 +278,7 @@ added 5 changesets with 0 changes to 0 files (run 'hg update' to get a working copy) $ hg -R repo_D pull --rev 15 - pulling from $TESTTMP/repo_A + pulling from $TESTTMP/repo_A (glob) searching for changes adding changesets adding manifests @@ -286,7 +286,7 @@ added 4 changesets with 0 changes to 0 files (+1 heads) (run 'hg heads' to see heads, 'hg merge' to merge) $ hg -R repo_D pull - pulling from $TESTTMP/repo_A + pulling from $TESTTMP/repo_A (glob) searching for changes adding changesets adding manifests @@ -404,7 +404,7 @@ updating to branch default 0 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg -R repo_E pull --rev e7d9710d9fc6 - pulling from $TESTTMP/repo_A + pulling from $TESTTMP/repo_A (glob) searching for changes adding changesets adding manifests @@ -420,7 +420,7 @@ updating to branch default 0 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg -R repo_F pull --rev d62d843c9a01 - pulling from $TESTTMP/repo_A + pulling from $TESTTMP/repo_A (glob) searching for changes adding changesets adding manifests @@ -436,7 +436,7 @@ updating to branch default 0 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg -R repo_G pull --rev 43227190fef8 - pulling from $TESTTMP/repo_A + pulling from $TESTTMP/repo_A (glob) searching for changes adding changesets adding manifests @@ -444,7 +444,7 @@ added 1 changesets with 0 changes to 0 files (+1 heads) (run 'hg heads' to see heads, 'hg merge' to merge) $ hg -R repo_G pull --rev 2702dd0c91e7 - pulling from $TESTTMP/repo_A + pulling from $TESTTMP/repo_A (glob) searching for changes adding changesets adding manifests diff --git a/tests/test-topic-dest.t b/tests/test-topic-dest.t --- a/tests/test-topic-dest.t +++ b/tests/test-topic-dest.t @@ -276,7 +276,7 @@ $ hg add other $ hg ci -m 'c_other' $ hg pull -r default --rebase - pulling from $TESTTMP/jungle + pulling from $TESTTMP/jungle (glob) searching for changes adding changesets adding manifests diff --git a/tests/test-topic-push.t b/tests/test-topic-push.t --- a/tests/test-topic-push.t +++ b
Re: [PATCH V2] merge: add `internal:dumpjson` tool to `resolve`, which outputs conflict state
I agree with pretty much all of that. Short standardized names that represent universal concepts in the codebase (like p1) are very useful. To steal Siracusa's description of Perl, it is a bit like Huffman coding: make the common case easy and short, and the more unusual case longer and more descriptive. From: Jun Wu Sent: Thursday, March 16, 2017 8:15 PM To: Jun Wu Cc: Phil Cohen; Ryan McElroy; Durham Goode; mercurial-devel Subject: Re: [PATCH V2] merge: add `internal:dumpjson` tool to `resolve`, which outputs conflict state Fix a cat typing. Excerpts from Jun Wu's message of 2017-03-16 20:12:28 -0700: > Just to add some notes on variable names. There are some very common short > names. Like "p1" representing "parent1". And "p1" should be preferred. An > incomplete list is at [1]. It's okay to use "fname" hetlridvnvrtrtf ^^^ or "fn" instead of > "filename". > > FWIW, Ruby community standard prefers longer names while Golang explicitly > prefers shorter names [2]. I think both are reasonable, as long as the code > is consistent. > > For less-common things like "fca", "fco", etc. Longer names are definitely > better. For common objects like "matcher", "manifest", I think either is > okay. Since we are unlikely to rename "p1" to "parent1", I personally prefer > shorter ones for unambiguous common objects, especially when it can reduce > line wraps. > > [1]: https://www.mercurial-scm.org/wiki/CodingStyle CodingStyle - Mercurial www.mercurial-scm.org 1. Introduction. This page is intended to save new developers a few round-trips when contributing changes. It doesn't cover everything, but it does cover some of the ... > [2]: https://github.com/golang/go/wiki/CodeReviewComments#variable-names https://avatars1.githubusercontent.com/u/4314092?v=3&s=400 CodeReviewComments · golang/go Wiki · GitHub github.com The former declares a nil slice value, while the latter is non-nil but zero-length. They are functionally equivalent—their len and cap are both zero—but the nil ... > > Excerpts from Phil Cohen's message of 2017-03-16 19:32:44 -0700: > > Thanks a lot for the points re: variable names! I'm actually really > > happy to hear that -- these names were taken from elsewhere in the > > codebase, and they were very confusing. I have forgotten/had to relearn > > the difference between fcd/fca/fco/etc several times. Glad to hear that > > slightly longer/clearer names are encouraged. > > > > On 3/15/17 11:20 PM, Ryan McElroy wrote: > > > More nits inline to consider since you're looking into a v3 anyway... > > > > > > > > > On 3/15/17 10:48 AM, Durham Goode wrote: > > >> > > >> > > >> On 3/7/17 11:40 AM, Phil Cohen wrote: > > >>> # HG changeset patch > > >>> # User Phil Cohen > > >>> # Date 1488915535 28800 > > >>> # Tue Mar 07 11:38:55 2017 -0800 > > >>> # Node ID bbce62e3790220f19e7b37160a2f8351b7461272 > > >>> # Parent 91e86a6c61c0c6a3b554eefeba906311aa29 > > >>> merge: add `internal:dumpjson` tool to `resolve`, which outputs > > >>> conflict state > > >>> > > >>> This supersedes a previous change which added a --prep option. > > >> > > >> Generally we don't reference previous iterations of the patch in the > > >> commit message, since those previous iterations wont' show up in the > > >> repo after this is pushed. > > >> > > >>> Normally, `hg resolve` takes the user on a whistle-stop tour of each > > >>> conflicted > > >>> file, pausing to launch the editor to resolve the conflicts. This is an > > >>> alternative workflow for resolving many conflicts in a random-access > > >>> fashion. It > > >>> doesn't change/replace the default behavior. > > >>> > > >>> This commit adds `--tool=internal:dumpjson`. It prints, for each > > >>> conflict, the > > >>> "base", "other", and "ours" versions (the contents, as well as their > > >>> exec/link > > >>> flags), and where the user/tool should write a resolved version > > >>> (i.e., the > > >>> working copy) as JSON. The user will then resolve the conflicts at > > >>> their leisure > > >>> and run `hg resolve --mark`. > > >> > > >> Overall I think it looks good. Some minor comments inline, but I'd be > > >> ok having this queued (since it's been sitting here a while) and > > >> addressing the nits in a follow up. > > >> > > >>> diff --git a/mercurial/commands.py b/mercurial/commands.py > > >>> --- a/mercurial/commands.py > > >>> +++ b/mercurial/commands.py > > >>> @@ -33,6 +33,7 @@ > > >>> error, > > >>> exchange, > > >>> extensions, > > >>> + formatter, > > >>> graphmod, > > >>> hbisect, > > >>> help, > > >>> @@ -4284,6 +4285,26 @@ > > >>> fm.end() > > >>> return 0 > > >>> > > >>> + if opts.get('tool', '') == "internal:dumpjson": > > >>> + fm = ui.formatter('resolve', {'template': 'json'}) > > >>> + ms = mergemod.mergestate.read(repo) > > > > > > I