From 8ba3790f12095c086c4b48cf07418a39547f83fe Mon Sep 17 00:00:00 2001 From: "Dr.Lt.Data" Date: Sat, 27 Apr 2024 00:14:45 +0900 Subject: [PATCH] fix: potential pip environment mismatch - `pip` -> `sys.executable -m pip` fix: validate environment when execute commands remove: install to repo of current dir - if --workspace is given, specified path should be used - if --workspace is not given, default path should be used improve: add --restore option to install command --- comfy_cli/cmdline.py | 29 ++++++++- comfy_cli/command/custom_nodes/command.py | 17 ++++++ comfy_cli/command/install.py | 73 ++++++++++++++--------- comfy_cli/env_checker.py | 16 +++++ pyproject.toml | 2 +- 5 files changed, 105 insertions(+), 32 deletions(-) diff --git a/comfy_cli/cmdline.py b/comfy_cli/cmdline.py index 798e0f2..3d779ee 100644 --- a/comfy_cli/cmdline.py +++ b/comfy_cli/cmdline.py @@ -25,6 +25,7 @@ def main(): init() app() + def init(): # TODO(yoland): after this metadata_manager = MetadataManager() @@ -58,6 +59,12 @@ def install( show_default=False, help="Path to ComfyUI workspace") ] = "~/comfy", + restore: Annotated[ + bool, + lambda: typer.Option( + default=False, + help="Restore dependencies for installed ComfyUI if not installed") + ] = False, skip_manager: Annotated[ bool, lambda: typer.Option( @@ -87,7 +94,7 @@ def install( if amd: torch_mode = 'amd' - install_inner.execute(url, manager_url, workspace, skip_manager, torch_mode) + install_inner.execute(url, manager_url, workspace, restore, skip_manager, torch_mode) def update(self): @@ -95,7 +102,7 @@ def update(self): print(f"Updating ComfyUI in {self.workspace}...") os.chdir(self.workspace) subprocess.run(["git", "pull"], check=True) - subprocess.run(["pip", "install", "-r", "requirements.txt"], check=True) + subprocess.run([sys.executable, '-m', "pip", "install", "-r", "requirements.txt"], check=True) @app.command(help="Run workflow file") @@ -105,6 +112,12 @@ def run( run_inner.execute(workflow_file) +def validate_comfyui(_env_checker): + if _env_checker.comfy_repo is None: + print(f"[bold red]If ComfyUI is not installed, this feature cannot be used.[/bold red]") + raise typer.Exit(code=1) + + def launch_comfyui(_env_checker, cpu): # TODO(yoland/data): Disabled config writing for now, checking with @data # We need to find a viable place to write config file, e.g. standard place @@ -114,6 +127,8 @@ def launch_comfyui(_env_checker, cpu): #_env_checker.config['DEFAULT']['recent_path'] = os.getcwd() #_env_checker.write_config() + validate_comfyui(_env_checker) + env_path = _env_checker.get_isolated_env() reboot_path = None @@ -149,10 +164,13 @@ def launch(workspace: Annotated[ ] = False, ): _env_checker = EnvChecker() + if workspace is not None: comfyui_path = os.path.join(workspace, 'ComfyUI') if os.path.exists(comfyui_path): os.chdir(comfyui_path) + _env_checker.check() # update env + print(f"\nLaunch ComfyUI from repo: {_env_checker.comfy_repo.working_dir}\n") launch_comfyui(_env_checker, cpu) else: @@ -165,7 +183,10 @@ def launch(workspace: Annotated[ elif _env_checker.config['DEFAULT'].get('recent_path') is not None: comfy_path = _env_checker.config['DEFAULT'].get('recent_path') print(f"\nLaunch ComfyUI from recent repo: {comfy_path}\n") + os.chdir(comfy_path) + _env_checker.check() # update env + launch_comfyui(_env_checker, cpu) else: print("\nComfyUI is not available.\nTo install ComfyUI, you can run:\n\n\tcomfy install\n\n", file=sys.stderr) @@ -182,10 +203,12 @@ def env(): def nodes(): print("\n[bold red] No such command, did you mean 'comfy node' instead?[/bold red]\n") + @app.command(hidden=True) def models(): print("\n[bold red] No such command, did you mean 'comfy model' instead?[/bold red]\n") + app.add_typer(models_command.app, name="model", help="Manage models.") app.add_typer(custom_nodes.app, name="node", help="Manage custom nodes.") -app.add_typer(custom_nodes.manager_app, name="manager", help="Manager ComfyUI-Manager.") \ No newline at end of file +app.add_typer(custom_nodes.manager_app, name="manager", help="Manager ComfyUI-Manager.") diff --git a/comfy_cli/command/custom_nodes/command.py b/comfy_cli/command/custom_nodes/command.py index 8a6be61..22f564c 100644 --- a/comfy_cli/command/custom_nodes/command.py +++ b/comfy_cli/command/custom_nodes/command.py @@ -4,6 +4,7 @@ import os import subprocess import sys +from rich import print app = typer.Typer() manager_app = typer.Typer() @@ -18,6 +19,8 @@ def execute_cm_cli(args, channel=None, mode=None, workspace=None): _env_checker = EnvChecker() _env_checker.write_config() + validate_comfyui_manager(_env_checker) + if workspace is not None: comfyui_path = os.path.join(workspace, 'ComfyUI') elif _env_checker.comfy_repo is not None: @@ -53,6 +56,20 @@ def execute_cm_cli(args, channel=None, mode=None, workspace=None): subprocess.run(cmd, env=new_env) +def validate_comfyui_manager(_env_checker): + manager_path = _env_checker.get_comfyui_manager_path() + + if manager_path is None: + print(f"[bold red]If ComfyUI is not installed, this feature cannot be used.[/bold red]") + raise typer.Exit(code=1) + elif not os.path.exists(manager_path): + print(f"[bold red]If ComfyUI-Manager is not installed, this feature cannot be used.[/bold red] \\[{manager_path}]") + raise typer.Exit(code=1) + elif not os.path.exists(os.path.join(manager_path, '.git')): + print(f"[bold red]The ComfyUI-Manager installation is invalid. This feature cannot be used.[/bold red] \\[{manager_path}]") + raise typer.Exit(code=1) + + @app.command('save-snapshot', help="Save a snapshot of the current ComfyUI environment") def save_snapshot(): execute_cm_cli(['save-snapshot']) diff --git a/comfy_cli/command/install.py b/comfy_cli/command/install.py index cdc7019..1938fa0 100644 --- a/comfy_cli/command/install.py +++ b/comfy_cli/command/install.py @@ -3,40 +3,55 @@ from rich.progress import Progress, SpinnerColumn, TextColumn from rich import print from comfy_cli import env_checker +import sys -def execute(url: str, manager_url: str, comfy_workspace: str, skip_manager: bool, torch_mode=None, *args, **kwargs): +def install_comfyui_dependencies(repo_dir, torch_mode): + os.chdir(repo_dir) + + # install torch + if torch_mode == 'amd': + pip_url = ['--extra-index-url', 'https://download.pytorch.org/whl/rocm5.7'] + else: + pip_url = ['--extra-index-url', 'https://download.pytorch.org/whl/cu121'] + subprocess.run([sys.executable, '-m', "pip", "install", "torch", "torchvision", "torchaudio"] + pip_url) + + # install other requirements + subprocess.run([sys.executable, '-m', "pip", "install", "-r", "requirements.txt"]) + + +# install requirements for manager +def install_manager_dependencies(repo_dir): + os.chdir(os.path.join(repo_dir, 'custom_nodes', 'ComfyUI-Manager')) + subprocess.run([sys.executable, '-m', "pip", "install", "-r", "requirements.txt"]) + + +def execute(url: str, manager_url: str, comfy_workspace: str, restore: bool, skip_manager: bool, torch_mode=None, *args, **kwargs): print(f"Installing from {url}") checker = env_checker.EnvChecker() # install ComfyUI - if checker.currently_in_comfy_repo: - print(f"Already in comfy repo. Skipping installation.") - repo_dir = os.getcwd() - else: - working_dir = os.path.expanduser(comfy_workspace) - repo_dir = os.path.join(working_dir, os.path.basename(url).replace(".git", "")) + working_dir = os.path.expanduser(comfy_workspace) + repo_dir = os.path.join(working_dir, os.path.basename(url).replace(".git", "")) + repo_dir = os.path.abspath(repo_dir) - if os.path.exists(os.path.join(repo_dir, '.git')): - print("ComfyUI is installed already. Skipping installation.") + if os.path.exists(os.path.join(repo_dir, '.git')): + if restore: + install_comfyui_dependencies(repo_dir, torch_mode) else: - print("\nInstalling ComfyUI..") - os.makedirs(working_dir, exist_ok=True) + print("ComfyUI is installed already. Skipping installation.\nIf you want to restore dependencies, add the '--restore' option.") + else: + print("\nInstalling ComfyUI..") + os.makedirs(working_dir, exist_ok=True) - repo_dir = os.path.join(working_dir, os.path.basename(url).replace(".git", "")) - subprocess.run(["git", "clone", url, repo_dir]) + repo_dir = os.path.join(working_dir, os.path.basename(url).replace(".git", "")) + repo_dir = os.path.abspath(repo_dir) + subprocess.run(["git", "clone", url, repo_dir]) - os.chdir(repo_dir) - # install torch - if torch_mode == 'amd': - pip_url = ['--extra-index-url', 'https://download.pytorch.org/whl/rocm5.7'] - else: - pip_url = ['--extra-index-url', 'https://download.pytorch.org/whl/cu121'] - subprocess.run(["pip", "install", "torch", "torchvision", "torchaudio"] + pip_url) + install_comfyui_dependencies(repo_dir, torch_mode) - # install other requirements - subprocess.run(["pip", "install", "-r", "requirements.txt"]) + print("") # install ComfyUI-Manager if skip_manager: @@ -45,17 +60,19 @@ def execute(url: str, manager_url: str, comfy_workspace: str, skip_manager: bool manager_repo_dir = os.path.join(repo_dir, 'custom_nodes', 'ComfyUI-Manager') if os.path.exists(manager_repo_dir): - print(f"Directory {manager_repo_dir} already exists. Skipping installation of ComfyUI-Manager.") + if restore: + install_manager_dependencies(repo_dir) + else: + print(f"Directory {manager_repo_dir} already exists. Skipping installation of ComfyUI-Manager.\nIf you want to restore dependencies, add the '--restore' option.") else: print("\nInstalling ComfyUI-Manager..") subprocess.run(["git", "clone", manager_url, manager_repo_dir]) - os.chdir(os.path.join(repo_dir, 'custom_nodes', 'ComfyUI-Manager')) + install_manager_dependencies(repo_dir) + + os.chdir(repo_dir) - subprocess.run(["pip", "install", "-r", "requirements.txt"]) - os.chdir(os.path.join('..', '..')) + print("") checker.config['DEFAULT']['recent_path'] = repo_dir checker.write_config() - - diff --git a/comfy_cli/env_checker.py b/comfy_cli/env_checker.py index c24fca7..6354309 100644 --- a/comfy_cli/env_checker.py +++ b/comfy_cli/env_checker.py @@ -93,6 +93,22 @@ def __init__(self): self.config = configparser.ConfigParser() self.check() + def get_comfyui_manager_path(self): + if self.comfy_repo is None: + return None + + # To check more robustly, verify up to the `.git` path. + manager_path = os.path.join(self.comfy_repo.working_dir, 'custom_nodes', 'ComfyUI-Manager') + return manager_path + + def is_comfyui_manager_installed(self): + if self.comfy_repo is None: + return False + + # To check more robustly, verify up to the `.git` path. + manager_git_path = os.path.join(self.comfy_repo.working_dir, 'custom_nodes', 'ComfyUI-Manager', '.git') + return os.path.exists(manager_git_path) + def is_isolated_env(self): return self.virtualenv_path or self.conda_env diff --git a/pyproject.toml b/pyproject.toml index d51e71d..191dc2a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta" [project] name = "comfy-cli" license = {file = "LICENSE"} -version = "2024.4.25" +version = "2024.4.26" requires-python = ">= 3.8" description = "A CLI tool for installing and using ComfyUI." readme = "README.md"