from datetime import datetime import subprocess import xml.etree.ElementTree as ET from typing import Optional from .entry import Entry from .util import escape_text_for_xml class RepeatEntry(Entry): """ Entry type for scripts that are executed on every update. Attributes: script: The script/command to execute stdout: Captured standard output from most recent execution stderr: Captured standard error from most recent execution exit_code: Process exit code from most recent execution """ def __init__(self, script: str, id: str, timestamp: datetime): """ Initialize a new repeat entry. Args: script: The script/command to execute id: Unique identifier for this entry timestamp: Creation timestamp for this entry """ super().__init__(id, timestamp) self.script = script self.stdout = "" self.stderr = "" self.exit_code: Optional[int] = None def update(self) -> None: """ Execute the script and update the output. Captures stdout, stderr and exit code from each execution. """ try: # Run script and capture output process = subprocess.run( self.script, shell=True, capture_output=True, text=True ) # Store results self.stdout = process.stdout self.stderr = process.stderr self.exit_code = process.returncode except subprocess.SubprocessError as e: # Handle subprocess errors by capturing the error message self.stdout = "" self.stderr = str(e) self.exit_code = -1 except Exception as e: # Handle any other errors self.stdout = "" self.stderr = f"Error executing script: {str(e)}" self.exit_code = -1 def generate_context(self) -> ET.Element: """ Generate an XML Element representing this repeat entry. Returns: ET.Element: XML element containing the entry's data """ # Create root element element = ET.Element("repeat", { "id": self.id, "exit_code": str(self.exit_code) if self.exit_code is not None else "-1" }) # Add script as CDATA or escaped text element.text = escape_text_for_xml(self.script) # Add stdout element stdout_elem = ET.SubElement(element, "stdout") stdout_elem.text = escape_text_for_xml(self.stdout) # Add stderr element stderr_elem = ET.SubElement(element, "stderr") stderr_elem.text = escape_text_for_xml(self.stderr) return element