Skip to content

Commit

Permalink
Merge pull request #102 from piercefreeman/feature/cli-verbosity
Browse files Browse the repository at this point in the history
Use rich cli in runserver
  • Loading branch information
piercefreeman authored Apr 29, 2024
2 parents cf70733 + fb27240 commit 1692785
Show file tree
Hide file tree
Showing 14 changed files with 373 additions and 151 deletions.
8 changes: 8 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,14 @@ jobs:
# Clang is already installed as part of the base image
apt-get update
apt-get -y install wget
# The maturin environment includes the gcc cross-compilers for aarch64, but it
# doesn't include the necessary headers
# This causes issues when rust / bindgen tries to run clang, which will fail with
# missing headers like 'bits/libc-header-start.h' file not found
# We install the headers here to fix this issue
apt install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
find /usr -name libc-header-start.h
else
echo "Unsupported distribution: $DISTRO"
exit 1
Expand Down
93 changes: 71 additions & 22 deletions ci_webapp/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 39 additions & 9 deletions mountaineer/cli.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
import asyncio
import socket
from contextlib import contextmanager
from contextlib import contextmanager, redirect_stdout
from dataclasses import dataclass
from functools import partial
from importlib import import_module
from importlib.metadata import distributions
from io import StringIO
from multiprocessing import Event, Process, Queue, get_start_method, set_start_method
from multiprocessing.queues import Queue as QueueType
from pathlib import Path
from signal import SIGINT, signal
from tempfile import mkdtemp
from threading import Thread
from time import sleep, time
from time import monotonic_ns, sleep, time
from traceback import format_exception
from typing import Any, Callable, MutableMapping

from click import secho
from fastapi import Request
from rich.traceback import install as rich_traceback_install

from mountaineer.app import AppController
from mountaineer.client_builder.builder import ClientBuilder
from mountaineer.console import CONSOLE, ERROR_CONSOLE
from mountaineer.controllers.exception_controller import ExceptionController
from mountaineer.js_compiler.exceptions import BuildProcessException
from mountaineer.logging import LOGGER
Expand Down Expand Up @@ -89,7 +92,23 @@ def run(self):
f"Starting isolated environment process with\nbuild_config: {self.build_config}\nrunserver_config: {self.runserver_config}"
)

app_controller = import_from_string(self.build_config.webcontroller)
CONSOLE.rule("[bold red]Mountaineer Build Started")

with (
# We don't want to print stdout on the initial import, since this will just duplicate
# the init code / logging of the app. We use our error console to avoid
# capturing the stdout of our logging
ERROR_CONSOLE.status("[bold blue]Loading app...", spinner="dots"),
StringIO() as buf,
redirect_stdout(buf),
):
start = monotonic_ns()
app_controller = import_from_string(self.build_config.webcontroller)
LOGGER.debug(f"Load app logs: {buf.getvalue()}")
CONSOLE.print(
f"[bold green]🎒 Loaded app in {(monotonic_ns() - start) / 1e9:.2f}s"
)

if not isinstance(app_controller, AppController):
raise ValueError(
f"Expected {self.build_config.webcontroller} to be an instance of AppController"
Expand Down Expand Up @@ -200,7 +219,6 @@ def wait_for_rebuild():
rebuild_thread.start()

def run_build(self, app_controller: AppController):
secho("Starting build...", fg="yellow")
start = time()
js_compiler = ClientBuilder(
app_controller,
Expand All @@ -213,14 +231,16 @@ def run_build(self, app_controller: AppController):
)
try:
js_compiler.build()
secho(f"Build finished in {time() - start:.2f} seconds", fg="green")
CONSOLE.print(
f"[bold green]🚀 App launched in {time() - start:.2f} seconds"
)

# Completed successfully
app_controller.build_exception = None

self.alert_notification_channel()
except BuildProcessException as e:
secho(f"Build failed: {e}", fg="red")
CONSOLE.print(f"[bold red]⚠️ Build failed: {e}")
app_controller.build_exception = e

def stop(self, hard_timeout: float = 5.0):
Expand Down Expand Up @@ -344,6 +364,8 @@ def handle_runserver(
"""
update_multiprocessing_settings()

rich_traceback_install()

current_process: IsolatedEnvProcess | None = None

# The global cache will let us keep cache files warm across
Expand Down Expand Up @@ -420,7 +442,7 @@ def handle_build(
)
start = time()
js_compiler.build()
secho(f"Build finished in {time() - start:.2f} seconds", fg="green")
CONSOLE.print(f"[bold green]App built in {time() - start:.2f}s")


def update_multiprocessing_settings():
Expand Down Expand Up @@ -516,12 +538,20 @@ def build_common_watchdog(
def init_global_state(webcontroller: str):
"""
Initialize global state: signal to each builder that they can
initialize global state before the fork.
set up their own global state before the fork.
"""
global_state: dict[Any, Any] = {}

app_controller = import_from_string(webcontroller)
with (
ERROR_CONSOLE.status(
"[bold blue]Setting up global state before fork...", spinner="dots"
),
StringIO() as buf,
redirect_stdout(buf),
):
app_controller = import_from_string(webcontroller)
LOGGER.debug(f"init_global_state Load app logs: {buf.getvalue()}")

if not isinstance(app_controller, AppController):
raise ValueError(f"Unknown app controller: {app_controller}")
Expand Down
43 changes: 24 additions & 19 deletions mountaineer/client_builder/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
TSLiteral,
python_payload_to_typescript,
)
from mountaineer.console import CONSOLE
from mountaineer.controller import ControllerBase
from mountaineer.io import gather_with_concurrency
from mountaineer.js_compiler.base import ClientBundleMetadata
Expand Down Expand Up @@ -70,26 +71,30 @@ def build(self):
async def async_build(self):
# Avoid rebuilding if we don't need to
if self.cache_is_outdated():
secho("Building useServer, cache outdated...", fg="green")

# Make sure our application definitions are in a valid state before we start
# to build the client code
self.validate_unique_paths()

# Static files that don't depend on client code
self.generate_static_files()

# The order of these generators don't particularly matter since most TSX linters
# won't refresh until they're all complete. However, this ordering better aligns
# with semantic dependencies so we keep the linearity where possible.
self.generate_model_definitions()
self.generate_action_definitions()
self.generate_link_shortcuts()
self.generate_link_aggregator()
self.generate_view_servers()
self.generate_index_file()
start = monotonic_ns()

with CONSOLE.status("Building useServer", spinner="dots"):
# Make sure our application definitions are in a valid state before we start
# to build the client code
self.validate_unique_paths()

# Static files that don't depend on client code
self.generate_static_files()

# The order of these generators don't particularly matter since most TSX linters
# won't refresh until they're all complete. However, this ordering better aligns
# with semantic dependencies so we keep the linearity where possible.
self.generate_model_definitions()
self.generate_action_definitions()
self.generate_link_shortcuts()
self.generate_link_aggregator()
self.generate_view_servers()
self.generate_index_file()
CONSOLE.print(
f"[bold green]🔨 Built useServer in {(monotonic_ns() - start) / 1e9:.2f}s"
)
else:
secho("useServer up to date", fg="green")
CONSOLE.print("[bold green]useServer up to date")

await self.build_javascript_chunks()

Expand Down
6 changes: 6 additions & 0 deletions mountaineer/console.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Separated from logging.py to isolate build-time dependencies
# from ones required by actual deployments
from rich.console import Console

CONSOLE = Console()
ERROR_CONSOLE = Console(stderr=True)
Loading

0 comments on commit 1692785

Please sign in to comment.