[PATCH] tests: exclude bundled pywatchman from check-code test

2016-12-20 Thread David Soria Parra
# HG changeset patch
# User David Soria Parra 
# Date 1482294521 28800
#  Tue Dec 20 20:28:41 2016 -0800
# Node ID 26a5b7f91ec50d20782816b83841bd8087478eb0
# Parent  b090cdf0e161af0ac6768cb404cc0e51bb0baf00
tests: exclude bundled pywatchman from check-code test

pywatchman is imported from upstream and therefore fails to pass
linting. We have added 'no-check-code' manually to every file in the
past. This is cumbersome and modifies upstream sources.

diff --git a/tests/test-check-code.t b/tests/test-check-code.t
--- a/tests/test-check-code.t
+++ b/tests/test-check-code.t
@@ -7,13 +7,8 @@
 New errors are not allowed. Warnings are strongly discouraged.
 (The writing "no-che?k-code" is for not skipping this file when checking.)
 
-  $ hg locate -X contrib/python-zstandard | sed 's-\\-/-g' |
-  >   xargs "$check_code" --warnings --per-file=0 || false
-  Skipping hgext/fsmonitor/pywatchman/__init__.py it has no-che?k-code (glob)
-  Skipping hgext/fsmonitor/pywatchman/bser.c it has no-che?k-code (glob)
-  Skipping hgext/fsmonitor/pywatchman/capabilities.py it has no-che?k-code 
(glob)
-  Skipping hgext/fsmonitor/pywatchman/msc_stdint.h it has no-che?k-code (glob)
-  Skipping hgext/fsmonitor/pywatchman/pybser.py it has no-che?k-code (glob)
+  $ hg locate -X contrib/python-zstandard -X hgext/fsmonitor/pywatchman |
+  > sed 's-\\-/-g' | xargs "$check_code" --warnings --per-file=0 || false
   Skipping i18n/polib.py it has no-che?k-code (glob)
   Skipping mercurial/httpclient/__init__.py it has no-che?k-code (glob)
   Skipping mercurial/httpclient/_readers.py it has no-che?k-code (glob)
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH] match: adding non-recursive directory matching

2016-12-20 Thread Rodrigo Damazio via Mercurial-devel
On Tue, Dec 20, 2016 at 5:47 AM, Pierre-Yves David <
pierre-yves.da...@ens-lyon.org> wrote:

>
>
> On 12/20/2016 06:00 AM, Rodrigo Damazio wrote:
>
>> Unfortunately, while set would match the right files, because of the way
>> the code is structured, it provides no way to not try visiting the
>> directories inside the non-recursive match - the set needs to first
>> collect all the files in all subdirectories (match.py, _expandset) and
>> then filter that down to the desired ones. In plain hg repos, that's
>> just much slower - in the context of narrowhg, the repo will simply not
>> have the manifests for those subdirectories and trying to visit them
>> will crash.
>>
>
> Okay, so this seems like the current tools allow you to specify the right
> request but shortcoming of the -implementation- are preventing that request
> to work probably with narrowhg (and have performance impacts)
>
> Did I got that right ?


Yes.

The follow-up change to this one (which I haven't sent yet but is
>> written) is updating visitdir to allow non-recursiveness, which btw
>> makes something like "hg files -I rootglob:browser/*" about 4-5x faster
>> in the firefox repo.
>>
>
> And, If I read you right, the implementation of 'rootglob:' you provided
> in your patch have the same implementation issue, but you have another
> patch to improve the implementation to behave a way you can use (and is
> faster).
>
> Did I got that right too ?
>

Yes.

If I got these two pieces right, it looks like we could just apply the
> improvement to 'visitdir' to 'set:your/glob/*' and have your usecase filled
> while not jumping into UI changes. Would that work for you ?
>

Not without a third set of changes, since set expansion doesn't use
visitdir (or the matcher being built) at all - the dependency is that
building the matcher depends on expanding the set (and thus the set can't
depend on the matcher).
It would technically be doable for re:, but I'm wary of getting into the
business of parsing and special-casing regexes to assume what they match or
don't.


> On Fri, Dec 16, 2016 at 6:21 AM, Pierre-Yves David
>> >
>> wrote:
>>
>>
>>
>> On 12/16/2016 02:19 AM, Augie Fackler wrote:
>>
>>
>> On Nov 24, 2016, at 10:28 AM, FUJIWARA Katsunori
>> > wrote:
>>
>> Yes, "files:" was the original version of this patch
>> and the case I really
>> care about :) I changed it to rootglob after your
>> comments.
>> Which way would be preferred to move forward?
>>
>>
>> "files:" is "path:" family, and "rootglob:" is "glob:"
>> family. As we
>> concluded before, "path:" itself can't control recursion of
>> matching
>> well.
>>
>> Therefore, I think that "files:" should be implemented if
>> needed,
>> regardless of implementing "rootglob:".
>>
>> Of course, we need high point view of this area, at first :-)
>>
>>
>> BTW, it is a little ambiguous (at least, for me) that
>> "files:foo"
>> matches against both file "foo" and files just under directory
>> "foo". Name other than "files:" may resolve this ambiguity,
>> but I
>> don't have any better (and short enough) name :-<
>>
>>  ==  === ===
>>  patternfoo  foo/bar foo/bar/baz
>>  ==  === ===
>>  path:fooo o o
>>
>>  files:foo   o o x
>>
>>  file:fooo x x
>>  dir:foo x o o
>>  ==  === ===
>>
>>
>> Scanning the plan page, I see that there’s a *lot* of work that
>> could be done and no consensus as yet, but that the only
>> immediate use case seems to be the rootfile/rootglob case. Is
>> there some path forward we could agree on that would unblock
>> those immediate needs for narrowhg and not make things harder in
>> the future?
>>
>> Alternatively, would we be okay with a slight refactor of the
>> matcher so that narrowhg can introduce a custom filesonly:
>> matcher for the time being so we can keep making forward
>> progress there?  I don’t know the matcher code well enough to be
>> able to guess if this is a reasonable path so we can be unblocked.
>>
>> (It’s very hard for to justify the amount of work implied by
>> reaching consensus on FileNamePatternsPlan and then executing
>> the entire thing when what we need is solvable today with a
>> sub-hour patch to existing code, thus my trying to find a
>> solution we can all live with.)
>>
>>

Re: [PATCH 4 of 4] convert: parse perforce data on-demand

2016-12-20 Thread Augie Fackler
On Tue, Dec 20, 2016 at 10:07:22AM -0800, David Soria Parra wrote:
> # HG changeset patch
> # User David Soria Parra 
> # Date 1482254630 28800
> #  Tue Dec 20 09:23:50 2016 -0800
> # Node ID a047a142f151709f882361916617e762816db619
> # Parent  77e1912e2e0817a96633568c400450a9566e7e33
> convert: parse perforce data on-demand

Queued these, thanks. How does it feel to be the convert maintainer?

>
> We are using read-only attributes that parse the perforce data on
> demand. We are reading the data only once whenever an attribute is
> requested and use it throughout the import process. This is equivalent
> to the previous behavior, but we are avoiding reading from perforce when
> we initialize the object, but instead run it during the actual import
> process, when the first attribute is requested (usually getheads(), see
> `convertcmd.convert`).
>
> diff --git a/hgext/convert/p4.py b/hgext/convert/p4.py
> --- a/hgext/convert/p4.py
> +++ b/hgext/convert/p4.py
> @@ -56,13 +56,8 @@
>  common.checktool('p4', abort=False)
>
>  self.revmap = {}
> -self.heads = []
> -self.changeset = {}
> -self.files = {}
> -self.copies = {}
>  self.encoding = self.ui.config('convert', 'p4.encoding',
> default=convcmd.orig_encoding)
> -self.depotname = {}   # mapping from local name to depot name
>  self.re_type = re.compile(
>  "([a-z]+)?(text|binary|symlink|apple|resource|unicode|utf\d+)"
>  "(\+\w+)?$")
> @@ -74,7 +69,6 @@
>  if revs and len(revs) > 1:
>  raise error.Abort(_("p4 source does not support specifying "
> "multiple revisions"))
> -self._parse_once(ui, path)
>
>  def setrevmap(self, revmap):
>  """Sets the parsed revmap dictionary.
> @@ -240,13 +234,29 @@
>  'depotname': depotname,
>  }
>
> -def _parse_once(self, ui, path):
> -d = self._parse(ui, path)
> -self.changeset = d['changeset']
> -self.heads = d['heads']
> -self.files = d['files']
> -self.copies = d['copies']
> -self.depotname = d['depotname']
> +@util.propertycache
> +def _parse_once(self):
> +return self._parse(self.ui, self.path)
> +
> +@util.propertycache
> +def copies(self):
> +return self._parse_once['copies']
> +
> +@util.propertycache
> +def files(self):
> +return self._parse_once['files']
> +
> +@util.propertycache
> +def changeset(self):
> +return self._parse_once['changeset']
> +
> +@util.propertycache
> +def heads(self):
> +return self._parse_once['heads']
> +
> +@util.propertycache
> +def depotname(self):
> +return self._parse_once['depotname']
>
>  def getheads(self):
>  return self.heads
> diff --git a/tests/test-convert-p4-filetypes.t 
> b/tests/test-convert-p4-filetypes.t
> --- a/tests/test-convert-p4-filetypes.t
> +++ b/tests/test-convert-p4-filetypes.t
> @@ -307,11 +307,11 @@
>  convert
>$ hg convert -s p4 $DEPOTPATH dst
>initializing destination dst repository
> +  scanning source...
>reading p4 views
>collecting p4 changelists
>1 initial
>2 keywords
> -  scanning source...
>sorting...
>converting...
>1 initial
> diff --git a/tests/test-convert-p4.t b/tests/test-convert-p4.t
> --- a/tests/test-convert-p4.t
> +++ b/tests/test-convert-p4.t
> @@ -67,12 +67,12 @@
>  convert
>$ hg convert -s p4 $DEPOTPATH dst
>initializing destination dst repository
> +  scanning source...
>reading p4 views
>collecting p4 changelists
>1 initial
>2 change a
>3 change b/c
> -  scanning source...
>sorting...
>converting...
>2 initial
> @@ -98,13 +98,10 @@
>
>  convert again
>$ hg convert -s p4 $DEPOTPATH dst
> +  scanning source...
>reading p4 views
>collecting p4 changelists
> -  1 initial
> -  2 change a
> -  3 change b/c
>4 change a b/c
> -  scanning source...
>sorting...
>converting...
>0 change a b/c
> @@ -130,14 +127,10 @@
>
>  convert again
>$ hg convert -s p4 $DEPOTPATH dst
> +  scanning source...
>reading p4 views
>collecting p4 changelists
> -  1 initial
> -  2 change a
> -  3 change b/c
> -  4 change a b/c
>5 add d e f
> -  scanning source...
>sorting...
>converting...
>0 add d e f
> ___
> 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] changegroup: simplify logic around enabling changegroup 03

2016-12-20 Thread Augie Fackler
On Mon, Dec 19, 2016 at 07:41:23AM +0100, Pierre-Yves David wrote:
> # HG changeset patch
> # User Pierre-Yves David 
> # Date 1482117918 -3600
> #  Mon Dec 19 04:25:18 2016 +0100
> # Node ID e62c766c60a19d89c4e0e50881701135c251fb6f
> # Parent  fef4a4a522c7ea405d8a036213223dca79fc3f84
> # EXP-Topic cleanup.changegroup
> changegroup: simplify logic around enabling changegroup 03

Queued, but there's a (now-obvious) bug (not a regression though) that
I'll expect a quick followup for: if treemanifest is in the
repo.requirements, 01 and 02 won't work, and so should be discarded.

>
> There was multiple spot that took care of adding '03' as supported changegroup
> version for different condition. We gather them all in one location for
> simplicity.
>
> The 'supportedincomingversions' function is now doing nothing, but I kept it
> around because it looks like a great hooking point for extension.
>
> (Note that we should probably just get changegroup3 out of experimental now, 
> But
> that would be a patch with a much wider scope).
>
> diff --git a/mercurial/changegroup.py b/mercurial/changegroup.py
> --- a/mercurial/changegroup.py
> +++ b/mercurial/changegroup.py
> @@ -877,16 +877,14 @@ class cg3packer(cg2packer):
>  def allsupportedversions(repo):
>  versions = set(_packermap.keys())
>  if not (repo.ui.configbool('experimental', 'changegroup3') or
> -repo.ui.configbool('experimental', 'treemanifest')):
> +repo.ui.configbool('experimental', 'treemanifest') or
> +'treemanifest' in repo.requirements):
>  versions.discard('03')
>  return versions
>
>  # Changegroup versions that can be applied to the repo
>  def supportedincomingversions(repo):
> -versions = allsupportedversions(repo)
> -if 'treemanifest' in repo.requirements:
> -versions.add('03')
> -return versions
> +return allsupportedversions(repo)
>
>  # Changegroup versions that can be created from the repo
>  def supportedoutgoingversions(repo):
> @@ -899,7 +897,6 @@ def supportedoutgoingversions(repo):
>  # support versions 01 and 02.
>  versions.discard('01')
>  versions.discard('02')
> -versions.add('03')
>  return versions
>
>  def safeversion(repo):
> ___
> 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] p4: drop an assignment that is never used

2016-12-20 Thread Augie Fackler
On Mon, Dec 19, 2016 at 10:23:43PM +, Jun Wu wrote:
> # HG changeset patch
> # User Jun Wu 
> # Date 1482186162 0
> #  Mon Dec 19 22:22:42 2016 +
> # Node ID a99748ec71eb65b50dabf1d73ab9de0c6b9124b2
> # Parent  935092e525b0ee5656d0830162a1c2adf8248de3
> # Available At https://bitbucket.org/quark-zju/hg-draft
> #  hg pull https://bitbucket.org/quark-zju/hg-draft -r 
> a99748ec71eb
> p4: drop an assignment that is never used

Yuya beat you to it: 32a07b8a9f7

(queued so the bot knows this is handled)

>
> Discovered by pyflakes:
>
>   hgext/convert/p4.py:305: local variable 'shortdesc' is assigned to but
>   never used
>
> diff --git a/hgext/convert/p4.py b/hgext/convert/p4.py
> --- a/hgext/convert/p4.py
> +++ b/hgext/convert/p4.py
> @@ -303,6 +303,4 @@ class p4_source(common.converter_source)
>  """
>  desc = self.recode(obj.get("desc", ""))
> -shortdesc = desc.split("\n", 1)[0]
> -
>  date = (int(obj["time"]), 0) # timezone not set
>  if parents is None:
> ___
> 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 hg-website] menu: capitalize the menu options in nav bar

2016-12-20 Thread Sean Farley
Sean Farley  writes:

> Pulkit Goyal <7895pul...@gmail.com> writes:
>
>> # HG changeset patch
>> # User Pulkit Goyal <7895pul...@gmail.com>
>> # Date 1481185128 -19800
>> #  Thu Dec 08 13:48:48 2016 +0530
>> # Node ID 39b44ed32913cc10bcc93115286262f080a257fb
>> # Parent  5d30d7a345692b6656b60c9f4dab86f012b391eb
>> menu: capitalize the menu options in nav bar
>>
>> This patch capitalize the first letter of the options in nav bar.
>
> Thanks! I'm a bit busy today but will try to swing back around to this
> later.

Finally got around to this. I am no UI expert but think it looks better
:-)

Queued (and now pushed)!
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


mercurial@30616: 9 new changesets

2016-12-20 Thread Mercurial Commits
9 new changesets in mercurial:

https://www.mercurial-scm.org/repo/hg/rev/b52e8a4f4c0f
changeset:   30608:b52e8a4f4c0f
user:Pierre-Yves David 
date:Mon Dec 12 13:32:45 2016 +0100
summary: registrar: raise a programming error on duplicated registering

