import os import sys import inspect import signal import subprocess from django.core.management.base import BaseCommand import mod_wsgi.server def check_percentage(string): if value is not None and value < 0 or value > 1: import argparse msg = '%s option value needs to be within the range 0 to 1.' % string raise argparse.ArgumentTypeError(msg) return value class Command(BaseCommand): args = '' help = 'Starts Apache/mod_wsgi web server.' if hasattr(BaseCommand, 'option_list'): # Used prior to Django 1.10. option_list = BaseCommand.option_list + mod_wsgi.server.option_list else: # This horrible mess tries to convert optparse option list to # argparse as required by Django 1.10+. We can't switch to # using argparse as need to still support Python 2.6, which # lacks the argparse module. def add_arguments(self, parser): ignore = set(['const', 'callback', 'callback_args', 'callback_kwargs']) types = { 'int': int, 'string': str } for option in mod_wsgi.server.option_list: opts = option._short_opts + option._long_opts kwargs = {} for attr in option.ATTRS: if attr not in ignore and hasattr(option, attr): if attr == 'type': if getattr(option, attr) in types: kwargs[attr] = types[getattr(option, attr)] elif attr == 'default': if getattr(option, attr) != ('NO', 'DEFAULT'): kwargs[attr] = getattr(option, attr) else: if getattr(option, attr) is not None: kwargs[attr] = getattr(option, attr) if (kwargs.get('action') == 'callback' and option.callback.__name__ == 'check_percentage'): del kwargs['action'] kwargs['type'] = check_percentage if kwargs.get('nargs') == 1: del kwargs['nargs'] parser.add_argument(*opts, **kwargs) def handle(self, *args, **options): self.stdout.write('Successfully ran command.') from django.conf import settings wsgi_application = settings.WSGI_APPLICATION fields = wsgi_application.split('.') module_name = '.'.join(fields[:-1]) callable_object = fields[-1] __import__(module_name) # script_file = inspect.getsourcefile(sys.modules[module_name]) # args = [script_file] options['application_type'] = 'module' options['callable_object'] = callable_object args = [module_name] # If there is no BASE_DIR in Django settings, assume that the # current working directory is the parent directory of the # directory the settings module is in. Either way, allow the # --working-directory option to override it to deal with where # meaning of BASE_DIR in the Django settings was changed. if options.get('working_directory') is None: if hasattr(settings, 'BASE_DIR'): options['working_directory'] = settings.BASE_DIR else: settings_module_path = os.environ['DJANGO_SETTINGS_MODULE'] root_module_path = settings_module_path.split('.')[0] root_module = sys.modules[root_module_path] parent = os.path.dirname(os.path.dirname(root_module.__file__)) options['working_directory'] = parent url_aliases = options.setdefault('url_aliases') or [] try: middleware = getattr(settings, 'MIDDLEWARE', None) if middleware is None: middleware = getattr(settings, 'MIDDLEWARE_CLASSES', []) if 'whitenoise.middleware.WhiteNoiseMiddleware' not in middleware: if settings.STATIC_URL and settings.STATIC_URL.startswith('/'): if settings.STATIC_ROOT: # We need a fiddle here as depending on the Python # version used, the list of URL aliases we are # passed could be either list of tuples or list of # lists. We need to ensure we use the same type so # that sorting of items in the lists works later. if not url_aliases: url_aliases.insert(0, ( settings.STATIC_URL.rstrip('/') or '/', settings.STATIC_ROOT)) else: url_aliases.insert(0, type(url_aliases[0])(( settings.STATIC_URL.rstrip('/') or '/', settings.STATIC_ROOT))) except AttributeError: pass options['url_aliases'] = url_aliases options = mod_wsgi.server._cmd_setup_server( 'start-server', args, options) if options['setup_only']: return executable = os.path.join(options['server_root'], 'apachectl') name = executable.ljust(len(options['process_name'])) if options['isatty'] and sys.stdout.isatty(): process = None def handler(signum, frame): if process is None: sys.exit(1) else: if signum not in [signal.SIGWINCH]: os.kill(process.pid, signum) signal.signal(signal.SIGINT, handler) signal.signal(signal.SIGTERM, handler) signal.signal(signal.SIGHUP, handler) signal.signal(signal.SIGUSR1, handler) signal.signal(signal.SIGWINCH, handler) process = subprocess.Popen([executable, 'start', '-DFOREGROUND'], preexec_fn=os.setpgrp) process.wait() else: os.execl(executable, name, 'start', '-DFOREGROUND')