|
5 | 5 | import numpy as np
|
6 | 6 | from datetime import datetime, timedelta
|
7 | 7 | import multiprocessing
|
| 8 | +import json |
| 9 | +from pathlib import Path |
8 | 10 |
|
9 | 11 | from PySide2 import QtCore, QtGui, QtWidgets
|
10 | 12 | from PySide2.QtCore import Qt, QObject, QUrl
|
@@ -250,25 +252,92 @@ def run(self):
|
250 | 252 | self.process_steps = "pulling"
|
251 | 253 | # Collect the output of the container and update the GUI
|
252 | 254 | self.total_layers = {}
|
253 |
| - for item in self.docker_client.api.pull(self.main_gui.cfg.settings['biapy_container_name'], stream=True, decode=True): |
254 |
| - self.main_gui.logger.info(item) |
255 |
| - if item["status"] == 'Pulling fs layer': |
256 |
| - self.total_layers[item["id"]+"_download"] = 0 |
257 |
| - self.total_layers[item["id"]+"_extract"] = 0 |
258 |
| - elif item["status"] == "Downloading": |
259 |
| - self.total_layers[item["id"]+"_download"] = item["progressDetail"]['current']/item["progressDetail"]['total'] |
260 |
| - elif item["status"] == "Extracting": |
261 |
| - self.total_layers[item["id"]+"_extract"] = item["progressDetail"]['current']/item["progressDetail"]['total'] |
262 |
| - elif item["status"] == "Pull complete": |
263 |
| - self.total_layers[item["id"]+"_download"] = 1 |
264 |
| - self.total_layers[item["id"]+"_extract"] = 1 |
265 |
| - |
266 |
| - if self.break_pulling: |
267 |
| - self.main_gui.logger.info("Stopping pulling process . . .") |
268 |
| - return |
269 |
| - # Update GUI |
270 |
| - steps = np.sum([int(float(x)*10) for x in self.total_layers.values()]) |
271 |
| - self.update_pulling_progress_signal.emit(steps) |
| 255 | + problem_attempts = 0 |
| 256 | + json_orig_data = None |
| 257 | + while problem_attempts < 4: |
| 258 | + try: |
| 259 | + self.main_gui.logger.info("Pulling container . . .") |
| 260 | + self.docker_client = docker.from_env() # Necessary |
| 261 | + for item in self.docker_client.api.pull(self.main_gui.cfg.settings['biapy_container_name'], stream=True, decode=True): |
| 262 | + self.main_gui.logger.info(item) |
| 263 | + if item["status"] == 'Pulling fs layer': |
| 264 | + self.total_layers[item["id"]+"_download"] = 0 |
| 265 | + self.total_layers[item["id"]+"_extract"] = 0 |
| 266 | + elif item["status"] == "Downloading": |
| 267 | + self.total_layers[item["id"]+"_download"] = item["progressDetail"]['current']/item["progressDetail"]['total'] |
| 268 | + elif item["status"] == "Extracting": |
| 269 | + self.total_layers[item["id"]+"_extract"] = item["progressDetail"]['current']/item["progressDetail"]['total'] |
| 270 | + elif item["status"] == "Pull complete": |
| 271 | + self.total_layers[item["id"]+"_download"] = 1 |
| 272 | + self.total_layers[item["id"]+"_extract"] = 1 |
| 273 | + |
| 274 | + if self.break_pulling: |
| 275 | + self.main_gui.logger.info("Stopping pulling process . . .") |
| 276 | + return |
| 277 | + # Update GUI |
| 278 | + steps = np.sum([int(float(x)*10) for x in self.total_layers.values()]) |
| 279 | + self.update_pulling_progress_signal.emit(steps) |
| 280 | + except Exception as e: |
| 281 | + problem_attempts += 1 |
| 282 | + self.main_gui.logger.error(f"Error pulling the container: {e}") |
| 283 | + self.main_gui.logger.info(f"Trying to modify ~/.docker/config.json - (attempt {problem_attempts})") |
| 284 | + |
| 285 | + # Attempt 1: trying to change the values of "credsStore" and some possible typos as documented in |
| 286 | + # the issue: https://github.com/docker/for-mac/issues/3785#issuecomment-518328553 |
| 287 | + if problem_attempts == 1: |
| 288 | + try: |
| 289 | + with open(Path.home() / ".docker" / "config.json", "r") as jsonFile: |
| 290 | + data = json.load(jsonFile) |
| 291 | + json_orig_data = data.copy() |
| 292 | + |
| 293 | + # Possible typo |
| 294 | + if "credSstore" in data: |
| 295 | + val = data["credSstore"] |
| 296 | + del data["credSstore"] |
| 297 | + data["credsStore"] = val |
| 298 | + |
| 299 | + # Change credsStore value |
| 300 | + if "credsStore" in data: |
| 301 | + val = data["credsStore"] |
| 302 | + data["credsStore"] = "osxkeychain" if "desktop" in val else "desktop" |
| 303 | + |
| 304 | + with open(Path.home() / ".docker" / "config.json", "w") as jsonFile: |
| 305 | + json.dump(data, jsonFile, indent=4) |
| 306 | + except Exception as e: |
| 307 | + self.main_gui.logger.error(f"Error modifying ~/.docker/config.json file (attempt 1): {e}") |
| 308 | + |
| 309 | + # Attempt 2: remove "credsStore" key |
| 310 | + elif problem_attempts == 2: |
| 311 | + try: |
| 312 | + with open(Path.home() / ".docker" / "config.json", "r") as jsonFile: |
| 313 | + data = json.load(jsonFile) |
| 314 | + |
| 315 | + # Delete credsStore directly |
| 316 | + if "credsStore" in data: |
| 317 | + del data["credsStore"] |
| 318 | + |
| 319 | + with open(Path.home() / ".docker" / "config.json", "w") as jsonFile: |
| 320 | + json.dump(data, jsonFile, indent=4) |
| 321 | + |
| 322 | + except Exception as e: |
| 323 | + self.main_gui.logger.error(f"Error modifying ~/.docker/config.json file (attempt 2): {e}") |
| 324 | + |
| 325 | + # Attempt 3: rename the file |
| 326 | + else: |
| 327 | + try: |
| 328 | + os.rename(Path.home() / ".docker" / "config.json", Path.home() / ".docker" / "config.json.backup") |
| 329 | + except Exception as e: |
| 330 | + self.main_gui.logger.error(f"Error modifying ~/.docker/config.json file (attempt 3): {e}") |
| 331 | + else: |
| 332 | + self.main_gui.logger.info(f"No errors pulling, continuing . . .") |
| 333 | + problem_attempts = 10 # break the loop |
| 334 | + |
| 335 | + # Revert configuration ~/.docker/config.json configuration |
| 336 | + if json_orig_data is not None: |
| 337 | + if os.path.exists(Path.home() / ".docker" / "config.json.backup"): |
| 338 | + os.rename(Path.home() / ".docker" / "config.json.backup", Path.home() / ".docker" / "config.json") |
| 339 | + with open(Path.home() / ".docker" / "config.json", "w") as jsonFile: |
| 340 | + json.dump(json_orig_data, jsonFile, indent=4) |
272 | 341 |
|
273 | 342 | self.update_pulling_signal.emit(1)
|
274 | 343 |
|
|
0 commit comments