from pathlib import Path import yaml from integrations.docker.compose import find_docker_compose, run_docker_command from integrations.docker.ports import _get_port_index, _replace_port_in_mapping def _backup_path_for(compose_path: Path) -> Path: if compose_path.suffix in {".yml", ".yaml"}: return compose_path.with_name(f"{compose_path.stem}.bak{compose_path.suffix}") return compose_path.with_name(f"{compose_path.name}.bak") async def change_port( service_name: str, folder: Path, port_from: int, port_to: int, host_to: str | None = None, rewrite_host: bool = False, ) -> bool: compose_data = find_docker_compose(folder) if compose_data is None: return False docker_compose, compose_path = compose_data compose_services = docker_compose.get("services") or {} if not compose_services: return False service_config = compose_services.get(service_name) if not isinstance(service_config, dict): return False mappings = service_config.get("ports") if not isinstance(mappings, list): return False idx = _get_port_index(mappings, port_from) if idx is None: return False mappings[idx] = _replace_port_in_mapping( mappings[idx], port_from, port_to, host_to=host_to, rewrite_host=rewrite_host, ) backup_path = _backup_path_for(compose_path) original_text = compose_path.read_text() backup_path.write_text(compose_path.read_text()) compose_path.write_text( yaml.dump(docker_compose, default_flow_style=False, sort_keys=False) ) result = await run_docker_command( compose_path, ["up", "-d", service_name], ) if result is None or result.get("status") != "success": compose_path.write_text(original_text) return False return True