mirror of
https://github.com/Comfy-Org/ComfyUI-Manager.git
synced 2025-12-17 02:12:58 +08:00
implement: support --user-directory
This commit is contained in:
parent
602d04e236
commit
31de8ffc3d
232
cm-cli.py
232
cm-cli.py
@ -13,13 +13,30 @@ from typing_extensions import List, Annotated
|
||||
import re
|
||||
import git
|
||||
|
||||
|
||||
sys.path.append(os.path.dirname(__file__))
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), "glob"))
|
||||
|
||||
import manager_util
|
||||
|
||||
comfy_path = os.environ.get('COMFYUI_PATH')
|
||||
if comfy_path is None:
|
||||
try:
|
||||
import folder_paths
|
||||
comfy_path = os.path.join(os.path.dirname(folder_paths.__file__))
|
||||
except:
|
||||
comfy_path = os.path.abspath(os.path.join(manager_util.comfyui_manager_path, '..', '..'))
|
||||
|
||||
sys.path.append(comfy_path)
|
||||
|
||||
import utils.extra_config
|
||||
import cm_global
|
||||
import manager_core as core
|
||||
from manager_core import unified_manager
|
||||
import cnr_utils
|
||||
|
||||
|
||||
|
||||
comfyui_manager_path = os.path.abspath(os.path.dirname(__file__))
|
||||
comfy_path = os.environ.get('COMFYUI_PATH')
|
||||
|
||||
@ -27,21 +44,14 @@ if comfy_path is None:
|
||||
print("\n[bold yellow]WARN: The `COMFYUI_PATH` environment variable is not set. Assuming `custom_nodes/ComfyUI-Manager/../../` as the ComfyUI path.[/bold yellow]", file=sys.stderr)
|
||||
comfy_path = os.path.abspath(os.path.join(comfyui_manager_path, '..', '..'))
|
||||
|
||||
startup_script_path = os.path.join(comfyui_manager_path, "startup-scripts")
|
||||
custom_nodes_path = os.path.join(comfy_path, 'custom_nodes')
|
||||
|
||||
script_path = os.path.join(startup_script_path, "install-scripts.txt")
|
||||
restore_snapshot_path = os.path.join(startup_script_path, "restore-snapshot.json")
|
||||
pip_overrides_path = os.path.join(comfyui_manager_path, "pip_overrides.json")
|
||||
git_script_path = os.path.join(comfyui_manager_path, "git_helper.py")
|
||||
|
||||
cm_global.pip_blacklist = ['torch', 'torchsde', 'torchvision']
|
||||
cm_global.pip_downgrade_blacklist = ['torch', 'torchsde', 'torchvision', 'transformers', 'safetensors', 'kornia']
|
||||
cm_global.pip_overrides = {}
|
||||
if os.path.exists(pip_overrides_path):
|
||||
with open(pip_overrides_path, 'r', encoding="UTF-8", errors="ignore") as json_file:
|
||||
cm_global.pip_overrides = {'numpy': 'numpy<2'}
|
||||
|
||||
if os.path.exists(os.path.join(manager_util.comfyui_manager_path, "pip_overrides.json")):
|
||||
with open(os.path.join(manager_util.comfyui_manager_path, "pip_overrides.json"), 'r', encoding="UTF-8", errors="ignore") as json_file:
|
||||
cm_global.pip_overrides = json.load(json_file)
|
||||
cm_global.pip_overrides['numpy'] = 'numpy<2'
|
||||
|
||||
|
||||
def check_comfyui_hash():
|
||||
@ -82,6 +92,8 @@ class Ctx:
|
||||
self.channel = 'default'
|
||||
self.no_deps = False
|
||||
self.mode = 'cache'
|
||||
self.user_directory = None
|
||||
self.custom_nodes_paths = [os.path.join(core.comfy_path, 'custom_nodes')]
|
||||
|
||||
def set_channel_mode(self, channel, mode):
|
||||
if mode is not None:
|
||||
@ -104,14 +116,45 @@ class Ctx:
|
||||
def set_no_deps(self, no_deps):
|
||||
self.no_deps = no_deps
|
||||
|
||||
def set_user_directory(self, user_directory):
|
||||
if user_directory is None:
|
||||
return
|
||||
|
||||
channel_ctx = Ctx()
|
||||
extra_model_paths_yaml = os.path.join(user_directory, 'extra_model_paths.yaml')
|
||||
if os.path.exists(extra_model_paths_yaml):
|
||||
utils.extra_config.load_extra_path_config(extra_model_paths_yaml)
|
||||
|
||||
core.update_user_directory(user_directory)
|
||||
|
||||
if os.path.exists(core.manager_pip_overrides_path):
|
||||
cm_global.pip_overrides = {'numpy': 'numpy<2'}
|
||||
with open(core.manager_pip_overrides_path, 'r', encoding="UTF-8", errors="ignore") as json_file:
|
||||
cm_global.pip_overrides = json.load(json_file)
|
||||
|
||||
@staticmethod
|
||||
def get_startup_scripts_path():
|
||||
return os.path.join(core.manager_startup_script_path, "install-scripts.txt")
|
||||
|
||||
@staticmethod
|
||||
def get_restore_snapshot_path():
|
||||
return os.path.join(core.manager_startup_script_path, "restore-snapshot.json")
|
||||
|
||||
@staticmethod
|
||||
def get_snapshot_path():
|
||||
return core.manager_snapshot_path
|
||||
|
||||
@staticmethod
|
||||
def get_custom_nodes_paths():
|
||||
return folder_paths.get_folder_paths('custom_nodes')
|
||||
|
||||
|
||||
cmd_ctx = Ctx()
|
||||
|
||||
|
||||
def install_node(node_spec_str, is_all=False, cnt_msg=''):
|
||||
if core.is_valid_url(node_spec_str):
|
||||
# install via urls
|
||||
res = asyncio.run(core.gitclone_install(node_spec_str, no_deps=channel_ctx.no_deps))
|
||||
res = asyncio.run(core.gitclone_install(node_spec_str, no_deps=cmd_ctx.no_deps))
|
||||
if not res.result:
|
||||
print(res.msg)
|
||||
print(f"[bold red]ERROR: An error occurred while installing '{node_spec_str}'.[/bold red]")
|
||||
@ -129,7 +172,7 @@ def install_node(node_spec_str, is_all=False, cnt_msg=''):
|
||||
if not is_specified:
|
||||
version_spec = None
|
||||
|
||||
res = asyncio.run(unified_manager.install_by_id(node_name, version_spec, channel_ctx.channel, channel_ctx.mode, instant_execution=True, no_deps=channel_ctx.no_deps))
|
||||
res = asyncio.run(unified_manager.install_by_id(node_name, version_spec, cmd_ctx.channel, cmd_ctx.mode, instant_execution=True, no_deps=cmd_ctx.no_deps))
|
||||
|
||||
if res.action == 'skip':
|
||||
print(f"{cnt_msg} [ SKIP ] {node_name:50} => Already installed")
|
||||
@ -175,7 +218,7 @@ def fix_node(node_spec_str, is_all=False, cnt_msg=''):
|
||||
node_name, version_spec, _ = node_spec
|
||||
|
||||
print(f"{cnt_msg} [ FIXING ]: {node_name:50}[{version_spec}]")
|
||||
res = unified_manager.unified_fix(node_name, version_spec, no_deps=channel_ctx.no_deps)
|
||||
res = unified_manager.unified_fix(node_name, version_spec, no_deps=cmd_ctx.no_deps)
|
||||
|
||||
if not res.result:
|
||||
print(f"ERROR: f{res.msg}")
|
||||
@ -215,7 +258,7 @@ def update_node(node_spec_str, is_all=False, cnt_msg=''):
|
||||
|
||||
node_name, version_spec, _ = node_spec
|
||||
|
||||
res = unified_manager.unified_update(node_name, version_spec, no_deps=channel_ctx.no_deps, return_postinstall=True)
|
||||
res = unified_manager.unified_update(node_name, version_spec, no_deps=cmd_ctx.no_deps, return_postinstall=True)
|
||||
|
||||
if not res.result:
|
||||
print(f"ERROR: An error occurred while updating '{node_name}'.")
|
||||
@ -333,7 +376,7 @@ def disable_node(node_spec_str: str, is_all=False, cnt_msg=''):
|
||||
|
||||
|
||||
def show_list(kind, simple=False):
|
||||
custom_nodes = asyncio.run(unified_manager.get_custom_nodes(channel=channel_ctx.channel, mode=channel_ctx.mode))
|
||||
custom_nodes = asyncio.run(unified_manager.get_custom_nodes(channel=cmd_ctx.channel, mode=cmd_ctx.mode))
|
||||
|
||||
# collect not-installed unknown nodes
|
||||
not_installed_unknown_nodes = []
|
||||
@ -454,7 +497,7 @@ def show_snapshot(simple_mode=False):
|
||||
|
||||
|
||||
def show_snapshot_list(simple_mode=False):
|
||||
snapshot_path = os.path.join(comfyui_manager_path, 'snapshots')
|
||||
snapshot_path = cmd_ctx.get_snapshot_path()
|
||||
|
||||
files = os.listdir(snapshot_path)
|
||||
json_files = [x for x in files if x.endswith('.json')]
|
||||
@ -463,11 +506,11 @@ def show_snapshot_list(simple_mode=False):
|
||||
|
||||
|
||||
def cancel():
|
||||
if os.path.exists(script_path):
|
||||
os.remove(script_path)
|
||||
if os.path.exists(cmd_ctx.get_startup_scripts_path()):
|
||||
os.remove(cmd_ctx.get_startup_scripts_path())
|
||||
|
||||
if os.path.exists(restore_snapshot_path):
|
||||
os.remove(restore_snapshot_path)
|
||||
if os.path.exists(cmd_ctx.get_restore_snapshot_path()):
|
||||
os.remove(cmd_ctx.get_restore_snapshot_path())
|
||||
|
||||
|
||||
def auto_save_snapshot():
|
||||
@ -562,9 +605,14 @@ def install(
|
||||
help="Skip installing any Python dependencies",
|
||||
),
|
||||
] = False,
|
||||
user_directory: str = typer.Option(
|
||||
None,
|
||||
help="user directory"
|
||||
),
|
||||
):
|
||||
channel_ctx.set_channel_mode(channel, mode)
|
||||
channel_ctx.set_no_deps(no_deps)
|
||||
cmd_ctx.set_user_directory(user_directory)
|
||||
cmd_ctx.set_channel_mode(channel, mode)
|
||||
cmd_ctx.set_no_deps(no_deps)
|
||||
for_each_nodes(nodes, act=install_node)
|
||||
|
||||
|
||||
@ -592,9 +640,14 @@ def reinstall(
|
||||
help="Skip installing any Python dependencies",
|
||||
),
|
||||
] = False,
|
||||
user_directory: str = typer.Option(
|
||||
None,
|
||||
help="user directory"
|
||||
),
|
||||
):
|
||||
channel_ctx.set_channel_mode(channel, mode)
|
||||
channel_ctx.set_no_deps(no_deps)
|
||||
cmd_ctx.set_user_directory(user_directory)
|
||||
cmd_ctx.set_channel_mode(channel, mode)
|
||||
cmd_ctx.set_no_deps(no_deps)
|
||||
for_each_nodes(nodes, act=reinstall_node)
|
||||
|
||||
|
||||
@ -615,7 +668,7 @@ def uninstall(
|
||||
help="[remote|local|cache]"
|
||||
),
|
||||
):
|
||||
channel_ctx.set_channel_mode(channel, mode)
|
||||
cmd_ctx.set_channel_mode(channel, mode)
|
||||
for_each_nodes(nodes, act=uninstall_node)
|
||||
|
||||
|
||||
@ -636,8 +689,13 @@ def update(
|
||||
None,
|
||||
help="[remote|local|cache]"
|
||||
),
|
||||
user_directory: str = typer.Option(
|
||||
None,
|
||||
help="user directory"
|
||||
),
|
||||
):
|
||||
channel_ctx.set_channel_mode(channel, mode)
|
||||
cmd_ctx.set_user_directory(user_directory)
|
||||
cmd_ctx.set_channel_mode(channel, mode)
|
||||
|
||||
if 'all' in nodes:
|
||||
auto_save_snapshot()
|
||||
@ -667,8 +725,13 @@ def disable(
|
||||
None,
|
||||
help="[remote|local|cache]"
|
||||
),
|
||||
user_directory: str = typer.Option(
|
||||
None,
|
||||
help="user directory"
|
||||
),
|
||||
):
|
||||
channel_ctx.set_channel_mode(channel, mode)
|
||||
cmd_ctx.set_user_directory(user_directory)
|
||||
cmd_ctx.set_channel_mode(channel, mode)
|
||||
|
||||
if 'all' in nodes:
|
||||
auto_save_snapshot()
|
||||
@ -693,8 +756,13 @@ def enable(
|
||||
None,
|
||||
help="[remote|local|cache]"
|
||||
),
|
||||
user_directory: str = typer.Option(
|
||||
None,
|
||||
help="user directory"
|
||||
),
|
||||
):
|
||||
channel_ctx.set_channel_mode(channel, mode)
|
||||
cmd_ctx.set_user_directory(user_directory)
|
||||
cmd_ctx.set_channel_mode(channel, mode)
|
||||
|
||||
if 'all' in nodes:
|
||||
auto_save_snapshot()
|
||||
@ -719,8 +787,13 @@ def fix(
|
||||
None,
|
||||
help="[remote|local|cache]"
|
||||
),
|
||||
user_directory: str = typer.Option(
|
||||
None,
|
||||
help="user directory"
|
||||
),
|
||||
):
|
||||
channel_ctx.set_channel_mode(channel, mode)
|
||||
cmd_ctx.set_user_directory(user_directory)
|
||||
cmd_ctx.set_channel_mode(channel, mode)
|
||||
|
||||
if 'all' in nodes:
|
||||
auto_save_snapshot()
|
||||
@ -754,6 +827,10 @@ def show(
|
||||
None,
|
||||
help="[remote|local|cache]"
|
||||
),
|
||||
user_directory: str = typer.Option(
|
||||
None,
|
||||
help="user directory"
|
||||
),
|
||||
):
|
||||
valid_commands = [
|
||||
"installed",
|
||||
@ -769,7 +846,8 @@ def show(
|
||||
typer.echo(f"Invalid command: `show {arg}`", err=True)
|
||||
exit(1)
|
||||
|
||||
channel_ctx.set_channel_mode(channel, mode)
|
||||
cmd_ctx.set_user_directory(user_directory)
|
||||
cmd_ctx.set_channel_mode(channel, mode)
|
||||
if arg == 'snapshot':
|
||||
show_snapshot()
|
||||
elif arg == 'snapshot-list':
|
||||
@ -794,6 +872,10 @@ def simple_show(
|
||||
None,
|
||||
help="[remote|local|cache]"
|
||||
),
|
||||
user_directory: str = typer.Option(
|
||||
None,
|
||||
help="user directory"
|
||||
),
|
||||
):
|
||||
valid_commands = [
|
||||
"installed",
|
||||
@ -808,7 +890,9 @@ def simple_show(
|
||||
typer.echo(f"[bold red]Invalid command: `show {arg}`[/bold red]", err=True)
|
||||
exit(1)
|
||||
|
||||
channel_ctx.set_channel_mode(channel, mode)
|
||||
cmd_ctx.set_user_directory(user_directory)
|
||||
cmd_ctx.set_channel_mode(channel, mode)
|
||||
|
||||
if arg == 'snapshot':
|
||||
show_snapshot(True)
|
||||
elif arg == 'snapshot-list':
|
||||
@ -821,8 +905,15 @@ def simple_show(
|
||||
def cli_only_mode(
|
||||
mode: str = typer.Argument(
|
||||
..., help="[enable|disable]"
|
||||
)):
|
||||
cli_mode_flag = os.path.join(os.path.dirname(__file__), '.enable-cli-only-mode')
|
||||
),
|
||||
user_directory: str = typer.Option(
|
||||
None,
|
||||
help="user directory"
|
||||
)
|
||||
):
|
||||
cmd_ctx.set_user_directory(user_directory)
|
||||
cli_mode_flag = os.path.join(cmd_ctx.manager_files_directory, '.enable-cli-only-mode')
|
||||
|
||||
if mode.lower() == 'enable':
|
||||
with open(cli_mode_flag, 'w'):
|
||||
pass
|
||||
@ -857,8 +948,13 @@ def deps_in_workflow(
|
||||
None,
|
||||
help="[remote|local|cache]"
|
||||
),
|
||||
user_directory: str = typer.Option(
|
||||
None,
|
||||
help="user directory"
|
||||
)
|
||||
):
|
||||
channel_ctx.set_channel_mode(channel, mode)
|
||||
cmd_ctx.set_user_directory(user_directory)
|
||||
cmd_ctx.set_channel_mode(channel, mode)
|
||||
|
||||
input_path = workflow
|
||||
output_path = output
|
||||
@ -867,7 +963,7 @@ def deps_in_workflow(
|
||||
print(f"[bold red]File not found: {input_path}[/bold red]")
|
||||
exit(1)
|
||||
|
||||
used_exts, unknown_nodes = asyncio.run(core.extract_nodes_from_workflow(input_path, mode=channel_ctx.mode, channel_url=channel_ctx.channel))
|
||||
used_exts, unknown_nodes = asyncio.run(core.extract_nodes_from_workflow(input_path, mode=cmd_ctx.mode, channel_url=cmd_ctx.channel))
|
||||
|
||||
custom_nodes = {}
|
||||
for x in used_exts:
|
||||
@ -894,7 +990,13 @@ def save_snapshot(
|
||||
show_default=False, help="Specify the output file path. (.json/.yaml)"
|
||||
),
|
||||
] = None,
|
||||
user_directory: str = typer.Option(
|
||||
None,
|
||||
help="user directory"
|
||||
)
|
||||
):
|
||||
cmd_ctx.set_user_directory(user_directory)
|
||||
|
||||
path = core.save_snapshot_with_postfix('snapshot', output)
|
||||
print(f"Current snapshot is saved as `{path}`")
|
||||
|
||||
@ -920,7 +1022,13 @@ def restore_snapshot(
|
||||
is_flag=True,
|
||||
help="Restore for pip packages specified by local paths.",
|
||||
),
|
||||
user_directory: str = typer.Option(
|
||||
None,
|
||||
help="user directory"
|
||||
)
|
||||
):
|
||||
cmd_ctx.set_user_directory(user_directory)
|
||||
|
||||
extras = []
|
||||
if pip_non_url:
|
||||
extras.append('--pip-non-url')
|
||||
@ -936,7 +1044,7 @@ def restore_snapshot(
|
||||
if os.path.exists(snapshot_name):
|
||||
snapshot_path = os.path.abspath(snapshot_name)
|
||||
else:
|
||||
snapshot_path = os.path.join(core.comfyui_manager_path, 'snapshots', snapshot_name)
|
||||
snapshot_path = os.path.join(cmd_ctx.get_snapshot_path(), snapshot_name)
|
||||
if not os.path.exists(snapshot_path):
|
||||
print(f"[bold red]ERROR: `{snapshot_path}` is not exists.[/bold red]")
|
||||
exit(1)
|
||||
@ -952,9 +1060,21 @@ def restore_snapshot(
|
||||
@app.command(
|
||||
"restore-dependencies", help="Restore dependencies from whole installed custom nodes."
|
||||
)
|
||||
def restore_dependencies():
|
||||
node_paths = [os.path.join(custom_nodes_path, name) for name in os.listdir(custom_nodes_path)
|
||||
if os.path.isdir(os.path.join(custom_nodes_path, name)) and not name.endswith('.disabled')]
|
||||
def restore_dependencies(
|
||||
user_directory: str = typer.Option(
|
||||
None,
|
||||
help="user directory"
|
||||
)
|
||||
):
|
||||
cmd_ctx.set_user_directory(user_directory)
|
||||
|
||||
node_paths = []
|
||||
|
||||
for base_path in cmd_ctx.get_custom_nodes_paths():
|
||||
for name in os.listdir(base_path):
|
||||
target = os.path.join(base_path, name)
|
||||
if os.path.isdir(target) and not name.endswith('.disabled'):
|
||||
node_paths.append(target)
|
||||
|
||||
total = len(node_paths)
|
||||
i = 1
|
||||
@ -971,7 +1091,8 @@ def restore_dependencies():
|
||||
def post_install(
|
||||
path: str = typer.Argument(
|
||||
help="path to custom node",
|
||||
)):
|
||||
)
|
||||
):
|
||||
path = os.path.expanduser(path)
|
||||
unified_manager.execute_install_script('', path, instant_execution=True)
|
||||
|
||||
@ -995,8 +1116,13 @@ def install_deps(
|
||||
None,
|
||||
help="[remote|local|cache]"
|
||||
),
|
||||
user_directory: str = typer.Option(
|
||||
None,
|
||||
help="user directory"
|
||||
),
|
||||
):
|
||||
channel_ctx.set_channel_mode(channel, mode)
|
||||
cmd_ctx.set_user_directory(user_directory)
|
||||
cmd_ctx.set_channel_mode(channel, mode)
|
||||
auto_save_snapshot()
|
||||
|
||||
if not os.path.exists(deps):
|
||||
@ -1040,14 +1166,20 @@ def export_custom_node_ids(
|
||||
mode: str = typer.Option(
|
||||
None,
|
||||
help="[remote|local|cache]"
|
||||
)):
|
||||
channel_ctx.set_channel_mode(channel, mode)
|
||||
),
|
||||
user_directory: str = typer.Option(
|
||||
None,
|
||||
help="user directory"
|
||||
),
|
||||
):
|
||||
cmd_ctx.set_user_directory(user_directory)
|
||||
cmd_ctx.set_channel_mode(channel, mode)
|
||||
|
||||
with open(path, "w", encoding='utf-8') as output_file:
|
||||
for x in unified_manager.cnr_map.keys():
|
||||
print(x, file=output_file)
|
||||
|
||||
custom_nodes = asyncio.run(unified_manager.get_custom_nodes(channel=channel_ctx.channel, mode=channel_ctx.mode))
|
||||
custom_nodes = asyncio.run(unified_manager.get_custom_nodes(channel=cmd_ctx.channel, mode=cmd_ctx.mode))
|
||||
for x in custom_nodes.values():
|
||||
if 'cnr_latest' not in x:
|
||||
if len(x['files']) == 1:
|
||||
@ -1063,7 +1195,13 @@ def export_custom_node_ids(
|
||||
"migrate",
|
||||
help="Migrate legacy node system to new node system",
|
||||
)
|
||||
def migrate():
|
||||
def migrate(
|
||||
user_directory: str = typer.Option(
|
||||
None,
|
||||
help="user directory"
|
||||
)
|
||||
):
|
||||
cmd_ctx.set_user_directory(user_directory)
|
||||
asyncio.run(unified_manager.migrate_unmanaged_nodes())
|
||||
|
||||
|
||||
|
||||
@ -326,20 +326,18 @@ def invalidate_custom_node_file(file_custom_node_infos):
|
||||
download_url(url, working_directory)
|
||||
|
||||
|
||||
def apply_snapshot(target):
|
||||
def apply_snapshot(path):
|
||||
try:
|
||||
# todo: should be if target is not in snapshots dir
|
||||
path = os.path.join(os.path.dirname(__file__), 'snapshots', f"{target}")
|
||||
if os.path.exists(path):
|
||||
if not target.endswith('.json') and not target.endswith('.yaml'):
|
||||
if not path.endswith('.json') and not path.endswith('.yaml'):
|
||||
print(f"Snapshot file not found: `{path}`")
|
||||
print("APPLY SNAPSHOT: False")
|
||||
return None
|
||||
|
||||
with open(path, 'r', encoding="UTF-8") as snapshot_file:
|
||||
if target.endswith('.json'):
|
||||
if path.endswith('.json'):
|
||||
info = json.load(snapshot_file)
|
||||
elif target.endswith('.yaml'):
|
||||
elif path.endswith('.yaml'):
|
||||
info = yaml.load(snapshot_file, Loader=yaml.SafeLoader)
|
||||
info = info['custom_nodes']
|
||||
else:
|
||||
|
||||
@ -34,7 +34,7 @@ import manager_util
|
||||
import manager_downloader
|
||||
|
||||
|
||||
version_code = [3, 0]
|
||||
version_code = [3, 1]
|
||||
version_str = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' if len(version_code) > 2 else '')
|
||||
|
||||
|
||||
@ -89,7 +89,6 @@ def check_invalid_nodes():
|
||||
|
||||
try:
|
||||
import folder_paths
|
||||
node_paths = folder_paths.get_folder_paths("custom_nodes")
|
||||
except:
|
||||
try:
|
||||
sys.path.append(comfy_path)
|
||||
@ -140,19 +139,50 @@ if comfy_path is None:
|
||||
comfy_path = os.path.abspath(os.path.join(manager_util.comfyui_manager_path, '..', '..'))
|
||||
|
||||
|
||||
channel_list_template_path = os.path.join(manager_util.comfyui_manager_path, 'channels.list.template')
|
||||
git_script_path = os.path.join(manager_util.comfyui_manager_path, "git_helper.py")
|
||||
|
||||
manager_files_path = None
|
||||
manager_config_path = None
|
||||
manager_channel_list_path = None
|
||||
manager_startup_script_path = None
|
||||
manager_snapshot_path = None
|
||||
manager_pip_overrides_path = None
|
||||
|
||||
def update_user_directory(user_dir):
|
||||
global manager_files_path
|
||||
global manager_config_path
|
||||
global manager_channel_list_path
|
||||
global manager_startup_script_path
|
||||
global manager_snapshot_path
|
||||
global manager_pip_overrides_path
|
||||
|
||||
manager_files_path = os.path.abspath(os.path.join(user_dir, 'default', 'ComfyUI-Manager'))
|
||||
if not os.path.exists(manager_files_path):
|
||||
os.makedirs(manager_files_path)
|
||||
|
||||
manager_snapshot_path = os.path.join(manager_files_path, "snapshots")
|
||||
if not os.path.exists(manager_snapshot_path):
|
||||
os.makedirs(manager_snapshot_path)
|
||||
|
||||
manager_startup_script_path = os.path.join(manager_files_path, "startup-scripts")
|
||||
if not os.path.exists(manager_startup_script_path):
|
||||
os.makedirs(manager_startup_script_path)
|
||||
|
||||
manager_config_path = os.path.join(manager_files_path, 'config.ini')
|
||||
manager_channel_list_path = os.path.join(manager_files_path, 'channels.list')
|
||||
manager_pip_overrides_path = os.path.join(manager_files_path, "pip_overrides.json")
|
||||
|
||||
try:
|
||||
import folder_paths
|
||||
manager_core_config_path = os.path.abspath(os.path.join(folder_paths.get_user_directory(), 'default', 'manager-core.ini'))
|
||||
update_user_directory(folder_paths.get_user_directory())
|
||||
|
||||
except Exception:
|
||||
# fallback:
|
||||
# This case is only possible when running with cm-cli, and in practice, this case is not actually used.
|
||||
manager_core_config_path = os.path.abspath(os.path.join(manager_util.comfyui_manager_path, 'manager-core.ini'))
|
||||
update_user_directory(os.path.abspath(manager_util.comfyui_manager_path))
|
||||
|
||||
|
||||
channel_list_path = os.path.join(manager_util.comfyui_manager_path, 'channels.list')
|
||||
config_path = os.path.join(manager_util.comfyui_manager_path, "config.ini")
|
||||
startup_script_path = os.path.join(manager_util.comfyui_manager_path, "startup-scripts")
|
||||
git_script_path = os.path.join(manager_util.comfyui_manager_path, "git_helper.py")
|
||||
cached_config = None
|
||||
js_path = None
|
||||
|
||||
@ -785,7 +815,7 @@ class UnifiedManager:
|
||||
return True
|
||||
|
||||
def reserve_cnr_switch(self, target, zip_url, from_path, to_path, no_deps):
|
||||
script_path = os.path.join(startup_script_path, "install-scripts.txt")
|
||||
script_path = os.path.join(manager_startup_script_path, "install-scripts.txt")
|
||||
with open(script_path, "a") as file:
|
||||
obj = [target, "#LAZY-CNR-SWITCH-SCRIPT", zip_url, from_path, to_path, no_deps, get_default_custom_nodes_path(), sys.executable]
|
||||
file.write(f"{obj}\n")
|
||||
@ -795,7 +825,7 @@ class UnifiedManager:
|
||||
return True
|
||||
|
||||
def reserve_migration(self, moves):
|
||||
script_path = os.path.join(startup_script_path, "install-scripts.txt")
|
||||
script_path = os.path.join(manager_startup_script_path, "install-scripts.txt")
|
||||
with open(script_path, "a") as file:
|
||||
obj = ["", "#LAZY-MIGRATION", moves]
|
||||
file.write(f"{obj}\n")
|
||||
@ -1402,10 +1432,10 @@ def get_channel_dict():
|
||||
if channel_dict is None:
|
||||
channel_dict = {}
|
||||
|
||||
if not os.path.exists(channel_list_path):
|
||||
shutil.copy(channel_list_path+'.template', channel_list_path)
|
||||
if not os.path.exists(manager_channel_list_path):
|
||||
shutil.copy(channel_list_template_path, manager_channel_list_path)
|
||||
|
||||
with open(os.path.join(manager_util.comfyui_manager_path, 'channels.list'), 'r') as file:
|
||||
with open(manager_channel_list_path, 'r') as file:
|
||||
channels = file.read()
|
||||
for x in channels.split('\n'):
|
||||
channel_info = x.split("::")
|
||||
@ -1468,18 +1498,18 @@ def write_config():
|
||||
'skip_migration_check': get_config()['skip_migration_check'],
|
||||
}
|
||||
|
||||
directory = os.path.dirname(manager_core_config_path)
|
||||
directory = os.path.dirname(manager_config_path)
|
||||
if not os.path.exists(directory):
|
||||
os.makedirs(directory)
|
||||
|
||||
with open(manager_core_config_path, 'w') as configfile:
|
||||
with open(manager_config_path, 'w') as configfile:
|
||||
config.write(configfile)
|
||||
|
||||
|
||||
def read_config():
|
||||
try:
|
||||
config = configparser.ConfigParser()
|
||||
config.read(config_path)
|
||||
config.read(manager_config_path)
|
||||
default_conf = config['default']
|
||||
|
||||
# policy migration: disable_unsecure_features -> security_level
|
||||
@ -1545,10 +1575,10 @@ def switch_to_default_branch(repo):
|
||||
|
||||
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" and comfy_ui_commit_datetime.date() >= comfy_ui_required_commit_datetime.date())):
|
||||
if not os.path.exists(startup_script_path):
|
||||
os.makedirs(startup_script_path)
|
||||
if not os.path.exists(manager_startup_script_path):
|
||||
os.makedirs(manager_startup_script_path)
|
||||
|
||||
script_path = os.path.join(startup_script_path, "install-scripts.txt")
|
||||
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")
|
||||
@ -2377,7 +2407,7 @@ def save_snapshot_with_postfix(postfix, path=None):
|
||||
date_time_format = now.strftime("%Y-%m-%d_%H-%M-%S")
|
||||
file_name = f"{date_time_format}_{postfix}"
|
||||
|
||||
path = os.path.join(manager_util.comfyui_manager_path, 'snapshots', f"{file_name}.json")
|
||||
path = os.path.join(manager_snapshot_path, f"{file_name}.json")
|
||||
else:
|
||||
file_name = path.replace('\\', '/').split('/')[-1]
|
||||
file_name = file_name.split('.')[-2]
|
||||
|
||||
@ -634,8 +634,7 @@ async def fetch_externalmodel_list(request):
|
||||
|
||||
@PromptServer.instance.routes.get("/snapshot/getlist")
|
||||
async def get_snapshot_list(request):
|
||||
snapshots_directory = os.path.join(manager_util.comfyui_manager_path, 'snapshots')
|
||||
items = [f[:-5] for f in os.listdir(snapshots_directory) if f.endswith('.json')]
|
||||
items = [f[:-5] for f in os.listdir(core.manager_snapshot_path) if f.endswith('.json')]
|
||||
items.sort(reverse=True)
|
||||
return web.json_response({'items': items}, content_type='application/json')
|
||||
|
||||
@ -649,7 +648,7 @@ async def remove_snapshot(request):
|
||||
try:
|
||||
target = request.rel_url.query["target"]
|
||||
|
||||
path = os.path.join(manager_util.comfyui_manager_path, 'snapshots', f"{target}.json")
|
||||
path = os.path.join(core.manager_snapshot_path, f"{target}.json")
|
||||
if os.path.exists(path):
|
||||
os.remove(path)
|
||||
|
||||
@ -667,12 +666,12 @@ async def restore_snapshot(request):
|
||||
try:
|
||||
target = request.rel_url.query["target"]
|
||||
|
||||
path = os.path.join(manager_util.comfyui_manager_path, 'snapshots', f"{target}.json")
|
||||
path = os.path.join(core.manager_snapshot_path, f"{target}.json")
|
||||
if os.path.exists(path):
|
||||
if not os.path.exists(core.startup_script_path):
|
||||
os.makedirs(core.startup_script_path)
|
||||
if not os.path.exists(core.manager_startup_script_path):
|
||||
os.makedirs(core.manager_startup_script_path)
|
||||
|
||||
target_path = os.path.join(core.startup_script_path, "restore-snapshot.json")
|
||||
target_path = os.path.join(core.manager_startup_script_path, "restore-snapshot.json")
|
||||
shutil.copy(path, target_path)
|
||||
|
||||
print(f"Snapshot restore scheduled: `{target}`")
|
||||
@ -1399,7 +1398,7 @@ async def default_cache_update():
|
||||
|
||||
threading.Thread(target=lambda: asyncio.run(default_cache_update())).start()
|
||||
|
||||
if not os.path.exists(core.config_path):
|
||||
if not os.path.exists(core.manager_config_path):
|
||||
core.get_config()
|
||||
core.write_config()
|
||||
|
||||
@ -1408,5 +1407,5 @@ cm_global.register_extension('ComfyUI-Manager',
|
||||
{'version': core.version,
|
||||
'name': 'ComfyUI Manager',
|
||||
'nodes': {},
|
||||
'description': 'It provides the ability to manage custom nodes in ComfyUI.', })
|
||||
'description': 'This extension provides the ability to manage custom nodes in ComfyUI.', })
|
||||
|
||||
|
||||
@ -65,10 +65,10 @@ async def share_option(request):
|
||||
|
||||
|
||||
def get_openart_auth():
|
||||
if not os.path.exists(os.path.join(core.comfyui_manager_path, ".openart_key")):
|
||||
if not os.path.exists(os.path.join(core.manager_files_path, ".openart_key")):
|
||||
return None
|
||||
try:
|
||||
with open(os.path.join(core.comfyui_manager_path, ".openart_key"), "r") as f:
|
||||
with open(os.path.join(core.manager_files_path, ".openart_key"), "r") as f:
|
||||
openart_key = f.read().strip()
|
||||
return openart_key if openart_key else None
|
||||
except:
|
||||
@ -76,10 +76,10 @@ def get_openart_auth():
|
||||
|
||||
|
||||
def get_matrix_auth():
|
||||
if not os.path.exists(os.path.join(core.comfyui_manager_path, "matrix_auth")):
|
||||
if not os.path.exists(os.path.join(core.manager_files_path, "matrix_auth")):
|
||||
return None
|
||||
try:
|
||||
with open(os.path.join(core.comfyui_manager_path, "matrix_auth"), "r") as f:
|
||||
with open(os.path.join(core.manager_files_path, "matrix_auth"), "r") as f:
|
||||
matrix_auth = f.read()
|
||||
homeserver, username, password = matrix_auth.strip().split("\n")
|
||||
if not homeserver or not username or not password:
|
||||
@ -94,10 +94,10 @@ def get_matrix_auth():
|
||||
|
||||
|
||||
def get_comfyworkflows_auth():
|
||||
if not os.path.exists(os.path.join(core.comfyui_manager_path, "comfyworkflows_sharekey")):
|
||||
if not os.path.exists(os.path.join(core.manager_files_path, "comfyworkflows_sharekey")):
|
||||
return None
|
||||
try:
|
||||
with open(os.path.join(core.comfyui_manager_path, "comfyworkflows_sharekey"), "r") as f:
|
||||
with open(os.path.join(core.manager_files_path, "comfyworkflows_sharekey"), "r") as f:
|
||||
share_key = f.read()
|
||||
if not share_key.strip():
|
||||
return None
|
||||
@ -107,10 +107,10 @@ def get_comfyworkflows_auth():
|
||||
|
||||
|
||||
def get_youml_settings():
|
||||
if not os.path.exists(os.path.join(core.comfyui_manager_path, ".youml")):
|
||||
if not os.path.exists(os.path.join(core.manager_files_path, ".youml")):
|
||||
return None
|
||||
try:
|
||||
with open(os.path.join(core.comfyui_manager_path, ".youml"), "r") as f:
|
||||
with open(os.path.join(core.manager_files_path, ".youml"), "r") as f:
|
||||
youml_settings = f.read().strip()
|
||||
return youml_settings if youml_settings else None
|
||||
except:
|
||||
@ -118,7 +118,7 @@ def get_youml_settings():
|
||||
|
||||
|
||||
def set_youml_settings(settings):
|
||||
with open(os.path.join(core.comfyui_manager_path, ".youml"), "w") as f:
|
||||
with open(os.path.join(core.manager_files_path, ".youml"), "w") as f:
|
||||
f.write(settings)
|
||||
|
||||
|
||||
@ -135,7 +135,7 @@ async def api_get_openart_auth(request):
|
||||
async def api_set_openart_auth(request):
|
||||
json_data = await request.json()
|
||||
openart_key = json_data['openart_key']
|
||||
with open(os.path.join(core.comfyui_manager_path, ".openart_key"), "w") as f:
|
||||
with open(os.path.join(core.manager_files_path, ".openart_key"), "w") as f:
|
||||
f.write(openart_key)
|
||||
return web.Response(status=200)
|
||||
|
||||
@ -178,14 +178,14 @@ async def api_get_comfyworkflows_auth(request):
|
||||
@PromptServer.instance.routes.post("/manager/set_esheep_workflow_and_images")
|
||||
async def set_esheep_workflow_and_images(request):
|
||||
json_data = await request.json()
|
||||
with open(os.path.join(core.comfyui_manager_path, "esheep_share_message.json"), "w", encoding='utf-8') as file:
|
||||
with open(os.path.join(core.manager_files_path, "esheep_share_message.json"), "w", encoding='utf-8') as file:
|
||||
json.dump(json_data, file, indent=4)
|
||||
return web.Response(status=200)
|
||||
|
||||
|
||||
@PromptServer.instance.routes.get("/manager/get_esheep_workflow_and_images")
|
||||
async def get_esheep_workflow_and_images(request):
|
||||
with open(os.path.join(core.comfyui_manager_path, "esheep_share_message.json"), 'r', encoding='utf-8') as file:
|
||||
with open(os.path.join(core.manager_files_path, "esheep_share_message.json"), 'r', encoding='utf-8') as file:
|
||||
data = json.load(file)
|
||||
return web.Response(status=200, text=json.dumps(data))
|
||||
|
||||
@ -194,12 +194,12 @@ def set_matrix_auth(json_data):
|
||||
homeserver = json_data['homeserver']
|
||||
username = json_data['username']
|
||||
password = json_data['password']
|
||||
with open(os.path.join(core.comfyui_manager_path, "matrix_auth"), "w") as f:
|
||||
with open(os.path.join(core.manager_files_path, "matrix_auth"), "w") as f:
|
||||
f.write("\n".join([homeserver, username, password]))
|
||||
|
||||
|
||||
def set_comfyworkflows_auth(comfyworkflows_sharekey):
|
||||
with open(os.path.join(core.comfyui_manager_path, "comfyworkflows_sharekey"), "w") as f:
|
||||
with open(os.path.join(core.manager_files_path, "comfyworkflows_sharekey"), "w") as f:
|
||||
f.write(comfyworkflows_sharekey)
|
||||
|
||||
|
||||
|
||||
@ -18,6 +18,7 @@ import manager_util
|
||||
import cm_global
|
||||
import manager_downloader
|
||||
from datetime import datetime
|
||||
import folder_paths
|
||||
|
||||
security_check.security_check()
|
||||
|
||||
@ -73,17 +74,19 @@ cm_global.register_api('cm.is_import_failed_extension', is_import_failed_extensi
|
||||
|
||||
|
||||
comfyui_manager_path = os.path.abspath(os.path.dirname(__file__))
|
||||
custom_nodes_path = os.path.abspath(os.path.join(comfyui_manager_path, ".."))
|
||||
startup_script_path = os.path.join(comfyui_manager_path, "startup-scripts")
|
||||
restore_snapshot_path = os.path.join(startup_script_path, "restore-snapshot.json")
|
||||
|
||||
custom_nodes_base_path = folder_paths.get_folder_paths('custom_nodes')[0]
|
||||
manager_files_path = os.path.abspath(os.path.join(folder_paths.get_user_directory(), 'default', 'ComfyUI-Manager'))
|
||||
manager_pip_overrides_path = os.path.join(manager_files_path, "pip_overrides.json")
|
||||
restore_snapshot_path = os.path.join(manager_files_path, "startup-scripts", "restore-snapshot.json")
|
||||
|
||||
git_script_path = os.path.join(comfyui_manager_path, "git_helper.py")
|
||||
cm_cli_path = os.path.join(comfyui_manager_path, "cm-cli.py")
|
||||
pip_overrides_path = os.path.join(comfyui_manager_path, "pip_overrides.json")
|
||||
|
||||
|
||||
cm_global.pip_overrides = {}
|
||||
if os.path.exists(pip_overrides_path):
|
||||
with open(pip_overrides_path, 'r', encoding="UTF-8", errors="ignore") as json_file:
|
||||
if os.path.exists(manager_pip_overrides_path):
|
||||
with open(manager_pip_overrides_path, 'r', encoding="UTF-8", errors="ignore") as json_file:
|
||||
cm_global.pip_overrides = json.load(json_file)
|
||||
cm_global.pip_overrides['numpy'] = 'numpy<2'
|
||||
cm_global.pip_overrides['ultralytics'] = 'ultralytics==8.3.40' # for security
|
||||
@ -146,15 +149,18 @@ try:
|
||||
postfix = ""
|
||||
|
||||
# Logger setup
|
||||
log_path_base = None
|
||||
if enable_file_logging:
|
||||
if os.path.exists(f"comfyui{postfix}.log"):
|
||||
if os.path.exists(f"comfyui{postfix}.prev.log"):
|
||||
if os.path.exists(f"comfyui{postfix}.prev2.log"):
|
||||
os.remove(f"comfyui{postfix}.prev2.log")
|
||||
os.rename(f"comfyui{postfix}.prev.log", f"comfyui{postfix}.prev2.log")
|
||||
os.rename(f"comfyui{postfix}.log", f"comfyui{postfix}.prev.log")
|
||||
log_path_base = os.path.join(folder_paths.user_directory, 'comfyui')
|
||||
|
||||
log_file = open(f"comfyui{postfix}.log", "w", encoding="utf-8", errors="ignore")
|
||||
if os.path.exists(f"{log_path_base}{postfix}.log"):
|
||||
if os.path.exists(f"{log_path_base}{postfix}.prev.log"):
|
||||
if os.path.exists(f"{log_path_base}{postfix}.prev2.log"):
|
||||
os.remove(f"{log_path_base}{postfix}.prev2.log")
|
||||
os.rename(f"{log_path_base}{postfix}.prev.log", f"{log_path_base}{postfix}.prev2.log")
|
||||
os.rename(f"{log_path_base}{postfix}.log", f"{log_path_base}{postfix}.prev.log")
|
||||
|
||||
log_file = open(f"{log_path_base}{postfix}.log", "w", encoding="utf-8", errors="ignore")
|
||||
|
||||
log_lock = threading.Lock()
|
||||
|
||||
@ -339,8 +345,8 @@ print("** Python version:", sys.version)
|
||||
print("** Python executable:", sys.executable)
|
||||
print("** ComfyUI Path:", comfy_path)
|
||||
|
||||
if enable_file_logging:
|
||||
print("** Log path:", os.path.abspath('comfyui.log'))
|
||||
if log_path_base is not None:
|
||||
print("** Log path:", os.path.abspath(f'{log_path_base}.log'))
|
||||
else:
|
||||
print("** Log path: file logging is disabled")
|
||||
|
||||
@ -386,7 +392,7 @@ check_bypass_ssl()
|
||||
|
||||
# Perform install
|
||||
processed_install = set()
|
||||
script_list_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "startup-scripts", "install-scripts.txt")
|
||||
script_list_path = os.path.join(folder_paths.user_directory, "default", "ComfyUI-Manager", "startup-scripts", "install-scripts.txt")
|
||||
pip_fixer = manager_util.PIPFixer(manager_util.get_installed_packages())
|
||||
|
||||
|
||||
@ -463,7 +469,7 @@ if os.path.exists(restore_snapshot_path):
|
||||
new_env["COMFYUI_PATH"] = comfy_path
|
||||
|
||||
cmd_str = [sys.executable, cm_cli_path, 'restore-snapshot', restore_snapshot_path]
|
||||
exit_code = process_wrap(cmd_str, custom_nodes_path, handler=msg_capture, env=new_env)
|
||||
exit_code = process_wrap(cmd_str, custom_nodes_base_path, handler=msg_capture, env=new_env)
|
||||
|
||||
if exit_code != 0:
|
||||
print("[ComfyUI-Manager] Restore snapshot failed.")
|
||||
|
||||
@ -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.0"
|
||||
version = "3.1"
|
||||
license = { file = "LICENSE.txt" }
|
||||
dependencies = ["GitPython", "PyGithub", "matrix-client==0.4.0", "transformers", "huggingface-hub>0.20", "typer", "rich", "typing-extensions"]
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user