Spaces:
Sleeping
Sleeping
| # msdl/docker_manager.py | |
| import os | |
| import subprocess | |
| import sys | |
| from functools import lru_cache | |
| import yaml | |
| from msdl.config import PROJECT_ROOT, TEMP_DIR | |
| from msdl.i18n import t | |
| def get_docker_command(): | |
| try: | |
| subprocess.run( | |
| ["docker", "compose", "version"], check=True, capture_output=True | |
| ) | |
| return ["docker", "compose"] | |
| except subprocess.CalledProcessError: | |
| try: | |
| subprocess.run( | |
| ["docker-compose", "--version"], check=True, capture_output=True | |
| ) | |
| return ["docker-compose"] | |
| except subprocess.CalledProcessError: | |
| print(t("DOCKER_COMPOSE_NOT_FOUND")) | |
| sys.exit(1) | |
| def check_docker_install(): | |
| try: | |
| subprocess.run(["docker", "--version"], check=True, capture_output=True) | |
| docker_compose_cmd = get_docker_command() | |
| subprocess.run( | |
| docker_compose_cmd + ["version"], check=True, capture_output=True | |
| ) | |
| print(t("DOCKER_INSTALLED")) | |
| return True | |
| except subprocess.CalledProcessError as e: | |
| print(t("DOCKER_INSTALL_ERROR", error=str(e))) | |
| return False | |
| except FileNotFoundError: | |
| print(t("DOCKER_NOT_FOUND")) | |
| return False | |
| def stop_and_remove_containers(): | |
| docker_compose_cmd = get_docker_command() | |
| compose_file = os.path.join(TEMP_DIR, "docker-compose.yaml") | |
| # Read the docker-compose.yaml file | |
| try: | |
| with open(compose_file, "r") as file: | |
| compose_config = yaml.safe_load(file) | |
| except Exception as e: | |
| print(t("COMPOSE_FILE_READ_ERROR", error=str(e))) | |
| return | |
| # Get project name and service names | |
| project_name = compose_config.get("name", "mindsearch") | |
| service_names = list(compose_config.get("services", {}).keys()) | |
| # Use only the project name as the container prefix | |
| container_prefix = f"{project_name}_" | |
| try: | |
| # 1. Try to stop containers using the current docker-compose.yaml | |
| subprocess.run( | |
| docker_compose_cmd + ["-f", compose_file, "down", "-v", "--remove-orphans"], | |
| check=True, | |
| ) | |
| except subprocess.CalledProcessError: | |
| print(t("CURRENT_COMPOSE_STOP_FAILED")) | |
| # 2. Attempt to clean up potentially existing containers, regardless of the success of the previous step | |
| try: | |
| # List all containers (including stopped ones) | |
| result = subprocess.run( | |
| ["docker", "ps", "-a", "--format", "{{.Names}}"], | |
| check=True, | |
| capture_output=True, | |
| text=True, | |
| ) | |
| all_containers = result.stdout.splitlines() | |
| # 3. Filter out containers belonging to our project | |
| project_containers = [ | |
| c | |
| for c in all_containers | |
| if c.startswith(container_prefix) | |
| or any(c == f"{project_name}-{service}" for service in service_names) | |
| ] | |
| if project_containers: | |
| # 4. Force stop and remove these containers | |
| for container in project_containers: | |
| try: | |
| subprocess.run(["docker", "stop", container], check=True) | |
| subprocess.run(["docker", "rm", "-f", container], check=True) | |
| print(t("CONTAINER_STOPPED_AND_REMOVED", container=container)) | |
| except subprocess.CalledProcessError as e: | |
| print(t("CONTAINER_STOP_ERROR", container=container, error=str(e))) | |
| # 5. Clean up potentially leftover networks | |
| try: | |
| subprocess.run(["docker", "network", "prune", "-f"], check=True) | |
| print(t("NETWORKS_PRUNED")) | |
| except subprocess.CalledProcessError as e: | |
| print(t("NETWORK_PRUNE_ERROR", error=str(e))) | |
| except subprocess.CalledProcessError as e: | |
| print(t("DOCKER_LIST_ERROR", error=str(e))) | |
| print(t("CONTAINERS_STOPPED_AND_REMOVED")) | |
| def run_docker_compose(): | |
| docker_compose_cmd = get_docker_command() | |
| try: | |
| print(t("STARTING_CONTAINERS_WITH_BUILD")) | |
| subprocess.run( | |
| docker_compose_cmd | |
| + [ | |
| "-f", | |
| os.path.join(TEMP_DIR, "docker-compose.yaml"), | |
| "--env-file", | |
| os.path.join(TEMP_DIR, ".env"), | |
| "up", | |
| "-d", | |
| "--build", | |
| ], | |
| check=True, | |
| ) | |
| print(t("CONTAINERS_STARTED")) | |
| except subprocess.CalledProcessError as e: | |
| print(t("DOCKER_ERROR", error=str(e))) | |
| print(t("DOCKER_OUTPUT")) | |
| print(e.output.decode() if e.output else "No output") | |
| stop_and_remove_containers() | |
| sys.exit(1) | |
| def update_docker_compose_paths(project_root=PROJECT_ROOT): | |
| docker_compose_path = os.path.join(TEMP_DIR, "docker-compose.yaml") | |
| with open(docker_compose_path, "r") as file: | |
| compose_data = yaml.safe_load(file) | |
| for service in compose_data["services"].values(): | |
| if "build" in service: | |
| if "context" in service["build"]: | |
| if service["build"]["context"] == "..": | |
| service["build"]["context"] = project_root | |
| else: | |
| service["build"]["context"] = os.path.join( | |
| project_root, service["build"]["context"] | |
| ) | |
| if "dockerfile" in service["build"]: | |
| dockerfile_name = os.path.basename(service["build"]["dockerfile"]) | |
| service["build"]["dockerfile"] = os.path.join(TEMP_DIR, dockerfile_name) | |
| with open(docker_compose_path, "w") as file: | |
| yaml.dump(compose_data, file) | |
| print(t("PATHS_UPDATED")) | |
| def main(): | |
| if check_docker_install(): | |
| update_docker_compose_paths() | |
| run_docker_compose() | |
| else: | |
| sys.exit(1) | |
| if __name__ == "__main__": | |
| main() | |