diff --git a/setup/git_hooks.py b/setup/git_hooks.py index e4da9d6d66..5724089cd8 100644 --- a/setup/git_hooks.py +++ b/setup/git_hooks.py @@ -2,35 +2,36 @@ # License: GPLv3 Copyright: 2025, un_pogaz import os -from collections import namedtuple +from contextlib import suppress +from typing import NamedTuple from setup import Command -base = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) -base_hooks = os.path.join(base, '.git', 'hooks') -src_script = os.path.splitext(os.path.realpath(__file__))[0] - - HOOK_TEMPLATE = '''\ -#!/bin/sh -#!/usr/bin/env bash +#!/usr/bin/env -S calibre-debug -e -- -- # File generated by calibre "setup.py git_hooks" -HOOK_DIR=$(cd "$(dirname "$0")" && pwd) -BASE_DIR=$(dirname "$(dirname "$HOOK_DIR")") -SCRIPT=$BASE_DIR/{file} - -exec python "$SCRIPT" {args} +import os +import runpy +import sys +base = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +sys.argv[0] = os.path.basename({file!r}) +runpy.run_path(os.path.join(base, 'setup', {file!r}), run_name='__main__') ''' -Hook = namedtuple('Hook', ['name', 'file', 'args_count', 'default']) + +class Hook(NamedTuple): + name: str + file: str + default: bool = True + HOOKS = {h.name:h for h in ( - Hook('post-checkout', 'git_post_checkout_hook.py', 3, True), - Hook('post-rewrite', 'git_post_rewrite_hook.py', 1, True), - Hook('pre-commit', 'git_pre_commit_hook.py', 0, True), + Hook('post-checkout', 'git_post_checkout_hook.py'), + Hook('post-rewrite', 'git_post_rewrite_hook.py'), + Hook('pre-commit', 'git_pre_commit_hook.py'), # disable by default, because except Kovid, nobody can run this hook - Hook('commit-msg', 'git_commit_msg_hook.py', 1, False), + Hook('commit-msg', 'git_commit_msg_hook.py', False), )} DEFAULT = ','.join(sorted(h.name for h in HOOKS.values() if h.default)) @@ -74,11 +75,10 @@ class GitHooks(Command): self.install() def _parse_template(self, hook_name): + base_hooks = os.path.join(os.path.dirname(self.SRC), '.git', 'hooks') hook = HOOKS[hook_name] path = self.j(base_hooks, hook.name) - sh_file = f'setup/{hook.file}' - sh_args = ' '.join(f'"${i}"' for i in range(1, hook.args_count+1)) - script = HOOK_TEMPLATE.format(file=sh_file, args=sh_args) + script = HOOK_TEMPLATE.format(file=hook.file) return path, script def install(self): @@ -100,8 +100,11 @@ class GitHooks(Command): continue self.info(f'{candidate}: installed.') + with suppress(OSError): + os.remove(path) # remove if symlink with open(path, 'wb') as f: f.write(script.encode('utf-8')) + os.chmod(path, 0o744, follow_symlinks=False) def uninstall(self): self.info('Uninstalling the hooks:', ', '.join(self.names))