Rework prompt: add exception classes for errors and reload/quit
This commit is contained in:
parent
0d21b1fa2c
commit
fd6d9288f7
6 changed files with 89 additions and 19 deletions
|
@ -26,6 +26,7 @@ import sys
|
||||||
import bot
|
import bot
|
||||||
import prompt
|
import prompt
|
||||||
from prompt.builtins import load_file
|
from prompt.builtins import load_file
|
||||||
|
from prompt.reset import PromptReset
|
||||||
import importer
|
import importer
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -116,7 +117,13 @@ if __name__ == "__main__":
|
||||||
print ("Nemubot v%s ready, my PID is %i!" % (bot.__version__,
|
print ("Nemubot v%s ready, my PID is %i!" % (bot.__version__,
|
||||||
os.getpid()))
|
os.getpid()))
|
||||||
context.start()
|
context.start()
|
||||||
while prmpt.run(context):
|
while True:
|
||||||
|
try:
|
||||||
|
prmpt.run(context)
|
||||||
|
except PromptReset as e:
|
||||||
|
if e.type == "quit":
|
||||||
|
break
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Reload context
|
# Reload context
|
||||||
imp.reload(bot)
|
imp.reload(bot)
|
||||||
|
|
|
@ -23,6 +23,8 @@ import shlex
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
from .error import PromptError
|
||||||
|
from .reset import PromptReset
|
||||||
from . import builtins
|
from . import builtins
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,12 +32,14 @@ class Prompt:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.selectedServer = None
|
self.selectedServer = None
|
||||||
|
self.lastretcode = 0
|
||||||
|
|
||||||
self.HOOKS_CAPS = dict()
|
self.HOOKS_CAPS = dict()
|
||||||
self.HOOKS_LIST = dict()
|
self.HOOKS_LIST = dict()
|
||||||
|
|
||||||
def add_cap_hook(self, name, call, data=None):
|
def add_cap_hook(self, name, call, data=None):
|
||||||
self.HOOKS_CAPS[name] = (lambda d, t, c, p: call(d, t, c, p), data)
|
self.HOOKS_CAPS[name] = lambda t, c: call(t, data=data,
|
||||||
|
context=c, prompt=self)
|
||||||
|
|
||||||
def add_list_hook(self, name, call):
|
def add_list_hook(self, name, call):
|
||||||
self.HOOKS_LIST[name] = call
|
self.HOOKS_LIST[name] = call
|
||||||
|
@ -77,13 +81,12 @@ class Prompt:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if toks[0] in builtins.CAPS:
|
if toks[0] in builtins.CAPS:
|
||||||
return builtins.CAPS[toks[0]](toks, context, self)
|
self.lastretcode = builtins.CAPS[toks[0]](toks, context, self)
|
||||||
elif toks[0] in self.HOOKS_CAPS:
|
elif toks[0] in self.HOOKS_CAPS:
|
||||||
f, d = self.HOOKS_CAPS[toks[0]]
|
self.lastretcode = self.HOOKS_CAPS[toks[0]](toks, context)
|
||||||
return f(d, toks, context, self)
|
|
||||||
else:
|
else:
|
||||||
print("Unknown command: `%s'" % toks[0])
|
print("Unknown command: `%s'" % toks[0])
|
||||||
return ""
|
self.lastretcode = 127
|
||||||
|
|
||||||
def getPS1(self):
|
def getPS1(self):
|
||||||
"""Get the PS1 associated to the selected server"""
|
"""Get the PS1 associated to the selected server"""
|
||||||
|
@ -99,14 +102,19 @@ class Prompt:
|
||||||
context -- current bot context
|
context -- current bot context
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ret = ""
|
while True: # Stopped by exception
|
||||||
while ret != "quit" and ret != "reset" and ret != "refresh":
|
|
||||||
try:
|
try:
|
||||||
line = input("\033[0;33m%s§\033[0m " % self.getPS1())
|
line = input("\033[0;33m%s\033[0;%dm§\033[0m " %
|
||||||
|
(self.getPS1(), 31 if self.lastretcode else 32))
|
||||||
cmds = self.lex_cmd(line.strip())
|
cmds = self.lex_cmd(line.strip())
|
||||||
for toks in cmds:
|
for toks in cmds:
|
||||||
try:
|
try:
|
||||||
ret = self.exec_cmd(toks, context)
|
self.exec_cmd(toks, context)
|
||||||
|
except PromptReset:
|
||||||
|
raise
|
||||||
|
except PromptError as e:
|
||||||
|
print(e.message)
|
||||||
|
self.lastretcode = 128
|
||||||
except:
|
except:
|
||||||
exc_type, exc_value, exc_traceback = sys.exc_info()
|
exc_type, exc_value, exc_traceback = sys.exc_info()
|
||||||
traceback.print_exception(exc_type, exc_value,
|
traceback.print_exception(exc_type, exc_value,
|
||||||
|
@ -114,9 +122,8 @@ class Prompt:
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print("")
|
print("")
|
||||||
except EOFError:
|
except EOFError:
|
||||||
ret = "quit"
|
|
||||||
print("quit")
|
print("quit")
|
||||||
return ret != "quit"
|
raise PromptReset("quit")
|
||||||
|
|
||||||
|
|
||||||
def hotswap(bak):
|
def hotswap(bak):
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from .reset import PromptReset
|
||||||
from tools.config import load_file
|
from tools.config import load_file
|
||||||
|
|
||||||
logger = logging.getLogger("nemubot.prompt.builtins")
|
logger = logging.getLogger("nemubot.prompt.builtins")
|
||||||
|
@ -26,12 +27,10 @@ logger = logging.getLogger("nemubot.prompt.builtins")
|
||||||
def end(toks, context, prompt):
|
def end(toks, context, prompt):
|
||||||
"""Quit the prompt for reload or exit"""
|
"""Quit the prompt for reload or exit"""
|
||||||
if toks[0] == "refresh":
|
if toks[0] == "refresh":
|
||||||
return "refresh"
|
raise PromptReset("refresh")
|
||||||
elif toks[0] == "reset":
|
elif toks[0] == "reset":
|
||||||
return "reset"
|
raise PromptReset("reset")
|
||||||
else:
|
raise PromptReset("quit")
|
||||||
context.quit()
|
|
||||||
return "quit"
|
|
||||||
|
|
||||||
|
|
||||||
def liste(toks, context, prompt):
|
def liste(toks, context, prompt):
|
||||||
|
@ -58,8 +57,11 @@ def liste(toks, context, prompt):
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print (" Unknown list `%s'" % l)
|
print (" Unknown list `%s'" % l)
|
||||||
|
return 2
|
||||||
|
return 0
|
||||||
else:
|
else:
|
||||||
print (" Please give a list to show: servers, ...")
|
print (" Please give a list to show: servers, ...")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
def load(toks, context, prompt):
|
def load(toks, context, prompt):
|
||||||
|
@ -69,7 +71,7 @@ def load(toks, context, prompt):
|
||||||
load_file(filename, context)
|
load_file(filename, context)
|
||||||
else:
|
else:
|
||||||
print ("Not enough arguments. `load' takes a filename.")
|
print ("Not enough arguments. `load' takes a filename.")
|
||||||
return
|
return 1
|
||||||
|
|
||||||
|
|
||||||
def select(toks, context, prompt):
|
def select(toks, context, prompt):
|
||||||
|
@ -80,9 +82,9 @@ def select(toks, context, prompt):
|
||||||
prompt.selectedServer = context.servers[toks[1]]
|
prompt.selectedServer = context.servers[toks[1]]
|
||||||
else:
|
else:
|
||||||
print ("select: server `%s' not found." % toks[1])
|
print ("select: server `%s' not found." % toks[1])
|
||||||
|
return 1
|
||||||
else:
|
else:
|
||||||
prompt.selectedServer = None
|
prompt.selectedServer = None
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def unload(toks, context, prompt):
|
def unload(toks, context, prompt):
|
||||||
|
@ -96,8 +98,10 @@ def unload(toks, context, prompt):
|
||||||
print (" Module `%s' successfully unloaded." % name)
|
print (" Module `%s' successfully unloaded." % name)
|
||||||
else:
|
else:
|
||||||
print (" No module `%s' loaded, can't unload!" % name)
|
print (" No module `%s' loaded, can't unload!" % name)
|
||||||
|
return 2
|
||||||
else:
|
else:
|
||||||
print ("Not enough arguments. `unload' takes a module name.")
|
print ("Not enough arguments. `unload' takes a module name.")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
def debug(toks, context, prompt):
|
def debug(toks, context, prompt):
|
||||||
|
@ -112,8 +116,10 @@ def debug(toks, context, prompt):
|
||||||
print (" Debug for module module `%s' disabled." % name)
|
print (" Debug for module module `%s' disabled." % name)
|
||||||
else:
|
else:
|
||||||
print (" No module `%s' loaded, can't debug!" % name)
|
print (" No module `%s' loaded, can't debug!" % name)
|
||||||
|
return 2
|
||||||
else:
|
else:
|
||||||
print ("Not enough arguments. `debug' takes a module name.")
|
print ("Not enough arguments. `debug' takes a module name.")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
# Register build-ins
|
# Register build-ins
|
||||||
|
|
23
prompt/error.py
Normal file
23
prompt/error.py
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# coding=utf-8
|
||||||
|
|
||||||
|
# Nemubot is a modulable IRC bot, built around XML configuration files.
|
||||||
|
# Copyright (C) 2012 Mercier Pierre-Olivier
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
class PromptError(Exception):
|
||||||
|
|
||||||
|
def __init__(self, message):
|
||||||
|
super(PromptError, self).__init__(message)
|
||||||
|
self.message = message
|
23
prompt/reset.py
Normal file
23
prompt/reset.py
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# coding=utf-8
|
||||||
|
|
||||||
|
# Nemubot is a modulable IRC bot, built around XML configuration files.
|
||||||
|
# Copyright (C) 2012 Mercier Pierre-Olivier
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
class PromptReset(Exception):
|
||||||
|
|
||||||
|
def __init__(self, type):
|
||||||
|
super(PromptReset, self).__init__("Prompt reset asked")
|
||||||
|
self.type = type
|
|
@ -69,6 +69,8 @@ class AbstractServer(io.IOBase):
|
||||||
if not hasattr(self, "_open") or self._open():
|
if not hasattr(self, "_open") or self._open():
|
||||||
_rlist.append(self)
|
_rlist.append(self)
|
||||||
_xlist.append(self)
|
_xlist.append(self)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
|
@ -82,6 +84,8 @@ class AbstractServer(io.IOBase):
|
||||||
_wlist.remove(self)
|
_wlist.remove(self)
|
||||||
if self in _xlist:
|
if self in _xlist:
|
||||||
_xlist.remove(self)
|
_xlist.remove(self)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
# Writes
|
# Writes
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue