Re: [PATCH 10 of 12 V3] bundle2: support a 'records' mode for the 'bookmarks' part

2018-03-22 Thread Durham Goode

Potential bug mentioned inline

On 11/20/17 8:52 AM, Boris Feld wrote:

# HG changeset patch
# User Boris Feld 
# Date 1508246776 -7200
#  Tue Oct 17 15:26:16 2017 +0200
# Node ID 7e610585998e3eff1d0498a6ce024350bb04fc23
# Parent  ab0fe3f91e7b9ed7bd508a9affa0b91128facf13
# EXP-Topic b2.bookmarks
# Available At 
https://urldefense.proofpoint.com/v2/url?u=https-3A__bitbucket.org_octobus_mercurial-2Ddevel_=DwIGaQ=5VD0RTtNlTh3ycd41b3MUw=nuarHzhP1wi1T9iURRCj1A=EyaOozG7mqYFV7-uTtZuxV3zYCWicwAVyqzUZmeNyFQ=6vm3KUlcZ0dR7UkeLmcuPjYetLgy50kNjAlNrys3aEI=
#  hg pull 
https://urldefense.proofpoint.com/v2/url?u=https-3A__bitbucket.org_octobus_mercurial-2Ddevel_=DwIGaQ=5VD0RTtNlTh3ycd41b3MUw=nuarHzhP1wi1T9iURRCj1A=EyaOozG7mqYFV7-uTtZuxV3zYCWicwAVyqzUZmeNyFQ=6vm3KUlcZ0dR7UkeLmcuPjYetLgy50kNjAlNrys3aEI=
 -r 7e610585998e
bundle2: support a 'records' mode for the 'bookmarks' part

In this mode, the bookmarks changes are record in the 'bundleoperation' records
instead of inflicted to the repository. This is necessary to use the part when
pulling.

diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -1898,40 +1898,55 @@ def handlepushkey(op, inpart):
 def handlebookmark(op, inpart):
 """transmit bookmark information

-The part contains binary encoded bookmark information. The bookmark
-information is applied as is to the unbundling repository. Make sure a
-'check:bookmarks' part is issued earlier to check for race condition in
-such update.
+The part contains binary encoded bookmark information.
+
+The exact behavior of this part can be controlled by the 'bookmarks' mode
+on the bundle operation.

-This behavior is suitable for pushing. Semantic adjustment will be needed
-for pull.
+When mode is 'apply' (the default) the bookmark information is applied as
+is to the unbundling repository. Make sure a 'check:bookmarks' part is
+issued earlier to check for push races in such update. This behavior is
+suitable for pushing.
+
+When mode is 'records', the information is recorded into the 'bookmarks'
+records of the bundle operation. This behavior is suitable for pulling.
 """
 changes = bookmarks.binarydecode(inpart)

-tr = op.gettransaction()
-bookstore = op.repo._bookmarks
+pushkeycompat = op.repo.ui.configbool('server', 'bookmarks-pushkey-compat')
+bookmarksmode = op.modes.get('bookmarks', 'apply')

-pushkeycompat = op.repo.ui.configbool('server', 'bookmarks-pushkey-compat')
-if pushkeycompat:
-allhooks = []
+if bookmarksmode == 'apply':
+tr = op.gettransaction()
+bookstore = op.repo._bookmarks
+if pushkeycompat:
+allhooks = []
+for book, node in changes:
+hookargs = tr.hookargs.copy()
+hookargs['pushkeycompat'] = '1'
+hookargs['namespace'] = 'bookmark'
+hookargs['key'] = book
+hookargs['old'] = nodemod.hex(bookstore.get(book, ''))
+hookargs['new'] = nodemod.hex(node if node is not None else '')
+allhooks.append(hookargs)
+
+for hookargs in allhooks:
+op.repo.hook('prepushkey', throw=True, **hookargs)
+
+bookstore.applychanges(op.repo, op.gettransaction(), changes)
+
+if pushkeycompat:
+def runhook():
+for hookargs in allhooks:
+op.repo.hook('prepushkey', **hookargs)


Should this be 'pushkey' instead of 'prepushkey'? Since it happens after 
the lock?  That would match localrepository.pushkey()'s behavior.



+op.repo._afterlock(runhook)
+
+elif bookmarksmode == 'records':
 for book, node in changes:
-hookargs = tr.hookargs.copy()
-hookargs['pushkeycompat'] = '1'
-hookargs['namespace'] = 'bookmark'
-hookargs['key'] = book
-hookargs['old'] = nodemod.hex(bookstore.get(book, ''))
-hookargs['new'] = nodemod.hex(node if node is not None else '')
-allhooks.append(hookargs)
-for hookargs in allhooks:
-op.repo.hook('prepushkey', throw=True, **hookargs)
-
-bookstore.applychanges(op.repo, tr, changes)
-
-if pushkeycompat:
-def runhook():
-for hookargs in allhooks:
-op.repo.hook('prepushkey', **hookargs)
-op.repo._afterlock(runhook)
+record = {'bookmark': book, 'node': node}
+op.records.add('bookmarks', record)
+else:
+raise error.ProgrammingError('unkown bookmark mode: %s' % 
bookmarksmode)

 @parthandler('phase-heads')
 def handlephases(op, inpart):
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org

D2108: infinitepush: drop the `--to` flag to push and use `-B` instead

2018-02-12 Thread durham (Durham Goode)
durham added a comment.


  > There are things which I am not sure whether to keep or not:
  > 
  > - the --bundle-store flag to push command
  
  This is useful for scripts or tools that want to upload a commit to the cloud 
without having to give it a name. For instance, you can use it to push a commit 
then send that commit hash to some build service which can checkout the commit 
without having to worry about a bookmark name.  But this could always be added 
back later, so it's probably fine to drop it if there's not an immediate need 
in Mozilla's use case.
  
  > - functionality to pull from bundlestore using hg pull
  
  Similar to the points above and below, this is useful for automation that 
already passes hashes around.  Not having to pass around bookmark names as well 
means it's easier for that automation to migrate to infinitepush.
  
  > - functionality to pull changesets from bundlestore if a changeset is not 
found locally on hg update
  
  This is a bit of magic that user's really like.  When combined with automatic 
backup pushes, it makes it feel like everyone is using the same repository.  
I'd highly recommend keeping this just for the eventual PR of saying "I can 
just hg commit, and my friend can do hg checkout HASH"
  
  > - logic around sql store
  
  Without this, would the server always store data in the filesystem?  The sql 
store seems like an important bit of making this robust in enterprise usage.
  
  > - interaction with the hoisting functionality of remotenames extension 
which is also being moved to core
  
  I'm not familiar with how infinitepush plays into hoisting, but I just wanted 
to make sure users never have to type 'remote/' or 'default/'.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D2108

To: pulkit, #hg-reviewers, indygreg
Cc: indygreg, durham, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D1814: rebase: add experimental.inmemory.nomergedriver to turn off IMM

2018-01-05 Thread durham (Durham Goode)
durham added inline comments.

INLINE COMMENTS

> rebase.py:812
> +elif (ui.config('experimental', 'mergedriver') and
> +  ui.configbool('rebase', 
> 'experimental.inmemory.nomergedriver')):
> +whynotimm = 'mergedriver enabled'

I think we probably want IMM disabled by default if merge drivers are 
specified.  If the merge-driver does IO during the preprocess step, it could 
cause problems in an IMM situation. So I don't think we can enable IMM by 
default in the merge-driver case until merge-driver enforces (or at least 
documents) that there should be no IO during preprocess.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D1814

To: phillco, #hg-reviewers
Cc: durham, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D1806: filemerge: fix backing up an in-memory file to a custom location

2018-01-04 Thread durham (Durham Goode)
durham accepted this revision.
durham added a comment.


  Accepting, since it seems more correct than before.
  
  Should we even be calling _makebackup in the case of an inmemory merge?  
Like, maybe the makebackup should be conditional based on if the source file 
context is actually a workingctx?

INLINE COMMENTS

> filemerge.py:623
> +Backups are only need to be written for the premerge, and not again 
> during
> +the main merge.
>  """

I know you're just documenting the parameter that already existed, but might be 
nice to explain why this is (if you happen to know why right now).

> filemerge.py:643
> +if premerge:
> +# Otherwise, write to wherever path the user specified the 
> backups
> +# should go. We still need to switch based on whether the source 
> is

s/wherever/whatever/

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D1806

To: phillco, #hg-reviewers, durham
Cc: durham, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D1564: worker: make windows workers daemons

2017-11-30 Thread durham (Durham Goode)
durham added inline comments.

INLINE COMMENTS

> worker.py:286
> +threads.remove(t)
> +except KeyboardInterrupt:
> +trykillworkers()

Why only do it on keyboard interrupt?  What if there's another exception?  If 
you did it for all exceptions, you could drop the trykillworkers() inside the 
loop, and just throw the exception up to here.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D1564

To: wlis, #hg-reviewers, ikostia
Cc: durham, ikostia, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D821: unamend: move fb extension unamend to core

2017-11-20 Thread durham (Durham Goode)
durham added inline comments.

INLINE COMMENTS

> pulkit wrote in uncommit.py:265
> Okay while trying to add this condition, I found we cannot refuse to unamend 
> a changeset on the basis of unamend_source, for e.g
> `a -amend-> b -unamend-> a' -amend-> c -unamend-> a''`
> 
> But if we refuse on basis on unamend_source, unamend `c` will refuse. We need 
> to be more smart here but when I think the other way around, I think it's 
> okay to unamend an unamend. I am open to suggestion and will go with what you 
> guys prefer is good.

I'd just let unamend undo an unamend.  Letting unamend toggle back and forth 
between the two states seems like it might grant the user more confidence in 
the command, even.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D821

To: pulkit, #hg-reviewers, durham
Cc: quark, durin42, ryanmce, singhsrb, durham, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D1358: remotenames: store journal entry for bookmarks if journal is loaded

2017-11-17 Thread durham (Durham Goode)
durham added a comment.


  There seems like two use cases for remotenames:  knowledge about the most 
recently seen location of each remote bookmark, and knowledge about where the 
remote bookmarks have been over time.  I think 99% of the benefit of 
remotenames comes from the first part.  Building a storage layer which suits 
both the journal and remotenames seems like massive scope creep to address the 
1% use case.  Even if we did unify the storage models, I still don't believe 
remotenames and the journal could share a common storage format because they 
don't have similar access patterns.  Remotenames is much more of a random 
access dict-like object, while the journal is much more of a sequential log.  
If I want to lookup the value of the latest remote master I don't want to deal 
with scanning some log of recent activity, and if I want to maintain a log of 
recent activity I don't want to build an index that allows for random access.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D1358

To: pulkit, #hg-reviewers
Cc: durham, quark, durin42, smf, dlax, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: Upstreaming Facebook extensions

2017-11-16 Thread Durham Goode



On 11/14/17 8:26 AM, Augie Fackler wrote:



On Nov 13, 2017, at 22:49, Matt Harbison  wrote:

On Mon, 13 Nov 2017 22:12:31 -0500, Jun Wu  wrote:


Excerpts from Matt Harbison's message of 2017-11-13 21:50:29 -0500:

For LFS, it has been used in a repo synced from p4 for about half a year.
It's mostly good except for lack of features (ex. support the Git-LFS SSH
authentication, support gc, etc.). It was actually written with some extra
care of upstream-friendliness. For example, I put remotefilelog integration
in remotefilelog instead of LFS intentionally.

Help is definitely welcomed!


OK, good to know.

So is upstreaming lfs in a single patch and marking it experimental a reasonable next 
step, or does this need to incubate in hg-experimental a bit more?  I didn't get it 
working outside of the tests (it said something about not having a common changegroup 
version), but it looks like there's some low hanging fruit like registering the config 
options, and tracking down some warning in url.py about an "unquoted realm" or 
similar.

I know BC doesn't apply to experimental things, but realistically, I assume 
things won't need to change other that maybe config stuff to add features?  I 
wouldn't mind using this sooner rather than later if the files can always be 
retrieved.


My sense of lfs is that it's a much better overall approach to largefiles 
handling, and that we should probably work to get it in core sooner rather than 
later as long as Facebook is ready to stabilize its development somewhat. When 
we do that, the commit message should go into detail why we think lfs is better 
than largefiles, and then probably also add a note to the largefiles help that 
we think lfs is the way of the future.

Does that sound like a starting place? Facebook folks, do you think it's a 
reasonable time to land lfs in core?


David should chime in here, because I haven't really been watching the 
LFS side of things.  I believe it's being used in production with a 
number of users at least, and I haven't heard of any lfs specific 
issues, so my guess is it's probably in good shape for upstreaming.

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


D1431: sshpeer: making the ssh error message configurable

2017-11-15 Thread durham (Durham Goode)
durham added a comment.


  I'd also update the commit summary with an example of what a better message 
might be.  Like "there was an ssh error, please see 
http://company/internalwiki/ssh.html;

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D1431

To: zuza, #hg-reviewers, durham, mitrandir
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D1431: sshpeer: making the ssh error message configurable

2017-11-15 Thread durham (Durham Goode)
durham requested changes to this revision.
durham added inline comments.
This revision now requires changes to proceed.

INLINE COMMENTS

> sshpeer.py:210
> +"errormessage",
> +_("no suitable response from remote hg"
>  

The standard Mercurial way to format this would be something like:

  msg = self.ui.config("ssh", "errormessage",
   _("no suitable response from remote hg"))
  self._abort(error.RepoError(msg))

> test-ssh.t:314
> +
> +
>  clone bookmarks

These lines seem unrelated to your change and therefore probably shouldn't have 
changed.  Usually this is caused by your editor trying to remove trailing 
whitespace from a file, then run-tests -i adding the missing new line back in.  
Can you undo these new line changes?  'hg uncommit tests/test-ssh.t && hg 
commit -i' could make it pretty straightforward.

> test-ssh.t:447
>> from mercurial import exchange, extensions
> -  > 
>> def wrappedpush(orig, repo, *args, **kwargs):

Same for this type of change

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D1431

To: zuza, #hg-reviewers, durham, mitrandir
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D1358: remotenames: store journal entry for bookmarks if journal is loaded

2017-11-15 Thread durham (Durham Goode)
durham added a comment.


  I'm a little confused here, in the same way Pulkit has expressed.  
remotenames has a couple parts related to storage: one is the storing of the 
remotenames themselves, and the other is tracking how they change over time.  
The remotename storage itself doesn't seem like it overlaps with journal or 
blackbox, as it's not a log.  The tracking of how they change over time seems 
to fit the journal exactly, which is a store for tracking how various 
references to commits (working copy parent, bookmarks, and now remotenames) 
change over time.
  
  So I guess I'm confused about what part of remotenames needs unification?  
They seem to either be completely orthogonal, or a complete match for an 
existing system.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D1358

To: pulkit, #hg-reviewers
Cc: durham, quark, durin42, smf, dlax, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D821: unamend: move fb extension unamend to core

2017-11-10 Thread durham (Durham Goode)
durham accepted this revision.
durham added a comment.


  Overall looks good to me.  My one comment is probably not enough to block 
this going in.

INLINE COMMENTS

> uncommit.py:260
> +prednode = markers[0].prednode()
> +predctx = unfi[prednode]
> +

Might be worth doing the predecessor check in the lock as well, since the 
result of this verification could technically change between now and when the 
lock is taken.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D821

To: pulkit, #hg-reviewers, durham
Cc: ryanmce, singhsrb, durham, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D1329: bundle: allow bundlerepo to support alternative manifest implementations

2017-11-09 Thread durham (Durham Goode)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGa2dfc723b6b5: bundle: allow bundlerepo to support 
alternative manifest implementations (authored by durham, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D1329?vs=3314=3385

REVISION DETAIL
  https://phab.mercurial-scm.org/D1329

AFFECTED FILES
  mercurial/bundlerepo.py

CHANGE DETAILS

diff --git a/mercurial/bundlerepo.py b/mercurial/bundlerepo.py
--- a/mercurial/bundlerepo.py
+++ b/mercurial/bundlerepo.py
@@ -352,14 +352,31 @@
 self.filestart = self.bundle.tell()
 return m
 
+def _consumemanifest(self):
+"""Consumes the manifest portion of the bundle, setting filestart so 
the
+file portion can be read."""
+self.bundle.seek(self.manstart)
+self.bundle.manifestheader()
+for delta in self.bundle.deltaiter():
+pass
+self.filestart = self.bundle.tell()
+
 @localrepo.unfilteredpropertycache
 def manstart(self):
 self.changelog
 return self.manstart
 
 @localrepo.unfilteredpropertycache
 def filestart(self):
 self.manifestlog
+
+# If filestart was not set by self.manifestlog, that means the
+# manifestlog implementation did not consume the manifests from the
+# changegroup (ex: it might be consuming trees from a separate bundle2
+# part instead). So we need to manually consume it.
+if 'filestart' not in self.__dict__:
+self._consumemanifest()
+
 return self.filestart
 
 def url(self):



To: durham, #hg-reviewers, indygreg
Cc: indygreg, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D1329: bundle: allow bundlerepo to support alternative manifest implementations

2017-11-07 Thread durham (Durham Goode)
durham created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  With our treemanifest logic, the manifests are no longer transported as part 
of
  the changegroup and are no longer stored in a revlog. This means the
  self.manifestlog line in bundlerepo.filestart no longer calls
  _constructmanifest, and therefore does not consume the manifest portion of the
  changegroup, which means filestart is not populated and we result in an 
infinite
  loop.
  
  The fix is to make filestart aware that self.manifestlog might not consume the
  changegroup part, and consume it manually if necessary.
  
  There's currently no way to test this in core, but our treemanifest extension
  has tests to cover this.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D1329

AFFECTED FILES
  mercurial/bundlerepo.py

CHANGE DETAILS

diff --git a/mercurial/bundlerepo.py b/mercurial/bundlerepo.py
--- a/mercurial/bundlerepo.py
+++ b/mercurial/bundlerepo.py
@@ -352,14 +352,31 @@
 self.filestart = self.bundle.tell()
 return m
 
+def _consumemanifest(self):
+"""Consumes the manifest portion of the bundle, setting filestart so 
the
+file portion can be read."""
+self.bundle.seek(self.manstart)
+self.bundle.manifestheader()
+for delta in self.bundle.deltaiter():
+pass
+self.filestart = self.bundle.tell()
+
 @localrepo.unfilteredpropertycache
 def manstart(self):
 self.changelog
 return self.manstart
 
 @localrepo.unfilteredpropertycache
 def filestart(self):
 self.manifestlog
+
+# If filestart was not set by self.manifestlog, that means the
+# manifestlog implementation did not consume the manifests from the
+# changegroup (ex: it might be consuming trees from a separate bundle2
+# part instead). So we need to manually consume it.
+if 'filestart' not in self.__dict__:
+self._consumemanifest()
+
 return self.filestart
 
 def url(self):



To: durham, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: Storage format for remotenames.

2017-11-07 Thread Durham Goode
I wish we had some easily reusable serializer/deserializer instead of 
having to reinvent these every time.  What's our reasoning for not using 
json? I forget. If there are some weird characters, like control 
characters or something, that break json, I'd say we just use json and 
prevent users from creating bookmarks and paths with those names.


Otherwise we could move the paths to a separate section and format the 
file something like:


[paths]
1=ssh://blahblah.com//blahblah
2=ssh://blahblah.com//blahblah
3=ssh://blahblah.com//blahblah

[bookmarks]
HASH 2 book/mark/name
HASH 1 book2/foo/bar

[branches]
HASH 1
HASH 3

On 11/6/17 4:34 AM, Pulkit Goyal wrote:

Hey,

I am working on porting functionalities from hgremotenames extension
to core. The hgremotenames extensions pull the information about
remote branches and remote bookmarks and store them to provide a
better workflow.

The current storage format which hgremotenames has is having a file
`.hg/remotenames` in which each line is of the format `node nametype
name`, where
  - `node` refers to node where the remotename was last seen
  -  `nametype` refers whether it's a bookmark or branch
  - `name` consists of name of the remote and name of the remote bookmark/branch

At sprint, Ryan suggested to split the file according to bookmark and
branches so that we can read and write more easily which makes sense.

While working on the patches, I found out that if the name of the
remote contains a '/', then the current storage format is not good and
we can fail to parse things correctly.

Do you guys have any better ideas on how we can store remotenames?

Pulkit


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


D1257: dirstate: remove excess attribute lookups for dirstate.status (issue5714)

2017-10-28 Thread durham (Durham Goode)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGffeea2406276: dirstate: remove excess attribute lookups for 
dirstate.status (issue5714) (authored by durham, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D1257?vs=3147=3150

REVISION DETAIL
  https://phab.mercurial-scm.org/D1257

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -1053,6 +1053,9 @@
 removed, deleted, clean = [], [], []
 
 dmap = self._map
+dmap.preload()
+dcontains = dmap.__contains__
+dget = dmap.__getitem__
 ladd = lookup.append# aka "unsure"
 madd = modified.append
 aadd = added.append
@@ -1074,7 +1077,7 @@
 full = listclean or match.traversedir is not None
 for fn, st in self.walk(match, subrepos, listunknown, listignored,
 full=full).iteritems():
-if fn not in dmap:
+if not dcontains(fn):
 if (listignored or mexact(fn)) and dirignore(fn):
 if listignored:
 iadd(fn)
@@ -1089,7 +1092,7 @@
 # a list, but falls back to creating a full-fledged iterator in
 # general. That is much slower than simply accessing and storing 
the
 # tuple members one by one.
-t = dmap[fn]
+t = dget(fn)
 state = t[0]
 mode = t[1]
 size = t[2]
@@ -1216,8 +1219,8 @@
 return self.copymap
 
 def clear(self):
-self._map = {}
-self.copymap = {}
+self._map.clear()
+self.copymap.clear()
 self.setparents(nullid, nullid)
 
 def iteritems(self):
@@ -1247,6 +1250,10 @@
 def keys(self):
 return self._map.keys()
 
+def preload(self):
+"""Loads the underlying data, if it's not already loaded"""
+self._map
+
 def nonnormalentries(self):
 '''Compute the nonnormal dirstate entries from the dmap'''
 try:
@@ -1373,6 +1380,13 @@
 if not self._dirtyparents:
 self.setparents(*p)
 
+# Avoid excess attribute lookups by fast pathing certain checks
+self.__contains__ = self._map.__contains__
+self.__getitem__ = self._map.__getitem__
+self.__setitem__ = self._map.__setitem__
+self.__delitem__ = self._map.__delitem__
+self.get = self._map.get
+
 def write(self, st, now):
 st.write(parsers.pack_dirstate(self._map, self.copymap,
self.parents(), now))



To: durham, #hg-reviewers, yuja
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D1257: dirstate: remove excess attribute lookups for dirstate.status (issue5714)

2017-10-28 Thread durham (Durham Goode)
durham added a comment.


  Fixed by using _map.clear() instead of replacing the _map.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D1257

To: durham, #hg-reviewers, yuja
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D1257: dirstate: remove excess attribute lookups for dirstate.status (issue5714)

2017-10-28 Thread durham (Durham Goode)
durham updated this revision to Diff 3147.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D1257?vs=3136=3147

REVISION DETAIL
  https://phab.mercurial-scm.org/D1257

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -1053,6 +1053,9 @@
 removed, deleted, clean = [], [], []
 
 dmap = self._map
+dmap.preload()
+dcontains = dmap.__contains__
+dget = dmap.__getitem__
 ladd = lookup.append# aka "unsure"
 madd = modified.append
 aadd = added.append
@@ -1074,7 +1077,7 @@
 full = listclean or match.traversedir is not None
 for fn, st in self.walk(match, subrepos, listunknown, listignored,
 full=full).iteritems():
-if fn not in dmap:
+if not dcontains(fn):
 if (listignored or mexact(fn)) and dirignore(fn):
 if listignored:
 iadd(fn)
@@ -1089,7 +1092,7 @@
 # a list, but falls back to creating a full-fledged iterator in
 # general. That is much slower than simply accessing and storing 
the
 # tuple members one by one.
-t = dmap[fn]
+t = dget(fn)
 state = t[0]
 mode = t[1]
 size = t[2]
@@ -1216,8 +1219,8 @@
 return self.copymap
 
 def clear(self):
-self._map = {}
-self.copymap = {}
+self._map.clear()
+self.copymap.clear()
 self.setparents(nullid, nullid)
 
 def iteritems(self):
@@ -1247,6 +1250,10 @@
 def keys(self):
 return self._map.keys()
 
+def preload(self):
+"""Loads the underlying data, if it's not already loaded"""
+self._map
+
 def nonnormalentries(self):
 '''Compute the nonnormal dirstate entries from the dmap'''
 try:
@@ -1373,6 +1380,13 @@
 if not self._dirtyparents:
 self.setparents(*p)
 
+# Avoid excess attribute lookups by fast pathing certain checks
+self.__contains__ = self._map.__contains__
+self.__getitem__ = self._map.__getitem__
+self.__setitem__ = self._map.__setitem__
+self.__delitem__ = self._map.__delitem__
+self.get = self._map.get
+
 def write(self, st, now):
 st.write(parsers.pack_dirstate(self._map, self.copymap,
self.parents(), now))



To: durham, #hg-reviewers, yuja
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D1253: dirstate: avoid reading the map when possible (issue5713) (issue5717)

