Skip to content

Commit

Permalink
feat: update policy for updating ComfyUI
Browse files Browse the repository at this point in the history
#1552

fixed: comfyui versions should be based on commit date
#1566

fixed: invalid identifying of nightly node packs which has `[email protected]:...` url
fixed: switch comfyui should be based on `master` branch instead of `main` branch
fixed: switch_to_default_branch - more robust switching
refactor: endpoints for policies
  • Loading branch information
ltdrdata committed Feb 19, 2025
1 parent 41172be commit 5dd8ea8
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 56 deletions.
15 changes: 14 additions & 1 deletion git_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,14 +154,27 @@ def switch_to_default_branch(repo):
repo.git.checkout(default_branch)
return True
except:
# try checkout master
# try checkout main if failed
try:
repo.git.checkout(repo.heads.master)
return True
except:
try:
if remote_name is not None:
repo.git.checkout('-b', 'master', f'{remote_name}/master')
return True
except:
pass
try:
repo.git.checkout(repo.heads.main)
return True
except:
try:
if remote_name is not None:
repo.git.checkout('-b', 'main', f'{remote_name}/main')
return True
except:
pass

print("[ComfyUI Manager] Failed to switch to the default branch")
return False
Expand Down
7 changes: 7 additions & 0 deletions glob/git_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,14 @@ def git_url(fullpath):
def normalize_url(url) -> str:
if 'github' in url or (GITHUB_ENDPOINT is not None and GITHUB_ENDPOINT in url):
author = os.path.basename(os.path.dirname(url))

if author.startswith('[email protected]:'):
author = author.split(':')[1]

repo_name = os.path.basename(url)
if repo_name.endswith('.git'):
repo_name = repo_name[:-4]

url = f"https://github.com/{author}/{repo_name}"

return url
Expand Down
85 changes: 71 additions & 14 deletions glob/manager_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
from node_package import InstalledNodePackage


version_code = [3, 24, 1]
version_code = [3, 25]
version_str = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' if len(version_code) > 2 else '')


Expand Down Expand Up @@ -538,6 +538,8 @@ def update_cache_at_path(self, fullpath):

if node_package.is_disabled and node_package.is_unknown:
url = git_utils.git_url(node_package.fullpath)
if url is not None:
url = git_utils.normalize_url(url)
self.unknown_inactive_nodes[node_package.id] = (url, node_package.fullpath)

if node_package.is_disabled and node_package.is_nightly:
Expand All @@ -548,6 +550,8 @@ def update_cache_at_path(self, fullpath):

if node_package.is_enabled and node_package.is_unknown:
url = git_utils.git_url(node_package.fullpath)
if url is not None:
url = git_utils.normalize_url(url)
self.unknown_active_nodes[node_package.id] = (url, node_package.fullpath)

if node_package.is_from_cnr and node_package.is_disabled:
Expand Down Expand Up @@ -1059,8 +1063,8 @@ def unified_enable(self, node_id, version_spec=None):

