tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

frontend.py (4632B)


      1 import argparse
      2 import logging
      3 import os
      4 import subprocess
      5 import sys
      6 
      7 here = os.path.dirname(__file__)
      8 wpt_root = os.path.abspath(os.path.join(here, ".."))
      9 
     10 # Directories relative to the wpt root that we want to include in the docs
     11 # Sphinx doesn't support including files outside of docs/ so we temporarily symlink
     12 # these directories under docs/ whilst running the build.
     13 link_dirs = [
     14    "tools/wptserve",
     15    "tools/certs",
     16    "tools/wptrunner",
     17    "tools/webtransport",
     18    "tools/third_party/pywebsocket3",
     19 ]
     20 
     21 logger = logging.getLogger()
     22 
     23 
     24 def link_source_dirs():
     25    created = set()
     26    failed = []
     27    for rel_path in link_dirs:
     28        rel_path = rel_path.replace("/", os.path.sep)
     29        src = os.path.join(wpt_root, rel_path)
     30        dest = os.path.join(here, rel_path)
     31        try:
     32            dest_dir = os.path.dirname(dest)
     33            if not os.path.exists(dest_dir):
     34                os.makedirs(dest_dir)
     35                created.add(dest_dir)
     36            if not os.path.exists(dest):
     37                os.symlink(src, dest, target_is_directory=True)
     38            else:
     39                if (not os.path.islink(dest) or
     40                    os.path.join(os.path.dirname(dest), os.readlink(dest)) != src):
     41                    # The file exists but it isn't a link or points at the wrong target
     42                    raise OSError("File exists")
     43        except Exception as e:
     44            failed.append((dest, e))
     45        else:
     46            created.add(dest)
     47    return created, failed
     48 
     49 
     50 def unlink_source_dirs(created):
     51    # Sort backwards in length to remove all files before getting to directory
     52    for path in sorted(created, key=lambda x: -len(x)):
     53        # This will also remove empty parent directories
     54        if not os.path.islink(path) and os.path.isdir(path):
     55            os.removedirs(path)
     56        else:
     57            os.unlink(path)
     58 
     59 
     60 def get_parser():
     61    p = argparse.ArgumentParser()
     62    p.add_argument("--type", default="html", help="Output type (default: html)")
     63    p.add_argument("--docker", action="store_true",
     64                   help="Run inside the docs docker image")
     65    p.add_argument("--serve", nargs="?", const=8000,
     66                   type=int, help="Run a server on the specified port (default: 8000)")
     67    return p
     68 
     69 
     70 def docker_build(tag="wpt:docs"):
     71    subprocess.check_call(["docker",
     72                           "build",
     73                           "--pull",
     74                           "--tag", tag,
     75                           here])
     76 
     77 def docker_run(**kwargs):
     78    cmd = ["docker", "run"]
     79    cmd.extend(["--mount",
     80                 "type=bind,source=%s,target=/app/web-platform-tests" % wpt_root])
     81    if kwargs["serve"] is not None:
     82        serve = str(kwargs["serve"])
     83        cmd.extend(["--expose", serve, "--publish", f"{serve}:{serve}"])
     84    cmd.extend(["-w", "/app/web-platform-tests"])
     85    if os.isatty(os.isatty(sys.stdout.fileno())):
     86        cmd.append("-it")
     87    cmd.extend(["wpt:docs", "./wpt"])
     88    # /app/venv is created during docker build and is always active inside the
     89    # container.
     90    cmd.extend(["--venv", "/app/venv", "--skip-venv-setup"])
     91    cmd.extend(["build-docs", "--type", kwargs["type"]])
     92    if kwargs["serve"] is not None:
     93        cmd.extend(["--serve", str(kwargs["serve"])])
     94    logger.debug(" ".join(cmd))
     95    return subprocess.call(cmd)
     96 
     97 
     98 def build(_venv, **kwargs):
     99    if kwargs["docker"]:
    100        docker_build()
    101        return docker_run(**kwargs)
    102 
    103    out_dir = os.path.join(here, "_build")
    104    try:
    105        created, failed = link_source_dirs()
    106        if failed:
    107            failure_msg = "\n".join(f"{dest}: {err}" for (dest, err) in failed)
    108            logger.error(f"Failed to create source symlinks:\n{failure_msg}")
    109            sys.exit(1)
    110        if kwargs["serve"] is not None:
    111            executable = "sphinx-autobuild"
    112            extras = ["--port", str(kwargs["serve"]),
    113                      "--host", "0.0.0.0",
    114                      "--watch", os.path.abspath(os.path.join(here, os.pardir, "resources")),
    115                      # Ignore changes to files specified with glob pattern
    116                      "--ignore", "**/flycheck_*",
    117                      "--ignore", "**/.*",
    118                      "--ignore", "**/#*",
    119                      "--ignore", "docs/frontend.py",
    120                      "--ignore", "docs/Dockerfile"]
    121        else:
    122            executable = "sphinx-build"
    123            extras = []
    124        cmd = [executable, "-n", "-v", "-b", kwargs["type"], "-j", "auto"] + extras + [here, out_dir]
    125        logger.debug(" ".join(cmd))
    126        subprocess.check_call(cmd)
    127    finally:
    128        unlink_source_dirs(created)