Skip to content

Instantly share code, notes, and snippets.

@Naddiseo
Last active January 19, 2018 00:36
Show Gist options
  • Save Naddiseo/a94f1c434dedd1c836bb3ec1ec3b6ec5 to your computer and use it in GitHub Desktop.
Save Naddiseo/a94f1c434dedd1c836bb3ec1ec3b6ec5 to your computer and use it in GitHub Desktop.
Caddy frontend for django manage.py.
import os
import sys
HERE = os.path.dirname(__file__)
# Stolen from a SO answer
def get_free_port():
import socket
import contextlib
with contextlib.closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
s.bind(('localhost', 0))
return s.getsockname()[1]
# Mostly stolen from some of the runserver internals
def runserver_to_caddy_args():
import re
from django.core.management.commands.runserver import Command, naiveip_re
ret_args = []
argv = list(sys.argv)
cmd = Command()
parser = cmd.create_parser(argv[0], argv[1])
options = parser.parse_args(argv[2:])
use_ipv6 = options.use_ipv6
if not options.addrport:
addr = ''
port = cmd.default_port
else:
m = re.match(naiveip_re, options.addrport)
if m is None:
raise Exception(f"{options.addrport} is not valid port or addr:port")
addr, _ipv4, _ipv6, _fqdn, port = m.groups()
if not port.isdigit():
raise Exception(f"{port} is not valid port")
if addr:
if _ipv6:
addr = addr[1:-1]
use_ipv6 = True
elif use_ipv6 and not _fqdn:
raise Exception(f"{addr} is not a valid ipv6 address")
if not addr:
addr = '::1' if use_ipv6 else '127.0.0.1'
free_local_port = get_free_port()
new_addrport = f'localhost:{free_local_port}'
# replace the command line address
if options.addrport:
try:
# Replace if possible
argv[argv.index(options.addrport)] = new_addrport
except ValueError:
# .index can raise ValueError, in which case we will ignore
pass
else:
argv.append(new_addrport)
crt_path = os.path.join(HERE, 'etc', 'localhost.crt')
key_path = os.path.join(HERE, 'etc', 'localhost.key')
ret_args.extend(('-host', addr))
ret_args.extend(('-port', port))
ret_args.extend((
f'proxy / {new_addrport}',
f'tls {crt_path} {key_path}',
))
ret_args.extend(('log stdout',))
return ret_args, argv
def main(*args):
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
from django.core import management
args = list(args)
if 'runserver' in args and os.environ.get('RUN_MAIN') == 'true':
import subprocess
import atexit
caddy_args, args = runserver_to_caddy_args()
p = subprocess.Popen(
['caddy', *caddy_args],
cwd = os.getcwd(),
env = os.environ,
stdout = sys.stdout,
stderr = sys.stderr,
)
def kill():
print("KILLING")
p.kill()
atexit.register(kill)
management.execute_from_command_line(*args)
if __name__ == '__main__':
main(*sys.argv)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment