From cdc2ecb19527551882cf181b4ca3407fe99bd3fa Mon Sep 17 00:00:00 2001 From: Bill Thiede Date: Thu, 4 Dec 2025 16:55:48 -0800 Subject: [PATCH] Automatically build custom image w/ cargo-aoc and allow networking --- aocsync.py | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/aocsync.py b/aocsync.py index 92ea197..b85cab4 100755 --- a/aocsync.py +++ b/aocsync.py @@ -626,7 +626,7 @@ class CargoAOCRunner: podman_cmd = [ 'podman', 'run', '--rm', # Remove container after execution - '--network=none', # No network access + #'--network=none', # No network access '--memory', docker_config.get('memory', '2g'), # Limit memory '--cpus', str(docker_config.get('cpus', '2')), # Limit CPU '--read-only', # Read-only root filesystem @@ -1991,6 +1991,8 @@ class AOCSync: self.html_gen = HTMLGenerator(self.config.output_dir) self.git_manager = GitManager() self.force_rerun = force_rerun + # Ensure Podman image exists + self._ensure_podman_image() def process_repository(self, repo_config: dict, user_name: str): """Process a single repository configuration""" @@ -2106,6 +2108,72 @@ class AOCSync: logger.info(f"Stored {len(results)} benchmark results for {user} year {year}") + def _ensure_podman_image(self): + """Check if the Podman image exists, build it if it doesn't""" + docker_config = self.config.docker_config + image_name = docker_config.get('image', 'aocsync:latest') + + # Only check/build if using aocsync:latest or custom image (not rust:latest) + if image_name != 'rust:latest': + # Check if image exists + try: + result = subprocess.run( + ['podman', 'images', '--format', '{{.Repository}}:{{.Tag}}'], + capture_output=True, + text=True, + timeout=5 + ) + + # Parse image name (handle cases like "aocsync:latest" or just "aocsync") + image_repo, image_tag = (image_name.split(':') + ['latest'])[:2] + + # Check if image exists in the output + image_exists = False + for line in result.stdout.strip().split('\n'): + if line: + repo, tag = (line.split(':') + ['latest'])[:2] + if repo == image_repo and tag == image_tag: + image_exists = True + break + + if not image_exists: + logger.info(f"Podman image {image_name} not found, building it...") + self._build_podman_image(image_name) + else: + logger.debug(f"Podman image {image_name} exists") + except Exception as e: + logger.warning(f"Could not check for Podman image {image_name}: {e}") + logger.info("Attempting to build image anyway...") + self._build_podman_image(image_name) + + def _build_podman_image(self, image_name: str): + """Build the Podman image from Dockerfile""" + dockerfile_path = Path(__file__).parent / 'Dockerfile' + + if not dockerfile_path.exists(): + logger.error(f"Dockerfile not found at {dockerfile_path}") + logger.error("Cannot build Podman image. Please create Dockerfile or use rust:latest image.") + return + + try: + logger.info(f"Building Podman image {image_name} from {dockerfile_path}...") + result = subprocess.run( + ['podman', 'build', '-t', image_name, '-f', str(dockerfile_path), str(dockerfile_path.parent)], + capture_output=True, + text=True, + timeout=600 # 10 minute timeout for build + ) + + if result.returncode == 0: + logger.info(f"Successfully built Podman image {image_name}") + else: + logger.error(f"Failed to build Podman image: {result.stderr}") + logger.warning("Falling back to rust:latest (will install cargo-aoc on each run)") + except subprocess.TimeoutExpired: + logger.error("Podman build timed out") + except Exception as e: + logger.error(f"Error building Podman image: {e}") + def sync_all(self): """Sync all repositories""" logger.info("Starting sync of all repositories...")