mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-12-09 14:45:01 -05:00
setup.py git_hooks
Install/uninstall git hooks
This commit is contained in:
parent
4fe9fe2974
commit
e7e1f86183
@ -15,6 +15,7 @@ __all__ = [
|
||||
'export_packages',
|
||||
'extdev',
|
||||
'get_translations',
|
||||
'git_hooks',
|
||||
'git_version',
|
||||
'gui',
|
||||
'hyphenation',
|
||||
@ -102,6 +103,10 @@ from setup.liberation import LiberationFonts
|
||||
|
||||
liberation_fonts = LiberationFonts()
|
||||
|
||||
from setup.git_hooks import GitHooks
|
||||
|
||||
git_hooks = GitHooks()
|
||||
|
||||
from setup.git_version import GitVersion
|
||||
|
||||
git_version = GitVersion()
|
||||
|
||||
125
setup/git_hooks.py
Normal file
125
setup/git_hooks.py
Normal file
@ -0,0 +1,125 @@
|
||||
#!/usr/bin/env python
|
||||
# License: GPLv3 Copyright: 2025, un_pogaz <un.pogaz@gmail.com>
|
||||
|
||||
import os
|
||||
from collections 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
|
||||
# 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}
|
||||
'''
|
||||
|
||||
Hook = namedtuple('Hook', ['name', 'file', 'args_count', 'default'])
|
||||
|
||||
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),
|
||||
# disable by default, because except Kovid, nobody can run this hook
|
||||
Hook('commit-msg', 'git_commit_msg_hook.py', 1, False),
|
||||
)}
|
||||
|
||||
DEFAULT = ','.join(sorted(h.name for h in HOOKS.values() if h.default))
|
||||
AVAILABLES = ', '.join(sorted(h for h in HOOKS))
|
||||
|
||||
|
||||
class GitHooks(Command):
|
||||
description = 'Install/uninstall git hooks'
|
||||
|
||||
def add_options(self, parser):
|
||||
parser.add_option('-n', '--name', default=DEFAULT,
|
||||
help='Name(s) of the hook to install, separated by commas. '
|
||||
f'Default: "{DEFAULT}". Hooks available: {AVAILABLES}')
|
||||
parser.add_option('-u', '--uninstall', default=False, action='store_true',
|
||||
help='Uninstall the selected hooks')
|
||||
parser.add_option('-f', '--force', default=False, action='store_true',
|
||||
help='Force the operations on the hooks')
|
||||
|
||||
def run(self, opts):
|
||||
self.force = opts.force
|
||||
self.names = []
|
||||
|
||||
invalides = []
|
||||
for candidate in sorted(c.strip().lower() for c in opts.name.split(',')):
|
||||
if not candidate:
|
||||
continue
|
||||
if candidate not in HOOKS:
|
||||
invalides.append(candidate)
|
||||
else:
|
||||
self.names.append(candidate)
|
||||
|
||||
if invalides:
|
||||
self.info('Info: The following hook names are not recognized:', ', '.join(invalides))
|
||||
if not self.names:
|
||||
self.info('No supported hook names recognized.')
|
||||
return
|
||||
|
||||
if opts.uninstall:
|
||||
self.uninstall()
|
||||
else:
|
||||
self.install()
|
||||
|
||||
def _parse_template(self, hook_name):
|
||||
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)
|
||||
return path, script
|
||||
|
||||
def install(self):
|
||||
self.info('Installing the hooks:', ', '.join(self.names))
|
||||
for candidate in self.names:
|
||||
path, script = self._parse_template(candidate)
|
||||
|
||||
if self.e(path):
|
||||
with open(path, 'rb') as f:
|
||||
previous = f.read().decode('utf-8')
|
||||
msg = f'{candidate}: a non-calibre hook is installed.'
|
||||
if previous == script:
|
||||
self.info(f'{candidate}: installed.')
|
||||
continue
|
||||
elif self.force:
|
||||
self.info(msg, 'Force installation.')
|
||||
else:
|
||||
self.info(msg, 'Skip installation.')
|
||||
continue
|
||||
|
||||
self.info(f'{candidate}: installed.')
|
||||
with open(path, 'wb') as f:
|
||||
f.write(script.encode('utf-8'))
|
||||
|
||||
def uninstall(self):
|
||||
self.info('Uninstalling the hooks:', ', '.join(self.names))
|
||||
for candidate in self.names:
|
||||
path, script = self._parse_template(candidate)
|
||||
|
||||
if not self.e(path):
|
||||
self.info(f'{candidate}: no hook to unistall.')
|
||||
continue
|
||||
|
||||
with open(path, 'rb') as f:
|
||||
previous = f.read().decode('utf-8')
|
||||
msg = f'{candidate}: a non-calibre hook is installed.'
|
||||
if previous == script:
|
||||
self.info(f'{candidate}: unistalled.')
|
||||
elif self.force:
|
||||
self.info(msg, 'Force unistallation.')
|
||||
else:
|
||||
self.info(msg, 'Skip unistallation.')
|
||||
continue
|
||||
|
||||
os.remove(path)
|
||||
Loading…
x
Reference in New Issue
Block a user