Compare commits

..

No commits in common. "cb62961be00d1b1c8549f4a7e20759dfcee0b1c4" and "48163aab7d509703edb961e6fb598af0dc34b7a7" have entirely different histories.

View File

@ -359,27 +359,6 @@ class GitManager:
class CargoAOCRunner: class CargoAOCRunner:
"""Runs cargo-aoc benchmarks and parses results""" """Runs cargo-aoc benchmarks and parses results"""
@staticmethod
def _strip_ansi_codes(text: str) -> str:
"""Remove ANSI escape codes from text"""
import re
if not text:
return text
# Remove ANSI escape sequences - comprehensive pattern
# This pattern matches all ANSI escape codes including:
# - ESC[...m (SGR/color codes)
# - ESC[...K (EL codes)
# - ESC[...H (cursor positioning)
# - ESC[38;5;...m (256-color codes)
# - ESC[0m, ESC[1m, etc.
ansi_escape = re.compile(r'\x1b\[[0-9;]*[a-zA-Z]')
# Also catch standalone ESC sequences
ansi_escape2 = re.compile(r'\x1b(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')
# Remove all ANSI codes
text = ansi_escape.sub('', text)
text = ansi_escape2.sub('', text)
return text
@staticmethod @staticmethod
def find_implemented_days(work_dir: Path) -> List[int]: def find_implemented_days(work_dir: Path) -> List[int]:
"""Find which days are implemented in the directory """Find which days are implemented in the directory
@ -498,8 +477,7 @@ class CargoAOCRunner:
@staticmethod @staticmethod
def run_benchmarks(repo_path: Path, year: int, user: str = "unknown", def run_benchmarks(repo_path: Path, year: int, user: str = "unknown",
repo_url: str = "", is_multi_year: bool = False, repo_url: str = "", is_multi_year: bool = False) -> List[PerformanceResult]:
log_file: Optional[Path] = None) -> List[PerformanceResult]:
"""Run cargo aoc benchmarks and parse results """Run cargo aoc benchmarks and parse results
Args: Args:
@ -508,7 +486,6 @@ class CargoAOCRunner:
user: User name for the results user: User name for the results
repo_url: Repository URL for linking repo_url: Repository URL for linking
is_multi_year: True if this is a multi-year repo (repo_path is already the year directory) is_multi_year: True if this is a multi-year repo (repo_path is already the year directory)
log_file: Optional path to log file to append cargo aoc output to
""" """
results = [] results = []
repo_path = Path(repo_path) repo_path = Path(repo_path)
@ -551,30 +528,6 @@ class CargoAOCRunner:
timeout=300 # 5 minute timeout per day timeout=300 # 5 minute timeout per day
) )
# Write to log file if provided
if log_file:
timestamp = datetime.now().isoformat()
# Strip ANSI codes from output before writing
stdout_clean = CargoAOCRunner._strip_ansi_codes(result.stdout or "")
stderr_clean = CargoAOCRunner._strip_ansi_codes(result.stderr or "")
with open(log_file, 'a', encoding='utf-8') as f:
f.write(f"\n{'='*80}\n")
f.write(f"[{timestamp}] {user} - Year {year} - Day {day}\n")
f.write(f"Command: {' '.join(cmd)}\n")
f.write(f"Working Directory: {work_dir}\n")
f.write(f"Return Code: {result.returncode}\n")
f.write(f"{'='*80}\n")
if result.stdout: # Check original, write cleaned version
f.write("STDOUT:\n")
f.write(stdout_clean)
f.write("\n")
if result.stderr: # Check original, write cleaned version
f.write("STDERR:\n")
f.write(stderr_clean)
f.write("\n")
f.write(f"{'='*80}\n\n")
if result.returncode != 0: if result.returncode != 0:
logger.warning(f"cargo aoc failed for day {day} in {work_dir}: {result.stderr}") logger.warning(f"cargo aoc failed for day {day} in {work_dir}: {result.stderr}")
continue continue
@ -583,13 +536,9 @@ class CargoAOCRunner:
if not result.stdout.strip() and not result.stderr.strip(): if not result.stdout.strip() and not result.stderr.strip():
logger.warning(f"No output from cargo aoc for {user} year {year} day {day}") logger.warning(f"No output from cargo aoc for {user} year {year} day {day}")
# Strip ANSI codes before parsing (for cleaner parsing)
stdout_clean = CargoAOCRunner._strip_ansi_codes(result.stdout or "")
stderr_clean = CargoAOCRunner._strip_ansi_codes(result.stderr or "")
# Parse output for runtime information # Parse output for runtime information
day_results = CargoAOCRunner._parse_runtime_output( day_results = CargoAOCRunner._parse_runtime_output(
stdout_clean, stderr_clean, day, year, user, git_rev, repo_url result.stdout, result.stderr, day, year, user, git_rev, repo_url
) )
if day_results: if day_results:
logger.info(f"Parsed {len(day_results)} runtime result(s) for {user} year {year} day {day}") logger.info(f"Parsed {len(day_results)} runtime result(s) for {user} year {year} day {day}")
@ -600,19 +549,9 @@ class CargoAOCRunner:
results.extend(day_results) results.extend(day_results)
except subprocess.TimeoutExpired: except subprocess.TimeoutExpired:
error_msg = f"Timeout running cargo aoc for day {day}" logger.error(f"Timeout running cargo aoc for day {day}")
logger.error(error_msg)
if log_file:
timestamp = datetime.now().isoformat()
with open(log_file, 'a', encoding='utf-8') as f:
f.write(f"\n[{timestamp}] ERROR: {error_msg}\n")
except Exception as e: except Exception as e:
error_msg = f"Error running cargo aoc for day {day}: {e}" logger.error(f"Error running cargo aoc for day {day}: {e}")
logger.error(error_msg)
if log_file:
timestamp = datetime.now().isoformat()
with open(log_file, 'a', encoding='utf-8') as f:
f.write(f"\n[{timestamp}] ERROR: {error_msg}\n")
return results return results
@ -1089,9 +1028,6 @@ class HTMLGenerator:
def _generate_html(self, data: dict, years: List[int], users: List[str], db: Database, config: Config) -> str: def _generate_html(self, data: dict, years: List[int], users: List[str], db: Database, config: Config) -> str:
"""Generate HTML content""" """Generate HTML content"""
# Get refresh interval from config (default 5 minutes = 300 seconds)
refresh_interval = config.config.get('html_refresh_interval', 300)
# Sort years descending (most recent first) # Sort years descending (most recent first)
sorted_years = sorted(years, reverse=True) sorted_years = sorted(years, reverse=True)
@ -1104,16 +1040,11 @@ class HTMLGenerator:
for part in day.values(): for part in day.values():
users_with_data.update(part.keys()) users_with_data.update(part.keys())
# Check if log file exists
log_file_path = Path(config.output_dir) / 'cargo-aoc.log'
log_file_exists = log_file_path.exists()
html = f"""<!DOCTYPE html> html = f"""<!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="refresh" content="{refresh_interval}">
<title>Advent of Code Performance Comparison</title> <title>Advent of Code Performance Comparison</title>
<style> <style>
* {{ * {{
@ -1510,7 +1441,6 @@ class HTMLGenerator:
<div class="controls"> <div class="controls">
<p><strong>Users:</strong> """ + ', '.join(sorted(users)) + """</p> <p><strong>Users:</strong> """ + ', '.join(sorted(users)) + """</p>
""" + (f'<p><a href="cargo-aoc.log" target="_blank">📋 View Cargo AOC Logs</a></p>' if log_file_exists else '') + """
</div> </div>
""" """
@ -1864,12 +1794,8 @@ class AOCSync:
repo_url: str = "", is_multi_year: bool = False): repo_url: str = "", is_multi_year: bool = False):
"""Run benchmarks and store results""" """Run benchmarks and store results"""
logger.info(f"Running benchmarks for {user} year {year} in {repo_path}") logger.info(f"Running benchmarks for {user} year {year} in {repo_path}")
# Create log file path in output directory
log_file = Path(self.config.output_dir) / 'cargo-aoc.log'
log_file.parent.mkdir(parents=True, exist_ok=True)
results = CargoAOCRunner.run_benchmarks(repo_path, year=year, user=user, results = CargoAOCRunner.run_benchmarks(repo_path, year=year, user=user,
repo_url=repo_url, is_multi_year=is_multi_year, repo_url=repo_url, is_multi_year=is_multi_year)
log_file=log_file)
# Store results # Store results
for result in results: for result in results:
@ -1881,15 +1807,6 @@ class AOCSync:
"""Sync all repositories""" """Sync all repositories"""
logger.info("Starting sync of all repositories...") logger.info("Starting sync of all repositories...")
# Clear log file at start of sync
log_file = Path(self.config.output_dir) / 'cargo-aoc.log'
log_file.parent.mkdir(parents=True, exist_ok=True)
# Clear the log file and write a header
with open(log_file, 'w', encoding='utf-8') as f:
f.write(f"{'#'*80}\n")
f.write(f"# Sync started at {datetime.now().isoformat()}\n")
f.write(f"{'#'*80}\n\n")
for repo_config in self.config.repositories: for repo_config in self.config.repositories:
user_name = repo_config['name'] user_name = repo_config['name']
try: try:
@ -1925,7 +1842,6 @@ class AOCSync:
try: try:
# Build rsync command # Build rsync command
# Use trailing slash on source to sync contents, not the directory itself # Use trailing slash on source to sync contents, not the directory itself
# This will include all files including cargo-aoc.log
source = str(output_dir) + "/" source = str(output_dir) + "/"
cmd = ['rsync', '-avz', '--delete', source, destination] cmd = ['rsync', '-avz', '--delete', source, destination]