""" core.pkg.backend.gitea - Vhex core backend for Gitea instance """ import os import subprocess import requests from core.pkg.backend.core import VxRemoteBackendCore from core.pkg.version import VxVersion from core.logger import log from core.config import config __all__ = [ 'VxBackendRemote' ] #--- # Public #--- class VxBackendRemote(VxRemoteBackendCore): """ Vhex Gitea backend class """ #--- # Public properties #--- @property def name(self): return 'gitea' @property def url(self): return self._url @property def package_list(self): """ Return the list of all repository find in the remote instance. This property is used to cache request's information and avoid big HTTP quesring to the remote instance of Gitea. """ # if cached, avoid quering operation if self._pkg_list: return self._pkg_list # raw HTTP request resp = requests.get( f'{self.url}/api/v1/repos/search', params={ 'q' : 'vxsdk', 'topic': 'True' }, timeout=10 ) if not resp.ok: log.warn( f'[backend] gitea: remote package requests failed\n' f'>>> {resp.status_code}' ) self._pkg_list = [] return [] # generate the pacakge list # @note # - hide private repositories self._pkg_list = [] for pkg in resp.json()['data']: if pkg['private']: continue self._pkg_list.append({ 'name' : pkg['name'], 'full_name' : pkg['full_name'], 'description' : pkg['description'], 'url' : pkg['clone_url'], 'created' : pkg['created_at'].split('T')[0], 'updated' : pkg['updated_at'].split('T')[0], 'author' : pkg['owner']['login'], 'default_branch' : pkg['default_branch'], 'storage' : 'remote', 'versions' : [] }) return self._pkg_list #--- # Private methods #--- def package_fetch_versions(self, pkg): """ Fetch package version information. Same as the `package_list` property, we using cache to avoid too many HTTP request. """ # if cached information, return it if pkg['versions']: return pkg['versions'] # request branches information pkg['versions'] = [] url = f"{self.url}/api/v1/repos/{pkg['full_name']}" resp = requests.get(f'{url}/branches', timeout=10) if not resp.ok: log.warn( f'[pkg]: backend: gitea: branches requests error\n' f'>>> url = {url}/branches\n' f'>>> status = {resp.status_code}' ) else: for ver in resp.json(): pkg['versions'].append( VxVersion(ver['name'], 'branch', 'remote') ) # request tag information resp = requests.get(f'{url}/tags', timeout=10) if not resp.ok: log.warn( f'[pkg]: backend: gitea: tags requests error\n' f'>>> url = {url}/tags\n' f'>>> status = {resp.status_code}' ) else: for ver in resp.json(): pkg['versions'].append(VxVersion(ver['name'], 'tag', 'remote')) return pkg['versions'] #--- # Public methods #--- def package_clone(self, pkg, prefix=''): """ Clone the package in global storage @args > pkg (dict) - package information returned by package_find() > prefix (str) - clone path prefix @return > Complet path for the package (str), or None if error """ # generate clonning information and handle cache pkg_ver = pkg['version'] pkg_path = f"{prefix}/{pkg['name']}" if not prefix: prefix = os.path.expanduser(config.get('path.packages')) if not os.path.exists(prefix): os.makedirs(prefix) pkg_name = f"{pkg['author']}@{pkg['name']}" pkg_name = f"{pkg_name}@{pkg_ver.name}@{pkg_ver.type}" pkg_path = f"{prefix}/{pkg_name}" if os.path.exists(pkg_path): log.warn(f"[clone]: {pkg_name} already exists, skipped") return pkg_path # perform high-level git clone cmd = [ 'git', '-c', 'advice.detachedHead=false', 'clone', pkg['url'], pkg_path, '--depth=1' ] if pkg_ver.name: cmd += ['--branch', pkg_ver.name] log.debug(f"[gitea] {cmd}") status = subprocess.run(cmd, capture_output=True, check=False) if status.returncode != 0: log.error(f"[clone] : unable to clone {pkg['name']}, abord") return '' # return the package path return pkg_path