feat: support extra_model_paths.yaml - custom_nodes

This commit is contained in:
Dr.Lt.Data 2024-11-29 02:43:02 +09:00
parent fa357479ef
commit 76b073c366
2 changed files with 131 additions and 71 deletions

View File

@ -23,13 +23,35 @@ sys.path.append(glob_path)
import cm_global import cm_global
from manager_util import * from manager_util import *
version = [2, 52, 1] version = [2, 53]
version_str = f"V{version[0]}.{version[1]}" + (f'.{version[2]}' if len(version) > 2 else '') 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__), '..')) comfyui_manager_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
custom_nodes_path = os.path.abspath(os.path.join(comfyui_manager_path, '..')) custom_nodes_path = os.path.abspath(os.path.join(comfyui_manager_path, '..'))
default_custom_nodes_path = None
def get_default_custom_nodes_path():
global default_custom_nodes_path
if default_custom_nodes_path is None:
try:
import folder_paths
default_custom_nodes_path = folder_paths.get_folder_paths("custom_nodes")[0]
except:
default_custom_nodes_path = custom_nodes_path
return default_custom_nodes_path
def get_custom_nodes_paths():
try:
import folder_paths
return folder_paths.get_folder_paths("custom_nodes")
except:
return [custom_nodes_path]
comfy_path = os.environ.get('COMFYUI_PATH') comfy_path = os.environ.get('COMFYUI_PATH')
if comfy_path is None: if comfy_path is None:
comfy_path = os.path.abspath(os.path.join(custom_nodes_path, '..')) comfy_path = os.path.abspath(os.path.join(custom_nodes_path, '..'))
@ -340,7 +362,7 @@ def __win_check_git_update(path, do_fetch=False, do_update=False):
new_env = os.environ.copy() new_env = os.environ.copy()
new_env["COMFYUI_PATH"] = comfy_path new_env["COMFYUI_PATH"] = comfy_path
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=custom_nodes_path) process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=get_default_custom_nodes_path())
output, _ = process.communicate() output, _ = process.communicate()
output = output.decode('utf-8').strip() output = output.decode('utf-8').strip()
@ -394,7 +416,7 @@ def __win_check_git_pull(path):
new_env = os.environ.copy() new_env = os.environ.copy()
new_env["COMFYUI_PATH"] = comfy_path new_env["COMFYUI_PATH"] = comfy_path
command = [sys.executable, git_script_path, "--pull", path] command = [sys.executable, git_script_path, "--pull", path]
process = subprocess.Popen(command, env=new_env, cwd=custom_nodes_path) process = subprocess.Popen(command, env=new_env, cwd=get_default_custom_nodes_path())
process.wait() process.wait()
@ -562,11 +584,11 @@ def gitclone_install(files, instant_execution=False, msg_prefix=''):
try: try:
print(f"Download: git clone '{url}'") print(f"Download: git clone '{url}'")
repo_name = os.path.splitext(os.path.basename(url))[0] repo_name = os.path.splitext(os.path.basename(url))[0]
repo_path = os.path.join(custom_nodes_path, repo_name) repo_path = os.path.join(get_default_custom_nodes_path(), repo_name)
# Clone the repository from the remote URL # Clone the repository from the remote URL
if not instant_execution and platform.system() == 'Windows': if not instant_execution and platform.system() == 'Windows':
res = manager_funcs.run_script([sys.executable, git_script_path, "--clone", custom_nodes_path, url], cwd=custom_nodes_path) res = manager_funcs.run_script([sys.executable, git_script_path, "--clone", get_default_custom_nodes_path(), url], cwd=get_default_custom_nodes_path())
if res != 0: if res != 0:
return False return False
else: else:
@ -690,6 +712,22 @@ async def get_data_by_mode(mode, filename, channel_url=None):
return json_obj return json_obj
def lookup_installed_custom_nodes(repo_name):
try:
import folder_paths
base_paths = folder_paths.get_folder_paths("custom_nodes")
except:
base_paths = [custom_nodes_path]
for base_path in base_paths:
repo_path = os.path.join(base_path, repo_name)
if os.path.exists(repo_path):
return True, repo_path
elif os.path.exists(repo_path+'.disabled'):
return False, repo_path
return None
def gitclone_fix(files, instant_execution=False): def gitclone_fix(files, instant_execution=False):
print(f"Try fixing: {files}") print(f"Try fixing: {files}")
for url in files: for url in files:
@ -701,13 +739,15 @@ def gitclone_fix(files, instant_execution=False):
url = url[:-1] url = url[:-1]
try: try:
repo_name = os.path.splitext(os.path.basename(url))[0] repo_name = os.path.splitext(os.path.basename(url))[0]
repo_path = os.path.join(custom_nodes_path, repo_name) repo_path = lookup_installed_custom_nodes(repo_name)
if os.path.exists(repo_path+'.disabled'): if repo_path is not None:
repo_path = repo_path+'.disabled' repo_path = repo_path[1]
if not execute_install_script(url, repo_path, instant_execution=instant_execution): if not execute_install_script(url, repo_path, instant_execution=instant_execution):
return False return False
else:
print(f"Custom node not found: {repo_name}")
except Exception as e: except Exception as e:
print(f"Install(git-clone) error: {url} / {e}", file=sys.stderr) print(f"Install(git-clone) error: {url} / {e}", file=sys.stderr)
@ -754,12 +794,12 @@ def gitclone_uninstall(files):
url = url[:-1] url = url[:-1]
try: try:
dir_name = os.path.splitext(os.path.basename(url))[0].replace(".git", "") dir_name = os.path.splitext(os.path.basename(url))[0].replace(".git", "")
dir_path = os.path.join(custom_nodes_path, dir_name) repo_path = lookup_installed_custom_nodes(dir_name)
# safety check if repo_path is None:
if dir_path == '/' or dir_path[1:] == ":/" or dir_path == '': continue
print(f"Uninstall(git-clone) error: invalid path '{dir_path}' for '{url}'")
return False dir_path = repo_path[1]
install_script_path = os.path.join(dir_path, "uninstall.py") install_script_path = os.path.join(dir_path, "uninstall.py")
disable_script_path = os.path.join(dir_path, "disable.py") disable_script_path = os.path.join(dir_path, "disable.py")
@ -775,10 +815,7 @@ def gitclone_uninstall(files):
if code != 0: if code != 0:
print(f"An error occurred during the execution of the disable.py script. Only the '{dir_path}' will be deleted.") print(f"An error occurred during the execution of the disable.py script. Only the '{dir_path}' will be deleted.")
if os.path.exists(dir_path): rmtree(dir_path)
rmtree(dir_path)
elif os.path.exists(dir_path + ".disabled"):
rmtree(dir_path + ".disabled")
except Exception as e: except Exception as e:
print(f"Uninstall(git-clone) error: {url} / {e}", file=sys.stderr) print(f"Uninstall(git-clone) error: {url} / {e}", file=sys.stderr)
return False return False
@ -801,13 +838,13 @@ def gitclone_set_active(files, is_disable):
url = url[:-1] url = url[:-1]
try: try:
dir_name = os.path.splitext(os.path.basename(url))[0].replace(".git", "") dir_name = os.path.splitext(os.path.basename(url))[0].replace(".git", "")
dir_path = os.path.join(custom_nodes_path, dir_name) repo_path = lookup_installed_custom_nodes(dir_name)
# safety check if repo_path is None:
if dir_path == '/' or dir_path[1:] == ":/" or dir_path == '': continue
print(f"{action_name}(git-clone) error: invalid path '{dir_path}' for '{url}'")
return False
dir_path = repo_path[1]
if is_disable: if is_disable:
current_path = dir_path current_path = dir_path
new_path = dir_path + ".disabled" new_path = dir_path + ".disabled"
@ -843,11 +880,13 @@ def gitclone_update(files, instant_execution=False, skip_script=False, msg_prefi
url = url[:-1] url = url[:-1]
try: try:
repo_name = os.path.splitext(os.path.basename(url))[0].replace(".git", "") repo_name = os.path.splitext(os.path.basename(url))[0].replace(".git", "")
repo_path = os.path.join(custom_nodes_path, repo_name) repo_path = lookup_installed_custom_nodes(repo_name)
if os.path.exists(repo_path+'.disabled'): if repo_path is None:
repo_path = repo_path+'.disabled' continue
repo_path = repo_path[1]
git_pull(repo_path) git_pull(repo_path)
if not skip_script: if not skip_script:
@ -917,10 +956,14 @@ def lookup_customnode_by_url(data, target):
for x in data['custom_nodes']: for x in data['custom_nodes']:
if target in x['files']: if target in x['files']:
dir_name = os.path.splitext(os.path.basename(target))[0].replace(".git", "") dir_name = os.path.splitext(os.path.basename(target))[0].replace(".git", "")
dir_path = os.path.join(custom_nodes_path, dir_name) repo_path = lookup_installed_custom_nodes(dir_name)
if os.path.exists(dir_path):
if repo_path is None:
continue
if repo_path[0]:
x['installed'] = 'True' x['installed'] = 'True'
elif os.path.exists(dir_path + ".disabled"): else:
x['installed'] = 'Disabled' x['installed'] = 'Disabled'
return x return x
@ -929,13 +972,15 @@ def lookup_customnode_by_url(data, target):
def simple_check_custom_node(url): def simple_check_custom_node(url):
dir_name = os.path.splitext(os.path.basename(url))[0].replace(".git", "") dir_name = os.path.splitext(os.path.basename(url))[0].replace(".git", "")
dir_path = os.path.join(custom_nodes_path, dir_name) repo_path = lookup_installed_custom_nodes(dir_name)
if os.path.exists(dir_path):
return 'installed'
elif os.path.exists(dir_path+'.disabled'):
return 'disabled'
return 'not-installed' if repo_path is None:
return 'not-installed'
if repo_path[0]:
return 'installed'
else:
return 'disabled'
def check_a_custom_node_installed(item, do_fetch=False, do_update_check=True, do_update=False): def check_a_custom_node_installed(item, do_fetch=False, do_update_check=True, do_update=False):
@ -948,8 +993,12 @@ def check_a_custom_node_installed(item, do_fetch=False, do_update_check=True, do
url = url[:-1] url = url[:-1]
dir_name = os.path.splitext(os.path.basename(url))[0].replace(".git", "") dir_name = os.path.splitext(os.path.basename(url))[0].replace(".git", "")
dir_path = os.path.join(custom_nodes_path, dir_name) repo_path = lookup_installed_custom_nodes(dir_name)
if os.path.exists(dir_path):
if repo_path is None:
item['installed'] = 'False'
elif repo_path[0]:
dir_path = repo_path[1]
try: try:
item['installed'] = 'True' # default item['installed'] = 'True' # default
@ -968,17 +1017,23 @@ def check_a_custom_node_installed(item, do_fetch=False, do_update_check=True, do
else: else:
item['installed'] = 'True' item['installed'] = 'True'
elif os.path.exists(dir_path + ".disabled"):
item['installed'] = 'Disabled'
else: else:
item['installed'] = 'False' item['installed'] = 'Disabled'
elif item['install_type'] == 'copy' and len(item['files']) == 1: elif item['install_type'] == 'copy' and len(item['files']) == 1:
dir_name = os.path.basename(item['files'][0]) dir_name = os.path.basename(item['files'][0])
if item['files'][0].endswith('.py'): if item['files'][0].endswith('.py'):
base_path = custom_nodes_path base_path = lookup_installed_custom_nodes(item['files'][0])
if base_path is None:
item['installed'] = 'False'
return
elif base_path[0]:
item['installed'] = 'True'
else:
item['installed'] = 'Disabled'
return
elif 'js_path' in item: elif 'js_path' in item:
base_path = os.path.join(js_path, item['js_path']) base_path = os.path.join(js_path, item['js_path'])
else: else:
@ -990,8 +1045,6 @@ def check_a_custom_node_installed(item, do_fetch=False, do_update_check=True, do
item['installed'] = 'Fail' item['installed'] = 'Fail'
else: else:
item['installed'] = 'True' item['installed'] = 'True'
elif os.path.exists(file_path + ".disabled"):
item['installed'] = 'Disabled'
else: else:
item['installed'] = 'False' item['installed'] = 'False'
@ -1028,39 +1081,46 @@ def get_current_snapshot():
git_custom_nodes = {} git_custom_nodes = {}
file_custom_nodes = [] file_custom_nodes = []
try:
import folder_paths
base_paths = folder_paths.get_folder_paths("custom_nodes")
except:
base_paths = [custom_nodes_path]
# Get custom nodes hash # Get custom nodes hash
for path in os.listdir(custom_nodes_path): for base_path in base_paths:
fullpath = os.path.join(custom_nodes_path, path) for path in os.listdir(base_path):
fullpath = os.path.join(base_path, path)
if os.path.isdir(fullpath): if os.path.isdir(fullpath):
is_disabled = path.endswith(".disabled") is_disabled = path.endswith(".disabled")
try: try:
git_dir = os.path.join(fullpath, '.git') git_dir = os.path.join(fullpath, '.git')
if not os.path.exists(git_dir): if not os.path.exists(git_dir):
continue continue
repo = git.Repo(fullpath) repo = git.Repo(fullpath)
commit_hash = repo.head.commit.hexsha commit_hash = repo.head.commit.hexsha
url = repo.remotes.origin.url url = repo.remotes.origin.url
git_custom_nodes[url] = { git_custom_nodes[url] = {
'hash': commit_hash, 'hash': commit_hash,
'disabled': is_disabled
}
except:
print(f"Failed to extract snapshots for the custom node '{path}'.")
elif path.endswith('.py'):
is_disabled = path.endswith(".py.disabled")
filename = os.path.basename(path)
item = {
'filename': filename,
'disabled': is_disabled 'disabled': is_disabled
} }
except: file_custom_nodes.append(item)
print(f"Failed to extract snapshots for the custom node '{path}'.")
elif path.endswith('.py'):
is_disabled = path.endswith(".py.disabled")
filename = os.path.basename(path)
item = {
'filename': filename,
'disabled': is_disabled
}
file_custom_nodes.append(item)
pip_packages = get_installed_pip_packages() pip_packages = get_installed_pip_packages()

View File

@ -1,7 +1,7 @@
[project] [project]
name = "comfyui-manager" 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." description = "ComfyUI-Manager provides features to install and manage custom nodes for ComfyUI, as well as various functionalities to assist with ComfyUI."
version = "2.52.1" version = "2.53"
license = { file = "LICENSE.txt" } license = { file = "LICENSE.txt" }
dependencies = ["GitPython", "PyGithub", "matrix-client==0.4.0", "transformers", "huggingface-hub>0.20", "typer", "rich", "typing-extensions"] dependencies = ["GitPython", "PyGithub", "matrix-client==0.4.0", "transformers", "huggingface-hub>0.20", "typer", "rich", "typing-extensions"]