# utils.py import time import uuid from constants import ( DOCKER_IMAGE_BASE, DEFAULT_DOCKER_PARAMS, VERSION_SPECIFIC_PARAMS, MACOS_VERSIONS ) # Path to the generated images inside the Docker container CONTAINER_MACOS_IMG_PATH = "/home/arch/OSX-KVM/mac_hdd_ng.img" # The OpenCore.qcow2 path can vary if BOOTDISK env var is used. # The default generated one by the scripts (if not overridden by BOOTDISK) is: CONTAINER_OPENCORE_QCOW2_PATH = "/home/arch/OSX-KVM/OpenCore/OpenCore.qcow2" def get_unique_container_name() -> str: """Generates a unique Docker container name.""" return f"skyscope-osx-vm-{uuid.uuid4().hex[:8]}" def build_docker_command(macos_version_name: str, container_name: str) -> list[str]: """ Builds the docker run command arguments as a list. Args: macos_version_name: The display name of the macOS version (e.g., "Sonoma"). container_name: The unique name for the Docker container. Returns: A list of strings representing the docker command and its arguments. """ if macos_version_name not in MACOS_VERSIONS: raise ValueError(f"Unsupported macOS version: {macos_version_name}") image_tag = MACOS_VERSIONS[macos_version_name] full_image_name = f"{DOCKER_IMAGE_BASE}:{image_tag}" # Removed --rm: we need the container to persist for file extraction final_command_args = ["docker", "run", "-it", "--name", container_name] # Base parameters for the docker command run_params = DEFAULT_DOCKER_PARAMS.copy() # Override/extend with version-specific parameters if macos_version_name in VERSION_SPECIFIC_PARAMS: version_specific = VERSION_SPECIFIC_PARAMS[macos_version_name] # More robustly handle environment variables (-e) # Collect all -e keys from defaults and version-specific default_env_vars = {k.split(" ", 1)[1].split("=")[0]: v for k, v in DEFAULT_DOCKER_PARAMS.items() if k.startswith("-e ")} version_env_vars = {k.split(" ", 1)[1].split("=")[0]: v for k, v in version_specific.items() if k.startswith("-e ")} merged_env_vars = {**default_env_vars, **version_env_vars} # Remove all old -e params from run_params before adding merged ones keys_to_remove_from_run_params = [k_param for k_param in run_params if k_param.startswith("-e ")] for k_rem in keys_to_remove_from_run_params: del run_params[k_rem] # Add merged env vars back with the "-e VAR_NAME" format for keys for env_name, env_val_str in merged_env_vars.items(): run_params[f"-e {env_name}"] = env_val_str # Add other non -e version-specific params for k, v in version_specific.items(): if not k.startswith("-e "): run_params[k] = v # Construct the command list for key, value in run_params.items(): if key.startswith("-e "): # Key is like "-e VARNAME", value is the actual value string like "'data'" or "GENERATE_UNIQUE='true'" env_var_name_from_key = key.split(" ", 1)[1] # e.g. GENERATE_UNIQUE or CPU # If value string itself contains '=', it's likely the full 'VAR=val' form if isinstance(value, str) and '=' in value and value.strip("'").upper().startswith(env_var_name_from_key.upper()): # e.g. value is "GENERATE_UNIQUE='true'" final_env_val = value.strip("'") else: # e.g. value is "'true'" for key "-e GENERATE_UNIQUE" final_env_val = f"{env_var_name_from_key}={value.strip("'")}" final_command_args.extend(["-e", final_env_val]) else: # for --device, -p, -v final_command_args.extend([key, value.strip("'")]) # Strip quotes for safety final_command_args.append(full_image_name) return final_command_args def build_docker_cp_command(container_name_or_id: str, container_path: str, host_path: str) -> list[str]: """Builds the 'docker cp' command.""" return ["docker", "cp", f"{container_name_or_id}:{container_path}", host_path] def build_docker_stop_command(container_name_or_id: str) -> list[str]: """Builds the 'docker stop' command.""" return ["docker", "stop", container_name_or_id] def build_docker_rm_command(container_name_or_id: str) -> list[str]: """Builds the 'docker rm' command.""" return ["docker", "rm", container_name_or_id] if __name__ == '__main__': # Test the functions container_name = get_unique_container_name() print(f"Generated container name: {container_name}") for version_name_key in MACOS_VERSIONS.keys(): print(f"Command for {version_name_key}:") cmd_list = build_docker_command(version_name_key, container_name) print(" ".join(cmd_list)) print("-" * 20) test_container_id = container_name # or an actual ID print(f"CP Main Image: {' '.join(build_docker_cp_command(test_container_id, CONTAINER_MACOS_IMG_PATH, './mac_hdd_ng.img'))}") print(f"CP OpenCore Image: {' '.join(build_docker_cp_command(test_container_id, CONTAINER_OPENCORE_QCOW2_PATH, './OpenCore.qcow2'))}") print(f"Stop Command: {' '.join(build_docker_stop_command(test_container_id))}") print(f"Remove Command: {' '.join(build_docker_rm_command(test_container_id))}") # Test with a non-existent version try: build_docker_command("NonExistentVersion", container_name) except ValueError as e: print(e)