diff --git a/cli/src/core/models.py b/cli/src/core/models.py index 6f00e92..cad5637 100644 --- a/cli/src/core/models.py +++ b/cli/src/core/models.py @@ -1,4 +1,5 @@ import re +import xml.etree.ElementTree as ET from typing import ClassVar import yaml @@ -17,6 +18,8 @@ MASTER_HLA_NAMES_FILENAME = MASTER_SERVICE_CONFIG_DIR / "hla_names.yml" IOCS_OVERVIEW_FILENAME = REPO_ROOT / "docs" / "ioc" / "ioc_overview.md" +SERVICE_MANAGER_UI_FILENAME = REPO_ROOT / "qt" / "A_BD_ServiceManager.ui" + class Service(BaseModel): name: str @@ -127,3 +130,129 @@ class IocsOverview(BaseModel): def write_to_file(self): with open(self.config_path, "w") as f: f.write(self.content) + + +# TODO: maybe separate models into their own files +class ServiceManagerUI(BaseModel): + config_path: ClassVar[str] = str(SERVICE_MANAGER_UI_FILENAME) + + tree: ET.ElementTree[ET.Element[str]] + + @classmethod + def read_from_file(cls) -> "ServiceManagerUI": + tree = ET.parse(cls.config_path) + return ServiceManagerUI(tree=tree) + + def update_xml(self, service: Service, ui_name: str, panelcmd: str) -> None: + num_macro_elements = self._update_macro(service=service, ui_name=ui_name, panelcmd=panelcmd) + self._update_heights(num_macro_elemnts=num_macro_elements) + + def _update_macro(self, service: Service, ui_name: str, panelcmd: str) -> int: + new_macro_element = _ServiceManagerUIMacroElement( + service_name_upper=service.name_upper, ui_name=ui_name, panelcmd=panelcmd + ) + + num_macro_elements = None + root = self.tree.getroot() + for widget in root.iter("widget"): + if widget.get("class") == "caInclude" and widget.get("name") == "cainclude": + for prop in widget.findall("property"): + # Update the macro data string + if prop.get("name") == "macro": + string_elem = prop.find("string") + if string_elem is not None and string_elem.text is not None: + string_elem.text = ( + string_elem.text + ";" + new_macro_element.to_string() + ) + # Dynamically update the count match so caInclude renders all rows + if prop.get("name") == "numberOfItems": + number_elem = prop.find("number") + assert number_elem is not None and number_elem.text is not None + num_macro_elements = int(number_elem.text) + number_elem.text = str(num_macro_elements + 1) + + assert num_macro_elements is not None, "could not find number of macro elements in xml" + return num_macro_elements + + def _update_heights(self, num_macro_elemnts: int) -> None: + """ + There are 3 heights to be adjusted: + + 1. Main window + 2. Tab widget + 3. Widget inside the tab widget + """ + root = self.tree.getroot() + + ca_include_height = self._get_height_cainclude() + height_to_add = ca_include_height / num_macro_elemnts * (num_macro_elemnts + 1) + + # 1. Main window + mainwindow = root.find(".//widget[@class='QMainWindow']") + if mainwindow is not None: + rect = mainwindow.find("./property[@name='geometry']/rect") + assert rect is not None + height = rect.find("height") + assert height is not None and height.text is not None + height.text = str(int(height.text) + height_to_add) + + for widget in root.iter("widget"): + widget_name = widget.get("name") + + # 2. Tab widget + if widget_name == "tabWidget": + rect = widget.find("./property[@name='geometry']/rect") + assert rect is not None + height = rect.find("height") + assert height is not None and height.text is not None + height.text = str(int(height.text) + height_to_add) + + # 3. Widget inside the tab widget + elif widget_name == "cainclude": + rect = widget.find("./property[@name='geometry']/rect") + assert rect is not None + height = rect.find("height") + assert height is not None and height.text is not None + height.text = str(int(height.text) + height_to_add) + + def _get_height_cainclude(self) -> int: + """ + Get the height of the area that includes all the services + """ + root = self.tree.getroot() + cainclude_height = None + + for widget in root.iter("widget"): + widget_name = widget.get("name") + + # Target the caInclude Widget of Required Services + if widget_name == "cainclude": + rect = widget.find("./property[@name='geometry']/rect") + assert rect is not None + height = rect.find("height") + assert height is not None and height.text is not None + cainclude_height = int(height.text) + + assert cainclude_height, "could not get height of cainclude widget" + return cainclude_height + + def write_to_file(self) -> None: + self.tree.write(self.config_path, encoding="utf-8", xml_declaration=True) + + +class _ServiceManagerUIMacroElement(BaseModel): + service_name_upper: str + ui_name: str + panel: int = 1 + svc_exist: int = 1 + panelcmd: str + + def to_string(self) -> str: + return ( + f"IOC=AGEBD-CPCL-{self.service_name_upper}," + f"service={self.service_name_upper}," + f"name={self.ui_name}," + f"panel={self.panel}," + f"svc_exist={self.svc_exist}," + f"panelcmd={self.panelcmd}" + ) diff --git a/cli/src/core/service_creator.py b/cli/src/core/service_creator.py index 835ed1a..bbb9040 100644 --- a/cli/src/core/service_creator.py +++ b/cli/src/core/service_creator.py @@ -14,7 +14,7 @@ from core.git import ( git_push_changes, switch_branch, ) -from core.models import IocsOverview, MasterHLANames, Service, ServiceRegistry +from core.models import IocsOverview, MasterHLANames, Service, ServiceManagerUI, ServiceRegistry from core.utils import get_git_root logger = logging.getLogger(__name__) @@ -30,9 +30,11 @@ MASTER_IOC_SUBS_FILE = MASTER_SERVICE_DIR / "ioc" / "AGEBD-CPCL-MASTER_main.subs class ServiceCreator: - def __init__(self, user: str, ioc_description: str) -> None: + def __init__(self, user: str, ioc_description: str, ui_name: str, panelcmd: str) -> None: self.user = user self.ioc_description = ioc_description + self.ui_name = ui_name + self.panelcmd = panelcmd def add_service(self, name: str): repo = git.Repo(REPO_ROOT) @@ -49,45 +51,50 @@ class ServiceCreator: iocs_overview_old = IocsOverview.read_from_file() iocs_overview = IocsOverview.read_from_file() iocs_overview.add_ioc(service, description=self.ioc_description) + service_manager_old = ServiceManagerUI.read_from_file() + service_manager = ServiceManagerUI.read_from_file() + service_manager.update_xml(service=service, ui_name=self.ui_name, panelcmd=self.panelcmd) - branch_name = f"feature/add-service-{service.dir_name}" - delete_local_branch(repo, branch_name) - switch_branch(repo, branch_name) + # branch_name = f"feature/add-service-{service.dir_name}" + # delete_local_branch(repo, branch_name) + # switch_branch(repo, branch_name) try: - self._render_new_service_templates( - service=service, - user=self.user, - ) - self._generate_uv_lock(service=service) - registry.write_to_config() - hla_names.write_to_config() - iocs_overview.write_to_file() + # self._render_new_service_templates( + # service=service, + # user=self.user, + # ) + # self._generate_uv_lock(service=service) + # registry.write_to_config() + # hla_names.write_to_config() + # iocs_overview.write_to_file() + service_manager.write_to_file() - self._append_to_master_ioc_subs( - service_name=service.name_upper, - starton="0", # TODO: ok? - autooff="0", # TODO: ok? - ) + # self._append_to_master_ioc_subs( + # service_name=service.name_upper, + # starton="0", # TODO: ok? + # autooff="0", # TODO: ok? + # ) # TODO: can't push if branch already exists in remote - git_push_changes( - repo=repo, - branch_name=branch_name, - service_dir_rel_path=f"services/{service.dir_name}/current", - registry_file_rel_path="config/services_registry.yml", - # TODO: maybe assert/get correct master service dirname from registry - master_hla_names_rel_path="services/master/current/app/config/hla_names.yml", - master_ioc_subs_rel_path="services/master/current/ioc/AGEBD-CPCL-MASTER_main.subs", - iocs_overview_rel_path="docs/ioc/ioc_overview.md", - commit_msg=f"feature: add new service {service.name_lower}", - ) - switch_branch(repo, original_branch) + # git_push_changes( + # repo=repo, + # branch_name=branch_name, + # service_dir_rel_path=f"services/{service.dir_name}/current", + # registry_file_rel_path="config/services_registry.yml", + # # TODO: maybe assert/get correct master service dirname from registry + # master_hla_names_rel_path="services/master/current/app/config/hla_names.yml", + # master_ioc_subs_rel_path="services/master/current/ioc/AGEBD-CPCL-MASTER_main.subs", + # iocs_overview_rel_path="docs/ioc/ioc_overview.md", + # commit_msg=f"feature: add new service {service.name_lower}", + # ) + # switch_branch(repo, original_branch) except Exception as e: shutil.rmtree(Path(SERVICE_DEST_DIR / service.dir_name), ignore_errors=True) registry_old.write_to_config() hla_names_old.write_to_config() iocs_overview_old.write_to_file() + service_manager_old.write_to_file() switch_branch(repo, original_branch) raise e diff --git a/cli/src/service.py b/cli/src/service.py index 96da23e..ff60fc7 100644 --- a/cli/src/service.py +++ b/cli/src/service.py @@ -16,12 +16,21 @@ def add( ioc_description: str = typer.Option( ..., "--ioc-description", "-d", help="See /docs/ioc/ioc_overview.md for examples" ), + ui_name: str = typer.Option( + ..., "--ui-name", help="See /qt/A_BD_ServiceManager.ui for examples" + ), + panelcmd: str = typer.Option( + ..., "--panelcmd", "-p", help="See /qt/A_BD_ServiceManager.ui for examples" + ), ): init_logging() - ServiceCreator( + service_creator = ServiceCreator( user=user, # TODO: read from 'whoami'? ioc_description=ioc_description, - ).add_service(name=name) + ui_name=ui_name, # TODO: make this standard? + panelcmd=panelcmd, # TODO: make this standard? + ) + service_creator.add_service(name=name) @service.command()