1 # packagescan.py - Helper module for identifing used modules. |
|
2 # Used for the py2exe distutil. |
|
3 # This module must be the first mercurial module imported in setup.py |
|
4 # |
|
5 # Copyright 2005, 2006 Volker Kleinfeld <Volker.Kleinfeld@gmx.de> |
|
6 # |
|
7 # This software may be used and distributed according to the terms |
|
8 # of the GNU General Public License, incorporated herein by reference. |
|
9 import glob |
|
10 import os |
|
11 import sys |
|
12 import ihooks |
|
13 import types |
|
14 import string |
|
15 |
|
16 # Install this module as fake demandload module |
|
17 sys.modules['mercurial.demandload'] = sys.modules[__name__] |
|
18 |
|
19 # Requiredmodules contains the modules imported by demandload. |
|
20 # Please note that demandload can be invoked before the |
|
21 # mercurial.packagescan.scan method is invoked in case a mercurial |
|
22 # module is imported. |
|
23 requiredmodules = {} |
|
24 def demandload(scope, modules): |
|
25 """ fake demandload function that collects the required modules |
|
26 foo import foo |
|
27 foo bar import foo, bar |
|
28 foo.bar import foo.bar |
|
29 foo@bar import foo as bar |
|
30 foo:bar from foo import bar |
|
31 foo:bar,quux from foo import bar, quux |
|
32 foo.bar:quux from foo.bar import quux""" |
|
33 |
|
34 for m in modules.split(): |
|
35 mod = None |
|
36 try: |
|
37 module, fromlist = m.split(':') |
|
38 fromlist = fromlist.split(',') |
|
39 except: |
|
40 module = m |
|
41 fromlist = [] |
|
42 as_ = None |
|
43 if '@' in module: |
|
44 module, as_ = module.split('@') |
|
45 mod = __import__(module, scope, scope, fromlist) |
|
46 if fromlist == []: |
|
47 # mod is only the top package, but we need all packages |
|
48 comp = module.split('.') |
|
49 i = 1 |
|
50 mn = comp[0] |
|
51 while True: |
|
52 # mn and mod.__name__ might not be the same |
|
53 if not as_: |
|
54 as_ = mn |
|
55 scope[as_] = mod |
|
56 requiredmodules[mod.__name__] = 1 |
|
57 if len(comp) == i: break |
|
58 mod = getattr(mod, comp[i]) |
|
59 mn = string.join(comp[:i+1],'.') |
|
60 i += 1 |
|
61 else: |
|
62 # mod is the last package in the component list |
|
63 requiredmodules[mod.__name__] = 1 |
|
64 for f in fromlist: |
|
65 scope[f] = getattr(mod, f) |
|
66 if type(scope[f]) == types.ModuleType: |
|
67 requiredmodules[scope[f].__name__] = 1 |
|
68 |
|
69 class SkipPackage(Exception): |
|
70 def __init__(self, reason): |
|
71 self.reason = reason |
|
72 |
|
73 scan_in_progress = False |
|
74 |
|
75 def scan(libpath, packagename): |
|
76 """ helper for finding all required modules of package <packagename> """ |
|
77 global scan_in_progress |
|
78 scan_in_progress = True |
|
79 # Use the package in the build directory |
|
80 libpath = os.path.abspath(libpath) |
|
81 sys.path.insert(0, libpath) |
|
82 packdir = os.path.join(libpath, packagename.replace('.', '/')) |
|
83 # A normal import would not find the package in |
|
84 # the build directory. ihook is used to force the import. |
|
85 # After the package is imported the import scope for |
|
86 # the following imports is settled. |
|
87 p = importfrom(packdir) |
|
88 globals()[packagename] = p |
|
89 sys.modules[packagename] = p |
|
90 # Fetch the python modules in the package |
|
91 cwd = os.getcwd() |
|
92 os.chdir(packdir) |
|
93 pymodulefiles = glob.glob('*.py') |
|
94 extmodulefiles = glob.glob('*.pyd') |
|
95 os.chdir(cwd) |
|
96 # Import all python modules and by that run the fake demandload |
|
97 for m in pymodulefiles: |
|
98 if m == '__init__.py': continue |
|
99 tmp = {} |
|
100 mname, ext = os.path.splitext(m) |
|
101 fullname = packagename+'.'+mname |
|
102 try: |
|
103 __import__(fullname, tmp, tmp) |
|
104 except SkipPackage, inst: |
|
105 print >> sys.stderr, 'skipping %s: %s' % (fullname, inst.reason) |
|
106 continue |
|
107 requiredmodules[fullname] = 1 |
|
108 # Import all extension modules and by that run the fake demandload |
|
109 for m in extmodulefiles: |
|
110 tmp = {} |
|
111 mname, ext = os.path.splitext(m) |
|
112 fullname = packagename+'.'+mname |
|
113 __import__(fullname, tmp, tmp) |
|
114 requiredmodules[fullname] = 1 |
|
115 |
|
116 def getmodules(): |
|
117 return requiredmodules.keys() |
|
118 |
|
119 def importfrom(filename): |
|
120 """ |
|
121 import module/package from a named file and returns the module. |
|
122 It does not check on sys.modules or includes the module in the scope. |
|
123 """ |
|
124 loader = ihooks.BasicModuleLoader() |
|
125 path, file = os.path.split(filename) |
|
126 name, ext = os.path.splitext(file) |
|
127 m = loader.find_module_in_dir(name, path) |
|
128 if not m: |
|
129 raise ImportError, name |
|
130 m = loader.load_module(name, m) |
|
131 return m |
|