]>
jfr.im git - erebus.git/blob - ctlmod.py
1 # Erebus IRC bot - Author: John Runyon
2 # vim: fileencoding=utf-8
3 # module loading/unloading/tracking code
5 from __future__
import print_function
7 import sys
, time
, importlib
, traceback
10 if sys
.version_info
.major
>= 3:
11 from importlib
import reload # reload is only available as a global in Py2, only in importlib in Py3
13 importlib
.invalidate_caches
= lambda: None # invalidate_caches doesn't exist in Py2
17 #dependents[modname] = [list of modules which depend on modname]
19 def isloaded(modname
): return modname
in modules
20 def modhas(modname
, attname
): return getattr(modules
[modname
], attname
, None) is not None
22 def load(parent
, modname
, dependent
=False):
23 """Wrapper to call _load and print the return value."""
25 print("(Loading dependency %s..." % (modname
), end
=' ')
27 print("%09.3f [MOD] [?] Loading %s..." % (time
.time() % 100000, modname
), end
=' ')
28 modstatus
= _load(parent
, modname
, dependent
)
31 print("failed: %s)" % (modstatus
), end
=' ')
33 print("failed: %s." % (modstatus
))
34 if isinstance(modstatus
, modlib
.error
) and isinstance(modstatus
.errormsg
, BaseException
):
35 traceback
.print_exception(modstatus
.errormsg
)
36 elif modstatus
== True:
43 print("OK: %s)" % (modstatus
), end
=' ')
45 print("OK: %s." % (modstatus
))
48 def _load(parent
, modname
, dependent
=False):
49 """Load and return the new status of the module."""
51 if not isloaded(modname
):
52 importlib
.invalidate_caches()
54 mod
= importlib
.import_module('modules.'+modname
)
55 reload(mod
) #in case it's been previously loaded.
56 except Exception as e
:
57 return modlib
.error(e
)
60 if not hasattr(mod
, 'modinfo'):
61 return modlib
.error('no modinfo')
63 if parent
.APIVERSION
not in mod
.modinfo
['compatible']:
64 return modlib
.error('API-incompatible')
66 modules
[modname
] = mod
67 dependents
[modname
] = []
69 for dep
in mod
.modinfo
['depends']:
70 if bool(int(parent
.cfg
.get('autoloads', dep
, default
=1))):
71 if dep
not in modules
:
72 depret
= load(parent
, dep
, dependent
=True)
73 if depret
is not None and not depret
:
76 return modlib
.error("dependent %s disabled" % (dep
))
77 dependents
[dep
].append(modname
)
79 for dep
in mod
.modinfo
['softdeps']:
80 if bool(int(parent
.cfg
.get('autoloads', dep
, default
=1))):
81 if dep
not in modules
:
82 depret
= load(parent
, dep
, dependent
=True)
83 if depret
is not None and not depret
:
84 successstatus
.append("softdep %s failed" % (dep
))
86 successstatus
.append("softdep %s disabled" % (dep
))
87 #swallow errors loading - softdeps are preferred, not required
91 ret
= mod
.modstart(parent
)
92 except Exception as e
:
93 return modlib
.error(e
)
98 del dependents
[modname
]
99 for dep
in mod
.modinfo
['depends']:
100 dependents
[dep
].remove(modname
)
102 successstatus
= ';'.join(successstatus
)
103 if len(successstatus
) > 0 and ret
:
107 return "%s (%s)" % (ret
, successstatus
)
110 else: #if not isloaded...else:
111 return modlib
.error('already loaded')
113 def unload(parent
, modname
):
114 if isloaded(modname
):
115 for dependent
in dependents
[modname
]:
116 unload(parent
, dependent
)
117 for dep
in modules
[modname
].modinfo
['depends']:
118 dependents
[dep
].remove(modname
)
119 ret
= modules
[modname
].modstop(parent
)
123 return modlib
.error('already unloaded')
125 def reloadmod(parent
, modname
):
126 if isloaded(modname
):
127 if modhas(modname
, 'modrestart'): modules
[modname
].modrestart(parent
)
128 else: modules
[modname
].modstop(parent
)
131 reload(modules
[modname
])
132 except BaseException
as e
:
133 return modlib
.error(e
)
135 if modhas(modname
, 'modrestarted'): ret
= modules
[modname
].modrestarted(parent
)
136 else: ret
= modules
[modname
].modstart(parent
)
140 return load(parent
, modname
)
143 def loadall(parent
, modlist
):
144 for m
in modlist
: load(parent
, m
)
145 def unloadall(parent
, modlist
):
146 for m
in modlist
: unload(parent
, m
)
147 def reloadall(parent
, modlist
):
148 for m
in modlist
: reloadmod(parent
, m
)