Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DRAFT] Support new ComfyUI-Manager #139

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions comfy_cli/command/custom_nodes/cm_cli_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,10 @@ def execute_cm_cli(args, channel=None, 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)
Expand Down
127 changes: 38 additions & 89 deletions comfy_cli/command/custom_nodes/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -497,9 +497,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):
Expand Down Expand Up @@ -630,6 +635,36 @@ def fix(
execute_cm_cli(["fix"] + nodes, channel, 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,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

node_name or node_id? Should we use node_id here?

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(
"install-deps",
help="Install dependencies from dependencies file(.json) or workflow(.png/.json)",
Expand Down Expand Up @@ -824,92 +859,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(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

registry_install -> we would need to update the commands inside the registry_web repository https://github.com/Comfy-Org/registry-web/blob/23948cfe4faa73f640a48139479a718a2d561ccd/components/nodes/NodeDetails.tsx#L209.

This should be replaced with a new command. node install <node_id>@<version>

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.",
Expand Down
12 changes: 10 additions & 2 deletions comfy_cli/command/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ def install_comfyui_dependencies(

# install requirements for manager
def 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
)
Expand Down Expand Up @@ -214,7 +214,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"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may need to change this. Depending on the version of comfyUI manager, the repo directory would change.

)

if os.path.exists(manager_repo_dir):
if restore:
Expand All @@ -227,6 +229,12 @@ def execute(
print("\nInstalling ComfyUI-Manager..")

subprocess.run(["git", "clone", manager_url, manager_repo_dir], check=True)

# TODO: REMOVED - Alpha Testing -----------------------------`
os.chdir(workspace_manager.get_comfyui_manager_path())
subprocess.run(["git", "switch", "feat/cnr"], check=True)
# ------------------------------------------------------------

install_manager_dependencies(repo_dir)

update_node_id_cache()
Expand Down
1 change: 1 addition & 0 deletions comfy_cli/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class OS(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"

Expand Down
46 changes: 38 additions & 8 deletions comfy_cli/workspace_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,21 +281,51 @@ 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(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously, we knew the absolute path of the comfyUI manager. With the new changes, the comfyUI manager directory name would change depending on which version you've installed (e.g., nightly vs. specific version). We need to figure out the directory of the ComfyUI Manager.

Let's add comments explaining what this logic is.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic may not work if we are caching the repository name for multiple workspace.

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:
Expand Down
Loading