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