https://www.mercurial-scm.org/repo/hg/rev/9bf43a72b49d
changeset:   30609:9bf43a72b49d
user:Jun Wu 
date:Fri Dec 16 21:02:39 2016 +
summary: context: correct metadataonlyctx's parameter

https://www.mercurial-scm.org/repo/hg/rev/66cffa87d2f2
changeset:   30610:66cffa87d2f2
user:Martin von Zweigbergk 
date:Fri Dec 16 09:48:14 2016 -0800
summary: help: make multirevs just an alias for revsets

https://www.mercurial-scm.org/repo/hg/rev/cbc61b1b52ea
changeset:   30611:cbc61b1b52ea
user:Pulkit Goyal <7895pul...@gmail.com>
date:Sat Dec 17 19:36:40 2016 +0530
summary: py3: use %d instead of %s for integers

https://www.mercurial-scm.org/repo/hg/rev/d623cc6b3742
changeset:   30612:d623cc6b3742
user:Pulkit Goyal <7895pul...@gmail.com>
date:Sat Dec 17 19:47:17 2016 +0530
summary: py3: replace os.pathsep with pycompat.ospathsep

https://www.mercurial-scm.org/repo/hg/rev/1112ff99d965
changeset:   30613:1112ff99d965
user:Pulkit Goyal <7895pul...@gmail.com>
date:Sat Dec 17 19:56:30 2016 +0530
summary: py3: replace os.sep with pycompat.ossep (part 1 of 4)

https://www.mercurial-scm.org/repo/hg/rev/cfe66dcf45c0
changeset:   30614:cfe66dcf45c0
user:Pulkit Goyal <7895pul...@gmail.com>
date:Sat Dec 17 20:02:50 2016 +0530
summary: py3: replace os.sep with pycompat.ossep (part 2 of 4)

https://www.mercurial-scm.org/repo/hg/rev/bb77654dc7ae
changeset:   30615:bb77654dc7ae
user:Pulkit Goyal <7895pul...@gmail.com>
date:Sat Dec 17 20:14:24 2016 +0530
summary: py3: replace os.sep with pycompat.ossep (part 3 of 4)

https://www.mercurial-scm.org/repo/hg/rev/6f9fcd29e290
changeset:   30616:6f9fcd29e290
bookmark:@
tag: tip
user:Pulkit Goyal <7895pul...@gmail.com>
date:Sat Dec 17 20:24:46 2016 +0530
summary: py3: replace os.sep with pycompat.ossep (part 4 of 4)

-- 
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 5 of 8 evolve-ext, V2] metaedit: use faster setparents instead of full update

2016-12-20 Thread Pierre-Yves David



On 12/06/2016 05:41 PM, Mateusz Kwapich wrote:

# HG changeset patch
# User Mateusz Kwapich 
# Date 1479325623 0
#  Wed Nov 16 19:47:03 2016 +
# Branch stable
# Node ID 651b6258e993f6d45e4ef7b324303201db5639b2
# Parent  d4a8c386a14b3e455e60fffec7fb315f9629ff12
metaedit: use faster setparents instead of full update

The working copy is not changing so there is no need to extra status call.


Urg, not very enthusiastic. Can we have at least number about this speedup ?


This makes metaedit work on dirty wc.


Note that since the file are identical on both side, we are sure there 
won't be merge conflict so we could use the update logic (enabling 
"merging"  and that would work as well. I would probably be move 
comfortable accepting something enable fold from a dirty WC using update 
and then another one moving to set parent.



diff --git a/hgext/evolve.py b/hgext/evolve.py
--- a/hgext/evolve.py
+++ b/hgext/evolve.py
@@ -3303,7 +3303,7 @@ def metaedit(ui, repo, *revs, **opts):
 if opts['fold']:
 ui.status('%i changesets folded\n' % len(revs))
 if newp1 is not None:
-hg.update(repo, newp1)
+repo.setparents(newp1)
 finally:
 lockmod.release(lock, wlock)

diff --git a/tests/test-evolve.t b/tests/test-evolve.t
--- a/tests/test-evolve.t
+++ b/tests/test-evolve.t
@@ -1489,7 +1489,6 @@ check that metaedit respects allowunstab
   abort: cannot fold chain not ending with a head or with branching
   [255]
   $ hg metaedit --user foobar
-  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg log --template '{rev}: {author}\n' -r '42:' --hidden
   42: test
   43: foobar
@@ -1497,7 +1496,6 @@ check that metaedit respects allowunstab
   43: foobar

   $ HGEDITOR="sed -i'' -e 's/safely/quickly/g'" hg metaedit '.^::.'
-  0 files updated, 0 files merged, 0 files removed, 0 files unresolved

   $ HGEDITOR=cat hg metaedit '.^::.' --fold
   HG: This is a fold of 2 changesets.
@@ -1519,7 +1517,6 @@ check that metaedit respects allowunstab
   HG: changed a
   HG: changed newfile
   2 changesets folded
-  0 files updated, 0 files merged, 0 files removed, 0 files unresolved

   $ glog -r .
   @  45:ca7a9e928b25@default(draft) amended
@@ -1553,7 +1550,6 @@ no new commit is created here because th

 TODO: don't create a new commit in this case
   $ hg metaedit --config defaults.metaedit=
-  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg log -r '.^::.' --template '{rev}: {desc|firstline}\n'
   36: add uu
   46: amended
@@ -1570,8 +1566,11 @@ TODO: don't create a new commit in this
   47: foobar2
   $ hg diff -r 45 -r 46 --hidden

-'fold' one commit
+'fold' one commit with dirty wc
+  $ echo x > newfile
   $ hg metaedit 39 --fold --user foobar3
   1 changesets folded
   $ hg log -r 48 --template '{rev}: {author}\n'
   48: foobar3
+  $ hg st -amr
+  M newfile


Cheers,

--
Pierre-Yves David
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 1 of 8 evolve-ext, V2] metaedit: add a helper function for just metadata rewrites

2016-12-20 Thread Pierre-Yves David

On 12/06/2016 05:41 PM, Mateusz Kwapich wrote:

# HG changeset patch
# User Mateusz Kwapich 
# Date 1481028829 28800
#  Tue Dec 06 04:53:49 2016 -0800
# Branch stable
# Node ID 78b75ed14103cee05ed13948025310919adde559
# Parent  727c7211c810d304ebf92b32db7ecf697ce46ac6
metaedit: add a helper function for just metadata rewrites

It will be used by metaedit.


I've eventually came to review this. Sorry for the delay.

The overall approach seems right, and I'm happy to see the "multiple 
revs" case implemented. However, I'm not thrilled with the amount of 
code duplicated. I think we can share more codepath here. I was not too 
sure of where to explain how, so you get a wall of text in patch 1. 
Happy reading.


About rewrite
-

The very venerable 'rewrite' function have been in this repository since 
september 19th 2011. And was actually written by Peter Arrenbrecht in 
spring 2011 (I just imported it in). It was originally written to handle 
'amend'. But is no longer used for this purpose.


Its signature is a bit strange.

  def rewrite(repo, old, updates, head, newbases, commitopts):

If will effectively fold "old + updates" and "rebase" the result on 
"newbases" without actually merging anything. so "updates" MUST be 
linear direct descendant of "old", and "newbases" must have the same 
manifest content as the old's parents.


"head" seems to just be 'heads(old + updates)'
The meta-data of "old" are reused for the resulting commit and mixed 
with "commitopts"



It looks like it could use some cleanup if you feel brave enough.

About metarewrite vs rewrite
--

metarewrite seems to be doing the same things as rewrite but:
1) For only a single changesets
2) In the case we know we can reuse the manifest revision (and so we do).

We can probably detect that directly within 'rewrite' and take a fast 
path in that case.


* We can detect (1) if 'updates' is empty (and therefore head is old),
* we check if the manifest is reusable by checking if the manifest 
nodeid for 'old.p1()' and 'old.p2()' match the one in 'newbases'. If we 
detect these two conditions, we can skip the expensive 'files' 
computation in rewrite ctx, and just call memlightctx to create the 
changeset.


These two checkes + small amount of conditional branching seems small 
enough to me that I don't think we should duplicate the code and just 
have rewrite be a bit smarter. This would avoid the two code bases to 
slowly diverge for no good reason.
In addition that would benefit other command that use 'rewrite' in 
compatible situation (eg: fold).


What do you think ?

About the core fold code


The same apply to the code duplication in the body of the metaedit 
function. We get two entirely new "codebase" for each code path (fold 
and not fold) while they still have a lot in common. This lead to slow 
but dangerous code drift. We already see it in your series where fold is 
properly handling phase preservation while not-fold lost it.


So in my opinion we could have a single code base using the fact that:

* Having only 1 folding action can still be expressed in a list of actions
* Not folding changesets together can be expressed with folding a set of 
only one changeset.


At that point, I'll move the rest into the reply to patch 3. for clarity.

Cheers


diff --git a/hgext/evolve.py b/hgext/evolve.py
--- a/hgext/evolve.py
+++ b/hgext/evolve.py
@@ -907,6 +907,13 @@ def rewrite(repo, old, updates, head, ne
 finally:
 lockmod.release(tr, lock, wlock)

+def metarewrite(repo, old, newbases, commitopts):
+'''Like rewrite but affects only the changeset metadata.'''
+# TODO: reuse the manifest for speed
+newid, created = rewrite(repo, old, [old], old, newbases,
+ commitopts=commitopts)
+return newid, created
+
 class MergeFailure(error.Abort):
 pass

___
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


Re: [PATCH 7 of 8 evolve-ext, V2] evolve: make the disallowing new unstable more accurate

2016-12-20 Thread Pierre-Yves David



On 12/06/2016 05:41 PM, Mateusz Kwapich wrote:

# HG changeset patch
# User Mateusz Kwapich 
# Date 1481040901 28800
#  Tue Dec 06 08:15:01 2016 -0800
# Branch stable
# Node ID a7cc11231c424e435252e7388dd05b139e766af2
# Parent  02a29df6827d1dae26b885c9c6c9d56be33ecd00
evolve: make the disallowing new unstable more accurate

If the changesets are already unstable don't trigger disallownewunstable


Well, yes, such run would not create more unstability. But the point of 
allow unstable is to prevent people to create unstable situation 
locally. And this would allow to create more unstability over some 
existing unstability.


I'm curious about your usecase here. Can you elaborate ?


diff --git a/hgext/evolve.py b/hgext/evolve.py
--- a/hgext/evolve.py
+++ b/hgext/evolve.py
@@ -3365,7 +3365,7 @@ def _disallowednewunstable(repo, revs):
 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
 if allowunstable:
 return revset.baseset()
-return repo.revs("(%ld::) - %ld", revs, revs)
+return repo.revs("(%ld::) - %ld - unstable() - obsolete()", revs, revs)

 @eh.wrapcommand('graft')
 def graftwrapper(orig, ui, repo, *revs, **kwargs):
___
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 2 of 4] convert: move localname state to function scope

2016-12-20 Thread David Soria Parra
# HG changeset patch
# User David Soria Parra 
# Date 1482254630 28800
#  Tue Dec 20 09:23:50 2016 -0800
# Node ID 6f7154489117ac5cc9f0f876e922fef5c44803d8
# Parent  4cb85a7af6deb30abfd4c40ec8e502560150999e
convert: move localname state to function scope

diff --git a/hgext/convert/p4.py b/hgext/convert/p4.py
--- a/hgext/convert/p4.py
+++ b/hgext/convert/p4.py
@@ -64,7 +64,6 @@
 self.encoding = self.ui.config('convert', 'p4.encoding',
default=convcmd.orig_encoding)
 self.depotname = {}   # mapping from local name to depot name
-self.localname = {} # mapping from depot name to local name
 self.re_type = re.compile(
 "([a-z]+)?(text|binary|symlink|apple|resource|unicode|utf\d+)"
 "(\+\w+)?$")
@@ -168,6 +167,7 @@
 files = []
 copies = {}
 copiedfiles = []
+localname = {}
 i = 0
 while ("depotFile%d" % i) in d and ("rev%d" % i) in d:
 oldname = d["depotFile%d" % i]
@@ -181,7 +181,7 @@
 self.depotname[filename] = oldname
 if (d.get("action%d" % i) == "move/add"):
 copiedfiles.append(filename)
-self.localname[oldname] = filename
+localname[oldname] = filename
 i += 1
 
 # Collect information about copied files
@@ -208,8 +208,8 @@
 j += 1
 i += 1
 
-if copiedoldname and copiedoldname in self.localname:
-copiedfilename = self.localname[copiedoldname]
+if copiedoldname and copiedoldname in localname:
+copiedfilename = localname[copiedoldname]
 break
 
 if copiedfilename:
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 3 of 4] convert: return calculated values from parse() instead of manpulating state

2016-12-20 Thread David Soria Parra
# HG changeset patch
# User David Soria Parra 
# Date 1482254630 28800
#  Tue Dec 20 09:23:50 2016 -0800
# Node ID 77e1912e2e0817a96633568c400450a9566e7e33
# Parent  6f7154489117ac5cc9f0f876e922fef5c44803d8
convert: return calculated values from parse() instead of manpulating state

diff --git a/hgext/convert/p4.py b/hgext/convert/p4.py
--- a/hgext/convert/p4.py
+++ b/hgext/convert/p4.py
@@ -56,7 +56,6 @@
 common.checktool('p4', abort=False)
 
 self.revmap = {}
-self.p4changes = {}
 self.heads = []
 self.changeset = {}
 self.files = {}
@@ -75,7 +74,7 @@
 if revs and len(revs) > 1:
 raise error.Abort(_("p4 source does not support specifying "
"multiple revisions"))
-self._parse(ui, path)
+self._parse_once(ui, path)
 
 def setrevmap(self, revmap):
 """Sets the parsed revmap dictionary.
@@ -103,11 +102,19 @@
 
 def _parse(self, ui, path):
 "Prepare list of P4 filenames and revisions to import"
+p4changes = {}
+changeset = {}
+files_map = {}
+copies_map = {}
+localname = {}
+depotname = {}
+heads = []
+
 ui.status(_('reading p4 views\n'))
 
 # read client spec or view
 if "/" in path:
-self.p4changes.update(self._parse_view(path))
+p4changes.update(self._parse_view(path))
 if path.startswith("//") and path.endswith("/..."):
 views = {path[:-3]:""}
 else:
@@ -120,7 +127,7 @@
 for client in clientspec:
 if client.startswith("View"):
 sview, cview = clientspec[client].split()
-self.p4changes.update(self._parse_view(sview))
+p4changes.update(self._parse_view(sview))
 if sview.endswith("...") and cview.endswith("..."):
 sview = sview[:-3]
 cview = cview[:-3]
@@ -129,8 +136,8 @@
 views[sview] = cview
 
 # list of changes that affect our source files
-self.p4changes = self.p4changes.keys()
-self.p4changes.sort(key=int)
+p4changes = p4changes.keys()
+p4changes.sort(key=int)
 
 # list with depot pathnames, longest first
 vieworder = views.keys()
@@ -142,7 +149,7 @@
 # now read the full changelists to get the list of file revisions
 ui.status(_('collecting p4 changelists\n'))
 lastid = None
-for change in self.p4changes:
+for change in p4changes:
 if startrev and int(change) < int(startrev):
 continue
 if self.revs and int(change) > int(self.revs[0]):
@@ -167,7 +174,6 @@
 files = []
 copies = {}
 copiedfiles = []
-localname = {}
 i = 0
 while ("depotFile%d" % i) in d and ("rev%d" % i) in d:
 oldname = d["depotFile%d" % i]
@@ -178,7 +184,7 @@
 break
 if filename:
 files.append((filename, d["rev%d" % i]))
-self.depotname[filename] = oldname
+depotname[filename] = oldname
 if (d.get("action%d" % i) == "move/add"):
 copiedfiles.append(filename)
 localname[oldname] = filename
@@ -186,7 +192,7 @@
 
 # Collect information about copied files
 for filename in copiedfiles:
-oldname = self.depotname[filename]
+oldname = depotname[filename]
 
 flcmd = 'p4 -G filelog %s' \
   % util.shellquote(oldname)
@@ -218,13 +224,29 @@
 ui.warn(_("cannot find source for copied file: %s@%s\n")
 % (filename, change))
 
-self.changeset[change] = c
-self.files[change] = files
-self.copies[change] = copies
+changeset[change] = c
+files_map[change] = files
+copies_map[change] = copies
 lastid = change
 
-if lastid and len(self.changeset) > 0:
-self.heads = [lastid]
+if lastid and len(changeset) > 0:
+heads = [lastid]
+
+return {
+'changeset': changeset,
+'files': files_map,
+'copies': copies_map,
+'heads': heads,
+'depotname': depotname,
+}
+
+def _parse_once(self, ui, path):
+d = self._parse(ui, path)
+self.changeset = d['changeset']
+self.heads = d['heads']
+self.files = d['files']
+self.copies = d['copies']
+self.depotname = d['depotname']
 
 def getheads(self):
 return self.heads
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org

[PATCH 4 of 4] convert: parse perforce data on-demand

2016-12-20 Thread David Soria Parra
# HG changeset patch
# User David Soria Parra 
# Date 1482254630 28800
#  Tue Dec 20 09:23:50 2016 -0800
# Node ID a047a142f151709f882361916617e762816db619
# Parent  77e1912e2e0817a96633568c400450a9566e7e33
convert: parse perforce data on-demand

We are using read-only attributes that parse the perforce data on
demand. We are reading the data only once whenever an attribute is
requested and use it throughout the import process. This is equivalent
to the previous behavior, but we are avoiding reading from perforce when
we initialize the object, but instead run it during the actual import
process, when the first attribute is requested (usually getheads(), see
`convertcmd.convert`).

diff --git a/hgext/convert/p4.py b/hgext/convert/p4.py
--- a/hgext/convert/p4.py
+++ b/hgext/convert/p4.py
@@ -56,13 +56,8 @@
 common.checktool('p4', abort=False)
 
 self.revmap = {}
-self.heads = []
-self.changeset = {}
-self.files = {}
-self.copies = {}
 self.encoding = self.ui.config('convert', 'p4.encoding',
default=convcmd.orig_encoding)
-self.depotname = {}   # mapping from local name to depot name
 self.re_type = re.compile(
 "([a-z]+)?(text|binary|symlink|apple|resource|unicode|utf\d+)"
 "(\+\w+)?$")
@@ -74,7 +69,6 @@
 if revs and len(revs) > 1:
 raise error.Abort(_("p4 source does not support specifying "
"multiple revisions"))
-self._parse_once(ui, path)
 
 def setrevmap(self, revmap):
 """Sets the parsed revmap dictionary.
@@ -240,13 +234,29 @@
 'depotname': depotname,
 }
 
-def _parse_once(self, ui, path):
-d = self._parse(ui, path)
-self.changeset = d['changeset']
-self.heads = d['heads']
-self.files = d['files']
-self.copies = d['copies']
-self.depotname = d['depotname']
+@util.propertycache
+def _parse_once(self):
+return self._parse(self.ui, self.path)
+
+@util.propertycache
+def copies(self):
+return self._parse_once['copies']
+
+@util.propertycache
+def files(self):
+return self._parse_once['files']
+
+@util.propertycache
+def changeset(self):
+return self._parse_once['changeset']
+
+@util.propertycache
+def heads(self):
+return self._parse_once['heads']
+
+@util.propertycache
+def depotname(self):
+return self._parse_once['depotname']
 
 def getheads(self):
 return self.heads
diff --git a/tests/test-convert-p4-filetypes.t 
b/tests/test-convert-p4-filetypes.t
--- a/tests/test-convert-p4-filetypes.t
+++ b/tests/test-convert-p4-filetypes.t
@@ -307,11 +307,11 @@
 convert
   $ hg convert -s p4 $DEPOTPATH dst
   initializing destination dst repository
+  scanning source...
   reading p4 views
   collecting p4 changelists
   1 initial
   2 keywords
-  scanning source...
   sorting...
   converting...
   1 initial
diff --git a/tests/test-convert-p4.t b/tests/test-convert-p4.t
--- a/tests/test-convert-p4.t
+++ b/tests/test-convert-p4.t
@@ -67,12 +67,12 @@
 convert
   $ hg convert -s p4 $DEPOTPATH dst
   initializing destination dst repository
+  scanning source...
   reading p4 views
   collecting p4 changelists
   1 initial
   2 change a
   3 change b/c
-  scanning source...
   sorting...
   converting...
   2 initial
@@ -98,13 +98,10 @@
 
 convert again
   $ hg convert -s p4 $DEPOTPATH dst
+  scanning source...
   reading p4 views
   collecting p4 changelists
-  1 initial
-  2 change a
-  3 change b/c
   4 change a b/c
-  scanning source...
   sorting...
   converting...
   0 change a b/c
@@ -130,14 +127,10 @@
 
 convert again
   $ hg convert -s p4 $DEPOTPATH dst
+  scanning source...
   reading p4 views
   collecting p4 changelists
-  1 initial
-  2 change a
-  3 change b/c
-  4 change a b/c
   5 add d e f
-  scanning source...
   sorting...
   converting...
   0 add d e f
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH RFC v8] scmutil: add a simple key-value file helper

2016-12-20 Thread Kostia Balytskyi


On 12/16/2016 6:45 PM, Augie Fackler wrote:
> On Fri, Dec 16, 2016 at 1:35 PM, Augie Fackler  wrote:
>>> scmutil: add a simple key-value file helper
>>>
>> At this point, I think I'd like to see obs-shelve too. Is there a
>> place I can do that?
> (Specifically: before we do a resend of this, I'd like to see the
> client, so a link to a pastebin or repo where I could see a client on
> this thread would be outstanding. THanks!)
Here's a pastebin of my shelve.py: http://pastebin.com/3CYmqf2J
Please note that I haven't worked on storing the actual shelved state in 
this file yet: that is a low-pri for me at the moment, but I want it to 
be available for when I have time.
See obsshelvefile on line 88. The use case in shelve is very primitive - 
I could just store the node in a text file and it would've been ok. But 
I wanted to have a potential for growth and a way to move states of 
other commands as well.

> ___
> 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] chgserver: move wrapchgui to runcommand

2016-12-20 Thread Jun Wu
Excerpts from Yuya Nishihara's message of 2016-12-20 23:29:17 +0900:
> On Tue, 20 Dec 2016 14:03:04 +, Jun Wu wrote:
> > Excerpts from Yuya Nishihara's message of 2016-12-20 21:47:23 +0900:
> > > BTW, is there any reason we have to delay the uisetup() call? I think we 
> > > can
> > > just set req.ui in place of req.uisetup:
> > > 
> > >   class chgui(uimod.ui):
> > >   ...
> > >   req = dispatch.request(ui=chgui.load())
> > 
> > It's useful if runcommand needs to wrap on top of the side effects of other
> > extensions (ex. pager). In my WIP patch, chgcmdserver.uisetup looks like:
> > 
> > def _uisetup(self, ui):
> > _wrapui(ui, self._csystem)
> > try:
> > pager = extensions.find('pager')
> > except KeyError:
> > pass
> > else:
> > if util.safehasattr(pager, '_runpager'):
> > extensions.wrapfunction(pager, '_runpager', self._runpager)
> > 
> > def _runpager(self, orig, ui, pagercmd):
> > self._csystem.write(pagercmd, type='pager')
> > while True:
> > cmd = self.client.readline()[:-1]
> > _log('pager subcommand: %s' % cmd)
> > if cmd == 'attachio':
> > self.attachio(ui)
> > elif cmd == '':
> > break
> > else:
> > raise error.Abort(_('unexpected command %s') % cmd)
> > 
> > _runpager is coupled with chgcmdserver.
> 
> Could it be implemented without req.uisetup() if we had ui.pager() function?
> 
> https://www.mercurial-scm.org/wiki/PagerInCorePlan 
> 
> I believe we'll need to refactor the pager handling to fix a couple of pager
> issues (e.g. issue5377.) So I'm not enthusiastic about this _runpager() 
> change.

I was aware of the pager refactoring. If we can figure out the final APIs,
and decouple the complex pager refactoring so the part needed by chg is
small, I can do that.

The pager API has 2 levels:

  - high-level (pagecmd): decide the command of the pager, call low-level
  - low-level (_runpager): accept a command and run it unconditionally

I think ui.pager() should be high-level, and chg only wants to replace the
low-level one.

Therefore a possible API is:

  - ui.pager() as the new high-level API which parses config and calls
low-level method.
  - ui._runpager(pagercmd) as the low-level API which will be implemented
differently by chg.

A possible approach is:

  1. Move pager._runpager to uimod.ui._runpager
  2. Override ui._runpager in chgui
  3. Move part of pagecmd to uimod.ui.pager (or startpager if we plan to
 have an endpager in the future)
  4. Revisit when to call ui.pager (complex)

1 and 2 are easy and related to chg. 3 does not block chg refactoring and is
simple enough so I could help by the way. 4 is a complex core part of the
pager plan but I'd like to avoid as it has nothing to do with chg.

+durin42 because of pager.

> > So uisetup is still necessary to wrap _runpager. The _wrapui change is
> > unnecessary if we use your proposal. In that case, both Patch 2 and 4 can be
> > dropped and Patch 1 and 3 are useful.
> 
> Yep, that's why I haven't pushed these patches yet.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH v2] push: add a message when pushing phases but not changes (issue4232)

2016-12-20 Thread Pierre-Yves David



On 12/07/2016 04:50 AM, Jeremy Wall (zaphar) wrote:

# HG changeset patch
# User Jeremy Wall (zaphar) 
# Date 1480542942 21600
#  Wed Nov 30 15:55:42 2016 -0600
# Node ID 6e1ad0fb4f792d01e75f18e41579e52bcceee198
# Parent  9e29d4e4e08b5996adda49cdd0b497d89e2b16ee
push: add a message when pushing phases but not changes (issue4232)


Thanks for looking into this, there is interesting bit in that proposal 
and it certainly bootstrap the discussion in a meaningful way.


First let me inflict you some generic tough about the BC concerns:
--

One of main design idea around phases (back in 2011) was that user who 
doesn't need to know about them should not know about them. Typically, 
user using Mercurial before phase and who have not opted in any new 
feature since then should not see them (With the obvious exception of 
when phases prevent them to rewrite exchanged history).


This principle can be extended to the current work on the message, 
people doing standard interaction with publishing server are not moving 
phases outside of the changeset they are pushing and pulling, so they 
don't need extra message and it is better to keep the output undisturbed 
in this case.


On the other hand, when user start to move toward less "classical" usage 
that explicitly involved phases (like interacting with a non-publishing 
server) it seems all right to introduce some output changes. Such logic 
around output (and behavior) changes also apply to things as our current 
"topic" experiment, people opt-in in the new feature can be exposed to 
message and behavior change.



The good new, is that your current change seems mostly in line with this 
principle as the new message will only be included only if we have phase 
changes without changesets exchange, something rare if you stick to the 
default publishing server setup.



About your new output
-

It is usually a good practice to include sample of your new output in 
the the changeset description.


Scanning through your test change I seems to pick two possibles new output.

> +  sending phase public for b740e3e5c05d
> +  sending phase draft for 967b449fbc94
> +  updated 2 phase boundaries

It is unclear to me what triggers each of them, so I went and looked at 
the code change in more details. I can't find trace of the first two 
anywhere. Are these stalled test change your forgot to update?


I'm not too excited about the new message "updated 2 phase boundaries". 
I'm afraid "phase boundary" is a term a bit too confusing for user. In 
addition, it is a bit too vagues, "3 phase boundary" can mean 3 
changesets changed phase as much as a couple thousand.


I've not though too much about it yet, but I would lean more toward 
something like:


42 changesets moved to public phases,

We could also try to leverage the experimental 'journal' extension to 
give the option to peek into more data about the phase changes.


About your implementation
-

I see a couple of issue with the implementation of your proposal,

First, the code introduced to handle "phase change report" live in a 
function (_pushcheckoutgoing) that live in the "pushing changesets" 
logic. So that seems wrong and we needs that phase related code in a 
more phases related code path (or generic one).


Second, your phase movement message is only triggered if there is no 
changeset pushed. We should also mention phases move for changeset that 
are not included in the push. We need logic outside of a 'if not 
outgoing.missing:' section to compute which changesets we move phase for 
and how they overlap with the outgoing changesets.


About my interest in this issue
---

I'm currently looking into the general issue of reporting more data 
about these date who currently move silently. This recently got in my 
todo-list for a paying customer (hooray). So I was planning to make 
progress on this over the coming handful of weeks.
If you want use to work together on the topic I'm very open to it. In 
all cases I will do my best to help something to happen on that topic.


Taking a step back: reporting more data in general
--

Your changeset focus on reporting phases change pushed to the server 
during a push. We have a whole set of related movement currently unreported:


- local phase movement on push,
- phase movement on pull,
- not phase data in incoming/outgoing

And we even more unreported data when you start taking things like 
obsolescence marker into account.


At that point, it is probably a good idea to take a step back and start 
a Plan page on the wiki to gather all things we want to report and thing 
about a unified rework of there reporting across commands. Let me know 
if you are interested in looking into that.




I've made a couple of extra comments inline the patch


diff -r 

Re: [PATCH 4 of 4] chgserver: move wrapchgui to runcommand

2016-12-20 Thread Yuya Nishihara
On Tue, 20 Dec 2016 14:03:04 +, Jun Wu wrote:
> Excerpts from Yuya Nishihara's message of 2016-12-20 21:47:23 +0900:
> > BTW, is there any reason we have to delay the uisetup() call? I think we can
> > just set req.ui in place of req.uisetup:
> > 
> >   class chgui(uimod.ui):
> >   ...
> >   req = dispatch.request(ui=chgui.load())
> 
> It's useful if runcommand needs to wrap on top of the side effects of other
> extensions (ex. pager). In my WIP patch, chgcmdserver.uisetup looks like:
> 
> def _uisetup(self, ui):
> _wrapui(ui, self._csystem)
> try:
> pager = extensions.find('pager')
> except KeyError:
> pass
> else:
> if util.safehasattr(pager, '_runpager'):
> extensions.wrapfunction(pager, '_runpager', self._runpager)
> 
> def _runpager(self, orig, ui, pagercmd):
> self._csystem.write(pagercmd, type='pager')
> while True:
> cmd = self.client.readline()[:-1]
> _log('pager subcommand: %s' % cmd)
> if cmd == 'attachio':
> self.attachio(ui)
> elif cmd == '':
> break
> else:
> raise error.Abort(_('unexpected command %s') % cmd)
> 
> _runpager is coupled with chgcmdserver.

Could it be implemented without req.uisetup() if we had ui.pager() function?

https://www.mercurial-scm.org/wiki/PagerInCorePlan

I believe we'll need to refactor the pager handling to fix a couple of pager
issues (e.g. issue5377.) So I'm not enthusiastic about this _runpager() change.

> So uisetup is still necessary to wrap _runpager. The _wrapui change is
> unnecessary if we use your proposal. In that case, both Patch 2 and 4 can be
> dropped and Patch 1 and 3 are useful.

Yep, that's why I haven't pushed these patches yet.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 8 of 9] py3: replace sys.platform with pycompat.sysplatform (part 1 of 2)

2016-12-20 Thread Pulkit Goyal
# HG changeset patch
# User Pulkit Goyal <7895pul...@gmail.com>
# Date 1482093924 -19800
#  Mon Dec 19 02:15:24 2016 +0530
# Node ID 068e2e6fe20712a2624c5b2050aedeb68ab619c2
# Parent  173684dd16962b352416332ee66bd1880497aa16
py3: replace sys.platform with pycompat.sysplatform (part 1 of 2)

sys.platform returns unicode on python 3 world. Our code base has most of the
things bytes because of the transformer. So we have a bytes version of this as
pycompat.sysplatform. This series of 2 patches replaces occurences of
sys.platform with pycompat.sysplatform.

diff -r 173684dd1696 -r 068e2e6fe207 mercurial/commands.py
--- a/mercurial/commands.py Mon Dec 19 00:28:12 2016 +0530
+++ b/mercurial/commands.py Mon Dec 19 02:15:24 2016 +0530
@@ -3891,15 +3891,15 @@
 
 keep = opts.get('system') or []
 if len(keep) == 0:
-if sys.platform.startswith('win'):
+if pycompat.sysplatform.startswith('win'):
 keep.append('windows')
-elif sys.platform == 'OpenVMS':
+elif pycompat.sysplatform == 'OpenVMS':
 keep.append('vms')
-elif sys.platform == 'plan9':
+elif pycompat.sysplatform == 'plan9':
 keep.append('plan9')
 else:
 keep.append('unix')
-keep.append(sys.platform.lower())
+keep.append(pycompat.sysplatform.lower())
 if ui.verbose:
 keep.append('verbose')
 
diff -r 173684dd1696 -r 068e2e6fe207 mercurial/posix.py
--- a/mercurial/posix.pyMon Dec 19 00:28:12 2016 +0530
+++ b/mercurial/posix.pyMon Dec 19 02:15:24 2016 +0530
@@ -303,7 +303,7 @@
 # fallback normcase function for non-ASCII strings
 normcasefallback = normcase
 
-if sys.platform == 'darwin':
+if pycompat.sysplatform == 'darwin':
 
 def normcase(path):
 '''
@@ -354,7 +354,7 @@
 # drop HFS+ ignored characters
 return encoding.hfsignoreclean(enc)
 
-if sys.platform == 'cygwin':
+if pycompat.sysplatform == 'cygwin':
 # workaround for cygwin, in which mount point part of path is
 # treated as case sensitive, even though underlying NTFS is case
 # insensitive.
@@ -447,7 +447,7 @@
 If command is a basename then PATH is searched for command.
 PATH isn't searched if command is an absolute or relative path.
 If command isn't found None is returned.'''
-if sys.platform == 'OpenVMS':
+if pycompat.sysplatform == 'OpenVMS':
 return command
 
 def findexisting(executable):
@@ -459,7 +459,7 @@
 if pycompat.ossep in command:
 return findexisting(command)
 
-if sys.platform == 'plan9':
+if pycompat.sysplatform == 'plan9':
 return findexisting(os.path.join('/bin', command))
 
 for path in encoding.environ.get('PATH', '').split(pycompat.ospathsep):
diff -r 173684dd1696 -r 068e2e6fe207 mercurial/scmposix.py
--- a/mercurial/scmposix.py Mon Dec 19 00:28:12 2016 +0530
+++ b/mercurial/scmposix.py Mon Dec 19 02:15:24 2016 +0530
@@ -25,7 +25,7 @@
 
 def systemrcpath():
 path = []
-if sys.platform == 'plan9':
+if pycompat.sysplatform == 'plan9':
 root = 'lib/mercurial'
 else:
 root = 'etc/mercurial'
@@ -38,7 +38,7 @@
 return path
 
 def userrcpath():
-if sys.platform == 'plan9':
+if pycompat.sysplatform == 'plan9':
 return [encoding.environ['home'] + '/lib/hgrc']
 else:
 return [os.path.expanduser('~/.hgrc')]
diff -r 173684dd1696 -r 068e2e6fe207 mercurial/sslutil.py
--- a/mercurial/sslutil.py  Mon Dec 19 00:28:12 2016 +0530
+++ b/mercurial/sslutil.py  Mon Dec 19 02:15:24 2016 +0530
@@ -668,7 +668,8 @@
   for using system certificate store CAs in addition to the provided
   cacerts file
 """
-if sys.platform != 'darwin' or util.mainfrozen() or not sys.executable:
+if (pycompat.sysplatform != 'darwin' or
+util.mainfrozen() or not sys.executable):
 return False
 exe = os.path.realpath(sys.executable).lower()
 return (exe.startswith('/usr/bin/python') or
@@ -725,7 +726,7 @@
 
 # The Apple OpenSSL trick isn't available to us. If Python isn't able to
 # load system certs, we're out of luck.
-if sys.platform == 'darwin':
+if pycompat.sysplatform == 'darwin':
 # FUTURE Consider looking for Homebrew or MacPorts installed certs
 # files. Also consider exporting the keychain certs to a file during
 # Mercurial install.
diff -r 173684dd1696 -r 068e2e6fe207 mercurial/ui.py
--- a/mercurial/ui.py   Mon Dec 19 00:28:12 2016 +0530
+++ b/mercurial/ui.py   Mon Dec 19 02:15:24 2016 +0530
@@ -1085,7 +1085,7 @@
 
 def geteditor(self):
 '''return editor to use'''
-if sys.platform == 'plan9':
+if pycompat.sysplatform == 'plan9':
 # vi is the MIPS instruction simulator on Plan 9. We
 # instead default to E to plumb commit messages to
 # avoid confusion.
___

[PATCH 6 of 9] py3: replace os.name with pycompat.osname (part 1 of 2)

2016-12-20 Thread Pulkit Goyal
# HG changeset patch
# User Pulkit Goyal <7895pul...@gmail.com>
# Date 1482086812 -19800
#  Mon Dec 19 00:16:52 2016 +0530
# Node ID e39ac3774a1c6703231bb5511ce082c50726b2ca
# Parent  6dbdae9bb9c6e5a038a2e9c9676fdd6663d235eb
py3: replace os.name with pycompat.osname (part 1 of 2)

os.name returns unicodes on py3 and we have pycompat.osname which returns
bytes. This series of 2 patches will change every ocurrence of os.name with
pycompat.osname.

diff -r 6dbdae9bb9c6 -r e39ac3774a1c mercurial/hgweb/server.py
--- a/mercurial/hgweb/server.py Sun Dec 18 02:08:59 2016 +0530
+++ b/mercurial/hgweb/server.py Mon Dec 19 00:16:52 2016 +0530
@@ -18,6 +18,7 @@
 
 from .. import (
 error,
+pycompat,
 util,
 )
 
@@ -266,7 +267,7 @@
 class MercurialHTTPServer(_mixin, httpservermod.httpserver, object):
 
 # SO_REUSEADDR has broken semantics on windows
-if os.name == 'nt':
+if pycompat.osname == 'nt':
 allow_reuse_address = 0
 
 def __init__(self, ui, app, addr, handler, **kwargs):
diff -r 6dbdae9bb9c6 -r e39ac3774a1c mercurial/i18n.py
--- a/mercurial/i18n.py Sun Dec 18 02:08:59 2016 +0530
+++ b/mercurial/i18n.py Mon Dec 19 00:16:52 2016 +0530
@@ -29,7 +29,7 @@
 unicode = str
 
 _languages = None
-if (os.name == 'nt'
+if (pycompat.osname == 'nt'
 and 'LANGUAGE' not in encoding.environ
 and 'LC_ALL' not in encoding.environ
 and 'LC_MESSAGES' not in encoding.environ
diff -r 6dbdae9bb9c6 -r e39ac3774a1c mercurial/pure/osutil.py
--- a/mercurial/pure/osutil.py  Sun Dec 18 02:08:59 2016 +0530
+++ b/mercurial/pure/osutil.py  Mon Dec 19 00:16:52 2016 +0530
@@ -159,7 +159,7 @@
 else:
 listdir = listdirpure
 
-if os.name != 'nt':
+if pycompat.osname != 'nt':
 posixfile = open
 
 _SCM_RIGHTS = 0x01
diff -r 6dbdae9bb9c6 -r e39ac3774a1c mercurial/scmutil.py
--- a/mercurial/scmutil.py  Sun Dec 18 02:08:59 2016 +0530
+++ b/mercurial/scmutil.py  Mon Dec 19 00:16:52 2016 +0530
@@ -34,7 +34,7 @@
 util,
 )
 
-if os.name == 'nt':
+if pycompat.osname == 'nt':
 from . import scmwindows as scmplatform
 else:
 from . import scmposix as scmplatform
@@ -281,7 +281,7 @@
 val = ui.config('ui', 'portablefilenames', 'warn')
 lval = val.lower()
 bval = util.parsebool(val)
-abort = os.name == 'nt' or lval == 'abort'
+abort = pycompat.osname == 'nt' or lval == 'abort'
 warn = bval or lval == 'warn'
 if bval is None and not (warn or abort or lval == 'ignore'):
 raise error.ConfigError(
@@ -1461,7 +1461,7 @@
 
 # Only Windows/NTFS has slow file closing. So only enable by default
 # on that platform. But allow to be enabled elsewhere for testing.
-defaultenabled = os.name == 'nt'
+defaultenabled = pycompat.osname == 'nt'
 enabled = ui.configbool('worker', 'backgroundclose', defaultenabled)
 
 if not enabled:
diff -r 6dbdae9bb9c6 -r e39ac3774a1c mercurial/sslutil.py
--- a/mercurial/sslutil.py  Sun Dec 18 02:08:59 2016 +0530
+++ b/mercurial/sslutil.py  Mon Dec 19 00:16:52 2016 +0530
@@ -18,6 +18,7 @@
 from .i18n import _
 from . import (
 error,
+pycompat,
 util,
 )
 
@@ -706,7 +707,7 @@
 # because we'll get a certificate verification error later and the lack
 # of loaded CA certificates will be the reason why.
 # Assertion: this code is only called if certificates are being verified.
-if os.name == 'nt':
+if pycompat.osname == 'nt':
 if not _canloaddefaultcerts:
 ui.warn(_('(unable to load Windows CA certificates; see '
   'https://mercurial-scm.org/wiki/SecureConnections for '
@@ -737,7 +738,7 @@
 # / is writable on Windows. Out of an abundance of caution make sure
 # we're not on Windows because paths from _systemcacerts could be installed
 # by non-admin users.
-assert os.name != 'nt'
+assert pycompat.osname != 'nt'
 
 # Try to find CA certificates in well-known locations. We print a warning
 # when using a found file because we don't want too much silent magic
diff -r 6dbdae9bb9c6 -r e39ac3774a1c mercurial/subrepo.py
--- a/mercurial/subrepo.py  Sun Dec 18 02:08:59 2016 +0530
+++ b/mercurial/subrepo.py  Mon Dec 19 00:16:52 2016 +0530
@@ -1313,7 +1313,7 @@
 notfoundhint = _("check git is installed and in your PATH")
 if e.errno != errno.ENOENT:
 raise error.Abort(genericerror % (self._path, e.strerror))
-elif os.name == 'nt':
+elif pycompat.osname == 'nt':
 try:
 self._gitexecutable = 'git.cmd'
 out, err = self._gitnodir(['--version'])
diff -r 6dbdae9bb9c6 -r e39ac3774a1c mercurial/util.py
--- a/mercurial/util.py Sun Dec 18 02:08:59 2016 +0530
+++ b/mercurial/util.py Mon Dec 19 00:16:52 2016 +0530
@@ -63,7 +63,7 @@
 urlreq = pycompat.urlreq
 xmlrpclib = pycompat.xmlrpclib
 
-if os.name == 'nt':
+if pycompat.osname == 'nt':
 from . import windows as 

[PATCH 9 of 9] py3: replace sys.platform with pycompat.sysplatform (part 2 of 2)

2016-12-20 Thread Pulkit Goyal
# HG changeset patch
# User Pulkit Goyal <7895pul...@gmail.com>
# Date 1482094601 -19800
#  Mon Dec 19 02:26:41 2016 +0530
# Node ID e0752031ef003151141020f68a2a902080db157b
# Parent  068e2e6fe20712a2624c5b2050aedeb68ab619c2
py3: replace sys.platform with pycompat.sysplatform (part 2 of 2)

diff -r 068e2e6fe207 -r e0752031ef00 hgext/win32mbcs.py
--- a/hgext/win32mbcs.pyMon Dec 19 02:15:24 2016 +0530
+++ b/hgext/win32mbcs.pyMon Dec 19 02:26:41 2016 +0530
@@ -169,7 +169,7 @@
 def extsetup(ui):
 # TODO: decide use of config section for this extension
 if ((not os.path.supports_unicode_filenames) and
-(sys.platform != 'cygwin')):
+(pycompat.sysplatform != 'cygwin')):
 ui.warn(_("[win32mbcs] cannot activate on this platform.\n"))
 return
 # determine encoding for filename
diff -r 068e2e6fe207 -r e0752031ef00 mercurial/posix.py
--- a/mercurial/posix.pyMon Dec 19 02:15:24 2016 +0530
+++ b/mercurial/posix.pyMon Dec 19 02:26:41 2016 +0530
@@ -80,7 +80,7 @@
 def parsepatchoutput(output_line):
 """parses the output produced by patch and returns the filename"""
 pf = output_line[14:]
-if os.sys.platform == 'OpenVMS':
+if pycompat.sysplatform == 'OpenVMS':
 if pf[0] == '`':
 pf = pf[1:-1] # Remove the quotes
 else:
@@ -404,7 +404,7 @@
 
 _needsshellquote = None
 def shellquote(s):
-if os.sys.platform == 'OpenVMS':
+if pycompat.sysplatform == 'OpenVMS':
 return '"%s"' % s
 global _needsshellquote
 if _needsshellquote is None:
@@ -423,7 +423,7 @@
 
 def testpid(pid):
 '''return False if pid dead, True if running or not sure'''
-if os.sys.platform == 'OpenVMS':
+if pycompat.sysplatform == 'OpenVMS':
 return True
 try:
 os.kill(pid, 0)
diff -r 068e2e6fe207 -r e0752031ef00 mercurial/pure/osutil.py
--- a/mercurial/pure/osutil.py  Mon Dec 19 02:15:24 2016 +0530
+++ b/mercurial/pure/osutil.py  Mon Dec 19 02:26:41 2016 +0530
@@ -12,7 +12,6 @@
 import os
 import socket
 import stat as statmod
-import sys
 
 from . import (
 policy,
@@ -70,14 +69,14 @@
 return result
 
 ffi = None
-if modulepolicy not in policynocffi and sys.platform == 'darwin':
+if modulepolicy not in policynocffi and pycompat.sysplatform == 'darwin':
 try:
 from _osutil_cffi import ffi, lib
 except ImportError:
 if modulepolicy == 'cffi': # strict cffi import
 raise
 
-if sys.platform == 'darwin' and ffi is not None:
+if pycompat.sysplatform == 'darwin' and ffi is not None:
 listdir_batch_size = 4096
 # tweakable number, only affects performance, which chunks
 # of bytes do we get back from getattrlistbulk
@@ -165,7 +164,7 @@
 _SCM_RIGHTS = 0x01
 _socklen_t = ctypes.c_uint
 
-if sys.platform == 'linux2':
+if pycompat.sysplatform.startswith('linux'):
 # socket.h says "the type should be socklen_t but the definition of
 # the kernel is incompatible with this."
 _cmsg_len_t = ctypes.c_size_t
diff -r 068e2e6fe207 -r e0752031ef00 mercurial/util.py
--- a/mercurial/util.py Mon Dec 19 02:15:24 2016 +0530
+++ b/mercurial/util.py Mon Dec 19 02:26:41 2016 +0530
@@ -795,7 +795,7 @@
 cmd = cmd.replace('INFILE', inname)
 cmd = cmd.replace('OUTFILE', outname)
 code = os.system(cmd)
-if sys.platform == 'OpenVMS' and code & 1:
+if pycompat.sysplatform == 'OpenVMS' and code & 1:
 code = 0
 if code:
 raise Abort(_("command '%s' failed: %s") %
@@ -998,7 +998,7 @@
 return str(val)
 origcmd = cmd
 cmd = quotecommand(cmd)
-if sys.platform == 'plan9' and (sys.version_info[0] == 2
+if pycompat.sysplatform == 'plan9' and (sys.version_info[0] == 2
 and sys.version_info[1] < 7):
 # subprocess kludge to work around issues in half-baked Python
 # ports, notably bichued/python:
@@ -1020,7 +1020,7 @@
 out.write(line)
 proc.wait()
 rc = proc.returncode
-if sys.platform == 'OpenVMS' and rc & 1:
+if pycompat.sysplatform == 'OpenVMS' and rc & 1:
 rc = 0
 if rc and onerr:
 errmsg = '%s %s' % (os.path.basename(origcmd.split(None, 1)[0]),
@@ -1383,7 +1383,7 @@
 
 def gui():
 '''Are we running in a GUI?'''
-if sys.platform == 'darwin':
+if pycompat.sysplatform == 'darwin':
 if 'SSH_CONNECTION' in encoding.environ:
 # handle SSH access to a box where the user is logged in
 return False
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 4 of 9] py3: replace os.environ with encoding.environ (part 4 of 5)

2016-12-20 Thread Pulkit Goyal
# HG changeset patch
# User Pulkit Goyal <7895pul...@gmail.com>
# Date 1482006960 -19800
#  Sun Dec 18 02:06:00 2016 +0530
# Node ID fc020b58c3081d84af150e5ed700bc67b7616c2b
# Parent  9cea8eb14d9e7fbf9be2fa6a67c94e6832d57c11
py3: replace os.environ with encoding.environ (part 4 of 5)

diff -r 9cea8eb14d9e -r fc020b58c308 mercurial/scmwindows.py
--- a/mercurial/scmwindows.py   Sun Dec 18 01:54:36 2016 +0530
+++ b/mercurial/scmwindows.py   Sun Dec 18 02:06:00 2016 +0530
@@ -3,6 +3,7 @@
 import os
 
 from . import (
+encoding,
 osutil,
 pycompat,
 util,
@@ -48,7 +49,7 @@
 home = os.path.expanduser('~')
 path = [os.path.join(home, 'mercurial.ini'),
 os.path.join(home, '.hgrc')]
-userprofile = os.environ.get('USERPROFILE')
+userprofile = encoding.environ.get('USERPROFILE')
 if userprofile and userprofile != home:
 path.append(os.path.join(userprofile, 'mercurial.ini'))
 path.append(os.path.join(userprofile, '.hgrc'))
diff -r 9cea8eb14d9e -r fc020b58c308 mercurial/statprof.py
--- a/mercurial/statprof.py Sun Dec 18 01:54:36 2016 +0530
+++ b/mercurial/statprof.py Sun Dec 18 02:06:00 2016 +0530
@@ -117,6 +117,7 @@
 import time
 
 from . import (
+encoding,
 pycompat,
 )
 
@@ -324,7 +325,7 @@
 
 state.accumulate_time(clock())
 state.last_start_time = None
-statprofpath = os.environ.get('STATPROF_DEST')
+statprofpath = encoding.environ.get('STATPROF_DEST')
 if statprofpath:
 save_data(statprofpath)
 
@@ -680,7 +681,7 @@
 
 def write_to_flame(data, fp, scriptpath=None, outputfile=None, **kwargs):
 if scriptpath is None:
-scriptpath = os.environ['HOME'] + '/flamegraph.pl'
+scriptpath = encoding.environ['HOME'] + '/flamegraph.pl'
 if not os.path.exists(scriptpath):
 print("error: missing %s" % scriptpath, file=fp)
 print("get it here: https://github.com/brendangregg/FlameGraph;,
diff -r 9cea8eb14d9e -r fc020b58c308 mercurial/ui.py
--- a/mercurial/ui.py   Sun Dec 18 01:54:36 2016 +0530
+++ b/mercurial/ui.py   Sun Dec 18 02:06:00 2016 +0530
@@ -143,7 +143,7 @@
 self.fin = util.stdin
 
 # shared read-only environment
-self.environ = os.environ
+self.environ = encoding.environ
 
 self.httppasswordmgrdb = urlreq.httppasswordmgrwithdefaultrealm()
 
diff -r 9cea8eb14d9e -r fc020b58c308 mercurial/util.py
--- a/mercurial/util.py Sun Dec 18 01:54:36 2016 +0530
+++ b/mercurial/util.py Sun Dec 18 02:06:00 2016 +0530
@@ -948,14 +948,14 @@
 Defaults to $HG or 'hg' in the search path.
 """
 if _hgexecutable is None:
