llm-gguf-tools/helpers/huggingface/repository.py
2025-08-09 17:16:02 +01:00

167 lines
5.1 KiB
Python

"""HuggingFace repository management.
Handles repository creation, configuration, and management operations.
"""
from __future__ import annotations
import subprocess
import time
from helpers.logger import logger
class RepositoryManager:
"""Manages HuggingFace repository operations.
Provides methods for creating repositories, checking existence,
and managing repository configuration.
"""
@staticmethod
def create_repository(
repo_id: str,
private: bool = False,
repo_type: str = "model",
) -> bool:
"""Create a new HuggingFace repository.
Creates a repository with the specified identifier and settings. Repository
identifiers follow the format "username/repo-name". Supports model, dataset,
and space repository types with configurable visibility.
Returns:
True if repository was created, False if it already exists.
"""
logger.info(f"Creating repository: {repo_id}")
cmd = [
"huggingface-cli",
"repo",
"create",
repo_id,
"--type",
repo_type,
]
if private:
cmd.append("--private")
try:
result = subprocess.run(
cmd,
capture_output=True,
text=True,
check=False,
)
if result.returncode == 0:
logger.info(f"Created repository: {repo_id}")
return True
if "already exists" in result.stderr.lower():
logger.info(f"Repository already exists: {repo_id}")
return False
logger.error(f"Failed to create repository: {result.stderr}")
except Exception as e:
logger.error(f"Error creating repository: {e}")
return False
@staticmethod
def ensure_repository_exists(repo_id: str) -> None:
"""Ensure repository exists, creating if necessary.
Attempts to create the repository if it doesn't exist, then waits
briefly to ensure the repository is ready for operations.
"""
# Try to create the repository
RepositoryManager.create_repository(repo_id)
# Small delay to ensure repository is ready
time.sleep(2)
@staticmethod
def check_repository_exists(repo_id: str) -> bool:
"""Check if a repository exists.
Queries the HuggingFace Hub to determine if a repository with the
given identifier exists and is accessible.
Returns:
True if repository exists, False otherwise.
"""
try:
result = subprocess.run(
["huggingface-cli", "repo", "ls-files", repo_id],
capture_output=True,
text=True,
check=False,
)
except Exception:
return False
else:
return result.returncode == 0
@staticmethod
def delete_repository(repo_id: str) -> bool:
"""Delete a HuggingFace repository.
Permanently removes a repository from the HuggingFace Hub. This operation
cannot be undone and requires appropriate permissions.
Returns:
True if deleted successfully, False otherwise.
"""
logger.warning(f"Deleting repository: {repo_id}")
try:
result = subprocess.run(
["huggingface-cli", "repo", "delete", repo_id, "--yes"],
capture_output=True,
text=True,
check=False,
)
if result.returncode == 0:
logger.info(f"Deleted repository: {repo_id}")
return True
logger.error(f"Failed to delete repository: {result.stderr}")
except Exception as e:
logger.error(f"Error deleting repository: {e}")
return False
else:
return False
@staticmethod
def get_repository_url(repo_id: str) -> str:
"""Get the full URL for a repository.
Constructs the complete HuggingFace Hub URL for accessing the repository
through a web browser.
Returns:
Full HuggingFace URL for the repository.
"""
return f"https://huggingface.co/{repo_id}"
@staticmethod
def set_repository_visibility(repo_id: str, private: bool) -> bool:
"""Set repository visibility (public/private).
Changes the visibility setting of an existing repository. Private repositories
require appropriate permissions and may have usage limitations.
Returns:
True if visibility changed successfully.
"""
visibility = "private" if private else "public"
logger.info(f"Setting {repo_id} visibility to {visibility}")
try:
# Note: This would require using the HuggingFace API directly
# as the CLI doesn't support changing visibility
logger.warning("Changing repository visibility requires API access")
except Exception as e:
logger.error(f"Error changing visibility: {e}")
return False