195 lines
6.0 KiB
Python
195 lines
6.0 KiB
Python
"""Collections commands for CmdForge CLI."""
|
|
|
|
import json
|
|
import sys
|
|
|
|
from ..resolver import install_from_registry
|
|
|
|
|
|
def cmd_collections(args):
|
|
"""Handle collections subcommands."""
|
|
if args.collections_cmd == "list":
|
|
return _cmd_collections_list(args)
|
|
elif args.collections_cmd == "info":
|
|
return _cmd_collections_info(args)
|
|
elif args.collections_cmd == "install":
|
|
return _cmd_collections_install(args)
|
|
else:
|
|
# Default: show help
|
|
print("Collections commands:")
|
|
print(" list List available collections")
|
|
print(" info <name> Show collection details")
|
|
print(" install <name> Install all tools in a collection")
|
|
return 0
|
|
|
|
|
|
def _cmd_collections_list(args):
|
|
"""List available collections."""
|
|
from ..registry_client import RegistryError, get_client
|
|
|
|
try:
|
|
client = get_client()
|
|
collections = client.get_collections()
|
|
|
|
# JSON output
|
|
if getattr(args, 'json', False):
|
|
print(json.dumps({"collections": collections}, indent=2))
|
|
return 0
|
|
|
|
if not collections:
|
|
print("No collections available.")
|
|
return 0
|
|
|
|
print(f"Available collections ({len(collections)}):\n")
|
|
for coll in collections:
|
|
name = coll.get("name", "")
|
|
display_name = coll.get("display_name", name)
|
|
description = coll.get("description", "")
|
|
tools = coll.get("tools", [])
|
|
tool_count = len(tools) if isinstance(tools, list) else 0
|
|
|
|
print(f" {name}")
|
|
print(f" {display_name}")
|
|
if description:
|
|
desc_short = description[:60] + ('...' if len(description) > 60 else '')
|
|
print(f" {desc_short}")
|
|
print(f" Tools: {tool_count}")
|
|
print()
|
|
|
|
print("Install a collection with: cmdforge collections install <name>")
|
|
|
|
except RegistryError as e:
|
|
if e.code == "CONNECTION_ERROR":
|
|
print("Could not connect to the registry.", file=sys.stderr)
|
|
else:
|
|
print(f"Error: {e.message}", file=sys.stderr)
|
|
return 1
|
|
except Exception as e:
|
|
print(f"Error: {e}", file=sys.stderr)
|
|
return 1
|
|
|
|
return 0
|
|
|
|
|
|
def _cmd_collections_info(args):
|
|
"""Show collection details."""
|
|
from ..registry_client import RegistryError, get_client
|
|
|
|
name = args.name
|
|
|
|
try:
|
|
client = get_client()
|
|
coll = client.get_collection(name)
|
|
|
|
# JSON output
|
|
if getattr(args, 'json', False):
|
|
print(json.dumps(coll, indent=2))
|
|
return 0
|
|
|
|
display_name = coll.get("display_name", name)
|
|
description = coll.get("description", "")
|
|
maintainer = coll.get("maintainer", "")
|
|
tools = coll.get("tools", [])
|
|
pinned = coll.get("pinned", {})
|
|
tags = coll.get("tags", [])
|
|
|
|
print(f"{display_name}")
|
|
print("=" * 50)
|
|
if description:
|
|
print(f"\n{description}\n")
|
|
if maintainer:
|
|
print(f"Maintainer: {maintainer}")
|
|
if tags:
|
|
print(f"Tags: {', '.join(tags)}")
|
|
|
|
print(f"\nTools ({len(tools)}):")
|
|
for tool_ref in tools:
|
|
version_constraint = pinned.get(tool_ref, "")
|
|
if version_constraint:
|
|
print(f" - {tool_ref} @ {version_constraint}")
|
|
else:
|
|
print(f" - {tool_ref}")
|
|
|
|
print(f"\nInstall all: cmdforge collections install {name}")
|
|
|
|
except RegistryError as e:
|
|
if e.code == "COLLECTION_NOT_FOUND":
|
|
print(f"Collection '{name}' not found.", file=sys.stderr)
|
|
print("List available collections: cmdforge collections list", file=sys.stderr)
|
|
elif e.code == "CONNECTION_ERROR":
|
|
print("Could not connect to the registry.", file=sys.stderr)
|
|
else:
|
|
print(f"Error: {e.message}", file=sys.stderr)
|
|
return 1
|
|
except Exception as e:
|
|
print(f"Error: {e}", file=sys.stderr)
|
|
return 1
|
|
|
|
return 0
|
|
|
|
|
|
def _cmd_collections_install(args):
|
|
"""Install all tools in a collection."""
|
|
from ..registry_client import RegistryError, get_client
|
|
|
|
name = args.name
|
|
use_pinned = getattr(args, 'pinned', False)
|
|
|
|
try:
|
|
client = get_client()
|
|
coll = client.get_collection(name)
|
|
|
|
tools = coll.get("tools", [])
|
|
pinned = coll.get("pinned", {}) if use_pinned else {}
|
|
display_name = coll.get("display_name", name)
|
|
|
|
if not tools:
|
|
print(f"Collection '{name}' has no tools.")
|
|
return 0
|
|
|
|
print(f"Installing collection: {display_name}")
|
|
print(f"Tools to install: {len(tools)}")
|
|
if use_pinned and pinned:
|
|
print(f"Using pinned versions: {len(pinned)} tools")
|
|
print()
|
|
|
|
installed = 0
|
|
failed = 0
|
|
|
|
for tool_ref in tools:
|
|
version = pinned.get(tool_ref)
|
|
try:
|
|
print(f" Installing {tool_ref}...", end=" ", flush=True)
|
|
resolved = install_from_registry(tool_ref, version)
|
|
print(f"v{resolved.version}")
|
|
installed += 1
|
|
except RegistryError as e:
|
|
print(f"FAILED: {e.message}")
|
|
failed += 1
|
|
except Exception as e:
|
|
print(f"FAILED: {e}")
|
|
failed += 1
|
|
|
|
print()
|
|
print(f"Installed: {installed}/{len(tools)}")
|
|
if failed:
|
|
print(f"Failed: {failed}")
|
|
return 1
|
|
|
|
print(f"\nCollection '{name}' installed successfully!")
|
|
|
|
except RegistryError as e:
|
|
if e.code == "COLLECTION_NOT_FOUND":
|
|
print(f"Collection '{name}' not found.", file=sys.stderr)
|
|
print("List available collections: cmdforge collections list", file=sys.stderr)
|
|
elif e.code == "CONNECTION_ERROR":
|
|
print("Could not connect to the registry.", file=sys.stderr)
|
|
else:
|
|
print(f"Error: {e.message}", file=sys.stderr)
|
|
return 1
|
|
except Exception as e:
|
|
print(f"Error: {e}", file=sys.stderr)
|
|
return 1
|
|
|
|
return 0
|