update_manager.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import os
  2. import subprocess
  3. import logging
  4. # Configure logging
  5. logger = logging.getLogger(__name__)
  6. def check_git_updates():
  7. """Check for available Git updates."""
  8. try:
  9. logger.debug("Checking for Git updates")
  10. subprocess.run(["git", "fetch", "--tags", "--force"], check=True)
  11. latest_remote_tag = subprocess.check_output(
  12. ["git", "describe", "--tags", "--abbrev=0", "origin/main"]
  13. ).strip().decode()
  14. latest_local_tag = subprocess.check_output(
  15. ["git", "describe", "--tags", "--abbrev=0"]
  16. ).strip().decode()
  17. tag_behind_count = 0
  18. if latest_local_tag != latest_remote_tag:
  19. tags = subprocess.check_output(
  20. ["git", "tag", "--merged", "origin/main"], text=True
  21. ).splitlines()
  22. found_local = False
  23. for tag in tags:
  24. if tag == latest_local_tag:
  25. found_local = True
  26. elif found_local:
  27. tag_behind_count += 1
  28. if tag == latest_remote_tag:
  29. break
  30. updates_available = latest_remote_tag != latest_local_tag
  31. logger.info(f"Updates available: {updates_available}, {tag_behind_count} versions behind")
  32. return {
  33. "updates_available": updates_available,
  34. "tag_behind_count": tag_behind_count,
  35. "latest_remote_tag": latest_remote_tag,
  36. "latest_local_tag": latest_local_tag,
  37. }
  38. except subprocess.CalledProcessError as e:
  39. logger.error(f"Error checking Git updates: {e}")
  40. return {
  41. "updates_available": False,
  42. "tag_behind_count": 0,
  43. "latest_remote_tag": None,
  44. "latest_local_tag": None,
  45. }
  46. def update_software():
  47. """Update the software to the latest version."""
  48. error_log = []
  49. logger.info("Starting software update process")
  50. def run_command(command, error_message):
  51. try:
  52. logger.debug(f"Running command: {' '.join(command)}")
  53. subprocess.run(command, check=True)
  54. except subprocess.CalledProcessError as e:
  55. logger.error(f"{error_message}: {e}")
  56. error_log.append(error_message)
  57. try:
  58. subprocess.run(["git", "fetch", "--tags"], check=True)
  59. latest_remote_tag = subprocess.check_output(
  60. ["git", "describe", "--tags", "--abbrev=0", "origin/main"]
  61. ).strip().decode()
  62. logger.info(f"Latest remote tag: {latest_remote_tag}")
  63. except subprocess.CalledProcessError as e:
  64. error_msg = f"Failed to fetch tags or get latest remote tag: {e}"
  65. logger.error(error_msg)
  66. error_log.append(error_msg)
  67. return False, error_msg, error_log
  68. run_command(["git", "checkout", latest_remote_tag, '--force'], f"Failed to checkout version {latest_remote_tag}")
  69. # Get host project directory for docker compose commands
  70. # When running inside a container, we need to use the host path for docker compose
  71. host_project_dir = os.environ.get("HOST_PROJECT_DIR")
  72. if host_project_dir:
  73. compose_cmd = ["docker", "compose", "-f", f"{host_project_dir}/docker-compose.yml"]
  74. logger.info(f"Using host project directory: {host_project_dir}")
  75. else:
  76. compose_cmd = ["docker", "compose"]
  77. logger.warning("HOST_PROJECT_DIR not set, using default docker compose")
  78. run_command(compose_cmd + ["pull"], "Failed to fetch Docker containers")
  79. run_command(compose_cmd + ["up", "-d"], "Failed to restart Docker containers")
  80. update_status = check_git_updates()
  81. if (
  82. update_status["updates_available"] is False
  83. and update_status["latest_local_tag"] == update_status["latest_remote_tag"]
  84. ):
  85. logger.info("Software update completed successfully")
  86. return True, None, None
  87. else:
  88. logger.error("Software update incomplete")
  89. return False, "Update incomplete", error_log