diff --git a/run_functions.py b/run_functions.py index be1459f..4168f5d 100644 --- a/run_functions.py +++ b/run_functions.py @@ -5,6 +5,8 @@ import numpy as np from datetime import datetime, timedelta import multiprocessing +import json +from pathlib import Path from PySide2 import QtCore, QtGui, QtWidgets from PySide2.QtCore import Qt, QObject, QUrl @@ -250,25 +252,92 @@ def run(self): self.process_steps = "pulling" # Collect the output of the container and update the GUI self.total_layers = {} - for item in self.docker_client.api.pull(self.main_gui.cfg.settings['biapy_container_name'], stream=True, decode=True): - self.main_gui.logger.info(item) - if item["status"] == 'Pulling fs layer': - self.total_layers[item["id"]+"_download"] = 0 - self.total_layers[item["id"]+"_extract"] = 0 - elif item["status"] == "Downloading": - self.total_layers[item["id"]+"_download"] = item["progressDetail"]['current']/item["progressDetail"]['total'] - elif item["status"] == "Extracting": - self.total_layers[item["id"]+"_extract"] = item["progressDetail"]['current']/item["progressDetail"]['total'] - elif item["status"] == "Pull complete": - self.total_layers[item["id"]+"_download"] = 1 - self.total_layers[item["id"]+"_extract"] = 1 - - if self.break_pulling: - self.main_gui.logger.info("Stopping pulling process . . .") - return - # Update GUI - steps = np.sum([int(float(x)*10) for x in self.total_layers.values()]) - self.update_pulling_progress_signal.emit(steps) + problem_attempts = 0 + json_orig_data = None + while problem_attempts < 4: + try: + self.main_gui.logger.info("Pulling container . . .") + self.docker_client = docker.from_env() # Necessary + for item in self.docker_client.api.pull(self.main_gui.cfg.settings['biapy_container_name'], stream=True, decode=True): + self.main_gui.logger.info(item) + if item["status"] == 'Pulling fs layer': + self.total_layers[item["id"]+"_download"] = 0 + self.total_layers[item["id"]+"_extract"] = 0 + elif item["status"] == "Downloading": + self.total_layers[item["id"]+"_download"] = item["progressDetail"]['current']/item["progressDetail"]['total'] + elif item["status"] == "Extracting": + self.total_layers[item["id"]+"_extract"] = item["progressDetail"]['current']/item["progressDetail"]['total'] + elif item["status"] == "Pull complete": + self.total_layers[item["id"]+"_download"] = 1 + self.total_layers[item["id"]+"_extract"] = 1 + + if self.break_pulling: + self.main_gui.logger.info("Stopping pulling process . . .") + return + # Update GUI + steps = np.sum([int(float(x)*10) for x in self.total_layers.values()]) + self.update_pulling_progress_signal.emit(steps) + except Exception as e: + problem_attempts += 1 + self.main_gui.logger.error(f"Error pulling the container: {e}") + self.main_gui.logger.info(f"Trying to modify ~/.docker/config.json - (attempt {problem_attempts})") + + # Attempt 1: trying to change the values of "credsStore" and some possible typos as documented in + # the issue: https://github.com/docker/for-mac/issues/3785#issuecomment-518328553 + if problem_attempts == 1: + try: + with open(Path.home() / ".docker" / "config.json", "r") as jsonFile: + data = json.load(jsonFile) + json_orig_data = data.copy() + + # Possible typo + if "credSstore" in data: + val = data["credSstore"] + del data["credSstore"] + data["credsStore"] = val + + # Change credsStore value + if "credsStore" in data: + val = data["credsStore"] + data["credsStore"] = "osxkeychain" if "desktop" in val else "desktop" + + with open(Path.home() / ".docker" / "config.json", "w") as jsonFile: + json.dump(data, jsonFile, indent=4) + except Exception as e: + self.main_gui.logger.error(f"Error modifying ~/.docker/config.json file (attempt 1): {e}") + + # Attempt 2: remove "credsStore" key + elif problem_attempts == 2: + try: + with open(Path.home() / ".docker" / "config.json", "r") as jsonFile: + data = json.load(jsonFile) + + # Delete credsStore directly + if "credsStore" in data: + del data["credsStore"] + + with open(Path.home() / ".docker" / "config.json", "w") as jsonFile: + json.dump(data, jsonFile, indent=4) + + except Exception as e: + self.main_gui.logger.error(f"Error modifying ~/.docker/config.json file (attempt 2): {e}") + + # Attempt 3: rename the file + else: + try: + os.rename(Path.home() / ".docker" / "config.json", Path.home() / ".docker" / "config.json.backup") + except Exception as e: + self.main_gui.logger.error(f"Error modifying ~/.docker/config.json file (attempt 3): {e}") + else: + self.main_gui.logger.info(f"No errors pulling, continuing . . .") + problem_attempts = 10 # break the loop + + # Revert configuration ~/.docker/config.json configuration + if json_orig_data is not None: + if os.path.exists(Path.home() / ".docker" / "config.json.backup"): + os.rename(Path.home() / ".docker" / "config.json.backup", Path.home() / ".docker" / "config.json") + with open(Path.home() / ".docker" / "config.json", "w") as jsonFile: + json.dump(json_orig_data, jsonFile, indent=4) self.update_pulling_signal.emit(1) diff --git a/settings.py b/settings.py index d5c18d3..d0e75e9 100644 --- a/settings.py +++ b/settings.py @@ -32,7 +32,7 @@ def init_default_settings(self): # BiaPy self.settings['biapy_code_version'] = "v3.4.4" self.settings['biapy_code_github'] = "https://github.com/BiaPyX/BiaPy" - self.settings['biapy_gui_version'] = "v1.0.7" + self.settings['biapy_gui_version'] = "v1.0.8" self.settings['biapy_gui_github'] = "https://github.com/BiaPyX/BiaPy-GUI" self.settings['biapy_container_basename'] = "biapyx/biapy" self.settings['biapy_container_name'] = self.settings['biapy_container_basename']+":latest-"+str(self.settings['CUDA_version'][-1])