2017-10-28 Thread durham (Durham Goode)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG6e66033f91cc: dirstate: avoid reading the map when possible 
(issue5713) (issue5717) (authored by durham, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D1253?vs=3129=3146

REVISION DETAIL
  https://phab.mercurial-scm.org/D1253

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -129,7 +129,7 @@
 def _map(self):
 '''Return the dirstate contents as a map from filename to
 (state, mode, size, time).'''
-self._read()
+self._map = dirstatemap(self._ui, self._opener, self._root)
 return self._map
 
 @property
@@ -353,10 +353,6 @@
 f.discard()
 raise
 
-def _read(self):
-self._map = dirstatemap(self._ui, self._opener, self._root)
-self._map.read()
-
 def invalidate(self):
 '''Causes the next access to reread the dirstate.
 
@@ -1201,14 +1197,24 @@
 self._root = root
 self._filename = 'dirstate'
 
-self._map = {}
-self.copymap = {}
 self._parents = None
 self._dirtyparents = False
 
 # for consistent view between _pl() and _read() invocations
 self._pendingmode = None
 
+@propertycache
+def _map(self):
+self._map = {}
+self.read()
+return self._map
+
+@propertycache
+def copymap(self):
+self.copymap = {}
+self._map
+return self.copymap
+
 def clear(self):
 self._map = {}
 self.copymap = {}
@@ -1388,7 +1394,7 @@
 
 @propertycache
 def identity(self):
-self.read()
+self._map
 return self.identity
 
 @propertycache



To: durham, #hg-reviewers, lothiraldan, yuja
Cc: yuja, lothiraldan, mharbison72, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D1252: dirstate: move clear onto dirstatemap class

2017-10-28 Thread durham (Durham Goode)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG0217f75b6e59: dirstate: move clear onto dirstatemap class 
(authored by durham, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D1252?vs=3128=3145

REVISION DETAIL
  https://phab.mercurial-scm.org/D1252

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -593,8 +593,7 @@
 return path
 
 def clear(self):
-self._map = dirstatemap(self._ui, self._opener, self._root)
-self._map.setparents(nullid, nullid)
+self._map.clear()
 self._lastnormaltime = 0
 self._updatedfiles.clear()
 self._dirty = True
@@ -1210,6 +1209,11 @@
 # for consistent view between _pl() and _read() invocations
 self._pendingmode = None
 
+def clear(self):
+self._map = {}
+self.copymap = {}
+self.setparents(nullid, nullid)
+
 def iteritems(self):
 return self._map.iteritems()
 



To: durham, #hg-reviewers, yuja
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D1257: dirstate: remove excess attribute lookups for dirstate.status (issue5714)

2017-10-27 Thread durham (Durham Goode)
durham created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  A recent refactor added a layer of abstraction to the dirstate which makes 
doing
  things like 'foo in dirstate' now require some extra Python attribute lookups.
  This is causing a 100ms slow down in hg status for mozilla-central.
  
  The fix is to hoist the inner dict's functions onto the main class once the 
lazy
  loading it complete, as well as store the actual functions before doing the
  status loop (as is done for other such functions).
  
  In my testing, it seems to address the performance regression, but we'll
  need to see the perf run results to know for sure.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D1257

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -1053,6 +1053,9 @@
 removed, deleted, clean = [], [], []
 
 dmap = self._map
+dmap.preload()
+dcontains = dmap.__contains__
+dget = dmap.__getitem__
 ladd = lookup.append# aka "unsure"
 madd = modified.append
 aadd = added.append
@@ -1074,7 +1077,7 @@
 full = listclean or match.traversedir is not None
 for fn, st in self.walk(match, subrepos, listunknown, listignored,
 full=full).iteritems():
-if fn not in dmap:
+if not dcontains(fn):
 if (listignored or mexact(fn)) and dirignore(fn):
 if listignored:
 iadd(fn)
@@ -1089,7 +1092,7 @@
 # a list, but falls back to creating a full-fledged iterator in
 # general. That is much slower than simply accessing and storing 
the
 # tuple members one by one.
-t = dmap[fn]
+t = dget(fn)
 state = t[0]
 mode = t[1]
 size = t[2]
@@ -1247,6 +1250,10 @@
 def keys(self):
 return self._map.keys()
 
+def preload(self):
+"""Loads the underlying data, if it's not already loaded"""
+self._map
+
 def nonnormalentries(self):
 '''Compute the nonnormal dirstate entries from the dmap'''
 try:
@@ -1373,6 +1380,13 @@
 if not self._dirtyparents:
 self.setparents(*p)
 
+# Avoid excess attribute lookups by fast pathing certain checks
+self.__contains__ = self._map.__contains__
+self.__getitem__ = self._map.__getitem__
+self.__setitem__ = self._map.__setitem__
+self.__delitem__ = self._map.__delitem__
+self.get = self._map.get
+
 def write(self, st, now):
 st.write(parsers.pack_dirstate(self._map, self.copymap,
self.parents(), now))



To: durham, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D1144: directaccess: add support to export and tests to demonstrate things

2017-10-27 Thread durham (Durham Goode)
durham added a comment.


  @lothiraldan
  Are pinned revs deleted when the cache is rebuilt?  I would kinda not expect 
them to be.  If they are deleted, then yea moving these exceptions to another 
attribute that is persisted across cache clears makes sense.
  
  For your concern about changing from a command-level option to a scope and 
revrange level option, I have a couple comments:
  
  - If we went the current command-level flag, the examples your talking about 
where it's initially ambiguous if the command is actually reading or writing 
the hidden commit (phase, fold --reuse-msg, etc) would default to warn mode and 
the only negative effect would be the user gets an extra warning message 
telling them a hash they passed is hidden. Probably not a common occurrence, 
and not a huge issue.  In the future we could add more logic within the command 
to suppress that warning when doing the read only paths, but for the short term 
this let's us get directaccess out the door without auditing and updating every 
commands logic.
  - As for adding exception context manager type things, I think one of the 
issues with our current visibility code is that it requires the person writing 
a command to be too aware that visibility exists.  If we start requiring 
commands to use this new context appropriately, and to pass the right argument 
to revrange at the right time, I think we just introduce more risk of commands 
being written incorrectly and having more complexity at the business logic 
layer.  If we can avoid all of that at the cost of printing warnings to the 
user slightly more often, I think that's a good trade off.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D1144

To: pulkit, #hg-reviewers, lothiraldan
Cc: durham, dlax, lothiraldan, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D1201: dirstate: clean up when restoring identical backups

2017-10-27 Thread durham (Durham Goode)
durham accepted this revision.
durham added a comment.


  lgtm.  Is this a recent regression?  Seems like this would be polluting lots 
of peoples repositories.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D1201

To: mbthomas, #hg-reviewers, krbullock, durham
Cc: krbullock, durham, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D1253: dirstate: avoid reading the map when possible (issue5713) (issue5717)

2017-10-27 Thread durham (Durham Goode)
durham added a comment.


  @mharbison72 your test output looks like the sort order changed?  Does it 
consistently repro before and after this patch?  The sort order is from the 
sort -u in the test, so I can't imagine this affecting it.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D1253

To: durham, #hg-reviewers, lothiraldan
Cc: yuja, lothiraldan, mharbison72, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D1253: dirstate: avoid reading the map when possible (issue5713) (issue5717)

2017-10-26 Thread durham (Durham Goode)
durham created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  Before the recent refactor, we would not load the entire map until it was
  accessed. As part of the refactor, that got lost and even just trying to load
  the dirstate parents would load the whole map. This caused a perf regression
  (issue5713) and a regression with static http serving (issue5717).
  
  Making it lazy loaded again fixes both.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D1253

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -129,7 +129,7 @@
 def _map(self):
 '''Return the dirstate contents as a map from filename to
 (state, mode, size, time).'''
-self._read()
+self._map = dirstatemap(self._ui, self._opener, self._root)
 return self._map
 
 @property
@@ -353,10 +353,6 @@
 f.discard()
 raise
 
-def _read(self):
-self._map = dirstatemap(self._ui, self._opener, self._root)
-self._map.read()
-
 def invalidate(self):
 '''Causes the next access to reread the dirstate.
 
@@ -1201,14 +1197,24 @@
 self._root = root
 self._filename = 'dirstate'
 
-self._map = {}
-self.copymap = {}
 self._parents = None
 self._dirtyparents = False
 
 # for consistent view between _pl() and _read() invocations
 self._pendingmode = None
 
+@propertycache
+def _map(self):
+self._map = {}
+self.read()
+return self._map
+
+@propertycache
+def copymap(self):
+self.copymap = {}
+self._map
+return self.copymap
+
 def clear(self):
 self._map = {}
 self.copymap = {}
@@ -1388,7 +1394,7 @@
 
 @propertycache
 def identity(self):
-self.read()
+self._map
 return self.identity
 
 @propertycache



To: durham, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D1252: dirstate: move clear onto dirstatemap class

2017-10-26 Thread durham (Durham Goode)
durham created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  A future diff will move the lazy loading aspect of dirstate to the dirstatemap
  class. This means it requires a slightly different strategy of clearing than
  just reinstantiating the object (since just reinstantiating the object will
  lazily load the on disk data again later instead of remaining permanently
  empty).
  
  So let's give it it's own clear function.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D1252

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -593,8 +593,7 @@
 return path
 
 def clear(self):
-self._map = dirstatemap(self._ui, self._opener, self._root)
-self._map.setparents(nullid, nullid)
+self._map.clear()
 self._lastnormaltime = 0
 self._updatedfiles.clear()
 self._dirty = True
@@ -1210,6 +1209,11 @@
 # for consistent view between _pl() and _read() invocations
 self._pendingmode = None
 
+def clear(self):
+self._map = {}
+self.copymap = {}
+self.setparents(nullid, nullid)
+
 def iteritems(self):
 return self._map.iteritems()
 



To: durham, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: Deploying registrar configs in a BC safe way

2017-10-25 Thread Durham Goode



On 10/25/17 5:48 AM, Augie Fackler wrote:



On Oct 25, 2017, at 07:51, Yuya Nishihara <y...@tcha.org> wrote:

On Tue, 24 Oct 2017 18:49:50 -0700, Gregory Szorc wrote:

On Oct 24, 2017, at 10:25, Durham Goode <dur...@fb.com> wrote:

I've been trying to update our extensions to support the new registrar class, 
and one thing I've noticed is that it's not really possible to have code that 
works with old versions of mercurial and new versions of mercurial at the same 
time, without having devel warnings. I can easily stub out the registration 
logic if the registrar module doesn't exist, but I can't leave the default 
values on the actual config accessor lines, which old mercurial versions would 
need.


I made all extension-specific configs "dynamic", and add explicit defaults
to ui.config*() calls instead.

https://urldefense.proofpoint.com/v2/url?u=https-3A__bitbucket.org_yuja_hgext-2Dtextful_commits_1f284a246abb=DwIFAg=5VD0RTtNlTh3ycd41b3MUw=nuarHzhP1wi1T9iURRCj1A=lR7l4BfqDK6q7Iea-79Q-h1teNA3oQLKKh7QiqDoA4M=2ycQgVlPv5dGVFQUeMGUTS1h8KHBikUl11j9FoGk7m4=


I tried to think of some way to fix this, like by leaving the defaults on the 
config access line, but ignoring it somehow, but that sounds funky. Thoughts on 
how to fix this?


How about making registrar instances on extensions have different behavior from 
core? e.g.

* No devel warnings for e.g. missing default values for a few releases
* Arguments to control which devel warnings are issued


Or,

* No devel warnings for the "ui.config()" default matching the "configitem"
 default, which should be harmless


That seems like a good transitional step, I like it. What do others think?



That would work for me. Adding the register's isn't the painful or risky 
part, updating the defaults and refactoring to support old mercurial is. 
So this would address that issue nicely.

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


Re: [PATCH remotenames] configs: update configs to use registrar

2017-10-24 Thread Durham Goode

I didn't fill in the commit message on this one. V2 incoming

On 10/24/17 2:15 PM, Durham Goode wrote:

# HG changeset patch
# User Durham Goode <dur...@fb.com>
# Date 1508879615 25200
#  Tue Oct 24 14:13:35 2017 -0700
# Node ID 9ead5c33dd22a9a66cea009bcf76ffd801d5677e
# Parent  5fb97b6b3d46fcd4dc1b3cb6be137762eb9e60e7
configs: update configs to use registrar

diff --git a/remotenames.py b/remotenames.py
--- a/remotenames.py
+++ b/remotenames.py
@@ -32,12 +32,14 @@ from mercurial import localrepo
 from mercurial import lock as lockmod
 from mercurial import namespaces
 from mercurial import obsutil
+from mercurial import registrar
 from mercurial import repair
 from mercurial import repoview
 from mercurial import revset
 from mercurial import scmutil
 from mercurial import setdiscovery
 from mercurial import templatekw
+from mercurial import ui as uimod
 from mercurial import url
 from mercurial import util
 from mercurial import vfs as vfsmod
@@ -51,12 +53,64 @@ try:
 except ImportError:
 smartset = revset

+configtable = {}
+try:
+from mercurial import registrar
+if not util.safehasattr(registrar, 'configitem'):
+raise ImportError()
+# Supported in 4.3+
+configitem = registrar.configitem(configtable)
+except ImportError:
+# Support older releases that didn't register config defaults
+registrar = None
+def configitem(section, name, default=None):
+configtable[(section, name)] = default
+
+def configdefault(orig, self, section, name, default=None,
+  untrusted=False):
+if default is None:
+default = configtable.get((section, name))
+return orig(self, section, name, default=default, untrusted=untrusted)
+
+configitem('remotenames', 'alias.default', default=False)
+configitem('remotenames', 'allownonfastforward', default=False)
+configitem('remotenames', 'bookmarks', default=True)
+configitem('remotenames', 'branches', default=True)
+configitem('remotenames', 'calculatedistance', default=True)
+configitem('remotenames', 'disallowedbookmarks', default=[])
+configitem('remotenames', 'disallowedhint', default=None)
+configitem('remotenames', 'disallowedto', default=None)
+configitem('remotenames', 'fastheaddiscovery', default=True)
+configitem('remotenames', 'forcecompat', default=False)
+configitem('remotenames', 'forceto', default=False)
+configitem('remotenames', 'hoist', default='default')
+configitem('remotenames', 'precachecurrent', default=True)
+configitem('remotenames', 'precachedistance', default=True)
+configitem('remotenames', 'pushanonheads', default=False)
+configitem('remotenames', 'pushrev', default=None)
+configitem('remotenames', 'resolvenodes', default=True)
+configitem('remotenames', 'selectivepull', default=False)
+configitem('remotenames', 'selectivepulldefault', default=[])
+configitem('remotenames', 'suppressbranches', default=False)
+configitem('remotenames', 'syncbookmarks', default=False)
+configitem('remotenames', 'tracking', default=True)
+configitem('remotenames', 'transitionbookmarks', default=[])
+configitem('remotenames', 'transitionmessage', default=None)
+configitem('remotenames', 'upstream', default=[])
+
 # namespace to use when recording an hg journal entry
 journalremotebookmarktype = 'remotebookmark'
 # name of the file that is used to mark that transition to selectivepull has
 # happened
 _selectivepullenabledfile = 'selectivepullenabled'

+def uisetup(ui):
+if registrar is None:
+if util.safehasattr(uimod.ui, '_config'):
+extensions.wrapfunction(uimod.ui, '_config', configdefault)
+else:
+extensions.wrapfunction(uimod.ui, 'config', configdefault)
+
 def exbookcalcupdate(orig, ui, repo, checkout):
 '''Return a tuple (targetrev, movemarkfrom) indicating the rev to
 check out and where to move the active bookmark from, if needed.'''
@@ -85,7 +139,7 @@ def expushop(orig, pushop, repo, remote,
 setattr(pushop, flag, kwargs.pop(flag, None))

 def _isselectivepull(ui):
-return ui.configbool('remotenames', 'selectivepull', False)
+return ui.configbool('remotenames', 'selectivepull')

 def _getselectivepulldefaultbookmarks(ui):
 default_books = ui.configlist('remotenames', 'selectivepulldefault')
@@ -186,7 +240,7 @@ def exfindcommonheads(orig, ui, local, r
 # the current remotenames are representative of what's on the server. In 
the
 # worst case the data might be slightly out of sync and the server sends us
 # more data than necessary, but this should be rare.
-if not ui.configbool('remotenames', 'fastheaddiscovery', True):
+if not ui.configbool('remotenames', 'fastheaddiscovery'):
 return orig(ui, local, remote, **kwargs)

 cl = local.changelog
@@ -280,7 +334,7 @@ def blockerhook(orig, repo, *args, **kwa
 return blockers

 def exupdatefromremote(orig, ui, repo, remotemarks, path, trfunc, explicit=()):
-if ui.configbool('remotenames', 'syncbookmarks',

[PATCH remotenames V2] configs: update configs to use registrar

2017-10-24 Thread Durham Goode
# HG changeset patch
# User Durham Goode <dur...@fb.com>
# Date 1508879721 25200
#  Tue Oct 24 14:15:21 2017 -0700
# Node ID c8d9ee2123baadd3ca1b571b3e7acf86ca1e6783
# Parent  5fb97b6b3d46fcd4dc1b3cb6be137762eb9e60e7
configs: update configs to use registrar

Upstream now gives devel warnings if configs aren't registered, or if they
specify defaults at access time. This updates remotenames to register all it's
configs. It tries to be backwards compatible and support older clients who don't
have config registering as well, but I haven't tested it well (testing against
4.0 crashes for other incompatibility reasons).

diff --git a/remotenames.py b/remotenames.py
--- a/remotenames.py
+++ b/remotenames.py
@@ -32,12 +32,14 @@ from mercurial import localrepo
 from mercurial import lock as lockmod
 from mercurial import namespaces
 from mercurial import obsutil
+from mercurial import registrar
 from mercurial import repair
 from mercurial import repoview
 from mercurial import revset
 from mercurial import scmutil
 from mercurial import setdiscovery
 from mercurial import templatekw
+from mercurial import ui as uimod
 from mercurial import url
 from mercurial import util
 from mercurial import vfs as vfsmod
@@ -51,12 +53,64 @@ try:
 except ImportError:
 smartset = revset
 
+configtable = {}
+try:
+from mercurial import registrar
+if not util.safehasattr(registrar, 'configitem'):
+raise ImportError()
+# Supported in 4.3+
+configitem = registrar.configitem(configtable)
+except ImportError:
+# Support older releases that didn't register config defaults
+registrar = None
+def configitem(section, name, default=None):
+configtable[(section, name)] = default
+
+def configdefault(orig, self, section, name, default=None,
+  untrusted=False):
+if default is None:
+default = configtable.get((section, name))
+return orig(self, section, name, default=default, untrusted=untrusted)
+
+configitem('remotenames', 'alias.default', default=False)
+configitem('remotenames', 'allownonfastforward', default=False)
+configitem('remotenames', 'bookmarks', default=True)
+configitem('remotenames', 'branches', default=True)
+configitem('remotenames', 'calculatedistance', default=True)
+configitem('remotenames', 'disallowedbookmarks', default=[])
+configitem('remotenames', 'disallowedhint', default=None)
+configitem('remotenames', 'disallowedto', default=None)
+configitem('remotenames', 'fastheaddiscovery', default=True)
+configitem('remotenames', 'forcecompat', default=False)
+configitem('remotenames', 'forceto', default=False)
+configitem('remotenames', 'hoist', default='default')
+configitem('remotenames', 'precachecurrent', default=True)
+configitem('remotenames', 'precachedistance', default=True)
+configitem('remotenames', 'pushanonheads', default=False)
+configitem('remotenames', 'pushrev', default=None)
+configitem('remotenames', 'resolvenodes', default=True)
+configitem('remotenames', 'selectivepull', default=False)
+configitem('remotenames', 'selectivepulldefault', default=[])
+configitem('remotenames', 'suppressbranches', default=False)
+configitem('remotenames', 'syncbookmarks', default=False)
+configitem('remotenames', 'tracking', default=True)
+configitem('remotenames', 'transitionbookmarks', default=[])
+configitem('remotenames', 'transitionmessage', default=None)
+configitem('remotenames', 'upstream', default=[])
+
 # namespace to use when recording an hg journal entry
 journalremotebookmarktype = 'remotebookmark'
 # name of the file that is used to mark that transition to selectivepull has
 # happened
 _selectivepullenabledfile = 'selectivepullenabled'
 
+def uisetup(ui):
+if registrar is None:
+if util.safehasattr(uimod.ui, '_config'):
+extensions.wrapfunction(uimod.ui, '_config', configdefault)
+else:
+extensions.wrapfunction(uimod.ui, 'config', configdefault)
+
 def exbookcalcupdate(orig, ui, repo, checkout):
 '''Return a tuple (targetrev, movemarkfrom) indicating the rev to
 check out and where to move the active bookmark from, if needed.'''
@@ -85,7 +139,7 @@ def expushop(orig, pushop, repo, remote,
 setattr(pushop, flag, kwargs.pop(flag, None))
 
 def _isselectivepull(ui):
-return ui.configbool('remotenames', 'selectivepull', False)
+return ui.configbool('remotenames', 'selectivepull')
 
 def _getselectivepulldefaultbookmarks(ui):
 default_books = ui.configlist('remotenames', 'selectivepulldefault')
@@ -186,7 +240,7 @@ def exfindcommonheads(orig, ui, local, r
 # the current remotenames are representative of what's on the server. In 
the
 # worst case the data might be slightly out of sync and the server sends us
 # more data than necessary, but this should be rare.
-if not ui.configbool('remotenames', 'fastheaddiscovery', True):
+if not ui.configbool('remotenames', 'fastheaddiscovery'):
 return orig(ui, local, 

[PATCH remotenames] configs: update configs to use registrar

2017-10-24 Thread Durham Goode
# HG changeset patch
# User Durham Goode <dur...@fb.com>
# Date 1508879615 25200
#  Tue Oct 24 14:13:35 2017 -0700
# Node ID 9ead5c33dd22a9a66cea009bcf76ffd801d5677e
# Parent  5fb97b6b3d46fcd4dc1b3cb6be137762eb9e60e7
configs: update configs to use registrar

diff --git a/remotenames.py b/remotenames.py
--- a/remotenames.py
+++ b/remotenames.py
@@ -32,12 +32,14 @@ from mercurial import localrepo
 from mercurial import lock as lockmod
 from mercurial import namespaces
 from mercurial import obsutil
+from mercurial import registrar
 from mercurial import repair
 from mercurial import repoview
 from mercurial import revset
 from mercurial import scmutil
 from mercurial import setdiscovery
 from mercurial import templatekw
+from mercurial import ui as uimod
 from mercurial import url
 from mercurial import util
 from mercurial import vfs as vfsmod
@@ -51,12 +53,64 @@ try:
 except ImportError:
 smartset = revset
 
+configtable = {}
+try:
+from mercurial import registrar
+if not util.safehasattr(registrar, 'configitem'):
+raise ImportError()
+# Supported in 4.3+
+configitem = registrar.configitem(configtable)
+except ImportError:
+# Support older releases that didn't register config defaults
+registrar = None
+def configitem(section, name, default=None):
+configtable[(section, name)] = default
+
+def configdefault(orig, self, section, name, default=None,
+  untrusted=False):
+if default is None:
+default = configtable.get((section, name))
+return orig(self, section, name, default=default, untrusted=untrusted)
+
+configitem('remotenames', 'alias.default', default=False)
+configitem('remotenames', 'allownonfastforward', default=False)
+configitem('remotenames', 'bookmarks', default=True)
+configitem('remotenames', 'branches', default=True)
+configitem('remotenames', 'calculatedistance', default=True)
+configitem('remotenames', 'disallowedbookmarks', default=[])
+configitem('remotenames', 'disallowedhint', default=None)
+configitem('remotenames', 'disallowedto', default=None)
+configitem('remotenames', 'fastheaddiscovery', default=True)
+configitem('remotenames', 'forcecompat', default=False)
+configitem('remotenames', 'forceto', default=False)
+configitem('remotenames', 'hoist', default='default')
+configitem('remotenames', 'precachecurrent', default=True)
+configitem('remotenames', 'precachedistance', default=True)
+configitem('remotenames', 'pushanonheads', default=False)
+configitem('remotenames', 'pushrev', default=None)
+configitem('remotenames', 'resolvenodes', default=True)
+configitem('remotenames', 'selectivepull', default=False)
+configitem('remotenames', 'selectivepulldefault', default=[])
+configitem('remotenames', 'suppressbranches', default=False)
+configitem('remotenames', 'syncbookmarks', default=False)
+configitem('remotenames', 'tracking', default=True)
+configitem('remotenames', 'transitionbookmarks', default=[])
+configitem('remotenames', 'transitionmessage', default=None)
+configitem('remotenames', 'upstream', default=[])
+
 # namespace to use when recording an hg journal entry
 journalremotebookmarktype = 'remotebookmark'
 # name of the file that is used to mark that transition to selectivepull has
 # happened
 _selectivepullenabledfile = 'selectivepullenabled'
 
+def uisetup(ui):
+if registrar is None:
+if util.safehasattr(uimod.ui, '_config'):
+extensions.wrapfunction(uimod.ui, '_config', configdefault)
+else:
+extensions.wrapfunction(uimod.ui, 'config', configdefault)
+
 def exbookcalcupdate(orig, ui, repo, checkout):
 '''Return a tuple (targetrev, movemarkfrom) indicating the rev to
 check out and where to move the active bookmark from, if needed.'''
@@ -85,7 +139,7 @@ def expushop(orig, pushop, repo, remote,
 setattr(pushop, flag, kwargs.pop(flag, None))
 
 def _isselectivepull(ui):
-return ui.configbool('remotenames', 'selectivepull', False)
+return ui.configbool('remotenames', 'selectivepull')
 
 def _getselectivepulldefaultbookmarks(ui):
 default_books = ui.configlist('remotenames', 'selectivepulldefault')
@@ -186,7 +240,7 @@ def exfindcommonheads(orig, ui, local, r
 # the current remotenames are representative of what's on the server. In 
the
 # worst case the data might be slightly out of sync and the server sends us
 # more data than necessary, but this should be rare.
-if not ui.configbool('remotenames', 'fastheaddiscovery', True):
+if not ui.configbool('remotenames', 'fastheaddiscovery'):
 return orig(ui, local, remote, **kwargs)
 
 cl = local.changelog
@@ -280,7 +334,7 @@ def blockerhook(orig, repo, *args, **kwa
 return blockers
 
 def exupdatefromremote(orig, ui, repo, remotemarks, path, trfunc, explicit=()):
-if ui.configbool('remotenames', 'syncbookmarks', False):
+if ui.configbool('remotenames', 'syncbookmarks'):
 return orig(ui, repo, remot

Deploying registrar configs in a BC safe way

2017-10-24 Thread Durham Goode
I've been trying to update our extensions to support the new registrar 
class, and one thing I've noticed is that it's not really possible to 
have code that works with old versions of mercurial and new versions of 
mercurial at the same time, without having devel warnings. I can easily 
stub out the registration logic if the registrar module doesn't exist, 
but I can't leave the default values on the actual config accessor 
lines, which old mercurial versions would need.


For now I'm just updating our extensions to only work with new 
mercurial, but if someone tries to use them with an older version it 
will cause subtle failures as the default configs will be different.


I tried to think of some way to fix this, like by leaving the defaults 
on the config access line, but ignoring it somehow, but that sounds 
funky. Thoughts on how to fix this?

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


D983: dirstate: move the _dirfoldmap to dirstatemap

2017-10-13 Thread durham (Durham Goode)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGe8a89ed7ce96: dirstate: move the _dirfoldmap to dirstatemap 
(authored by durham, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D983?vs=2513=2713

REVISION DETAIL
  https://phab.mercurial-scm.org/D983

AFFECTED FILES
  contrib/perf.py
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -132,14 +132,6 @@
 self._read()
 return self._map
 
-@propertycache
-def _dirfoldmap(self):
-f = {}
-normcase = util.normcase
-for name in self._map.dirs:
-f[normcase(name)] = name
-return f
-
 @property
 def _sparsematcher(self):
 """The matcher for the sparse checkout.
@@ -372,8 +364,7 @@
 rereads the dirstate. Use localrepo.invalidatedirstate() if you want to
 check whether the dirstate has changed before rereading it.'''
 
-for a in ("_map", "_dirfoldmap", "_branch",
-  "_ignore"):
+for a in ("_map", "_branch", "_ignore"):
 if a in self.__dict__:
 delattr(self, a)
 self._lastnormaltime = 0
@@ -568,15 +559,15 @@
 normed = util.normcase(path)
 folded = self._map.filefoldmap.get(normed, None)
 if folded is None:
-folded = self._dirfoldmap.get(normed, None)
+folded = self._map.dirfoldmap.get(normed, None)
 if folded is None:
 if isknown:
 folded = path
 else:
 # store discovered result in dirfoldmap so that future
 # normalizefile calls don't start matching directories
 folded = self._discoverpath(path, normed, ignoremissing, 
exists,
-self._dirfoldmap)
+self._map.dirfoldmap)
 return folded
 
 def normalize(self, path, isknown=False, ignoremissing=False):
@@ -875,7 +866,7 @@
 if len(paths) > 1:
 for path in paths:
 folded = self._discoverpath(path, norm, True, None,
-self._dirfoldmap)
+self._map.dirfoldmap)
 if path != folded:
 results[path] = None
 
@@ -1396,3 +1387,10 @@
 self.read()
 return self.identity
 
+@propertycache
+def dirfoldmap(self):
+f = {}
+normcase = util.normcase
+for name in self.dirs:
+f[normcase(name)] = name
+return f
diff --git a/contrib/perf.py b/contrib/perf.py
--- a/contrib/perf.py
+++ b/contrib/perf.py
@@ -560,8 +560,8 @@
 dirstate = repo.dirstate
 'a' in dirstate
 def d():
-dirstate._dirfoldmap.get('a')
-del dirstate._dirfoldmap
+dirstate._map.dirfoldmap.get('a')
+del dirstate._map.dirfoldmap
 del dirstate._map.dirs
 timer(d)
 fm.end()



To: durham, #hg-reviewers, quark, durin42
Cc: quark, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D981: dirstate: remove _filefoldmap property cache

2017-10-13 Thread durham (Durham Goode)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGbfddc3d678ae: dirstate: remove _filefoldmap property cache 
(authored by durham, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D981?vs=2511=2710

REVISION DETAIL
  https://phab.mercurial-scm.org/D981

AFFECTED FILES
  contrib/perf.py
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -133,10 +133,6 @@
 return self._map
 
 @propertycache
-def _filefoldmap(self):
-return self._map.filefoldmap()
-
-@propertycache
 def _dirfoldmap(self):
 f = {}
 normcase = util.normcase
@@ -380,7 +376,7 @@
 rereads the dirstate. Use localrepo.invalidatedirstate() if you want to
 check whether the dirstate has changed before rereading it.'''
 
-for a in ("_map", "_filefoldmap", "_dirfoldmap", "_branch",
+for a in ("_map", "_dirfoldmap", "_branch",
   "_dirs", "_ignore"):
 if a in self.__dict__:
 delattr(self, a)
@@ -412,10 +408,10 @@
 if self[f] not in "?r" and "_dirs" in self.__dict__:
 self._dirs.delpath(f)
 
-if "_filefoldmap" in self.__dict__:
+if "filefoldmap" in self._map.__dict__:
 normed = util.normcase(f)
-if normed in self._filefoldmap:
-del self._filefoldmap[normed]
+if normed in self._map.filefoldmap:
+del self._map.filefoldmap[normed]
 
 self._updatedfiles.add(f)
 
@@ -563,18 +559,18 @@
 
 def _normalizefile(self, path, isknown, ignoremissing=False, exists=None):
 normed = util.normcase(path)
-folded = self._filefoldmap.get(normed, None)
+folded = self._map.filefoldmap.get(normed, None)
 if folded is None:
 if isknown:
 folded = path
 else:
 folded = self._discoverpath(path, normed, ignoremissing, 
exists,
-self._filefoldmap)
+self._map.filefoldmap)
 return folded
 
 def _normalize(self, path, isknown, ignoremissing=False, exists=None):
 normed = util.normcase(path)
-folded = self._filefoldmap.get(normed, None)
+folded = self._map.filefoldmap.get(normed, None)
 if folded is None:
 folded = self._dirfoldmap.get(normed, None)
 if folded is None:
@@ -1270,6 +1266,7 @@
 otherparent.add(fname)
 return nonnorm, otherparent
 
+@propertycache
 def filefoldmap(self):
 """Returns a dictionary mapping normalized case paths to their
 non-normalized versions.
diff --git a/contrib/perf.py b/contrib/perf.py
--- a/contrib/perf.py
+++ b/contrib/perf.py
@@ -549,8 +549,8 @@
 dirstate = repo.dirstate
 'a' in dirstate
 def d():
-dirstate._filefoldmap.get('a')
-del dirstate._filefoldmap
+dirstate._map.filefoldmap.get('a')
+del dirstate._map.filefoldmap
 timer(d)
 fm.end()
 



To: durham, #hg-reviewers, quark, durin42
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D982: dirstate: remove _dirs property cache

2017-10-13 Thread durham (Durham Goode)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG014bd2a555c8: dirstate: remove _dirs property cache 
(authored by durham, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D982?vs=2512=2711

REVISION DETAIL
  https://phab.mercurial-scm.org/D982

AFFECTED FILES
  contrib/perf.py
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -136,7 +136,7 @@
 def _dirfoldmap(self):
 f = {}
 normcase = util.normcase
-for name in self._dirs:
+for name in self._map.dirs:
 f[normcase(name)] = name
 return f
 
@@ -166,12 +166,8 @@
 def _pl(self):
 return self._map.parents()
 
-@propertycache
-def _dirs(self):
-return self._map.dirs()
-
 def dirs(self):
-return self._dirs
+return self._map.dirs
 
 @rootcache('.hgignore')
 def _ignore(self):
@@ -377,7 +373,7 @@
 check whether the dirstate has changed before rereading it.'''
 
 for a in ("_map", "_dirfoldmap", "_branch",
-  "_dirs", "_ignore"):
+  "_ignore"):
 if a in self.__dict__:
 delattr(self, a)
 self._lastnormaltime = 0
@@ -405,8 +401,8 @@
 return self._map.copymap
 
 def _droppath(self, f):
-if self[f] not in "?r" and "_dirs" in self.__dict__:
-self._dirs.delpath(f)
+if self[f] not in "?r" and "dirs" in self._map.__dict__:
+self._map.dirs.delpath(f)
 
 if "filefoldmap" in self._map.__dict__:
 normed = util.normcase(f)
@@ -419,18 +415,18 @@
 oldstate = self[f]
 if state == 'a' or oldstate == 'r':
 scmutil.checkfilename(f)
-if f in self._dirs:
+if f in self._map.dirs:
 raise error.Abort(_('directory %r already in dirstate') % f)
 # shadows
 for d in util.finddirs(f):
-if d in self._dirs:
+if d in self._map.dirs:
 break
 entry = self._map.get(d)
 if entry is not None and entry[0] != 'r':
 raise error.Abort(
 _('file %r in dirstate clashes with %r') % (d, f))
-if oldstate in "?r" and "_dirs" in self.__dict__:
-self._dirs.addpath(f)
+if oldstate in "?r" and "dirs" in self._map.__dict__:
+self._map.dirs.addpath(f)
 self._dirty = True
 self._updatedfiles.add(f)
 self._map[f] = dirstatetuple(state, mode, size, mtime)
@@ -607,8 +603,6 @@
 
 def clear(self):
 self._map = dirstatemap(self._ui, self._opener, self._root)
-if "_dirs" in self.__dict__:
-delattr(self, "_dirs")
 self._map.setparents(nullid, nullid)
 self._lastnormaltime = 0
 self._updatedfiles.clear()
@@ -1287,6 +1281,7 @@
 f['.'] = '.' # prevents useless util.fspath() invocation
 return f
 
+@propertycache
 def dirs(self):
 """Returns a set-like object containing all the directories in the
 current dirstate.
diff --git a/contrib/perf.py b/contrib/perf.py
--- a/contrib/perf.py
+++ b/contrib/perf.py
@@ -519,7 +519,7 @@
 'a' in dirstate
 def d():
 dirstate.dirs()
-del dirstate._dirs
+del dirstate._map.dirs
 timer(d)
 fm.end()
 
@@ -538,8 +538,8 @@
 timer, fm = gettimer(ui, opts)
 "a" in repo.dirstate
 def d():
-"a" in repo.dirstate._dirs
-del repo.dirstate._dirs
+"a" in repo.dirstate._map.dirs
+del repo.dirstate._map.dirs
 timer(d)
 fm.end()
 
@@ -562,7 +562,7 @@
 def d():
 dirstate._dirfoldmap.get('a')
 del dirstate._dirfoldmap
-del dirstate._dirs
+del dirstate._map.dirs
 timer(d)
 fm.end()
 



To: durham, #hg-reviewers, quark, durin42
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D979: dirstate: move nonnormal and otherparent sets to dirstatemap

2017-10-13 Thread durham (Durham Goode)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG60927b19ed65: dirstate: move nonnormal and otherparent sets 
to dirstatemap (authored by durham, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D979?vs=2509=2708

REVISION DETAIL
  https://phab.mercurial-scm.org/D979

AFFECTED FILES
  contrib/dirstatenonnormalcheck.py
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -138,18 +138,6 @@
 return self._identity
 
 @propertycache
-def _nonnormalset(self):
-nonnorm, otherparents = self._map.nonnormalentries()
-self._otherparentset = otherparents
-return nonnorm
-
-@propertycache
-def _otherparentset(self):
-nonnorm, otherparents = self._map.nonnormalentries()
-self._nonnormalset = nonnorm
-return otherparents
-
-@propertycache
 def _filefoldmap(self):
 return self._map.filefoldmap()
 
@@ -349,7 +337,8 @@
 self._map.setparents(p1, p2)
 copies = {}
 if oldp2 != nullid and p2 == nullid:
-candidatefiles = self._nonnormalset.union(self._otherparentset)
+candidatefiles = self._map.nonnormalset.union(
+self._map.otherparentset)
 for f in candidatefiles:
 s = self._map.get(f)
 if s is None:
@@ -401,8 +390,7 @@
 
 for a in ("_map", "_identity",
   "_filefoldmap", "_dirfoldmap", "_branch",
-  "_dirs", "_ignore", "_nonnormalset",
-  "_otherparentset"):
+  "_dirs", "_ignore"):
 if a in self.__dict__:
 delattr(self, a)
 self._lastnormaltime = 0
@@ -460,19 +448,19 @@
 self._updatedfiles.add(f)
 self._map[f] = dirstatetuple(state, mode, size, mtime)
 if state != 'n' or mtime == -1:
-self._nonnormalset.add(f)
+self._map.nonnormalset.add(f)
 if size == -2:
-self._otherparentset.add(f)
+self._map.otherparentset.add(f)
 
 def normal(self, f):
 '''Mark a file normal and clean.'''
 s = os.lstat(self._join(f))
 mtime = s.st_mtime
 self._addpath(f, 'n', s.st_mode,
   s.st_size & _rangemask, mtime & _rangemask)
 self._map.copymap.pop(f, None)
-if f in self._nonnormalset:
-self._nonnormalset.remove(f)
+if f in self._map.nonnormalset:
+self._map.nonnormalset.remove(f)
 if mtime > self._lastnormaltime:
 # Remember the most recent modification timeslot for status(),
 # to make sure we won't miss future size-preserving file content
@@ -500,8 +488,8 @@
 return
 self._addpath(f, 'n', 0, -1, -1)
 self._map.copymap.pop(f, None)
-if f in self._nonnormalset:
-self._nonnormalset.remove(f)
+if f in self._map.nonnormalset:
+self._map.nonnormalset.remove(f)
 
 def otherparent(self, f):
 '''Mark as coming from the other parent, always dirty.'''
@@ -534,9 +522,9 @@
 size = -1
 elif entry[0] == 'n' and entry[2] == -2: # other parent
 size = -2
-self._otherparentset.add(f)
+self._map.otherparentset.add(f)
 self._map[f] = dirstatetuple('r', 0, size, 0)
-self._nonnormalset.add(f)
+self._map.nonnormalset.add(f)
 if size == 0:
 self._map.copymap.pop(f, None)
 
@@ -552,8 +540,8 @@
 self._dirty = True
 self._droppath(f)
 del self._map[f]
-if f in self._nonnormalset:
-self._nonnormalset.remove(f)
+if f in self._map.nonnormalset:
+self._map.nonnormalset.remove(f)
 self._map.copymap.pop(f, None)
 
 def _discoverpath(self, path, normed, ignoremissing, exists, storemap):
@@ -632,8 +620,6 @@
 
 def clear(self):
 self._map = dirstatemap(self._ui, self._opener, self._root)
-self._nonnormalset = set()
-self._otherparentset = set()
 if "_dirs" in self.__dict__:
 delattr(self, "_dirs")
 self._map.setparents(nullid, nullid)
@@ -687,7 +673,7 @@
 e = dmap.get(f)
 if e is not None and e[0] == 'n' and e[3] == now:
 dmap[f] = dirstatetuple(e[0], e[1], e[2], -1)
-self._nonnormalset.add(f)
+self._map.nonnormalset.add(f)
 
 # emulate that all 'dirstate.normal' results are written out
 self._lastnormaltime = 0
@@ -740,7 +726,6 @@
 break
 
 self._map.write(st, now)
-self._nonnormalset, self._otherparentset = 

D978: dirstate: move write into dirstatemap

2017-10-13 Thread durham (Durham Goode)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGe2214632c3a2: dirstate: move write into dirstatemap 
(authored by durham, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D978?vs=2508=2707

REVISION DETAIL
  https://phab.mercurial-scm.org/D978

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -739,12 +739,10 @@
 now = end # trust our estimate that the end is near now
 break
 
-st.write(parsers.pack_dirstate(self._map._map, self._map.copymap,
-   self._pl, now))
+self._map.write(st, now)
 self._nonnormalset, self._otherparentset = self._map.nonnormalentries()
-st.close()
 self._lastnormaltime = 0
-self._dirty = self._map._dirtyparents = False
+self._dirty = False
 
 def _dirignore(self, f):
 if f == '.':
@@ -1401,3 +1399,9 @@
 p = parse_dirstate(self._map, self.copymap, st)
 if not self._dirtyparents:
 self.setparents(*p)
+
+def write(self, st, now):
+st.write(parsers.pack_dirstate(self._map, self.copymap,
+   self.parents(), now))
+st.close()
+self._dirtyparents = False



To: durham, #hg-reviewers, quark, durin42
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D977: dirstate: move _read into dirstatemap

2017-10-13 Thread durham (Durham Goode)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGe159f217230e: dirstate: move _read into dirstatemap 
(authored by durham, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D977?vs=2507=2706

REVISION DETAIL
  https://phab.mercurial-scm.org/D977

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -386,53 +386,11 @@
 raise
 
 def _read(self):
-self._map = dirstatemap(self._ui, self._opener, self._root)
-
 # ignore HG_PENDING because identity is used only for writing
 self._identity = util.filestat.frompath(
 self._opener.join(self._filename))
-try:
-fp = self._map._opendirstatefile()
-try:
-st = fp.read()
-finally:
-fp.close()
-except IOError as err:
-if err.errno != errno.ENOENT:
-raise
-return
-if not st:
-return
-
-if util.safehasattr(parsers, 'dict_new_presized'):
-# Make an estimate of the number of files in the dirstate based on
-# its size. From a linear regression on a set of real-world repos,
-# all over 10,000 files, the size of a dirstate entry is 85
-# bytes. The cost of resizing is significantly higher than the cost
-# of filling in a larger presized dict, so subtract 20% from the
-# size.
-#
-# This heuristic is imperfect in many ways, so in a future dirstate
-# format update it makes sense to just record the number of entries
-# on write.
-self._map._map = parsers.dict_new_presized(len(st) / 71)
-
-# Python's garbage collector triggers a GC each time a certain number
-# of container objects (the number being defined by
-# gc.get_threshold()) are allocated. parse_dirstate creates a tuple
-# for each file in the dirstate. The C version then immediately marks
-# them as not to be tracked by the collector. However, this has no
-# effect on when GCs are triggered, only on what objects the GC looks
-# into. This means that O(number of files) GCs are unavoidable.
-# Depending on when in the process's lifetime the dirstate is parsed,
-# this can get very expensive. As a workaround, disable GC while
-# parsing the dirstate.
-#
-# (we cannot decorate the function directly since it is in a C module)
-parse_dirstate = util.nogc(parsers.parse_dirstate)
-p = parse_dirstate(self._map._map, self._map.copymap, st)
-if not self._map._dirtyparents:
-self._map.setparents(*p)
+self._map = dirstatemap(self._ui, self._opener, self._root)
+self._map.read()
 
 def invalidate(self):
 '''Causes the next access to reread the dirstate.
@@ -1399,3 +1357,47 @@
 def setparents(self, p1, p2):
 self._parents = (p1, p2)
 self._dirtyparents = True
+
+def read(self):
+try:
+fp = self._opendirstatefile()
+try:
+st = fp.read()
+finally:
+fp.close()
+except IOError as err:
+if err.errno != errno.ENOENT:
+raise
+return
+if not st:
+return
+
+if util.safehasattr(parsers, 'dict_new_presized'):
+# Make an estimate of the number of files in the dirstate based on
+# its size. From a linear regression on a set of real-world repos,
+# all over 10,000 files, the size of a dirstate entry is 85
+# bytes. The cost of resizing is significantly higher than the cost
+# of filling in a larger presized dict, so subtract 20% from the
+# size.
+#
+# This heuristic is imperfect in many ways, so in a future dirstate
+# format update it makes sense to just record the number of entries
+# on write.
+self._map = parsers.dict_new_presized(len(st) / 71)
+
+# Python's garbage collector triggers a GC each time a certain number
+# of container objects (the number being defined by
+# gc.get_threshold()) are allocated. parse_dirstate creates a tuple
+# for each file in the dirstate. The C version then immediately marks
+# them as not to be tracked by the collector. However, this has no
+# effect on when GCs are triggered, only on what objects the GC looks
+# into. This means that O(number of files) GCs are unavoidable.
+# Depending on when in the process's lifetime the dirstate is parsed,
+# this can get very expensive. As a workaround, disable GC while
+# parsing the 

D980: dirstate: move identity to dirstatemap

2017-10-13 Thread durham (Durham Goode)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGc6ef9a2498a5: dirstate: move identity to dirstatemap 
(authored by durham, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D980?vs=2510=2709

REVISION DETAIL
  https://phab.mercurial-scm.org/D980

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -133,11 +133,6 @@
 return self._map
 
 @propertycache
-def _identity(self):
-self._read()
-return self._identity
-
-@propertycache
 def _filefoldmap(self):
 return self._map.filefoldmap()
 
@@ -375,9 +370,6 @@
 raise
 
 def _read(self):
-# ignore HG_PENDING because identity is used only for writing
-self._identity = util.filestat.frompath(
-self._opener.join(self._filename))
 self._map = dirstatemap(self._ui, self._opener, self._root)
 self._map.read()
 
@@ -388,8 +380,7 @@
 rereads the dirstate. Use localrepo.invalidatedirstate() if you want to
 check whether the dirstate has changed before rereading it.'''
 
-for a in ("_map", "_identity",
-  "_filefoldmap", "_dirfoldmap", "_branch",
+for a in ("_map", "_filefoldmap", "_dirfoldmap", "_branch",
   "_dirs", "_ignore"):
 if a in self.__dict__:
 delattr(self, a)
@@ -652,7 +643,7 @@
 If identity of previous dirstate is equal to this, writing
 changes based on the former dirstate out can keep consistency.
 '''
-return self._identity
+return self._map.identity
 
 def write(self, tr):
 if not self._dirty:
@@ -1342,6 +1333,10 @@
 self._dirtyparents = True
 
 def read(self):
+# ignore HG_PENDING because identity is used only for writing
+self.identity = util.filestat.frompath(
+self._opener.join(self._filename))
+
 try:
 fp = self._opendirstatefile()
 try:
@@ -1404,3 +1399,8 @@
 self.nonnormalset = nonnorm
 return otherparents
 
+@propertycache
+def identity(self):
+self.read()
+return self.identity
+



To: durham, #hg-reviewers, quark, durin42
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D960: bundle2: immediate exit for ctrl+c (issue5692)

2017-10-11 Thread durham (Durham Goode)
durham added inline comments.

INLINE COMMENTS

> yuja wrote in bundle2.py:380
> SignalInterrupt is a subclass of KeyboardInterrupt, so there might
> be deeper problem.
> 
> FWIW, I think it's probably a good idea to replace this blacklist
> with `isinstance(exc, Exception)`.

Before my refactor there used to be two levels of error handling, 1) inside 
_parthandler which tried to seek to the end if it wasn't systemexit or 
keyboardinterrup, and 2) inside processbundle (which calls _parthandler) which 
only caught type Exception.

It seems like the correct unification of these would be to just keep the 
`isinstance(exc, Exception)` check above, and delete this sub-check entirely.  
I'll send an update.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D960

To: durham, #hg-reviewers, quark
Cc: yuja, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D945: fsmonitor: update to match new dirstate refactor

2017-10-11 Thread durham (Durham Goode)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG7259f0ddfc0f: fsmonitor: update to match new dirstate 
refactor (authored by durham, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D945?vs=2536=2583

REVISION DETAIL
  https://phab.mercurial-scm.org/D945

AFFECTED FILES
  hgext/fsmonitor/__init__.py

CHANGE DETAILS

diff --git a/hgext/fsmonitor/__init__.py b/hgext/fsmonitor/__init__.py
--- a/hgext/fsmonitor/__init__.py
+++ b/hgext/fsmonitor/__init__.py
@@ -251,7 +251,7 @@
 
 matchfn = match.matchfn
 matchalways = match.always()
-dmap = self._map
+dmap = self._map._map
 nonnormalset = getattr(self, '_nonnormalset', None)
 
 copymap = self._map.copymap



To: durham, #hg-reviewers, quark, yuja, ryanmce
Cc: ryanmce, yuja, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D981: dirstate: remove _filefoldmap property cache

2017-10-06 Thread durham (Durham Goode)
durham created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  Now that the filefoldmap is source of truthed on the dirstatemap, let's get 
rid
  of the property cache on the dirstate.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D981

AFFECTED FILES
  contrib/perf.py
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -133,10 +133,6 @@
 return self._map
 
 @propertycache
-def _filefoldmap(self):
-return self._map.filefoldmap()
-
-@propertycache
 def _dirfoldmap(self):
 f = {}
 normcase = util.normcase
@@ -380,7 +376,7 @@
 rereads the dirstate. Use localrepo.invalidatedirstate() if you want to
 check whether the dirstate has changed before rereading it.'''
 
-for a in ("_map", "_filefoldmap", "_dirfoldmap", "_branch",
+for a in ("_map", "_dirfoldmap", "_branch",
   "_dirs", "_ignore"):
 if a in self.__dict__:
 delattr(self, a)
@@ -412,10 +408,10 @@
 if self[f] not in "?r" and "_dirs" in self.__dict__:
 self._dirs.delpath(f)
 
-if "_filefoldmap" in self.__dict__:
+if "filefoldmap" in self._map.__dict__:
 normed = util.normcase(f)
-if normed in self._filefoldmap:
-del self._filefoldmap[normed]
+if normed in self._map.filefoldmap:
+del self._map.filefoldmap[normed]
 
 self._updatedfiles.add(f)
 
@@ -563,18 +559,18 @@
 
 def _normalizefile(self, path, isknown, ignoremissing=False, exists=None):
 normed = util.normcase(path)
-folded = self._filefoldmap.get(normed, None)
+folded = self._map.filefoldmap.get(normed, None)
 if folded is None:
 if isknown:
 folded = path
 else:
 folded = self._discoverpath(path, normed, ignoremissing, 
exists,
-self._filefoldmap)
+self._map.filefoldmap)
 return folded
 
 def _normalize(self, path, isknown, ignoremissing=False, exists=None):
 normed = util.normcase(path)
-folded = self._filefoldmap.get(normed, None)
+folded = self._map.filefoldmap.get(normed, None)
 if folded is None:
 folded = self._dirfoldmap.get(normed, None)
 if folded is None:
@@ -1270,6 +1266,7 @@
 otherparent.add(fname)
 return nonnorm, otherparent
 
+@propertycache
 def filefoldmap(self):
 """Returns a dictionary mapping normalized case paths to their
 non-normalized versions.
diff --git a/contrib/perf.py b/contrib/perf.py
--- a/contrib/perf.py
+++ b/contrib/perf.py
@@ -539,8 +539,8 @@
 dirstate = repo.dirstate
 'a' in dirstate
 def d():
-dirstate._filefoldmap.get('a')
-del dirstate._filefoldmap
+dirstate._map.filefoldmap.get('a')
+del dirstate._map.filefoldmap
 timer(d)
 fm.end()
 



To: durham, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D982: dirstate: remove _dirs property cache

2017-10-06 Thread durham (Durham Goode)
durham created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  Now that dirs is source of truthed on the dirstatemap, let's get rid of the
  _dirs propertycache on the dirstate.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D982

AFFECTED FILES
  contrib/perf.py
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -136,7 +136,7 @@
 def _dirfoldmap(self):
 f = {}
 normcase = util.normcase
-for name in self._dirs:
+for name in self._map.dirs:
 f[normcase(name)] = name
 return f
 
@@ -166,12 +166,8 @@
 def _pl(self):
 return self._map.parents()
 
-@propertycache
-def _dirs(self):
-return self._map.dirs()
-
 def dirs(self):
-return self._dirs
+return self._map.dirs
 
 @rootcache('.hgignore')
 def _ignore(self):
@@ -377,7 +373,7 @@
 check whether the dirstate has changed before rereading it.'''
 
 for a in ("_map", "_dirfoldmap", "_branch",
-  "_dirs", "_ignore"):
+  "_ignore"):
 if a in self.__dict__:
 delattr(self, a)
 self._lastnormaltime = 0
@@ -405,8 +401,8 @@
 return self._map.copymap
 
 def _droppath(self, f):
-if self[f] not in "?r" and "_dirs" in self.__dict__:
-self._dirs.delpath(f)
+if self[f] not in "?r" and "dirs" in self._map.__dict__:
+self._map.dirs.delpath(f)
 
 if "filefoldmap" in self._map.__dict__:
 normed = util.normcase(f)
@@ -419,18 +415,18 @@
 oldstate = self[f]
 if state == 'a' or oldstate == 'r':
 scmutil.checkfilename(f)
-if f in self._dirs:
+if f in self._map.dirs:
 raise error.Abort(_('directory %r already in dirstate') % f)
 # shadows
 for d in util.finddirs(f):
-if d in self._dirs:
+if d in self._map.dirs:
 break
 entry = self._map.get(d)
 if entry is not None and entry[0] != 'r':
 raise error.Abort(
 _('file %r in dirstate clashes with %r') % (d, f))
-if oldstate in "?r" and "_dirs" in self.__dict__:
-self._dirs.addpath(f)
+if oldstate in "?r" and "dirs" in self._map.__dict__:
+self._map.dirs.addpath(f)
 self._dirty = True
 self._updatedfiles.add(f)
 self._map[f] = dirstatetuple(state, mode, size, mtime)
@@ -607,8 +603,6 @@
 
 def clear(self):
 self._map = dirstatemap(self._ui, self._opener, self._root)
-if "_dirs" in self.__dict__:
-delattr(self, "_dirs")
 self._map.setparents(nullid, nullid)
 self._lastnormaltime = 0
 self._updatedfiles.clear()
@@ -1287,6 +1281,7 @@
 f['.'] = '.' # prevents useless util.fspath() invocation
 return f
 
+@propertycache
 def dirs(self):
 """Returns a set-like object containing all the directories in the
 current dirstate.
diff --git a/contrib/perf.py b/contrib/perf.py
--- a/contrib/perf.py
+++ b/contrib/perf.py
@@ -509,7 +509,7 @@
 'a' in dirstate
 def d():
 dirstate.dirs()
-del dirstate._dirs
+del dirstate._map.dirs
 timer(d)
 fm.end()
 
@@ -528,8 +528,8 @@
 timer, fm = gettimer(ui, opts)
 "a" in repo.dirstate
 def d():
-"a" in repo.dirstate._dirs
-del repo.dirstate._dirs
+"a" in repo.dirstate._map.dirs
+del repo.dirstate._map.dirs
 timer(d)
 fm.end()
 
@@ -552,7 +552,7 @@
 def d():
 dirstate._dirfoldmap.get('a')
 del dirstate._dirfoldmap
-del dirstate._dirs
+del dirstate._map.dirs
 timer(d)
 fm.end()
 



To: durham, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D983: dirstate: move the _dirfoldmap to dirstatemap

2017-10-06 Thread durham (Durham Goode)
durham created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  Now that dirstatemap is the source of truth for the list of directories, let's
  move _dirfoldmap on to it.
  
  This pattern of moving cached variables onto the dirstate map makes it easier 
to
  invalidate them, as seen by how the cache invalidation functions are slowly
  shrinking to just be recreating the dirstatemap instance.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D983

AFFECTED FILES
  contrib/perf.py
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -132,14 +132,6 @@
 self._read()
 return self._map
 
-@propertycache
-def _dirfoldmap(self):
-f = {}
-normcase = util.normcase
-for name in self._map.dirs:
-f[normcase(name)] = name
-return f
-
 @property
 def _sparsematcher(self):
 """The matcher for the sparse checkout.
@@ -372,8 +364,7 @@
 rereads the dirstate. Use localrepo.invalidatedirstate() if you want to
 check whether the dirstate has changed before rereading it.'''
 
-for a in ("_map", "_dirfoldmap", "_branch",
-  "_ignore"):
+for a in ("_map", "_branch", "_ignore"):
 if a in self.__dict__:
 delattr(self, a)
 self._lastnormaltime = 0
@@ -568,15 +559,15 @@
 normed = util.normcase(path)
 folded = self._map.filefoldmap.get(normed, None)
 if folded is None:
-folded = self._dirfoldmap.get(normed, None)
+folded = self._map.dirfoldmap.get(normed, None)
 if folded is None:
 if isknown:
 folded = path
 else:
 # store discovered result in dirfoldmap so that future
 # normalizefile calls don't start matching directories
 folded = self._discoverpath(path, normed, ignoremissing, 
exists,
-self._dirfoldmap)
+self._map.dirfoldmap)
 return folded
 
 def normalize(self, path, isknown=False, ignoremissing=False):
@@ -875,7 +866,7 @@
 if len(paths) > 1:
 for path in paths:
 folded = self._discoverpath(path, norm, True, None,
-self._dirfoldmap)
+self._map.dirfoldmap)
 if path != folded:
 results[path] = None
 
@@ -1396,3 +1387,10 @@
 self.read()
 return self.identity
 
+@propertycache
+def dirfoldmap(self):
+f = {}
+normcase = util.normcase
+for name in self.dirs:
+f[normcase(name)] = name
+return f
diff --git a/contrib/perf.py b/contrib/perf.py
--- a/contrib/perf.py
+++ b/contrib/perf.py
@@ -550,8 +550,8 @@
 dirstate = repo.dirstate
 'a' in dirstate
 def d():
-dirstate._dirfoldmap.get('a')
-del dirstate._dirfoldmap
+dirstate._map.dirfoldmap.get('a')
+del dirstate._map.dirfoldmap
 del dirstate._map.dirs
 timer(d)
 fm.end()



To: durham, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D979: dirstate: move nonnormal and otherparent sets to dirstatemap

2017-10-06 Thread durham (Durham Goode)
durham created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  As part of separating dirstate business logic from storage, let's move the
  nonnormal and otherparent storage to the dirstatemap class. This will allow
  alternative dirstate storage to persist these sets instead of recomputing 
them.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D979

AFFECTED FILES
  contrib/dirstatenonnormalcheck.py
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -138,18 +138,6 @@
 return self._identity
 
 @propertycache
-def _nonnormalset(self):
-nonnorm, otherparents = self._map.nonnormalentries()
-self._otherparentset = otherparents
-return nonnorm
-
-@propertycache
-def _otherparentset(self):
-nonnorm, otherparents = self._map.nonnormalentries()
-self._nonnormalset = nonnorm
-return otherparents
-
-@propertycache
 def _filefoldmap(self):
 return self._map.filefoldmap()
 
@@ -349,7 +337,8 @@
 self._map.setparents(p1, p2)
 copies = {}
 if oldp2 != nullid and p2 == nullid:
-candidatefiles = self._nonnormalset.union(self._otherparentset)
+candidatefiles = self._map.nonnormalset.union(
+self._map.otherparentset)
 for f in candidatefiles:
 s = self._map.get(f)
 if s is None:
@@ -401,8 +390,7 @@
 
 for a in ("_map", "_identity",
   "_filefoldmap", "_dirfoldmap", "_branch",
-  "_dirs", "_ignore", "_nonnormalset",
-  "_otherparentset"):
+  "_dirs", "_ignore"):
 if a in self.__dict__:
 delattr(self, a)
 self._lastnormaltime = 0
@@ -460,19 +448,19 @@
 self._updatedfiles.add(f)
 self._map[f] = dirstatetuple(state, mode, size, mtime)
 if state != 'n' or mtime == -1:
-self._nonnormalset.add(f)
+self._map.nonnormalset.add(f)
 if size == -2:
-self._otherparentset.add(f)
+self._map.otherparentset.add(f)
 
 def normal(self, f):
 '''Mark a file normal and clean.'''
 s = os.lstat(self._join(f))
 mtime = s.st_mtime
 self._addpath(f, 'n', s.st_mode,
   s.st_size & _rangemask, mtime & _rangemask)
 self._map.copymap.pop(f, None)
-if f in self._nonnormalset:
-self._nonnormalset.remove(f)
+if f in self._map.nonnormalset:
+self._map.nonnormalset.remove(f)
 if mtime > self._lastnormaltime:
 # Remember the most recent modification timeslot for status(),
 # to make sure we won't miss future size-preserving file content
@@ -500,8 +488,8 @@
 return
 self._addpath(f, 'n', 0, -1, -1)
 self._map.copymap.pop(f, None)
-if f in self._nonnormalset:
-self._nonnormalset.remove(f)
+if f in self._map.nonnormalset:
+self._map.nonnormalset.remove(f)
 
 def otherparent(self, f):
 '''Mark as coming from the other parent, always dirty.'''
@@ -534,9 +522,9 @@
 size = -1
 elif entry[0] == 'n' and entry[2] == -2: # other parent
 size = -2
-self._otherparentset.add(f)
+self._map.otherparentset.add(f)
 self._map[f] = dirstatetuple('r', 0, size, 0)
-self._nonnormalset.add(f)
+self._map.nonnormalset.add(f)
 if size == 0:
 self._map.copymap.pop(f, None)
 
@@ -552,8 +540,8 @@
 self._dirty = True
 self._droppath(f)
 del self._map[f]
-if f in self._nonnormalset:
-self._nonnormalset.remove(f)
+if f in self._map.nonnormalset:
+self._map.nonnormalset.remove(f)
 self._map.copymap.pop(f, None)
 
 def _discoverpath(self, path, normed, ignoremissing, exists, storemap):
@@ -632,8 +620,6 @@
 
 def clear(self):
 self._map = dirstatemap(self._ui, self._opener, self._root)
-self._nonnormalset = set()
-self._otherparentset = set()
 if "_dirs" in self.__dict__:
 delattr(self, "_dirs")
 self._map.setparents(nullid, nullid)
@@ -687,7 +673,7 @@
 e = dmap.get(f)
 if e is not None and e[0] == 'n' and e[3] == now:
 dmap[f] = dirstatetuple(e[0], e[1], e[2], -1)
-self._nonnormalset.add(f)
+self._map.nonnormalset.add(f)
 
 # emulate that all 'dirstate.normal' results are written out
 self._lastnormaltime = 0
@@ -740,7 +726,6 @@
 break
 
 

D980: dirstate: move identity to dirstatemap

2017-10-06 Thread durham (Durham Goode)
durham created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  Moving the identity function to the dirstatemap class will allow alternative
  dirstate implementations to replace the implementation.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D980

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -133,11 +133,6 @@
 return self._map
 
 @propertycache
-def _identity(self):
-self._read()
-return self._identity
-
-@propertycache
 def _filefoldmap(self):
 return self._map.filefoldmap()
 
@@ -375,9 +370,6 @@
 raise
 
 def _read(self):
-# ignore HG_PENDING because identity is used only for writing
-self._identity = util.filestat.frompath(
-self._opener.join(self._filename))
 self._map = dirstatemap(self._ui, self._opener, self._root)
 self._map.read()
 
@@ -388,8 +380,7 @@
 rereads the dirstate. Use localrepo.invalidatedirstate() if you want to
 check whether the dirstate has changed before rereading it.'''
 
-for a in ("_map", "_identity",
-  "_filefoldmap", "_dirfoldmap", "_branch",
+for a in ("_map", "_filefoldmap", "_dirfoldmap", "_branch",
   "_dirs", "_ignore"):
 if a in self.__dict__:
 delattr(self, a)
@@ -652,7 +643,7 @@
 If identity of previous dirstate is equal to this, writing
 changes based on the former dirstate out can keep consistency.
 '''
-return self._identity
+return self._map.identity
 
 def write(self, tr):
 if not self._dirty:
@@ -1342,6 +1333,10 @@
 self._dirtyparents = True
 
 def read(self):
+# ignore HG_PENDING because identity is used only for writing
+self.identity = util.filestat.frompath(
+self._opener.join(self._filename))
+
 try:
 fp = self._opendirstatefile()
 try:
@@ -1404,3 +1399,8 @@
 self.nonnormalset = nonnorm
 return otherparents
 
+@propertycache
+def identity(self):
+self.read()
+return self.identity
+



To: durham, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D978: dirstate: move write into dirstatemap

2017-10-06 Thread durham (Durham Goode)
durham created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  As part of separating the dirstate business logic from the dirstate storage
  logic, let's move the serialization code down into dirstatemap.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D978

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -739,12 +739,10 @@
 now = end # trust our estimate that the end is near now
 break
 
-st.write(parsers.pack_dirstate(self._map._map, self._map.copymap,
-   self._pl, now))
+self._map.write(st, now)
 self._nonnormalset, self._otherparentset = self._map.nonnormalentries()
-st.close()
 self._lastnormaltime = 0
-self._dirty = self._map._dirtyparents = False
+self._dirty = False
 
 def _dirignore(self, f):
 if f == '.':
@@ -1401,3 +1399,9 @@
 p = parse_dirstate(self._map, self.copymap, st)
 if not self._dirtyparents:
 self.setparents(*p)
+
+def write(self, st, now):
+st.write(parsers.pack_dirstate(self._map, self.copymap,
+   self.parents(), now))
+st.close()
+self._dirtyparents = False



To: durham, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D960: bundle2: immediate exit for ctrl+c (issue5692)

2017-10-05 Thread durham (Durham Goode)
durham created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  https://phab.mercurial-scm.org/rHG21c2df59a1dad534bfac45acc0bbfb6cb2afe9b4 
regressed bundle2 by catching all exceptions and trying to handle
  them. The old behavior was to allow KeyboardInterrupts to throw and not have
  graceful cleanup, which allowed it to exit immediately. Let's go back to that
  behavior.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D960

AFFECTED FILES
  mercurial/bundle2.py

CHANGE DETAILS

diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -370,7 +370,10 @@
 if not self.iterator:
 return
 
-if exc:
+# Only gracefully abort in a normal exception situation. User aborts
+# like Ctrl+C throw a KeyboardInterrupt which is not a base Exception,
+# and should not gracefully cleanup.
+if isinstance(exc, Exception):
 # If exiting or interrupted, do not attempt to seek the stream in
 # the finally block below. This makes abort faster.
 if (self.current and



To: durham, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH phase] exchange: fix test for remote support of binary phases

2017-10-04 Thread Durham Goode

On 9/30/17 6:26 AM, Yuya Nishihara wrote:

On Sat, 30 Sep 2017 16:01:36 +0530, Pulkit Goyal wrote:

I don't see the traceback after applying this patch. If possible, this
patch should be folded with the previous series.

On Sat, Sep 30, 2017 at 3:05 PM, Boris Feld  wrote:

# HG changeset patch
# User Boris Feld 
# Date 1506762569 -3600
#  Sat Sep 30 10:09:29 2017 +0100
# Node ID 4d26dbcdfdb38fd3fc4efa157b64819f5281c8e0
# Parent  ec769bba34d377503f42308dea5ddcb8ce4c0ade
# EXP-Topic fix-phases
exchange: fix test for remote support of binary phases


Queued, thanks.


Should there be a test to cover this case?
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D945: fsmonitor: update to match new dirstate refactor

2017-10-04 Thread durham (Durham Goode)
durham created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  The dirstate was refactored so dirstate._map is now at dirstate._map._map. 
Same
  for _copymap, is not _map.copymap. It seems none of the mercurial tests cover
  this stuff, but it was caught by our Facebook extension tests.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D945

AFFECTED FILES
  hgext/fsmonitor/__init__.py

CHANGE DETAILS

diff --git a/hgext/fsmonitor/__init__.py b/hgext/fsmonitor/__init__.py
--- a/hgext/fsmonitor/__init__.py
+++ b/hgext/fsmonitor/__init__.py
@@ -228,10 +228,10 @@
 
 matchfn = match.matchfn
 matchalways = match.always()
-dmap = self._map
+dmap = self._map._map
 nonnormalset = getattr(self, '_nonnormalset', None)
 
-copymap = self._copymap
+copymap = self._map.copymap
 getkind = stat.S_IFMT
 dirkind = stat.S_IFDIR
 regkind = stat.S_IFREG



To: durham, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D759: dirstate: move parents source of truth to dirstatemap

2017-09-29 Thread durham (Durham Goode)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG5fabba9b3d9c: dirstate: move parents source of truth to 
dirstatemap (authored by durham, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D759?vs=2083=2162

REVISION DETAIL
  https://phab.mercurial-scm.org/D759

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -71,7 +71,6 @@
 # UNC path pointing to root share (issue4557)
 self._rootdir = pathutil.normasprefix(root)
 self._dirty = False
-self._dirtypl = False
 self._lastnormaltime = 0
 self._ui = ui
 self._filecache = {}
@@ -184,7 +183,7 @@
 raise
 return "default"
 
-@propertycache
+@property
 def _pl(self):
 return self._map.parents()
 
@@ -343,11 +342,11 @@
 raise ValueError("cannot set dirstate parent without "
  "calling dirstate.beginparentchange")
 
-self._dirty = self._dirtypl = True
+self._dirty = True
 oldp2 = self._pl[1]
 if self._origpl is None:
 self._origpl = self._pl
-self._pl = p1, p2
+self._map.setparents(p1, p2)
 copies = {}
 if oldp2 != nullid and p2 == nullid:
 candidatefiles = self._nonnormalset.union(self._otherparentset)
@@ -432,8 +431,8 @@
 # (we cannot decorate the function directly since it is in a C module)
 parse_dirstate = util.nogc(parsers.parse_dirstate)
 p = parse_dirstate(self._map._map, self._map.copymap, st)
-if not self._dirtypl:
-self._pl = p
+if not self._map._dirtyparents:
+self._map.setparents(*p)
 
 def invalidate(self):
 '''Causes the next access to reread the dirstate.
@@ -444,7 +443,7 @@
 
 for a in ("_map", "_identity",
   "_filefoldmap", "_dirfoldmap", "_branch",
-  "_pl", "_dirs", "_ignore", "_nonnormalset",
+  "_dirs", "_ignore", "_nonnormalset",
   "_otherparentset"):
 if a in self.__dict__:
 delattr(self, a)
@@ -679,7 +678,7 @@
 self._otherparentset = set()
 if "_dirs" in self.__dict__:
 delattr(self, "_dirs")
-self._pl = [nullid, nullid]
+self._map.setparents(nullid, nullid)
 self._lastnormaltime = 0
 self._updatedfiles.clear()
 self._dirty = True
@@ -694,7 +693,7 @@
 
 if self._origpl is None:
 self._origpl = self._pl
-self._pl = (parent, nullid)
+self._map.setparents(parent, nullid)
 for f in changedfiles:
 if f in allfiles:
 self.normallookup(f)
@@ -787,7 +786,7 @@
 self._nonnormalset, self._otherparentset = self._map.nonnormalentries()
 st.close()
 self._lastnormaltime = 0
-self._dirty = self._dirtypl = False
+self._dirty = self._map._dirtyparents = False
 
 def _dirignore(self, f):
 if f == '.':
@@ -1292,6 +1291,8 @@
 
 self._map = {}
 self.copymap = {}
+self._parents = None
+self._dirtyparents = False
 
 # for consistent view between _pl() and _read() invocations
 self._pendingmode = None
@@ -1370,16 +1371,28 @@
 return fp
 
 def parents(self):
-try:
-fp = self._opendirstatefile()
-st = fp.read(40)
-fp.close()
+if not self._parents:
+try:
+fp = self._opendirstatefile()
+st = fp.read(40)
+fp.close()
+except IOError as err:
+if err.errno != errno.ENOENT:
+raise
+# File doesn't exist, so the current state is empty
+st = ''
+
 l = len(st)
 if l == 40:
-return st[:20], st[20:40]
-elif l > 0 and l < 40:
-raise error.Abort(_('working directory state appears 
damaged!'))
-except IOError as err:
-if err.errno != errno.ENOENT:
-raise
-return [nullid, nullid]
+self._parents = st[:20], st[20:40]
+elif l == 0:
+self._parents = [nullid, nullid]
+else:
+raise error.Abort(_('working directory state appears '
+'damaged!'))
+
+return self._parents
+
+def setparents(self, p1, p2):
+self._parents = (p1, p2)
+self._dirtyparents = True



To: durham, #hg-reviewers, indygreg
Cc: indygreg, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel

D754: dirstate: move filefoldmap to dirstatemap

2017-09-29 Thread durham (Durham Goode)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG19a5ad535cb1: dirstate: move filefoldmap to dirstatemap 
(authored by durham, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D754?vs=2078=2157

REVISION DETAIL
  https://phab.mercurial-scm.org/D754

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -160,21 +160,7 @@
 
 @propertycache
 def _filefoldmap(self):
-try:
-makefilefoldmap = parsers.make_file_foldmap
-except AttributeError:
-pass
-else:
-return makefilefoldmap(self._map._map, util.normcasespec,
-   util.normcasefallback)
-
-f = {}
-normcase = util.normcase
-for name, s in self._map.iteritems():
-if s[0] != 'r':
-f[normcase(name)] = name
-f['.'] = '.' # prevents useless util.fspath() invocation
-return f
+return self._map.filefoldmap()
 
 @propertycache
 def _dirfoldmap(self):
@@ -1370,3 +1356,22 @@
 otherparent.add(fname)
 return nonnorm, otherparent
 
+def filefoldmap(self):
+"""Returns a dictionary mapping normalized case paths to their
+non-normalized versions.
+"""
+try:
+makefilefoldmap = parsers.make_file_foldmap
+except AttributeError:
+pass
+else:
+return makefilefoldmap(self._map, util.normcasespec,
+   util.normcasefallback)
+
+f = {}
+normcase = util.normcase
+for name, s in self._map.iteritems():
+if s[0] != 'r':
+f[normcase(name)] = name
+f['.'] = '.' # prevents useless util.fspath() invocation
+return f



To: durham, #hg-reviewers, indygreg
Cc: indygreg, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D758: dirstate: move parent reading to the dirstatemap class

2017-09-29 Thread durham (Durham Goode)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG949276a8cd76: dirstate: move parent reading to the 
dirstatemap class (authored by durham, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D758?vs=2082=2161

REVISION DETAIL
  https://phab.mercurial-scm.org/D758

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -186,19 +186,7 @@
 
 @propertycache
 def _pl(self):
-try:
-fp = self._map._opendirstatefile()
-st = fp.read(40)
-fp.close()
-l = len(st)
-if l == 40:
-return st[:20], st[20:40]
-elif l > 0 and l < 40:
-raise error.Abort(_('working directory state appears 
damaged!'))
-except IOError as err:
-if err.errno != errno.ENOENT:
-raise
-return [nullid, nullid]
+return self._map.parents()
 
 @propertycache
 def _dirs(self):
@@ -1381,3 +1369,17 @@
 self._pendingmode = mode
 return fp
 
+def parents(self):
+try:
+fp = self._opendirstatefile()
+st = fp.read(40)
+fp.close()
+l = len(st)
+if l == 40:
+return st[:20], st[20:40]
+elif l > 0 and l < 40:
+raise error.Abort(_('working directory state appears 
damaged!'))
+except IOError as err:
+if err.errno != errno.ENOENT:
+raise
+return [nullid, nullid]



To: durham, #hg-reviewers, indygreg
Cc: indygreg, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D752: dirstate: create new dirstatemap class

2017-09-29 Thread durham (Durham Goode)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG42b68c9c2742: dirstate: create new dirstatemap class 
(authored by durham, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D752?vs=1947=2155

REVISION DETAIL
  https://phab.mercurial-scm.org/D752

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -57,7 +57,7 @@
 def nonnormalentries(dmap):
 '''Compute the nonnormal dirstate entries from the dmap'''
 try:
-return parsers.nonnormalotherparententries(dmap)
+return parsers.nonnormalotherparententries(dmap._map)
 except AttributeError:
 nonnorm = set()
 otherparent = set()
@@ -179,7 +179,7 @@
 except AttributeError:
 pass
 else:
-return makefilefoldmap(self._map, util.normcasespec,
+return makefilefoldmap(self._map._map, util.normcasespec,
util.normcasefallback)
 
 f = {}
@@ -238,7 +238,7 @@
 
 @propertycache
 def _dirs(self):
-return util.dirs(self._map, 'r')
+return util.dirs(self._map._map, 'r')
 
 def dirs(self):
 return self._dirs
@@ -444,7 +444,8 @@
 return fp
 
 def _read(self):
-self._map = {}
+self._map = dirstatemap()
+
 self._copymap = {}
 # ignore HG_PENDING because identity is used only for writing
 self._identity = util.filestat.frompath(
@@ -473,7 +474,7 @@
 # This heuristic is imperfect in many ways, so in a future dirstate
 # format update it makes sense to just record the number of entries
 # on write.
-self._map = parsers.dict_new_presized(len(st) / 71)
+self._map._map = parsers.dict_new_presized(len(st) / 71)
 
 # Python's garbage collector triggers a GC each time a certain number
 # of container objects (the number being defined by
@@ -488,7 +489,7 @@
 #
 # (we cannot decorate the function directly since it is in a C module)
 parse_dirstate = util.nogc(parsers.parse_dirstate)
-p = parse_dirstate(self._map, self._copymap, st)
+p = parse_dirstate(self._map._map, self._copymap, st)
 if not self._dirtypl:
 self._pl = p
 
@@ -731,7 +732,7 @@
 return path
 
 def clear(self):
-self._map = {}
+self._map = dirstatemap()
 self._nonnormalset = set()
 self._otherparentset = set()
 if "_dirs" in self.__dict__:
@@ -840,7 +841,8 @@
 now = end # trust our estimate that the end is near now
 break
 
-st.write(parsers.pack_dirstate(self._map, self._copymap, self._pl, 
now))
+st.write(parsers.pack_dirstate(self._map._map, self._copymap, self._pl,
+   now))
 self._nonnormalset, self._otherparentset = nonnormalentries(self._map)
 st.close()
 self._lastnormaltime = 0
@@ -979,7 +981,7 @@
 results[nf] = None
 else: # does it match a missing directory?
 if alldirs is None:
-alldirs = util.dirs(dmap)
+alldirs = util.dirs(dmap._map)
 if nf in alldirs:
 if matchedir:
 matchedir(nf)
@@ -1339,3 +1341,31 @@
 def clearbackup(self, tr, backupname):
 '''Clear backup file'''
 self._opener.unlink(backupname)
+
+class dirstatemap(object):
+def __init__(self):
+self._map = {}
+
+def iteritems(self):
+return self._map.iteritems()
+
+def __iter__(self):
+return iter(self._map)
+
+def get(self, key, default=None):
+return self._map.get(key, default)
+
+def __contains__(self, key):
+return key in self._map
+
+def __setitem__(self, key, value):
+self._map[key] = value
+
+def __getitem__(self, key):
+return self._map[key]
+
+def __delitem__(self, key):
+del self._map[key]
+
+def keys(self):
+return self._map.keys()



To: durham, #hg-reviewers, indygreg
Cc: indygreg, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D757: dirstate: move opendirstatefile to dirstatemap

2017-09-29 Thread durham (Durham Goode)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG0407c611b7be: dirstate: move opendirstatefile to 
dirstatemap (authored by durham, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D757?vs=2081=2160

REVISION DETAIL
  https://phab.mercurial-scm.org/D757

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -82,9 +82,6 @@
 self._origpl = None
 self._updatedfiles = set()
 
-# for consistent view between _pl() and _read() invocations
-self._pendingmode = None
-
 @contextlib.contextmanager
 def parentchange(self):
 '''Context manager for handling dirstate parents.
@@ -190,7 +187,7 @@
 @propertycache
 def _pl(self):
 try:
-fp = self._opendirstatefile()
+fp = self._map._opendirstatefile()
 st = fp.read(40)
 fp.close()
 l = len(st)
@@ -401,23 +398,14 @@
 f.discard()
 raise
 
-def _opendirstatefile(self):
-fp, mode = txnutil.trypending(self._root, self._opener, self._filename)
-if self._pendingmode is not None and self._pendingmode != mode:
-fp.close()
-raise error.Abort(_('working directory state may be '
-'changed parallelly'))
-self._pendingmode = mode
-return fp
-
 def _read(self):
-self._map = dirstatemap()
+self._map = dirstatemap(self._ui, self._opener, self._root)
 
 # ignore HG_PENDING because identity is used only for writing
 self._identity = util.filestat.frompath(
 self._opener.join(self._filename))
 try:
-fp = self._opendirstatefile()
+fp = self._map._opendirstatefile()
 try:
 st = fp.read()
 finally:
@@ -698,7 +686,7 @@
 return path
 
 def clear(self):
-self._map = dirstatemap()
+self._map = dirstatemap(self._ui, self._opener, self._root)
 self._nonnormalset = set()
 self._otherparentset = set()
 if "_dirs" in self.__dict__:
@@ -1308,10 +1296,18 @@
 self._opener.unlink(backupname)
 
 class dirstatemap(object):
-def __init__(self):
+def __init__(self, ui, opener, root):
+self._ui = ui
+self._opener = opener
+self._root = root
+self._filename = 'dirstate'
+
 self._map = {}
 self.copymap = {}
 
+# for consistent view between _pl() and _read() invocations
+self._pendingmode = None
+
 def iteritems(self):
 return self._map.iteritems()
 
@@ -1375,3 +1371,13 @@
 current dirstate.
 """
 return util.dirs(self._map, 'r')
+
+def _opendirstatefile(self):
+fp, mode = txnutil.trypending(self._root, self._opener, self._filename)
+if self._pendingmode is not None and self._pendingmode != mode:
+fp.close()
+raise error.Abort(_('working directory state may be '
+'changed parallelly'))
+self._pendingmode = mode
+return fp
+



To: durham, #hg-reviewers, indygreg
Cc: indygreg, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D756: dirstate: move _copymap to dirstatemap

2017-09-29 Thread durham (Durham Goode)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG894cd88815ca: dirstate: move _copymap to dirstatemap 
(authored by durham, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D756?vs=2080=2159

REVISION DETAIL
  https://phab.mercurial-scm.org/D756

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -137,11 +137,6 @@
 return self._map
 
 @propertycache
-def _copymap(self):
-self._read()
-return self._copymap
-
-@propertycache
 def _identity(self):
 self._read()
 return self._identity
@@ -378,13 +373,13 @@
 
 # Discard 'm' markers when moving away from a merge state
 if s[0] == 'm':
-source = self._copymap.get(f)
+source = self._map.copymap.get(f)
 if source:
 copies[f] = source
 self.normallookup(f)
 # Also fix up otherparent markers
 elif s[0] == 'n' and s[2] == -2:
-source = self._copymap.get(f)
+source = self._map.copymap.get(f)
 if source:
 copies[f] = source
 self.add(f)
@@ -418,7 +413,6 @@
 def _read(self):
 self._map = dirstatemap()
 
-self._copymap = {}
 # ignore HG_PENDING because identity is used only for writing
 self._identity = util.filestat.frompath(
 self._opener.join(self._filename))
@@ -461,7 +455,7 @@
 #
 # (we cannot decorate the function directly since it is in a C module)
 parse_dirstate = util.nogc(parsers.parse_dirstate)
-p = parse_dirstate(self._map._map, self._copymap, st)
+p = parse_dirstate(self._map._map, self._map.copymap, st)
 if not self._dirtypl:
 self._pl = p
 
@@ -472,7 +466,7 @@
 rereads the dirstate. Use localrepo.invalidatedirstate() if you want to
 check whether the dirstate has changed before rereading it.'''
 
-for a in ("_map", "_copymap", "_identity",
+for a in ("_map", "_identity",
   "_filefoldmap", "_dirfoldmap", "_branch",
   "_pl", "_dirs", "_ignore", "_nonnormalset",
   "_otherparentset"):
@@ -490,17 +484,17 @@
 return
 self._dirty = True
 if source is not None:
-self._copymap[dest] = source
+self._map.copymap[dest] = source
 self._updatedfiles.add(source)
 self._updatedfiles.add(dest)
-elif self._copymap.pop(dest, None):
+elif self._map.copymap.pop(dest, None):
 self._updatedfiles.add(dest)
 
 def copied(self, file):
-return self._copymap.get(file, None)
+return self._map.copymap.get(file, None)
 
 def copies(self):
-return self._copymap
+return self._map.copymap
 
 def _droppath(self, f):
 if self[f] not in "?r" and "_dirs" in self.__dict__:
@@ -543,7 +537,7 @@
 mtime = s.st_mtime
 self._addpath(f, 'n', s.st_mode,
   s.st_size & _rangemask, mtime & _rangemask)
-self._copymap.pop(f, None)
+self._map.copymap.pop(f, None)
 if f in self._nonnormalset:
 self._nonnormalset.remove(f)
 if mtime > self._lastnormaltime:
@@ -561,7 +555,7 @@
 entry = self._map.get(f)
 if entry is not None:
 if entry[0] == 'r' and entry[2] in (-1, -2):
-source = self._copymap.get(f)
+source = self._map.copymap.get(f)
 if entry[2] == -1:
 self.merge(f)
 elif entry[2] == -2:
@@ -572,7 +566,7 @@
 if entry[0] == 'm' or entry[0] == 'n' and entry[2] == -2:
 return
 self._addpath(f, 'n', 0, -1, -1)
-self._copymap.pop(f, None)
+self._map.copymap.pop(f, None)
 if f in self._nonnormalset:
 self._nonnormalset.remove(f)
 
@@ -587,12 +581,12 @@
 else:
 # add-like
 self._addpath(f, 'n', 0, -2, -1)
-self._copymap.pop(f, None)
+self._map.copymap.pop(f, None)
 
 def add(self, f):
 '''Mark a file added.'''
 self._addpath(f, 'a', 0, -1, -1)
-self._copymap.pop(f, None)
+self._map.copymap.pop(f, None)
 
 def remove(self, f):
 '''Mark a file removed.'''
@@ -611,7 +605,7 @@
 self._map[f] = dirstatetuple('r', 0, size, 0)
 self._nonnormalset.add(f)
 if size == 0:
-self._copymap.pop(f, None)
+self._map.copymap.pop(f, None)
 
 def merge(self, f):
 '''Mark a file merged.'''
@@ -627,7 

D753: dirstate: move nonnormalentries to dirstatemap

2017-09-29 Thread durham (Durham Goode)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG362ed91ca00c: dirstate: move nonnormalentries to 
dirstatemap (authored by durham, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D753?vs=1948=2156

REVISION DETAIL
  https://phab.mercurial-scm.org/D753

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -54,20 +54,6 @@
 os.close(tmpfd)
 vfs.unlink(tmpname)
 
-def nonnormalentries(dmap):
-'''Compute the nonnormal dirstate entries from the dmap'''
-try:
-return parsers.nonnormalotherparententries(dmap._map)
-except AttributeError:
-nonnorm = set()
-otherparent = set()
-for fname, e in dmap.iteritems():
-if e[0] != 'n' or e[3] == -1:
-nonnorm.add(fname)
-if e[0] == 'n' and e[2] == -2:
-otherparent.add(fname)
-return nonnorm, otherparent
-
 class dirstate(object):
 
 def __init__(self, opener, ui, root, validate, sparsematchfn):
@@ -162,13 +148,13 @@
 
 @propertycache
 def _nonnormalset(self):
-nonnorm, otherparents = nonnormalentries(self._map)
+nonnorm, otherparents = self._map.nonnormalentries()
 self._otherparentset = otherparents
 return nonnorm
 
 @propertycache
 def _otherparentset(self):
-nonnorm, otherparents = nonnormalentries(self._map)
+nonnorm, otherparents = self._map.nonnormalentries()
 self._nonnormalset = nonnorm
 return otherparents
 
@@ -843,7 +829,7 @@
 
 st.write(parsers.pack_dirstate(self._map._map, self._copymap, self._pl,
now))
-self._nonnormalset, self._otherparentset = nonnormalentries(self._map)
+self._nonnormalset, self._otherparentset = self._map.nonnormalentries()
 st.close()
 self._lastnormaltime = 0
 self._dirty = self._dirtypl = False
@@ -1369,3 +1355,18 @@
 
 def keys(self):
 return self._map.keys()
+
+def nonnormalentries(self):
+'''Compute the nonnormal dirstate entries from the dmap'''
+try:
+return parsers.nonnormalotherparententries(self._map)
+except AttributeError:
+nonnorm = set()
+otherparent = set()
+for fname, e in self._map.iteritems():
+if e[0] != 'n' or e[3] == -1:
+nonnorm.add(fname)
+if e[0] == 'n' and e[2] == -2:
+otherparent.add(fname)
+return nonnorm, otherparent
+



To: durham, #hg-reviewers, indygreg
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D821: unamend: move fb extension unamend to core

2017-09-27 Thread durham (Durham Goode)
durham requested changes to this revision.
durham added a comment.
This revision now requires changes to proceed.


  Generally looks good.  Just need to fix the transaction thing.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D821

To: pulkit, #hg-reviewers, durham
Cc: durham, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D821: unamend: move fb extension unamend to core

2017-09-27 Thread durham (Durham Goode)
durham added inline comments.

INLINE COMMENTS

> uncommit.py:260
> +
> +tr = repo.transaction('unamend')
> +with dirstate.parentchange():

This should be in a with statement probably?  Can we just have it be as part of 
the top level lock with statement?

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D821

To: pulkit, #hg-reviewers
Cc: durham, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D738: directaccess: add support to export and tests to demonstrate things

2017-09-26 Thread durham (Durham Goode)
durham accepted this revision.
durham added inline comments.

INLINE COMMENTS

> test-directaccess.t:11
> +  > [extensions]
> +  > uncommit =
> +  > amend =

Do we need uncommit? It doesn't seem used.

> test-directaccess.t:64
> +
> +  $ hg exp 7
> +  # HG changeset patch

I'm still not sure we want to support rev numbers.  I think we definitely don't 
want to support them for write commands, even recoverable ones.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D738

To: pulkit, #hg-reviewers, durham
Cc: durham, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D737: directaccess: add support for accessing hidden commits if command is read only

2017-09-26 Thread durham (Durham Goode)
durham requested changes to this revision.
durham added a comment.
This revision now requires changes to proceed.


  Probably needs a simple test, unless that comes later in the series.

INLINE COMMENTS

> dispatch.py:898
> +if cmdtype == readonly:
> +repo = repo.unfiltered()
>  args.insert(0, repo)

This seems overly broad.  'hg log' is a readonly command, and if I do 'hg log 
-r HIDDEN_HASH' I want to see the hidden commit, but if I do 'hg log' I don't 
want to see hidden commits.  I think this change would cause hg log to show all 
hidden commits right?

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D737

To: pulkit, #hg-reviewers, durham
Cc: durham, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D736: directaccess: add support for storing the type of command in func object

2017-09-26 Thread durham (Durham Goode)
durham accepted this revision.
durham added a comment.


  Minor comments, but lgtm

INLINE COMMENTS

> registrar.py:143
> +unrecoverablewrite = "unrecoverable"
> +recoverablewrite = "recoverable"
> +readonly = "readonly"

Might be worth a comment describing what these mean, since it's not obvious 
without context.

> registrar.py:150
> +
> +possiblecmdtypes = set(["unrecoverable", "recoverable", "readonly"])
> +if cmdtype not in possiblecmdtypes:

These should probably refer to the class constants instead of hard coding 
duplicate strings.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D736

To: pulkit, #hg-reviewers, durham
Cc: durham, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D728: rebase: move working parent movement logic to scmutil.cleanupnodes

2017-09-26 Thread durham (Durham Goode)
durham requested changes to this revision.
durham added inline comments.
This revision now requires changes to proceed.

INLINE COMMENTS

> scmutil.py:603
> +changes will be discarded, the caller is responsible for checking the
> +cleanness of working copy.
>  """

This seems like a bit of a bizarre feature for an api about cleaning up nodes.  
Maybe cleanup nodes should return a mapping of before-to-after and the caller 
can use that to perform an update if they need to?  I'd rather have APIs that 
can be composed, than add new permutations to existing APIs.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D728

To: quark, #hg-reviewers, durham
Cc: durham, pulkit, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D758: dirstate: move parent reading to the dirstatemap class

2017-09-26 Thread durham (Durham Goode)
durham added inline comments.

INLINE COMMENTS

> indygreg wrote in dirstate.py:1370
> Nit: this should ideally be in a context manager or try..finally block. But 
> it existed this way before, so not worth blocking over.

Left this alone for now to avoid code churn during the refactor.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D758

To: durham, #hg-reviewers, indygreg
Cc: indygreg, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D757: dirstate: move opendirstatefile to dirstatemap

2017-09-26 Thread durham (Durham Goode)
durham marked an inline comment as done.
durham added inline comments.

INLINE COMMENTS

> indygreg wrote in dirstate.py:1373-1374
> This (pre-existing) error message is pretty bad because typical end users 
> won't have a clue what it means or what to do if they see it.

Agreed.  I'm not even sure what it's actually saying as a mercurial developer...

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D757

To: durham, #hg-reviewers, indygreg
Cc: indygreg, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D756: dirstate: move _copymap to dirstatemap

2017-09-26 Thread durham (Durham Goode)
durham updated this revision to Diff 2080.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D756?vs=1951=2080

REVISION DETAIL
  https://phab.mercurial-scm.org/D756

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -137,11 +137,6 @@
 return self._map
 
 @propertycache
-def _copymap(self):
-self._read()
-return self._copymap
-
-@propertycache
 def _identity(self):
 self._read()
 return self._identity
@@ -378,13 +373,13 @@
 
 # Discard 'm' markers when moving away from a merge state
 if s[0] == 'm':
-source = self._copymap.get(f)
+source = self._map.copymap.get(f)
 if source:
 copies[f] = source
 self.normallookup(f)
 # Also fix up otherparent markers
 elif s[0] == 'n' and s[2] == -2:
-source = self._copymap.get(f)
+source = self._map.copymap.get(f)
 if source:
 copies[f] = source
 self.add(f)
@@ -418,7 +413,6 @@
 def _read(self):
 self._map = dirstatemap()
 
-self._copymap = {}
 # ignore HG_PENDING because identity is used only for writing
 self._identity = util.filestat.frompath(
 self._opener.join(self._filename))
@@ -461,7 +455,7 @@
 #
 # (we cannot decorate the function directly since it is in a C module)
 parse_dirstate = util.nogc(parsers.parse_dirstate)
-p = parse_dirstate(self._map._map, self._copymap, st)
+p = parse_dirstate(self._map._map, self._map.copymap, st)
 if not self._dirtypl:
 self._pl = p
 
@@ -472,7 +466,7 @@
 rereads the dirstate. Use localrepo.invalidatedirstate() if you want to
 check whether the dirstate has changed before rereading it.'''
 
-for a in ("_map", "_copymap", "_identity",
+for a in ("_map", "_identity",
   "_filefoldmap", "_dirfoldmap", "_branch",
   "_pl", "_dirs", "_ignore", "_nonnormalset",
   "_otherparentset"):
@@ -490,17 +484,17 @@
 return
 self._dirty = True
 if source is not None:
-self._copymap[dest] = source
+self._map.copymap[dest] = source
 self._updatedfiles.add(source)
 self._updatedfiles.add(dest)
-elif self._copymap.pop(dest, None):
+elif self._map.copymap.pop(dest, None):
 self._updatedfiles.add(dest)
 
 def copied(self, file):
-return self._copymap.get(file, None)
+return self._map.copymap.get(file, None)
 
 def copies(self):
-return self._copymap
+return self._map.copymap
 
 def _droppath(self, f):
 if self[f] not in "?r" and "_dirs" in self.__dict__:
@@ -543,7 +537,7 @@
 mtime = s.st_mtime
 self._addpath(f, 'n', s.st_mode,
   s.st_size & _rangemask, mtime & _rangemask)
-self._copymap.pop(f, None)
+self._map.copymap.pop(f, None)
 if f in self._nonnormalset:
 self._nonnormalset.remove(f)
 if mtime > self._lastnormaltime:
@@ -561,7 +555,7 @@
 entry = self._map.get(f)
 if entry is not None:
 if entry[0] == 'r' and entry[2] in (-1, -2):
-source = self._copymap.get(f)
+source = self._map.copymap.get(f)
 if entry[2] == -1:
 self.merge(f)
 elif entry[2] == -2:
@@ -572,7 +566,7 @@
 if entry[0] == 'm' or entry[0] == 'n' and entry[2] == -2:
 return
 self._addpath(f, 'n', 0, -1, -1)
-self._copymap.pop(f, None)
+self._map.copymap.pop(f, None)
 if f in self._nonnormalset:
 self._nonnormalset.remove(f)
 
@@ -587,12 +581,12 @@
 else:
 # add-like
 self._addpath(f, 'n', 0, -2, -1)
-self._copymap.pop(f, None)
+self._map.copymap.pop(f, None)
 
 def add(self, f):
 '''Mark a file added.'''
 self._addpath(f, 'a', 0, -1, -1)
-self._copymap.pop(f, None)
+self._map.copymap.pop(f, None)
 
 def remove(self, f):
 '''Mark a file removed.'''
@@ -611,7 +605,7 @@
 self._map[f] = dirstatetuple('r', 0, size, 0)
 self._nonnormalset.add(f)
 if size == 0:
-self._copymap.pop(f, None)
+self._map.copymap.pop(f, None)
 
 def merge(self, f):
 '''Mark a file merged.'''
@@ -627,7 +621,7 @@
 del self._map[f]
 if f in self._nonnormalset:
 self._nonnormalset.remove(f)
-

D759: dirstate: move parents source of truth to dirstatemap

2017-09-26 Thread durham (Durham Goode)
durham updated this revision to Diff 2083.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D759?vs=1954=2083

REVISION DETAIL
  https://phab.mercurial-scm.org/D759

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -71,7 +71,6 @@
 # UNC path pointing to root share (issue4557)
 self._rootdir = pathutil.normasprefix(root)
 self._dirty = False
-self._dirtypl = False
 self._lastnormaltime = 0
 self._ui = ui
 self._filecache = {}
@@ -184,7 +183,7 @@
 raise
 return "default"
 
-@propertycache
+@property
 def _pl(self):
 return self._map.parents()
 
@@ -343,11 +342,11 @@
 raise ValueError("cannot set dirstate parent without "
  "calling dirstate.beginparentchange")
 
-self._dirty = self._dirtypl = True
+self._dirty = True
 oldp2 = self._pl[1]
 if self._origpl is None:
 self._origpl = self._pl
-self._pl = p1, p2
+self._map.setparents(p1, p2)
 copies = {}
 if oldp2 != nullid and p2 == nullid:
 candidatefiles = self._nonnormalset.union(self._otherparentset)
@@ -432,8 +431,8 @@
 # (we cannot decorate the function directly since it is in a C module)
 parse_dirstate = util.nogc(parsers.parse_dirstate)
 p = parse_dirstate(self._map._map, self._map.copymap, st)
-if not self._dirtypl:
-self._pl = p
+if not self._map._dirtyparents:
+self._map.setparents(*p)
 
 def invalidate(self):
 '''Causes the next access to reread the dirstate.
@@ -444,7 +443,7 @@
 
 for a in ("_map", "_identity",
   "_filefoldmap", "_dirfoldmap", "_branch",
-  "_pl", "_dirs", "_ignore", "_nonnormalset",
+  "_dirs", "_ignore", "_nonnormalset",
   "_otherparentset"):
 if a in self.__dict__:
 delattr(self, a)
@@ -679,7 +678,7 @@
 self._otherparentset = set()
 if "_dirs" in self.__dict__:
 delattr(self, "_dirs")
-self._pl = [nullid, nullid]
+self._map.setparents(nullid, nullid)
 self._lastnormaltime = 0
 self._updatedfiles.clear()
 self._dirty = True
@@ -694,7 +693,7 @@
 
 if self._origpl is None:
 self._origpl = self._pl
-self._pl = (parent, nullid)
+self._map.setparents(parent, nullid)
 for f in changedfiles:
 if f in allfiles:
 self.normallookup(f)
@@ -787,7 +786,7 @@
 self._nonnormalset, self._otherparentset = self._map.nonnormalentries()
 st.close()
 self._lastnormaltime = 0
-self._dirty = self._dirtypl = False
+self._dirty = self._map._dirtyparents = False
 
 def _dirignore(self, f):
 if f == '.':
@@ -1292,6 +1291,8 @@
 
 self._map = {}
 self.copymap = {}
+self._parents = None
+self._dirtyparents = False
 
 # for consistent view between _pl() and _read() invocations
 self._pendingmode = None
@@ -1370,16 +1371,28 @@
 return fp
 
 def parents(self):
-try:
-fp = self._opendirstatefile()
-st = fp.read(40)
-fp.close()
+if not self._parents:
+try:
+fp = self._opendirstatefile()
+st = fp.read(40)
+fp.close()
+except IOError as err:
+if err.errno != errno.ENOENT:
+raise
+# File doesn't exist, so the current state is empty
+st = ''
+
 l = len(st)
 if l == 40:
-return st[:20], st[20:40]
-elif l > 0 and l < 40:
-raise error.Abort(_('working directory state appears 
damaged!'))
-except IOError as err:
-if err.errno != errno.ENOENT:
-raise
-return [nullid, nullid]
+self._parents = st[:20], st[20:40]
+elif l == 0:
+self._parents = [nullid, nullid]
+else:
+raise error.Abort(_('working directory state appears '
+'damaged!'))
+
+return self._parents
+
+def setparents(self, p1, p2):
+self._parents = (p1, p2)
+self._dirtyparents = True



To: durham, #hg-reviewers, indygreg
Cc: indygreg, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D757: dirstate: move opendirstatefile to dirstatemap

2017-09-26 Thread durham (Durham Goode)
durham updated this revision to Diff 2081.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D757?vs=1952=2081

REVISION DETAIL
  https://phab.mercurial-scm.org/D757

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -82,9 +82,6 @@
 self._origpl = None
 self._updatedfiles = set()
 
-# for consistent view between _pl() and _read() invocations
-self._pendingmode = None
-
 @contextlib.contextmanager
 def parentchange(self):
 '''Context manager for handling dirstate parents.
@@ -190,7 +187,7 @@
 @propertycache
 def _pl(self):
 try:
-fp = self._opendirstatefile()
+fp = self._map._opendirstatefile()
 st = fp.read(40)
 fp.close()
 l = len(st)
@@ -401,23 +398,14 @@
 f.discard()
 raise
 
-def _opendirstatefile(self):
-fp, mode = txnutil.trypending(self._root, self._opener, self._filename)
-if self._pendingmode is not None and self._pendingmode != mode:
-fp.close()
-raise error.Abort(_('working directory state may be '
-'changed parallelly'))
-self._pendingmode = mode
-return fp
-
 def _read(self):
-self._map = dirstatemap()
+self._map = dirstatemap(self._ui, self._opener, self._root)
 
 # ignore HG_PENDING because identity is used only for writing
 self._identity = util.filestat.frompath(
 self._opener.join(self._filename))
 try:
-fp = self._opendirstatefile()
+fp = self._map._opendirstatefile()
 try:
 st = fp.read()
 finally:
@@ -698,7 +686,7 @@
 return path
 
 def clear(self):
-self._map = dirstatemap()
+self._map = dirstatemap(self._ui, self._opener, self._root)
 self._nonnormalset = set()
 self._otherparentset = set()
 if "_dirs" in self.__dict__:
@@ -1308,10 +1296,18 @@
 self._opener.unlink(backupname)
 
 class dirstatemap(object):
-def __init__(self):
+def __init__(self, ui, opener, root):
+self._ui = ui
+self._opener = opener
+self._root = root
+self._filename = 'dirstate'
+
 self._map = {}
 self.copymap = {}
 
+# for consistent view between _pl() and _read() invocations
+self._pendingmode = None
+
 def iteritems(self):
 return self._map.iteritems()
 
@@ -1375,3 +1371,13 @@
 current dirstate.
 """
 return util.dirs(self._map, 'r')
+
+def _opendirstatefile(self):
+fp, mode = txnutil.trypending(self._root, self._opener, self._filename)
+if self._pendingmode is not None and self._pendingmode != mode:
+fp.close()
+raise error.Abort(_('working directory state may be '
+'changed parallelly'))
+self._pendingmode = mode
+return fp
+



To: durham, #hg-reviewers, indygreg
Cc: indygreg, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D758: dirstate: move parent reading to the dirstatemap class

2017-09-26 Thread durham (Durham Goode)
durham updated this revision to Diff 2082.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D758?vs=1953=2082

REVISION DETAIL
  https://phab.mercurial-scm.org/D758

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -186,19 +186,7 @@
 
 @propertycache
 def _pl(self):
-try:
-fp = self._map._opendirstatefile()
-st = fp.read(40)
-fp.close()
-l = len(st)
-if l == 40:
-return st[:20], st[20:40]
-elif l > 0 and l < 40:
-raise error.Abort(_('working directory state appears 
damaged!'))
-except IOError as err:
-if err.errno != errno.ENOENT:
-raise
-return [nullid, nullid]
+return self._map.parents()
 
 @propertycache
 def _dirs(self):
@@ -1381,3 +1369,17 @@
 self._pendingmode = mode
 return fp
 
+def parents(self):
+try:
+fp = self._opendirstatefile()
+st = fp.read(40)
+fp.close()
+l = len(st)
+if l == 40:
+return st[:20], st[20:40]
+elif l > 0 and l < 40:
+raise error.Abort(_('working directory state appears 
damaged!'))
+except IOError as err:
+if err.errno != errno.ENOENT:
+raise
+return [nullid, nullid]



To: durham, #hg-reviewers, indygreg
Cc: indygreg, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D755: dirstate: move _dirs to dirstatemap

2017-09-26 Thread durham (Durham Goode)
durham updated this revision to Diff 2079.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D755?vs=1950=2079

REVISION DETAIL
  https://phab.mercurial-scm.org/D755

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -210,7 +210,7 @@
 
 @propertycache
 def _dirs(self):
-return util.dirs(self._map._map, 'r')
+return self._map.dirs()
 
 def dirs(self):
 return self._dirs
@@ -1375,3 +1375,9 @@
 f[normcase(name)] = name
 f['.'] = '.' # prevents useless util.fspath() invocation
 return f
+
+def dirs(self):
+"""Returns a set-like object containing all the directories in the
+current dirstate.
+"""
+return util.dirs(self._map, 'r')



To: durham, #hg-reviewers, indygreg
Cc: indygreg, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D754: dirstate: move filefoldmap to dirstatemap

2017-09-26 Thread durham (Durham Goode)
durham updated this revision to Diff 2078.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D754?vs=1949=2078

REVISION DETAIL
  https://phab.mercurial-scm.org/D754

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -160,21 +160,7 @@
 
 @propertycache
 def _filefoldmap(self):
-try:
-makefilefoldmap = parsers.make_file_foldmap
-except AttributeError:
-pass
-else:
-return makefilefoldmap(self._map._map, util.normcasespec,
-   util.normcasefallback)
-
-f = {}
-normcase = util.normcase
-for name, s in self._map.iteritems():
-if s[0] != 'r':
-f[normcase(name)] = name
-f['.'] = '.' # prevents useless util.fspath() invocation
-return f
+return self._map.filefoldmap()
 
 @propertycache
 def _dirfoldmap(self):
@@ -1370,3 +1356,22 @@
 otherparent.add(fname)
 return nonnorm, otherparent
 
+def filefoldmap(self):
+"""Returns a dictionary mapping normalized case paths to their
+non-normalized versions.
+"""
+try:
+makefilefoldmap = parsers.make_file_foldmap
+except AttributeError:
+pass
+else:
+return makefilefoldmap(self._map, util.normcasespec,
+   util.normcasefallback)
+
+f = {}
+normcase = util.normcase
+for name, s in self._map.iteritems():
+if s[0] != 'r':
+f[normcase(name)] = name
+f['.'] = '.' # prevents useless util.fspath() invocation
+return f



To: durham, #hg-reviewers, indygreg
Cc: indygreg, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D752: dirstate: create new dirstatemap class

2017-09-26 Thread durham (Durham Goode)
durham added inline comments.

INLINE COMMENTS

> indygreg wrote in dirstate.py:1345
> Do we want this inherit from `collections.MutableMapping`?
> 
> A good reason to say "no" is KISS, especially if we'll be having multiple 
> backends.

For now I'd say no, until we've done at least one other backend implementation 
and have seen that MutableMapping is still appropriate.  In particular, we 
might not want to allow iteration without a matcher, to discourage O(working 
copy) operations.

> indygreg wrote in dirstate.py:1349-1350
> Given that `iteritems()` no longer exists in Python 3, should we change this 
> to `items()` and standardize on the modern convention?

Do we do that anywhere else in the code base already?  My initial tendency is 
to just follow existing patterns, especially during a refactor, to minimize 
churn.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D752

To: durham, #hg-reviewers, indygreg
Cc: indygreg, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D752: dirstate: create new dirstatemap class

2017-09-20 Thread durham (Durham Goode)
durham added a comment.


  This series is the first 8 commits of a 20 patch series. At the end all the 
storage for the dirstate goes through the dirstatemap class.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D752

To: durham, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D758: dirstate: move parent reading to the dirstatemap class

2017-09-20 Thread durham (Durham Goode)
durham created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  As part of moving dirstate storage logic to a separate class, let's move the
  function that reads the parents from the file. This will allow extensions to
  write dirstate's that store the parents in other ways.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D758

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -186,19 +186,7 @@
 
 @propertycache
 def _pl(self):
-try:
-fp = self._map._opendirstatefile()
-st = fp.read(40)
-fp.close()
-l = len(st)
-if l == 40:
-return st[:20], st[20:40]
-elif l > 0 and l < 40:
-raise error.Abort(_('working directory state appears 
damaged!'))
-except IOError as err:
-if err.errno != errno.ENOENT:
-raise
-return [nullid, nullid]
+return self._map.parents()
 
 @propertycache
 def _dirs(self):
@@ -1375,3 +1363,17 @@
 self._pendingmode = mode
 return fp
 
+def parents(self):
+try:
+fp = self._opendirstatefile()
+st = fp.read(40)
+fp.close()
+l = len(st)
+if l == 40:
+return st[:20], st[20:40]
+elif l > 0 and l < 40:
+raise error.Abort(_('working directory state appears 
damaged!'))
+except IOError as err:
+if err.errno != errno.ENOENT:
+raise
+return [nullid, nullid]



To: durham, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D754: dirstate: move filefoldmap to dirstatemap

2017-09-20 Thread durham (Durham Goode)
durham created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  As part of moving the dirstate storage logic to a separate class, lets move 
the
  filfoldmap computation to that class. This will allow extensions to replace 
the
  dirstate storage with something that persists the filefoldmap.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D754

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -160,21 +160,7 @@
 
 @propertycache
 def _filefoldmap(self):
-try:
-makefilefoldmap = parsers.make_file_foldmap
-except AttributeError:
-pass
-else:
-return makefilefoldmap(self._map._map, util.normcasespec,
-   util.normcasefallback)
-
-f = {}
-normcase = util.normcase
-for name, s in self._map.iteritems():
-if s[0] != 'r':
-f[normcase(name)] = name
-f['.'] = '.' # prevents useless util.fspath() invocation
-return f
+return self._map.filefoldmap()
 
 @propertycache
 def _dirfoldmap(self):
@@ -1370,3 +1356,19 @@
 otherparent.add(fname)
 return nonnorm, otherparent
 
+def filefoldmap(self):
+try:
+makefilefoldmap = parsers.make_file_foldmap
+except AttributeError:
+pass
+else:
+return makefilefoldmap(self._map, util.normcasespec,
+   util.normcasefallback)
+
+f = {}
+normcase = util.normcase
+for name, s in self._map.iteritems():
+if s[0] != 'r':
+f[normcase(name)] = name
+f['.'] = '.' # prevents useless util.fspath() invocation
+return f



To: durham, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D759: dirstate: move parents source of truth to dirstatemap

2017-09-20 Thread durham (Durham Goode)
durham created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  As part of moving dirstate storage to its own class, let's move the source of
  truth for the dirstate parents to dirstatemap. This requires that dirstate._pl
  no longer be a cache, and that all sets go through dirstatemap.setparents.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D759

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -71,7 +71,6 @@
 # UNC path pointing to root share (issue4557)
 self._rootdir = pathutil.normasprefix(root)
 self._dirty = False
-self._dirtypl = False
 self._lastnormaltime = 0
 self._ui = ui
 self._filecache = {}
@@ -184,7 +183,7 @@
 raise
 return "default"
 
-@propertycache
+@property
 def _pl(self):
 return self._map.parents()
 
@@ -343,11 +342,11 @@
 raise ValueError("cannot set dirstate parent without "
  "calling dirstate.beginparentchange")
 
-self._dirty = self._dirtypl = True
+self._dirty = True
 oldp2 = self._pl[1]
 if self._origpl is None:
 self._origpl = self._pl
-self._pl = p1, p2
+self._map.setparents(p1, p2)
 copies = {}
 if oldp2 != nullid and p2 == nullid:
 candidatefiles = self._nonnormalset.union(self._otherparentset)
@@ -432,8 +431,8 @@
 # (we cannot decorate the function directly since it is in a C module)
 parse_dirstate = util.nogc(parsers.parse_dirstate)
 p = parse_dirstate(self._map._map, self._map.copymap, st)
-if not self._dirtypl:
-self._pl = p
+if not self._map._dirtyparents:
+self._map.setparents(*p)
 
 def invalidate(self):
 '''Causes the next access to reread the dirstate.
@@ -444,7 +443,7 @@
 
 for a in ("_map", "_identity",
   "_filefoldmap", "_dirfoldmap", "_branch",
-  "_pl", "_dirs", "_ignore", "_nonnormalset",
+  "_dirs", "_ignore", "_nonnormalset",
   "_otherparentset"):
 if a in self.__dict__:
 delattr(self, a)
@@ -679,7 +678,7 @@
 self._otherparentset = set()
 if "_dirs" in self.__dict__:
 delattr(self, "_dirs")
-self._pl = [nullid, nullid]
+self._map.setparents(nullid, nullid)
 self._lastnormaltime = 0
 self._updatedfiles.clear()
 self._dirty = True
@@ -694,7 +693,7 @@
 
 if self._origpl is None:
 self._origpl = self._pl
-self._pl = (parent, nullid)
+self._map.setparents(parent, nullid)
 for f in changedfiles:
 if f in allfiles:
 self.normallookup(f)
@@ -787,7 +786,7 @@
 self._nonnormalset, self._otherparentset = self._map.nonnormalentries()
 st.close()
 self._lastnormaltime = 0
-self._dirty = self._dirtypl = False
+self._dirty = self._map._dirtyparents = False
 
 def _dirignore(self, f):
 if f == '.':
@@ -1292,6 +1291,8 @@
 
 self._map = {}
 self.copymap = {}
+self._parents = None
+self._dirtyparents = False
 
 # for consistent view between _pl() and _read() invocations
 self._pendingmode = None
@@ -1364,16 +1365,25 @@
 return fp
 
 def parents(self):
-try:
-fp = self._opendirstatefile()
-st = fp.read(40)
-fp.close()
-l = len(st)
-if l == 40:
-return st[:20], st[20:40]
-elif l > 0 and l < 40:
-raise error.Abort(_('working directory state appears 
damaged!'))
-except IOError as err:
-if err.errno != errno.ENOENT:
-raise
-return [nullid, nullid]
+if not self._parents:
+try:
+fp = self._opendirstatefile()
+st = fp.read(40)
+fp.close()
+l = len(st)
+if l == 40:
+self._parents = st[:20], st[20:40]
+elif l > 0 and l < 40:
+raise error.Abort(_('working directory state appears '
+'damaged!'))
+except IOError as err:
+if err.errno != errno.ENOENT:
+raise
+if not self._parents:
+self._parents = [nullid, nullid]
+
+return self._parents
+
+def setparents(self, p1, p2):
+self._parents = (p1, p2)
+self._dirtyparents = True



To: durham, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list

D752: dirstate: create new dirstatemap class

2017-09-20 Thread durham (Durham Goode)
durham created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  This is part of a larger refactor to move the dirstate storage logic to a
  separate class, so it's easier to rewrite the dirstate storage layer without
  having to rewrite all the algorithms as well.
  
  Step one it to create the class, and replace dirstate._map with it.  The
  abstraction bleeds through in a few places where the main dirstate class has 
to
  access self._map._map, but those will be cleaned up in future patches.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D752

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -57,7 +57,7 @@
 def nonnormalentries(dmap):
 '''Compute the nonnormal dirstate entries from the dmap'''
 try:
-return parsers.nonnormalotherparententries(dmap)
+return parsers.nonnormalotherparententries(dmap._map)
 except AttributeError:
 nonnorm = set()
 otherparent = set()
@@ -179,7 +179,7 @@
 except AttributeError:
 pass
 else:
-return makefilefoldmap(self._map, util.normcasespec,
+return makefilefoldmap(self._map._map, util.normcasespec,
util.normcasefallback)
 
 f = {}
@@ -238,7 +238,7 @@
 
 @propertycache
 def _dirs(self):
-return util.dirs(self._map, 'r')
+return util.dirs(self._map._map, 'r')
 
 def dirs(self):
 return self._dirs
@@ -444,7 +444,8 @@
 return fp
 
 def _read(self):
-self._map = {}
+self._map = dirstatemap()
+
 self._copymap = {}
 # ignore HG_PENDING because identity is used only for writing
 self._identity = util.filestat.frompath(
@@ -473,7 +474,7 @@
 # This heuristic is imperfect in many ways, so in a future dirstate
 # format update it makes sense to just record the number of entries
 # on write.
-self._map = parsers.dict_new_presized(len(st) / 71)
+self._map._map = parsers.dict_new_presized(len(st) / 71)
 
 # Python's garbage collector triggers a GC each time a certain number
 # of container objects (the number being defined by
@@ -488,7 +489,7 @@
 #
 # (we cannot decorate the function directly since it is in a C module)
 parse_dirstate = util.nogc(parsers.parse_dirstate)
-p = parse_dirstate(self._map, self._copymap, st)
+p = parse_dirstate(self._map._map, self._copymap, st)
 if not self._dirtypl:
 self._pl = p
 
@@ -731,7 +732,7 @@
 return path
 
 def clear(self):
-self._map = {}
+self._map = dirstatemap()
 self._nonnormalset = set()
 self._otherparentset = set()
 if "_dirs" in self.__dict__:
@@ -840,7 +841,8 @@
 now = end # trust our estimate that the end is near now
 break
 
-st.write(parsers.pack_dirstate(self._map, self._copymap, self._pl, 
now))
+st.write(parsers.pack_dirstate(self._map._map, self._copymap, self._pl,
+   now))
 self._nonnormalset, self._otherparentset = nonnormalentries(self._map)
 st.close()
 self._lastnormaltime = 0
@@ -979,7 +981,7 @@
 results[nf] = None
 else: # does it match a missing directory?
 if alldirs is None:
-alldirs = util.dirs(dmap)
+alldirs = util.dirs(dmap._map)
 if nf in alldirs:
 if matchedir:
 matchedir(nf)
@@ -1339,3 +1341,31 @@
 def clearbackup(self, tr, backupname):
 '''Clear backup file'''
 self._opener.unlink(backupname)
+
+class dirstatemap(object):
+def __init__(self):
+self._map = {}
+
+def iteritems(self):
+return self._map.iteritems()
+
+def __iter__(self):
+return iter(self._map)
+
+def get(self, key, default=None):
+return self._map.get(key, default)
+
+def __contains__(self, key):
+return key in self._map
+
+def __setitem__(self, key, value):
+self._map[key] = value
+
+def __getitem__(self, key):
+return self._map[key]
+
+def __delitem__(self, key):
+del self._map[key]
+
+def keys(self):
+return self._map.keys()



To: durham, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D757: dirstate: move opendirstatefile to dirstatemap

2017-09-20 Thread durham (Durham Goode)
durham created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  As part of moving the dirstate storage logic to another class, let's move
  opendirstatefile to dirstatemap. This will allow extensions to replace the
  pending abstraction.
  
  Future patches will move the consumers of _opendirstatefile into dirstatemap 
as
  well.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D757

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -82,9 +82,6 @@
 self._origpl = None
 self._updatedfiles = set()
 
-# for consistent view between _pl() and _read() invocations
-self._pendingmode = None
-
 @contextlib.contextmanager
 def parentchange(self):
 '''Context manager for handling dirstate parents.
@@ -190,7 +187,7 @@
 @propertycache
 def _pl(self):
 try:
-fp = self._opendirstatefile()
+fp = self._map._opendirstatefile()
 st = fp.read(40)
 fp.close()
 l = len(st)
@@ -401,23 +398,14 @@
 f.discard()
 raise
 
-def _opendirstatefile(self):
-fp, mode = txnutil.trypending(self._root, self._opener, self._filename)
-if self._pendingmode is not None and self._pendingmode != mode:
-fp.close()
-raise error.Abort(_('working directory state may be '
-'changed parallelly'))
-self._pendingmode = mode
-return fp
-
 def _read(self):
-self._map = dirstatemap()
+self._map = dirstatemap(self._opener, self._ui, self._root)
 
 # ignore HG_PENDING because identity is used only for writing
 self._identity = util.filestat.frompath(
 self._opener.join(self._filename))
 try:
-fp = self._opendirstatefile()
+fp = self._map._opendirstatefile()
 try:
 st = fp.read()
 finally:
@@ -698,7 +686,7 @@
 return path
 
 def clear(self):
-self._map = dirstatemap()
+self._map = dirstatemap(self._opener, self._ui, self._root)
 self._nonnormalset = set()
 self._otherparentset = set()
 if "_dirs" in self.__dict__:
@@ -1308,10 +1296,18 @@
 self._opener.unlink(backupname)
 
 class dirstatemap(object):
-def __init__(self):
+def __init__(self, opener, ui, root):
+self._opener = opener
+self._ui = ui
+self._root = root
+self._filename = 'dirstate'
+
 self._map = {}
 self.copymap = {}
 
+# for consistent view between _pl() and _read() invocations
+self._pendingmode = None
+
 def iteritems(self):
 return self._map.iteritems()
 
@@ -1369,3 +1365,13 @@
 
 def dirs(self):
 return util.dirs(self._map, 'r')
+
+def _opendirstatefile(self):
+fp, mode = txnutil.trypending(self._root, self._opener, self._filename)
+if self._pendingmode is not None and self._pendingmode != mode:
+fp.close()
+raise error.Abort(_('working directory state may be '
+'changed parallelly'))
+self._pendingmode = mode
+return fp
+



To: durham, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D756: dirstate: move _copymap to dirstatemap

2017-09-20 Thread durham (Durham Goode)
durham created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  As part of moving all dirstate storage to a new class, let's move the copymap
  onto that class. In a future patch this will let us move the read/write
  functions to the dirstatemap class, and for extensions this lets us replace 
the
  copy storage with alternative storage.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D756

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -137,11 +137,6 @@
 return self._map
 
 @propertycache
-def _copymap(self):
-self._read()
-return self._copymap
-
-@propertycache
 def _identity(self):
 self._read()
 return self._identity
@@ -378,13 +373,13 @@
 
 # Discard 'm' markers when moving away from a merge state
 if s[0] == 'm':
-source = self._copymap.get(f)
+source = self._map.copymap.get(f)
 if source:
 copies[f] = source
 self.normallookup(f)
 # Also fix up otherparent markers
 elif s[0] == 'n' and s[2] == -2:
-source = self._copymap.get(f)
+source = self._map.copymap.get(f)
 if source:
 copies[f] = source
 self.add(f)
@@ -418,7 +413,6 @@
 def _read(self):
 self._map = dirstatemap()
 
-self._copymap = {}
 # ignore HG_PENDING because identity is used only for writing
 self._identity = util.filestat.frompath(
 self._opener.join(self._filename))
@@ -461,7 +455,7 @@
 #
 # (we cannot decorate the function directly since it is in a C module)
 parse_dirstate = util.nogc(parsers.parse_dirstate)
-p = parse_dirstate(self._map._map, self._copymap, st)
+p = parse_dirstate(self._map._map, self._map.copymap, st)
 if not self._dirtypl:
 self._pl = p
 
@@ -472,7 +466,7 @@
 rereads the dirstate. Use localrepo.invalidatedirstate() if you want to
 check whether the dirstate has changed before rereading it.'''
 
-for a in ("_map", "_copymap", "_identity",
+for a in ("_map", "_identity",
   "_filefoldmap", "_dirfoldmap", "_branch",
   "_pl", "_dirs", "_ignore", "_nonnormalset",
   "_otherparentset"):
@@ -490,17 +484,17 @@
 return
 self._dirty = True
 if source is not None:
-self._copymap[dest] = source
+self._map.copymap[dest] = source
 self._updatedfiles.add(source)
 self._updatedfiles.add(dest)
-elif self._copymap.pop(dest, None):
+elif self._map.copymap.pop(dest, None):
 self._updatedfiles.add(dest)
 
 def copied(self, file):
-return self._copymap.get(file, None)
+return self._map.copymap.get(file, None)
 
 def copies(self):
-return self._copymap
+return self._map.copymap
 
 def _droppath(self, f):
 if self[f] not in "?r" and "_dirs" in self.__dict__:
@@ -543,7 +537,7 @@
 mtime = s.st_mtime
 self._addpath(f, 'n', s.st_mode,
   s.st_size & _rangemask, mtime & _rangemask)
-self._copymap.pop(f, None)
+self._map.copymap.pop(f, None)
 if f in self._nonnormalset:
 self._nonnormalset.remove(f)
 if mtime > self._lastnormaltime:
@@ -561,7 +555,7 @@
 entry = self._map.get(f)
 if entry is not None:
 if entry[0] == 'r' and entry[2] in (-1, -2):
-source = self._copymap.get(f)
+source = self._map.copymap.get(f)
 if entry[2] == -1:
 self.merge(f)
 elif entry[2] == -2:
@@ -572,7 +566,7 @@
 if entry[0] == 'm' or entry[0] == 'n' and entry[2] == -2:
 return
 self._addpath(f, 'n', 0, -1, -1)
-self._copymap.pop(f, None)
+self._map.copymap.pop(f, None)
 if f in self._nonnormalset:
 self._nonnormalset.remove(f)
 
@@ -587,12 +581,12 @@
 else:
 # add-like
 self._addpath(f, 'n', 0, -2, -1)
-self._copymap.pop(f, None)
+self._map.copymap.pop(f, None)
 
 def add(self, f):
 '''Mark a file added.'''
 self._addpath(f, 'a', 0, -1, -1)
-self._copymap.pop(f, None)
+self._map.copymap.pop(f, None)
 
 def remove(self, f):
 '''Mark a file removed.'''
@@ -611,7 +605,7 @@
 self._map[f] = dirstatetuple('r', 0, size, 0)
 self._nonnormalset.add(f)
 if size == 0:
-

D753: dirstate: move nonnormalentries to dirstatemap

2017-09-20 Thread durham (Durham Goode)
durham created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  As part of moving dirstate storage to its own class, let's move the
  nonnormalentries logic onto the dirstatemap class. This will let extensions
  replace the nonnormalentries logic with a persisted cache.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D753

AFFECTED FILES
  mercurial/dirstate.py

CHANGE DETAILS

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -54,20 +54,6 @@
 os.close(tmpfd)
 vfs.unlink(tmpname)
 
-def nonnormalentries(dmap):
-'''Compute the nonnormal dirstate entries from the dmap'''
-try:
-return parsers.nonnormalotherparententries(dmap._map)
-except AttributeError:
-nonnorm = set()
-otherparent = set()
-for fname, e in dmap.iteritems():
-if e[0] != 'n' or e[3] == -1:
-nonnorm.add(fname)
-if e[0] == 'n' and e[2] == -2:
-otherparent.add(fname)
-return nonnorm, otherparent
-
 class dirstate(object):
 
 def __init__(self, opener, ui, root, validate, sparsematchfn):
@@ -162,13 +148,13 @@
 
 @propertycache
 def _nonnormalset(self):
-nonnorm, otherparents = nonnormalentries(self._map)
+nonnorm, otherparents = self._map.nonnormalentries()
 self._otherparentset = otherparents
 return nonnorm
 
 @propertycache
 def _otherparentset(self):
-nonnorm, otherparents = nonnormalentries(self._map)
+nonnorm, otherparents = self._map.nonnormalentries()
 self._nonnormalset = nonnorm
 return otherparents
 
@@ -843,7 +829,7 @@
 
 st.write(parsers.pack_dirstate(self._map._map, self._copymap, self._pl,
now))
-self._nonnormalset, self._otherparentset = nonnormalentries(self._map)
+self._nonnormalset, self._otherparentset = self._map.nonnormalentries()
 st.close()
 self._lastnormaltime = 0
 self._dirty = self._dirtypl = False
@@ -1369,3 +1355,18 @@
 
 def keys(self):
 return self._map.keys()
+
+def nonnormalentries(self):
+'''Compute the nonnormal dirstate entries from the dmap'''
+try:
+return parsers.nonnormalotherparententries(self._map)
+except AttributeError:
+nonnorm = set()
+otherparent = set()
+for fname, e in self._map.iteritems():
+if e[0] != 'n' or e[3] == -1:
+nonnorm.add(fname)
+if e[0] == 'n' and e[2] == -2:
+otherparent.add(fname)
+return nonnorm, otherparent
+



To: durham, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D730: revlog: add revmap back to revlog.addgroup

2017-09-20 Thread durham (Durham Goode)
This revision was automatically updated to reflect the committed changes.
durham marked an inline comment as done.
Closed by commit rHG1db9abf407c5: revlog: add revmap back to revlog.addgroup 
(authored by durham, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D730?vs=1888=1942

REVISION DETAIL
  https://phab.mercurial-scm.org/D730

AFFECTED FILES
  mercurial/changegroup.py
  mercurial/revlog.py
  tests/test-revlog-raw.py

CHANGE DETAILS

diff --git a/tests/test-revlog-raw.py b/tests/test-revlog-raw.py
--- a/tests/test-revlog-raw.py
+++ b/tests/test-revlog-raw.py
@@ -119,7 +119,7 @@
 'deltabase': rlog.node(deltaparent),
 'delta': rlog.revdiff(deltaparent, r)}
 
-def deltaiter(self, linkmapper):
+def deltaiter(self):
 chain = None
 for chunkdata in iter(lambda: self.deltachunk(chain), {}):
 node = chunkdata['node']
@@ -130,17 +130,16 @@
 delta = chunkdata['delta']
 flags = chunkdata['flags']
 
-link = linkmapper(cs)
 chain = node
 
-yield (node, p1, p2, link, deltabase, delta, flags)
+yield (node, p1, p2, cs, deltabase, delta, flags)
 
 def linkmap(lnode):
 return rlog.rev(lnode)
 
 dlog = newrevlog(destname, recreate=True)
-dummydeltas = dummychangegroup().deltaiter(linkmap)
-dlog.addgroup(dummydeltas, tr)
+dummydeltas = dummychangegroup().deltaiter()
+dlog.addgroup(dummydeltas, linkmap, tr)
 return dlog
 
 def lowlevelcopy(rlog, tr, destname=b'_destrevlog.i'):
diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -1910,7 +1910,7 @@
 ifh.write(data[1])
 self.checkinlinesize(transaction, ifh)
 
-def addgroup(self, deltas, transaction, addrevisioncb=None):
+def addgroup(self, deltas, linkmapper, transaction, addrevisioncb=None):
 """
 add a delta group
 
@@ -1944,7 +1944,8 @@
 try:
 # loop through our set of deltas
 for data in deltas:
-node, p1, p2, link, deltabase, delta, flags = data
+node, p1, p2, linknode, deltabase, delta, flags = data
+link = linkmapper(linknode)
 flags = flags or REVIDX_DEFAULT_FLAGS
 
 nodes.append(node)
diff --git a/mercurial/changegroup.py b/mercurial/changegroup.py
--- a/mercurial/changegroup.py
+++ b/mercurial/changegroup.py
@@ -245,8 +245,8 @@
 # no new manifest will be created and the manifest group will
 # be empty during the pull
 self.manifestheader()
-deltas = self.deltaiter(revmap)
-repo.manifestlog._revlog.addgroup(deltas, trp)
+deltas = self.deltaiter()
+repo.manifestlog._revlog.addgroup(deltas, revmap, trp)
 repo.ui.progress(_('manifests'), None)
 self.callback = None
 
@@ -308,8 +308,8 @@
 efiles.update(cl.readfiles(node))
 
 self.changelogheader()
-deltas = self.deltaiter(csmap)
-cgnodes = cl.addgroup(deltas, trp, addrevisioncb=onchangelog)
+deltas = self.deltaiter()
+cgnodes = cl.addgroup(deltas, csmap, trp, 
addrevisioncb=onchangelog)
 efiles = len(efiles)
 
 if not cgnodes:
@@ -430,7 +430,7 @@
 ret = deltaheads + 1
 return ret
 
-def deltaiter(self, linkmapper):
+def deltaiter(self):
 """
 returns an iterator of the deltas in this changegroup
 
@@ -446,10 +446,9 @@
 delta = chunkdata['delta']
 flags = chunkdata['flags']
 
-link = linkmapper(cs)
 chain = node
 
-yield (node, p1, p2, link, deltabase, delta, flags)
+yield (node, p1, p2, cs, deltabase, delta, flags)
 
 class cg2unpacker(cg1unpacker):
 """Unpacker for cg2 streams.
@@ -491,8 +490,8 @@
 d = chunkdata["filename"]
 repo.ui.debug("adding %s revisions\n" % d)
 dirlog = repo.manifestlog._revlog.dirlog(d)
-deltas = self.deltaiter(revmap)
-if not dirlog.addgroup(deltas, trp):
+deltas = self.deltaiter()
+if not dirlog.addgroup(deltas, revmap, trp):
 raise error.Abort(_("received dir revlog group is empty"))
 
 class headerlessfixup(object):
@@ -983,8 +982,8 @@
 fl = repo.file(f)
 o = len(fl)
 try:
-deltas = source.deltaiter(revmap)
-if not fl.addgroup(deltas, trp):
+deltas = source.deltaiter()
+if not fl.addgroup(deltas, revmap, trp):
 raise error.Abort(_("received file revlog group is empty"))
 except error.CensoredBaseError as e:
 raise error.Abort(_("received delta base is censored: %s") % e)



To: durham, indygreg, 

D746: changegroup: remove dictionary creation from deltachunk

2017-09-20 Thread durham (Durham Goode)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG05131c963767: changegroup: remove dictionary creation from 
deltachunk (authored by durham, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D746?vs=1934=1945

REVISION DETAIL
  https://phab.mercurial-scm.org/D746

AFFECTED FILES
  mercurial/changegroup.py

CHANGE DETAILS

diff --git a/mercurial/changegroup.py b/mercurial/changegroup.py
--- a/mercurial/changegroup.py
+++ b/mercurial/changegroup.py
@@ -188,8 +188,7 @@
 header = struct.unpack(self.deltaheader, headerdata)
 delta = readexactly(self._stream, l - self.deltaheadersize)
 node, p1, p2, deltabase, cs, flags = self._deltaheader(header, 
prevnode)
-return {'node': node, 'p1': p1, 'p2': p2, 'cs': cs,
-'deltabase': deltabase, 'delta': delta, 'flags': flags}
+return (node, p1, p2, cs, deltabase, delta, flags)
 
 def getchunks(self):
 """returns all the chunks contains in the bundle
@@ -438,17 +437,9 @@
 """
 chain = None
 for chunkdata in iter(lambda: self.deltachunk(chain), {}):
-node = chunkdata['node']
-p1 = chunkdata['p1']
-p2 = chunkdata['p2']
-cs = chunkdata['cs']
-deltabase = chunkdata['deltabase']
-delta = chunkdata['delta']
-flags = chunkdata['flags']
-
-chain = node
-
-yield (node, p1, p2, cs, deltabase, delta, flags)
+# Chunkdata: (node, p1, p2, cs, deltabase, delta, flags)
+yield chunkdata
+chain = chunkdata[0]
 
 class cg2unpacker(cg1unpacker):
 """Unpacker for cg2 streams.



To: durham, #hg-reviewers, martinvonz
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D745: bundlerepo: update to use new deltaiter api

2017-09-20 Thread durham (Durham Goode)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG0fe62d8bdd50: bundlerepo: update to use new deltaiter api 
(authored by durham, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D745?vs=1933=1944

REVISION DETAIL
  https://phab.mercurial-scm.org/D745

AFFECTED FILES
  mercurial/bundlerepo.py

CHANGE DETAILS

diff --git a/mercurial/bundlerepo.py b/mercurial/bundlerepo.py
--- a/mercurial/bundlerepo.py
+++ b/mercurial/bundlerepo.py
@@ -55,25 +55,16 @@
 self.bundle = bundle
 n = len(self)
 self.repotiprev = n - 1
-chain = None
 self.bundlerevs = set() # used by 'bundle()' revset expression
-getchunk = lambda: bundle.deltachunk(chain)
-for chunkdata in iter(getchunk, {}):
-node = chunkdata['node']
-p1 = chunkdata['p1']
-p2 = chunkdata['p2']
-cs = chunkdata['cs']
-deltabase = chunkdata['deltabase']
-delta = chunkdata['delta']
-flags = chunkdata['flags']
+for deltadata in bundle.deltaiter():
+node, p1, p2, cs, deltabase, delta, flags = deltadata
 
 size = len(delta)
 start = bundle.tell() - size
 
 link = linkmapper(cs)
 if node in self.nodemap:
 # this can happen if two branches make the same change
-chain = node
 self.bundlerevs.add(self.nodemap[node])
 continue
 
@@ -93,7 +84,6 @@
 self.index.insert(-1, e)
 self.nodemap[node] = n
 self.bundlerevs.add(n)
-chain = node
 n += 1
 
 def _chunk(self, rev):



To: durham, #hg-reviewers, martinvonz
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D744: debug: update debugbundle to use new deltaiter api

2017-09-20 Thread durham (Durham Goode)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG311f6ccf8f23: debug: update debugbundle to use new 
deltaiter api (authored by durham, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D744?vs=1932=1943

REVISION DETAIL
  https://phab.mercurial-scm.org/D744

AFFECTED FILES
  mercurial/debugcommands.py

CHANGE DETAILS

diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py
--- a/mercurial/debugcommands.py
+++ b/mercurial/debugcommands.py
@@ -263,18 +263,11 @@
 
 def showchunks(named):
 ui.write("\n%s%s\n" % (indent_string, named))
-chain = None
-for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
-node = chunkdata['node']
-p1 = chunkdata['p1']
-p2 = chunkdata['p2']
-cs = chunkdata['cs']
-deltabase = chunkdata['deltabase']
-delta = chunkdata['delta']
+for deltadata in gen.deltaiter():
+node, p1, p2, cs, deltabase, delta, flags = deltadata
 ui.write("%s%s %s %s %s %s %s\n" %
  (indent_string, hex(node), hex(p1), hex(p2),
   hex(cs), hex(deltabase), len(delta)))
-chain = node
 
 chunkdata = gen.changelogheader()
 showchunks("changelog")
@@ -287,11 +280,9 @@
 if isinstance(gen, bundle2.unbundle20):
 raise error.Abort(_('use debugbundle2 for this file'))
 chunkdata = gen.changelogheader()
-chain = None
-for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
-node = chunkdata['node']
+for deltadata in gen.deltaiter():
+node, p1, p2, cs, deltabase, delta, flags = deltadata
 ui.write("%s%s\n" % (indent_string, hex(node)))
-chain = node
 
 def _debugobsmarkers(ui, part, indent=0, **opts):
 """display version and markers contained in 'data'"""



To: durham, #hg-reviewers, martinvonz
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D730: revlog: add revmap back to revlog.addgroup

2017-09-20 Thread durham (Durham Goode)
durham marked an inline comment as done.
durham added a comment.


  I've updated the message and attached 3 more commits to the stack that update 
debugbundle, bundlerepo, and the deltachunk fix you suggested.

INLINE COMMENTS

> martinvonz wrote in changegroup.py:191-192
> I'll repeat my comment from https://phab.mercurial-scm.org/D688: This now 
> seems unnecessary since the first thing you do is to convert it back into a 
> very similar tuple. Do you think the is still useful? Maybe use a named tuple 
> if we want the names? Either way, that's not for this patch, of course.

I've added a diff to the end of the stack to change it to a tuple. No need for 
names I think, since the return value is only consumed internal to the class.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D730

To: durham, indygreg, #hg-reviewers
Cc: martinvonz, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D745: bundlerepo: update to use new deltaiter api

2017-09-20 Thread durham (Durham Goode)
durham created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D745

AFFECTED FILES
  mercurial/bundlerepo.py

CHANGE DETAILS

diff --git a/mercurial/bundlerepo.py b/mercurial/bundlerepo.py
--- a/mercurial/bundlerepo.py
+++ b/mercurial/bundlerepo.py
@@ -55,25 +55,16 @@
 self.bundle = bundle
 n = len(self)
 self.repotiprev = n - 1
-chain = None
 self.bundlerevs = set() # used by 'bundle()' revset expression
-getchunk = lambda: bundle.deltachunk(chain)
-for chunkdata in iter(getchunk, {}):
-node = chunkdata['node']
-p1 = chunkdata['p1']
-p2 = chunkdata['p2']
-cs = chunkdata['cs']
-deltabase = chunkdata['deltabase']
-delta = chunkdata['delta']
-flags = chunkdata['flags']
+for deltadata in bundle.deltaiter():
+node, p1, p2, cs, deltabase, delta, flags = deltadata
 
 size = len(delta)
 start = bundle.tell() - size
 
 link = linkmapper(cs)
 if node in self.nodemap:
 # this can happen if two branches make the same change
-chain = node
 self.bundlerevs.add(self.nodemap[node])
 continue
 
@@ -93,7 +84,6 @@
 self.index.insert(-1, e)
 self.nodemap[node] = n
 self.bundlerevs.add(n)
-chain = node
 n += 1
 
 def _chunk(self, rev):



To: durham, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D746: changegroup: remove dictionary creation from deltachunk

2017-09-20 Thread durham (Durham Goode)
durham created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  Previously delta chunk returned a dictionary. Now that we consume deltachunk
  within changegroup (instead of outside in revlog) we can just return a tuple 
and
  have it be returned directly by deltaiter.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D746

AFFECTED FILES
  mercurial/changegroup.py

CHANGE DETAILS

diff --git a/mercurial/changegroup.py b/mercurial/changegroup.py
--- a/mercurial/changegroup.py
+++ b/mercurial/changegroup.py
@@ -188,8 +188,7 @@
 header = struct.unpack(self.deltaheader, headerdata)
 delta = readexactly(self._stream, l - self.deltaheadersize)
 node, p1, p2, deltabase, cs, flags = self._deltaheader(header, 
prevnode)
-return {'node': node, 'p1': p1, 'p2': p2, 'cs': cs,
-'deltabase': deltabase, 'delta': delta, 'flags': flags}
+return (node, p1, p2, cs, deltabase, delta, flags)
 
 def getchunks(self):
 """returns all the chunks contains in the bundle
@@ -438,17 +437,9 @@
 """
 chain = None
 for chunkdata in iter(lambda: self.deltachunk(chain), {}):
-node = chunkdata['node']
-p1 = chunkdata['p1']
-p2 = chunkdata['p2']
-cs = chunkdata['cs']
-deltabase = chunkdata['deltabase']
-delta = chunkdata['delta']
-flags = chunkdata['flags']
-
-chain = node
-
-yield (node, p1, p2, cs, deltabase, delta, flags)
+# Chunkdata: (node, p1, p2, cs, deltabase, delta, flags)
+yield chunkdata
+chain = chunkdata[0]
 
 class cg2unpacker(cg1unpacker):
 """Unpacker for cg2 streams.



To: durham, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D744: debug: update debugbundle to use new deltaiter api

2017-09-20 Thread durham (Durham Goode)
durham created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  Changegroup now has a deltaiter api for easy iteration over a series of 
deltas.
  Let's use that in the debugbundle command.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D744

AFFECTED FILES
  mercurial/debugcommands.py

CHANGE DETAILS

diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py
--- a/mercurial/debugcommands.py
+++ b/mercurial/debugcommands.py
@@ -263,18 +263,11 @@
 
 def showchunks(named):
 ui.write("\n%s%s\n" % (indent_string, named))
-chain = None
-for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
-node = chunkdata['node']
-p1 = chunkdata['p1']
-p2 = chunkdata['p2']
-cs = chunkdata['cs']
-deltabase = chunkdata['deltabase']
-delta = chunkdata['delta']
+for deltadata in gen.deltaiter():
+node, p1, p2, cs, deltabase, delta, flags = deltadata
 ui.write("%s%s %s %s %s %s %s\n" %
  (indent_string, hex(node), hex(p1), hex(p2),
   hex(cs), hex(deltabase), len(delta)))
-chain = node
 
 chunkdata = gen.changelogheader()
 showchunks("changelog")
@@ -287,11 +280,9 @@
 if isinstance(gen, bundle2.unbundle20):
 raise error.Abort(_('use debugbundle2 for this file'))
 chunkdata = gen.changelogheader()
-chain = None
-for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
-node = chunkdata['node']
+for deltadata in gen.deltaiter():
+node, p1, p2, cs, deltabase, delta, flags = deltadata
 ui.write("%s%s\n" % (indent_string, hex(node)))
-chain = node
 
 def _debugobsmarkers(ui, part, indent=0, **opts):
 """display version and markers contained in 'data'"""



To: durham, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D708: bundle2: remove unnecessary try finally

2017-09-18 Thread durham (Durham Goode)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGcc7b37c90616: bundle2: remove unnecessary try finally 
(authored by durham, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D708?vs=1820=1875

REVISION DETAIL
  https://phab.mercurial-scm.org/D708

AFFECTED FILES
  mercurial/bundle2.py

CHANGE DETAILS

diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -505,32 +505,28 @@
 
 The part is guaranteed to have been fully consumed when the function exits
 (even if an exception is raised)."""
-try:
-handler = _gethandler(op, part)
-if handler is None:
-return
+handler = _gethandler(op, part)
+if handler is None:
+return
 
-# handler is called outside the above try block so that we don't
-# risk catching KeyErrors from anything other than the
-# parthandlermapping lookup (any KeyError raised by handler()
-# itself represents a defect of a different variety).
-output = None
-if op.captureoutput and op.reply is not None:
-op.ui.pushbuffer(error=True, subproc=True)
-output = ''
-try:
-handler(op, part)
-finally:
-if output is not None:
-output = op.ui.popbuffer()
-if output:
-outpart = op.reply.newpart('output', data=output,
-   mandatory=False)
-outpart.addparam(
-'in-reply-to', pycompat.bytestr(part.id), mandatory=False)
+# handler is called outside the above try block so that we don't
+# risk catching KeyErrors from anything other than the
+# parthandlermapping lookup (any KeyError raised by handler()
+# itself represents a defect of a different variety).
+output = None
+if op.captureoutput and op.reply is not None:
+op.ui.pushbuffer(error=True, subproc=True)
+output = ''
+try:
+handler(op, part)
 finally:
-pass
-
+if output is not None:
+output = op.ui.popbuffer()
+if output:
+outpart = op.reply.newpart('output', data=output,
+   mandatory=False)
+outpart.addparam(
+'in-reply-to', pycompat.bytestr(part.id), mandatory=False)
 
 def decodecaps(blob):
 """decode a bundle2 caps bytes blob into a dictionary



To: durham, #hg-reviewers, indygreg, krbullock
Cc: indygreg, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D709: bundle2: move part processing to a separate function

2017-09-18 Thread durham (Durham Goode)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGf010097c885c: bundle2: move part processing to a separate 
function (authored by durham, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D709?vs=1821=1876

REVISION DETAIL
  https://phab.mercurial-scm.org/D709

AFFECTED FILES
  mercurial/bundle2.py

CHANGE DETAILS

diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -447,12 +447,15 @@
 msg.append('\n')
 repo.ui.debug(''.join(msg))
 
+processparts(repo, op, unbundler)
+
+return op
+
+def processparts(repo, op, unbundler):
 with partiterator(repo, op, unbundler) as parts:
 for part in parts:
 _processpart(op, part)
 
-return op
-
 def _processchangegroup(op, cg, tr, source, url, **kwargs):
 ret = cg.apply(op.repo, tr, source, url, **kwargs)
 op.records.add('changegroup', {



To: durham, #hg-reviewers, krbullock
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D707: bundle2: move handler validation out of processpart

2017-09-18 Thread durham (Durham Goode)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG07e4170f02f3: bundle2: move handler validation out of 
processpart (authored by durham, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D707?vs=1819=1873

REVISION DETAIL
  https://phab.mercurial-scm.org/D707

AFFECTED FILES
  mercurial/bundle2.py

CHANGE DETAILS

diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -460,48 +460,55 @@
 })
 return ret
 
+def _gethandler(op, part):
+status = 'unknown' # used by debug output
+try:
+handler = parthandlermapping.get(part.type)
+if handler is None:
+status = 'unsupported-type'
+raise error.BundleUnknownFeatureError(parttype=part.type)
+indebug(op.ui, 'found a handler for part %r' % part.type)
+unknownparams = part.mandatorykeys - handler.params
+if unknownparams:
+unknownparams = list(unknownparams)
+unknownparams.sort()
+status = 'unsupported-params (%s)' % unknownparams
+raise error.BundleUnknownFeatureError(parttype=part.type,
+  params=unknownparams)
+status = 'supported'
+except error.BundleUnknownFeatureError as exc:
+if part.mandatory: # mandatory parts
+raise
+indebug(op.ui, 'ignoring unsupported advisory part %s' % exc)
+return # skip to part processing
+finally:
+if op.ui.debugflag:
+msg = ['bundle2-input-part: "%s"' % part.type]
+if not part.mandatory:
+msg.append(' (advisory)')
+nbmp = len(part.mandatorykeys)
+nbap = len(part.params) - nbmp
+if nbmp or nbap:
+msg.append(' (params:')
+if nbmp:
+msg.append(' %i mandatory' % nbmp)
+if nbap:
+msg.append(' %i advisory' % nbmp)
+msg.append(')')
+msg.append(' %s\n' % status)
+op.ui.debug(''.join(msg))
+
+return handler
+
 def _processpart(op, part):
 """process a single part from a bundle
 
 The part is guaranteed to have been fully consumed when the function exits
 (even if an exception is raised)."""
-status = 'unknown' # used by debug output
 try:
-try:
-handler = parthandlermapping.get(part.type)
-if handler is None:
-status = 'unsupported-type'
-raise error.BundleUnknownFeatureError(parttype=part.type)
-indebug(op.ui, 'found a handler for part %r' % part.type)
-unknownparams = part.mandatorykeys - handler.params
-if unknownparams:
-unknownparams = list(unknownparams)
-unknownparams.sort()
-status = 'unsupported-params (%s)' % unknownparams
-raise error.BundleUnknownFeatureError(parttype=part.type,
-  params=unknownparams)
-status = 'supported'
-except error.BundleUnknownFeatureError as exc:
-if part.mandatory: # mandatory parts
-raise
-indebug(op.ui, 'ignoring unsupported advisory part %s' % exc)
-return # skip to part processing
-finally:
-if op.ui.debugflag:
-msg = ['bundle2-input-part: "%s"' % part.type]
-if not part.mandatory:
-msg.append(' (advisory)')
-nbmp = len(part.mandatorykeys)
-nbap = len(part.params) - nbmp
-if nbmp or nbap:
-msg.append(' (params:')
-if nbmp:
-msg.append(' %i mandatory' % nbmp)
-if nbap:
-msg.append(' %i advisory' % nbmp)
-msg.append(')')
-msg.append(' %s\n' % status)
-op.ui.debug(''.join(msg))
+handler = _gethandler(op, part)
+if handler is None:
+return
 
 # handler is called outside the above try block so that we don't
 # risk catching KeyErrors from anything other than the



To: durham, #hg-reviewers, indygreg
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D477: revlog: add option to mmap revlog index

2017-09-15 Thread durham (Durham Goode)
durham added a comment.


  Also, the improvements should become more pronounced if we fix some 
algorithms (like phases) that access really old commits.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D477

To: mbthomas, #fbhgext, indygreg, #hg-reviewers, durin42, quark
Cc: durham, quark, durin42, simonfar, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D696: registrar: add a enum 'cmdtype' for the type of the command

2017-09-14 Thread durham (Durham Goode)
durham accepted this revision.
durham added a comment.


  I think the name could be better, but that can be bikeshed.  Stamping my 
approval for the concept and pattern.

INLINE COMMENTS

> registrar.py:148
>  
> +class cmdtype(object):
> +""" enum for the type of command which will tell whether the command is

`cmdtype` might be overly vague, since I could imagine a number of 
classifications it could mean.  Maybe "cmdwritetype"?

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D696

To: pulkit, #hg-reviewers, durham
Cc: durham, indygreg, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D706: bundle2: move processpart stream maintenance into part iterator

2017-09-14 Thread durham (Durham Goode)
durham updated this revision to Diff 1818.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D706?vs=1802=1818

REVISION DETAIL
  https://phab.mercurial-scm.org/D706

AFFECTED FILES
  mercurial/bundle2.py

CHANGE DETAILS

diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -354,21 +354,32 @@
 self.unbundler = unbundler
 self.iterator = None
 self.count = 0
+self.current = None
 
 def __enter__(self):
 def func():
 itr = enumerate(self.unbundler.iterparts())
 for count, p in itr:
 self.count = count
+self.current = p
 yield p
+p.seek(0, 2)
+self.current = None
 self.iterator = func()
 return self.iterator
 
 def __exit__(self, type, exc, tb):
 if not self.iterator:
 return
 
 if exc:
+# If exiting or interrupted, do not attempt to seek the stream in
+# the finally block below. This makes abort faster.
+if (self.current and
+not isinstance(exc, (SystemExit, KeyboardInterrupt))):
+# consume the part content to not corrupt the stream.
+self.current.seek(0, 2)
+
 # Any exceptions seeking to the end of the bundle at this point are
 # almost certainly related to the underlying stream being bad.
 # And, chances are that the exception we're handling is related to
@@ -455,7 +466,6 @@
 The part is guaranteed to have been fully consumed when the function exits
 (even if an exception is raised)."""
 status = 'unknown' # used by debug output
-hardabort = False
 try:
 try:
 handler = parthandlermapping.get(part.type)
@@ -511,15 +521,8 @@
mandatory=False)
 outpart.addparam(
 'in-reply-to', pycompat.bytestr(part.id), mandatory=False)
-# If exiting or interrupted, do not attempt to seek the stream in the
-# finally block below. This makes abort faster.
-except (SystemExit, KeyboardInterrupt):
-hardabort = True
-raise
 finally:
-# consume the part content to not corrupt the stream.
-if not hardabort:
-part.seek(0, 2)
+pass
 
 
 def decodecaps(blob):
@@ -1143,7 +1146,15 @@
 return
 part = unbundlepart(self.ui, headerblock, self._fp)
 op = interruptoperation(self.ui)
-_processpart(op, part)
+hardabort = False
+try:
+_processpart(op, part)
+except (SystemExit, KeyboardInterrupt):
+hardabort = True
+raise
+finally:
+if not hardabort:
+part.seek(0, 2)
 self.ui.debug('bundle2-input-stream-interrupt:'
   ' closing out of band context\n')
 



To: durham, #hg-reviewers, indygreg
Cc: indygreg, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D707: bundle2: move handler validation out of processpart

2017-09-14 Thread durham (Durham Goode)
durham updated this revision to Diff 1819.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D707?vs=1803=1819

REVISION DETAIL
  https://phab.mercurial-scm.org/D707

AFFECTED FILES
  mercurial/bundle2.py

CHANGE DETAILS

diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -460,48 +460,55 @@
 })
 return ret
 
+def _gethandler(op, part):
+status = 'unknown' # used by debug output
+try:
+handler = parthandlermapping.get(part.type)
+if handler is None:
+status = 'unsupported-type'
+raise error.BundleUnknownFeatureError(parttype=part.type)
+indebug(op.ui, 'found a handler for part %r' % part.type)
+unknownparams = part.mandatorykeys - handler.params
+if unknownparams:
+unknownparams = list(unknownparams)
+unknownparams.sort()
+status = 'unsupported-params (%s)' % unknownparams
+raise error.BundleUnknownFeatureError(parttype=part.type,
+  params=unknownparams)
+status = 'supported'
+except error.BundleUnknownFeatureError as exc:
+if part.mandatory: # mandatory parts
+raise
+indebug(op.ui, 'ignoring unsupported advisory part %s' % exc)
+return # skip to part processing
+finally:
+if op.ui.debugflag:
+msg = ['bundle2-input-part: "%s"' % part.type]
+if not part.mandatory:
+msg.append(' (advisory)')
+nbmp = len(part.mandatorykeys)
+nbap = len(part.params) - nbmp
+if nbmp or nbap:
+msg.append(' (params:')
+if nbmp:
+msg.append(' %i mandatory' % nbmp)
+if nbap:
+msg.append(' %i advisory' % nbmp)
+msg.append(')')
+msg.append(' %s\n' % status)
+op.ui.debug(''.join(msg))
+
+return handler
+
 def _processpart(op, part):
 """process a single part from a bundle
 
 The part is guaranteed to have been fully consumed when the function exits
 (even if an exception is raised)."""
-status = 'unknown' # used by debug output
 try:
-try:
-handler = parthandlermapping.get(part.type)
-if handler is None:
-status = 'unsupported-type'
-raise error.BundleUnknownFeatureError(parttype=part.type)
-indebug(op.ui, 'found a handler for part %r' % part.type)
-unknownparams = part.mandatorykeys - handler.params
-if unknownparams:
-unknownparams = list(unknownparams)
-unknownparams.sort()
-status = 'unsupported-params (%s)' % unknownparams
-raise error.BundleUnknownFeatureError(parttype=part.type,
-  params=unknownparams)
-status = 'supported'
-except error.BundleUnknownFeatureError as exc:
-if part.mandatory: # mandatory parts
-raise
-indebug(op.ui, 'ignoring unsupported advisory part %s' % exc)
-return # skip to part processing
-finally:
-if op.ui.debugflag:
-msg = ['bundle2-input-part: "%s"' % part.type]
-if not part.mandatory:
-msg.append(' (advisory)')
-nbmp = len(part.mandatorykeys)
-nbap = len(part.params) - nbmp
-if nbmp or nbap:
-msg.append(' (params:')
-if nbmp:
-msg.append(' %i mandatory' % nbmp)
-if nbap:
-msg.append(' %i advisory' % nbmp)
-msg.append(')')
-msg.append(' %s\n' % status)
-op.ui.debug(''.join(msg))
+handler = _gethandler(op, part)
+if handler is None:
+return
 
 # handler is called outside the above try block so that we don't
 # risk catching KeyErrors from anything other than the



To: durham, #hg-reviewers, indygreg
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D708: bundle2: remove unnecessary try finally

2017-09-14 Thread durham (Durham Goode)
durham updated this revision to Diff 1820.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D708?vs=1804=1820

REVISION DETAIL
  https://phab.mercurial-scm.org/D708

AFFECTED FILES
  mercurial/bundle2.py

CHANGE DETAILS

diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -505,32 +505,28 @@
 
 The part is guaranteed to have been fully consumed when the function exits
 (even if an exception is raised)."""
-try:
-handler = _gethandler(op, part)
-if handler is None:
-return
+handler = _gethandler(op, part)
+if handler is None:
+return
 
-# handler is called outside the above try block so that we don't
-# risk catching KeyErrors from anything other than the
-# parthandlermapping lookup (any KeyError raised by handler()
-# itself represents a defect of a different variety).
-output = None
-if op.captureoutput and op.reply is not None:
-op.ui.pushbuffer(error=True, subproc=True)
-output = ''
-try:
-handler(op, part)
-finally:
-if output is not None:
-output = op.ui.popbuffer()
-if output:
-outpart = op.reply.newpart('output', data=output,
-   mandatory=False)
-outpart.addparam(
-'in-reply-to', pycompat.bytestr(part.id), mandatory=False)
+# handler is called outside the above try block so that we don't
+# risk catching KeyErrors from anything other than the
+# parthandlermapping lookup (any KeyError raised by handler()
+# itself represents a defect of a different variety).
+output = None
+if op.captureoutput and op.reply is not None:
+op.ui.pushbuffer(error=True, subproc=True)
+output = ''
+try:
+handler(op, part)
 finally:
-pass
-
+if output is not None:
+output = op.ui.popbuffer()
+if output:
+outpart = op.reply.newpart('output', data=output,
+   mandatory=False)
+outpart.addparam(
+'in-reply-to', pycompat.bytestr(part.id), mandatory=False)
 
 def decodecaps(blob):
 """decode a bundle2 caps bytes blob into a dictionary



To: durham, #hg-reviewers, indygreg
Cc: indygreg, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D705: bundle2: move exception handling into part iterator

2017-09-13 Thread durham (Durham Goode)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG3d8fb0c37e12: bundle2: move exception handling into part 
iterator (authored by durham, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D705?vs=1801=1809

REVISION DETAIL
  https://phab.mercurial-scm.org/D705

AFFECTED FILES
  mercurial/bundle2.py

CHANGE DETAILS

diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -348,8 +348,9 @@
 return op
 
 class partiterator(object):
-def __init__(self, repo, unbundler):
+def __init__(self, repo, op, unbundler):
 self.repo = repo
+self.op = op
 self.unbundler = unbundler
 self.iterator = None
 self.count = 0
@@ -363,10 +364,43 @@
 self.iterator = func()
 return self.iterator
 
-def __exit__(self, type, value, tb):
+def __exit__(self, type, exc, tb):
 if not self.iterator:
 return
 
+if exc:
+# Any exceptions seeking to the end of the bundle at this point are
+# almost certainly related to the underlying stream being bad.
+# And, chances are that the exception we're handling is related to
+# getting in that bad state. So, we swallow the seeking error and
+# re-raise the original error.
+seekerror = False
+try:
+for part in self.iterator:
+# consume the bundle content
+part.seek(0, 2)
+except Exception:
+seekerror = True
+
+# Small hack to let caller code distinguish exceptions from bundle2
+# processing from processing the old format. This is mostly needed
+# to handle different return codes to unbundle according tothe type
+# of bundle. We should probably clean up or drop this return code
+# craziness in a future version.
+exc.duringunbundle2 = True
+salvaged = []
+replycaps = None
+if self.op.reply is not None:
+salvaged = self.op.reply.salvageoutput()
+replycaps = self.op.reply.capabilities
+exc._replycaps = replycaps
+exc._bundle2salvagedoutput = salvaged
+
+# Re-raising from a variable loses the original stack. So only use
+# that form if we need to.
+if seekerror:
+raise exc
+
 self.repo.ui.debug('bundle2-input-bundle: %i parts total\n' %
self.count)
 
@@ -402,45 +436,9 @@
 msg.append('\n')
 repo.ui.debug(''.join(msg))
 
-with partiterator(repo, unbundler) as parts:
-part = None
-try:
-for part in parts:
-_processpart(op, part)
-except Exception as exc:
-# Any exceptions seeking to the end of the bundle at this point are
-# almost certainly related to the underlying stream being bad.
-# And, chances are that the exception we're handling is related to
-# getting in that bad state. So, we swallow the seeking error and
-# re-raise the original error.
-seekerror = False
-try:
-for part in parts:
-# consume the bundle content
-part.seek(0, 2)
-except Exception:
-seekerror = True
-
-# Small hack to let caller code distinguish exceptions from bundle2
-# processing from processing the old format. This is mostly needed
-# to handle different return codes to unbundle according to the 
type
-# of bundle. We should probably clean up or drop this return code
-# craziness in a future version.
-exc.duringunbundle2 = True
-salvaged = []
-replycaps = None
-if op.reply is not None:
-salvaged = op.reply.salvageoutput()
-replycaps = op.reply.capabilities
-exc._replycaps = replycaps
-exc._bundle2salvagedoutput = salvaged
-
-# Re-raising from a variable loses the original stack. So only use
-# that form if we need to.
-if seekerror:
-raise exc
-else:
-raise
+with partiterator(repo, op, unbundler) as parts:
+for part in parts:
+_processpart(op, part)
 
 return op
 



To: durham, #hg-reviewers, indygreg
Cc: indygreg, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D704: bundle2: move part counter to partiterator

2017-09-13 Thread durham (Durham Goode)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG550343626bb2: bundle2: move part counter to partiterator 
(authored by durham, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D704?vs=1800=1808

REVISION DETAIL
  https://phab.mercurial-scm.org/D704

AFFECTED FILES
  mercurial/bundle2.py

CHANGE DETAILS

diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -348,14 +348,27 @@
 return op
 
 class partiterator(object):
-def __init__(self, unbundler):
+def __init__(self, repo, unbundler):
+self.repo = repo
 self.unbundler = unbundler
+self.iterator = None
+self.count = 0
 
 def __enter__(self):
-return enumerate(self.unbundler.iterparts())
+def func():
+itr = enumerate(self.unbundler.iterparts())
+for count, p in itr:
+self.count = count
+yield p
+self.iterator = func()
+return self.iterator
 
 def __exit__(self, type, value, tb):
-pass
+if not self.iterator:
+return
+
+self.repo.ui.debug('bundle2-input-bundle: %i parts total\n' %
+   self.count)
 
 def processbundle(repo, unbundler, transactiongetter=None, op=None):
 """This function process a bundle, apply effect to/from a repo
@@ -389,11 +402,10 @@
 msg.append('\n')
 repo.ui.debug(''.join(msg))
 
-with partiterator(unbundler) as parts:
+with partiterator(repo, unbundler) as parts:
 part = None
-nbpart = 0
 try:
-for nbpart, part in parts:
+for part in parts:
 _processpart(op, part)
 except Exception as exc:
 # Any exceptions seeking to the end of the bundle at this point are
@@ -403,7 +415,7 @@
 # re-raise the original error.
 seekerror = False
 try:
-for nbpart, part in parts:
+for part in parts:
 # consume the bundle content
 part.seek(0, 2)
 except Exception:
@@ -429,8 +441,6 @@
 raise exc
 else:
 raise
-finally:
-repo.ui.debug('bundle2-input-bundle: %i parts total\n' % nbpart)
 
 return op
 



To: durham, #hg-reviewers, indygreg
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D703: bundle2: move part iterator a separate class

2017-09-13 Thread durham (Durham Goode)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGe9e0e1143fc5: bundle2: move part iterator a separate class 
(authored by durham, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D703?vs=1799=1807

REVISION DETAIL
  https://phab.mercurial-scm.org/D703

AFFECTED FILES
  mercurial/bundle2.py

CHANGE DETAILS

diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -347,6 +347,16 @@
 _processchangegroup(op, unbundler, tr, source, url, **kwargs)
 return op
 
+class partiterator(object):
+def __init__(self, unbundler):
+self.unbundler = unbundler
+
+def __enter__(self):
+return enumerate(self.unbundler.iterparts())
+
+def __exit__(self, type, value, tb):
+pass
+
 def processbundle(repo, unbundler, transactiongetter=None, op=None):
 """This function process a bundle, apply effect to/from a repo
 
@@ -378,48 +388,49 @@
 msg.append(' with-transaction')
 msg.append('\n')
 repo.ui.debug(''.join(msg))
-iterparts = enumerate(unbundler.iterparts())
-part = None
-nbpart = 0
-try:
-for nbpart, part in iterparts:
-_processpart(op, part)
-except Exception as exc:
-# Any exceptions seeking to the end of the bundle at this point are
-# almost certainly related to the underlying stream being bad.
-# And, chances are that the exception we're handling is related to
-# getting in that bad state. So, we swallow the seeking error and
-# re-raise the original error.
-seekerror = False
+
+with partiterator(unbundler) as parts:
+part = None
+nbpart = 0
 try:
-for nbpart, part in iterparts:
-# consume the bundle content
-part.seek(0, 2)
-except Exception:
-seekerror = True
+for nbpart, part in parts:
+_processpart(op, part)
+except Exception as exc:
+# Any exceptions seeking to the end of the bundle at this point are
+# almost certainly related to the underlying stream being bad.
+# And, chances are that the exception we're handling is related to
+# getting in that bad state. So, we swallow the seeking error and
+# re-raise the original error.
+seekerror = False
+try:
+for nbpart, part in parts:
+# consume the bundle content
+part.seek(0, 2)
+except Exception:
+seekerror = True
 
-# Small hack to let caller code distinguish exceptions from bundle2
-# processing from processing the old format. This is mostly
-# needed to handle different return codes to unbundle according to the
-# type of bundle. We should probably clean up or drop this return code
-# craziness in a future version.
-exc.duringunbundle2 = True
-salvaged = []
-replycaps = None
-if op.reply is not None:
-salvaged = op.reply.salvageoutput()
-replycaps = op.reply.capabilities
-exc._replycaps = replycaps
-exc._bundle2salvagedoutput = salvaged
+# Small hack to let caller code distinguish exceptions from bundle2
+# processing from processing the old format. This is mostly needed
+# to handle different return codes to unbundle according to the 
type
+# of bundle. We should probably clean up or drop this return code
+# craziness in a future version.
+exc.duringunbundle2 = True
+salvaged = []
+replycaps = None
+if op.reply is not None:
+salvaged = op.reply.salvageoutput()
+replycaps = op.reply.capabilities
+exc._replycaps = replycaps
+exc._bundle2salvagedoutput = salvaged
 
-# Re-raising from a variable loses the original stack. So only use
-# that form if we need to.
-if seekerror:
-raise exc
-else:
-raise
-finally:
-repo.ui.debug('bundle2-input-bundle: %i parts total\n' % nbpart)
+# Re-raising from a variable loses the original stack. So only use
+# that form if we need to.
+if seekerror:
+raise exc
+else:
+raise
+finally:
+repo.ui.debug('bundle2-input-bundle: %i parts total\n' % nbpart)
 
 return op
 



To: durham, #hg-reviewers, indygreg
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D706: bundle2: move processpart stream maintenance into part iterator

2017-09-13 Thread durham (Durham Goode)
durham created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  The processpart function also did some stream maintenance, so let's move it to
  the part iterator as well, as part of moving all part iteration logic into the
  class.
  
  There is one place processpart is called outside of the normal loop, so we
  manually handle the seek there.
  
  The now-empty try/finally will be removed in a later patch, for ease of 
review.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D706

AFFECTED FILES
  mercurial/bundle2.py

CHANGE DETAILS

diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -354,21 +354,32 @@
 self.unbundler = unbundler
 self.iterator = None
 self.count = 0
+self.current = None
 
 def __enter__(self):
 def func():
 itr = enumerate(self.unbundler.iterparts())
 for count, p in itr:
 self.count = count
+self.current = p
 yield p
+p.seek(0, 2)
+self.current = None
 self.iterator = func()
 return self.iterator
 
 def __exit__(self, type, exc, tb):
 if not self.iterator:
 return
 
 if exc:
+# If exiting or interrupted, do not attempt to seek the stream in
+# the finally block below. This makes abort faster.
+if (self.current and
+not isinstance(exc, (SystemExit, KeyboardInterrupt))):
+# consume the part content to not corrupt the stream.
+self.current.seek(0, 2)
+
 # Any exceptions seeking to the end of the bundle at this point are
 # almost certainly related to the underlying stream being bad.
 # And, chances are that the exception we're handling is related to
@@ -455,7 +466,6 @@
 The part is guaranteed to have been fully consumed when the function exits
 (even if an exception is raised)."""
 status = 'unknown' # used by debug output
-hardabort = False
 try:
 try:
 handler = parthandlermapping.get(part.type)
@@ -511,15 +521,8 @@
mandatory=False)
 outpart.addparam(
 'in-reply-to', pycompat.bytestr(part.id), mandatory=False)
-# If exiting or interrupted, do not attempt to seek the stream in the
-# finally block below. This makes abort faster.
-except (SystemExit, KeyboardInterrupt):
-hardabort = True
-raise
 finally:
-# consume the part content to not corrupt the stream.
-if not hardabort:
-part.seek(0, 2)
+pass
 
 
 def decodecaps(blob):
@@ -1143,7 +1146,10 @@
 return
 part = unbundlepart(self.ui, headerblock, self._fp)
 op = interruptoperation(self.ui)
-_processpart(op, part)
+try:
+_processpart(op, part)
+finally:
+part.seek(0, 2)
 self.ui.debug('bundle2-input-stream-interrupt:'
   ' closing out of band context\n')
 



To: durham, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D708: bundle2: remove unnecessary try finally

2017-09-13 Thread durham (Durham Goode)
durham created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  This is no longer needed.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D708

AFFECTED FILES
  mercurial/bundle2.py

CHANGE DETAILS

diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -505,32 +505,28 @@
 
 The part is guaranteed to have been fully consumed when the function exits
 (even if an exception is raised)."""
-try:
-handler = _gethandler(op, part)
-if handler is None:
-return
+handler = _gethandler(op, part)
+if handler is None:
+return
 
-# handler is called outside the above try block so that we don't
-# risk catching KeyErrors from anything other than the
-# parthandlermapping lookup (any KeyError raised by handler()
-# itself represents a defect of a different variety).
-output = None
-if op.captureoutput and op.reply is not None:
-op.ui.pushbuffer(error=True, subproc=True)
-output = ''
-try:
-handler(op, part)
-finally:
-if output is not None:
-output = op.ui.popbuffer()
-if output:
-outpart = op.reply.newpart('output', data=output,
-   mandatory=False)
-outpart.addparam(
-'in-reply-to', pycompat.bytestr(part.id), mandatory=False)
+# handler is called outside the above try block so that we don't
+# risk catching KeyErrors from anything other than the
+# parthandlermapping lookup (any KeyError raised by handler()
+# itself represents a defect of a different variety).
+output = None
+if op.captureoutput and op.reply is not None:
+op.ui.pushbuffer(error=True, subproc=True)
+output = ''
+try:
+handler(op, part)
 finally:
-pass
-
+if output is not None:
+output = op.ui.popbuffer()
+if output:
+outpart = op.reply.newpart('output', data=output,
+   mandatory=False)
+outpart.addparam(
+'in-reply-to', pycompat.bytestr(part.id), mandatory=False)
 
 def decodecaps(blob):
 """decode a bundle2 caps bytes blob into a dictionary



To: durham, #hg-reviewers
Cc: mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


  1   2   3   4   5   >