diff --git a/components/tools/OmeroPy/src/omero/cli.py b/components/tools/OmeroPy/src/omero/cli.py index 94532ce224f..2f426552500 100755 --- a/components/tools/OmeroPy/src/omero/cli.py +++ b/components/tools/OmeroPy/src/omero/cli.py @@ -650,6 +650,34 @@ def _check_admin(*args, **kwargs): return _admin_only +class Error(object): + """ + Wrapper for error messages which can be registered by an BaseControl + subclass in its _configure method. Example: + + class MyControl(BaseControl): + def _configure(self, parser): + self.add_error("NAME", 100, "some message: %s") + ... + def __call__(self, *args): + self.raise_error("NAME", "my text") + """ + + def __init__(self, ctx, rcode, msg): + self.ctx = ctx + self.rcode = rcode + self.msg = msg + + def die(self, *args): + """ + Call ctx.die passing the return code and the message for this instance + """ + self.ctx.die(self.rcode, self.msg % tuple(args)) + + def __str__(self): + return "Error(%d, '%s')" % (self.rcode, self.msg) + + class BaseControl(object): """Controls get registered with a CLI instance on loadplugins(). @@ -679,6 +707,32 @@ def __init__(self, ctx=None, dir=OMERODIR): self.ctx = ctx if self.ctx is None: self.ctx = Context() # Prevents unncessary stop_event creation + self.__errors = {} + + def add_error(self, name, rcode, msg): + """ + Register an Error by name both for discovery via the ErrorsControl + as well as for raising an exception via raise_error. + """ + err = self.__errors.get(name) + if err is not None: + self.ctx.die(2, "Error already exists: %s (%s)" % (name, err)) + self.__errors[name] = Error(self.ctx, rcode, msg) + + def get_errors(self): + """ + Returns a mapping from name to Error object + """ + return dict(self.__errors) + + def raise_error(self, name, *args): + """ + Call die on the named Error using the arguments to format the message + """ + err = self.__errors.get(name) + if err is None: + self.ctx.die(2, "Error doesn't exist: %s" % name) + err.die(*args) def _isWindows(self): p_s = platform.system() diff --git a/components/tools/OmeroPy/src/omero/plugins/admin.py b/components/tools/OmeroPy/src/omero/plugins/admin.py index aeda1624c66..3765616b42e 100755 --- a/components/tools/OmeroPy/src/omero/plugins/admin.py +++ b/components/tools/OmeroPy/src/omero/plugins/admin.py @@ -102,6 +102,34 @@ def _complete(self, text, line, begidx, endidx): def _configure(self, parser): sub = parser.sub() self._add_diagnostics(parser, sub) + self.add_error( + "NOT_WINDOWS", 123, + "Not Windows") + self.add_error( + "SETUP", 200, + "Error during service user set up: (%s) %s") + self.add_error( + "RUNNING", 201, + "%s is already running. Use stop first") + self.add_error( + "NO_SERVICE", 202, + "%s service deleted.") + self.add_error( + "BAD_CONFIG", 300, + "Bad configuration: No IceGrid.Node.Data property") + self.add_error( + "WIN_CONFIG", 400, """ + + %s is not in this directory. Aborting... + + Please see the installation instructions on modifying + the files for your installation (%s) + with bin\winconfig.bat + + """) + self.add_error( + "NO_WIN32", 666, + "Could not import win32service and/or win32evtlogutil") self.actions = {} class Action(object): @@ -551,8 +579,7 @@ def _start_service(self, config, descript, svc_name, pasw, user): policy_handle, sid_obj, ('SeServiceLogonRight',)) win32security.LsaClose(policy_handle) except pywintypes.error, details: - self.ctx.die(200, "Error during service user set up:" - " (%s) %s" % (details[0], details[2])) + self.raise_error("SETUP", details[0], details[2]) if not pasw: try: pasw = config.as_map()["omero.windows.pass"] @@ -581,8 +608,7 @@ def _start_service(self, config, descript, svc_name, pasw, user): # Then check if the server is already running if 0 <= output.find("RUNNING"): - self.ctx.die(201, "%s is already running. Use stop first" - % svc_name) + self.raise_error("RUNNING", svc_name) # Finally, try to start the service - delete if startup fails hscm = win32service.OpenSCManager( @@ -597,7 +623,7 @@ def _start_service(self, config, descript, svc_name, pasw, user): self.ctx.out("%s service startup failed: (%s) %s" % (svc_name, details[0], details[2])) win32service.DeleteService(hs) - self.ctx.die(202, "%s service deleted." % svc_name) + self.raise_error("NO_SERVICE", svc_name) finally: win32service.CloseServiceHandle(hs) win32service.CloseServiceHandle(hscm) @@ -615,20 +641,17 @@ def DumpRecord(record): else: def events(self, svc_name): - self.ctx.die( - 666, "Could not import win32service and/or win32evtlogutil") + self.raise_error("NO_WIN32") def _query_service(self, svc_name): - self.ctx.die( - 666, "Could not import win32service and/or win32evtlogutil") + self.raise_error("NO_WIN32") def _start_service(self, config, descript, svc_name, pasw, user): - self.ctx.die( - 666, "Could not import win32service and/or win32evtlogutil") + self.raise_error("NO_WIN32") def _stop_service(self, svc_name): - self.ctx.die( - 666, "Could not import win32service and/or win32evtlogutil") + self.raise_error("NO_WIN32") + # # End Windows Methods # @@ -693,15 +716,14 @@ def checkwindows(self, args): """ self.check_access(os.R_OK) if not self._isWindows(): - self.ctx.die(123, "Not Windows") + self.raise_error("NOT_WINDOWS") import Ice key = "IceGrid.Node.Data" properties = Ice.createProperties([self._icecfg()]) nodedata = properties.getProperty(key) if not nodedata: - self.ctx.die(300, - "Bad configuration: No IceGrid.Node.Data property") + self.raise_error("BAD_CONFIG") nodepath = path(nodedata) pp = nodepath.parpath(self.ctx.dir) if pp: @@ -713,15 +735,7 @@ def checkwindows(self, args): count = win_set_path(dir=self.ctx.dir) if count: return - self.ctx.die(400, """ - - %s is not in this directory. Aborting... - - Please see the installation instructions on modifying - the files for your installation (%s) - with bin\winconfig.bat - - """ % (nodedata, self.ctx.dir)) + self.raise_error("WIN_CONFIG", nodedata, self.ctx.dir) ############################################## # diff --git a/components/tools/OmeroPy/src/omero/plugins/basics.py b/components/tools/OmeroPy/src/omero/plugins/basics.py index 1f25268d8f7..d2498bad8be 100644 --- a/components/tools/OmeroPy/src/omero/plugins/basics.py +++ b/components/tools/OmeroPy/src/omero/plugins/basics.py @@ -20,6 +20,8 @@ import sys +from collections import defaultdict + from omero_ext.argparse import FileType from omero.cli import BaseControl @@ -240,9 +242,44 @@ def __call__(self, args): elif args.topic: self.print_single_command_or_topic(args) + +class ErrorsControl(BaseControl): + + def _configure(self, parser): + parser.set_defaults(func=self.__call__) + parser.add_argument("--length", default=50, type=int, + help="Length of message to print") + parser.add_argument("plugins", nargs="*", default=(), + help="Limit to these plugins; otherwise all") + + def __call__(self, args): + arranged = defaultdict(lambda: defaultdict( + lambda: defaultdict(list))) + for name, control in self.ctx.controls.items(): + if not args.plugins or name in args.plugins: + combined = [] + if hasattr(control, "get_errors"): + combined.extend(control.get_errors().items()) + combined.sort(lambda a, b: cmp(a[1].rcode, b[1].rcode)) + for key, err in combined: + arranged[err.rcode][name][key].append(err) + + for rcode, names in sorted(arranged.items()): + for name, keys in sorted(names.items()): + for key, errors in sorted(keys.items()): + for err in errors: + msg = err.msg + if len(msg) > (args.length+1): + msg = msg[:args.length] + "..." + msg = msg.replace("\n", " ") + msg = msg.strip() + t = (err.rcode, name, key, msg) + self.ctx.out("%5d\t%10s\t%10s\t'%s'" % t) + controls = { "help": (HelpControl, "Syntax help for all commands"), "quit": (QuitControl, "Quit application"), + "errors": (ErrorsControl, "Display all plugin error codes"), "shell": (ShellControl, """Starts an IPython interpreter session All arguments not understood vi %(prog)s will be passed to the shell. diff --git a/components/tools/OmeroPy/src/omero/plugins/server.py b/components/tools/OmeroPy/src/omero/plugins/server.py index fe254cfab15..be9a3cafccb 100755 --- a/components/tools/OmeroPy/src/omero/plugins/server.py +++ b/components/tools/OmeroPy/src/omero/plugins/server.py @@ -34,6 +34,7 @@ def _configure(self, parser): parser.add(sub, self.indexer, help="Start OMERO.indexer") # web = parser.add(sub, self.web, help = "Start OMERO.web") # web.add_argument("arg", nargs="*") + self.add_error("NO_CONFIG", 201, "No --Ice.Config provided") def _prop(self, data, key): return data.properties.getProperty("omero."+key) @@ -43,7 +44,7 @@ def _checkIceConfig(self, args): try: args["--Ice.Config"] except KeyError: - self.ctx.die(201, "No --Ice.Config provided") + self.raise_error("NO_CONFIG") pre = [] post = [] for arg in args.args: