##// END OF EJS Templates
demandimport: avoid infinite recursion at actual module importing (issue5304)...
demandimport: avoid infinite recursion at actual module importing (issue5304) Before this patch, importing C module on Windows environment causes infinite recursion call, if py2exe is used with -b2 option. At importing C module "a.b", extra hooking by zipextimporter of py2exe causes: 0. assumption before accessing "b" of "a": - built-in module object is created for "a", (= "a" is actually imported) - _demandmod is created for "a.b" as a proxy object, and (= "a.b" is not yet imported) - an attribute "b" of "a" is initialized by the latter 1. invocation of __import__ via _hgextimport() in _demandmod._load() for "a.b" implies _demandimport() for "a.b" This is unintentional, because _demandmod might be returned by _hgextimport() instead of built-in module object. 2. _demandimport() at (1) is invoked with not context of "a", but context of zipextimporter Just after invocation of _hgextimport() in _demandimport(), an attribute "b" of the built-in module object for "a" is still bound to the proxy object for "a.b", because context of "a" isn't updated by actual importing "a.b". even though the built-in module object for "a.b" already appears in sys.modules. Therefore, chainmodules() returns _demandmod for "a.b", which is gotten from the attribute "b" of "a". 3. processfromitem() on "a.b" causes _demandmod._load() for "a.b" again _demandimport() takes context of "a" in this case. Therefore, attributes below are bound to built-in module object for "a.b", as expected: - "b" of built-in module object for "a" - _module of _demandmod for "a.b" 4. but _demandimport() invoked at (1) returns _demandmod object because _demandimport() just returns the object returned by chainmodules() at (3) above. 5. then, _demandmod._load() causes infinite recursion call _demandimport() returns _demandmod for "a.b", and it is "self" at _demandmod._load(). To avoid infinite recursion at actual module importing, this patch uses self._module, if _hgextimport() returns _demandmod itself. If _demandmod._module isn't yet bound at this point, execution should be aborted, because actual importing failed. In this patch, _demandmod._module is examined not on _demandimport() side, but on _demandmod._load() side, because: - the former has some exit points - only the latter uses _hgextimport(), except for _demandimport() BTW, this issue occurs only in the code path for non .py/.pyc files in zipextimporter (strictly speaking, in _memimporter) of py2exe. Even if zipextimporter is enabled, .py/.pyc files are handled by zipimporter, and it doesn't imply unintentional _demandimport() at invocation of __import__ via _hgextimport().

File last commit:

r29421:ecbbf4d5 default
r29642:8960fcb7 stable
Show More
localstore.py
66 lines | 2.3 KiB | text/x-python | PythonLexer
various
hgext: add largefiles extension...
r15168 # Copyright 2009-2010 Gregory P. Ward
# Copyright 2009-2010 Intelerad Medical Systems Incorporated
# Copyright 2010-2011 Fog Creek Software
# Copyright 2010-2011 Unity Technologies
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
Greg Ward
largefiles: improve comments, internal docstrings...
r15252 '''store class for local filesystem'''
liscju
py3: make largefiles/localstore.py use absolute_import
r29310 from __future__ import absolute_import
various
hgext: add largefiles extension...
r15168
from mercurial.i18n import _
liscju
py3: make largefiles/localstore.py use absolute_import
r29310 from . import (
basestore,
lfutil,
)
various
hgext: add largefiles extension...
r15168
class localstore(basestore.basestore):
Benjamin Pollack
largefiles: make the store primary, and the user cache secondary...
r15317 '''localstore first attempts to grab files out of the store in the remote
Mads Kiilerich
fix trivial spelling errors
r17424 Mercurial repository. Failing that, it attempts to grab the files from
Benjamin Pollack
largefiles: make the store primary, and the user cache secondary...
r15317 the user cache.'''
various
hgext: add largefiles extension...
r15168
def __init__(self, ui, repo, remote):
Sune Foldager
peer: introduce peer methods to prepare for peer classes...
r17191 self.remote = remote.local()
Mads Kiilerich
largefiles: cleanup of warnings on errors getting largefiles...
r18155 super(localstore, self).__init__(ui, repo, self.remote.url())
various
hgext: add largefiles extension...
r15168
Benjamin Pollack
largefiles: make the store primary, and the user cache secondary...
r15317 def put(self, source, hash):
if lfutil.instore(self.remote, hash):
return
Mads Kiilerich
largefiles: 'put' should store 'source' file in under 'hash', also in localstore
r19007 lfutil.link(source, lfutil.storepath(self.remote, hash))
various
hgext: add largefiles extension...
r15168
Matt Harbison
largefiles: adjust localstore to handle batch statlfile requests (issue3583)...
r17411 def exists(self, hashes):
retval = {}
for hash in hashes:
retval[hash] = lfutil.instore(self.remote, hash)
return retval
various
hgext: add largefiles extension...
r15168 def _getfile(self, tmpfile, filename, hash):
Mads Kiilerich
largefiles: refactoring - use findfile in localstore._getfile
r19000 path = lfutil.findfile(self.remote, hash)
if not path:
Mads Kiilerich
largefiles: cleanup of warnings on errors getting largefiles...
r18155 raise basestore.StoreError(filename, hash, self.url,
Martin Geisler
largefiles: lowercase messages
r16928 _("can't get file locally"))
Bryan O'Sullivan
largefiles: use a context manager in _getfile
r27769 with open(path, 'rb') as fd:
Benjamin Pollack
largefiles: make the store primary, and the user cache secondary...
r15317 return lfutil.copyandhash(fd, tmpfile)
various
hgext: add largefiles extension...
r15168
liscju
largefiles: change basestore._verifyfile to take list of files to check...
r29067 def _verifyfiles(self, contents, filestocheck):
failed = False
for cset, filename, expectedhash in filestocheck:
liscju
largefiles: check file in the repo store before checking remotely (issue5257)...
r29421 storepath, exists = lfutil.findstorepath(self.repo, expectedhash)
if not exists:
storepath, exists = lfutil.findstorepath(
self.remote, expectedhash)
liscju
largefiles: change basestore._verifyfile to take list of files to check...
r29067 if not exists:
various
hgext: add largefiles extension...
r15168 self.ui.warn(
liscju
largefiles: change basestore._verifyfile to take list of files to check...
r29067 _('changeset %s: %s references missing %s\n')
Mads Kiilerich
largefiles: report localstore errors with single line warnings messages...
r18545 % (cset, filename, storepath))
liscju
largefiles: change basestore._verifyfile to take list of files to check...
r29067 failed = True
elif contents:
actualhash = lfutil.hashfile(storepath)
if actualhash != expectedhash:
self.ui.warn(
_('changeset %s: %s references corrupted %s\n')
% (cset, filename, storepath))
failed = True
return failed