from pathlib import Path import yaml from utils.docker.manager import find_docker_compose def _get_service_port(mapping: str) -> int | None: match mapping.split(":"): case [""]: return None case [port] | [port, _]: return int(port) case ["localhost" | "127.0.0.1", _, _]: return None case [_, port, _]: return int(port) case _: return None def _replace_port_in_mapping(mapping: str, port_from: int, port_to: int) -> str: parts = str(mapping).split(":") match parts: case [_]: # "8080" -> "9090" return str(port_to) case [_, container_port]: # "8080:80" -> "9090:80" return f"{port_to}:{container_port}" case [ip, _, container_port]: # "127.0.0.1:8080:80" -> "127.0.0.1:9090:80" return f"{ip}:{port_to}:{container_port}" case _: return str(port_to) def _get_port_index(mappings: list[str], port: int) -> int | None: for i, mapping in enumerate(mappings): if _get_service_port(mapping) == port: return i return None def change_port( folder: Path, service_name: str, port_from: int, port_to: int, ): docker_compose, filename = find_docker_compose(folder) if not docker_compose or not docker_compose.get('services'): return compose_path = folder / filename backup_compose_path = folder / filename.replace(".yml", ".bak.yml") compose_path.copy(backup_compose_path) for service, config in docker_compose["services"].items(): if service != service_name: continue idx = _get_port_index(config["ports"], port_from) if idx is None: return config["ports"][idx] = _replace_port_in_mapping(config["ports"][idx], port_from, port_to) compose_path.write_text(yaml.dump(docker_compose, default_flow_style=False)) # TODO: run docker compose commands