mirror of
https://github.com/harvard-edge/cs249r_book.git
synced 2026-04-29 17:20:21 -05:00
New Commands: - Add PreviewCommand for live development server with hot reload - Add DoctorCommand for comprehensive health checks (18 checks) - Clear command descriptions distinguish build vs preview vs formats Command Clarity: - build: Build static files to disk (HTML) - preview: Start live dev server with hot reload - pdf: Build static PDF file to disk - epub: Build static EPUB file to disk Health Check Features: - System dependencies (Python, Quarto, Git, Node.js, R) - Configuration file validation - Chapter file scanning (62 chapters found) - Build artifacts status - Git repository status - File permissions check All tests passing - comprehensive CLI ready for use
118 lines
4.1 KiB
Python
118 lines
4.1 KiB
Python
"""
|
|
Preview command implementation for MLSysBook CLI.
|
|
|
|
Handles starting development servers with live reload for interactive development.
|
|
"""
|
|
|
|
import subprocess
|
|
import signal
|
|
import sys
|
|
from pathlib import Path
|
|
from typing import List, Optional
|
|
from rich.console import Console
|
|
|
|
console = Console()
|
|
|
|
|
|
class PreviewCommand:
|
|
"""Handles preview operations for the MLSysBook."""
|
|
|
|
def __init__(self, config_manager, chapter_discovery):
|
|
"""Initialize preview command.
|
|
|
|
Args:
|
|
config_manager: ConfigManager instance
|
|
chapter_discovery: ChapterDiscovery instance
|
|
"""
|
|
self.config_manager = config_manager
|
|
self.chapter_discovery = chapter_discovery
|
|
|
|
def preview_full(self, format_type: str = "html") -> bool:
|
|
"""Start full preview server for the entire book.
|
|
|
|
Args:
|
|
format_type: Format to preview ('html' only supported)
|
|
|
|
Returns:
|
|
True if server started successfully, False otherwise
|
|
"""
|
|
if format_type != "html":
|
|
console.print(f"[yellow]⚠️ Preview only supports HTML format, not {format_type}[/yellow]")
|
|
return False
|
|
|
|
console.print("[blue]🌐 Starting full book preview server...[/blue]")
|
|
|
|
# Setup config
|
|
config_name = self.config_manager.setup_symlink(format_type)
|
|
console.print(f"[blue]🔗 Using {config_name}[/blue]")
|
|
console.print("[dim]🛑 Press Ctrl+C to stop the server[/dim]")
|
|
|
|
try:
|
|
# Start Quarto preview server
|
|
preview_cmd = ["quarto", "preview"]
|
|
|
|
console.print(f"[blue]💻 Command: {' '.join(preview_cmd)}[/blue]")
|
|
|
|
# Run preview server (this will block until Ctrl+C)
|
|
result = subprocess.run(
|
|
preview_cmd,
|
|
cwd=self.config_manager.book_dir
|
|
)
|
|
|
|
return result.returncode == 0
|
|
|
|
except KeyboardInterrupt:
|
|
console.print("\n[yellow]🛑 Preview server stopped[/yellow]")
|
|
return True
|
|
except Exception as e:
|
|
console.print(f"[red]❌ Preview server error: {e}[/red]")
|
|
return False
|
|
|
|
def preview_chapter(self, chapter_name: str) -> bool:
|
|
"""Start preview server for a specific chapter.
|
|
|
|
Args:
|
|
chapter_name: Name of the chapter to preview
|
|
|
|
Returns:
|
|
True if server started successfully, False otherwise
|
|
"""
|
|
# Find the chapter file
|
|
chapter_file = self.chapter_discovery.find_chapter_file(chapter_name)
|
|
if not chapter_file:
|
|
console.print(f"[red]❌ No chapter found matching '{chapter_name}'[/red]")
|
|
console.print("[yellow]💡 Available chapters:[/yellow]")
|
|
self.chapter_discovery.show_chapters()
|
|
return False
|
|
|
|
target_path = str(chapter_file.relative_to(self.config_manager.book_dir))
|
|
chapter_display_name = str(chapter_file.relative_to(self.config_manager.book_dir / "contents")).replace(".qmd", "")
|
|
|
|
console.print(f"[blue]🌐 Starting preview for[/blue] [bold]{chapter_display_name}[/bold]")
|
|
|
|
# Setup HTML config for preview
|
|
self.config_manager.setup_symlink("html")
|
|
|
|
console.print("[dim]🛑 Press Ctrl+C to stop the server[/dim]")
|
|
|
|
try:
|
|
# Start Quarto preview for specific file
|
|
preview_cmd = ["quarto", "preview", target_path]
|
|
|
|
console.print(f"[blue]💻 Command: {' '.join(preview_cmd)}[/blue]")
|
|
|
|
# Run preview server (this will block until Ctrl+C)
|
|
result = subprocess.run(
|
|
preview_cmd,
|
|
cwd=self.config_manager.book_dir
|
|
)
|
|
|
|
return result.returncode == 0
|
|
|
|
except KeyboardInterrupt:
|
|
console.print("\n[yellow]🛑 Preview server stopped[/yellow]")
|
|
return True
|
|
except Exception as e:
|
|
console.print(f"[red]❌ Preview server error: {e}[/red]")
|
|
return False
|