mirror of
https://github.com/Comfy-Org/ComfyUI-Manager.git
synced 2025-12-16 18:02:58 +08:00
Remove package-level caching in cnr_utils and node_package modules to enable proper dynamic custom node installation and version switching without ComfyUI server restarts. Key Changes: - Remove @lru_cache decorators from version-sensitive functions - Remove cached_property from NodePackage for dynamic state updates - Add comprehensive test suite with parallel execution support - Implement version switching tests (CNR ↔ Nightly) - Add case sensitivity integration tests - Improve error handling and logging API Priority Rules (manager_core.py:1801): - Enabled-Priority: Show only enabled version when both exist - CNR-Priority: Show only CNR when both CNR and Nightly are disabled - Prevents duplicate package entries in /v2/customnode/installed API - Cross-match using cnr_id and aux_id for CNR ↔ Nightly detection Test Infrastructure: - 8 test files with 59 comprehensive test cases - Parallel test execution across 5 isolated environments - Automated test scripts with environment setup - Configurable timeout (60 minutes default) - Support for both master and dr-support-pip-cm branches Bug Fixes: - Fix COMFYUI_CUSTOM_NODES_PATH environment variable export - Resolve test fixture regression with module-level variables - Fix import timing issues in test configuration - Register pytest integration marker to eliminate warnings - Fix POSIX compliance in shell scripts (((var++)) → $((var + 1))) Documentation: - CNR_VERSION_MANAGEMENT_DESIGN.md v1.0 → v1.1 with API priority rules - Add test guides and execution documentation (TESTING_PROMPT.md) - Add security-enhanced installation guide - Create CLI migration guides and references - Document package version management 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
103 lines
3.4 KiB
Python
103 lines
3.4 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
import os
|
|
|
|
from .git_utils import get_commit_hash
|
|
|
|
|
|
@dataclass
|
|
class InstalledNodePackage:
|
|
"""Information about an installed node package."""
|
|
|
|
id: str
|
|
fullpath: str
|
|
disabled: bool
|
|
version: str
|
|
repo_url: str = None # Git repository URL for nightly packages
|
|
|
|
@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
|
|
|
|
def get_commit_hash(self) -> str:
|
|
return get_commit_hash(self.fullpath)
|
|
|
|
def isValid(self) -> bool:
|
|
if self.is_from_cnr:
|
|
return os.path.exists(os.path.join(self.fullpath, '.tracking'))
|
|
|
|
return True
|
|
|
|
@staticmethod
|
|
def from_fullpath(fullpath: str, resolve_from_path) -> InstalledNodePackage:
|
|
from . import git_utils
|
|
|
|
parent_folder_name = os.path.basename(os.path.dirname(fullpath))
|
|
module_name = os.path.basename(fullpath)
|
|
|
|
if module_name.endswith(".disabled"):
|
|
node_id = module_name[:-9]
|
|
disabled = True
|
|
elif parent_folder_name == ".disabled":
|
|
# Nodes under custom_nodes/.disabled/* are disabled
|
|
# Parse directory name format: packagename@version
|
|
# Examples:
|
|
# comfyui_sigmoidoffsetscheduler@nightly → id: comfyui_sigmoidoffsetscheduler, version: nightly
|
|
# comfyui_sigmoidoffsetscheduler@1_0_2 → id: comfyui_sigmoidoffsetscheduler, version: 1.0.2
|
|
node_id = module_name
|
|
disabled = True
|
|
else:
|
|
node_id = module_name
|
|
disabled = False
|
|
|
|
info = resolve_from_path(fullpath)
|
|
repo_url = None
|
|
version_from_dirname = None
|
|
|
|
# For disabled packages, try to extract version from directory name
|
|
if disabled and parent_folder_name == ".disabled" and '@' in module_name:
|
|
parts = module_name.split('@')
|
|
if len(parts) == 2:
|
|
node_id = parts[0] # Use the normalized name from directory
|
|
version_from_dirname = parts[1].replace('_', '.') # Convert 1_0_2 → 1.0.2
|
|
|
|
if info is None:
|
|
version = version_from_dirname if version_from_dirname else 'unknown'
|
|
else:
|
|
node_id = info['id'] # robust module guessing
|
|
# Prefer version from directory name for disabled packages (preserves 'nightly' literal)
|
|
# Otherwise use version from package inspection (commit hash for git repos)
|
|
if version_from_dirname:
|
|
version = version_from_dirname
|
|
else:
|
|
version = info['ver']
|
|
|
|
# Get repository URL for both nightly and CNR packages
|
|
if version == 'nightly':
|
|
# For nightly packages, get repo URL from git
|
|
repo_url = git_utils.git_url(fullpath)
|
|
elif 'url' in info and info['url']:
|
|
# For CNR packages, get repo URL from pyproject.toml
|
|
repo_url = info['url']
|
|
|
|
return InstalledNodePackage(
|
|
id=node_id, fullpath=fullpath, disabled=disabled, version=version, repo_url=repo_url
|
|
)
|