Spaces:
Running
Running
from __future__ import annotations | |
import shutil, tempfile, textwrap, time | |
from pathlib import Path | |
from typing import Dict | |
import git | |
from huggingface_hub import HfApi | |
from huggingface_hub.errors import HfHubHTTPError | |
from .exceptions import ( | |
DockerfileMissingError, | |
RepoCloneError, | |
SpaceBuildTimeoutError, | |
SpaceCreationError, | |
SpaceDeployError, | |
) | |
__all__ = [ | |
"deploy_space", | |
"SpaceDeployError", | |
] | |
from .utils import _chmod_and_retry | |
def deploy_space(*, hf_token: str, git_repo_url: str, deploy_path: str, space_name: str, space_port: int, description: str, env_vars: Dict[str, str], private: bool) -> str: | |
deploy_path = deploy_path.strip(".").strip("/") | |
api = HfApi(token=hf_token) | |
try: | |
username = api.whoami().get("name", None) | |
repo_id = f"{username}/{space_name}" | |
api.create_repo( | |
repo_id=repo_id, | |
repo_type="space", | |
space_sdk="docker", | |
private=private, | |
# space_variables=[{}], | |
space_secrets=[{"key": k, "value": v} for k, v in env_vars.items()], | |
exist_ok=False, | |
) | |
except HfHubHTTPError as exc: | |
raise SpaceCreationError(exc) from exc | |
tmp = tempfile.mkdtemp(prefix="hf_space_") | |
try: | |
try: | |
if not deploy_path: | |
git.Repo.clone_from( | |
git_repo_url, | |
tmp, | |
depth=1, | |
multi_options=["--single-branch"] | |
) | |
else: | |
repo = git.Repo.clone_from( | |
git_repo_url, tmp, | |
depth=1, | |
no_checkout=True, | |
filter=["tree:0"], | |
sparse=True, | |
multi_options=["--single-branch"], | |
) | |
repo.git.sparse_checkout("init", "--no-cone") | |
repo.git.sparse_checkout("set", "--no-cone", f"/{deploy_path}/**") | |
repo.git.checkout() | |
# 平移文件到根目录 | |
src = Path(tmp, deploy_path) | |
for item in src.iterdir(): | |
shutil.move(item, tmp) # 根目录目前是空的 | |
shutil.rmtree(src) | |
except git.GitCommandError as exc: | |
raise RepoCloneError(str(exc)) from exc | |
git_dir = Path(tmp, ".git") | |
if git_dir.exists() and git_dir.is_dir(): | |
shutil.rmtree(git_dir, onerror=_chmod_and_retry) | |
if not Path(tmp, "Dockerfile").exists(): | |
raise DockerfileMissingError() | |
readme = Path(tmp, "README.md") | |
header = ( | |
f"---\n" | |
f"title: \"{space_name}\"\n" | |
f"emoji: \"🚀\"\n" | |
f"colorFrom: blue\n" | |
f"colorTo: green\n" | |
f"sdk: docker\n" | |
f"app_port: {space_port}\n" | |
f"---\n" | |
) | |
badge = ( | |
f"### 🚀 一键部署\n" | |
f"[](https://github.com/kfcx/HFSpaceDeploy)\n\n" | |
f"本项目由[HFSpaceDeploy](https://github.com/kfcx/HFSpaceDeploy)一键部署\n" | |
) | |
readme.write_text(f"{header}\n{badge}\n{description}\n", encoding="utf-8") | |
api.upload_folder(folder_path=tmp, repo_id=repo_id, repo_type="space", ignore_patterns=[".git"]) | |
finally: | |
shutil.rmtree(tmp, ignore_errors=True) | |
deadline = time.time() + 15 * 60 | |
while time.time() < deadline: | |
stage = api.get_space_runtime(repo_id).stage | |
if stage == "RUNNING": | |
return f"https://huggingface.co/spaces/{repo_id}" | |
if stage in ("BUILD_ERROR", "CONFIG_ERROR", "RUNTIME_ERROR",): | |
raise SpaceDeployError("Space failed during config/build/runtime") | |
if stage in ("NO_APP_FILE", "STOPPED", "PAUSED", "DELETING", ): | |
raise SpaceDeployError("Space is currently unavailable") | |
time.sleep(5) | |
raise SpaceBuildTimeoutError() | |