# update cache
if version_spec == 'unknown':
self.unknown_active_nodes[node_id] = self.unknown_inactive_nodes[node_id][0], to_path
del self.unknown_inactive_nodes[node_id]
self.unknown_active_nodes[node_id] = to_path
return result.with_target(to_path)
elif version_spec == 'nightly':
del self.nightly_inactive_nodes[node_id]
Expand Down Expand Up @@ -1401,7 +1405,7 @@ async def install_by_id(self, node_id, version_spec=None, channel=None, mode=Non
res = self.repo_install(repo_url, to_path, instant_execution=instant_execution, no_deps=no_deps, return_postinstall=return_postinstall)
if res.result:
if version_spec == 'unknown':
self.unknown_active_nodes[node_id] = to_path
self.unknown_active_nodes[node_id] = repo_url, to_path
elif version_spec == 'nightly':
cnr_utils.generate_cnr_id(to_path, node_id)
self.active_nodes[node_id] = 'nightly', to_path
Expand Down Expand Up @@ -1577,6 +1581,7 @@ def write_config():
'bypass_ssl': get_config()['bypass_ssl'],
"file_logging": get_config()['file_logging'],
'component_policy': get_config()['component_policy'],
'update_policy': get_config()['update_policy'],
'windows_selector_event_loop_policy': get_config()['windows_selector_event_loop_policy'],
'model_download_by_agent': get_config()['model_download_by_agent'],
'downgrade_blacklist': get_config()['downgrade_blacklist'],
Expand Down Expand Up @@ -1615,6 +1620,7 @@ def get_bool(key, default_value):
'bypass_ssl': get_bool('bypass_ssl', False),
'file_logging': get_bool('file_logging', True),
'component_policy': default_conf.get('component_policy', 'workflow').lower(),
'update_policy': default_conf.get('update_policy', 'stable-comfyui').lower(),
'windows_selector_event_loop_policy': get_bool('windows_selector_event_loop_policy', False),
'model_download_by_agent': get_bool('model_download_by_agent', False),
'downgrade_blacklist': default_conf.get('downgrade_blacklist', '').lower(),
Expand All @@ -1637,6 +1643,7 @@ def get_bool(key, default_value):
'bypass_ssl': False,
'file_logging': True,
'component_policy': 'workflow',
'update_policy': 'stable-comfyui',
'windows_selector_event_loop_policy': False,
'model_download_by_agent': False,
'downgrade_blacklist': '',
Expand Down Expand Up @@ -1688,14 +1695,27 @@ def switch_to_default_branch(repo):
repo.git.checkout(default_branch)
return True
except:
# try checkout master
# try checkout main if failed
try:
repo.git.checkout(repo.heads.master)
return True
except:
try:
if remote_name is not None:
repo.git.checkout('-b', 'master', f'{remote_name}/master')
return True
except:
pass
try:
repo.git.checkout(repo.heads.main)
return True
except:
try:
if remote_name is not None:
repo.git.checkout('-b', 'main', f'{remote_name}/main')
return True
except:
pass

print("[ComfyUI Manager] Failed to switch to the default branch")
return False
Expand Down Expand Up @@ -2347,16 +2367,45 @@ def gitclone_update(files, instant_execution=False, skip_script=False, msg_prefi
return True


def update_to_stable_comfyui(repo_path):
try:
repo = git.Repo(repo_path)
repo.git.checkout(repo.heads.master)
versions, current_tag, _ = get_comfyui_versions(repo)

if len(versions) == 0 or (len(versions) == 1 and versions[0] == 'nightly'):
logging.info("[ComfyUI-Manager] Unable to update to the stable ComfyUI version.")
return "fail", None

if versions[0] == 'nightly':
latest_tag = versions[1]
else:
latest_tag = versions[0]

if current_tag == latest_tag:
return "skip", None
else:
logging.info(f"[ComfyUI-Manager] Updating ComfyUI: {current_tag} -> {latest_tag}")
repo.git.checkout(latest_tag)
return 'updated', latest_tag
except:
traceback.print_exc()
return "fail", None


def update_path(repo_path, instant_execution=False, no_deps=False):
if not os.path.exists(os.path.join(repo_path, '.git')):
return "fail"

# version check
repo = git.Repo(repo_path)

is_switched = False
if repo.head.is_detached:
if not switch_to_default_branch(repo):
return "fail"
else:
is_switched = True

current_branch = repo.active_branch
branch_name = current_branch.name
Expand Down Expand Up @@ -2395,6 +2444,8 @@ def update_path(repo_path, instant_execution=False, no_deps=False):
git_pull(repo_path)
execute_install_script("ComfyUI", repo_path, instant_execution=instant_execution, no_deps=no_deps)
return "updated"
elif is_switched:
return "updated"
else:
return "skipped"

Expand Down Expand Up @@ -2705,9 +2756,6 @@ def extract_nodes(sub_workflow):
if ext == 'https://github.com/comfyanonymous/ComfyUI':
pass
elif ext is not None:
if 'Fooocus' in ext:
print(f">> {node_name}")

used_exts.add(ext)
else:
unknown_nodes.add(node_name)
Expand Down Expand Up @@ -3176,17 +3224,26 @@ async def check_need_to_migrate():
need_to_migrate = True


def get_comfyui_versions():
repo = git.Repo(comfy_path)
def get_comfyui_versions(repo=None):
if repo is None:
repo = git.Repo(comfy_path)

try:
remote = get_remote_name(repo)
repo.remotes[remote].fetch()
except:
logging.error("[ComfyUI-Manager] Failed to fetch ComfyUI")

versions = [x.name for x in repo.tags if x.name.startswith('v')]
versions.reverse() # nearest tag

# nearest tag
versions = sorted(versions, key=lambda v: repo.git.log('-1', '--format=%ct', v), reverse=True)
versions = versions[:4]

current_tag = repo.git.describe('--tags')

if current_tag not in versions:
versions = sorted(versions + [current_tag], reverse=True)
versions = sorted(versions + [current_tag], key=lambda v: repo.git.log('-1', '--format=%ct', v), reverse=True)
versions = versions[:4]

main_branch = repo.heads.master
Expand All @@ -3199,16 +3256,16 @@ def get_comfyui_versions():
versions[0] = 'nightly'
current_tag = 'nightly'

return versions, current_tag
return versions, current_tag, latest_tag


def switch_comfyui(tag):
repo = git.Repo(comfy_path)

if tag == 'nightly':
repo.git.checkout('main')
repo.git.checkout('master')
repo.remotes.origin.pull()
print("[ComfyUI-Manager] ComfyUI version is switched to the latest 'main' version")
print("[ComfyUI-Manager] ComfyUI version is switched to the latest 'master' version")
else:
repo.git.checkout(tag)
print(f"[ComfyUI-Manager] ComfyUI version is switched to '{tag}'")
Expand Down
41 changes: 32 additions & 9 deletions glob/manager_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ def set_preview_method(method):
def set_component_policy(mode):
core.get_config()['component_policy'] = mode

def set_update_policy(mode):
core.get_config()['update_policy'] = mode

def print_comfyui_version():
global comfy_ui_hash
Expand Down Expand Up @@ -452,20 +454,29 @@ async def do_update(item):

return {'msg':f"An error occurred while updating '{node_name}'."}

async def do_update_comfyui() -> str:
async def do_update_comfyui(is_stable) -> str:
try:
repo_path = os.path.dirname(folder_paths.__file__)
res = core.update_path(repo_path)

latest_tag = None
if is_stable:
res, latest_tag = core.update_to_stable_comfyui(repo_path)
else:
res = core.update_path(repo_path)

if res == "fail":
logging.error("ComfyUI update fail: The installed ComfyUI does not have a Git repository.")
return "The installed ComfyUI does not have a Git repository."
elif res == "updated":
logging.info("ComfyUI is updated.")
return "success"
if is_stable:
logging.info("ComfyUI is updated to latest stable version.")
return "success-stable-"+latest_tag
else:
logging.info("ComfyUI is updated to latest nightly version.")
return "success-nightly"
else: # skipped
logging.info("ComfyUI is up-to-date.")
return "skip"

except Exception:
traceback.print_exc()

Expand Down Expand Up @@ -597,7 +608,7 @@ async def do_install_model(item) -> str:
elif kind == 'update-main':
msg = await do_update(item)
elif kind == 'update-comfyui':
msg = await do_update_comfyui()
msg = await do_update_comfyui(item[1])
elif kind == 'fix':
msg = await do_fix(item)
elif kind == 'uninstall':
Expand Down Expand Up @@ -1337,14 +1348,15 @@ async def update_custom_node(request):

@routes.get("/manager/queue/update_comfyui")
async def update_comfyui(request):
task_queue.put(("update-comfyui", ('comfyui',)))
is_stable = core.get_config()['update_policy'] != 'nightly-comfyui'
task_queue.put(("update-comfyui", ('comfyui', is_stable)))
return web.Response(status=200)


@routes.get("/comfyui_manager/comfyui_versions")
async def comfyui_versions(request):
try:
res, current = core.get_comfyui_versions()
res, current, latest = core.get_comfyui_versions()
return web.json_response({'versions': res, 'current': current}, status=200, content_type='application/json')
except Exception as e:
logging.error(f"ComfyUI update fail: {e}", file=sys.stderr)
Expand Down Expand Up @@ -1435,7 +1447,7 @@ async def preview_method(request):
return web.Response(status=200)


@routes.get("/manager/component/policy")
@routes.get("/manager/policy/component")
async def component_policy(request):
if "value" in request.rel_url.query:
set_component_policy(request.rel_url.query['value'])
Expand All @@ -1446,6 +1458,17 @@ async def component_policy(request):
return web.Response(status=200)


@routes.get("/manager/policy/update")
async def update_policy(request):
if "value" in request.rel_url.query:
set_update_policy(request.rel_url.query['value'])
core.write_config()
else:
return web.Response(text=core.get_config()['update_policy'], status=200)

return web.Response(status=200)


@routes.get("/manager/channel_url_list")
async def channel_url_list(request):
channels = core.get_channel_dict()
Expand Down
Loading

0 comments on commit 5dd8ea8

Please sign in to comment.