import sys import os import subprocess import uuid import requests import json from git import Repo from huggingface_hub import snapshot_download def get_github_user(token): try: response = requests.get( "https://api.github.com/user", headers={ "Authorization": f"token {token}", "Accept": "application/vnd.github.v3+json" }, timeout=10 ) if response.ok: return response.json().get("login") except Exception as e: print(f"Error fetching GitHub user: {e}") return None def create_github_repo(token, name): try: # First check if it exists user = get_github_user(token) if not user: return False check_res = requests.get( f"https://api.github.com/repos/{user}/{name}", headers={ "Authorization": f"token {token}", "Accept": "application/vnd.github.v3+json" }, timeout=10 ) if check_res.status_code == 200: print(f"Repository {user}/{name} already exists.") return True # Create it print(f"Creating repository {user}/{name}...") response = requests.post( "https://api.github.com/user/repos", headers={ "Authorization": f"token {token}", "Accept": "application/vnd.github.v3+json" }, json={ "name": name, "private": True, "description": f"Imported from Hugging Face Space" }, timeout=10 ) return response.ok except Exception as e: print(f"Error creating GitHub repo: {e}") return False def parse_hf_repo_id(hf_input): if not hf_input: return None, None if "huggingface.co/spaces/" in hf_input: parts = hf_input.split("huggingface.co/spaces/")[1].split("/") return parts[0], parts[1] if "/" in hf_input: parts = hf_input.split("/") return parts[0], parts[1] return None, None def parse_github_repo_id(git_input): if not git_input: return None, None if "github.com/" in git_input: parts = git_input.split("github.com/")[1].split("/") return parts[0], parts[1].replace(".git", "") if "/" in git_input: parts = git_input.split("/") return parts[0], parts[1] return None, git_input def get_hf_token(): return os.environ.get("HF_TOKEN") def get_github_token(): return os.environ.get("GITHUB_TOKEN") def handle_upload(hf_space_input, git_repo_input, branch): hf_profile, hf_space = parse_hf_repo_id(hf_space_input) if not hf_profile or not hf_space: return {"error": f"Invalid HF Space ID: '{hf_space_input}'"} hf_space_full = f"{hf_profile}/{hf_space}" git_token = get_github_token() if not git_token: return {"error": "GITHUB_TOKEN not found in environment secrets."} git_profile, git_repo = parse_github_repo_id(git_repo_input) # If no git_repo provided, use hf_space name if not git_repo: git_repo = hf_space # If no profile provided, fetch it from token if not git_profile: git_profile = get_github_user(git_token) if not git_profile: return {"error": "Could not determine GitHub user profile from token."} if not branch: branch = "main" hf_token = get_hf_token() if not hf_token: return {"error": "HF_TOKEN not found in environment secrets."} # Ensure Repo exists create_github_repo(git_token, git_repo) work_dir = "/tmp/jules_uploads" os.makedirs(work_dir, exist_ok=True) upload_dir = os.path.join(work_dir, f"upload_{uuid.uuid4().hex}") os.makedirs(upload_dir, exist_ok=True) try: # 1. Download HF Space print(f"Downloading {hf_space_full}...") snapshot_download( repo_id=hf_space_full, repo_type="space", local_dir=upload_dir, token=hf_token ) # 2. Target URL target_url = f"https://{git_token}@github.com/{git_profile}/{git_repo}.git" # 3. Push to GitHub repo = Repo.init(upload_dir) # Setup branch try: repo.git.checkout("-b", branch) except: repo.git.checkout(branch) repo.git.add(A=True) if repo.git.status("--short"): repo.index.commit(f"Import from HF Space {hf_space_full}") if "origin" in [remote.name for remote in repo.remotes]: origin = repo.remote("origin") origin.set_url(target_url) else: origin = repo.create_remote("origin", target_url) print(f"Pushing to GitHub {git_profile}/{git_repo}...") repo.git.push("origin", branch, force=True) return { "status": "success", "message": f"{hf_space_full} uploaded to {git_profile}/{git_repo} ({branch})", "repo_id": f"{git_profile}/{git_repo}" } except Exception as e: return {"error": str(e)} if __name__ == "__main__": if len(sys.argv) < 4: print(json.dumps({"error": "Missing arguments"})) sys.exit(1) hf_space = sys.argv[1] git_repo = sys.argv[2] branch = sys.argv[3] result = handle_upload(hf_space, git_repo, branch) print(json.dumps(result))