-hg = os.environ.get('HG')
+hg = encoding.environ.get('HG')
 mainmod = sys.modules['__main__']
 if hg:
 _sethgexecutable(hg)
 elif mainfrozen():
 if getattr(sys, 'frozen', None) == 'macosx_app':
 # Env variable set by py2app
-_sethgexecutable(os.environ['EXECUTABLEPATH'])
+_sethgexecutable(encoding.environ['EXECUTABLEPATH'])
 else:
 _sethgexecutable(sys.executable)
 elif os.path.basename(getattr(mainmod, '__file__', '')) == 'hg':
@@ -1006,7 +1006,7 @@
 os.chdir(cwd)
 rc = os.system(cmd)
 else:
-env = dict(os.environ)
+env = dict(encoding.environ)
 env.update((k, py2shell(v)) for k, v in environ.iteritems())
 env['HG'] = hgexecutable()
 if out is None or _isstdout(out):
@@ -1384,7 +1384,7 @@
 def gui():
 '''Are we running in a GUI?'''
 if sys.platform == 'darwin':
-if 'SSH_CONNECTION' in os.environ:
+if 'SSH_CONNECTION' in encoding.environ:
 # handle SSH access to a box where the user is logged in
 return False
 elif getattr(osutil, 'isgui', None):
@@ -1394,7 +1394,7 @@
 # pure build; use a safe default
 return True
 else:
-return os.name == "nt" or os.environ.get("DISPLAY")
+return os.name == "nt" or encoding.environ.get("DISPLAY")
 
 def mktempcopy(name, emptyok=False, createmode=None):
 """Create a temporary file with the same contents from name
@@ -2297,7 +2297,7 @@
 if mainfrozen():
 if getattr(sys, 'frozen', None) == 'macosx_app':
 # Env variable set by py2app
-return [os.environ['EXECUTABLEPATH']]
+return [encoding.environ['EXECUTABLEPATH']]
 else:
 return [sys.executable]
 return gethgcmd()
diff -r 9cea8eb14d9e -r fc020b58c308 mercurial/win32.py
--- a/mercurial/win32.pySun Dec 18 01:54:36 2016 +0530
+++ b/mercurial/win32.pySun Dec 18 02:06:00 2016 +0530
@@ -14,6 +14,8 @@
 import random
 import subprocess
 
+from . import encoding
+
 _kernel32 = ctypes.windll.kernel32
 _advapi32 = ctypes.windll.advapi32
 _user32 = ctypes.windll.user32
@@ -424,8 +426,8 @@
 pi = 

[PATCH 2 of 9] py3: replace os.environ with encoding.environ (part 2 of 5)

2016-12-20 Thread Pulkit Goyal
# HG changeset patch
# User Pulkit Goyal <7895pul...@gmail.com>
# Date 1482005799 -19800
#  Sun Dec 18 01:46:39 2016 +0530
# Node ID c1a8b0e2a088a8cd365f7aa6a3f5d609fc57a92f
# Parent  961ff24b8c2f9d71ff8f5d6539f760e78d88d07a
py3: replace os.environ with encoding.environ (part 2 of 5)

diff -r 961ff24b8c2f -r c1a8b0e2a088 mercurial/chgserver.py
--- a/mercurial/chgserver.pySun Dec 18 01:34:41 2016 +0530
+++ b/mercurial/chgserver.pySun Dec 18 01:46:39 2016 +0530
@@ -55,6 +55,7 @@
 from . import (
 cmdutil,
 commandserver,
+encoding,
 error,
 extensions,
 osutil,
@@ -102,7 +103,8 @@
 for section in _configsections:
 sectionitems.append(ui.configitems(section))
 sectionhash = _hashlist(sectionitems)
-envitems = [(k, v) for k, v in os.environ.iteritems() if _envre.match(k)]
+envitems = [(k, v) for k, v in encoding.environ.iteritems()\
+if _envre.match(k)]
 envhash = _hashlist(sorted(envitems))
 return sectionhash[:6] + envhash[:6]
 
@@ -177,7 +179,7 @@
 if not ui.formatted():
 return
 
-p = ui.config("pager", "pager", os.environ.get("PAGER"))
+p = ui.config("pager", "pager", encoding.environ.get("PAGER"))
 usepager = False
 always = util.parsebool(options['pager'])
 auto = options['pager'] == 'auto'
@@ -237,7 +239,7 @@
 if val is True:
 return '1'
 return str(val)
-env = os.environ.copy()
+env = encoding.environ.copy()
 if environ:
 env.update((k, py2shell(v)) for k, v in environ.iteritems())
 env['HG'] = util.hgexecutable()
@@ -515,8 +517,8 @@
 except ValueError:
 raise ValueError('unexpected value in setenv request')
 _log('setenv: %r\n' % sorted(newenv.keys()))
-os.environ.clear()
-os.environ.update(newenv)
+encoding.environ.clear()
+encoding.environ.update(newenv)
 
 capabilities = commandserver.server.capabilities.copy()
 capabilities.update({'attachio': attachio,
@@ -626,8 +628,8 @@
 def chgunixservice(ui, repo, opts):
 # CHGINTERNALMARK is temporarily set by chg client to detect if chg will
 # start another chg. drop it to avoid possible side effects.
-if 'CHGINTERNALMARK' in os.environ:
-del os.environ['CHGINTERNALMARK']
+if 'CHGINTERNALMARK' in encoding.environ:
+del encoding.environ['CHGINTERNALMARK']
 
 if repo:
 # one chgserver can serve multiple repos. drop repo information
diff -r 961ff24b8c2f -r c1a8b0e2a088 mercurial/sshserver.py
--- a/mercurial/sshserver.pySun Dec 18 01:34:41 2016 +0530
+++ b/mercurial/sshserver.pySun Dec 18 01:46:39 2016 +0530
@@ -8,11 +8,11 @@
 
 from __future__ import absolute_import
 
-import os
 import sys
 
 from .i18n import _
 from . import (
+encoding,
 error,
 hook,
 util,
@@ -131,5 +131,5 @@
 return cmd != ''
 
 def _client(self):
-client = os.environ.get('SSH_CLIENT', '').split(' ', 1)[0]
+client = encoding.environ.get('SSH_CLIENT', '').split(' ', 1)[0]
 return 'remote:ssh:' + client
diff -r 961ff24b8c2f -r c1a8b0e2a088 mercurial/subrepo.py
--- a/mercurial/subrepo.py  Sun Dec 18 01:34:41 2016 +0530
+++ b/mercurial/subrepo.py  Sun Dec 18 01:46:39 2016 +0530
@@ -24,6 +24,7 @@
 from . import (
 cmdutil,
 config,
+encoding,
 error,
 exchange,
 filemerge,
@@ -1102,7 +1103,7 @@
 path = self.wvfs.reljoin(self._ctx.repo().origroot,
  self._path, filename)
 cmd.append(path)
-env = dict(os.environ)
+env = dict(encoding.environ)
 # Avoid localized output, preserve current locale for everything else.
 lc_all = env.get('LC_ALL')
 if lc_all:
@@ -1398,7 +1399,7 @@
 """
 self.ui.debug('%s: git %s\n' % (self._relpath, ' '.join(commands)))
 if env is None:
-env = os.environ.copy()
+env = encoding.environ.copy()
 # disable localization for Git output (issue5176)
 env['LC_ALL'] = 'C'
 # fix for Git CVE-2015-7545
@@ -1633,7 +1634,7 @@
 if self._gitmissing():
 raise error.Abort(_("subrepo %s is missing") % self._relpath)
 cmd = ['commit', '-a', '-m', text]
-env = os.environ.copy()
+env = encoding.environ.copy()
 if user:
 cmd += ['--author', user]
 if date:
