1
2
3 """
4 Python driver for OMERO
5
6 Provides access to various OMERO.blitz server- and client-side
7 utilities, including starting and stopping servers, running
8 analyses, configuration, and more.
9
10 Usable via the ./omero script provided with the distribution
11 as well as from python via "import omero.cli; omero.cli.argv()"
12
13 Arguments are taken from (in order of priority): the run method
14 arguments, sys.argv, and finally from standard in using the
15 cmd.Cmd.cmdloop method.
16
17 Josh Moore, josh at glencoesoftware.com
18 Copyright (c) 2007, Glencoe Software, Inc.
19 See LICENSE for details.
20
21 """
22
23 sys = __import__("sys")
24
25 import cmd, string, re, os, subprocess, socket, exceptions, traceback, glob, platform, time
26 import shlex as pyshlex
27 from exceptions import Exception as Exc
28 from threading import Thread, Lock
29 from omero_version import omero_version
30 from path import path
31
32
33
34
35
36 VERSION=omero_version
37 DEBUG = False
38 if os.environ.has_key("DEBUG"):
39 print "Deprecated warning: use the 'bin/omero debug [args]' to debug"
40 print "Running omero with debugging on"
41 DEBUG = True
42 TEXT="""
43 OMERO Python Shell. Version %s
44 Type "help" for more information, "quit" or Ctrl-D to exit
45 """ % str(VERSION)
46
47 OMEROCLI = path(__file__).expand().dirname()
48 OMERODIR = os.getenv('OMERODIR', None)
49 if OMERODIR is not None:
50 OMERODIR = path(OMERODIR)
51 else:
52 OMERODIR = OMEROCLI.dirname().dirname().dirname()
53
54 COMMENT = re.compile("^\s*#")
55 RELFILE = re.compile("^\w")
56 LINEWSP = re.compile("^\s*\w+\s+")
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
79 self.rv = rv
80 Exc.__init__(self, *args)
81
82
83
84
86 """
87 Wrapper for arguments in all controls. All non-"_" control methods are
88 assumed to take some representation of the command line. This can either
89 be:
90
91 - the line as a string
92 - the shlex'd line as a string list
93
94 To simplify usage, this class can be used at the beginning of every
95 method so::
96
97 def method(self, args):
98 args = Arguments(args)
99
100 and it will handle the above cases as well as wrapping other Argument
101 instances. If the method takes varargs and it is desired to test for
102 single argument of the above type, then use::
103
104 args = Arguments(*args)
105
106 """
107
109 if args == None:
110 self.args = []
111 self.argmap = {}
112 elif isinstance(args, Arguments):
113 self.args = args.args
114 self.argmap = args.argmap
115 elif isinstance(args, str):
116 self.args = self.shlex(args)
117 self.make_argmap()
118 elif isinstance(args, list):
119 for l in args:
120 assert (isinstance(l, str) or isinstance(l, unicode))
121 self.args = args
122 self.make_argmap()
123 else:
124 raise exceptions.Exception("Unknown argument: %s" % args)
125
127 self.argmap = {}
128 for arg in self.args:
129 parts = arg.split("=", 1)
130 if len(parts) == 1:
131 self.argmap[parts[0]] = True
132 else:
133 self.argmap[parts[0]] = parts[1]
134
136 if len(self.args) == 0:
137 return (None,[])
138 elif len(self.args) == 1:
139 return (self.args[0], [])
140 else:
141 return (self.args[0], self.args[1:])
142
144 return self.args.pop(0)
145
147 """
148 Used to split a string argument via shlex.split(). If the
149 argument is not a string, then it is returned unchnaged.
150 This is useful since the arg argument to all plugins can
151 be either a list or a string.
152 """
153 if None == input:
154 return []
155 elif isinstance(input, str):
156 return pyshlex.split(input)
157 else:
158 return input
159
160
161
162
163
165 return iter(self.args)
167 return len(self.args)
169 return ", ".join(self.args)
170 - def join(self, text):
171 return text.join(self.args)
173 """
174 For every argument without an "=" we return True. Otherwise,
175 the value following the first "=" is returned.
176 """
177 return self.argmap[idx]
178
179
180
182 """Simple context used for default logic. The CLI registry which registers
183 the plugins installs itself as a fully functional Context.
184
185 The Context class is designed to increase pluggability. Rather than
186 making calls directly on other plugins directly, the pub() method
187 routes messages to other commands. Similarly, out() and err() should
188 be used for printing statements to the user, and die() should be
189 used for exiting fatally.
190
191 """
192
193 - def __init__(self, controls = {}):
194 self.controls = controls
195 self.dir = OMERODIR
196 self.isdebug = DEBUG
197
198 - def setdebug(self):
200
201 - def safePrint(self, text, stream, newline = True):
202 """
203 Prints text to a given string, caputring any exceptions.
204 """
205 try:
206 stream.write(text % {"program_name": sys.argv[0]})
207 if newline:
208 stream.write("\n")
209 else:
210 stream.flush()
211 except:
212 print >>sys.stderr, "Error printing text"
213 print >>sys.stdout, text
214 if self.isdebug:
215 traceback.print_exc()
216
217 - def pythonpath(self):
218 """
219 Converts the current sys.path to a PYTHONPATH string
220 to be used by plugins which must start a new process.
221
222 Note: this was initially created for running during
223 testing when PYTHONPATH is not properly set.
224 """
225 path = list(sys.path)
226 for i in range(0,len(path)-1):
227 if path[i] == '':
228 path[i] = os.getcwd()
229 pythonpath = ":".join(path)
230 return pythonpath
231
233 """
234 Returns a user directory (as path.path) which can be used
235 for storing configuration. The directory is guaranteed to
236 exist and be private (700) after execution.
237 """
238 dir = path(os.path.expanduser("~")) / "omero" / "cli"
239 if not dir.exists():
240 dir.mkdir()
241 elif not dir.isdir():
242 raise Exc("%s is not a directory"%dir)
243 dir.chmod(0700)
244 return dir
245
246 - def pub(self, args):
247 self.safePrint(str(args), sys.stdout)
248
249 - def input(self, prompt, hidden = False):
250 """
251 Reads from standard in. If hidden == True, then
252 uses getpass
253 """
254 if hidden:
255 import getpass
256 defuser = getpass.getuser()
257 return getpass.getpass(prompt)
258 else:
259 return raw_input(prompt)
260
261 - def out(self, text, newline = True):
262 """
263 Expects as single string as argument"
264 """
265 self.safePrint(text, sys.stdout, newline)
266
267 - def err(self, text, newline = True):
268 """
269 Expects a single string as argument.
270 """
271 self.safePrint(text, sys.stderr, newline)
272
273 - def dbg(self, text, newline = True):
274 """
275 Passes text to err() if self.isdebug is set
276 """
277 if self.isdebug:
278 self.err(text, newline)
279
280 - def die(self, rc, args):
281 raise exceptions.Exception((rc,args))
282
283 - def exit(self, args):
284 self.out(args)
285 self.interrupt_loop = True
286
287 - def call(self, args):
289
290 - def popen(self, args):
292
294 raise NotImplementedException()
295
296
297
298
299
301 """Controls get registered with a CLI instance on loadplugins().
302
303 To create a new control, subclass BaseControl and end your module with::
304
305 try:
306 registry("name", MyControl)
307 except:
308 MyControl()._main()
309
310 This module should be put in the omero.plugins package.
311
312 All methods which do NOT begin with "_" are assumed to be accessible
313 to CLI users.
314 """
315
316
317
318
319
321 self.dir = path(dir)
322 self.ctx = ctx
323
325 p_s = platform.system()
326 if p_s == 'Windows':
327 return True
328 else:
329 return False
330
332 """
333 Return hostname of current machine. Termed to be the
334 value return from socket.gethostname() up to the first
335 decimal.
336 """
337 if not hasattr(self, "hostname") or not self.hostname:
338 self.hostname = socket.gethostname()
339 if self.hostname.find(".") > 0:
340 self.hostname = self.hostname.split(".")[0]
341 return self.hostname
342
343 - def _node(self, omero_node = None):
344 """
345 Return the name of this node, using either the environment
346 vairable OMERO_NODE or _host(). Some subclasses may
347 override this functionality, most notably "admin" commands
348 which assume a node name of "master".
349
350 If the optional argument is not None, then the OMERO_NODE
351 environment variable will be set.
352 """
353 if omero_node != None:
354 os.environ["OMERO_NODE"] = omero_node
355
356 if os.environ.has_key("OMERO_NODE"):
357 return os.environ["OMERO_NODE"]
358 else:
359 return self._host()
360
362 """
363 General data method for creating a path from an Ice property.
364 """
365 try:
366 nodepath = self._properties()[property]
367
368 if RELFILE.match(nodepath):
369 nodedata = self.dir / path(nodepath)
370 else:
371 nodedata = path(nodepath)
372
373 created = False
374 if not nodedata.exists():
375 self.ctx.out("Creating "+nodedata)
376 nodedata.makedirs()
377 created = True
378 return (nodedata, created)
379
380 except KeyError, ke:
381 self.ctx.err(property + " is not configured")
382 self.ctx.die(4, str(ke))
383
385 """
386 Initialize the directory into which the current node will log.
387 """
388 props = self._properties()
389 nodedata = self._nodedata()
390 logdata = self.dir / path(props["Ice.StdOut"]).dirname()
391 if not logdata.exists():
392 self.ctx.out("Initializing %s" % logdata)
393 logdata.makedirs()
394
395
397 """
398 Returns the data directory path for this node. This is determined
399 from the "IceGrid.Node.Data" property in the _properties()
400 map.
401
402 The directory will be created if it does not exist.
403 """
404 data, created = self._icedata("IceGrid.Node.Data")
405 return data
406
408 """
409 Returns the data directory for the IceGrid registry.
410 This is determined from the "IceGrid.Registry.Data" property
411 in the _properties() map.
412
413 The directory will be created if it does not exist, and
414 a warning issued.
415 """
416 data, created = self._icedata("IceGrid.Registry.Data")
417
419 """
420 Returns a path of the form "_nodedata() / _node() + ".pid",
421 i.e. a file named NODENAME.pid in the node's data directory.
422 """
423 pidfile = self._nodedata() / (self._node() + ".pid")
424 return pidfile
425
427 """
428 Returns a list of configuration files for this node. This
429 defaults to the internal configuration for all nodes,
430 followed by a file named NODENAME.cfg under the etc/
431 directory, following by PLATFORM.cfg if it exists.
432 """
433 cfgs = self.dir / "etc"
434 internal = cfgs / "internal.cfg"
435 owncfg = cfgs / self._node() + ".cfg"
436 results = [internal,owncfg]
437
438 p_s = platform.system()
439 p_c = cfgs / p_s + ".cfg"
440 if p_c.exists():
441 results.append(p_c)
442 return results
443
445 """
446 Uses _cfglist() to return a string argument of the form
447 "--Ice.Config=..." suitable for passing to omero.client
448 as an argument.
449 """
450 icecfg = "--Ice.Config=%s" % ",".join(self._cfglist())
451 return str(icecfg)
452
454 """
455 Returns an Ice.Config string with only the internal configuration
456 file for connecting to the IceGrid Locator.
457 """
458 intcfg = self.dir / "etc" / "internal.cfg"
459 intcfg.abspath()
460 return str("--Ice.Config=%s" % intcfg)
461
463 """
464 Loads all files returned by _cfglist() into a new
465 Ice.Properties instance and return the map from
466 getPropertiesForPrefix(prefix) where the default is
467 to return all properties.
468 """
469 import Ice
470 if not hasattr(self, "_props") or self._props == None:
471 self._props = Ice.createProperties()
472 for cfg in self._cfglist():
473 try:
474 self._props.load(str(cfg))
475 except Exc, exc:
476 self.ctx.die(3, "Could not find file: "+cfg + "\nDid you specify the proper node?")
477 return self._props.getPropertiesForPrefix(prefix)
478
480 while not root_pass or len(root_pass) < 1:
481 root_pass = self.ctx.input("Please enter password%s: "%reason, hidden = True)
482 if root_pass == None or root_pass == "":
483 self.ctx.err("Password cannot be empty")
484 continue
485 confirm = self.ctx.input("Please re-enter password%s: "%reason, hidden = True)
486 if root_pass != confirm:
487 root_pass = None
488 self.ctx.err("Passwords don't match")
489 continue
490 break
491 return root_pass
492
493
494
495
496
497 - def help(self, args = []):
498 return """ Help not implemented """
499
500 - def _complete(self, text, line, begidx, endidx):
501 try:
502 import readline
503
504 except ImportError, ie:
505 self.ctx.err("No readline")
506 return []
507
508
509
510
511 completions = [method for method in dir(self) if callable(getattr(self, method)) ]
512 completions = [ str(method + " ") for method in completions if method.startswith(text) and not method.startswith("_") ]
513 return completions
514
516 """
517 Checks whether or not it is likely for the given args
518 to be run successfully by the given command. This is
519 useful for plugins which have significant start up
520 times.
521
522 Simply return True is a possible solution. The default
523 implementation checks that the subclass has a method
524 matching the first argument, such that the default
525 __call__() implementation could dispatch to it. Or if
526 no arguments are given, True is returned since self._noargs()
527 can be called.
528 """
529 args = Arguments(args)
530 first, other = args.firstOther()
531 if first == None or hasattr(self, first):
532 return True
533 return False
534
536 """
537 Main dispatch method for a control instance. The default
538 implementation assumes that the *args consists of either
539 no elements or exactly one list of strings ==> (["str"],)
540
541 If no args are present, _noargs is called. Subclasses may want
542 to read from stdin or drop into a shell from _noargs().
543
544 Otherwise, the rest of the arguments are passed to the method
545 named by the first argument, if _likes() returns True.
546 """
547 args = Arguments(*args)
548 first,other = args.firstOther()
549 if first == None:
550 self._noargs()
551 else:
552 if not self._likes(args):
553 if self.ctx.isdebug:
554
555
556 raise Exc("Bad arguments: " + str(args))
557 self.ctx.err("Bad arguments: " + ",".join(args))
558 self.help()
559 self.ctx.die(8, "Exiting.")
560 else:
561 m = getattr(self, first)
562 return m(other)
563
565 """
566 Method called when __call__() is called without any arguments. Some implementations
567 may want to drop the user into a shell or read from standard in. By default, help()
568 is printed.
569 """
570 self.help()
571
573 """
574 Simple _main() logic which is reusable by subclasses to do something when the control
575 is executed directly. It is unlikely that such an excution will function properly,
576 but it may be useful for testing purposes.
577 """
578 if __name__ == "__main__":
579 if not self._likes(sys.argv[1:]):
580 self.help()
581 else:
582 self.__call__(sys.argv[1:])
583
585 """
586 Defined here since the background loading might be too
587 slow to have all help available
588 """
589
590 - def _complete(self, text, line, begidx, endidx):
591 """
592 This is something of a hack. This should either be a part
593 of the context interface, or we should put it somewhere
594 in a utility. FIXME.
595 """
596 return self.ctx.completenames(text, line, begidx, endidx)
597
598 - def help(self, args = None):
599 self.out("Print help")
600
602
603 args = Arguments(*args)
604 first, other = args.firstOther()
605
606 self.ctx.waitForPlugins()
607 controls = self.ctx.controls.keys()
608 controls.sort()
609
610 if not first:
611 print """OmeroCli client, version %(version)s
612
613 Usage: %(program_name)s <command> [options] args
614 See 'help <command>' for more information on syntax
615 Type 'quit' to exit
616
617 Available commands:
618 """ % {"program_name":sys.argv[0],"version":VERSION}
619
620 for name in controls:
621 print """ %s""" % name
622 print """
623 For additional information, see http://trac.openmicroscopy.org.uk/omero/wiki/OmeroCli"""
624
625 else:
626 try:
627 self.ctx.controls[first].help_method()
628
629
630
631 except KeyError, ke:
632 self.ctx.unknown_command(first)
633
634 -class CLI(cmd.Cmd, Context):
635 """
636 Command line interface class. Supports various styles of executing the
637 registered plugins. Each plugin is given the chance to update this class
638 by adding methods of the form "do_<plugin name>".
639 """
640
642 """
643 Thread-safe class for storing whether or not all the plugins
644 have been loaded
645 """
647 self.lock = Lock()
648 self.done = False
650 self.lock.acquire()
651 try:
652 return self.done
653 finally:
654 self.lock.release()
656 self.lock.acquire()
657 try:
658 self.done = True
659 finally:
660 self.lock.release()
661
663 """
664 Also sets the "_client" field for this instance to None. Each cli
665 maintains a single active client.
666 """
667 cmd.Cmd.__init__(self)
668 Context.__init__(self)
669 self.prompt = 'omero> '
670 self.interrupt_loop = False
671 self._client = None
672 self._pluginsLoaded = CLI.PluginsLoaded()
673 self.rv = 0
674
682
684 self.selfintro = TEXT
685 if not self.stdin.isatty():
686 self.selfintro = ""
687 self.prompt = ""
688 while not self.interrupt_loop:
689 try:
690 self.cmdloop(self.selfintro)
691 except KeyboardInterrupt, ki:
692
693 self.selfintro = ""
694 try:
695 import readline
696 if len(readline.get_line_buffer()) > 0:
697 self.out("")
698 else:
699 self.out("Use quit to exit")
700 except ImportError:
701 self.out("Use quit to exit")
702
708
710 args = Arguments(line)
711 try:
712
713
714 self.rv = 0
715 return cmd.Cmd.onecmd(self, args)
716 except AttributeError, ae:
717 self.err("Possible error in plugin:")
718 self.err(str(ae))
719 if self.isdebug:
720 traceback.print_exc()
721 except NonZeroReturnCode, nzrc:
722 self.rv = nzrc.rv
723 return False
724
725 - def postcmd(self, stop, line):
726 return self.interrupt_loop
727
730
732 """
733 Overrides the parseline functionality of cmd.py in order to
734 take command line parameters without shlex'ing and unshlex'ing
735 them. If "line" is an array, then the first element will be
736 returned as "cmd" and the rest as "args".
737 """
738 if isinstance(line,list):
739 if not line:
740 return (None, None, None)
741 elif len(line) == 0:
742 return (None, None, "")
743 elif len(line) == 1:
744 return (line[0],None,line[0])
745 else:
746 return (line[0],line[1:],Arguments(line))
747 elif isinstance(line, Arguments):
748 first,other = line.firstOther()
749 return (first, other, line)
750 else:
751 return cmd.Cmd.parseline(self,line)
752
754 arg = Arguments(arg)
755 try:
756 arg["EOF"]
757 self.exit("")
758 except KeyError:
759 first, other = arg.firstOther()
760 file = OMEROCLI / "plugins" / (first + ".py")
761 loc = {"register": self.register}
762 try:
763 execfile( str(file), loc )
764 except Exc, ex:
765 self.dbg("Could not load %s: %s" % (first, ex))
766 self.waitForPlugins()
767
768 if self.controls.has_key(first):
769 return self.invoke(arg.args)
770 else:
771 self.unknown_command(first)
772
774 self.err("""Unknown command: "%s" Try "help".""" % first)
775
777 names = self.controls.keys()
778 return [ str(n + " ") for n in names if n.startswith(line) ]
779
780
782 """
783 Alias for "node start"
784 """
785 args = pyshlex.split(args)
786 if not args:
787 args = ["node","start"]
788 else:
789 args = ["node","start"] + args
790 self.pub(args)
791
792
793
794
795
796 - def exit(self, args):
797 self.out(args)
798 self.interrupt_loop = True
799
800 - def die(self, rc, text):
801 self.err(text)
802 self.rv = rc
803 self.interrupt_loop = True
804 raise NonZeroReturnCode(rc, "die called")
805
806 - def pub(self, args):
807 """
808 Publishes the command, using the first argument as routing
809 information, i.e. the name of the plugin to be instantiated,
810 and the rest as the arguments to its __call__() method.
811 """
812 try:
813 args = Arguments(args)
814 first, other = args.firstOther()
815 if first == None:
816 self.ctx.die(2, "No plugin given. Giving up")
817 else:
818 control = self.controls[first]
819 control(other)
820 except KeyError, ke:
821 self.die(11, "Missing required plugin: "+ str(ke))
822
824 """
825 Configure environment with PYTHONPATH as
826 setup by bin/omero
827 """
828 home = str(self.dir / "lib" / "python")
829 env = dict(os.environ)
830 pypath = env.get("PYTHONPATH", None)
831 if pypath is None:
832 pypath = home
833 else:
834 if pypath.endswith(os.path.pathsep):
835 pypath = "%s%s" % (pypath, home)
836 else:
837 pypath = "%s%s%s" % (pypath, os.path.pathsep, home)
838 env["PYTHONPATH"] = pypath
839 return env
840
841 - def _cwd(self, cwd):
842 if cwd is None:
843 cwd = str(OMERODIR)
844 else:
845 cwd = str(cwd)
846 return cwd
847
848 - def call(self, args, strict = True, cwd = None):
849 """
850 Calls the string in a subprocess and dies if the return value is not 0
851 """
852 self.dbg("Executing: %s" % args)
853 rv = subprocess.call(args, env = self._env(), cwd = self._cwd(cwd))
854 if strict and not rv == 0:
855 raise NonZeroReturnCode(rv, "%s => %d" % (" ".join(args), rv))
856 return rv
857
858 - def popen(self, args, cwd = None):
859 self.dbg("Returning popen: %s" % args)
860 return subprocess.Popen(args, env = self._env(), cwd = self._cwd(cwd), stdout = subprocess.PIPE, stderr = subprocess.PIPE)
861
863 try:
864 f = path(OMERODIR) / "etc" / "omero.properties"
865 f = f.open()
866 output = "".join(f.readlines())
867 f.close()
868 except:
869 if self.isdebug:
870 raise
871 print "No omero.properties found"
872 output = ""
873 return output
874
876 for line in output.splitlines():
877 if line.startswith("Listening for transport dt_socket at address"):
878 self.dbg("Ignoring stdout 'Listening for transport' from DEBUG=1")
879 continue
880 parts = line.split("=",1)
881 if len(parts) == 2:
882 data.properties.setProperty(parts[0],parts[1])
883 self.dbg("Set property: %s=%s" % (parts[0],parts[1]) )
884 else:
885 self.dbg("Bad property:"+str(parts))
886 return data
887
889 """
890 Uses "omero prefs" to create an Ice.InitializationData().
891 """
892 from omero.plugins.prefs import getprefs
893 output = getprefs(["get"], str(OMERODIR / "lib"))
894
895 import Ice
896 data = Ice.InitializationData()
897 data.properties = Ice.createProperties()
898 for k,v in properties.items():
899 data.properties.setProperty(k,v)
900 self.parsePropertyFile(data, output)
901 return data
902
903
904 - def conn(self, properties={}, profile=None):
905 """
906 Either creates or returns the exiting omero.client instance.
907 Uses the comm() method with the same signature.
908 """
909
910 if self._client:
911 return self._client
912
913 import omero
914 try:
915 data = self.initData(properties)
916 self._client = omero.client(sys.argv, id = data)
917 self._client.createSession()
918 return self._client
919 except Exc, exc:
920 self._client = None
921 raise exc
922
923
924
925
926
928 """ This method is added to the globals when execfile() is
929 called on each plugin. An instance of the control should be
930 passed to the register method which will be added to the CLI.
931 """
932
933 class Wrapper:
934 def __init__(self, ctx, control):
935 self.ctx = ctx
936 self.Control = Control
937 self.control = None
938 def _setup(self):
939 if self.control == None:
940 self.control = self.Control(ctx = self.ctx)
941 def do_method(self, *args):
942 try:
943 self._setup()
944 return self.control.__call__(*args)
945 except NonZeroReturnCode, nzrc:
946 raise
947 except Exc, exc:
948 if self.ctx.isdebug:
949 traceback.print_exc()
950
951 self.ctx.die(10, str(exc))
952 def complete_method(self, *args):
953 try:
954 self._setup()
955 return self.control._complete(*args)
956 except Exc, exc:
957 self.ctx.err("Completion error:"+str(exc))
958 def help_method(self, *args):
959 try:
960 self._setup()
961 return self.control.help(*args)
962 except Exc, exc:
963 self.ctx.err("Help error:"+str(exc))
964 def __call__(self, *args):
965 """
966 If the wrapper gets treated like the control
967 instance, and __call__()'d, then pass the *args
968 to do_method()
969 """
970 return self.do_method(*args)
971
972 wrapper = Wrapper(self, Control)
973 setattr(self, "do_" + name, wrapper.do_method)
974 setattr(self, "complete_" + name, wrapper.complete_method)
975 setattr(self, "help_" + name, wrapper.help_method)
976 self.controls[name] = wrapper
977
979 self.dbg("Starting waitForPlugins")
980 while not self._pluginsLoaded.get():
981 self.dbg("Waiting for plugins...")
982 time.sleep(0.1)
983
985 """ Finds all plugins and gives them a chance to register
986 themselves with the CLI instance """
987
988 loc = {"register": self.register}
989
990 plugins = OMEROCLI / "plugins"
991 for plugin in plugins.walkfiles("*.py"):
992 if self.isdebug:
993 print "Loading " + plugin
994 if -1 == plugin.find("#"):
995 try:
996 execfile( plugin, loc )
997 except KeyboardInterrupt:
998 raise
999 except:
1000 self.err("Error loading:"+plugin)
1001 traceback.print_exc()
1002 self._pluginsLoaded.set()
1003
1004
1005
1006
1008 """
1009 Main entry point for the OMERO command-line interface. First
1010 loads all plugins by passing them the classes defined here
1011 so they can register their methods.
1012
1013 Then the case where arguments are passed on the command line are
1014 handled.
1015
1016 Finally, the cli enters a command loop reading from standard in.
1017 """
1018
1019
1020 old_ice_config = os.getenv("ICE_CONFIG")
1021 os.unsetenv("ICE_CONFIG")
1022 try:
1023
1024
1025
1026 executable = path(args[0])
1027 executable = str(executable.basename())
1028 if executable.find("-") >= 0:
1029 parts = executable.split("-")
1030 for arg in args[1:]:
1031 parts.append(arg)
1032 args = parts
1033
1034 cli = CLI()
1035 cli.register("help", HelpControl)
1036 class PluginLoader(Thread):
1037 def run(self):
1038 cli.loadplugins()
1039
1040
1041 PluginLoader().run()
1042
1043 if len(args) > 1:
1044 cli.invoke(args[1:])
1045 return cli.rv
1046 else:
1047 cli.invokeloop()
1048 return cli.rv
1049 finally:
1050 if old_ice_config:
1051 os.putenv("ICE_CONFIG", old_ice_config)
1052