Merge "Force or replace local site theme on *.googlesource.com"
diff --git a/contrib/mitm-ui/README.md b/contrib/mitm-ui/README.md
index c8df490..ad23140 100644
--- a/contrib/mitm-ui/README.md
+++ b/contrib/mitm-ui/README.md
@@ -36,6 +36,17 @@
 2. Open any *.googlesource.com domain in proxied window
 3. plugin.html and more.js are served
 
+### Force or replace default site theme for *.googlesource.com
+
+1. Create a new proxied browser window and start mitmproxy via Docker:
+   ```
+   ~/mitm-gerrit/mitm-theme.sh ./path/to/theme.html
+   ```
+2. Open any *.googlesource.com domain in proxied window
+3. Default site themes are enabled.
+4. Local `theme.html` content replaces `/static/gerrit-theme.html`
+5. `/static/*` URLs are served from local theme directory, i.e. `./path/to/`
+
 ### Serve uncompiled PolyGerrit
 
 1. Create a new proxied browser window and start mitmproxy via Docker:
diff --git a/contrib/mitm-ui/mitm-theme.sh b/contrib/mitm-ui/mitm-theme.sh
new file mode 100755
index 0000000..9290235
--- /dev/null
+++ b/contrib/mitm-ui/mitm-theme.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+if [[ -z "$1" ]]; then
+    echo This script forces or replaces default site theme on *.googlesource.com
+    echo Provide path to the theme.html as a parameter.
+    exit 1
+fi
+
+realpath() {
+  OURPWD=$PWD
+  cd "$(dirname "$1")"
+  LINK=$(basename "$1")
+  while [ -L "$LINK" ]; do
+      LINK=$(readlink "$LINK")
+      cd "$(dirname "$LINK")"
+      LINK="$(basename "$1")"
+  done
+  REAL_DIR=`pwd -P`
+  RESULT=$REAL_DIR/$LINK
+  cd "$OURPWD"
+  echo "$RESULT"
+}
+
+theme=$(realpath "$1")
+theme_dir=$(dirname "${theme}")
+
+mitm_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
+
+"${mitm_dir}"/dev-chrome.sh &
+
+"${mitm_dir}"/mitm-docker.sh -v "${theme_dir}":"${theme_dir}" "serve-app-dev.py --strip_assets --theme \"${theme}\""
diff --git a/contrib/mitm-ui/serve-app-dev.py b/contrib/mitm-ui/serve-app-dev.py
index bd054e5..18e9de1 100644
--- a/contrib/mitm-ui/serve-app-dev.py
+++ b/contrib/mitm-ui/serve-app-dev.py
@@ -32,9 +32,10 @@
 import argparse
 import os.path
 import json
+import mimetypes
 
 class Server:
-    def __init__(self, devpath, plugins, pluginroot, assets, strip_assets):
+    def __init__(self, devpath, plugins, pluginroot, assets, strip_assets, theme):
         if devpath:
             print("Serving app from " + devpath)
         if pluginroot:
@@ -53,6 +54,7 @@
         self.devpath = devpath
         self.pluginroot = pluginroot
         self.strip_assets = strip_assets
+        self.theme = theme
 
     def readfile(self, path):
         with open(path, 'rb') as contentfile:
@@ -92,6 +94,8 @@
     localfile = ""
     if flow.request.path == "/config/server/info":
         config = json.loads(flow.response.content[5:].decode('utf8'))
+        if server.theme:
+            config['default_theme'] = '/static/gerrit-theme.html'
         for filename, path in server.plugins.items():
             pluginname = filename.split(".")[0]
             payload = config["plugin"]["js_resource_paths" if filename.endswith(".js") else "html_resource_paths"]
@@ -115,13 +119,23 @@
                 localfile = server.pluginroot + pluginfile
             elif os.path.isfile(server.pluginroot + pluginurl):
                 localfile = server.pluginroot + pluginurl
+
+    if server.theme:
+        if flow.request.path.endswith('/gerrit-theme.html'):
+            localfile = server.theme
+        else:
+            match = re.match("^/static(/[\w\.]+)$", flow.request.path)
+            if match is not None:
+                localfile = os.path.dirname(server.theme) + match.group(1)
+
     if localfile and os.path.isfile(localfile):
         if pluginmatch is not None:
             print("Serving " + flow.request.path + " from " + localfile)
         flow.response.content = server.readfile(localfile)
         flow.response.status_code = 200
-        if localfile.endswith('.js'):
-            flow.response.headers['Content-type'] = 'text/javascript'
+        localtype = mimetypes.guess_type(localfile)
+        if localtype and localtype[0]:
+            flow.response.headers['Content-type'] = localtype[0]
 
 def expandpath(path):
     return os.path.realpath(os.path.expanduser(path))
@@ -132,8 +146,11 @@
 parser.add_argument("--plugin_root", type=str, default="", help="Path containing individual plugin files to replace")
 parser.add_argument("--assets", type=str, default="", help="Path containing assets file to import.")
 parser.add_argument("--strip_assets", action="store_true", help="Strip plugin bundles from the response.")
+parser.add_argument("--theme", type=str, help="Path to the default site theme to be used.")
 args = parser.parse_args()
 server = Server(expandpath(args.app) + '/',
-                args.plugins, expandpath(args.plugin_root) + '/',
+                args.plugins,
+                expandpath(args.plugin_root) + '/',
                 args.assets and expandpath(args.assets),
-                args.strip_assets)
+                args.strip_assets,
+                expandpath(args.theme))