from typing import Optional, Dict, Any
import logging
import os
from briefcase.integrations.vcs.base import VcsClientBase
logger = logging.getLogger(__name__)
class DvcClient(VcsClientBase):
def __init__(
self,
repository: str,
branch: str = "main",
briefcase_client=None,
repo_path: Optional[str] = None,
remote: Optional[str] = None,
**extra
):
super().__init__(
provider_type="dvc",
repository=repository,
branch=branch,
briefcase_client=briefcase_client,
endpoint=remote,
**extra
)
self.repo_path = repo_path or os.getenv("DVC_REPO_PATH", ".")
self.remote = remote or os.getenv("DVC_REMOTE")
try:
import dvc.repo
self._provider_client = dvc.repo.Repo(self.repo_path)
self._has_provider = True
except (ImportError, Exception) as e:
logger.warning(f"DVC not available: {e}. Using mock mode.")
self._has_provider = False
def _read_object_impl(self, path: str) -> bytes:
if not self._has_provider:
return b"Mock DVC content: " + path.encode()
try:
full_path = f"{self.repo_path}/{path}"
with open(full_path, "rb") as f:
return f.read()
except FileNotFoundError:
raise FileNotFoundError(f"DVC object not found: {path}")
def _write_object_impl(
self,
path: str,
data: bytes,
content_type: str
) -> None:
if not self._has_provider:
logger.info(f"Mock DVC: Would write {len(data)} bytes to {path}")
return
try:
full_path = f"{self.repo_path}/{path}"
os.makedirs(os.path.dirname(full_path), exist_ok=True)
with open(full_path, "wb") as f:
f.write(data)
logger.info(f"Wrote {len(data)} bytes to {path}")
except Exception as e:
logger.error(f"Failed to write DVC object: {e}")
raise
def _create_version_impl(
self,
message: str,
metadata: Optional[Dict[str, str]]
) -> str:
if not self._has_provider:
return f"dvc-{self.branch}-mock-version"
try:
import subprocess
subprocess.run(
["git", "add", "-A"],
cwd=self.repo_path,
check=True,
capture_output=True
)
result = subprocess.run(
["git", "commit", "-m", message],
cwd=self.repo_path,
capture_output=True,
text=True
)
sha_result = subprocess.run(
["git", "rev-parse", "HEAD"],
cwd=self.repo_path,
capture_output=True,
text=True,
check=True
)
return sha_result.stdout.strip()
except Exception as e:
logger.error(f"Failed to create DVC version: {e}")
raise