CLI Update + Threading (#1046)
This commit is contained in:
parent
6dc2778a15
commit
d1703f41b6
@ -378,23 +378,13 @@ class App(Base):
|
||||
):
|
||||
self.pages[froute(constants.SLUG_404)] = component
|
||||
|
||||
def compile(self, force_compile: bool = False):
|
||||
"""Compile the app and output it to the pages folder.
|
||||
|
||||
If the config environment is set to production, the app will
|
||||
not be compiled.
|
||||
|
||||
Args:
|
||||
force_compile: Whether to force the app to compile.
|
||||
"""
|
||||
def compile(self):
|
||||
"""Compile the app and output it to the pages folder."""
|
||||
for render, kwargs in DECORATED_ROUTES:
|
||||
self.add_page(render, **kwargs)
|
||||
|
||||
# Get the env mode.
|
||||
config = get_config()
|
||||
if config.env != constants.Env.DEV and not force_compile:
|
||||
print("Skipping compilation in non-dev mode.")
|
||||
return
|
||||
|
||||
# Update models during hot reload.
|
||||
if config.db_url is not None:
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
import os
|
||||
import platform
|
||||
import threading
|
||||
from pathlib import Path
|
||||
|
||||
import httpx
|
||||
@ -125,16 +126,15 @@ def run(
|
||||
telemetry.send(f"run-{env.value}", get_config().telemetry_enabled)
|
||||
|
||||
# Run the frontend and backend.
|
||||
try:
|
||||
if frontend:
|
||||
frontend_cmd(app.app, Path.cwd(), frontend_port)
|
||||
if backend:
|
||||
backend_cmd(app.__name__, port=int(backend_port), loglevel=loglevel)
|
||||
finally:
|
||||
if frontend:
|
||||
processes.kill_process_on_port(frontend_port)
|
||||
if backend:
|
||||
processes.kill_process_on_port(backend_port)
|
||||
# try:
|
||||
if backend:
|
||||
threading.Thread(
|
||||
target=backend_cmd, args=(app.__name__, backend_port, loglevel)
|
||||
).start()
|
||||
if frontend:
|
||||
threading.Thread(
|
||||
target=frontend_cmd, args=(app.app, Path.cwd(), frontend_port)
|
||||
).start()
|
||||
|
||||
|
||||
@cli.command()
|
||||
|
@ -77,6 +77,7 @@ def export_app(
|
||||
frontend: bool = True,
|
||||
zip: bool = False,
|
||||
deploy_url: Optional[str] = None,
|
||||
loglevel: constants.LogLevel = constants.LogLevel.ERROR,
|
||||
):
|
||||
"""Zip up the app for deployment.
|
||||
|
||||
@ -86,10 +87,8 @@ def export_app(
|
||||
frontend: Whether to zip up the frontend app.
|
||||
zip: Whether to zip the app.
|
||||
deploy_url: The URL of the deployed app.
|
||||
loglevel: The log level to use.
|
||||
"""
|
||||
# Force compile the app.
|
||||
app.compile(force_compile=True)
|
||||
|
||||
# Remove the static folder.
|
||||
path_ops.rm(constants.WEB_STATIC_DIR)
|
||||
|
||||
@ -106,18 +105,17 @@ def export_app(
|
||||
# Start the progress bar
|
||||
with progress:
|
||||
# Run the subprocess command
|
||||
process = subprocess.Popen(
|
||||
export_process = subprocess.Popen(
|
||||
[prerequisites.get_package_manager(), "run", "export"],
|
||||
cwd=constants.WEB_DIR,
|
||||
stderr=subprocess.DEVNULL,
|
||||
env=os.environ,
|
||||
stderr=subprocess.STDOUT,
|
||||
stdout=subprocess.PIPE, # Redirect stdout to a pipe
|
||||
universal_newlines=True, # Set universal_newlines to True for text mode
|
||||
)
|
||||
|
||||
# Read the output of the subprocess line by line
|
||||
if process.stdout:
|
||||
for line in iter(process.stdout.readline, ""):
|
||||
# Update the progress bar based on the output
|
||||
if export_process.stdout:
|
||||
for line in iter(export_process.stdout.readline, ""):
|
||||
if "Linting and checking " in line:
|
||||
progress.update(task, advance=100)
|
||||
elif "Compiled successfully" in line:
|
||||
@ -127,8 +125,15 @@ def export_app(
|
||||
elif "automatically rendered as static HTML" in line:
|
||||
progress.update(task, advance=100)
|
||||
elif "Export successful" in line:
|
||||
print("DOOE")
|
||||
progress.update(task, completed=500)
|
||||
break # Exit the loop if the completion message is found
|
||||
elif loglevel == constants.LogLevel.DEBUG:
|
||||
print(line, end="")
|
||||
|
||||
# Wait for the subprocess to complete
|
||||
export_process.wait()
|
||||
print("Export process completed.")
|
||||
|
||||
# Zip up the app.
|
||||
if zip:
|
||||
|
@ -5,11 +5,10 @@ from __future__ import annotations
|
||||
import os
|
||||
import platform
|
||||
import subprocess
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import typer
|
||||
import uvicorn
|
||||
from rich import print
|
||||
|
||||
from pynecone import constants
|
||||
@ -32,44 +31,58 @@ def start_watching_assets_folder(root):
|
||||
asset_watch.start()
|
||||
|
||||
|
||||
def run_process_and_launch_url(run_command: list[str], root: Path):
|
||||
def run_process_and_launch_url(
|
||||
run_command: list[str],
|
||||
root: Path,
|
||||
loglevel: constants.LogLevel = constants.LogLevel.ERROR,
|
||||
):
|
||||
"""Run the process and launch the URL.
|
||||
|
||||
Args:
|
||||
run_command: The command to run.
|
||||
root: root path of the project.
|
||||
loglevel: The log level to use.
|
||||
"""
|
||||
process = subprocess.Popen(
|
||||
run_command,
|
||||
cwd=constants.WEB_DIR,
|
||||
env=os.environ,
|
||||
stderr=subprocess.DEVNULL,
|
||||
stderr=subprocess.STDOUT,
|
||||
stdout=subprocess.PIPE,
|
||||
universal_newlines=True,
|
||||
)
|
||||
|
||||
message_found = False
|
||||
current_time = datetime.now()
|
||||
if process.stdout:
|
||||
for line in process.stdout:
|
||||
if "ready started server on" in line:
|
||||
url = line.split("url: ")[-1].strip()
|
||||
print(f"App running at: [bold green]{url}")
|
||||
typer.launch(url)
|
||||
message_found = True
|
||||
break
|
||||
|
||||
if not message_found and process.stdout:
|
||||
for line in process.stdout:
|
||||
print(line, end="")
|
||||
if (
|
||||
"Fast Refresh" in line
|
||||
and (datetime.now() - current_time).total_seconds() > 1
|
||||
):
|
||||
print(
|
||||
f"[yellow][Updating App][/yellow] Applying changes and refreshing. Time: {current_time}"
|
||||
)
|
||||
current_time = datetime.now()
|
||||
elif loglevel == constants.LogLevel.DEBUG:
|
||||
print(line, end="")
|
||||
|
||||
|
||||
def run_frontend(app: App, root: Path, port: str):
|
||||
def run_frontend(
|
||||
app: App,
|
||||
root: Path,
|
||||
port: str,
|
||||
loglevel: constants.LogLevel = constants.LogLevel.ERROR,
|
||||
):
|
||||
"""Run the frontend.
|
||||
|
||||
Args:
|
||||
app: The app.
|
||||
root: root path of the project.
|
||||
port: port of the app.
|
||||
loglevel: The log level to use.
|
||||
"""
|
||||
# validate bun version
|
||||
prerequisites.validate_and_install_bun(initialize=False)
|
||||
@ -77,33 +90,36 @@ def run_frontend(app: App, root: Path, port: str):
|
||||
# Set up the frontend.
|
||||
setup_frontend(root)
|
||||
|
||||
# start watching asset folder
|
||||
# Start watching asset folder.
|
||||
start_watching_assets_folder(root)
|
||||
|
||||
# Compile the frontend.
|
||||
app.compile(force_compile=True)
|
||||
|
||||
# Run the frontend in development mode.
|
||||
console.rule("[bold green]App Running")
|
||||
os.environ["PORT"] = get_config().port if port is None else port
|
||||
run_process_and_launch_url(
|
||||
[prerequisites.get_package_manager(), "run", "dev"], root
|
||||
[prerequisites.get_package_manager(), "run", "dev"], root, loglevel
|
||||
)
|
||||
|
||||
|
||||
def run_frontend_prod(app: App, root: Path, port: str):
|
||||
def run_frontend_prod(
|
||||
app: App,
|
||||
root: Path,
|
||||
port: str,
|
||||
loglevel: constants.LogLevel = constants.LogLevel.ERROR,
|
||||
):
|
||||
"""Run the frontend.
|
||||
|
||||
Args:
|
||||
app: The app.
|
||||
root: root path of the project.
|
||||
port: port of the app.
|
||||
loglevel: The log level to use.
|
||||
"""
|
||||
# Set up the frontend.
|
||||
setup_frontend(root)
|
||||
|
||||
# Export the app.
|
||||
export_app(app)
|
||||
export_app(app, loglevel=loglevel)
|
||||
|
||||
# Set the port.
|
||||
os.environ["PORT"] = get_config().port if port is None else port
|
||||
@ -111,7 +127,7 @@ def run_frontend_prod(app: App, root: Path, port: str):
|
||||
# Run the frontend in production mode.
|
||||
console.rule("[bold green]App Running")
|
||||
run_process_and_launch_url(
|
||||
[prerequisites.get_package_manager(), "run", "prod"], root
|
||||
[prerequisites.get_package_manager(), "run", "prod"], root, loglevel
|
||||
)
|
||||
|
||||
|
||||
@ -127,13 +143,23 @@ def run_backend(
|
||||
"""
|
||||
setup_backend()
|
||||
|
||||
uvicorn.run(
|
||||
cmd = [
|
||||
"uvicorn",
|
||||
f"{app_name}:{constants.APP_VAR}.{constants.API_VAR}",
|
||||
host=constants.BACKEND_HOST,
|
||||
port=port,
|
||||
log_level=loglevel,
|
||||
reload=True,
|
||||
)
|
||||
"--host",
|
||||
constants.BACKEND_HOST,
|
||||
"--port",
|
||||
str(port),
|
||||
"--log-level",
|
||||
loglevel,
|
||||
"--reload",
|
||||
]
|
||||
process = subprocess.Popen(cmd)
|
||||
|
||||
try:
|
||||
process.wait()
|
||||
except KeyboardInterrupt:
|
||||
process.terminate()
|
||||
|
||||
|
||||
def run_backend_prod(
|
||||
|
@ -15,7 +15,7 @@ while ! nc -z localhost 3000 || ! lsof -i :8000 >/dev/null; do
|
||||
echo "Error: Server process with PID $pid exited early"
|
||||
break
|
||||
fi
|
||||
if ((wait_time >= 300)); then
|
||||
if ((wait_time >= 500)); then
|
||||
echo "Error: Timeout waiting for ports 3000 and 8000 to become available"
|
||||
exit 1
|
||||
fi
|
||||
|
Loading…
Reference in New Issue
Block a user