108 lines
3.3 KiB
Python
108 lines
3.3 KiB
Python
from __future__ import annotations
|
|
|
|
import configparser
|
|
import logging
|
|
from io import StringIO
|
|
from pathlib import Path
|
|
|
|
from app.models import Mirror
|
|
from app.services.host import host_path, run_on_host
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
MARKER = "mirror-manager"
|
|
INSTEAD_SECTION = f'url "https://github.com/" managed by {MARKER}'
|
|
|
|
|
|
def _gitconfig_paths() -> list[Path]:
|
|
paths = []
|
|
for rel in ("root/.gitconfig", "home/.gitconfig"):
|
|
p = host_path(rel)
|
|
if p not in paths:
|
|
paths.append(p)
|
|
local = Path.home() / ".gitconfig"
|
|
if local not in paths:
|
|
paths.append(local)
|
|
system = host_path("etc/gitconfig")
|
|
if system not in paths:
|
|
paths.append(system)
|
|
return paths
|
|
|
|
|
|
def read_current_github() -> dict:
|
|
configs = {}
|
|
for path in _gitconfig_paths():
|
|
if path.exists():
|
|
configs[str(path)] = path.read_text(encoding="utf-8")
|
|
return configs
|
|
|
|
|
|
def _parse_gitconfig(content: str) -> configparser.ConfigParser:
|
|
parser = configparser.ConfigParser()
|
|
parser.read_string(content if content.strip() else "[core]\n")
|
|
return parser
|
|
|
|
|
|
def _serialize_gitconfig(parser: configparser.ConfigParser) -> str:
|
|
buf = StringIO()
|
|
parser.write(buf)
|
|
return buf.getvalue()
|
|
|
|
|
|
def _remove_mirror_sections(parser: configparser.ConfigParser) -> None:
|
|
to_remove = []
|
|
for section in parser.sections():
|
|
if not section.startswith('url "'):
|
|
continue
|
|
instead_of = parser.get(section, "insteadOf", fallback="")
|
|
if instead_of in ("https://github.com/", "git@github.com:"):
|
|
to_remove.append(section)
|
|
for section in to_remove:
|
|
parser.remove_section(section)
|
|
|
|
|
|
def apply_github(mirror: Mirror) -> dict:
|
|
meta = mirror.get_meta()
|
|
instead_prefix = meta.get("instead_prefix") or mirror.url
|
|
if not instead_prefix:
|
|
return {"success": False, "error": "prefix میرور GitHub تعریف نشده"}
|
|
|
|
instead_prefix = instead_prefix.rstrip("/") + "/"
|
|
section_name = f'url "{instead_prefix}"'
|
|
|
|
applied_paths = []
|
|
for path in _gitconfig_paths():
|
|
content = path.read_text(encoding="utf-8") if path.exists() else ""
|
|
parser = _parse_gitconfig(content)
|
|
_remove_mirror_sections(parser)
|
|
|
|
if not parser.has_section(section_name):
|
|
parser.add_section(section_name)
|
|
parser.set(section_name, "insteadOf", "https://github.com/")
|
|
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
path.write_text(_serialize_gitconfig(parser), encoding="utf-8")
|
|
applied_paths.append(str(path))
|
|
|
|
test = run_on_host(
|
|
["git", "ls-remote", "https://github.com/octocat/Hello-World.git", "HEAD"],
|
|
timeout=60,
|
|
)
|
|
|
|
return {
|
|
"success": test.returncode == 0,
|
|
"message": f"GitHub mirror اعمال شد: {mirror.name}",
|
|
"paths": applied_paths,
|
|
"test_output": (test.stdout or test.stderr)[:300] if test.returncode != 0 else "git ls-remote موفق",
|
|
"error": test.stderr[:300] if test.returncode != 0 else None,
|
|
}
|
|
|
|
|
|
def remove_github_config() -> None:
|
|
for path in _gitconfig_paths():
|
|
if not path.exists():
|
|
continue
|
|
parser = _parse_gitconfig(path.read_text(encoding="utf-8"))
|
|
_remove_mirror_sections(parser)
|
|
path.write_text(_serialize_gitconfig(parser), encoding="utf-8")
|