mirror of
https://git.datalinker.icu/ltdrdata/ComfyUI-Manager
synced 2025-12-08 21:54:26 +08:00
Add NodePackage
This commit is contained in:
parent
f8e5521b50
commit
9d1ef85af8
1
.gitignore
vendored
1
.gitignore
vendored
@ -17,3 +17,4 @@ github-stats-cache.json
|
||||
pip_overrides.json
|
||||
*.json
|
||||
check2.sh
|
||||
/venv/
|
||||
@ -224,7 +224,7 @@ def fix_node(node_spec_str, is_all=False, cnt_msg=''):
|
||||
print(f"ERROR: f{res.msg}")
|
||||
|
||||
|
||||
def uninstall_node(node_spec_str, is_all=False, cnt_msg=''):
|
||||
def uninstall_node(node_spec_str: str, is_all: bool = False, cnt_msg: str = ''):
|
||||
spec = node_spec_str.split('@')
|
||||
if len(spec) == 2 and spec[1] == 'unknown':
|
||||
node_name = spec[0]
|
||||
|
||||
@ -437,6 +437,16 @@ def setup_environment():
|
||||
git.Git().update_environment(GIT_PYTHON_GIT_EXECUTABLE=config['default']['git_exe'])
|
||||
|
||||
|
||||
def is_git_repo(path: str) -> bool:
|
||||
""" Check if the path is a git repository. """
|
||||
try:
|
||||
# Try to create a Repo object from the path
|
||||
_ = git.Repo(path).git_dir
|
||||
return True
|
||||
except git.exc.InvalidGitRepositoryError:
|
||||
return False
|
||||
|
||||
|
||||
setup_environment()
|
||||
|
||||
|
||||
|
||||
@ -32,6 +32,7 @@ import cm_global
|
||||
import cnr_utils
|
||||
import manager_util
|
||||
import manager_downloader
|
||||
from node_package import InstalledNodePackage
|
||||
|
||||
|
||||
version_code = [3, 1]
|
||||
@ -329,6 +330,8 @@ def get_commit_hash(fullpath):
|
||||
|
||||
class UnifiedManager:
|
||||
def __init__(self):
|
||||
self.installed_node_packages: dict[str, InstalledNodePackage] = {}
|
||||
|
||||
self.cnr_inactive_nodes = {} # node_id -> node_version -> fullpath
|
||||
self.nightly_inactive_nodes = {} # node_id -> fullpath
|
||||
self.unknown_inactive_nodes = {} # node_id -> repo url * fullpath
|
||||
@ -462,94 +465,26 @@ class UnifiedManager:
|
||||
else:
|
||||
return "unknown"
|
||||
|
||||
def resolve_id_from_repo(self, fullpath):
|
||||
git_config_path = os.path.join(fullpath, '.git', 'config')
|
||||
def update_cache_at_path(self, fullpath):
|
||||
node_package = InstalledNodePackage.from_fullpath(fullpath)
|
||||
self.installed_node_packages[node_package.id] = node_package
|
||||
|
||||
if not os.path.exists(git_config_path):
|
||||
return None
|
||||
if node_package.is_disabled and node_package.is_unknown:
|
||||
# TODO: figure out where url is used.
|
||||
self.unknown_inactive_nodes[node_package.id] = ('', node_package.fullpath)
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
config.read(git_config_path)
|
||||
if node_package.is_disabled and node_package.is_nightly:
|
||||
self.nightly_inactive_nodes[node_package.id] = node_package.fullpath
|
||||
|
||||
for k, v in config.items():
|
||||
if k.startswith('remote ') and 'url' in v:
|
||||
cnr = self.get_cnr_by_repo(v['url'])
|
||||
if cnr:
|
||||
return "nightly", cnr['id'], v['url']
|
||||
else:
|
||||
return "unknown", v['url'].split('/')[-1], v['url']
|
||||
if node_package.is_enabled:
|
||||
self.active_nodes[node_package.id] = node_package.version, node_package.fullpath
|
||||
|
||||
def resolve_unknown(self, node_id, fullpath):
|
||||
res = self.resolve_id_from_repo(fullpath)
|
||||
if node_package.is_enabled and node_package.is_unknown:
|
||||
# TODO: figure out where url is used.
|
||||
self.unknown_active_nodes[node_package.id] = ('', node_package.fullpath)
|
||||
|
||||
if res is None:
|
||||
self.unknown_inactive_nodes[node_id] = '', fullpath
|
||||
return
|
||||
|
||||
ver_spec, node_id, url = res
|
||||
|
||||
if ver_spec == 'nightly':
|
||||
self.nightly_inactive_nodes[node_id] = fullpath
|
||||
else:
|
||||
self.unknown_inactive_nodes[node_id] = url, fullpath
|
||||
|
||||
def update_cache_at_path(self, fullpath, is_disabled):
|
||||
name = os.path.basename(fullpath)
|
||||
|
||||
if name.endswith(".disabled"):
|
||||
node_spec = name[:-9]
|
||||
is_disabled = True
|
||||
else:
|
||||
node_spec = name
|
||||
|
||||
if '@' in node_spec:
|
||||
node_spec = node_spec.split('@')
|
||||
node_id = node_spec[0]
|
||||
if node_id is None:
|
||||
node_version = 'unknown'
|
||||
else:
|
||||
node_version = node_spec[1].replace("_", ".")
|
||||
|
||||
if node_version != 'unknown':
|
||||
if node_id not in self.cnr_map:
|
||||
# fallback
|
||||
v = node_version
|
||||
|
||||
self.cnr_map[node_id] = {
|
||||
'id': node_id,
|
||||
'name': node_id,
|
||||
'latest_version': {'version': v},
|
||||
'publisher': {'id': 'N/A', 'name': 'N/A'}
|
||||
}
|
||||
|
||||
elif node_version == 'unknown':
|
||||
res = self.resolve_id_from_repo(fullpath)
|
||||
if res is None:
|
||||
print(f"Custom node unresolved: {fullpath}")
|
||||
return
|
||||
|
||||
node_version, node_id, _ = res
|
||||
else:
|
||||
res = self.resolve_id_from_repo(fullpath)
|
||||
if res is None:
|
||||
print(f"Custom node unresolved: {fullpath}")
|
||||
return
|
||||
|
||||
node_version, node_id, _ = res
|
||||
|
||||
if not is_disabled:
|
||||
# active nodes
|
||||
if node_version == 'unknown':
|
||||
self.unknown_active_nodes[node_id] = node_version, fullpath
|
||||
else:
|
||||
self.active_nodes[node_id] = node_version, fullpath
|
||||
else:
|
||||
if node_version == 'unknown':
|
||||
self.resolve_unknown(node_id, fullpath)
|
||||
elif node_version == 'nightly':
|
||||
self.nightly_inactive_nodes[node_id] = fullpath
|
||||
else:
|
||||
self.add_to_cnr_inactive_nodes(node_id, node_version, fullpath)
|
||||
if node_package.is_from_cnr and node_package.is_disabled:
|
||||
self.add_to_cnr_inactive_nodes(node_package.id, node_package.version, node_package.fullpath)
|
||||
|
||||
def is_updatable(self, node_id):
|
||||
cur_ver = self.get_cnr_active_version(node_id)
|
||||
@ -722,7 +657,7 @@ class UnifiedManager:
|
||||
fullpath = os.path.join(custom_nodes_path, x)
|
||||
if os.path.isdir(fullpath):
|
||||
if x not in ['__pycache__', '.disabled']:
|
||||
self.update_cache_at_path(fullpath, is_disabled=False)
|
||||
self.update_cache_at_path(fullpath)
|
||||
|
||||
# reload node status info from custom_nodes/.disabled/*
|
||||
for custom_nodes_path in folder_paths.get_folder_paths('custom_nodes'):
|
||||
@ -731,7 +666,7 @@ class UnifiedManager:
|
||||
for x in os.listdir(disabled_dir):
|
||||
fullpath = os.path.join(disabled_dir, x)
|
||||
if os.path.isdir(fullpath):
|
||||
self.update_cache_at_path(fullpath, is_disabled=True)
|
||||
self.update_cache_at_path(fullpath)
|
||||
|
||||
@staticmethod
|
||||
async def load_nightly(channel, mode):
|
||||
@ -1112,7 +1047,7 @@ class UnifiedManager:
|
||||
|
||||
return result
|
||||
|
||||
def unified_uninstall(self, node_id, is_unknown):
|
||||
def unified_uninstall(self, node_id: str, is_unknown: bool):
|
||||
"""
|
||||
Remove whole installed custom nodes including inactive nodes
|
||||
"""
|
||||
|
||||
70
glob/node_package.py
Normal file
70
glob/node_package.py
Normal file
@ -0,0 +1,70 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
import os
|
||||
|
||||
import toml
|
||||
|
||||
from git_helper import is_git_repo
|
||||
|
||||
|
||||
@dataclass
|
||||
class InstalledNodePackage:
|
||||
"""Information about an installed node package."""
|
||||
|
||||
id: str
|
||||
fullpath: str
|
||||
disabled: bool
|
||||
version: str
|
||||
|
||||
@property
|
||||
def is_unknown(self) -> bool:
|
||||
return self.version == "unknown"
|
||||
|
||||
@property
|
||||
def is_nightly(self) -> bool:
|
||||
return self.version == "nightly"
|
||||
|
||||
@property
|
||||
def is_from_cnr(self) -> bool:
|
||||
return not self.is_unknown and not self.is_nightly
|
||||
|
||||
@property
|
||||
def is_enabled(self) -> bool:
|
||||
return not self.disabled
|
||||
|
||||
@property
|
||||
def is_disabled(self) -> bool:
|
||||
return self.disabled
|
||||
|
||||
@staticmethod
|
||||
def from_fullpath(fullpath: str) -> InstalledNodePackage:
|
||||
parent_folder_name = os.path.split(fullpath)[-2]
|
||||
module_name = os.path.basename(fullpath)
|
||||
pyproject_toml_path = os.path.join(fullpath, "pyproject.toml")
|
||||
|
||||
if module_name.endswith(".disabled"):
|
||||
node_id = module_name[:-9]
|
||||
disabled = True
|
||||
elif parent_folder_name == ".disabled":
|
||||
# Nodes under custom_nodes/.disabled/* are disabled
|
||||
node_id = module_name
|
||||
disabled = True
|
||||
else:
|
||||
node_id = module_name
|
||||
disabled = False
|
||||
|
||||
if is_git_repo(fullpath):
|
||||
version = "nightly"
|
||||
elif os.path.exists(pyproject_toml_path):
|
||||
# Read project.toml to get the version
|
||||
with open(pyproject_toml_path, "r", encoding="utf-8") as f:
|
||||
pyproject_toml = toml.load(f)
|
||||
# Fallback to 'unknown' if project.version doesn't exist
|
||||
version = pyproject_toml.get("project", {}).get("version", "unknown")
|
||||
else:
|
||||
version = "unknown"
|
||||
|
||||
return InstalledNodePackage(
|
||||
id=node_id, fullpath=fullpath, disabled=disabled, version=version
|
||||
)
|
||||
@ -47,7 +47,7 @@ class WorkflowMetadataExtension {
|
||||
const modules = nodeData.python_module.split(".");
|
||||
|
||||
if (modules[0] === "custom_nodes") {
|
||||
const nodePackageName = modules[1].split("@")[0];
|
||||
const nodePackageName = modules[1];
|
||||
const nodeVersion = this.installedNodeVersions[nodePackageName];
|
||||
nodeVersions[nodePackageName] = nodeVersion;
|
||||
} else if (["nodes", "comfy_extras"].includes(modules[0])) {
|
||||
|
||||
@ -6,3 +6,4 @@ huggingface-hub>0.20
|
||||
typer
|
||||
rich
|
||||
typing-extensions
|
||||
toml
|
||||
Loading…
x
Reference in New Issue
Block a user