#!/usr/bin/env python3 import requests import os import os.path import subprocess import logging logger = logging.getLogger(__name__) def mirror_host(d, host, token): for repo, url in get_repos(host, token): p = os.path.join(d, repo) if os.path.exists(os.path.join(p, 'config')): logger.debug("Updating %s", repo) cmd = ['git', '-C', p, 'fetch'] else: logger.info("Cloning new repo: %s", repo) os.makedirs(p, exist_ok=True) cmd = ['git', 'clone', '--mirror', url, p] try: subprocess.run(cmd, check=True) except subprocess.CalledProcessError: logger.exception("Failed to process %s", repo) def get_repos(host, token, pagesize=50): page = 1 headers = { 'authorization': f"token {token}", 'accept': 'application/json' } while True: r = requests.get(f"{host}/api/v1/user/repos?limit={pagesize}&page={page}", headers=headers) if r.status_code != 200: r.raise_for_status() data = r.json() for repo in data: yield repo['full_name'], repo['ssh_url'] if len(data) < pagesize: break page += 1 if __name__ == '__main__': import argparse parser = argparse.ArgumentParser() parser.add_argument('instance', help='Gitea instance') parser.add_argument('target', default='.', help='Target location') parser.add_argument('--token', '-t', help="Token (default GITEA_TOKEN)") parser.add_argument('--level', '-l', default='info', help='Logging level') options = parser.parse_args() logging.basicConfig(level=getattr(logging, options.level.upper(), logging.INFO)) logger.debug(options) token = options.token or os.ENVIRON['GITEA_TOKEN'] mirror_host(options.target, options.instance, token)