From 12e1ea6e6e0cb75c610655a052e773159f215381 Mon Sep 17 00:00:00 2001 From: Griatch Date: Mon, 2 Feb 2015 15:56:17 +0100 Subject: [PATCH] Added a wrapper to evennia.py, in order to get testing done on Windows. --- bin/evennia | 908 +--------------------------------------------------- 1 file changed, 9 insertions(+), 899 deletions(-) diff --git a/bin/evennia b/bin/evennia index 06e2dc1abb..dd311e1d77 100755 --- a/bin/evennia +++ b/bin/evennia @@ -1,904 +1,14 @@ -#!/usr/bin/env python +#! /usr/bin/python2.7 """ -EVENNIA SERVER STARTUP SCRIPT - -This is the start point for running Evennia. - -Sets the appropriate environmental variables and launches the server -and portal through the evennia_runner. Run without arguments to get a -menu. Run the script with the -h flag to see usage information. - +Linux evennia launcher wrapper. Windows (which doesn't support +shebangs but which associates .py files with the python launcher) will +use the evennia.py program directly. """ + import os import sys -import signal -import shutil -import importlib -from argparse import ArgumentParser -from subprocess import Popen, check_output, call, CalledProcessError, STDOUT -import django +import subprocess -# Signal processing -SIG = signal.SIGINT - -# Set up the main python paths to Evennia -EVENNIA_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -EVENNIA_BIN = os.path.join(EVENNIA_ROOT, "bin") - -import evennia -EVENNIA_LIB = os.path.join(os.path.dirname(os.path.abspath(evennia.__file__))) -EVENNIA_RUNNER = os.path.join(EVENNIA_BIN, "evennia_runner.py") -EVENNIA_TEMPLATE = os.path.join(EVENNIA_LIB, "game_template") -EVENNIA_BINTESTING = os.path.join(EVENNIA_BIN, "testing") -EVENNIA_DUMMYRUNNER = os.path.join(EVENNIA_BINTESTING, "dummyrunner.py") - -TWISTED_BINARY = "twistd" - -# Game directory structure -SETTINGFILE = "settings.py" -SERVERDIR = "server" -CONFDIR = os.path.join(SERVERDIR, "conf") -SETTINGS_PATH = os.path.join(CONFDIR, SETTINGFILE) -SETTINGS_DOTPATH = "server.conf.settings" -CURRENT_DIR = os.getcwd() -GAMEDIR = CURRENT_DIR - -# Operational setup -SERVER_LOGFILE = None -PORTAL_LOGFILE = None -HTTP_LOGFILE = None -SERVER_PIDFILE = None -PORTAL_PIDFILE = None -SERVER_RESTART = None -PORTAL_RESTART = None -SERVER_PY_FILE = None -PORTAL_PY_FILE = None - -PYTHON_MIN = '2.7' -TWISTED_MIN = '12.0' -DJANGO_MIN = '1.7' -DJANGO_REC = '1.7' - -# add Evennia root and bin dir to PYTHONPATH -# note that we want to remove bin/ (path[0]) from -# pythonpath since there is otherwise a clash over -# the name evennia -sys.path[0] = EVENNIA_ROOT - -#------------------------------------------------------------ -# -# Messages -# -#------------------------------------------------------------ - -CREATED_NEW_GAMEDIR = \ - """ - Welcome to Evennia! - Created a new Evennia game directory '{gamedir}'. - - You can now optionally edit your new settings file - at {settings_path}. If you don't, the defaults - will work out of the box. When ready to continue, 'cd' to your - game directory and run: - - evennia migrate - - This initializes the database. To start the server for the first - time, run: - - evennia -i start - - Make sure to create a superuser when asked for it. You should now - be able to (by default) connect to your server on server - 'localhost', port 4000 using a telnet/mud client or - http://localhost:8000 using your web browser. If things don't - work, check so those ports are open. - - """ - -ERROR_NO_GAMEDIR = \ - """ - No Evennia settings file was found. You must run this command from - inside a valid game directory first created with --init. - """ - -WARNING_RUNSERVER = \ - """ - WARNING: There is no need to run the Django development - webserver to test out Evennia web features (the web client - will in fact not work since the Django test server knows - nothing about MUDs). Instead, just start Evennia with the - webserver component active (this is the default). - """ - -ERROR_SETTINGS = \ - """ - There was an error importing Evennia's config file {settingspath}. There is usually - one of three reasons for this: - 1) You are not running this command from your game directory. - Change directory to your game directory and try again (or - create a new game directory using evennia --init ) - 2) The settings file contains a syntax error. If you see a - traceback above, review it, resolve the problem and try again. - 3) Django is not correctly installed. This usually shows as - errors mentioning 'DJANGO_SETTINGS_MODULE'. If you run a - virtual machine, it might be worth to restart it to see if - this resolves the issue. - """.format(settingsfile=SETTINGFILE, settingspath=SETTINGS_PATH) - -ERROR_DATABASE = \ - """ - Your database does not seem to be set up correctly. - (error was '{traceback}') - - Standing in your game directory, try to run - - evennia migrate - - to initialize/update the database according to your settings. - """ - -ERROR_WINDOWS_WIN32API = \ - """ - ERROR: Unable to import win32api, which Twisted requires to run. - You may download it from: - - http://sourceforge.net/projects/pywin32 - or - http://starship.python.net/crew/mhammond/win32/Downloads.html - """ - -INFO_WINDOWS_BATFILE = \ - """ - INFO: Since you are running Windows, a file 'twistd.bat' was - created for you. This is a simple batch file that tries to call - the twisted executable. Evennia determined this to be: - - %(twistd_path)s - - If you run into errors at startup you might need to edit - twistd.bat to point to the actual location of the Twisted - executable (usually called twistd.py) on your machine. - - This procedure is only done once. Run evennia.py again when you - are ready to start the server. - """ - -CMDLINE_HELP = \ - """ - Starts or operates the Evennia MU* server. Also allows for - initializing a new game directory and managing the game's - database. You can also pass django manage.py arguments through - this launcher. If you need manage.py --options, use djangoadmin - directly instead. - """ - - -VERSION_INFO = \ - """ - {about} - Evennia {version} - OS: {os} - Python: {python} - Twisted: {twisted} - Django: {django} - """ - -ABOUT_INFO= \ - """ - Evennia MUD/MUX/MU* development system - - Licence: BSD 3-Clause Licence - Web: http://www.evennia.com - Irc: #evennia on FreeNode - Forum: http://www.evennia.com/discussions - Maintainer (2010-): Griatch (griatch AT gmail DOT com) - Maintainer (2006-10): Greg Taylor - - Use -h for command line options. - """ - -HELP_ENTRY = \ - """ - Enter 'evennia -h' for command-line options. - - Use option (1) in a production environment. During development (2) is - usually enough, portal debugging is usually only useful if you are - adding new protocols or are debugging Evennia itself. - - Reload with (5) to update the server with your changes without - disconnecting any players. - - Note: Reload and stop are sometimes poorly supported in Windows. If you have - issues, log into the game to stop or restart the server instead. - """ - -MENU = \ - """ - +----Evennia Launcher-------------------------------------------+ - | | - +--- Starting --------------------------------------------------+ - | | - | 1) (normal): All output to logfiles | - | 2) (server devel): Server logs to terminal (-i option) | - | 3) (portal devel): Portal logs to terminal | - | 4) (full devel): Both Server and Portal logs to terminal | - | | - +--- Restarting ------------------------------------------------+ - | | - | 5) Reload the Server | - | 6) Reload the Portal (only works with portal/full debug) | - | | - +--- Stopping --------------------------------------------------+ - | | - | 7) Stopping both Portal and Server | - | 8) Stopping only Server | - | 9) Stopping only Portal | - | | - +---------------------------------------------------------------+ - | h) Help i) About info q) Abort | - +---------------------------------------------------------------+ - """ - -ERROR_PYTHON_VERSION = \ - """ - ERROR: Python {pversion} used. Evennia requires version - {python_min} or higher (but not 3.x). - """ - -WARNING_TWISTED_VERSION = \ - """ - WARNING: Twisted {tversion} found. Evennia recommends - v{twisted_min} or higher." - """ - -ERROR_NOTWISTED = \ - """ - ERROR: Twisted does not seem to be installed. - """ - -ERROR_DJANGO_MIN = \ - """ - ERROR: Django {dversion} found. Evennia requires version - {django_min} or higher. - """ - -NOTE_DJANGO_MIN = \ - """ - NOTE: Django {dversion} found. This will work, but v{django_rec} - is recommended for production. - """ - -NOTE_DJANGO_NEW = \ - """ - NOTE: Django {dversion} found. This is newer than Evennia's - recommended version (v{django_rec}). It will probably work, but - may be new enough not to be fully tested yet. Report any issues." - """ - -ERROR_NODJANGO = \ - """ - ERROR: Django does not seem to be installed. - """ - -#------------------------------------------------------------ -# -# Functions -# -#------------------------------------------------------------ - -def evennia_version(): - """ - Get the Evennia version info from the main package. - """ - version = "Unknown" - try: - import evennia - version = evennia.__version__ - except ImportError: - pass - try: - version = "%s (rev %s)" % (version, check_output("git rev-parse --short HEAD", shell=True, cwd=EVENNIA_ROOT, stderr=STDOUT).strip()) - except (IOError, CalledProcessError): - pass - return version - -EVENNIA_VERSION = evennia_version() - - -def check_main_evennia_dependencies(): - """ - Checks and imports the Evennia dependencies. This must be done - already before the paths are set up. - """ - error = False - - # Python - pversion = ".".join(str(num) for num in sys.version_info if type(num) == int) - if pversion < PYTHON_MIN: - print ERROR_PYTHON_VERSION.format(pversion=pversion, python_min=PYTHON_MIN) - error = True - # Twisted - try: - import twisted - tversion = twisted.version.short() - if tversion < TWISTED_MIN: - print WARNING_TWISTED_VERSION.format(tversion=tversion, twisted_min=TWISTED_MIN) - except ImportError: - print ERROR_NOTWISTED - error = True - # Django - try: - dversion = ".".join(str(num) for num in django.VERSION if type(num) == int) - # only the main version (1.5, not 1.5.4.0) - dversion_main = ".".join(dversion.split(".")[:2]) - if dversion < DJANGO_MIN: - print ERROR_DJANGO_MIN.format(dversion=dversion_main, django_min=DJANGO_MIN) - error = True - elif DJANGO_MIN <= dversion < DJANGO_REC: - print NOTE_DJANGO_MIN.format(dversion=dversion_main, django_rec=DJANGO_REC) - elif DJANGO_REC < dversion_main: - print NOTE_DJANGO_NEW.format(dversion=dversion_main, django_rec=DJANGO_REC) - except ImportError: - print ERROR_NODJANGO - error = True - if error: - sys.exit() - - -def set_gamedir(path): - """ - Set GAMEDIR based on path, by figuring out where the setting file - is inside the directory tree. - """ - - global GAMEDIR - if os.path.exists(os.path.join(path, SETTINGS_PATH)): - # path at root of game dir - GAMEDIR = os.path.abspath(path) - elif os.path.exists(os.path.join(path, os.path.pardir, SETTINGS_PATH)): - # path given to somewhere one level down - GAMEDIR = os.path.dirname(path) - elif os.path.exists(os.path.join(path, os.path.pardir, os.path.pardir, SETTINGS_PATH)): - # path given to somwhere two levels down - GAMEDIR = os.path.dirname(os.path.dirname(path)) - elif os.path.exists(os.path.join(path, os.path.pardir, os.path. pardir, os.path.pardir, SETTINGS_PATH)): - # path given to somewhere three levels down (custom directories) - GAMEDIR = os.path.dirname(os.path.dirname(os.path.dirname(path))) - else: - # we don't look further down than this ... - print ERROR_NO_GAMEDIR - sys.exit() - - -def create_secret_key(): - """ - Randomly create the secret key for the settings file - """ - import random - import string - secret_key = list((string.letters + - string.digits + string.punctuation).replace("\\", "").replace("'", '"')) - random.shuffle(secret_key) - secret_key = "".join(secret_key[:40]) - return secret_key - - -def create_settings_file(): - """ - Uses the template settings file to build a working - settings file. - """ - settings_path = os.path.join(GAMEDIR, "server", "conf", "settings.py") - with open(settings_path, 'r') as f: - settings_string = f.read() - - # tweak the settings - setting_dict = {"settings_default": os.path.join(EVENNIA_LIB, "settings_default.py"), - "servername":"\"%s\"" % GAMEDIR.rsplit(os.path.sep, 1)[1].capitalize(), - "game_dir":"\"%s\"" % GAMEDIR, - "secret_key":"\'%s\'" % create_secret_key()} - - # modify the settings - settings_string = settings_string.format(**setting_dict) - - with open(settings_path, 'w') as f: - f.write(settings_string) - - -def create_game_directory(dirname): - """ - Initialize a new game directory named dirname - at the current path. This means copying the - template directory from evennia's root. - """ - global GAMEDIR - GAMEDIR = os.path.abspath(os.path.join(CURRENT_DIR, dirname)) - if os.path.exists(GAMEDIR): - print "Cannot create new Evennia game dir: '%s' already exists." % dirname - sys.exit() - # copy template directory - shutil.copytree(EVENNIA_TEMPLATE, GAMEDIR) - # pre-build settings file in the new GAMEDIR - create_settings_file() - - -def create_superuser(): - "Create the superuser player" - print "\nCreate a superuser below. The superuser is Player #1, the 'owner' account of the server.\n" - django.core.management.call_command("createsuperuser", interactive=True) - - -def check_database(exit_on_error=False): - """ - Check database exists - """ - # Check so a database exists and is accessible - from django.db import connection - tables = connection.introspection.get_table_list(connection.cursor()) - if tables and u'players_playerdb' in tables: - # database exists and seems set up. Initialize evennia. - import evennia - evennia.init() - else: - if exit_on_error: - print ERROR_DATABASE.format(traceback=e) - sys.exit() - return False - return True - # Try to get Player#1 - from evennia.players.models import PlayerDB - try: - PlayerDB.objects.get(id=1) - except PlayerDB.DoesNotExist: - # no superuser yet. We need to create it. - create_superuser() - return True - - -def getenv(): - """ - Get current environment and add PYTHONPATH - """ - sep = ";" if os.name == 'nt' else ":" - env = os.environ.copy() - env['PYTHONPATH'] = sep.join(sys.path) - return env - - -def get_pid(pidfile): - """ - Get the PID (Process ID) by trying to access - an PID file. - """ - pid = None - if os.path.exists(pidfile): - f = open(pidfile, 'r') - pid = f.read() - return pid - - -def del_pid(pidfile): - """ - The pidfile should normally be removed after a process has - finished, but when sending certain signals they remain, so we need - to clean them manually. - """ - if os.path.exists(pidfile): - os.remove(pidfile) - - -def kill(pidfile, signal=SIG, succmsg="", errmsg="", restart_file=SERVER_RESTART, restart=False): - """ - Send a kill signal to a process based on PID. A customized - success/error message will be returned. If clean=True, the system - will attempt to manually remove the pid file. - """ - pid = get_pid(pidfile) - if pid: - if os.name == 'nt': - os.remove(pidfile) - # set restart/norestart flag - if restart: - django.core.management.call_command('collectstatic', interactive=False, verbosity=0) - with open(restart_file, 'w') as f: - f.write("reload") - else: - with open(restart_file, 'w') as f: - f.write("shutdown") - try: - os.kill(int(pid), signal) - except OSError: - print "Process %(pid)s cannot be stopped. "\ - "The PID file 'server/%(pidfile)s' seems stale. "\ - "Try removing it." % {'pid': pid, 'pidfile': pidfile} - return - print "Evennia:", succmsg - return - print "Evennia:", errmsg - - -def show_version_info(about=False): - """ - Display version info - """ - import os, sys - import twisted - import django - - return VERSION_INFO.format(version=EVENNIA_VERSION, - about=ABOUT_INFO if about else "", - os=os.name, python=sys.version.split()[0], - twisted=twisted.version.short(), - django=django.get_version()) - - -def error_check_python_modules(): - """ - Import settings modules in settings. This will raise exceptions on - pure python-syntax issues which are hard to catch gracefully - with exceptions in the engine (since they are formatting errors in - the python source files themselves). Best they fail already here - before we get any further. - """ - from django.conf import settings - def imp(path, split=True): - mod, fromlist = path, "None" - if split: - mod, fromlist = path.rsplit('.', 1) - __import__(mod, fromlist=[fromlist]) - - # core modules - imp(settings.COMMAND_PARSER) - imp(settings.SEARCH_AT_RESULT) - imp(settings.SEARCH_AT_MULTIMATCH_INPUT) - imp(settings.CONNECTION_SCREEN_MODULE) - #imp(settings.AT_INITIAL_SETUP_HOOK_MODULE, split=False) - for path in settings.LOCK_FUNC_MODULES: - imp(path, split=False) - # cmdsets - - deprstring = "settings.%s should be renamed to %s. If defaults are used, " \ - "their path/classname must be updated (see evennia/settings_default.py)." - if hasattr(settings, "CMDSET_DEFAULT"): - raise DeprecationWarning(deprstring % ("CMDSET_DEFAULT", "CMDSET_CHARACTER")) - if hasattr(settings, "CMDSET_OOC"): - raise DeprecationWarning(deprstring % ("CMDSET_OOC", "CMDSET_PLAYER")) - if settings.WEBSERVER_ENABLED and not isinstance(settings.WEBSERVER_PORTS[0], tuple): - raise DeprecationWarning("settings.WEBSERVER_PORTS must be on the form [(proxyport, serverport), ...]") - if hasattr(settings, "BASE_COMM_TYPECLASS"): - raise DeprecationWarning(deprstring % ("BASE_COMM_TYPECLASS", "BASE_CHANNEL_TYPECLASS")) - if hasattr(settings, "COMM_TYPECLASS_PATHS"): - raise DeprecationWarning(deprstring % ("COMM_TYPECLASS_PATHS", "CHANNEL_TYPECLASS_PATHS")) - if hasattr(settings, "CHARACTER_DEFAULT_HOME"): - raise DeprecationWarning("settings.CHARACTER_DEFAULT_HOME should be renamed to DEFAULT_HOME. " \ - "See also settings.START_LOCATION (see evennia/settings_default.py).") - - from evennia.commands import cmdsethandler - if not cmdsethandler.import_cmdset(settings.CMDSET_UNLOGGEDIN, None): print "Warning: CMDSET_UNLOGGED failed to load!" - if not cmdsethandler.import_cmdset(settings.CMDSET_CHARACTER, None): print "Warning: CMDSET_CHARACTER failed to load" - if not cmdsethandler.import_cmdset(settings.CMDSET_PLAYER, None): print "Warning: CMDSET_PLAYER failed to load" - # typeclasses - imp(settings.BASE_PLAYER_TYPECLASS) - imp(settings.BASE_OBJECT_TYPECLASS) - imp(settings.BASE_CHARACTER_TYPECLASS) - imp(settings.BASE_ROOM_TYPECLASS) - imp(settings.BASE_EXIT_TYPECLASS) - imp(settings.BASE_SCRIPT_TYPECLASS) - - -def init_game_directory(path, check_db=True): - """ - Try to analyze the given path to find settings.py - this defines - the game directory and also sets PYTHONPATH as well as the - django path. - """ - # set the GAMEDIR path - set_gamedir(path) - - # Add gamedir to python path - sys.path.insert(1, GAMEDIR) - - # Prepare django; set the settings location - os.environ['DJANGO_SETTINGS_MODULE'] = SETTINGS_DOTPATH - - # required since django1.7 - django.setup() - - # test existence of the settings module - try: - from django.conf import settings - except Exception, ex: - if not str(ex).startswith("No module named"): - import traceback - print traceback.format_exc().strip() - print ERROR_SETTINGS - sys.exit() - - # this will both check the database and initialize the evennia dir. - if check_db: - check_database() - - # set up the Evennia executables and log file locations - global SERVER_PY_FILE, PORTAL_PY_FILE - global SERVER_LOGFILE, PORTAL_LOGFILE, HTTP_LOGFILE - global SERVER_PIDFILE, PORTAL_PIDFILE - global SERVER_RESTART, PORTAL_RESTART - global EVENNIA_VERSION - - SERVER_PY_FILE = os.path.join(EVENNIA_LIB, "server", "server.py") - PORTAL_PY_FILE = os.path.join(EVENNIA_LIB, "portal", "portal", "portal.py") - - SERVER_PIDFILE = os.path.join(GAMEDIR, SERVERDIR, "server.pid") - PORTAL_PIDFILE = os.path.join(GAMEDIR, SERVERDIR, "portal.pid") - - SERVER_RESTART = os.path.join(GAMEDIR, SERVERDIR, "server.restart") - PORTAL_RESTART = os.path.join(GAMEDIR, SERVERDIR, "portal.restart") - - SERVER_LOGFILE = settings.SERVER_LOG_FILE - PORTAL_LOGFILE = settings.PORTAL_LOG_FILE - HTTP_LOGFILE = settings.HTTP_LOG_FILE - - if os.name == 'nt': - # We need to handle Windows twisted separately. We create a - # batchfile in game/server, linking to the actual binary - - global TWISTED_BINARY - TWISTED_BINARY = "twistd.bat" - - # add path so system can find the batfile - sys.path.insert(1, os.path.join(GAMEDIR, SERVERDIR)) - - try: - importlib.import_module("win32api") - except ImportError: - print ERROR_WINDOWS_WIN32API - sys.exit() - - if not os.path.exists(os.path.join(EVENNIA_BIN, TWISTED_BINARY)): - # Test for executable twisted batch file. This calls the - # twistd.py executable that is usually not found on the - # path in Windows. It's not enough to locate - # scripts.twistd, what we want is the executable script - # C:\PythonXX/Scripts/twistd.py. Alas we cannot hardcode - # this location since we don't know if user has Python in - # a non-standard location. So we try to figure it out. - twistd = importlib.import_module("twisted.scripts.twistd") - twistd_dir = os.path.dirname(twistd.__file__) - - # note that we hope the twistd package won't change here, since we - # try to get to the executable by relative path. - twistd_path = os.path.abspath(os.path.join(twistd_dir, - os.pardir, os.pardir, os.pardir, os.pardir, - 'scripts', 'twistd.py')) - - with open('twistd.bat', 'w') as bat_file: - # build a custom bat file for windows - bat_file.write("@\"%s\" \"%s\" %%*" % (sys.executable, twistd_path)) - - print INFO_WINDOWS_BATFILE.format(twistd_path=twistd_path) - -def run_dummyrunner(number_of_dummies): - """ - Start an instance of the dummyrunner - - The dummy players' behavior can be customized by adding a - dummyrunner_settings.py config file in the game's conf directory. - """ - number_of_dummies = str(int(number_of_dummies)) if number_of_dummies else 1 - cmdstr = [sys.executable, EVENNIA_DUMMYRUNNER, "-N", number_of_dummies] - config_file = os.path.join(SETTINGS_PATH, "dummyrunner_settings.py") - if os.path.exists(config_file): - cmdstr.extend(["--config", config_file]) - try: - call(cmdstr, env=getenv()) - except KeyboardInterrupt: - pass - -def run_menu(): - """ - This launches an interactive menu. - """ - while True: - # menu loop - - print MENU - inp = raw_input(" option > ") - - # quitting and help - if inp.lower() == 'q': - return - elif inp.lower() == 'h': - print HELP_ENTRY - raw_input("press to continue ...") - continue - elif inp.lower() in ('v', 'i', 'a'): - print show_version_info(about=True) - raw_input("press to continue ...") - continue - - # options - try: - inp = int(inp) - except ValueError: - print "Not a valid option." - continue - if inp == 1: - # start everything, log to log files - server_operation("start", "all", False, False) - elif inp == 2: - # start everything, server interactive start - server_operation("start", "all", True, False) - elif inp == 3: - # start everything, portal interactive start - server_operation("start", "server", False, False) - server_operation("start", "portal", True, False) - elif inp == 4: - # start both server and portal interactively - server_operation("start", "server", True, False) - server_operation("start", "portal", True, False) - elif inp == 5: - # reload the server - server_operation("reload", "server", None, None) - elif inp == 6: - # reload the portal - server_operation("reload", "portal", None, None) - elif inp == 7: - # stop server and portal - server_operation("stop", "all", None, None) - elif inp == 8: - # stop server - server_operation("stop", "server", None, None) - elif inp == 9: - # stop portal - server_operation("stop", "portal", None, None) - else: - print "Not a valid option." - continue - return - - -def server_operation(mode, service, interactive, profiler): - """ - Handle argument options given on the command line. - - mode - str; start/stop etc - service - str; server, portal or all - interactive - bool; use interactive mode or daemon - profiler - run the service under the profiler - """ - - cmdstr = [sys.executable, EVENNIA_RUNNER] - errmsg = "The %s does not seem to be running." - - if mode == 'start': - - # launch the error checker. Best to catch the errors already here. - error_check_python_modules() - - # starting one or many services - if service == 'server': - if profiler: - cmdstr.append('--pserver') - if interactive: - cmdstr.append('--iserver') - cmdstr.append('--noportal') - elif service == 'portal': - if profiler: - cmdstr.append('--pportal') - if interactive: - cmdstr.append('--iportal') - cmdstr.append('--noserver') - django.core.management.call_command('collectstatic', verbosity=1, interactive=False) - else: # all - # for convenience we don't start logging of - # portal, only of server with this command. - if profiler: - cmdstr.append('--pserver') # this is the common case - if interactive: - cmdstr.append('--iserver') - django.core.management.call_command('collectstatic', verbosity=1, interactive=False) - cmdstr.extend([GAMEDIR, TWISTED_BINARY, SERVER_LOGFILE, PORTAL_LOGFILE, HTTP_LOGFILE]) - # start the server - Popen(cmdstr, env=getenv()) - - elif mode == 'reload': - # restarting services - if os.name == 'nt': - print "Restarting from command line is not supported under Windows. Log into the game to restart." - return - if service == 'server': - kill(SERVER_PIDFILE, SIG, "Server reloaded.", errmsg % 'Server', SERVER_RESTART, restart=True) - elif service == 'portal': - print """ - Note: Portal usually doesnt't need to be reloaded unless you are debugging in interactive mode. - If Portal was running in default Daemon mode, it cannot be restarted. In that case you have - to restart it manually with 'evennia.py start portal' - """ - kill(PORTAL_PIDFILE, SIG, "Portal reloaded (or stopped, if it was in daemon mode).", errmsg % 'Portal', PORTAL_RESTART, restart=True) - else: # all - # default mode, only restart server - kill(SERVER_PIDFILE, SIG, "Server reload.", errmsg % 'Server', SERVER_RESTART, restart=True) - - elif mode == 'stop': - # stop processes, avoiding reload - if service == 'server': - kill(SERVER_PIDFILE, SIG, "Server stopped.", errmsg % 'Server', SERVER_RESTART) - elif service == 'portal': - kill(PORTAL_PIDFILE, SIG, "Portal stopped.", errmsg % 'Portal', PORTAL_RESTART) - else: - kill(PORTAL_PIDFILE, SIG, "Portal stopped.", errmsg % 'Portal', PORTAL_RESTART) - kill(SERVER_PIDFILE, SIG, "Server stopped.", errmsg % 'Server', SERVER_RESTART) - - - -def main(): - """ - Run the evennia main program. - """ - - # set up argument parser - - parser = ArgumentParser(description=CMDLINE_HELP) - parser.add_argument('-v', '--version', action='store_true', - dest='show_version', default=False, - help="Show version info.") - parser.add_argument('-i', '--interactive', action='store_true', - dest='interactive', default=False, - help="Start given processes in interactive mode.") - parser.add_argument('--init', action='store', dest="init", metavar="name", - help="Creates a new game directory 'name' at the current location.") - parser.add_argument('--profiler', action='store_true', dest='profiler', default=False, - help="Start given server component under the Python profiler.") - parser.add_argument('--dummyrunner', nargs=1, action='store', dest='dummyrunner', metavar="N", - help="Tests a running server by connecting N dummy players to it.") - parser.add_argument("mode", metavar="option", nargs='?', default="help", - help="Operational mode or management option. Commonly start, stop, reload, migrate, or menu (default).") - parser.add_argument("service", metavar="component", nargs='?', choices=["all", "server", "portal"], default="all", - help="Which server component to operate on. One of server, portal or all (default).") - - args = parser.parse_args() - - # handle arguments - - mode, service = args.mode, args.service - - check_main_evennia_dependencies() - - if args.init: - create_game_directory(args.init) - print CREATED_NEW_GAMEDIR.format(gamedir=args.init, - settings_path=os.path.join(args.init, SETTINGS_PATH)) - sys.exit() - - if args.show_version: - print show_version_info(mode=="help") - sys.exit() - if mode == "help" and not args.dummyrunner: - print ABOUT_INFO - sys.exit() - check_db = not mode == "migrate" - - # this must be done first - it sets up all the global properties - # and initializes django for the game directory - init_game_directory(CURRENT_DIR, check_db=check_db) - - if args.dummyrunner: - # launch the dummy runner - run_dummyrunner(args.dummyrunner[0]) - elif mode == 'menu': - # launch menu for operation - run_menu() - elif mode in ('start', 'reload', 'stop'): - # operate the server directly - server_operation(mode, service, args.interactive, args.profiler) - else: - # pass-through to django manager - if mode in ('runserver', 'testserver'): - print WARNING_RUNSERVER - django.core.management.call_command(mode) - - -if __name__ == '__main__': - # start Evennia from the command line - main() +# set up the path and launch evennia.py +evenniapath = os.path.join(os.path.dirname(os.path.abspath(__file__)), "evennia.py") +subprocess.Popen([sys.executable] + [evenniapath] + sys.argv[1:])