From 38ee8f5181c2d241466988b33c30ad525aa0683e Mon Sep 17 00:00:00 2001 From: Egor Tensin Date: Tue, 30 Mar 2021 00:48:58 +0300 Subject: cgitize.cgit: factor out setup_git_auth --- cgitize/cgit.py | 39 ++------------------------------------- cgitize/git.py | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ cgitize/utils.py | 22 ++++++++++++++++++++++ 3 files changed, 72 insertions(+), 37 deletions(-) diff --git a/cgitize/cgit.py b/cgitize/cgit.py index 167456f..7c6e6f6 100644 --- a/cgitize/cgit.py +++ b/cgitize/cgit.py @@ -3,49 +3,14 @@ # For details, see https://github.com/egor-tensin/cgitize. # Distributed under the MIT License. -from contextlib import contextmanager import logging import os -import os.path import shutil -import stat from cgitize.git import Git from cgitize.utils import chdir -@contextmanager -def setup_git_auth(repo): - if not repo.url_auth: - yield - return - config_path = os.path.expanduser('~/.gitconfig') - exists = os.path.exists(config_path) - if exists: - old_permissions = stat.S_IMODE(os.stat(config_path).st_mode) - new_permissions = stat.S_IRUSR | stat.S_IWUSR # 0x600 - os.chmod(config_path, new_permissions) - with open(config_path, encoding='utf-8', mode='r') as fd: - old_contents = fd.read() - else: - old_contents = '' - new_contents = f'''{old_contents} -[url "{repo.clone_url_with_auth}"] - insteadOf = {repo.clone_url} -''' - with open(config_path, encoding='utf-8', mode='w') as fd: - fd.write(new_contents) - try: - yield - finally: - if exists: - with open(config_path, encoding='utf-8', mode='w') as fd: - fd.write(old_contents) - os.chmod(config_path, old_permissions) - else: - os.unlink(config_path) - - class CGitServer: def __init__(self, clone_url): self.clone_url = clone_url @@ -150,14 +115,14 @@ class CGitRepositories: except Exception as e: logging.exception(e) return False - with setup_git_auth(repo): + with Git.setup_auth(repo): return Git.check('clone', '--mirror', '--quiet', repo.clone_url, repo_dir) def _update_existing(self, repo): logging.info("Updating repository '%s'", repo.repo_id) repo_dir = self.get_repo_dir(repo) with chdir(repo_dir): - with setup_git_auth(repo): + with Git.setup_auth(repo): if not Git.check('remote', 'update', '--prune'): return False # In case the local repository is not a bare repository, but a diff --git a/cgitize/git.py b/cgitize/git.py index 87554dd..a2be8df 100644 --- a/cgitize/git.py +++ b/cgitize/git.py @@ -3,6 +3,7 @@ # For details, see https://github.com/egor-tensin/cgitize. # Distributed under the MIT License. +from contextlib import contextmanager import os import cgitize.utils as utils @@ -12,6 +13,33 @@ GIT_ENV = os.environ.copy() GIT_ENV['GIT_SSH_COMMAND'] = 'ssh -oBatchMode=yes -oLogLevel=QUIET -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null' +class Config: + def __init__(self, path): + self.path = path + + def exists(self): + return os.path.exists(self.path) + + def open(self, mode='r'): + return open(self.path, mode=mode, encoding='utf-8') + + def read(self): + with self.open(mode='r') as fd: + return fd.read() + + def write(self, contents): + with self.open(mode='w') as fd: + fd.write(contents) + + @contextmanager + def backup(self): + old_contents = self.read() + try: + yield old_contents + finally: + self.write(old_contents) + + class Git: EXE = 'git' @@ -22,3 +50,23 @@ class Git: @staticmethod def capture(*args, **kwargs): return utils.try_run_capture(Git.EXE, *args, env=GIT_ENV, **kwargs) + + @staticmethod + def get_global_config(): + return Config(os.path.expanduser('~/.gitconfig')) + + @staticmethod + @contextmanager + def setup_auth(repo): + if not repo.url_auth: + yield + return + config = Git.get_global_config() + with utils.protected_file(config.path): + with config.backup() as old_contents: + new_contents = f'''{old_contents} +[url "{repo.clone_url_with_auth}"] + insteadOf = {repo.clone_url} +''' + config.write(new_contents) + yield diff --git a/cgitize/utils.py b/cgitize/utils.py index 0bfa855..152684f 100644 --- a/cgitize/utils.py +++ b/cgitize/utils.py @@ -6,6 +6,7 @@ from contextlib import contextmanager import logging import os +import stat import subprocess import sys @@ -69,3 +70,24 @@ def chdir(new_cwd): yield finally: os.chdir(old_cwd) + + +@contextmanager +def protected_file(path): + # 0600: + new_permissions = stat.S_IRUSR | stat.S_IWUSR + if os.path.exists(path): + old_permissions = stat.S_IMODE(os.stat(path).st_mode) + os.chmod(path, new_permissions) + try: + yield + finally: + os.chmod(path, old_permissions) + else: + with open(path, mode='w'): + pass + os.chmod(path, new_permissions) + try: + yield + finally: + os.unlink(path) -- cgit v1.2.3