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