fred-dev/comfy_ui_ali
0
1import os2import shutil3import subprocess4import sys5import atexit6import threading7import re8import locale9import platform10import json11import ast12import logging13import traceback14 15glob_path = os.path.join(os.path.dirname(__file__), "glob")16sys.path.append(glob_path)17 18import security_check19import manager_util20import cm_global21import manager_downloader22import folder_paths23 24manager_util.add_python_path_to_env()25 26import datetime as dt27 28if hasattr(dt, 'datetime'):29 from datetime import datetime as dt_datetime30 31 def current_timestamp():32 return dt_datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]33else:34 # NOTE: Occurs in some Mac environments.35 import time36 logging.error(f"[ComfyUI-Manager] fallback timestamp mode\n datetime module is invalid: '{dt.__file__}'")37 38 def current_timestamp():39 return str(time.time()).split('.')[0]40 41security_check.security_check()42 43cm_global.pip_blacklist = {'torch', 'torchsde', 'torchvision'}44cm_global.pip_downgrade_blacklist = ['torch', 'torchsde', 'torchvision', 'transformers', 'safetensors', 'kornia']45 46 47def skip_pip_spam(x):48 return ('Requirement already satisfied:' in x) or ("DEPRECATION: Loading egg at" in x)49 50 51message_collapses = [skip_pip_spam]52import_failed_extensions = set()53cm_global.variables['cm.on_revision_detected_handler'] = []54enable_file_logging = True55 56 57def register_message_collapse(f):58 global message_collapses59 message_collapses.append(f)60 61 62def is_import_failed_extension(name):63 global import_failed_extensions64 return name in import_failed_extensions65 66 67comfy_path = os.environ.get('COMFYUI_PATH')68comfy_base_path = os.environ.get('COMFYUI_FOLDERS_BASE_PATH')69 70if comfy_path is None:71 # legacy env var72 comfy_path = os.environ.get('COMFYUI_PATH')73 74if comfy_path is None:75 comfy_path = os.path.abspath(os.path.dirname(sys.modules['__main__'].__file__))76 77if comfy_base_path is None:78 comfy_base_path = comfy_path79 80sys.__comfyui_manager_register_message_collapse = register_message_collapse81sys.__comfyui_manager_is_import_failed_extension = is_import_failed_extension82cm_global.register_api('cm.register_message_collapse', register_message_collapse)83cm_global.register_api('cm.is_import_failed_extension', is_import_failed_extension)84 85 86comfyui_manager_path = os.path.abspath(os.path.dirname(__file__))87 88custom_nodes_base_path = folder_paths.get_folder_paths('custom_nodes')[0]89manager_files_path = os.path.abspath(os.path.join(folder_paths.get_user_directory(), 'default', 'ComfyUI-Manager'))90manager_pip_overrides_path = os.path.join(manager_files_path, "pip_overrides.json")91manager_pip_blacklist_path = os.path.join(manager_files_path, "pip_blacklist.list")92restore_snapshot_path = os.path.join(manager_files_path, "startup-scripts", "restore-snapshot.json")93manager_config_path = os.path.join(manager_files_path, 'config.ini')94 95cm_cli_path = os.path.join(comfyui_manager_path, "cm-cli.py")96 97 98default_conf = {}99 100def read_config():101 global default_conf102 try:103 import configparser104 config = configparser.ConfigParser(strict=False)105 config.read(manager_config_path)106 default_conf = config['default']107 except Exception:108 pass109 110def read_uv_mode():111 if 'use_uv' in default_conf:112 manager_util.use_uv = default_conf['use_uv'].lower() == 'true'113 114def check_file_logging():115 global enable_file_logging116 if 'file_logging' in default_conf and default_conf['file_logging'].lower() == 'false':117 enable_file_logging = False118 119 120read_config()121read_uv_mode()122check_file_logging()123 124cm_global.pip_overrides = {'numpy': 'numpy<2', 'ultralytics': 'ultralytics==8.3.40'}125if os.path.exists(manager_pip_overrides_path):126 with open(manager_pip_overrides_path, 'r', encoding="UTF-8", errors="ignore") as json_file:127 cm_global.pip_overrides = json.load(json_file)128 cm_global.pip_overrides['numpy'] = 'numpy<2'129 cm_global.pip_overrides['ultralytics'] = 'ultralytics==8.3.40' # for security130 131 132if os.path.exists(manager_pip_blacklist_path):133 with open(manager_pip_blacklist_path, 'r', encoding="UTF-8", errors="ignore") as f:134 for x in f.readlines():135 y = x.strip()136 if y != '':137 cm_global.pip_blacklist.add(y)138 139 140def remap_pip_package(pkg):141 if pkg in cm_global.pip_overrides:142 res = cm_global.pip_overrides[pkg]143 print(f"[ComfyUI-Manager] '{pkg}' is remapped to '{res}'")144 return res145 else:146 return pkg147 148 149std_log_lock = threading.Lock()150 151 152def handle_stream(stream, prefix):153 stream.reconfigure(encoding=locale.getpreferredencoding(), errors='replace')154 for msg in stream:155 if prefix == '[!]' and ('it/s]' in msg or 's/it]' in msg) and ('%|' in msg or 'it [' in msg):156 if msg.startswith('100%'):157 print('\r' + msg, end="", file=sys.stderr),158 else:159 print('\r' + msg[:-1], end="", file=sys.stderr),160 else:161 if prefix == '[!]':162 print(prefix, msg, end="", file=sys.stderr)163 else:164 print(prefix, msg, end="")165 166 167def process_wrap(cmd_str, cwd_path, handler=None, env=None):168 process = subprocess.Popen(cmd_str, cwd=cwd_path, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, bufsize=1)169 170 if handler is None:171 handler = handle_stream172 173 stdout_thread = threading.Thread(target=handler, args=(process.stdout, ""))174 stderr_thread = threading.Thread(target=handler, args=(process.stderr, "[!]"))175 176 stdout_thread.start()177 stderr_thread.start()178 179 stdout_thread.join()180 stderr_thread.join()181 182 return process.wait()183 184 185original_stdout = sys.stdout186 187 188def try_get_custom_nodes(x):189 for custom_nodes_dir in folder_paths.get_folder_paths('custom_nodes'):190 if x.startswith(custom_nodes_dir):191 relative_path = os.path.relpath(x, custom_nodes_dir)192 next_segment = relative_path.split(os.sep)[0]193 if next_segment.lower() != 'comfyui-manager':194 return next_segment, os.path.join(custom_nodes_dir, next_segment)195 return None196 197 198def extract_origin_module():199 stack = traceback.extract_stack()[:-2]200 for frame in reversed(stack):201 info = try_get_custom_nodes(frame.filename)202 if info is None:203 continue204 else:205 return info206 return None207 208def extract_origin_module_from_strings(file_paths):209 for filepath in file_paths:210 info = try_get_custom_nodes(filepath)211 if info is None:212 continue213 else:214 return info215 return None216 217 218def finalize_startup():219 res = {}220 for k, v in cm_global.error_dict.items():221 if v['path'] in import_failed_extensions:222 res[k] = v223 224 cm_global.error_dict = res225 226 227try:228 if '--port' in sys.argv:229 port_index = sys.argv.index('--port')230 if port_index + 1 < len(sys.argv):231 port = int(sys.argv[port_index + 1])232 postfix = f"_{port}"233 else:234 postfix = ""235 else:236 postfix = ""237 238 # Logger setup239 log_path_base = None240 if enable_file_logging:241 log_path_base = os.path.join(folder_paths.user_directory, 'comfyui')242 243 if not os.path.exists(folder_paths.user_directory):244 os.makedirs(folder_paths.user_directory)245 246 if os.path.exists(f"{log_path_base}{postfix}.log"):247 if os.path.exists(f"{log_path_base}{postfix}.prev.log"):248 if os.path.exists(f"{log_path_base}{postfix}.prev2.log"):249 os.remove(f"{log_path_base}{postfix}.prev2.log")250 os.rename(f"{log_path_base}{postfix}.prev.log", f"{log_path_base}{postfix}.prev2.log")251 os.rename(f"{log_path_base}{postfix}.log", f"{log_path_base}{postfix}.prev.log")252 253 log_file = open(f"{log_path_base}{postfix}.log", "w", encoding="utf-8", errors="ignore")254 255 log_lock = threading.Lock()256 257 original_stdout = sys.stdout258 original_stderr = sys.stderr259 260 if original_stdout.encoding.lower() == 'utf-8':261 write_stdout = original_stdout.write262 write_stderr = original_stderr.write263 else:264 def wrapper_stdout(msg):265 original_stdout.write(msg.encode('utf-8').decode(original_stdout.encoding, errors="ignore"))266 267 def wrapper_stderr(msg):268 original_stderr.write(msg.encode('utf-8').decode(original_stderr.encoding, errors="ignore"))269 270 write_stdout = wrapper_stdout271 write_stderr = wrapper_stderr272 273 pat_tqdm = r'\d+%.*\[(.*?)\]'274 pat_import_fail = r'seconds \(IMPORT FAILED\):(.*)$'275 276 is_start_mode = True277 278 279 class ComfyUIManagerLogger:280 def __init__(self, is_stdout):281 self.is_stdout = is_stdout282 self.encoding = "utf-8"283 self.last_char = ''284 285 def fileno(self):286 try:287 if self.is_stdout:288 return original_stdout.fileno()289 else:290 return original_stderr.fileno()291 except AttributeError:292 # Handle error293 raise ValueError("The object does not have a fileno method")294 295 def isatty(self):296 return False297 298 def write(self, message):299 global is_start_mode300 301 if any(f(message) for f in message_collapses):302 return303 304 if is_start_mode:305 match = re.search(pat_import_fail, message)306 if match:307 import_failed_extensions.add(match.group(1).strip())308 309 if not self.is_stdout:310 origin_info = extract_origin_module()311 if origin_info is not None:312 name, origin_path = origin_info313 314 if name != 'comfyui-manager':315 if name not in cm_global.error_dict:316 cm_global.error_dict[name] = {'name': name, 'path': origin_path, 'msg': ''}317 318 cm_global.error_dict[name]['msg'] += message319 320 if not self.is_stdout:321 match = re.search(pat_tqdm, message)322 if match:323 message = re.sub(r'([#|])\d', r'\1▌', message)324 message = re.sub('#', '█', message)325 if '100%' in message:326 self.sync_write(message)327 else:328 write_stderr(message)329 original_stderr.flush()330 else:331 self.sync_write(message)332 else:333 self.sync_write(message)334 335 def sync_write(self, message, file_only=False):336 with log_lock:337 timestamp = current_timestamp()338 if self.last_char != '\n':339 log_file.write(message)340 else:341 log_file.write(f"[{timestamp}] {message}")342 log_file.flush()343 self.last_char = message if message == '' else message[-1]344 345 if not file_only:346 with std_log_lock:347 if self.is_stdout:348 write_stdout(message)349 original_stdout.flush()350 else:351 write_stderr(message)352 original_stderr.flush()353 354 def flush(self):355 log_file.flush()356 357 with std_log_lock:358 if self.is_stdout:359 original_stdout.flush()360 else:361 original_stderr.flush()362 363 def close(self):364 self.flush()365 366 def reconfigure(self, *args, **kwargs):367 pass368 369 # You can close through sys.stderr.close_log()370 def close_log(self):371 sys.stderr = original_stderr372 sys.stdout = original_stdout373 log_file.close()374 375 def close_log():376 sys.stderr = original_stderr377 sys.stdout = original_stdout378 log_file.close()379 380 381 if enable_file_logging:382 sys.stdout = ComfyUIManagerLogger(True)383 stderr_wrapper = ComfyUIManagerLogger(False)384 sys.stderr = stderr_wrapper385 386 atexit.register(close_log)387 else:388 sys.stdout.close_log = lambda: None389 stderr_wrapper = None390 391 392 class LoggingHandler(logging.Handler):393 def emit(self, record):394 global is_start_mode395 396 message = record.getMessage()397 398 if is_start_mode:399 match = re.search(pat_import_fail, message)400 if match:401 import_failed_extensions.add(match.group(1).strip())402 403 if 'Traceback' in message:404 file_lists = self._extract_file_paths(message)405 origin_info = extract_origin_module_from_strings(file_lists)406 if origin_info is not None:407 name, origin_path = origin_info408 409 if name != 'comfyui-manager':410 if name not in cm_global.error_dict:411 cm_global.error_dict[name] = {'name': name, 'path': origin_path, 'msg': ''}412 413 cm_global.error_dict[name]['msg'] += message414 415 if 'Starting server' in message:416 is_start_mode = False417 finalize_startup()418 419 if stderr_wrapper:420 stderr_wrapper.sync_write(message+'\n', file_only=True)421 422 def _extract_file_paths(self, msg):423 file_paths = []424 for line in msg.split('\n'):425 match = re.findall(r'File \"(.*?)\", line \d+', line)426 for x in match:427 if not x.startswith('<'):428 file_paths.extend(match)429 return file_paths430 431 432 logging.getLogger().addHandler(LoggingHandler())433 434 435except Exception as e:436 print(f"[ComfyUI-Manager] Logging failed: {e}")437 438 439def ensure_dependencies():440 try:441 import git # noqa: F401442 import toml # noqa: F401443 import rich # noqa: F401444 import chardet # noqa: F401445 except ModuleNotFoundError:446 my_path = os.path.dirname(__file__)447 requirements_path = os.path.join(my_path, "requirements.txt")448 449 print("## ComfyUI-Manager: installing dependencies. (GitPython)")450 try:451 subprocess.check_output(manager_util.make_pip_cmd(['install', '-r', requirements_path]))452 except subprocess.CalledProcessError:453 print("## [ERROR] ComfyUI-Manager: Attempting to reinstall dependencies using an alternative method.")454 try:455 subprocess.check_output(manager_util.make_pip_cmd(['install', '--user', '-r', requirements_path]))456 except subprocess.CalledProcessError:457 print("## [ERROR] ComfyUI-Manager: Failed to install the GitPython package in the correct Python environment. Please install it manually in the appropriate environment. (You can seek help at https://app.element.io/#/room/%23comfyui_space%3Amatrix.org)")458 459 try:460 print("## ComfyUI-Manager: installing dependencies done.")461 except:462 # maybe we should sys.exit() here? there is at least two screens worth of error messages still being pumped after our error messages463 print("## [ERROR] ComfyUI-Manager: GitPython package seems to be installed, but failed to load somehow. Make sure you have a working git client installed")464 465ensure_dependencies()466 467 468print("** ComfyUI startup time:", current_timestamp())469print("** Platform:", platform.system())470print("** Python version:", sys.version)471print("** Python executable:", sys.executable)472print("** ComfyUI Path:", comfy_path)473print("** ComfyUI Base Folder Path:", comfy_base_path)474print("** User directory:", folder_paths.user_directory)475print("** ComfyUI-Manager config path:", manager_config_path)476 477 478if log_path_base is not None:479 print("** Log path:", os.path.abspath(f'{log_path_base}.log'))480else:481 print("** Log path: file logging is disabled")482 483 484def read_downgrade_blacklist():485 try:486 if 'downgrade_blacklist' in default_conf:487 items = default_conf['downgrade_blacklist'].split(',')488 items = [x.strip() for x in items if x != '']489 cm_global.pip_downgrade_blacklist += items490 cm_global.pip_downgrade_blacklist = list(set(cm_global.pip_downgrade_blacklist))491 except:492 pass493 494 495read_downgrade_blacklist()496 497 498def check_bypass_ssl():499 try:500 import ssl501 if 'bypass_ssl' in default_conf and default_conf['bypass_ssl'].lower() == 'true':502 print(f"[ComfyUI-Manager] WARN: Unsafe - SSL verification bypass option is Enabled. (see {manager_config_path})")503 ssl._create_default_https_context = ssl._create_unverified_context # SSL certificate error fix.504 except Exception:505 pass506 507check_bypass_ssl()508 509 510# Perform install511processed_install = set()512script_list_path = os.path.join(folder_paths.user_directory, "default", "ComfyUI-Manager", "startup-scripts", "install-scripts.txt")513pip_fixer = manager_util.PIPFixer(manager_util.get_installed_packages(), comfy_path, manager_files_path)514 515 516def is_installed(name):517 name = name.strip()518 519 if name.startswith('#'):520 return True521 522 pattern = r'([^<>!~=]+)([<>!~=]=?)([0-9.a-zA-Z]*)'523 match = re.search(pattern, name)524 525 if match:526 name = match.group(1)527 528 if name in cm_global.pip_blacklist:529 return True530 531 if name in cm_global.pip_downgrade_blacklist:532 pips = manager_util.get_installed_packages()533 534 if match is None:535 if name in pips:536 return True537 elif match.group(2) in ['<=', '==', '<', '~=']:538 if name in pips:539 if manager_util.StrictVersion(pips[name]) >= manager_util.StrictVersion(match.group(3)):540 print(f"[ComfyUI-Manager] skip black listed pip installation: '{name}'")541 return True542 543 pkg = manager_util.get_installed_packages().get(name.lower())544 if pkg is None:545 return False # update if not installed546 547 if match is None:548 return True # don't update if version is not specified549 550 if match.group(2) in ['>', '>=']:551 if manager_util.StrictVersion(pkg) < manager_util.StrictVersion(match.group(3)):552 return False553 elif manager_util.StrictVersion(pkg) > manager_util.StrictVersion(match.group(3)):554 print(f"[SKIP] Downgrading pip package isn't allowed: {name.lower()} (cur={pkg})")555 556 if match.group(2) == '==':557 if manager_util.StrictVersion(pkg) < manager_util.StrictVersion(match.group(3)):558 return False559 560 if match.group(2) == '~=':561 if manager_util.StrictVersion(pkg) == manager_util.StrictVersion(match.group(3)):562 return False563 564 return True # prevent downgrade565 566 567if os.path.exists(restore_snapshot_path):568 try:569 cloned_repos = []570 571 def msg_capture(stream, prefix):572 stream.reconfigure(encoding=locale.getpreferredencoding(), errors='replace')573 for msg in stream:574 if msg.startswith("CLONE: "):575 cloned_repos.append(msg[7:])576 if prefix == '[!]':577 print(prefix, msg, end="", file=sys.stderr)578 else:579 print(prefix, msg, end="")580 581 elif prefix == '[!]' and ('it/s]' in msg or 's/it]' in msg) and ('%|' in msg or 'it [' in msg):582 if msg.startswith('100%'):583 print('\r' + msg, end="", file=sys.stderr),584 else:585 print('\r'+msg[:-1], end="", file=sys.stderr),586 else:587 if prefix == '[!]':588 print(prefix, msg, end="", file=sys.stderr)589 else:590 print(prefix, msg, end="")591 592 print("[ComfyUI-Manager] Restore snapshot.")593 new_env = os.environ.copy()594 if 'COMFYUI_FOLDERS_BASE_PATH' not in new_env:595 new_env["COMFYUI_FOLDERS_BASE_PATH"] = comfy_path596 597 cmd_str = [sys.executable, cm_cli_path, 'restore-snapshot', restore_snapshot_path]598 exit_code = process_wrap(cmd_str, custom_nodes_base_path, handler=msg_capture, env=new_env)599 600 if exit_code != 0:601 print("[ComfyUI-Manager] Restore snapshot failed.")602 else:603 print("[ComfyUI-Manager] Restore snapshot done.")604 605 except Exception as e:606 print(e)607 print("[ComfyUI-Manager] Restore snapshot failed.")608 609 os.remove(restore_snapshot_path)610 611 612def execute_lazy_install_script(repo_path, executable):613 global processed_install614 615 install_script_path = os.path.join(repo_path, "install.py")616 requirements_path = os.path.join(repo_path, "requirements.txt")617 618 if os.path.exists(requirements_path):619 print(f"Install: pip packages for '{repo_path}'")620 621 lines = manager_util.robust_readlines(requirements_path)622 for line in lines:623 package_name = remap_pip_package(line.strip())624 if package_name and not is_installed(package_name):625 if '--index-url' in package_name:626 s = package_name.split('--index-url')627 install_cmd = manager_util.make_pip_cmd(["install", s[0].strip(), '--index-url', s[1].strip()])628 else:629 install_cmd = manager_util.make_pip_cmd(["install", package_name])630 631 process_wrap(install_cmd, repo_path)632 633 if os.path.exists(install_script_path) and f'{repo_path}/install.py' not in processed_install:634 processed_install.add(f'{repo_path}/install.py')635 print(f"Install: install script for '{repo_path}'")636 install_cmd = [executable, "install.py"]637 638 new_env = os.environ.copy()639 if 'COMFYUI_FOLDERS_BASE_PATH' not in new_env:640 new_env["COMFYUI_FOLDERS_BASE_PATH"] = comfy_path641 process_wrap(install_cmd, repo_path, env=new_env)642 643 644def execute_lazy_cnr_switch(target, zip_url, from_path, to_path, no_deps, custom_nodes_path):645 import uuid646 import shutil647 648 # 1. download649 archive_name = f"CNR_temp_{str(uuid.uuid4())}.zip" # should be unpredictable name - security precaution650 download_path = os.path.join(custom_nodes_path, archive_name)651 manager_downloader.download_url(zip_url, custom_nodes_path, archive_name)652 653 # 2. extract files into <node_id>@<cur_ver>654 extracted = manager_util.extract_package_as_zip(download_path, from_path)655 os.remove(download_path)656 657 if extracted is None:658 if len(os.listdir(from_path)) == 0:659 shutil.rmtree(from_path)660 661 print(f'Empty archive file: {target}')662 return False663 664 665 # 3. calculate garbage files (.tracking - extracted)666 tracking_info_file = os.path.join(from_path, '.tracking')667 prev_files = set()668 with open(tracking_info_file, 'r') as f:669 for line in f:670 prev_files.add(line.strip())671 garbage = prev_files.difference(extracted)672 garbage = [os.path.join(custom_nodes_path, x) for x in garbage]673 674 # 4-1. remove garbage files675 for x in garbage:676 if os.path.isfile(x):677 os.remove(x)678 679 # 4-2. remove garbage dir if empty680 for x in garbage:681 if os.path.isdir(x):682 if not os.listdir(x):683 os.rmdir(x)684 685 # 5. rename dir name <node_id>@<prev_ver> ==> <node_id>@<cur_ver>686 print(f"'{from_path}' is moved to '{to_path}'")687 shutil.move(from_path, to_path)688 689 # 6. create .tracking file690 tracking_info_file = os.path.join(to_path, '.tracking')691 with open(tracking_info_file, "w", encoding='utf-8') as file:692 file.write('\n'.join(list(extracted)))693 694 695script_executed = False696 697def execute_startup_script():698 global script_executed699 print("\n#######################################################################")700 print("[ComfyUI-Manager] Starting dependency installation/(de)activation for the extension\n")701 702 custom_nodelist_cache = None703 704 def get_custom_node_paths():705 nonlocal custom_nodelist_cache706 if custom_nodelist_cache is None:707 custom_nodelist_cache = set()708 for base in folder_paths.get_folder_paths('custom_nodes'):709 for x in os.listdir(base):710 fullpath = os.path.join(base, x)711 if os.path.isdir(fullpath):712 custom_nodelist_cache.add(fullpath)713 714 return custom_nodelist_cache715 716 def execute_lazy_delete(path):717 # Validate to prevent arbitrary paths from being deleted718 if path not in get_custom_node_paths():719 logging.error(f"## ComfyUI-Manager: The scheduled '{path}' is not a custom node path, so the deletion has been canceled.")720 return721 722 if not os.path.exists(path):723 logging.info(f"## ComfyUI-Manager: SKIP-DELETE => '{path}' (already deleted)")724 return725 726 try:727 shutil.rmtree(path)728 logging.info(f"## ComfyUI-Manager: DELETE => '{path}'")729 except Exception as e:730 logging.error(f"## ComfyUI-Manager: Failed to delete '{path}' ({e})")731 732 executed = set()733 # Read each line from the file and convert it to a list using eval734 with open(script_list_path, 'r', encoding="UTF-8", errors="ignore") as file:735 for line in file:736 if line in executed:737 continue738 739 executed.add(line)740 741 try:742 script = ast.literal_eval(line)743 744 if script[1].startswith('#') and script[1] != '#FORCE':745 if script[1] == "#LAZY-INSTALL-SCRIPT":746 execute_lazy_install_script(script[0], script[2])747 748 elif script[1] == "#LAZY-CNR-SWITCH-SCRIPT":749 execute_lazy_cnr_switch(script[0], script[2], script[3], script[4], script[5], script[6])750 execute_lazy_install_script(script[3], script[7])751 752 elif script[1] == "#LAZY-DELETE-NODEPACK":753 execute_lazy_delete(script[2])754 755 elif os.path.exists(script[0]):756 if script[1] == "#FORCE":757 del script[1]758 else:759 if 'pip' in script[1:] and 'install' in script[1:] and is_installed(script[-1]):760 continue761 762 print(f"\n## ComfyUI-Manager: EXECUTE => {script[1:]}")763 print(f"\n## Execute management script for '{script[0]}'")764 765 new_env = os.environ.copy()766 if 'COMFYUI_FOLDERS_BASE_PATH' not in new_env:767 new_env["COMFYUI_FOLDERS_BASE_PATH"] = comfy_path768 exit_code = process_wrap(script[1:], script[0], env=new_env)769 770 if exit_code != 0:771 print(f"management script failed: {script[0]}")772 else:773 print(f"\n## ComfyUI-Manager: CANCELED => {script[1:]}")774 775 except Exception as e:776 print(f"[ERROR] Failed to execute management script: {line} / {e}")777 778 # Remove the script_list_path file779 if os.path.exists(script_list_path):780 script_executed = True781 os.remove(script_list_path)782 783 print("\n[ComfyUI-Manager] Startup script completed.")784 print("#######################################################################\n")785 786 787# Check if script_list_path exists788if os.path.exists(script_list_path):789 execute_startup_script()790 791 792pip_fixer.fix_broken()793 794del processed_install795del pip_fixer796manager_util.clear_pip_cache()797 798if script_executed:799 # Restart800 print("[ComfyUI-Manager] Restarting to reapply dependency installation.")801 802 if '__COMFY_CLI_SESSION__' in os.environ:803 with open(os.path.join(os.environ['__COMFY_CLI_SESSION__'] + '.reboot'), 'w'):804 pass805 806 print("--------------------------------------------------------------------------\n")807 exit(0)808 else:809 sys_argv = sys.argv.copy()810 811 if sys_argv[0].endswith("__main__.py"): # this is a python module812 module_name = os.path.basename(os.path.dirname(sys_argv[0]))813 cmds = [sys.executable, '-m', module_name] + sys_argv[1:]814 elif sys.platform.startswith('win32'):815 cmds = ['"' + sys.executable + '"', '"' + sys_argv[0] + '"'] + sys_argv[1:]816 else:817 cmds = [sys.executable] + sys_argv818 819 print(f"Command: {cmds}", flush=True)820 print("--------------------------------------------------------------------------\n")821 822 os.execv(sys.executable, cmds)823 824 825def check_windows_event_loop_policy():826 try:827 import configparser828 config = configparser.ConfigParser(strict=False)829 config.read(manager_config_path)830 default_conf = config['default']831 832 if 'windows_selector_event_loop_policy' in default_conf and default_conf['windows_selector_event_loop_policy'].lower() == 'true':833 try:834 import asyncio835 import asyncio.windows_events836 asyncio.set_event_loop_policy(asyncio.windows_events.WindowsSelectorEventLoopPolicy())837 print("[ComfyUI-Manager] Windows event loop policy mode enabled")838 except Exception as e:839 print(f"[ComfyUI-Manager] WARN: Windows initialization fail: {e}")840 except Exception:841 pass842 843 844if platform.system() == 'Windows':845 check_windows_event_loop_policy()846 