Source code for asv.commands.preview
# Licensed under a 3-clause BSD style license - see LICENSE.rst
import errno
import http.server
import os
import random
import socketserver
from .. import util
from ..console import log
from . import Command
[docs]
def random_ports(port, n):
"""Generate a list of n random ports near the given port.
The first 5 ports will be sequential, and the remaining n-5 will be
randomly selected in the range [port-2*n, port+2*n].
"""
if port != 0:
yield port
else:
port = 8080
for i in range(min(5, n)):
yield port + i
for i in range(n - 5):
yield max(1, port + random.randint(-2 * n, 2 * n))
[docs]
def create_httpd(handler_cls, port=0):
# Create a server that allows address reuse
class MyTCPServer(socketserver.ThreadingTCPServer):
allow_reuse_address = True
daemon_threads = True
for port in random_ports(port, 5):
try:
httpd = MyTCPServer(("", port), handler_cls)
base_url = f"http://127.0.0.1:{port}/"
break
except OSError as e:
if e.errno == errno.EADDRINUSE:
continue
else:
raise
else:
raise util.UserError("Failed to find an unused port for serving web pages")
return httpd, base_url
[docs]
class Preview(Command):
@classmethod
[docs]
def setup_arguments(cls, subparsers):
parser = subparsers.add_parser(
"preview",
help="Preview the results using a local web server",
description="Preview the results using a local web server",
)
parser.add_argument(
"--port", "-p", type=int, default=0, help="Port to run webserver on. [8080]"
)
parser.add_argument("--browser", "-b", action="store_true", help="Open in webbrowser")
parser.add_argument(
'--html-dir',
'-o',
default=None,
help=("Optional output directory. Default is 'html_dir' from asv config"),
)
parser.set_defaults(func=cls.run_from_args)
return parser
@classmethod
[docs]
def run_from_conf_args(cls, conf, args):
if args.html_dir:
conf.html_dir = args.html_dir
return cls.run(conf=conf, port=args.port, browser=args.browser)
@classmethod
[docs]
def run(cls, conf, port=0, browser=False):
os.chdir(conf.html_dir)
class Handler(http.server.SimpleHTTPRequestHandler):
def translate_path(self, path):
path = http.server.SimpleHTTPRequestHandler.translate_path(self, path)
return util.long_path(path)
httpd, base_url = create_httpd(Handler, port=port)
log.info(f"Serving at {base_url}")
if browser:
import webbrowser
webbrowser.open(base_url)
log.info("Press ^C to abort\n")
try:
httpd.serve_forever()
except KeyboardInterrupt:
return