diff --git a/cm-cli.py b/cm-cli.py index 2e78f0e..758b284 100644 --- a/cm-cli.py +++ b/cm-cli.py @@ -24,7 +24,7 @@ if not (len(sys.argv) == 2 and sys.argv[1] in ['save-snapshot', 'restore-depende f" [update|disable|enable|fix] all ?[--channel ] ?[--mode [remote|local|cache]]\n" f" [simple-show|show] [installed|enabled|not-installed|disabled|all|snapshot|snapshot-list] ?[--channel ] ?[--mode [remote|local|cache]]\n" f" save-snapshot ?[--output ]\n" - f" restore-snapshot \n" + f" restore-snapshot ?[--pip-non-url] ?[--pip-non-local-url] ?[--pip-local-url]\n" f" cli-only-mode [enable|disable]\n" f" restore-dependencies\n" f" deps-in-workflow --workflow --output \n" @@ -126,9 +126,14 @@ def install_deps(): print("Dependency installation and activation complete.") -def restore_snapshot(snapshot_name): +def restore_snapshot(): global processed_install + snapshot_name = sys.argv[2] + extras = [x for x in sys.argv if x in ['--pip-non-url', '--pip-local-url', '--pip-non-local-url']] + + print(f"pips restore mode: {extras}") + if os.path.exists(snapshot_name): snapshot_path = os.path.abspath(snapshot_name) else: @@ -163,7 +168,7 @@ def restore_snapshot(snapshot_name): is_failed = True print(f"Restore snapshot.") - cmd_str = [sys.executable, git_script_path, '--apply-snapshot', snapshot_path] + cmd_str = [sys.executable, git_script_path, '--apply-snapshot', snapshot_path] + extras output = subprocess.check_output(cmd_str, cwd=custom_nodes_path, text=True) msg_lines = output.split('\n') extract_infos(msg_lines) @@ -647,7 +652,7 @@ elif op == 'save-snapshot': print(f"Current snapshot is saved as `{path}`") elif op == 'restore-snapshot': - restore_snapshot(sys.argv[2]) + restore_snapshot() elif op == 'restore-dependencies': restore_dependencies() diff --git a/git_helper.py b/git_helper.py index f7b2cc3..2a55d2b 100644 --- a/git_helper.py +++ b/git_helper.py @@ -1,5 +1,8 @@ +import subprocess import sys import os +import traceback + import git import configparser import re @@ -13,6 +16,10 @@ config_path = os.path.join(os.path.dirname(__file__), "config.ini") nodelist_path = os.path.join(os.path.dirname(__file__), "custom-node-list.json") working_directory = os.getcwd() +if os.path.basename(working_directory) != 'custom_nodes': + print(f"ERROR: This script should be executed in custom_nodes dir") + exit(-1) + class GitProgress(RemoteProgress): def __init__(self): @@ -133,7 +140,7 @@ def gitpull(path): def checkout_comfyui_hash(target_hash): - repo_path = os.path.join(working_directory, '..') # ComfyUI dir + repo_path = os.path.abspath(os.path.join(working_directory, '..')) # ComfyUI dir repo = git.Repo(repo_path) commit_hash = repo.head.commit.hexsha @@ -282,7 +289,7 @@ def apply_snapshot(target): if not target.endswith('.json') and not target.endswith('.yaml'): print(f"Snapshot file not found: `{path}`") print("APPLY SNAPSHOT: False") - return + return None with open(path, 'r', encoding="UTF-8") as snapshot_file: if target.endswith('.json'): @@ -293,7 +300,7 @@ def apply_snapshot(target): else: # impossible case print("APPLY SNAPSHOT: False") - return + return None comfyui_hash = info['comfyui'] git_custom_node_infos = info['git_custom_nodes'] @@ -304,14 +311,81 @@ def apply_snapshot(target): invalidate_custom_node_file(file_custom_node_infos) print("APPLY SNAPSHOT: True") - return + if 'pips' in info: + return info['pips'] + else: + return None print(f"Snapshot file not found: `{path}`") print("APPLY SNAPSHOT: False") + + return None except Exception as e: print(e) + traceback.print_exc() print("APPLY SNAPSHOT: False") + return None + + +def restore_pip_snapshot(pips, options): + non_url = [] + local_url = [] + non_local_url = [] + for k, v in pips.items(): + if v == "": + non_url.append(v) + else: + if v.startswith('file:'): + local_url.append(v) + else: + non_local_url.append(v) + + failed = [] + if '--pip-non-url' in options: + # try all at once + res = 1 + try: + res = subprocess.check_call([sys.executable, '-m', 'pip', 'install'] + non_url) + except: + pass + + # fallback + if res != 0: + for x in non_url: + res = 1 + try: + res = subprocess.check_call([sys.executable, '-m', 'pip', 'install', x]) + except: + pass + + if res != 0: + failed.append(x) + + if '--pip-non-local-url' in options: + for x in non_local_url: + res = 1 + try: + res = subprocess.check_call([sys.executable, '-m', 'pip', 'install', x]) + except: + pass + + if res != 0: + failed.append(x) + + if '--pip-local-url' in options: + for x in local_url: + res = 1 + try: + res = subprocess.check_call([sys.executable, '-m', 'pip', 'install', x]) + except: + pass + + if res != 0: + failed.append(x) + + print(f"Installation failed for pip packages: {failed}") + def setup_environment(): config = configparser.ConfigParser() @@ -333,7 +407,15 @@ try: elif sys.argv[1] == "--pull": gitpull(sys.argv[2]) elif sys.argv[1] == "--apply-snapshot": - apply_snapshot(sys.argv[2]) + options = set() + for x in sys.argv: + if x in ['--pip-non-url', '--pip-local-url', '--pip-non-local-url']: + options.add(x) + + pips = apply_snapshot(sys.argv[2]) + + if pips and len(options) > 0: + restore_pip_snapshot(pips, options) sys.exit(0) except Exception as e: print(e) diff --git a/glob/manager_core.py b/glob/manager_core.py index db20bea..f86df58 100644 --- a/glob/manager_core.py +++ b/glob/manager_core.py @@ -22,7 +22,7 @@ sys.path.append(glob_path) import cm_global from manager_util import * -version = [2, 26] +version = [2, 27] version_str = f"V{version[0]}.{version[1]}" + (f'.{version[2]}' if len(version) > 2 else '') comfyui_manager_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) @@ -312,7 +312,7 @@ def __win_check_git_update(path, do_fetch=False, do_update=False): else: command = [sys.executable, git_script_path, "--check", path] - process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=custom_nodes_path) output, _ = process.communicate() output = output.decode('utf-8').strip() @@ -364,7 +364,7 @@ def __win_check_git_update(path, do_fetch=False, do_update=False): def __win_check_git_pull(path): command = [sys.executable, git_script_path, "--pull", path] - process = subprocess.Popen(command) + process = subprocess.Popen(command, cwd=custom_nodes_path) process.wait() @@ -513,7 +513,7 @@ def gitclone_install(files, instant_execution=False, msg_prefix=''): # Clone the repository from the remote URL if not instant_execution and platform.system() == 'Windows': - res = manager_funcs.run_script([sys.executable, git_script_path, "--clone", custom_nodes_path, url]) + res = manager_funcs.run_script([sys.executable, git_script_path, "--clone", custom_nodes_path, url], cwd=custom_nodes_path) if res != 0: return False else: @@ -941,6 +941,24 @@ def check_a_custom_node_installed(item, do_fetch=False, do_update_check=True, do item['installed'] = 'False' +def get_installed_pip_packages(): + # extract pip package infos + pips = subprocess.check_output([sys.executable, '-m', 'pip', 'freeze'], text=True).split('\n') + + res = {} + for x in pips: + if x.strip() == "": + continue + + if ' @ ' in x: + spec_url = x.split(' @ ') + res[spec_url[0]] = spec_url[1] + else: + res[x] = "" + + return res + + def get_current_snapshot(): # Get ComfyUI hash repo_path = comfy_path @@ -990,10 +1008,13 @@ def get_current_snapshot(): file_custom_nodes.append(item) + pip_packages = get_installed_pip_packages() + return { 'comfyui': comfyui_commit_hash, 'git_custom_nodes': git_custom_nodes, 'file_custom_nodes': file_custom_nodes, + 'pips': pip_packages, } @@ -1133,6 +1154,5 @@ async def extract_nodes_from_workflow(filepath, mode='local', channel_url='defau else: unknown_nodes.add(node_name) - return used_exts, unknown_nodes diff --git a/glob/manager_server.py b/glob/manager_server.py index 36bac02..af05cbb 100644 --- a/glob/manager_server.py +++ b/glob/manager_server.py @@ -872,7 +872,6 @@ async def update_comfyui(request): return web.Response(status=200) except Exception as e: print(f"ComfyUI update fail: {e}", file=sys.stderr) - pass return web.Response(status=400) diff --git a/js/comfyui-manager.js b/js/comfyui-manager.js index 125955a..3e98c23 100644 --- a/js/comfyui-manager.js +++ b/js/comfyui-manager.js @@ -615,7 +615,7 @@ async function updateAll(update_check_checkbox, manager_dialog) { const response1 = await api.fetchApi('/comfyui_manager/update_comfyui'); const response2 = await api.fetchApi(`/customnode/update_all?mode=${mode}`); - if (response1.status != 200 && response2.status != 201) { + if (response1.status == 400 || response2.status == 400) { app.ui.dialog.show('Failed to update ComfyUI or several extensions.

See terminal log.
'); app.ui.dialog.element.style.zIndex = 10010; return false;