feat: simulate git clone

This commit is contained in:
tretrauit 2023-06-16 04:36:45 +07:00
parent 6ef9911461
commit 8ca7cd3504
2 changed files with 76 additions and 8 deletions

View File

@ -22,3 +22,5 @@ tools_cache_path = base_dirs.site_cache_path.joinpath("tools")
tools_cache_path.mkdir(parents=True, exist_ok=True)
launcher_cache_path = base_dirs.site_cache_path.joinpath("launcher")
launcher_cache_path.mkdir(parents=True, exist_ok=True)
utils_cache_path = base_dirs.site_cache_path.joinpath("utils")
utils_cache_path.mkdir(parents=True, exist_ok=True)

View File

@ -1,35 +1,99 @@
import subprocess
import requests
import json
from pathlib import Path
from shutil import which
from vollerei.utils.git.exceptions import GitCloneError, GitNotInstalled
from zipfile import ZipFile
from io import BytesIO
from shutil import which, rmtree
from urllib.parse import urlparse
from vollerei.constants import utils_cache_path
from vollerei.utils.git.exceptions import GitCloneError
class Git:
"""
Quick wrapper around git binary
Quick wrapper around git binary (or simulate git if git is not installed)
Simulate git because Windows users may not have git installed.
"""
def __init__(self) -> None:
pass
self._cache = utils_cache_path.joinpath("git")
self._cache.mkdir(parents=True, exist_ok=True)
@staticmethod
def check_git():
def is_installed():
"""
Check for git installation, if not found raise GitNotInstalled
"""
if not which("git"):
raise GitNotInstalled("git is not installed")
return False
return True
def _is_gitea(self, netloc: str) -> bool:
"""
Check if the url is a Gitea server
"""
rsp = requests.get(f"https://{netloc}/api/v1/meta")
try:
data: dict = rsp.json()
except json.JSONDecodeError:
return False
if not data.get("version"):
return False
return True
def _clone(self, url: str, path: str = None) -> None:
"""
"Clone" a git repository without git
"""
if Path(url).suffix == ".git":
url = url[:-4]
url_info = urlparse(url)
netloc = url_info.netloc
if path is None:
path = Path.cwd().joinpath(Path(url).stem)
if self._is_gitea(netloc):
# Hardcoding the branch to master, because well :D
file = BytesIO()
rsp = requests.get(
f"https://{netloc}/api/v1/repos/{url_info.path}/archive/master.zip",
stream=True,
)
rsp.raise_for_status()
with open(file, "wb") as f:
for chunk in rsp.iter_content(chunk_size=32768):
f.write(chunk)
zip_file = ZipFile(file)
zip_file.extractall(path)
with Path(path).joinpath(".git/PLEASE_INSTALL_GIT").open("w") as f:
f.write(json.dumps({"type": "gitea", "netloc": netloc, "path": url_info.path}))
else:
raise NotImplementedError
def pull_or_clone(self, url: str, path: str = None) -> None:
self.check_git()
"""
Pulls or clones a git repository
If the repository already exists and the url matches, it'll be pulled.
"""
if not self.is_installed():
# Git is not installed, we need to simulate it
self._clone(url, path)
return
if path is None:
path = Path.cwd().joinpath(Path(url).stem)
if Path(url).suffix == ".git":
path = Path.cwd().joinpath(Path(url).stem)
else:
path = Path.cwd().joinpath(Path(url).name)
path_as_path = Path(path)
if path_as_path.joinpath(".git/PLEASE_INSTALL_GIT").exists():
# This is a fake .git directory we created.
# We need to clone the repository
rmtree(path)
try:
if not path_as_path.exists():
raise subprocess.CalledProcessError
origin_url = subprocess.check_output(
["git", "config", "--get", "remote.origin.url"], cwd=path
).decode()
@ -37,6 +101,8 @@ class Git:
raise subprocess.CalledProcessError
subprocess.check_call(["git", "pull"], cwd=path)
except subprocess.CalledProcessError:
if path_as_path.exists():
rmtree(path)
try:
subprocess.check_call(["git", "clone", url, path])
except subprocess.CalledProcessError as e: