|
|
# packagescan.py - Helper module for identifing used modules.
|
|
|
# Used for the py2exe distutil.
|
|
|
# This module must be the first mercurial module imported in setup.py
|
|
|
#
|
|
|
# Copyright 2005, 2006 Volker Kleinfeld <Volker.Kleinfeld@gmx.de>
|
|
|
#
|
|
|
# This software may be used and distributed according to the terms
|
|
|
# of the GNU General Public License, incorporated herein by reference.
|
|
|
import glob
|
|
|
import os
|
|
|
import sys
|
|
|
import ihooks
|
|
|
import types
|
|
|
import string
|
|
|
|
|
|
# Install this module as fake demandload module
|
|
|
sys.modules['mercurial.demandload'] = sys.modules[__name__]
|
|
|
|
|
|
# Requiredmodules contains the modules imported by demandload.
|
|
|
# Please note that demandload can be invoked before the
|
|
|
# mercurial.packagescan.scan method is invoked in case a mercurial
|
|
|
# module is imported.
|
|
|
requiredmodules = {}
|
|
|
def demandload(scope, modules):
|
|
|
""" fake demandload function that collects the required modules
|
|
|
foo import foo
|
|
|
foo bar import foo, bar
|
|
|
foo.bar import foo.bar
|
|
|
foo@bar import foo as bar
|
|
|
foo:bar from foo import bar
|
|
|
foo:bar,quux from foo import bar, quux
|
|
|
foo.bar:quux from foo.bar import quux"""
|
|
|
|
|
|
for m in modules.split():
|
|
|
mod = None
|
|
|
try:
|
|
|
module, fromlist = m.split(':')
|
|
|
fromlist = fromlist.split(',')
|
|
|
except:
|
|
|
module = m
|
|
|
fromlist = []
|
|
|
as_ = None
|
|
|
if '@' in module:
|
|
|
module, as_ = module.split('@')
|
|
|
mod = __import__(module, scope, scope, fromlist)
|
|
|
if fromlist == []:
|
|
|
# mod is only the top package, but we need all packages
|
|
|
comp = module.split('.')
|
|
|
i = 1
|
|
|
mn = comp[0]
|
|
|
while True:
|
|
|
# mn and mod.__name__ might not be the same
|
|
|
if not as_:
|
|
|
as_ = mn
|
|
|
scope[as_] = mod
|
|
|
requiredmodules[mod.__name__] = 1
|
|
|
if len(comp) == i: break
|
|
|
mod = getattr(mod, comp[i])
|
|
|
mn = string.join(comp[:i+1],'.')
|
|
|
i += 1
|
|
|
else:
|
|
|
# mod is the last package in the component list
|
|
|
requiredmodules[mod.__name__] = 1
|
|
|
for f in fromlist:
|
|
|
scope[f] = getattr(mod, f)
|
|
|
if type(scope[f]) == types.ModuleType:
|
|
|
requiredmodules[scope[f].__name__] = 1
|
|
|
|
|
|
class SkipPackage(Exception):
|
|
|
def __init__(self, reason):
|
|
|
self.reason = reason
|
|
|
|
|
|
scan_in_progress = False
|
|
|
|
|
|
def scan(libpath, packagename):
|
|
|
""" helper for finding all required modules of package <packagename> """
|
|
|
global scan_in_progress
|
|
|
scan_in_progress = True
|
|
|
# Use the package in the build directory
|
|
|
libpath = os.path.abspath(libpath)
|
|
|
sys.path.insert(0, libpath)
|
|
|
packdir = os.path.join(libpath, packagename.replace('.', '/'))
|
|
|
# A normal import would not find the package in
|
|
|
# the build directory. ihook is used to force the import.
|
|
|
# After the package is imported the import scope for
|
|
|
# the following imports is settled.
|
|
|
p = importfrom(packdir)
|
|
|
globals()[packagename] = p
|
|
|
sys.modules[packagename] = p
|
|
|
# Fetch the python modules in the package
|
|
|
cwd = os.getcwd()
|
|
|
os.chdir(packdir)
|
|
|
pymodulefiles = glob.glob('*.py')
|
|
|
extmodulefiles = glob.glob('*.pyd')
|
|
|
os.chdir(cwd)
|
|
|
# Import all python modules and by that run the fake demandload
|
|
|
for m in pymodulefiles:
|
|
|
if m == '__init__.py': continue
|
|
|
tmp = {}
|
|
|
mname, ext = os.path.splitext(m)
|
|
|
fullname = packagename+'.'+mname
|
|
|
try:
|
|
|
__import__(fullname, tmp, tmp)
|
|
|
except SkipPackage, inst:
|
|
|
print >> sys.stderr, 'skipping %s: %s' % (fullname, inst.reason)
|
|
|
continue
|
|
|
requiredmodules[fullname] = 1
|
|
|
# Import all extension modules and by that run the fake demandload
|
|
|
for m in extmodulefiles:
|
|
|
tmp = {}
|
|
|
mname, ext = os.path.splitext(m)
|
|
|
fullname = packagename+'.'+mname
|
|
|
__import__(fullname, tmp, tmp)
|
|
|
requiredmodules[fullname] = 1
|
|
|
|
|
|
def getmodules():
|
|
|
return requiredmodules.keys()
|
|
|
|
|
|
def importfrom(filename):
|
|
|
"""
|
|
|
import module/package from a named file and returns the module.
|
|
|
It does not check on sys.modules or includes the module in the scope.
|
|
|
"""
|
|
|
loader = ihooks.BasicModuleLoader()
|
|
|
path, file = os.path.split(filename)
|
|
|
name, ext = os.path.splitext(file)
|
|
|
m = loader.find_module_in_dir(name, path)
|
|
|
if not m:
|
|
|
raise ImportError, name
|
|
|
m = loader.load_module(name, m)
|
|
|
return m
|
|
|
|