diff -r 961ff24b8c2f -r c1a8b0e2a088 mercurial/worker.py
--- a/mercurial/worker.py   Sun Dec 18 01:34:41 2016 +0530
+++ b/mercurial/worker.py   Sun Dec 18 01:46:39 2016 +0530
@@ -14,6 +14,7 @@
 
 from .i18n import _
 from . import (
+encoding,
 error,
 scmutil,
 util,
@@ -32,7 +33,7 @@
 
 # windows
 try:
-n = int(os.environ['NUMBER_OF_PROCESSORS'])
+n = int(encoding.environ['NUMBER_OF_PROCESSORS'])
 if n > 0:

[PATCH 5 of 9] py3: replace os.environ with encoding.environ (part 5 of 5)

2016-12-20 Thread Pulkit Goyal
# HG changeset patch
# User Pulkit Goyal <7895pul...@gmail.com>
# Date 1482007139 -19800
#  Sun Dec 18 02:08:59 2016 +0530
# Node ID 6dbdae9bb9c6e5a038a2e9c9676fdd6663d235eb
# Parent  fc020b58c3081d84af150e5ed700bc67b7616c2b
py3: replace os.environ with encoding.environ (part 5 of 5)

diff -r fc020b58c308 -r 6dbdae9bb9c6 hgext/color.py
--- a/hgext/color.pySun Dec 18 02:06:00 2016 +0530
+++ b/hgext/color.pySun Dec 18 02:08:59 2016 +0530
@@ -171,6 +171,7 @@
 cmdutil,
 commands,
 dispatch,
+encoding,
 extensions,
 subrepo,
 ui as uimod,
@@ -245,7 +246,8 @@
 if not always and not auto:
 return None
 
-formatted = always or (os.environ.get('TERM') != 'dumb' and ui.formatted())
+formatted = always or (encoding.environ.get('TERM') != 'dumb'\
+and ui.formatted())
 
 mode = ui.config('color', 'mode', 'auto')
 
@@ -256,7 +258,7 @@
 realmode = mode
 if mode == 'auto':
 if os.name == 'nt':
-term = os.environ.get('TERM')
+term = encoding.environ.get('TERM')
 # TERM won't be defined in a vanilla cmd.exe environment.
 
 # UNIX-like environments on Windows such as Cygwin and MSYS will
diff -r fc020b58c308 -r 6dbdae9bb9c6 hgext/convert/cvs.py
--- a/hgext/convert/cvs.py  Sun Dec 18 02:06:00 2016 +0530
+++ b/hgext/convert/cvs.py  Sun Dec 18 02:08:59 2016 +0530
@@ -189,7 +189,7 @@
 
 if conntype != "pserver":
 if conntype == "rsh":
-rsh = os.environ.get("CVS_RSH") or "ssh"
+rsh = encoding.environ.get("CVS_RSH") or "ssh"
 if user:
 cmd = [rsh, '-l', user, host] + cmd
 else:
diff -r fc020b58c308 -r 6dbdae9bb9c6 hgext/convert/cvsps.py
--- a/hgext/convert/cvsps.pySun Dec 18 02:06:00 2016 +0530
+++ b/hgext/convert/cvsps.pySun Dec 18 02:08:59 2016 +0530
@@ -11,6 +11,7 @@
 
 from mercurial.i18n import _
 from mercurial import (
+encoding,
 hook,
 pycompat,
 util,
@@ -147,7 +148,7 @@
 pass
 
 if not root:
-root = os.environ.get('CVSROOT', '')
+root = encoding.environ.get('CVSROOT', '')
 
 # read log cache if one exists
 oldlog = []
diff -r fc020b58c308 -r 6dbdae9bb9c6 hgext/logtoprocess.py
--- a/hgext/logtoprocess.py Sun Dec 18 02:06:00 2016 +0530
+++ b/hgext/logtoprocess.py Sun Dec 18 02:08:59 2016 +0530
@@ -40,6 +40,8 @@
 import subprocess
 import sys
 
+from mercurial import encoding
+
 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' 
for
 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
 # be specifying the version(s) of Mercurial they are tested with, or
@@ -117,7 +119,7 @@
 optpairs = (
 ('OPT_{0}'.format(key.upper()), str(value))
 for key, value in opts.iteritems())
-env = dict(itertools.chain(os.environ.items(),
+env = dict(itertools.chain(encoding.environ.items(),
msgpairs, optpairs),
EVENT=event, HGPID=str(os.getpid()))
 # Connect stdin to /dev/null to prevent child processes messing
diff -r fc020b58c308 -r 6dbdae9bb9c6 hgext/pager.py
--- a/hgext/pager.pySun Dec 18 02:06:00 2016 +0530
+++ b/hgext/pager.pySun Dec 18 02:08:59 2016 +0530
@@ -71,6 +71,7 @@
 cmdutil,
 commands,
 dispatch,
+encoding,
 extensions,
 util,
 )
@@ -123,7 +124,7 @@
 return
 
 def pagecmd(orig, ui, options, cmd, cmdfunc):
-p = ui.config("pager", "pager", os.environ.get("PAGER"))
+p = ui.config("pager", "pager", encoding.environ.get("PAGER"))
 usepager = False
 always = util.parsebool(options['pager'])
 auto = options['pager'] == 'auto'
diff -r fc020b58c308 -r 6dbdae9bb9c6 hgext/patchbomb.py
--- a/hgext/patchbomb.pySun Dec 18 02:06:00 2016 +0530
+++ b/hgext/patchbomb.pySun Dec 18 02:08:59 2016 +0530
@@ -75,6 +75,7 @@
 from mercurial import (
 cmdutil,
 commands,
+encoding,
 error,
 hg,
 mail,
@@ -693,8 +694,8 @@
 if opts.get('test'):
 ui.status(_('displaying '), subj, ' ...\n')
 ui.flush()
-if 'PAGER' in os.environ and not ui.plain():
-fp = util.popen(os.environ['PAGER'], 'w')
+if 'PAGER' in encoding.environ and not ui.plain():
+fp = util.popen(encoding.environ['PAGER'], 'w')
 else:
 fp = ui
 generator = emailmod.Generator.Generator(fp, mangle_from_=False)
diff -r fc020b58c308 -r 6dbdae9bb9c6 tests/test-check-config.t
--- a/tests/test-check-config.t Sun Dec 18 02:06:00 2016 +0530
+++ b/tests/test-check-config.t Sun Dec 18 02:08:59 2016 +0530
@@ -7,6 +7,3 @@
 
   $ hg files "set:(**.py or **.txt) - tests/**" | sed 's|\\|/|g' |
   >   python 

[PATCH 3 of 9] py3: replace os.environ with encoding.environ (part 3 of 5)

2016-12-20 Thread Pulkit Goyal
# HG changeset patch
# User Pulkit Goyal <7895pul...@gmail.com>
# Date 1482006276 -19800
#  Sun Dec 18 01:54:36 2016 +0530
# Node ID 9cea8eb14d9e7fbf9be2fa6a67c94e6832d57c11
# Parent  c1a8b0e2a088a8cd365f7aa6a3f5d609fc57a92f
py3: replace os.environ with encoding.environ (part 3 of 5)

diff -r c1a8b0e2a088 -r 9cea8eb14d9e mercurial/filemerge.py
--- a/mercurial/filemerge.pySun Dec 18 01:46:39 2016 +0530
+++ b/mercurial/filemerge.pySun Dec 18 01:54:36 2016 +0530
@@ -16,6 +16,7 @@
 from .node import nullid, short
 
 from . import (
+encoding,
 error,
 formatter,
 match,
@@ -165,7 +166,7 @@
 return (force, force)
 
 # HGMERGE takes next precedence
-hgmerge = os.environ.get("HGMERGE")
+hgmerge = encoding.environ.get("HGMERGE")
 if hgmerge:
 if changedelete and not supportscd(hgmerge):
 return ":prompt", None
diff -r c1a8b0e2a088 -r 9cea8eb14d9e mercurial/hgweb/common.py
--- a/mercurial/hgweb/common.py Sun Dec 18 01:46:39 2016 +0530
+++ b/mercurial/hgweb/common.py Sun Dec 18 01:54:36 2016 +0530
@@ -13,6 +13,7 @@
 import os
 
 from .. import (
+encoding,
 pycompat,
 util,
 )
@@ -191,7 +192,7 @@
 """
 return (config("web", "contact") or
 config("ui", "username") or
-os.environ.get("EMAIL") or "")
+encoding.environ.get("EMAIL") or "")
 
 def caching(web, req):
 tag = 'W/"%s"' % web.mtime
diff -r c1a8b0e2a088 -r 9cea8eb14d9e mercurial/hgweb/hgweb_mod.py
--- a/mercurial/hgweb/hgweb_mod.py  Sun Dec 18 01:46:39 2016 +0530
+++ b/mercurial/hgweb/hgweb_mod.py  Sun Dec 18 01:54:36 2016 +0530
@@ -286,7 +286,8 @@
 Modern servers should be using WSGI and should avoid this
 method, if possible.
 """
-if not os.environ.get('GATEWAY_INTERFACE', '').startswith("CGI/1."):
+if not encoding.environ.get('GATEWAY_INTERFACE',\
+'').startswith("CGI/1."):
 raise RuntimeError("This function is only intended to be "
"called while running as a CGI script.")
 wsgicgi.launch(self)
diff -r c1a8b0e2a088 -r 9cea8eb14d9e mercurial/hgweb/hgwebdir_mod.py
--- a/mercurial/hgweb/hgwebdir_mod.py   Sun Dec 18 01:46:39 2016 +0530
+++ b/mercurial/hgweb/hgwebdir_mod.py   Sun Dec 18 01:54:36 2016 +0530
@@ -186,7 +186,8 @@
 self.lastrefresh = time.time()
 
 def run(self):
-if not os.environ.get('GATEWAY_INTERFACE', '').startswith("CGI/1."):
+if not encoding.environ.get('GATEWAY_INTERFACE',\
+'').startswith("CGI/1."):
 raise RuntimeError("This function is only intended to be "
"called while running as a CGI script.")
 wsgicgi.launch(self)
diff -r c1a8b0e2a088 -r 9cea8eb14d9e mercurial/hgweb/wsgicgi.py
--- a/mercurial/hgweb/wsgicgi.pySun Dec 18 01:46:39 2016 +0530
+++ b/mercurial/hgweb/wsgicgi.pySun Dec 18 01:54:36 2016 +0530
@@ -10,9 +10,8 @@
 
 from __future__ import absolute_import
 
-import os
-
 from .. import (
+encoding,
 util,
 )
 
@@ -24,7 +23,7 @@
 util.setbinary(util.stdin)
 util.setbinary(util.stdout)
 
-environ = dict(os.environ.iteritems())
+environ = dict(encoding.environ.iteritems())
 environ.setdefault('PATH_INFO', '')
 if environ.get('SERVER_SOFTWARE', '').startswith('Microsoft-IIS'):
 # IIS includes script_name in PATH_INFO
diff -r c1a8b0e2a088 -r 9cea8eb14d9e mercurial/url.py
--- a/mercurial/url.py  Sun Dec 18 01:46:39 2016 +0530
+++ b/mercurial/url.py  Sun Dec 18 01:54:36 2016 +0530
@@ -15,6 +15,7 @@
 
 from .i18n import _
 from . import (
+encoding,
 error,
 httpconnection as httpconnectionmod,
 keepalive,
@@ -118,8 +119,8 @@
 if ui.config("http_proxy", "host"):
 for env in ["HTTP_PROXY", "http_proxy", "no_proxy"]:
 try:
-if env in os.environ:
-del os.environ[env]
+if env in encoding.environ:
+del encoding.environ[env]
 except OSError:
 pass
 
diff -r c1a8b0e2a088 -r 9cea8eb14d9e mercurial/windows.py
--- a/mercurial/windows.py  Sun Dec 18 01:46:39 2016 +0530
+++ b/mercurial/windows.py  Sun Dec 18 01:54:36 2016 +0530
@@ -177,7 +177,7 @@
 try:
 return sys.getwindowsversion()[3] == 1
 except AttributeError:
-return 'command' in os.environ.get('comspec', '')
+return 'command' in encoding.environ.get('comspec', '')
 
 def openhardlinks():
 return not _is_win_9x()
@@ -303,7 +303,7 @@
 PATH isn't searched if command is an absolute or relative path.
 An extension from PATHEXT is found and added if not present.
 If command isn't found None is returned.'''
-pathext = os.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD')
+pathext = encoding.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD')
 pathexts = 

[PATCH 1 of 9] py3: replace os.environ with encoding.environ (part 1 of 5)

2016-12-20 Thread Pulkit Goyal
# HG changeset patch
# User Pulkit Goyal <7895pul...@gmail.com>
# Date 1482005081 -19800
#  Sun Dec 18 01:34:41 2016 +0530
# Node ID 961ff24b8c2f9d71ff8f5d6539f760e78d88d07a
# Parent  ebca87566128e20c8f044f4e2d9aaec36efef625
py3: replace os.environ with encoding.environ (part 1 of 5)

os.environ is a dictionary which has string elements on Python 3. We have
encoding.environ which take care of all these things. This is the first patch
of 5 patch series which tend to replace the occurences of os.environ with
encoding.environ as using os.environ will result in unusual behaviour.

diff -r ebca87566128 -r 961ff24b8c2f mercurial/bookmarks.py
--- a/mercurial/bookmarks.pySun Dec 18 01:17:12 2016 +0530
+++ b/mercurial/bookmarks.pySun Dec 18 01:34:41 2016 +0530
@@ -8,7 +8,6 @@
 from __future__ import absolute_import
 
 import errno
-import os
 
 from .i18n import _
 from .node import (
@@ -31,7 +30,7 @@
 may need to tweak this behavior further.
 """
 bkfile = None
-if 'HG_PENDING' in os.environ:
+if 'HG_PENDING' in encoding.environ:
 try:
 bkfile = repo.vfs('bookmarks.pending')
 except IOError as inst:
diff -r ebca87566128 -r 961ff24b8c2f mercurial/dirstate.py
--- a/mercurial/dirstate.py Sun Dec 18 01:17:12 2016 +0530
+++ b/mercurial/dirstate.py Sun Dec 18 01:34:41 2016 +0530
@@ -67,7 +67,7 @@
 
 This returns '(fp, is_pending_opened)' tuple.
 '''
-if root == os.environ.get('HG_PENDING'):
+if root == encoding.environ.get('HG_PENDING'):
 try:
 return (vfs('%s.pending' % filename), True)
 except IOError as inst:
diff -r ebca87566128 -r 961ff24b8c2f mercurial/localrepo.py
--- a/mercurial/localrepo.pySun Dec 18 01:17:12 2016 +0530
+++ b/mercurial/localrepo.pySun Dec 18 01:34:41 2016 +0530
@@ -499,8 +499,8 @@
 @storecache('00changelog.i')
 def changelog(self):
 c = changelog.changelog(self.svfs)
-if 'HG_PENDING' in os.environ:
-p = os.environ['HG_PENDING']
+if 'HG_PENDING' in encoding.environ:
+p = encoding.environ['HG_PENDING']
 if p.startswith(self.root):
 c.readpending('00changelog.i.a')
 return c
@@ -1299,7 +1299,7 @@
 # the contents of parentenvvar are used by the underlying lock to
 # determine whether it can be inherited
 if parentenvvar is not None:
-parentlock = os.environ.get(parentenvvar)
+parentlock = encoding.environ.get(parentenvvar)
 try:
 l = lockmod.lock(vfs, lockname, 0, releasefn=releasefn,
  acquirefn=acquirefn, desc=desc,
diff -r ebca87566128 -r 961ff24b8c2f mercurial/phases.py
--- a/mercurial/phases.py   Sun Dec 18 01:17:12 2016 +0530
+++ b/mercurial/phases.py   Sun Dec 18 01:34:41 2016 +0530
@@ -103,7 +103,6 @@
 from __future__ import absolute_import
 
 import errno
-import os
 
 from .i18n import _
 from .node import (
@@ -114,6 +113,7 @@
 short,
 )
 from . import (
+encoding,
 error,
 )
 
@@ -137,7 +137,7 @@
 roots = [set() for i in allphases]
 try:
 f = None
-if 'HG_PENDING' in os.environ:
+if 'HG_PENDING' in encoding.environ:
 try:
 f = repo.svfs('phaseroots.pending')
 except IOError as inst:
diff -r ebca87566128 -r 961ff24b8c2f mercurial/posix.py
--- a/mercurial/posix.pySun Dec 18 01:17:12 2016 +0530
+++ b/mercurial/posix.pySun Dec 18 01:34:41 2016 +0530
@@ -462,7 +462,7 @@
 if sys.platform == 'plan9':
 return findexisting(os.path.join('/bin', command))
 
-for path in os.environ.get('PATH', '').split(pycompat.ospathsep):
+for path in encoding.environ.get('PATH', '').split(pycompat.ospathsep):
 executable = findexisting(os.path.join(path, command))
 if executable is not None:
 return executable
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 7 of 9] py3: replace os.name with pycompat.osname (part 2 of 2)

2016-12-20 Thread Pulkit Goyal
# HG changeset patch
# User Pulkit Goyal <7895pul...@gmail.com>
# Date 1482087492 -19800
#  Mon Dec 19 00:28:12 2016 +0530
# Node ID 173684dd16962b352416332ee66bd1880497aa16
# Parent  e39ac3774a1c6703231bb5511ce082c50726b2ca
py3: replace os.name with pycompat.osname (part 2 of 2)

diff -r e39ac3774a1c -r 173684dd1696 hgext/color.py
--- a/hgext/color.pyMon Dec 19 00:16:52 2016 +0530
+++ b/hgext/color.pyMon Dec 19 00:28:12 2016 +0530
@@ -164,8 +164,6 @@
 
 from __future__ import absolute_import
 
-import os
-
 from mercurial.i18n import _
 from mercurial import (
 cmdutil,
@@ -173,6 +171,7 @@
 dispatch,
 encoding,
 extensions,
+pycompat,
 subrepo,
 ui as uimod,
 util,
@@ -257,7 +256,7 @@
 
 realmode = mode
 if mode == 'auto':
-if os.name == 'nt':
+if pycompat.osname == 'nt':
 term = encoding.environ.get('TERM')
 # TERM won't be defined in a vanilla cmd.exe environment.
 
@@ -583,7 +582,7 @@
 ui.write(', '.join(ui.label(e, e) for e in effects.split()))
 ui.write('\n')
 
-if os.name != 'nt':
+if pycompat.osname != 'nt':
 w32effects = None
 else:
 import ctypes
diff -r e39ac3774a1c -r 173684dd1696 hgext/convert/subversion.py
--- a/hgext/convert/subversion.py   Mon Dec 19 00:16:52 2016 +0530
+++ b/hgext/convert/subversion.py   Mon Dec 19 00:28:12 2016 +0530
@@ -103,7 +103,7 @@
 pass
 if os.path.isdir(path):
 path = os.path.normpath(os.path.abspath(path))
-if os.name == 'nt':
+if pycompat.osname == 'nt':
 path = '/' + util.normpath(path)
 # Module URL is later compared with the repository URL returned
 # by svn API, which is UTF-8.
@@ -254,8 +254,8 @@
 try:
 proto, path = url.split('://', 1)
 if proto == 'file':
-if (os.name == 'nt' and path[:1] == '/' and path[1:2].isalpha()
-and path[2:6].lower() == '%3a/'):
+if (pycompat.osname == 'nt' and path[:1] == '/'\
+and path[1:2].isalpha() and path[2:6].lower() == '%3a/'):
 path = path[:2] + ':/' + path[6:]
 path = urlreq.url2pathname(path)
 except ValueError:
diff -r e39ac3774a1c -r 173684dd1696 hgext/largefiles/lfutil.py
--- a/hgext/largefiles/lfutil.pyMon Dec 19 00:16:52 2016 +0530
+++ b/hgext/largefiles/lfutil.pyMon Dec 19 00:28:12 2016 +0530
@@ -23,6 +23,7 @@
 httpconnection,
 match as matchmod,
 node,
+pycompat,
 scmutil,
 util,
 )
@@ -72,7 +73,7 @@
 path = ui.configpath(longname, 'usercache', None)
 if path:
 return path
-if os.name == 'nt':
+if pycompat.osname == 'nt':
 appdata = os.getenv('LOCALAPPDATA', os.getenv('APPDATA'))
 if appdata:
 return os.path.join(appdata, longname)
@@ -80,7 +81,7 @@
 home = os.getenv('HOME')
 if home:
 return os.path.join(home, 'Library', 'Caches', longname)
-elif os.name == 'posix':
+elif pycompat.osname == 'posix':
 path = os.getenv('XDG_CACHE_HOME')
 if path:
 return os.path.join(path, longname)
@@ -88,7 +89,8 @@
 if home:
 return os.path.join(home, '.cache', longname)
 else:
-raise error.Abort(_('unknown operating system: %s\n') % os.name)
+raise error.Abort(_('unknown operating system: %s\n') %\
+pycompat.osname)
 raise error.Abort(_('unknown %s usercache location') % longname)
 
 def inusercache(ui, hash):
diff -r e39ac3774a1c -r 173684dd1696 hgext/schemes.py
--- a/hgext/schemes.py  Mon Dec 19 00:16:52 2016 +0530
+++ b/hgext/schemes.py  Mon Dec 19 00:28:12 2016 +0530
@@ -50,6 +50,7 @@
 error,
 extensions,
 hg,
+pycompat,
 templater,
 util,
 )
@@ -114,7 +115,7 @@
 schemes.update(dict(ui.configitems('schemes')))
 t = templater.engine(lambda x: x)
 for scheme, url in schemes.items():
-if (os.name == 'nt' and len(scheme) == 1 and scheme.isalpha()
+if (pycompat.osname == 'nt' and len(scheme) == 1 and scheme.isalpha()
 and os.path.exists('%s:\\' % scheme)):
 raise error.Abort(_('custom scheme %s:// conflicts with drive '
'letter %s:\\\n') % (scheme, scheme.upper()))
diff -r e39ac3774a1c -r 173684dd1696 hgext/win32mbcs.py
--- a/hgext/win32mbcs.pyMon Dec 19 00:16:52 2016 +0530
+++ b/hgext/win32mbcs.pyMon Dec 19 00:28:12 2016 +0530
@@ -179,7 +179,7 @@
 if _encoding.lower() in problematic_encodings.split():
 for f in funcs.split():
 wrapname(f, wrapper)
-if os.name == 'nt':
+if pycompat.osname == 'nt':
 for f in winfuncs.split():
 wrapname(f, wrapper)
 wrapname("mercurial.osutil.listdir", wrapperforlistdir)
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org

Re: [PATCH 4 of 4] chgserver: move wrapchgui to runcommand

2016-12-20 Thread Jun Wu
Excerpts from Yuya Nishihara's message of 2016-12-20 21:47:23 +0900:
> On Mon, 19 Dec 2016 16:32:16 +, Jun Wu wrote:
> > Excerpts from Yuya Nishihara's message of 2016-12-19 23:46:26 +0900:
> > > On Sun, 18 Dec 2016 18:24:45 +, Jun Wu wrote:
> > > > The direction is to eventually lose control on "ui" used in runcommand, 
> > > > and
> > > > let dispatch construct a "ui" object on its own.
> > > 
> > > I got it.
> > > 
> > > > And we then use a special
> > > > "uisetup" which calls "wrapui" to modify the ui object created by 
> > > > dispatch.
> > > 
> > > Who will call this "uisetup"? dispatch or chgserver.runcommand?
> > 
> > The plan is to add a "uisetup" argument to dispatch.request:
> > 
> >   diff --git a/mercurial/dispatch.py b/mercurial/dispatch.py
> >   --- a/mercurial/dispatch.py
> >   +++ b/mercurial/dispatch.py
> >   @@ -49,5 +49,5 @@ from . import (
> >class request(object):
> >def __init__(self, args, ui=None, repo=None, fin=None, fout=None,
> >   - ferr=None):
> >   + ferr=None, uisetup=None):
> >self.args = args
> >self.ui = ui
> >   @@ -59,4 +59,7 @@ class request(object):
> >self.ferr = ferr
> >
> >   +# an extra uisetup unrelated to extensions, used by chg
> >   +self.uisetup = uisetup
> >   +
> >def run():
> >"run the command in sys.argv"
> >   @@ -660,4 +663,9 @@ def _dispatch(req):
> >extensions.loadall(lui)
> >exts = [ext for ext in extensions.extensions() if ext[0] not in 
> > _loaded]
> >   +
> >   +# An extra uisetup of the request, currently used by chg
> >   +if req.uisetup is not None:
> >   +req.uisetup(lui)
> >   +
> ># Propagate any changes to lui.__class__ by extensions
> >ui.__class__ = lui.__class__
> 
> Ah, that seems okay.
> 
> BTW, is there any reason we have to delay the uisetup() call? I think we can
> just set req.ui in place of req.uisetup:
> 
>   class chgui(uimod.ui):
>   ...
>   req = dispatch.request(ui=chgui.load())

It's useful if runcommand needs to wrap on top of the side effects of other
extensions (ex. pager). In my WIP patch, chgcmdserver.uisetup looks like:

def _uisetup(self, ui):
_wrapui(ui, self._csystem)
try:
pager = extensions.find('pager')
except KeyError:
pass
else:
if util.safehasattr(pager, '_runpager'):
extensions.wrapfunction(pager, '_runpager', self._runpager)

def _runpager(self, orig, ui, pagercmd):
self._csystem.write(pagercmd, type='pager')
while True:
cmd = self.client.readline()[:-1]
_log('pager subcommand: %s' % cmd)
if cmd == 'attachio':
self.attachio(ui)
elif cmd == '':
break
else:
raise error.Abort(_('unexpected command %s') % cmd)

_runpager is coupled with chgcmdserver.

So uisetup is still necessary to wrap _runpager. The _wrapui change is
unnecessary if we use your proposal. In that case, both Patch 2 and 4 can be
dropped and Patch 1 and 3 are useful.

> > > I'm slightly afraid of modifying ui class in the middle of the server 
> > > session
> > > since the ui might be used after runcommand(). That could lead  to a 
> > > subtle bug.
> > 
> > I agree. So patch 4 should be deferred until the uisetup work is done. Since
> > that depends on a lot of other things. Patch 4 should be dropped now.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH] bookmarks: introduce binary encoding

2016-12-20 Thread Stanislau Hlebik
Excerpts from Stanislau Hlebik's message of 2016-12-20 13:49:37 +:
> Excerpts from Pierre-Yves David's message of 2016-12-17 08:39:18 +0100:
> > 
> > On 12/09/2016 12:16 PM, Stanislau Hlebik wrote:
> > > # HG changeset patch
> > > # User Stanislau Hlebik 
> > > # Date 1481281951 28800
> > > #  Fri Dec 09 03:12:31 2016 -0800
> > > # Node ID 001ceadc2bc36699bdf816370899a27203bf1818
> > > # Parent  9e29d4e4e08b5996adda49cdd0b497d89e2b16ee
> > > bookmarks: introduce binary encoding
> > >
> > > Bookmarks binary encoding will be used for `bookmarks` bundle2 part.
> > > The format is: <4 bytes - bookmark size, big-endian>
> > ><1 byte - 0 if node is empty 1 otherwise><20 bytes node>
> > > ValueError maybe thrown if input is incorrect.
> > >
> > > diff --git a/mercurial/bookmarks.py b/mercurial/bookmarks.py
> > > --- a/mercurial/bookmarks.py
> > > +++ b/mercurial/bookmarks.py
> > > @@ -8,7 +8,9 @@
> > >  from __future__ import absolute_import
> > >
> > >  import errno
> > > +import io
> > >  import os
> > > +import struct
> > >
> > >  from .i18n import _
> > >  from .node import (
> > > @@ -23,6 +25,72 @@
> > >  util,
> > >  )
> > >
> > > +_NONEMPTYNODE = struct.pack('?', False)
> > > +_EMPTYNODE = struct.pack('?', True)
> > 
> > Our constant are still lower case ;-)
> > 
> > > +def _unpackbookmarksize(stream):
> > > +"""Returns 0 if stream is empty.
> > > +"""
> > > +
> > > +intstruct = struct.Struct('>i')
> > > +expectedsize = intstruct.size
> > > +encodedbookmarksize = stream.read(expectedsize)
> > > +if not encodedbookmarksize:
> > > +return 0
> > 
> > [small nits]
> > 
> > What does this "stream" empty case means?
> > 
> > If this is an error we should probably just error.
> > 
> > If this is an end condition, we could make that more explicit by 
> > returning None.
> >
> 
> It's an end condition, I'll change to None and update comment

Oh, and I won't be able to use changegroup.readexactly here because it
will throw exception if stream is empty

> 
> > > +if len(encodedbookmarksize) != expectedsize:
> > > +raise ValueError(
> > > +_('cannot decode bookmark size: '
> > > +  'expected size: %d, actual size: %d') %
> > > +(expectedsize, len(encodedbookmarksize)))
> > 
> > Check "changegroup.readexactly" it does this check for you.
> >
> 
> Thanks for the pointer. I noticed that it's used in couple of files
> already so it's not specific to changegroup. I think it makes sense to
> move it from changegroup.py to other file (maybe util.py?) What do you
> think?
> 
> > > +return intstruct.unpack(encodedbookmarksize)[0]
> > > +
> > > +def encodebookmarks(bookmarks):
> > > +"""Encodes bookmark to node mapping to the byte string.
> > > +
> > > +Format: <4 bytes - bookmark size>
> > > +<1 byte - 0 if node is empty 1 otherwise><20 bytes node>
> > > +Node may be 20 byte binary string or empty
> > > +"""
> > > +
> > > +intstruct = struct.Struct('>i')
> > > +for bookmark, node in sorted(bookmarks.iteritems()):
> > > +encodedbookmark = encoding.fromlocal(bookmark)
> > > +yield intstruct.pack(len(encodedbookmark))
> > > +yield encodedbookmark
> > > +if node:
> > > +if len(node) != 20:
> > > +raise ValueError(_('node must be 20 or bytes long'))
> > 
> > Is there case where the content  of the node can be wrong ? if not, I 
> > would probably just use an assert.
> 
> Will fix
> 
> > 
> > > +yield _NONEMPTYNODE
> > > +yield node
> > > +else:
> > > +yield _EMPTYNODE
> > > +
> > > +def decodebookmarks(buf):
> > > +"""Decodes buffer into bookmark to node mapping.
> > > +
> > > +Node is either 20 bytes or empty.
> > > +"""
> > > +
> > > +stream = io.BytesIO(buf)
> > > +bookmarks = {}
> > > +bookmarksize = _unpackbookmarksize(stream)
> > > +boolstruct = struct.Struct('?')
> > > +while bookmarksize:
> > > +bookmark = stream.read(bookmarksize)
> > > +if len(bookmark) != bookmarksize:
> > > +raise ValueError(
> > > +_('cannot decode bookmark: expected size: %d, '
> > > +'actual size: %d') % (bookmarksize, len(bookmark)))
> > 
> > CF previous comment about changegroup.readexactly.
> > 
> > > +bookmark = encoding.tolocal(bookmark)
> > > +packedemptynodeflag = stream.read(boolstruct.size)
> > > +emptynode = boolstruct.unpack(packedemptynodeflag)[0]
> > > +node = ''
> > > +if not emptynode:
> > > +node = stream.read(20)
> > 
> > lalala, changegroup.readexactly.
> > 
> > > +bookmarks[bookmark] = node
> > > +bookmarksize = _unpackbookmarksize(stream)
> > > +return bookmarks
> > > +
> > >  def _getbkfile(repo):
> > >  """Hook so that extensions that mess with the store can hook bm 
> > > storage.
> > 
> > Cheers,
> 

Re: [PATCH] bookmarks: introduce binary encoding

2016-12-20 Thread Stanislau Hlebik
Excerpts from Pierre-Yves David's message of 2016-12-17 08:39:18 +0100:
> 
> On 12/09/2016 12:16 PM, Stanislau Hlebik wrote:
> > # HG changeset patch
> > # User Stanislau Hlebik 
> > # Date 1481281951 28800
> > #  Fri Dec 09 03:12:31 2016 -0800
> > # Node ID 001ceadc2bc36699bdf816370899a27203bf1818
> > # Parent  9e29d4e4e08b5996adda49cdd0b497d89e2b16ee
> > bookmarks: introduce binary encoding
> >
> > Bookmarks binary encoding will be used for `bookmarks` bundle2 part.
> > The format is: <4 bytes - bookmark size, big-endian>
> ><1 byte - 0 if node is empty 1 otherwise><20 bytes node>
> > ValueError maybe thrown if input is incorrect.
> >
> > diff --git a/mercurial/bookmarks.py b/mercurial/bookmarks.py
> > --- a/mercurial/bookmarks.py
> > +++ b/mercurial/bookmarks.py
> > @@ -8,7 +8,9 @@
> >  from __future__ import absolute_import
> >
> >  import errno
> > +import io
> >  import os
> > +import struct
> >
> >  from .i18n import _
> >  from .node import (
> > @@ -23,6 +25,72 @@
> >  util,
> >  )
> >
> > +_NONEMPTYNODE = struct.pack('?', False)
> > +_EMPTYNODE = struct.pack('?', True)
> 
> Our constant are still lower case ;-)
> 
> > +def _unpackbookmarksize(stream):
> > +"""Returns 0 if stream is empty.
> > +"""
> > +
> > +intstruct = struct.Struct('>i')
> > +expectedsize = intstruct.size
> > +encodedbookmarksize = stream.read(expectedsize)
> > +if not encodedbookmarksize:
> > +return 0
> 
> [small nits]
> 
> What does this "stream" empty case means?
> 
> If this is an error we should probably just error.
> 
> If this is an end condition, we could make that more explicit by 
> returning None.
>

It's an end condition, I'll change to None and update comment

> > +if len(encodedbookmarksize) != expectedsize:
> > +raise ValueError(
> > +_('cannot decode bookmark size: '
> > +  'expected size: %d, actual size: %d') %
> > +(expectedsize, len(encodedbookmarksize)))
> 
> Check "changegroup.readexactly" it does this check for you.
>

Thanks for the pointer. I noticed that it's used in couple of files
already so it's not specific to changegroup. I think it makes sense to
move it from changegroup.py to other file (maybe util.py?) What do you
think?

> > +return intstruct.unpack(encodedbookmarksize)[0]
> > +
> > +def encodebookmarks(bookmarks):
> > +"""Encodes bookmark to node mapping to the byte string.
> > +
> > +Format: <4 bytes - bookmark size>
> > +<1 byte - 0 if node is empty 1 otherwise><20 bytes node>
> > +Node may be 20 byte binary string or empty
> > +"""
> > +
> > +intstruct = struct.Struct('>i')
> > +for bookmark, node in sorted(bookmarks.iteritems()):
> > +encodedbookmark = encoding.fromlocal(bookmark)
> > +yield intstruct.pack(len(encodedbookmark))
> > +yield encodedbookmark
> > +if node:
> > +if len(node) != 20:
> > +raise ValueError(_('node must be 20 or bytes long'))
> 
> Is there case where the content  of the node can be wrong ? if not, I 
> would probably just use an assert.

Will fix

> 
> > +yield _NONEMPTYNODE
> > +yield node
> > +else:
> > +yield _EMPTYNODE
> > +
> > +def decodebookmarks(buf):
> > +"""Decodes buffer into bookmark to node mapping.
> > +
> > +Node is either 20 bytes or empty.
> > +"""
> > +
> > +stream = io.BytesIO(buf)
> > +bookmarks = {}
> > +bookmarksize = _unpackbookmarksize(stream)
> > +boolstruct = struct.Struct('?')
> > +while bookmarksize:
> > +bookmark = stream.read(bookmarksize)
> > +if len(bookmark) != bookmarksize:
> > +raise ValueError(
> > +_('cannot decode bookmark: expected size: %d, '
> > +'actual size: %d') % (bookmarksize, len(bookmark)))
> 
> CF previous comment about changegroup.readexactly.
> 
> > +bookmark = encoding.tolocal(bookmark)
> > +packedemptynodeflag = stream.read(boolstruct.size)
> > +emptynode = boolstruct.unpack(packedemptynodeflag)[0]
> > +node = ''
> > +if not emptynode:
> > +node = stream.read(20)
> 
> lalala, changegroup.readexactly.
> 
> > +bookmarks[bookmark] = node
> > +bookmarksize = _unpackbookmarksize(stream)
> > +return bookmarks
> > +
> >  def _getbkfile(repo):
> >  """Hook so that extensions that mess with the store can hook bm 
> > storage.
> 
> Cheers,
> 
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 2 of 3 V2] chg: start server at a unique address

2016-12-20 Thread Yuya Nishihara
On Mon, 19 Dec 2016 22:19:24 +, Jun Wu wrote:
> # HG changeset patch
> # User Jun Wu 
> # Date 1482185389 0
> #  Mon Dec 19 22:09:49 2016 +
> # Node ID 24534dee38fe515f2c406e18153f623a074148b3
> # Parent  c543f9fd1a5b7657d4114e61e87a8d9bc32f7617
> # Available At https://bitbucket.org/quark-zju/hg-draft
> #  hg pull https://bitbucket.org/quark-zju/hg-draft -r 
> 24534dee38fe
> chg: start server at a unique address

Updated test-chg.t and queued the series, thanks.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 1 of 4] py3: make sure encoding.encoding is a bytes variable

2016-12-20 Thread Yuya Nishihara
On Sun, 18 Dec 2016 17:31:31 +0530, Pulkit Goyal wrote:
> # HG changeset patch
> # User Pulkit Goyal <7895pul...@gmail.com>
> # Date 1481999125 -19800
> #  Sat Dec 17 23:55:25 2016 +0530
> # Node ID af87471131e2fecc9e6edeb2a5c2e155953da4bb
> # Parent  1c8efe62f1f36fdf1a1bd6fcc5924cf557141d4a
> py3: make sure encoding.encoding is a bytes variable

Looks good. Queued the series, thanks.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH] match: adding non-recursive directory matching

2016-12-20 Thread Pierre-Yves David



On 12/20/2016 06:00 AM, Rodrigo Damazio wrote:

Unfortunately, while set would match the right files, because of the way
the code is structured, it provides no way to not try visiting the
directories inside the non-recursive match - the set needs to first
collect all the files in all subdirectories (match.py, _expandset) and
then filter that down to the desired ones. In plain hg repos, that's
just much slower - in the context of narrowhg, the repo will simply not
have the manifests for those subdirectories and trying to visit them
will crash.


Okay, so this seems like the current tools allow you to specify the 
right request but shortcoming of the -implementation- are preventing 
that request to work probably with narrowhg (and have performance impacts)


Did I got that right ?


The follow-up change to this one (which I haven't sent yet but is
written) is updating visitdir to allow non-recursiveness, which btw
makes something like "hg files -I rootglob:browser/*" about 4-5x faster
in the firefox repo.


And, If I read you right, the implementation of 'rootglob:' you provided 
in your patch have the same implementation issue, but you have another 
patch to improve the implementation to behave a way you can use (and is 
faster).


Did I got that right too ?


If I got these two pieces right, it looks like we could just apply the 
improvement to 'visitdir' to 'set:your/glob/*' and have your usecase 
filled while not jumping into UI changes. Would that work for you ?



On Fri, Dec 16, 2016 at 6:21 AM, Pierre-Yves David
>
wrote:



On 12/16/2016 02:19 AM, Augie Fackler wrote:


On Nov 24, 2016, at 10:28 AM, FUJIWARA Katsunori
> wrote:

Yes, "files:" was the original version of this patch
and the case I really
care about :) I changed it to rootglob after your
comments.
Which way would be preferred to move forward?


"files:" is "path:" family, and "rootglob:" is "glob:"
family. As we
concluded before, "path:" itself can't control recursion of
matching
well.

Therefore, I think that "files:" should be implemented if
needed,
regardless of implementing "rootglob:".

Of course, we need high point view of this area, at first :-)


BTW, it is a little ambiguous (at least, for me) that
"files:foo"
matches against both file "foo" and files just under directory
"foo". Name other than "files:" may resolve this ambiguity,
but I
don't have any better (and short enough) name :-<

 ==  === ===
 patternfoo  foo/bar foo/bar/baz
 ==  === ===
 path:fooo o o

 files:foo   o o x

 file:fooo x x
 dir:foo x o o
 ==  === ===


Scanning the plan page, I see that there’s a *lot* of work that
could be done and no consensus as yet, but that the only
immediate use case seems to be the rootfile/rootglob case. Is
there some path forward we could agree on that would unblock
those immediate needs for narrowhg and not make things harder in
the future?

Alternatively, would we be okay with a slight refactor of the
matcher so that narrowhg can introduce a custom filesonly:
matcher for the time being so we can keep making forward
progress there?  I don’t know the matcher code well enough to be
able to guess if this is a reasonable path so we can be unblocked.

(It’s very hard for to justify the amount of work implied by
reaching consensus on FileNamePatternsPlan and then executing
the entire thing when what we need is solvable today with a
sub-hour patch to existing code, thus my trying to find a
solution we can all live with.)


As far as I understand, Foozy finding shows that the feature
narrowhg needs is already there and nothing new is necessary.

You can add "set:" in front of your glob to make it non recursive in
all cases "set:your/directory/you/want/to/match/files/in/*"

If this does not fits your needs, this probably mean I got your
usecase wrong. In that case can you re-explain the issue you are
trying to solve here?


At the project level, it will make sense to clean up the Pattern
Matching at some point, and Foozy wiki work will help us to do that.

Cheers.

--
Pierre-Yves David




--
Pierre-Yves David
___
Mercurial-devel mailing list

Re: [PATCH 2 of 2] bookmarks: make bookmarks.comparebookmarks accept binary nodes (API)

2016-12-20 Thread Stanislau Hlebik
Excerpts from Pierre-Yves David's message of 2016-12-17 08:33:20 +0100:
> 
> On 12/09/2016 12:31 PM, Stanislau Hlebik wrote:
> > # HG changeset patch
> > # User Stanislau Hlebik 
> > # Date 1481282546 28800
> > #  Fri Dec 09 03:22:26 2016 -0800
> > # Node ID df861963a18c00d72362b415a77a62d2c18660bf
> > # Parent  08ab8f9d0abcbd1b2405ecb0a8670d212866af1f
> > bookmarks: make bookmarks.comparebookmarks accept binary nodes (API)
> >
> > Binary bookmark format should be used internally. It doesn't make sense to 
> > have
> > optional parameters `srchex` and `dsthex`. This patch removes them. It will
> > also be useful for `bookmarks` bundle2 part because unnecessary conversions
> > between hex and bin nodes will be avoided.
> 
> Great, I've put a second acceptance stamp on this changeset and it 
> should show as public shortly.
> 
> There is a couple thing in this patch that highlight the need for extra 
> work on that topic to remove all list key call from the client/server 
> exchange. I'm not sure if we should have something special to track 
> these, but see my comment below.
> 
> > diff --git a/mercurial/bookmarks.py b/mercurial/bookmarks.py
> > --- a/mercurial/bookmarks.py
> > +++ b/mercurial/bookmarks.py
> > @@ -391,8 +391,7 @@
> >  finally:
> >  lockmod.release(tr, l, w)
> >
> > -def comparebookmarks(repo, srcmarks, dstmarks,
> > - srchex=None, dsthex=None, targets=None):
> > +def comparebookmarks(repo, srcmarks, dstmarks, targets=None):
> >  '''Compare bookmarks between srcmarks and dstmarks
> >
> >  This returns tuple "(addsrc, adddst, advsrc, advdst, diverge,
> > @@ -415,19 +414,9 @@
> >  Changeset IDs of tuples in "addsrc", "adddst", "differ" or
> >   "invalid" list may be unknown for repo.
> >
> > -This function expects that "srcmarks" and "dstmarks" return
> > -changeset ID in 40 hexadecimal digit string for specified
> > -bookmark. If not so (e.g. bmstore "repo._bookmarks" returning
> > -binary value), "srchex" or "dsthex" should be specified to convert
> > -into such form.
> > -
> >  If "targets" is specified, only bookmarks listed in it are
> >  examined.
> >  '''
> > -if not srchex:
> > -srchex = lambda x: x
> > -if not dsthex:
> > -dsthex = lambda x: x
> >
> >  if targets:
> >  bset = set(targets)
> > @@ -449,14 +438,14 @@
> >  for b in sorted(bset):
> >  if b not in srcmarks:
> >  if b in dstmarks:
> > -adddst((b, None, dsthex(dstmarks[b])))
> > +adddst((b, None, dstmarks[b]))
> >  else:
> >  invalid((b, None, None))
> >  elif b not in dstmarks:
> > -addsrc((b, srchex(srcmarks[b]), None))
> > +addsrc((b, srcmarks[b], None))
> >  else:
> > -scid = srchex(srcmarks[b])
> > -dcid = dsthex(dstmarks[b])
> > +scid = srcmarks[b]
> > +dcid = dstmarks[b]
> >  if scid == dcid:
> >  same((b, scid, dcid))
> >  elif scid in repo and dcid in repo:
> > @@ -507,11 +496,17 @@
> >
> >  return None
> >
> > +def unhexlifybookmarks(marks):
> > +binremotemarks = {}
> > +for name, node in marks.items():
> > +binremotemarks[name] = bin(node)
> > +return binremotemarks
> > +
> 
> This function looked suspicious and was the start of my quest to know 
> more. My thinking seeing this was, "wait", if we moved internal to 
> binary why do we still needs it?
> 
> Keep scrolling for the result of that investigation.
> 
> >  def updatefromremote(ui, repo, remotemarks, path, trfunc, explicit=()):
> >  ui.debug("checking for updated bookmarks\n")
> >  localmarks = repo._bookmarks
> >  (addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same
> > - ) = comparebookmarks(repo, remotemarks, localmarks, dsthex=hex)
> > +) = comparebookmarks(repo, remotemarks, localmarks)
> >
> >  status = ui.status
> >  warn = ui.warn
> > @@ -522,15 +517,15 @@
> >  changed = []
> >  for b, scid, dcid in addsrc:
> >  if scid in repo: # add remote bookmarks for changes we already have
> > -changed.append((b, bin(scid), status,
> > +changed.append((b, scid, status,
> >  _("adding remote bookmark %s\n") % (b)))
> >  elif b in explicit:
> >  explicit.remove(b)
> >  ui.warn(_("remote bookmark %s points to locally missing %s\n")
> > -% (b, scid[:12]))
> > +% (b, hex(scid)[:12]))
> >
> >  for b, scid, dcid in advsrc:
> > -changed.append((b, bin(scid), status,
> > +changed.append((b, scid, status,
> >  _("updating bookmark %s\n") % (b)))
> >  # remove normal movement from explicit set
> >  explicit.difference_update(d[0] for d in changed)
> > @@ -538,13 +533,12 @@
> >  

[PATCH STABLE V2] demandimport: do not raise ImportError for unknown item in fromlist

2016-12-20 Thread Yuya Nishihara
# HG changeset patch
# User Yuya Nishihara 
# Date 1482155160 -32400
#  Mon Dec 19 22:46:00 2016 +0900
# Branch stable
# Node ID 09d785da911964c3282768438024a3b8e63dbd53
# Parent  7817df5585db1d87d3f6c7f496085c86d87e2e9a
demandimport: do not raise ImportError for unknown item in fromlist

This is the behavior of the default __import__() function, which doesn't
validate the existence of the fromlist items. Later on, the missing attribute
is detected while processing the import statement.

https://hg.python.org/cpython/file/v2.7.13/Python/import.c#l2575

The comtypes library relies on this (maybe) undocumented behavior, and we
got a bug report to TortoiseHg, sigh.

https://bitbucket.org/tortoisehg/thg/issues/4647/

The test added at 26a4e46af2bc verifies the behavior of the import statement,
so this patch only adds the test of __import__() function and works around
CPython/PyPy difference.

diff --git a/mercurial/demandimport.py b/mercurial/demandimport.py
--- a/mercurial/demandimport.py
+++ b/mercurial/demandimport.py
@@ -199,8 +199,11 @@ def _demandimport(name, globals=None, lo
 nonpkg = getattr(mod, '__path__', nothing) is nothing
 if symbol is nothing:
 if nonpkg:
-# do not try relative import, which would raise ValueError
-raise ImportError('cannot import name %s' % attr)
+# do not try relative import, which would raise ValueError,
+# and leave unknown attribute as the default __import__()
+# would do. the missing attribute will be detected later
+# while processing the import statement.
+return
 mn = '%s.%s' % (mod.__name__, attr)
 if mn in ignore:
 importfunc = _origimport
diff --git a/tests/test-demandimport.py b/tests/test-demandimport.py
--- a/tests/test-demandimport.py
+++ b/tests/test-demandimport.py
@@ -70,7 +70,16 @@ try:
 print('no demandmod should be created for attribute of non-package '
   'module:\ncontextlib.unknownattr =', f(unknownattr))
 except ImportError as inst:
-print('contextlib.unknownattr = ImportError: %s' % inst)
+print('contextlib.unknownattr = ImportError: %s'
+  % rsub(r"'", '', str(inst)))
+
+# Unlike the import statement, __import__() function should not raise
+# ImportError even if fromlist has an unknown item
+# (see Python/import.c:import_module_level() and ensure_fromlist())
+contextlibimp = __import__('contextlib', globals(), locals(), ['unknownattr'])
+print("__import__('contextlib', ..., ['unknownattr']) =", f(contextlibimp))
+print("hasattr(contextlibimp, 'unknownattr') =",
+  util.safehasattr(contextlibimp, 'unknownattr'))
 
 demandimport.disable()
 os.environ['HGDEMANDIMPORT'] = 'disable'
diff --git a/tests/test-demandimport.py.out b/tests/test-demandimport.py.out
--- a/tests/test-demandimport.py.out
+++ b/tests/test-demandimport.py.out
@@ -18,4 +18,6 @@ re.stderr = ', mod
 re = 
 contextlib = 
 contextlib.unknownattr = ImportError: cannot import name unknownattr
+__import__('contextlib', ..., ['unknownattr']) = 
+hasattr(contextlibimp, 'unknownattr') = False
 node = 
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel