mirror of
https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13.git
synced 2025-12-10 09:54:52 +00:00
102 lines
3.4 KiB
Python
Executable File
102 lines
3.4 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# hooks/install.py
|
|
#
|
|
# This script is configured by adding `*.hook` and `*.merge` files in the same
|
|
# directory. Such files should be `#!/bin/sh` scripts, usually invoking Python.
|
|
# This installer will have to be re-run any time a hook or merge file is added
|
|
# or removed, but not when they are changed.
|
|
#
|
|
# Merge drivers will also need a corresponding entry in the `.gitattributes`
|
|
# file.
|
|
|
|
import os
|
|
import stat
|
|
import glob
|
|
import re
|
|
import pygit2
|
|
import shlex
|
|
|
|
|
|
def write_hook(fname, command):
|
|
with open(fname, 'w', encoding='utf-8', newline='\n') as f:
|
|
print("#!/bin/sh", file=f)
|
|
print("exec", command, file=f)
|
|
|
|
# chmod +x
|
|
st = os.stat(fname)
|
|
if not hasattr(st, 'st_file_attributes'):
|
|
os.chmod(fname, st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
|
|
|
|
|
|
def _find_stuff(target=None):
|
|
repo_dir = pygit2.discover_repository(target or os.getcwd())
|
|
repo = pygit2.Repository(repo_dir)
|
|
# Strips any active worktree to find the hooks directory.
|
|
root_repo_dir = re.sub(r'/.git/worktrees/[^/]+/', '/.git/', repo_dir)
|
|
hooks_dir = os.path.join(root_repo_dir, 'hooks')
|
|
return repo, hooks_dir
|
|
|
|
|
|
def uninstall(target=None, keep=()):
|
|
repo, hooks_dir = _find_stuff(target)
|
|
|
|
# Remove hooks
|
|
for fname in glob.glob(os.path.join(hooks_dir, '*')):
|
|
_, shortname = os.path.split(fname)
|
|
if not fname.endswith('.sample') and f"{shortname}.hook" not in keep:
|
|
print('Removing hook:', shortname)
|
|
os.unlink(fname)
|
|
|
|
# Remove merge driver configuration
|
|
for entry in repo.config:
|
|
match = re.match(r'^merge\.([^.]+)\.driver$', entry.name)
|
|
if match and f"{match.group(1)}.merge" not in keep:
|
|
print('Removing merge driver:', match.group(1))
|
|
del repo.config[entry.name]
|
|
|
|
|
|
def install(target=None):
|
|
repo, hooks_dir = _find_stuff(target)
|
|
tools_hooks = os.path.split(__file__)[0]
|
|
|
|
keep = set()
|
|
for full_path in glob.glob(os.path.join(tools_hooks, '*.hook')):
|
|
_, fname = os.path.split(full_path)
|
|
name, _ = os.path.splitext(fname)
|
|
print('Installing hook:', name)
|
|
keep.add(fname)
|
|
relative_path = shlex.quote(os.path.relpath(full_path, repo.workdir).replace('\\', '/'))
|
|
write_hook(os.path.join(hooks_dir, name), f'{relative_path} "$@"')
|
|
|
|
# Use libgit2 config manipulation to set the merge driver config.
|
|
for full_path in glob.glob(os.path.join(tools_hooks, '*.merge')):
|
|
# Merge drivers are documented here: https://git-scm.com/docs/gitattributes
|
|
_, fname = os.path.split(full_path)
|
|
name, _ = os.path.splitext(fname)
|
|
print('Installing merge driver:', name)
|
|
keep.add(fname)
|
|
# %P: "real" path of the file, should not usually be read or modified
|
|
# %O: ancestor's version
|
|
# %A: current version, and also the output path
|
|
# %B: other branches' version
|
|
# %L: conflict marker size
|
|
relative_path = shlex.quote(os.path.relpath(full_path, repo.workdir).replace('\\', '/'))
|
|
repo.config[f"merge.{name}.driver"] = f'{relative_path} %P %O %A %B %L'
|
|
|
|
uninstall(target, keep=keep)
|
|
|
|
|
|
def main(argv):
|
|
if len(argv) <= 1:
|
|
return install()
|
|
elif argv[1] == '--uninstall':
|
|
return uninstall()
|
|
else:
|
|
print("Usage: python -m hooks.install [--uninstall]")
|
|
return 1
|
|
|
|
|
|
if __name__ == '__main__':
|
|
import sys
|
|
exit(main(sys.argv))
|