From 6ff6e054086a783d3f761af1dbd3d90ceee2d07f Mon Sep 17 00:00:00 2001 From: "Dr.Lt.Data" Date: Thu, 13 Feb 2025 22:04:33 +0900 Subject: [PATCH] improve: update all - background updating modified: update all - don't update ComfyUI --- glob/manager_core.py | 2 +- glob/manager_server.py | 109 ++++++------ js/comfyui-manager.js | 330 +++++++++++++++++++------------------ js/common.js | 23 ++- js/custom-nodes-manager.js | 22 +-- pyproject.toml | 2 +- 6 files changed, 257 insertions(+), 231 deletions(-) diff --git a/glob/manager_core.py b/glob/manager_core.py index 746e3878..e159eb24 100644 --- a/glob/manager_core.py +++ b/glob/manager_core.py @@ -42,7 +42,7 @@ import manager_downloader from node_package import InstalledNodePackage -version_code = [3, 19, 1] +version_code = [3, 20] version_str = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' if len(version_code) > 2 else '') diff --git a/glob/manager_server.py b/glob/manager_server.py index a2beb62a..de509070 100644 --- a/glob/manager_server.py +++ b/glob/manager_server.py @@ -419,7 +419,10 @@ async def task_worker(): manager_util.clear_pip_cache() if res.result: - return 'success' + if res.action == 'skip': + return 'skip' + else: + return 'success' logging.error(f"\nERROR: An error occurred while updating '{node_name}'.") except Exception: @@ -427,6 +430,25 @@ async def task_worker(): return f"An error occurred while updating '{node_name}'." + async def do_update_comfyui() -> str: + try: + repo_path = os.path.dirname(folder_paths.__file__) + 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" + else: # skipped + logging.info("ComfyUI is up-to-date.") + return "skip" + except Exception: + traceback.print_exc() + + return f"An error occurred while updating 'comfyui'." + async def do_fix(item) -> str: ui_id, node_name, node_ver = item @@ -550,6 +572,10 @@ async def task_worker(): msg = await do_install_model(item) elif kind == 'update': msg = await do_update(item) + elif kind == 'update-main': + msg = await do_update(item) + elif kind == 'update-comfyui': + msg = await do_update_comfyui() elif kind == 'fix': msg = await do_fix(item) elif kind == 'uninstall': @@ -569,6 +595,11 @@ async def task_worker(): if kind == 'install-model': model_result[ui_id] = msg ui_target = "model_manager" + elif kind == 'update-main': + nodepack_result[ui_id] = msg + ui_target = "main" + elif kind == 'update-comfyui': + ui_target = "main" else: nodepack_result[ui_id] = msg ui_target = "nodepack_manager" @@ -643,49 +674,37 @@ async def fetch_updates(request): return web.Response(status=400) -@routes.get("/customnode/update_all") +@routes.get("/manager/queue/update_all") async def update_all(request): if not is_allowed_security_level('middle'): logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW) return web.Response(status=403) - try: - await core.save_snapshot_with_postfix('autosave') + with task_worker_lock: + is_processing = task_worker_thread is not None and task_worker_thread.is_alive() + if is_processing: + return web.Response(status=401) + + await core.save_snapshot_with_postfix('autosave') - if request.rel_url.query["mode"] == "local": - channel = 'local' - else: - channel = core.get_config()['channel_url'] + if request.rel_url.query["mode"] == "local": + channel = 'local' + else: + channel = core.get_config()['channel_url'] - await core.unified_manager.reload(request.rel_url.query["mode"]) - await core.unified_manager.get_custom_nodes(channel, request.rel_url.query["mode"]) + await core.unified_manager.reload(request.rel_url.query["mode"]) + await core.unified_manager.get_custom_nodes(channel, request.rel_url.query["mode"]) - updated_cnr = [] - for k, v in core.unified_manager.active_nodes.items(): - if v[0] != 'nightly': - res = core.unified_manager.unified_update(k, v[0]) - if res.action == 'switch-cnr' and res: - updated_cnr.append(k) + for k, v in core.unified_manager.active_nodes.items(): + if k == 'comfyui-manager': + # skip updating comfyui-manager if desktop version + if os.environ.get('__COMFYUI_DESKTOP_VERSION__'): + continue - res = core.unified_manager.fetch_or_pull_git_repo(is_pull=True) + update_item = k, k, v[0] + task_queue.put(("update-main", update_item)) - res['updated'] += updated_cnr - - for x in res['failed']: - logging.error(f"PULL FAILED: {x}") - - if len(res['updated']) == 0 and len(res['failed']) == 0: - status = 200 - else: - status = 201 - - logging.info("\nDone.") - return web.json_response(res, status=status, content_type='application/json') - except: - traceback.print_exc() - return web.Response(status=400) - finally: - manager_util.clear_pip_cache() + return web.Response(status=200) def convert_markdown_to_html(input_text): @@ -1281,26 +1300,10 @@ async def update_custom_node(request): return web.Response(status=200) -@routes.get("/comfyui_manager/update_comfyui") +@routes.get("/manager/queue/update_comfyui") async def update_comfyui(request): - logging.info("Update ComfyUI") - - try: - repo_path = os.path.dirname(folder_paths.__file__) - res = core.update_path(repo_path) - if res == "fail": - logging.error("ComfyUI update fail: The installed ComfyUI does not have a Git repository.") - return web.Response(status=400) - elif res == "updated": - logging.info("ComfyUI is updated.") - return web.Response(status=201) - else: # skipped - logging.info("ComfyUI is up-to-date.") - return web.Response(status=200) - except Exception as e: - logging.error(f"ComfyUI update fail: {e}", file=sys.stderr) - - return web.Response(status=400) + task_queue.put(("update-comfyui", ('comfyui',))) + return web.Response(status=200) @routes.get("/comfyui_manager/comfyui_versions") diff --git a/js/comfyui-manager.js b/js/comfyui-manager.js index ba1a9b84..ca30f12e 100644 --- a/js/comfyui-manager.js +++ b/js/comfyui-manager.js @@ -13,7 +13,9 @@ import { import { OpenArtShareDialog } from "./comfyui-share-openart.js"; import { free_models, install_pip, install_via_git_url, manager_instance, - rebootAPI, migrateAPI, setManagerInstance, show_message, customAlert, customPrompt } from "./common.js"; + rebootAPI, migrateAPI, setManagerInstance, show_message, customAlert, customPrompt, + infoToast, showTerminal, setNeedRestart +} from "./common.js"; import { ComponentBuilderDialog, getPureName, load_components, set_component_policy } from "./components-manager.js"; import { CustomNodesManager } from "./custom-nodes-manager.js"; import { ModelManager } from "./model-manager.js"; @@ -225,7 +227,11 @@ var update_comfyui_button = null; var switch_comfyui_button = null; var fetch_updates_button = null; var update_all_button = null; +var restart_stop_button = null; + let share_option = 'all'; +var is_updating_all = false; + // copied style from https://github.com/pythongosssss/ComfyUI-Custom-Scripts const style = ` @@ -424,102 +430,54 @@ async function init_notice(notice) { await init_share_option(); -async function fetchNicknames() { - const response1 = await api.fetchApi(`/customnode/getmappings?mode=nickname`); - const mappings = await response1.json(); - let result = {}; - let nickname_patterns = []; +async function set_inprogress_mode() { + update_comfyui_button.disabled = true; + update_comfyui_button.style.backgroundColor = "gray"; - for (let i in mappings) { - let item = mappings[i]; - var nickname; - if (item[1].nickname) { - nickname = item[1].nickname; - } - else if (item[1].title) { - nickname = item[1].title; - } - else { - nickname = item[1].title_aux; - } + update_all_button.disabled = true; + update_all_button.style.backgroundColor = "gray"; - for (let j in item[0]) { - result[item[0][j]] = nickname; - } + switch_comfyui_button.disabled = true; + switch_comfyui_button.style.backgroundColor = "gray"; - if(item[1].nodename_pattern) { - nickname_patterns.push([item[1].nodename_pattern, nickname]); - } - } - - return [result, nickname_patterns]; + restart_stop_button.innerText = 'Stop'; } -const [nicknames, nickname_patterns] = await fetchNicknames(); -function getNickname(node, nodename) { - if(node.nickname) { - return node.nickname; +async function reset_action_buttons() { + const isElectron = 'electronAPI' in window; + + if(isElectron) { + update_all_button.innerText = "Update All Custom Nodes"; } else { - if (nicknames[nodename]) { - node.nickname = nicknames[nodename]; - } - else if(node.getInnerNodes) { - let pure_name = getPureName(node); - let groupNode = app.graph.extra?.groupNodes?.[pure_name]; - if(groupNode) { - let packname = groupNode.packname; - node.nickname = packname; - } - return node.nickname; - } - else { - for(let i in nickname_patterns) { - let item = nickname_patterns[i]; - if(nodename.match(item[0])) { - node.nickname = item[1]; - } - } - } - - return node.nickname; + update_all_button.innerText = "Update All"; } + + update_comfyui_button.innerText = "Update ComfyUI"; + switch_comfyui_button.innerText = "Switch ComfyUI"; + restart_stop_button.innerText = 'Restart'; + + update_comfyui_button.disabled = false; + update_all_button.disabled = false; + switch_comfyui_button.disabled = false; + + update_comfyui_button.style.backgroundColor = ""; + update_all_button.style.backgroundColor = ""; + switch_comfyui_button.style.backgroundColor = ""; } async function updateComfyUI() { let prev_text = update_comfyui_button.innerText; update_comfyui_button.innerText = "Updating ComfyUI..."; - update_comfyui_button.disabled = true; - update_comfyui_button.style.backgroundColor = "gray"; - try { - const response = await api.fetchApi('/comfyui_manager/update_comfyui'); + set_inprogress_mode(); - if (response.status == 400) { - show_message('Failed to update ComfyUI.'); - return false; - } + const response = await api.fetchApi('/manager/queue/update_comfyui'); - if (response.status == 201) { - show_message('ComfyUI has been successfully updated.'); - } - else { - show_message('ComfyUI is already up to date with the latest version.'); - } - - return true; - } - catch (exception) { - show_message(`Failed to update ComfyUI / ${exception}`); - return false; - } - finally { - update_comfyui_button.disabled = false; - update_comfyui_button.innerText = prev_text; - update_comfyui_button.style.backgroundColor = ""; - } + showTerminal(); + await api.fetchApi('/manager/queue/start'); } function showVersionSelectorDialog(versions, current, onSelect) { @@ -647,26 +605,32 @@ function showVersionSelectorDialog(versions, current, onSelect) { } async function switchComfyUI() { - let res = await api.fetchApi(`/comfyui_manager/comfyui_versions`, { cache: "no-store" }); + let res = await api.fetchApi(`/comfyui_manager/comfyui_versions`, { cache: "no-store" }); - if(res.status == 200) { - let obj = await res.json(); + if(res.status == 200) { + let obj = await res.json(); - let versions = []; - let default_version; + let versions = []; + let default_version; - for(let v of obj.versions) { - default_version = v; - versions.push(v); - } + for(let v of obj.versions) { + default_version = v; + versions.push(v); + } - showVersionSelectorDialog(versions, obj.current, (selected_version) => { - api.fetchApi(`/comfyui_manager/comfyui_switch_version?ver=${selected_version}`, { cache: "no-store" }); - }); - } - else { - show_message('Failed to fetch ComfyUI versions.'); - } + showVersionSelectorDialog(versions, obj.current, async (selected_version) => { + let response = await api.fetchApi(`/comfyui_manager/comfyui_switch_version?ver=${selected_version}`, { cache: "no-store" }); + if (response.status == 200) { + infoToast(`ComfyUI version is switched to ${selected_version}`); + } + else { + customAlert('Failed to switch ComfyUI version.'); + } + }); + } + else { + customAlert('Failed to fetch ComfyUI versions.'); + } } @@ -720,70 +684,100 @@ async function fetchUpdates(update_check_checkbox) { } } -async function updateAll(update_check_checkbox, manager_dialog) { - let prev_text = update_all_button.innerText; - update_all_button.innerText = "Updating all...(ComfyUI)"; - update_all_button.disabled = true; - update_all_button.style.backgroundColor = "gray"; +async function onQueueStatus(event) { + const isElectron = 'electronAPI' in window; - try { - var mode = manager_instance.datasrc_combo.value; + if(event.detail.status == 'in_progress') { + set_inprogress_mode(); + update_all_button.innerText = `in progress.. (${event.detail.done_count}/${event.detail.total_count})`; + } + else if(event.detail.status == 'done') { + reset_action_buttons(); - update_all_button.innerText = "Updating all..."; - const response1 = await api.fetchApi('/comfyui_manager/update_comfyui'); - const response2 = await api.fetchApi(`/customnode/update_all?mode=${mode}`); - - if (response2.status == 403) { - show_message('This action is not allowed with this security level configuration.'); - return false; + if(!is_updating_all) { + return; } - if (response1.status == 400 || response2.status == 400) { - show_message('Failed to update ComfyUI or several extensions.

See terminal log.
'); - return false; + let success_list = []; + let failed_list = []; + + for(let k in event.detail.nodepack_result){ + let v = event.detail.nodepack_result[k]; + + if(v == 'success') + success_list.push(k); + else if(v == 'skip') { + // do nothing + } + else + failed_list.push(k); } - if(response1.status == 201 || response2.status == 201) { - const update_info = await response2.json(); - - let failed_list = ""; - if(update_info.failed.length > 0) { - failed_list = "
FAILED: "+update_info.failed.join(", "); + let msg = ""; + + if(success_list.length == 0) { + if(failed_list.length == 0) { + msg += "All custom nodes are already up to date."; } - - let updated_list = ""; - if(update_info.updated.length > 0) { - updated_list = "
UPDATED: "+update_info.updated.join(", "); - } - - show_message( - "ComfyUI and all extensions have been updated to the latest version.
To apply the updated custom node, please ComfyUI. And refresh browser.
" - +failed_list - +updated_list - ); - - const rebootButton = document.getElementById('cm-reboot-button5'); - rebootButton.addEventListener("click", - function() { - if(rebootAPI()) { - manager_dialog.close(); - } - }); } else { - show_message('ComfyUI and all extensions are already up-to-date with the latest versions.'); + msg = "To apply the updates, you need to ComfyUI.
"; + msg += "The following custom nodes have been updated:"; + + setNeedRestart(true); + } + + if(failed_list.length > 0) { + msg += '
The update for the following custom nodes has failed:' } - return true; + show_message(msg); + + const rebootButton = document.getElementById('cm-reboot-button5'); + rebootButton?.addEventListener("click", + function() { + if(rebootAPI()) { + manager_dialog.close(); + } + }); } - catch (exception) { - show_message(`Failed to update ComfyUI or several extensions / ${exception}`); - return false; +} + +api.addEventListener("cm-queue-status", onQueueStatus); + + +async function updateAll(update_comfyui, manager_dialog) { + let prev_text = update_all_button.innerText; + update_all_button.innerText = "Updating..."; + + set_inprogress_mode(); + + var mode = manager_instance.datasrc_combo.value; + + showTerminal(); + + if(update_comfyui) { + update_all_button.innerText = "Updating ComfyUI..."; + await api.fetchApi('/manager/queue/update_comfyui'); } - finally { - update_all_button.disabled = false; - update_all_button.innerText = prev_text; - update_all_button.style.backgroundColor = ""; + + const response = await api.fetchApi(`/manager/queue/update_all?mode=${mode}`); + + if (response.status == 401) { + customAlert('Another task is already in progress. Please stop the ongoing task first.'); + } + else if(response.status == 200) { + is_updating_all = true; + await api.fetchApi('/manager/queue/start'); } } @@ -807,6 +801,16 @@ const isOutputNode = (node) => { return SUPPORTED_OUTPUT_NODE_TYPES.includes(node.type); } +function restartOrStop() { + if(restart_stop_button.innerText == 'Restart'){ + rebootAPI(); + } + else { + api.fetchApi('/manager/queue/reset'); + infoToast('Cancel', 'Remaining tasks will stop after completing the current task.'); + } +} + // ----------- class ManagerMenuDialog extends ComfyDialog { createControlsMid() { @@ -843,14 +847,32 @@ class ManagerMenuDialog extends ComfyDialog { () => fetchUpdates(this.update_check_checkbox) }); - update_all_button = - $el("button.cm-button", { + restart_stop_button = + $el("button.cm-button-red", { type: "button", - textContent: "Update All", - onclick: - () => updateAll(this.update_check_checkbox, self) + textContent: "Restart", + onclick: () => restartOrStop() }); + if(isElectron) { + update_all_button = + $el("button.cm-button", { + type: "button", + textContent: "Update All Custom Nodes", + onclick: + () => updateAll(false, self) + }); + } + else { + update_all_button = + $el("button.cm-button", { + type: "button", + textContent: "Update All", + onclick: + () => updateAll(true, self) + }); + } + const res = [ $el("button.cm-button", { @@ -909,11 +931,7 @@ class ManagerMenuDialog extends ComfyDialog { fetch_updates_button, $el("br", {}, []), - $el("button.cm-button-red", { - type: "button", - textContent: "Restart", - onclick: () => rebootAPI() - }), + restart_stop_button, ]; let migration_btn = diff --git a/js/common.js b/js/common.js index e9c02ace..53fa32f6 100644 --- a/js/common.js +++ b/js/common.js @@ -431,4 +431,25 @@ export function showTerminal() { catch(exception) { // do nothing } -} \ No newline at end of file +} + +let need_restart = false; + +export function setNeedRestart(value) { + need_restart = value; +} + +async function onReconnected(event) { + if(need_restart) { + setNeedRestart(false); + + const confirmed = await customConfirm("To apply the changes to the node pack's installation status, you need to refresh the browser. Would you like to refresh?"); + if (!confirmed) { + return; + } + + window.location.reload(true); + } +} + +api.addEventListener('reconnected', onReconnected); \ No newline at end of file diff --git a/js/custom-nodes-manager.js b/js/custom-nodes-manager.js index dd70cb4b..15c2b4d2 100644 --- a/js/custom-nodes-manager.js +++ b/js/custom-nodes-manager.js @@ -5,7 +5,7 @@ import { api } from "../../scripts/api.js"; import { manager_instance, rebootAPI, install_via_git_url, fetchData, md5, icons, show_message, customConfirm, customAlert, customPrompt, - sanitizeHTML, infoToast, showTerminal + sanitizeHTML, infoToast, showTerminal, setNeedRestart } from "./common.js"; // https://cenfun.github.io/turbogrid/api.html @@ -401,7 +401,6 @@ export class CustomNodesManager { this.init(); api.addEventListener("cm-queue-status", this.onQueueStatus); - api.addEventListener('reconnected', this.onReconnected); } init() { @@ -1403,21 +1402,6 @@ export class CustomNodesManager { } } - async onReconnected(event) { - let self = CustomNodesManager.instance; - - if(self.need_restart) { - self.need_restart = false; - - const confirmed = await customConfirm("To apply the changes to the node pack's installation status, you need to refresh the browser. Would you like to refresh?"); - if (!confirmed) { - return; - } - - window.location.reload(true); - } - } - async onQueueStatus(event) { let self = CustomNodesManager.instance; if(event.detail.status == 'in_progress' && event.detail.ui_target == 'nodepack_manager') { @@ -1457,7 +1441,7 @@ export class CustomNodesManager { for(let hash in result){ let v = result[hash]; - if(v != 'success') + if(v != 'success' && v != 'skip') errorMsg += v+'\n'; } @@ -1898,7 +1882,7 @@ export class CustomNodesManager { showRestart() { this.element.querySelector(".cn-manager-restart").style.display = "block"; - this.need_restart = true; + setNeedRestart(true); } showStop() { diff --git a/pyproject.toml b/pyproject.toml index 87dea994..2087c4dd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "comfyui-manager" description = "ComfyUI-Manager provides features to install and manage custom nodes for ComfyUI, as well as various functionalities to assist with ComfyUI." -version = "3.19.1" +version = "3.20" license = { file = "LICENSE.txt" } dependencies = ["GitPython", "PyGithub", "matrix-client==0.4.0", "transformers", "huggingface-hub>0.20", "typer", "rich", "typing-extensions"]