mirror of https://github.com/zulip/zulip.git
167 lines
6.1 KiB
Python
Executable File
167 lines
6.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
import argparse
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
from typing import NoReturn, Optional
|
|
|
|
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
|
|
|
os.chdir(os.path.join(os.path.dirname(__file__), "../web"))
|
|
|
|
|
|
from version import ZULIP_VERSION
|
|
|
|
|
|
def build_for_prod_or_puppeteer(quiet: bool, config_name: Optional[str] = None) -> NoReturn:
|
|
"""Builds for production, writing the output to disk"""
|
|
|
|
with open("/proc/meminfo") as meminfo:
|
|
if int(next(meminfo).split()[1]) < 3 * 1024 * 1024:
|
|
os.environ["NODE_OPTIONS"] = "--max-old-space-size=1536"
|
|
webpack_args = [
|
|
"../node_modules/.bin/webpack-cli",
|
|
"--mode=production",
|
|
f"--env=ZULIP_VERSION={ZULIP_VERSION}",
|
|
]
|
|
if quiet:
|
|
webpack_args += ["--stats=errors-only"]
|
|
if config_name is not None:
|
|
webpack_args += [f"--config-name={config_name}"]
|
|
|
|
# Silence warnings from "browserslist" about using old data; those
|
|
# warnings are only useful for development
|
|
os.environ["BROWSERSLIST_IGNORE_OLD_DATA"] = "1"
|
|
|
|
os.execvp(webpack_args[0], webpack_args)
|
|
|
|
|
|
def build_for_dev_server(host: str, port: str, minify: bool, disable_host_check: bool) -> None:
|
|
"""watches and rebuilds on changes, serving files from memory via webpack-dev-server"""
|
|
|
|
# This is our most dynamic configuration, which we use for our
|
|
# dev server. The key piece here is that we identify changes to
|
|
# files as devs make edits and serve new assets on the fly.
|
|
webpack_args = ["../node_modules/.bin/webpack-cli", "serve"]
|
|
webpack_args += [
|
|
# webpack-cli has a bug where it ignores --watch-poll with
|
|
# multi-config, and we don't need the katex part anyway.
|
|
"--config-name=frontend",
|
|
f"--host={host}",
|
|
f"--port={port}",
|
|
# We add the hot flag using the cli because it takes care
|
|
# of addition to entry points and adding the plugin
|
|
# automatically
|
|
"--hot",
|
|
]
|
|
if minify:
|
|
webpack_args.append("--env=minimize")
|
|
if disable_host_check:
|
|
webpack_args.append("--allowed-hosts=all")
|
|
else:
|
|
webpack_args.append(f"--allowed-hosts={host},.zulipdev.com,.zulipdev.org")
|
|
|
|
# Tell webpack-dev-server to fall back to periodic polling on
|
|
# filesystems where inotify is known to be broken.
|
|
cwd = os.getcwd()
|
|
inotify_broken = False
|
|
with open("/proc/self/mounts") as mounts:
|
|
for line in mounts:
|
|
fields = line.split()
|
|
if fields[1] == cwd:
|
|
inotify_broken = fields[2] in ["nfs", "vboxsf", "prl_fs"]
|
|
if inotify_broken:
|
|
os.environ["CHOKIDAR_USEPOLLING"] = "1"
|
|
os.environ["CHOKIDAR_INTERVAL"] = "1000"
|
|
|
|
# TODO: This process should also fall back to periodic polling if
|
|
# inotify_broken.
|
|
import pyinotify
|
|
|
|
try:
|
|
webpack_process = subprocess.Popen(webpack_args)
|
|
|
|
class WebpackConfigFileChangeHandler(pyinotify.ProcessEvent):
|
|
def process_default(self, event: pyinotify.Event) -> None:
|
|
nonlocal webpack_process
|
|
print("Restarting webpack-dev-server due to config changes...")
|
|
webpack_process.terminate()
|
|
webpack_process.wait()
|
|
webpack_process = subprocess.Popen(webpack_args)
|
|
|
|
watch_manager = pyinotify.WatchManager()
|
|
event_notifier = pyinotify.Notifier(watch_manager, WebpackConfigFileChangeHandler())
|
|
# We did a chdir to the root of the Zulip checkout above.
|
|
for filepath in [
|
|
"webpack.config.ts",
|
|
"webpack.assets.json",
|
|
"webpack.dev-assets.json",
|
|
]:
|
|
watch_manager.add_watch(filepath, pyinotify.IN_MODIFY)
|
|
event_notifier.loop()
|
|
finally:
|
|
webpack_process.terminate()
|
|
webpack_process.wait()
|
|
|
|
|
|
def build_for_most_tests() -> None:
|
|
"""Generates a stub asset stat file for django so backend test can render a page"""
|
|
|
|
# Tests like test-backend, test-api, and test-home-documentation use
|
|
# our "test" configuration. The one exception is Puppeteer, which uses
|
|
# our production configuration.
|
|
#
|
|
# It's not completely clear why we don't also use the same
|
|
# configuration for ALL tests, but figuring out the full history here
|
|
# was out of the scope of the effort here to add some comments and
|
|
# clean up names.
|
|
with open("webpack.assets.json") as json_data:
|
|
entries = json.load(json_data)
|
|
|
|
with open("webpack.dev-assets.json") as json_data:
|
|
entries.update(json.load(json_data))
|
|
|
|
stat_data = {
|
|
"status": "done",
|
|
"chunks": {entry: [f"{entry}-stubentry.js"] for entry in entries},
|
|
}
|
|
directory = "../var"
|
|
if not os.path.exists(directory):
|
|
os.makedirs(directory)
|
|
with open(os.path.join(directory, "webpack-stats-test.json"), "w") as outfile:
|
|
json.dump(stat_data, outfile)
|
|
|
|
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument(
|
|
"--test",
|
|
action="store_true",
|
|
help="generate a stub webpack-stats.json file (for backend testing)",
|
|
)
|
|
parser.add_argument("--quiet", action="store_true", help="Minimizes webpack output while running")
|
|
parser.add_argument(
|
|
"--watch", action="store_true", help="watch for changes to source files (for development)"
|
|
)
|
|
parser.add_argument(
|
|
"--host", default="127.0.0.1", help="set the host for the webpack server to run on"
|
|
)
|
|
parser.add_argument("--port", default="9994", help="set the port for the webpack server to run on")
|
|
parser.add_argument(
|
|
"--minify", action="store_true", help="Minify and optimize the assets (for development)"
|
|
)
|
|
parser.add_argument(
|
|
"--disable-host-check", action="store_true", help="Disable host check for webpack-dev-server"
|
|
)
|
|
parser.add_argument("--config-name", help="Limit production building to only one config-name")
|
|
|
|
args = parser.parse_args()
|
|
if "PUPPETEER_TESTS" in os.environ:
|
|
build_for_prod_or_puppeteer(args.quiet)
|
|
elif args.test:
|
|
build_for_most_tests()
|
|
elif args.watch:
|
|
build_for_dev_server(args.host, args.port, args.minify, args.disable_host_check)
|
|
else:
|
|
build_for_prod_or_puppeteer(args.quiet, args.config_name)
|