]>
Commit | Line | Data |
---|---|---|
1 | # Erebus IRC bot - Author: John Runyon | |
2 | # module loading/unloading/tracking code | |
3 | ||
4 | from __future__ import print_function | |
5 | ||
6 | import sys, time, importlib | |
7 | import modlib | |
8 | ||
9 | if sys.version_info.major >= 3: | |
10 | from importlib import reload | |
11 | else: | |
12 | importlib.invalidate_caches = lambda: None | |
13 | ||
14 | modules = {} | |
15 | dependents = {} | |
16 | #dependents[modname] = [list of modules which depend on modname] | |
17 | ||
18 | def isloaded(modname): return modname in modules | |
19 | def modhas(modname, attname): return getattr(modules[modname], attname, None) is not None | |
20 | ||
21 | def load(parent, modname, dependent=False): | |
22 | """Wrapper to call _load and print the return value.""" | |
23 | if dependent: | |
24 | print("(Loading dependency %s..." % (modname), end=' ') | |
25 | else: | |
26 | print("%09.3f [MOD] [?] Loading %s..." % (time.time() % 100000, modname), end=' ') | |
27 | modstatus = _load(parent, modname, dependent) | |
28 | if not modstatus: | |
29 | if dependent: | |
30 | print("failed: %s)" % (modstatus), end=' ') | |
31 | else: | |
32 | print("failed: %s." % (modstatus)) | |
33 | elif modstatus == True: | |
34 | if dependent: | |
35 | print("OK)", end=' ') | |
36 | else: | |
37 | print("OK.") | |
38 | else: | |
39 | if dependent: | |
40 | print("OK: %s)" % (modstatus), end=' ') | |
41 | else: | |
42 | print("OK: %s." % (modstatus)) | |
43 | return modstatus | |
44 | ||
45 | def _load(parent, modname, dependent=False): | |
46 | """Load and return the new status of the module.""" | |
47 | successstatus = [] | |
48 | if not isloaded(modname): | |
49 | importlib.invalidate_caches() | |
50 | try: | |
51 | mod = importlib.import_module('modules.'+modname) | |
52 | reload(mod) #in case it's been previously loaded. | |
53 | except Exception as e: | |
54 | return modlib.error(e) | |
55 | ||
56 | ||
57 | if not hasattr(mod, 'modinfo'): | |
58 | return modlib.error('no modinfo') | |
59 | ||
60 | if parent.APIVERSION not in mod.modinfo['compatible']: | |
61 | return modlib.error('API-incompatible') | |
62 | ||
63 | modules[modname] = mod | |
64 | dependents[modname] = [] | |
65 | ||
66 | for dep in mod.modinfo['depends']: | |
67 | if bool(int(parent.cfg.get('autoloads', dep, default=1))): | |
68 | if dep not in modules: | |
69 | depret = load(parent, dep, dependent=True) | |
70 | if depret is not None and not depret: | |
71 | return depret | |
72 | else: | |
73 | return modlib.error("dependent %s disabled" % (dep)) | |
74 | dependents[dep].append(modname) | |
75 | ||
76 | for dep in mod.modinfo['softdeps']: | |
77 | if bool(int(parent.cfg.get('autoloads', dep, default=1))): | |
78 | if dep not in modules: | |
79 | depret = load(parent, dep, dependent=True) | |
80 | if depret is not None: | |
81 | if not depret: | |
82 | successstatus.append("softdep %s failed" % (dep)) | |
83 | else: | |
84 | successstatus.append("softdep %s disabled" % (dep)) | |
85 | #swallow errors loading - softdeps are preferred, not required | |
86 | ||
87 | ||
88 | ret = mod.modstart(parent) | |
89 | if ret is None: | |
90 | ret = True | |
91 | if not ret: | |
92 | del modules[modname] | |
93 | del dependents[modname] | |
94 | for dep in mod.modinfo['depends']: | |
95 | dependents[dep].remove(modname) | |
96 | ||
97 | successstatus = ';'.join(successstatus) | |
98 | if len(successstatus) > 0 and ret: | |
99 | if ret == True: | |
100 | return successstatus | |
101 | else: | |
102 | return "%s (%s)" % (ret, successstatus) | |
103 | else: | |
104 | return ret | |
105 | else: #if not isloaded...else: | |
106 | return modlib.error('already loaded') | |
107 | ||
108 | def unload(parent, modname): | |
109 | if isloaded(modname): | |
110 | for dependent in dependents[modname]: | |
111 | unload(parent, dependent) | |
112 | for dep in modules[modname].modinfo['depends']: | |
113 | dependents[dep].remove(modname) | |
114 | ret = modules[modname].modstop(parent) | |
115 | del modules[modname] | |
116 | return ret | |
117 | else: | |
118 | return modlib.error('already unloaded') | |
119 | ||
120 | def reloadmod(parent, modname): | |
121 | if isloaded(modname): | |
122 | if modhas(modname, 'modrestart'): modules[modname].modrestart(parent) | |
123 | else: modules[modname].modstop(parent) | |
124 | ||
125 | try: | |
126 | reload(modules[modname]) | |
127 | except BaseException as e: | |
128 | return modlib.error(e) | |
129 | ||
130 | if modhas(modname, 'modrestarted'): ret = modules[modname].modrestarted(parent) | |
131 | else: ret = modules[modname].modstart(parent) | |
132 | ||
133 | return ret | |
134 | else: | |
135 | return load(parent, modname) | |
136 | ||
137 | ||
138 | def loadall(parent, modlist): | |
139 | for m in modlist: load(parent, m) | |
140 | def unloadall(parent, modlist): | |
141 | for m in modlist: unload(parent, m) | |
142 | def reloadall(parent, modlist): | |
143 | for m in modlist: reloadmod(parent, m) |