diff --git a/comfy_cli/command/custom_nodes/cm_cli_util.py b/comfy_cli/command/custom_nodes/cm_cli_util.py index 78f3370e..546bcd67 100644 --- a/comfy_cli/command/custom_nodes/cm_cli_util.py +++ b/comfy_cli/command/custom_nodes/cm_cli_util.py @@ -30,10 +30,10 @@ def execute_cm_cli(args, channel=None, fast_deps=False, mode=None) -> str | None print("\n[bold red]ComfyUI path is not resolved.[/bold red]\n", file=sys.stderr) raise typer.Exit(code=1) - cm_cli_path = os.path.join(workspace_path, "custom_nodes", "ComfyUI-Manager", "cm-cli.py") - if not os.path.exists(cm_cli_path): + cm_cli_path = workspace_manager.get_cm_cli_path() + if cm_cli_path is None: print( - f"\n[bold red]ComfyUI-Manager not found: {cm_cli_path}[/bold red]\n", + f"\n[bold red]ComfyUI-Manager not found[/bold red]\n", file=sys.stderr, ) raise typer.Exit(code=1) diff --git a/comfy_cli/command/custom_nodes/command.py b/comfy_cli/command/custom_nodes/command.py index 50b4ef62..04217f2d 100644 --- a/comfy_cli/command/custom_nodes/command.py +++ b/comfy_cli/command/custom_nodes/command.py @@ -304,7 +304,7 @@ def validate_mode(mode): @tracking.track_command("node") def show( arg: str = typer.Argument( - help="[installed|enabled|not-installed|disabled|all|snapshot|snapshot-list]", + help="[installed|enabled|not-installed|disabled|all|cnr|snapshot|snapshot-list]", autocompletion=show_completer, ), channel: Annotated[ @@ -327,6 +327,7 @@ def show( "not-installed", "disabled", "all", + "cnr", "snapshot", "snapshot-list", ] @@ -480,7 +481,14 @@ def update_node_id_cache(): config_manager = ConfigManager() workspace_path = workspace_manager.workspace_path - cm_cli_path = os.path.join(workspace_path, "custom_nodes", "ComfyUI-Manager", "cm-cli.py") + cm_cli_path = workspace_manager.get_cm_cli_path() + + if cm_cli_path is None: + print( + f"\n[bold red]ComfyUI-Manager not found[/bold red]\n", + file=sys.stderr, + ) + raise typer.Exit(code=1) tmp_path = os.path.join(config_manager.get_config_path(), "tmp") if not os.path.exists(tmp_path): @@ -611,6 +619,45 @@ def fix( execute_cm_cli(["fix"] + nodes, channel=channel, mode=mode) +@app.command( + "show-versions", + help="Show the list of available versions for the target custom node.", +) +@tracking.track_command("node") +def show_versions( + node_name: str, + channel: Annotated[ + Optional[str], + typer.Option( + show_default=False, + help="Specify the operation mode", + autocompletion=channel_completer, + ), + ] = None, + mode: str = typer.Option( + None, + help="[remote|local|cache]", + autocompletion=mode_completer, + ), +): + validate_mode(mode) + + execute_cm_cli( + ["show-versions", node_name], + channel, + mode, + ) + + +@app.command( + "migrate", + help="Changes the old-style custom node installation to the new-style custom node installation.", +) +@tracking.track_command("node") +def migration(): + execute_cm_cli(["migrate"]) + + @app.command( "install-deps", help="Install dependencies from dependencies file(.json) or workflow(.png/.json)", @@ -791,82 +838,6 @@ def display_all_nodes(): ) -@app.command( - "registry-install", - help="Install a node from the registry", - hidden=True, -) -@tracking.track_command("node") -def registry_install( - node_id: str, - version: Optional[str] = None, - force_download: Annotated[ - bool, - typer.Option( - "--force-download", - help="Force download the node even if it is already installed", - ), - ] = False, -): - """ - Install a node from the registry. - Args: - node_id: The ID of the node to install. - version: The version of the node to install. If not provided, the latest version will be installed. - """ - - # If the node ID is not provided, prompt the user to enter it - if not node_id: - node_id = typer.prompt("Enter the ID of the node you want to install") - - node_version = None - try: - # Call the API to install the node - node_version = registry_api.install_node(node_id, version) - if not node_version.download_url: - logging.error("Download URL not provided from the registry.") - ui.display_error_message(f"Failed to download the custom node {node_id}.") - return - - except Exception as e: - logging.error(f"Encountered an error while installing the node. error: {str(e)}") - ui.display_error_message(f"Failed to download the custom node {node_id}.") - return - - # Download the node archive - custom_nodes_path = pathlib.Path(workspace_manager.workspace_path) / "custom_nodes" - node_specific_path = custom_nodes_path / node_id # Subdirectory for the node - if node_specific_path.exists(): - print( - f"[bold red] The node {node_id} already exists in the workspace. This migit delete any model files in the node.[/bold red]" - ) - - confirm = ui.prompt_confirm_action( - "Do you want to overwrite it?", - force_download, - ) - if not confirm: - return - node_specific_path.mkdir(parents=True, exist_ok=True) # Create the directory if it doesn't exist - - local_filename = node_specific_path / f"{node_id}-{node_version.version}.zip" - logging.debug(f"Start downloading the node {node_id} version {node_version.version} to {local_filename}") - download_file(node_version.download_url, local_filename) - - # Extract the downloaded archive to the custom_node directory on the workspace. - logging.debug(f"Start extracting the node {node_id} version {node_version.version} to {custom_nodes_path}") - extract_package_as_zip(local_filename, node_specific_path) - - # TODO: temoporary solution to run requirement.txt and install script - execute_install_script(node_specific_path) - - # Delete the downloaded archive - logging.debug(f"Deleting the downloaded archive {local_filename}") - os.remove(local_filename) - - logging.info(f"Node {node_id} version {node_version.version} has been successfully installed.") - - @app.command( "pack", help="Pack the current node into a zip file. Ignorining .gitignore files.", diff --git a/comfy_cli/command/install.py b/comfy_cli/command/install.py index c25d970a..987e457c 100644 --- a/comfy_cli/command/install.py +++ b/comfy_cli/command/install.py @@ -139,7 +139,7 @@ def pip_install_comfyui_dependencies( # install requirements for manager def pip_install_manager_dependencies(repo_dir): - os.chdir(os.path.join(repo_dir, "custom_nodes", "ComfyUI-Manager")) + os.chdir(workspace_manager.get_comfyui_manager_path()) subprocess.run([sys.executable, "-m", "pip", "install", "-r", "requirements.txt"], check=True) @@ -205,7 +205,9 @@ def execute( if skip_manager: print("Skipping installation of ComfyUI-Manager. (by --skip-manager)") else: - manager_repo_dir = os.path.join(repo_dir, "custom_nodes", "ComfyUI-Manager") + manager_repo_dir = os.path.join( + repo_dir, "custom_nodes", "comfyui-manager@nightly" + ) if os.path.exists(manager_repo_dir): if restore and not fast_deps: diff --git a/comfy_cli/constants.py b/comfy_cli/constants.py index 98304baa..0df07c3e 100644 --- a/comfy_cli/constants.py +++ b/comfy_cli/constants.py @@ -40,6 +40,7 @@ class PROC(str, Enum): CONFIG_KEY_USER_ID = "user_id" CONFIG_KEY_INSTALL_EVENT_TRIGGERED = "install_event_triggered" CONFIG_KEY_BACKGROUND = "background" +CONFIG_KEY_COMFYUI_MANAGER_PATH = "comfyui_manager_path" CIVITAI_API_TOKEN_KEY = "civitai_api_token" diff --git a/comfy_cli/workspace_manager.py b/comfy_cli/workspace_manager.py index fc5f451a..d2293df6 100644 --- a/comfy_cli/workspace_manager.py +++ b/comfy_cli/workspace_manager.py @@ -262,17 +262,50 @@ def get_comfyui_manager_path(self): if self.workspace_path is None: return None - # To check more robustly, verify up to the `.git` path. - manager_path = os.path.join(self.workspace_path, "custom_nodes", "ComfyUI-Manager") + cached_manager_path = self.config_manager.get( + constants.CONFIG_KEY_COMFYUI_MANAGER_PATH + ) + + if cached_manager_path is None or not cached_manager_path.startswith( + self.workspace_path + ): + manager_path = os.path.join( + self.workspace_path, "custom_nodes", "comfyui-manager@nightly" + ) + else: + manager_path = cached_manager_path + + if not os.path.exists(manager_path): + manager_path = os.path.join( + self.workspace_path, "custom_nodes", "ComfyUI-Manager" + ) + + if not os.path.exists(manager_path): + custom_nodes = os.path.join(self.workspace_path, "custom_nodes") + + manager_path = None + for subdir in os.listdir(custom_nodes): + if subdir.startswith("comfyui-manager@"): + manager_path = os.path.join(custom_nodes, subdir) + break + + if manager_path is not None and manager_path != cached_manager_path: + self.config_manager.set( + constants.CONFIG_KEY_COMFYUI_MANAGER_PATH, manager_path + ) return manager_path def is_comfyui_manager_installed(self): if self.workspace_path is None: return False - # To check more robustly, verify up to the `.git` path. - manager_git_path = os.path.join(self.workspace_path, "custom_nodes", "ComfyUI-Manager", ".git") - return os.path.exists(manager_git_path) + return self.get_comfyui_manager_path() is not None + + def get_cm_cli_path(self): + cm_path = self.get_comfyui_manager_path() + if cm_path is not None: + return os.path.join(cm_path, "cm-cli.py") + return None def scan_dir(self): if not self.workspace_path: