diff --git a/aocsync.py b/aocsync.py index ad3bb70..bbe25c5 100755 --- a/aocsync.py +++ b/aocsync.py @@ -78,6 +78,10 @@ class Config: @property def compare_days(self) -> Optional[List[int]]: return self.config.get('compare_days') + + @property + def rsync_config(self) -> Optional[dict]: + return self.config.get('rsync') class Database: @@ -1160,6 +1164,49 @@ class AOCSync: # Generate HTML report logger.info("Generating HTML report...") self.html_gen.generate(self.db, self.config) + + # Rsync output if configured + self._rsync_output() + + def _rsync_output(self): + """Rsync output directory to remote server if configured""" + rsync_config = self.config.rsync_config + if not rsync_config or not rsync_config.get('enabled', False): + return + + destination = rsync_config.get('destination') + if not destination: + logger.warning("Rsync enabled but no destination specified") + return + + output_dir = Path(self.config.output_dir) + if not output_dir.exists(): + logger.warning(f"Output directory {output_dir} does not exist, skipping rsync") + return + + logger.info(f"Rsyncing {output_dir} to {destination}...") + + try: + # Build rsync command + # Use trailing slash on source to sync contents, not the directory itself + source = str(output_dir) + "/" + cmd = ['rsync', '-avz', '--delete', source, destination] + + result = subprocess.run( + cmd, + capture_output=True, + text=True, + timeout=60 # 1 minute timeout + ) + + if result.returncode == 0: + logger.info(f"Successfully rsynced output to {destination}") + else: + logger.error(f"Rsync failed: {result.stderr}") + except subprocess.TimeoutExpired: + logger.error("Rsync timed out") + except Exception as e: + logger.error(f"Error during rsync: {e}") def run_continuous(self): """Run continuous polling"""