fixed: robust rmtree for windows environment

- reserve for deletion upon restart if a permission error occurs during rmtree

https://github.com/ltdrdata/ComfyUI-Manager/issues/1579
This commit is contained in:
Dr.Lt.Data 2025-03-03 21:34:38 +09:00
parent c150eec2b6
commit 1248bd0413
3 changed files with 70 additions and 18 deletions

View File

@ -42,7 +42,7 @@ import manager_downloader
from node_package import InstalledNodePackage
version_code = [3, 27, 7]
version_code = [3, 27, 8]
version_str = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' if len(version_code) > 2 else '')
@ -1173,14 +1173,14 @@ class UnifiedManager:
ver_and_path = self.active_nodes.get(node_id)
if ver_and_path is not None and os.path.exists(ver_and_path[1]):
shutil.rmtree(ver_and_path[1])
try_rmtree(node_id, ver_and_path[1])
result.items.append(ver_and_path)
del self.active_nodes[node_id]
# remove from nightly inactives
fullpath = self.nightly_inactive_nodes.get(node_id)
if fullpath is not None and os.path.exists(fullpath):
shutil.rmtree(fullpath)
try_rmtree(node_id, fullpath)
result.items.append(('nightly', fullpath))
del self.nightly_inactive_nodes[node_id]
@ -1188,7 +1188,7 @@ class UnifiedManager:
ver_map = self.cnr_inactive_nodes.get(node_id)
if ver_map is not None:
for key, fullpath in ver_map.items():
shutil.rmtree(fullpath)
try_rmtree(node_id, fullpath)
result.items.append((key, fullpath))
del self.cnr_inactive_nodes[node_id]
@ -1750,18 +1750,29 @@ def switch_to_default_branch(repo):
return False
def reserve_script(repo_path, install_cmds):
if not os.path.exists(manager_startup_script_path):
os.makedirs(manager_startup_script_path)
script_path = os.path.join(manager_startup_script_path, "install-scripts.txt")
with open(script_path, "a") as file:
obj = [repo_path] + install_cmds
file.write(f"{obj}\n")
def try_rmtree(title, fullpath):
try:
shutil.rmtree(fullpath)
except Exception as e:
logging.warning(f"[ComfyUI-Manager] An error occurred while deleting '{fullpath}', so it has been scheduled for deletion upon restart.\nEXCEPTION: {e}")
reserve_script(title, ["#LAZY-DELETE-NODEPACK", fullpath])
def try_install_script(url, repo_path, install_cmd, instant_execution=False):
if not instant_execution and (
(len(install_cmd) > 0 and install_cmd[0].startswith('#')) or platform.system() == "Windows" or get_config()['always_lazy_install']
):
if not os.path.exists(manager_startup_script_path):
os.makedirs(manager_startup_script_path)
script_path = os.path.join(manager_startup_script_path, "install-scripts.txt")
with open(script_path, "a") as file:
obj = [repo_path] + install_cmd
file.write(f"{obj}\n")
reserve_script(repo_path, install_cmd)
return True
else:
if len(install_cmd) == 5 and install_cmd[2:4] == ['pip', 'install']:

View File

@ -1,4 +1,5 @@
import os
import shutil
import subprocess
import sys
import atexit
@ -695,13 +696,44 @@ def execute_migration(moves):
shutil.move(x[0], x[1])
print(f"[ComfyUI-Manager] MIGRATION: '{x[0]}' -> '{x[1]}'")
script_executed = False
# Check if script_list_path exists
if os.path.exists(script_list_path):
def execute_startup_script():
global script_executed
print("\n#######################################################################")
print("[ComfyUI-Manager] Starting dependency installation/(de)activation for the extension\n")
custom_nodelist_cache = None
def get_custom_node_paths():
nonlocal custom_nodelist_cache
if custom_nodelist_cache is None:
custom_nodelist_cache = set()
for base in folder_paths.get_folder_paths('custom_nodes'):
for x in os.listdir(base):
fullpath = os.path.join(base, x)
if os.path.isdir(fullpath):
custom_nodelist_cache.add(fullpath)
return custom_nodelist_cache
def execute_lazy_delete(path):
# Validate to prevent arbitrary paths from being deleted
if path not in get_custom_node_paths():
logging.error(f"## ComfyUI-Manager: The scheduled '{path}' is not a custom node path, so the deletion has been canceled.")
return
if not os.path.exists(path):
logging.info(f"## ComfyUI-Manager: SKIP-DELETE => '{path}' (already deleted)")
return
try:
shutil.rmtree(path)
logging.info(f"## ComfyUI-Manager: DELETE => '{path}'")
except Exception as e:
logging.error(f"## ComfyUI-Manager: Failed to delete '{path}' ({e})")
executed = set()
# Read each line from the file and convert it to a list using eval
with open(script_list_path, 'r', encoding="UTF-8", errors="ignore") as file:
@ -725,6 +757,9 @@ if os.path.exists(script_list_path):
elif script[1] == "#LAZY-MIGRATION":
execute_migration(script[2])
elif script[1] == "#LAZY-DELETE-NODEPACK":
execute_lazy_delete(script[2])
elif os.path.exists(script[0]):
if script[1] == "#FORCE":
del script[1]
@ -733,7 +768,7 @@ if os.path.exists(script_list_path):
continue
print(f"\n## ComfyUI-Manager: EXECUTE => {script[1:]}")
print(f"\n## Execute install/(de)activation script for '{script[0]}'")
print(f"\n## Execute management script for '{script[0]}'")
new_env = os.environ.copy()
if 'COMFYUI_FOLDERS_BASE_PATH' not in new_env:
@ -741,12 +776,12 @@ if os.path.exists(script_list_path):
exit_code = process_wrap(script[1:], script[0], env=new_env)
if exit_code != 0:
print(f"install/(de)activation script failed: {script[0]}")
print(f"management script failed: {script[0]}")
else:
print(f"\n## ComfyUI-Manager: CANCELED => {script[1:]}")
except Exception as e:
print(f"[ERROR] Failed to execute install/(de)activation script: {line} / {e}")
print(f"[ERROR] Failed to execute management script: {line} / {e}")
# Remove the script_list_path file
if os.path.exists(script_list_path):
@ -756,6 +791,12 @@ if os.path.exists(script_list_path):
print("\n[ComfyUI-Manager] Startup script completed.")
print("#######################################################################\n")
# Check if script_list_path exists
if os.path.exists(script_list_path):
execute_startup_script()
pip_fixer.fix_broken()
del processed_install

View File

@ -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.27.7"
version = "3.27.8"
license = { file = "LICENSE.txt" }
dependencies = ["GitPython", "PyGithub", "matrix-client==0.4.0", "transformers", "huggingface-hub>0.20", "typer", "rich", "typing-extensions", "toml", "uv", "chardet"]