config_states.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. """
  2. Supports saving and restoring webui and extensions from a known working set of commits
  3. """
  4. import os
  5. import json
  6. import time
  7. import tqdm
  8. from datetime import datetime
  9. from collections import OrderedDict
  10. import git
  11. from modules import shared, extensions, errors
  12. from modules.paths_internal import script_path, config_states_dir
  13. all_config_states = OrderedDict()
  14. def list_config_states():
  15. global all_config_states
  16. all_config_states.clear()
  17. os.makedirs(config_states_dir, exist_ok=True)
  18. config_states = []
  19. for filename in os.listdir(config_states_dir):
  20. if filename.endswith(".json"):
  21. path = os.path.join(config_states_dir, filename)
  22. with open(path, "r", encoding="utf-8") as f:
  23. j = json.load(f)
  24. j["filepath"] = path
  25. config_states.append(j)
  26. config_states = sorted(config_states, key=lambda cs: cs["created_at"], reverse=True)
  27. for cs in config_states:
  28. timestamp = time.asctime(time.gmtime(cs["created_at"]))
  29. name = cs.get("name", "Config")
  30. full_name = f"{name}: {timestamp}"
  31. all_config_states[full_name] = cs
  32. return all_config_states
  33. def get_webui_config():
  34. webui_repo = None
  35. try:
  36. if os.path.exists(os.path.join(script_path, ".git")):
  37. webui_repo = git.Repo(script_path)
  38. except Exception:
  39. errors.report(f"Error reading webui git info from {script_path}", exc_info=True)
  40. webui_remote = None
  41. webui_commit_hash = None
  42. webui_commit_date = None
  43. webui_branch = None
  44. if webui_repo and not webui_repo.bare:
  45. try:
  46. webui_remote = next(webui_repo.remote().urls, None)
  47. head = webui_repo.head.commit
  48. webui_commit_date = webui_repo.head.commit.committed_date
  49. webui_commit_hash = head.hexsha
  50. webui_branch = webui_repo.active_branch.name
  51. except Exception:
  52. webui_remote = None
  53. return {
  54. "remote": webui_remote,
  55. "commit_hash": webui_commit_hash,
  56. "commit_date": webui_commit_date,
  57. "branch": webui_branch,
  58. }
  59. def get_extension_config():
  60. ext_config = {}
  61. for ext in extensions.extensions:
  62. ext.read_info_from_repo()
  63. entry = {
  64. "name": ext.name,
  65. "path": ext.path,
  66. "enabled": ext.enabled,
  67. "is_builtin": ext.is_builtin,
  68. "remote": ext.remote,
  69. "commit_hash": ext.commit_hash,
  70. "commit_date": ext.commit_date,
  71. "branch": ext.branch,
  72. "have_info_from_repo": ext.have_info_from_repo
  73. }
  74. ext_config[ext.name] = entry
  75. return ext_config
  76. def get_config():
  77. creation_time = datetime.now().timestamp()
  78. webui_config = get_webui_config()
  79. ext_config = get_extension_config()
  80. return {
  81. "created_at": creation_time,
  82. "webui": webui_config,
  83. "extensions": ext_config
  84. }
  85. def restore_webui_config(config):
  86. print("* Restoring webui state...")
  87. if "webui" not in config:
  88. print("Error: No webui data saved to config")
  89. return
  90. webui_config = config["webui"]
  91. if "commit_hash" not in webui_config:
  92. print("Error: No commit saved to webui config")
  93. return
  94. webui_commit_hash = webui_config.get("commit_hash", None)
  95. webui_repo = None
  96. try:
  97. if os.path.exists(os.path.join(script_path, ".git")):
  98. webui_repo = git.Repo(script_path)
  99. except Exception:
  100. errors.report(f"Error reading webui git info from {script_path}", exc_info=True)
  101. return
  102. try:
  103. webui_repo.git.fetch(all=True)
  104. webui_repo.git.reset(webui_commit_hash, hard=True)
  105. print(f"* Restored webui to commit {webui_commit_hash}.")
  106. except Exception:
  107. errors.report(f"Error restoring webui to commit{webui_commit_hash}")
  108. def restore_extension_config(config):
  109. print("* Restoring extension state...")
  110. if "extensions" not in config:
  111. print("Error: No extension data saved to config")
  112. return
  113. ext_config = config["extensions"]
  114. results = []
  115. disabled = []
  116. for ext in tqdm.tqdm(extensions.extensions):
  117. if ext.is_builtin:
  118. continue
  119. ext.read_info_from_repo()
  120. current_commit = ext.commit_hash
  121. if ext.name not in ext_config:
  122. ext.disabled = True
  123. disabled.append(ext.name)
  124. results.append((ext, current_commit[:8], False, "Saved extension state not found in config, marking as disabled"))
  125. continue
  126. entry = ext_config[ext.name]
  127. if "commit_hash" in entry and entry["commit_hash"]:
  128. try:
  129. ext.fetch_and_reset_hard(entry["commit_hash"])
  130. ext.read_info_from_repo()
  131. if current_commit != entry["commit_hash"]:
  132. results.append((ext, current_commit[:8], True, entry["commit_hash"][:8]))
  133. except Exception as ex:
  134. results.append((ext, current_commit[:8], False, ex))
  135. else:
  136. results.append((ext, current_commit[:8], False, "No commit hash found in config"))
  137. if not entry.get("enabled", False):
  138. ext.disabled = True
  139. disabled.append(ext.name)
  140. else:
  141. ext.disabled = False
  142. shared.opts.disabled_extensions = disabled
  143. shared.opts.save(shared.config_filename)
  144. print("* Finished restoring extensions. Results:")
  145. for ext, prev_commit, success, result in results:
  146. if success:
  147. print(f" + {ext.name}: {prev_commit} -> {result}")
  148. else:
  149. print(f" ! {ext.name}: FAILURE ({result})")