| # Copyright 2023 The Chromium Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| from __future__ import annotations |
| |
| import abc |
| import html |
| import pathlib |
| import urllib.parse |
| from argparse import ArgumentTypeError |
| from typing import TYPE_CHECKING, Dict |
| |
| if TYPE_CHECKING: |
| from crossbench.runner.run import Run |
| |
| |
| class SplashScreen: |
| NONE: SplashScreen |
| MINIMAL: SplashScreen |
| DETAILED: SplashScreen |
| DEFAULT: SplashScreen |
| |
| @classmethod |
| def parse(cls, value: str) -> SplashScreen: |
| if not value or value == "default": |
| return cls.DEFAULT |
| if value in ("none", "skip"): |
| return cls.NONE |
| if value == "minimal": |
| return cls.MINIMAL |
| if value == "detailed": |
| return cls.DETAILED |
| if value.startswith("http:") or value.startswith("https:"): |
| return URLSplashScreen(value) |
| maybe_path = pathlib.Path(value) |
| if maybe_path.exists(): |
| return URLSplashScreen(maybe_path.absolute().as_uri()) |
| raise ArgumentTypeError(f"Unknown splashscreen: {value}") |
| |
| def run(self, run: Run) -> None: |
| pass |
| |
| |
| _BLANK_PAGE_HTML = "<html></html>" |
| _BLANK_PAGE_DATA_URL = f"data:text/html;charset=utf-8,{urllib.parse.quote(_BLANK_PAGE_HTML)}" |
| |
| |
| class BaseURLSplashScreen(SplashScreen, metaclass=abc.ABCMeta): |
| |
| def __init__(self, timeout: float = 2) -> None: |
| super().__init__() |
| self._timeout = timeout |
| |
| def run(self, run: Run) -> None: |
| with run.actions("SplashScreen") as action: |
| action.show_url(self.get_url(run)) |
| action.wait(self._timeout) |
| action.show_url(_BLANK_PAGE_DATA_URL) |
| |
| @abc.abstractmethod |
| def get_url(self, run: Run) -> str: |
| pass |
| |
| |
| class DetailedSplashScreen(BaseURLSplashScreen): |
| |
| def get_url(self, run: Run) -> str: |
| browser = run.browser |
| title = html.escape(browser.app_name.title()) |
| version = html.escape(browser.version) |
| page = ("<html><head>" |
| f"<title>Run Details</title>" |
| "<style>" |
| """ |
| html { font-family: sans-serif; background-color: #000; color: #fff; } |
| dl { |
| display: grid; |
| grid-template-columns: max-content auto; |
| } |
| dt { grid-column-start: 1; } |
| dd { grid-column-start: 2; font-family: monospace; } |
| """ |
| "</style>" |
| "</head><body>" |
| f"<h1>{title} {version}</h1>") |
| page += self._render_browser_details(run) |
| page += self._render_run_details(run) |
| page += "</body></html>" |
| data_url = f"data:text/html;charset=utf-8,{urllib.parse.quote(page)}" |
| return data_url |
| |
| def _render_properties(self, title: str, properties: Dict[str, str]) -> str: |
| section = f"<h2>{html.escape(title)}</h2><dl>" |
| for property_name, value in properties.items(): |
| section += f"<dt>{html.escape(property_name)}</dt>" |
| section += f"<dd>{html.escape(str(value))}</dd>" |
| section += "</dl>" |
| return section |
| |
| def _render_browser_details(self, run: Run) -> str: |
| browser = run.browser |
| properties = { |
| "User Agent": browser.user_agent(run.runner), |
| **browser.details_json() |
| } |
| return self._render_properties("Browser Details", properties) |
| |
| def _render_run_details(self, run: Run) -> str: |
| return self._render_properties("Run Details", run.details_json()) |
| |
| |
| class MinimalSplashScreen(DetailedSplashScreen): |
| |
| def _render_browser_details(self, run: Run) -> str: |
| properties = {"User Agent": run.browser.user_agent(run.runner)} |
| return self._render_properties("Browser Details", properties) |
| |
| |
| class URLSplashScreen(BaseURLSplashScreen): |
| |
| def __init__(self, url: str, timeout: float = 2) -> None: |
| super().__init__(timeout) |
| self._url = url |
| |
| def get_url(self, run: Run) -> str: |
| return self._url |
| |
| @property |
| def url(self) -> str: |
| return self._url |
| |
| |
| SplashScreen.NONE = SplashScreen() |
| SplashScreen.MINIMAL = MinimalSplashScreen() |
| SplashScreen.DETAILED = DetailedSplashScreen() |
| SplashScreen.DEFAULT = SplashScreen.DETAILED |