# Copyright (c) 2004-2005 DoCoMo Euro-Labs GmbH (Munich, Germany). # Copyright (c) 2001-2005 LOGILAB S.A. (Paris, FRANCE). # # http://www.docomolab-euro.com/ -- mailto:tarlano@docomolab-euro.com # http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """\ USAGE: %s [OPTIONS] Start the Narval interpreter (except with some specific options, see description below). Options ``````` --help print this help message and exit --version print narval's version and exit --create-home create a fresh narval home and exit --stop stop a currently running interpreter and exit --quiet be the less verbose as possible --debug log debug information --profile run in profiled mode --home=dir overwrite NARVAL_HOME environment variable with the given directory --rc-file=file use instead of default narvalrc.xml init file --memory-file=file uses specified instead of default memory file --with-shell starts interactive python shell with '_' as the Narval instance --xmlrpc-port=port listens for xmlrpc client connections on the specified port --pyro-port=port listens for pyro client connections on the specified port --max-threads=n sets maximum number of concurrent threads --start-plan=plan execute (i.e. .) right after starting --context=match used with --start-plan, launch the plan with elements matching the given match expression --quit-when-done quit when no more running plan (only done or failed) --quit-after=n quit after seconds of execution --save-mem-on-quit=file save memory to when quitting Environment variables ````````````````````` - NARVAL_SHARE: location of narval's shared resources - NARVAL_HOME: user's narval home directory (default to ~/.narval) :version: $Revision:$ :author: Logilab """ __revision__ = "$Id: engine.py,v 1.110 2003/03/18 17:51:04 syt Exp $" __docformat__ = "restructuredtext en" import sys import getopt import os from os.path import exists, abspath, basename, join import socket from narval import init_log, config from narval.public import AL_NS def stop(narval) : """wrapper function on narval.shutdown to be used to stop the Narval interpreter from a signal handler :type narval: `Narval` :param narval: the narval intrepreter """ narval.shutdown() def dump_stats(statfile): """display statistics from profiling mode :type statfile: str :param statfile: path to the file containing profile information """ import pstats prof = pstats.Stats(statfile) prof.sort_stats('time','calls').print_stats(.25) prof.sort_stats('cum','calls').print_stats(.25) prof.strip_dirs().sort_stats('cum','calls').print_callers(.25) prof.strip_dirs().sort_stats('cum','calls').print_callees() def usage(status=1): """display usage and exit :type status: int :param status: exit status """ print __doc__ % basename(sys.argv[0]) sys.exit(status) def run(args=None): """command line launcher :type args: list :param args: command line arguments, without the script name """ long_list = ['help', 'version', 'stop', 'create-home', 'debug', 'test', 'quiet', 'profile=', 'home=', 'rc-file=', 'memory-file=', 'xmlrpc-port=', 'pyro-port=', 'max-threads=', 'with-shell', 'signals', 'start-plan=', 'context=', 'quit-after=', 'quit-when-done', 'save-mem-on-quit='] try: optlist, args = getopt.getopt(args or sys.argv[1:], 'h', long_list) except getopt.error, ex: print 'Error:', ex print usage(1) quiet = [opt for opt in optlist if opt[0] == '--quiet'] if quiet: init_log(LOG_ERR, sid='narval') else: init_log(LOG_NOTICE, sid='narval') # specific home or memory setup ? home, mempath, profpath, rcpath = None, None, None, None manage_signals = False action = 'start' narval_opts = [] for opt, val in optlist: if opt in ('-h', '--help'): usage(0) if opt == '--version': from narval.__pkginfo__ import version print 'Python %s\nnarval %s' % (sys.version, version) sys.exit(0) elif opt in ('--create-home', '--stop'): action = opt[2:] elif opt == '--home': home = abspath(val) elif opt == '--memory-file' : log(LOG_NOTICE, 'using %s as memory file', val) mempath = abspath(val) elif opt == '--rc-file' : log(LOG_NOTICE, 'using %s as configuration file', val) rcpath = abspath(val) elif opt == '--profile': profpath = val action = 'profile' elif opt == '--signals': manage_signals = True elif opt != '--quiet': narval_opts.append((opt, val)) # load the configuration config.DEFAULT_CONFIGURATOR.build_config() # manage narval home if home: config.DEFAULT_CONFIGURATOR.set_home_from_command_line(home) if action == 'create-home': action_create_home() else: # check user home exists try: config.check_home() except config.ConfigurationError, ex: print ex sys.exit(1) home = config.get_home() log(LOG_NOTICE, 'using %s as home', home) pid_file = join(home, 'narval.pid') if action == 'stop': action_stop(pid_file) elif action == 'profile': import hotshot profile = hotshot.Profile(profpath) log(LOG_NOTICE,'profiling execution') try: profile.runcall(action_start, pid_file, narval_opts, rcpath, mempath, manage_signals) finally: dump_stats(profpath) else: # action == 'start' action_start(pid_file, narval_opts, rcpath, mempath, manage_signals) sys.exit(0) def action_create_home(): config.create_home() print "initialized narval home in %s" % config.get_home() def action_stop(pid_file): try: pid = open(pid_file).read().strip() except IOError: print 'no pid file found' sys.exit(1) import signal try: os.kill(int(pid), signal.SIGTERM) except OSError: # suppose it's a "No Such Process" error pass # remove the pid file FIXME: ensure process has been killed os.remove(pid_file) def action_start(pid_file, narval_opts, rcpath, mempath, profpath, manage_signals=True): # create pid lock file if it doesn't exist yet if exists(pid_file): print '''\ A narval pid file has been found (%s), which seems to indicate that a narval is already running using that home. Stop the running narval or remove the pid file manually before rerunning this command. ''' % pid_file sys.exit(1) if not ('--quit-when-done', '') in narval_opts: open(pid_file, 'wt').write(str(os.getpid())) # create Narval instance from narval.engine import Narval narval = Narval(rcpath) narval.post_event( ('load_protocol_handlers',) ) narval.post_event( ('load_interfaces',) ) narval.post_event( ('load_elements',) ) narval.post_event( ('load_recipes',) ) narval.post_event( ('load_modules',) ) narval.post_event( ('load_memory', mempath) ) if manage_signals: import signal signal.signal(signal.SIGINT, lambda x, y, z=narval: stop(z)) signal.signal(signal.SIGTERM, lambda x, y, z=narval: stop(z)) log(LOG_INFO, "managing signals") # process narval options narval_options(narval, narval_opts) narval.run() def narval_options(narval, optlist): """configure the narval interpreter according to options :type narval: `Narval` :param narval: the narval intrepreter :type optlist: list :param optlist: (option, value) tuples """ start_plan, context_match = None, None # process options for opt, val in optlist: if opt == '--debug': from narval.listeners import PlanListenerLogImpl, \ MemoryListenerLogImpl narval.debug = 1 init_log(LOG_DEBUG, sid='narval') narval.start_com_service() narval.com_service.add_listener('plan', PlanListenerLogImpl()) narval.com_service.add_listener('memory', MemoryListenerLogImpl()) elif opt == '--with-shell': narval.post_event( ('start_shell_service', ) ) elif opt == '--quit-after' : narval.schedule_event(('quit',), when=int(val)) elif opt == '--quit-when-done': narval.quit_when_done = True elif opt == '--save-mem-on-quit' : narval.save_mem_on_quit = val elif opt == '--start-plan' : start_plan = val elif opt == '--context' : context_match = val elif opt == '--test' : narval.test_mode = True elif opt in ('--pyro-port', '--xmlrpc-port'): proto = opt.split('-')[2] listen_xml = '' % (proto, socket.gethostname(), int(val), AL_NS) narval.add_element(listen_xml) elif opt == '--max-threads' : narval.max_threads = int(val) if start_plan: narval.start_plan(start_plan, context_match or []) elif context_match: log(LOG_ERR, '--context require --start-plan') if __name__ == "__main__": run(sys.argv[1:])