Last active
August 9, 2024 20:12
-
-
Save Sigmanificient/c68e03d1ad750a83233c6ab05761cbf2 to your computer and use it in GitHub Desktop.
Script to insert missing `preInstall` and `postInstall` hook within `installPhase` of nixpkgs derivations
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import io | |
import re | |
import pathlib | |
import sys | |
HOOK_PATTERN = r'(?P<ident>[ ]+)?(?P<decl>installPhase\s+=\s+)"(?P<block>.*)";' | |
HOOK_PATTERN_MULTILINE = ( | |
r"(?P<decl>installPhase\s+=\s+(?:let(?:(?!\s+in\s+)(?:.|\n))+\s+in\s+)?)" | |
r"'{2,3}\n?(?P<ident>\s+)?" | |
r"(?P<block>(?:(?!'{2,3};)(?:\n|.)?)+)" | |
r"(?P<quotes>'{2,3});" | |
) | |
def _replace_match_helper(pattern, func): | |
def wrapped(content: str): | |
patched = io.StringIO() | |
last = 0 | |
hit = 0 | |
for matched in re.finditer(pattern, content): | |
full = matched.group() | |
if "preInstall" in full or "postInstall" in full: | |
continue | |
prev, post = matched.span() | |
patched.write(content[last:prev]) | |
func(patched, matched) | |
last = post | |
hit += 1 | |
patched.write(content[last:]) | |
return patched.getvalue(), hit | |
return wrapped | |
def replace_match(pattern): | |
def wrapper(func): | |
return _replace_match_helper(pattern, func) | |
return wrapper | |
@replace_match(HOOK_PATTERN) | |
def add_runhook(out: io.StringIO, matched: re.Match) -> bool: | |
ident, decl, block = matched.groups() | |
ident_out = ident or '' | |
ident = f"{ident_out} " | |
# block = f'\n{ident}'.join(line.strip() for line in block.split(';')) | |
for part in ( | |
ident_out, decl, | |
f'"runHook preInstall; {block}; runHook postInstall";' | |
): | |
out.write(part) | |
return True | |
@replace_match(HOOK_PATTERN_MULTILINE) | |
def add_runhook_multiline(out: io.StringIO, matched: re.Match): | |
decl, ident, block, quotes = matched.groups() | |
ident = ident or ' ' | |
post_ident = ' ' * (len(ident) - 2) | |
for part in ( | |
decl, f"{quotes}\n", | |
ident, "runHook preInstall\n\n", | |
ident, block.strip(), "\n\n", | |
ident, "runHook postInstall\n", | |
post_ident, f"{quotes};", | |
): | |
out.write(part) | |
return True | |
def main(): | |
hits = 0 | |
for filepath in (line.rstrip("\r\n") for line in sys.stdin): | |
content = pathlib.Path(filepath).read_text() | |
print("processing:", filepath) | |
patched, hit = add_runhook(content) | |
hits += hit | |
patched, hit = add_runhook_multiline(patched) | |
hits += hit | |
with open(filepath, 'w+') as f: | |
f.write(patched) | |
print(hits) | |
if __name__ == "__main__": | |
main() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
grep -rP "installPhase =" \ | |
| cut -d ':' -f 1 \ | |
| xargs -i sh -c "grep -P 'runHook\s+preInstall' {} >/dev/null || echo '{}'" \ | |
| python add_missing_hooks.py |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment