Commit 748d9525 authored by bow's avatar bow
Browse files

Add git pre-commit hook script

parent 2c14276c
#!/usr/bin/env python
# Adapted from: http://tech.yipit.com/2011/11/16/183772396/
# Changes by Wibowo Arindrarto
# Changes:
# - Allow code modification by linters to be comitted
# - Updated CHECKS
# - Python 3 calls + code style updates
#
# Usage: save this file into your .git/hooks directory as `pre-commit`
# and set it to executable
import os
import re
import subprocess
import sys
modified = re.compile(r"^[MA]\s+(?P<name>.*)$")
CHECKS = [
{
"exe": "scalariform",
"output": "Formatting code with scalariform ...",
# Remove lines without filenames
"command": "scalariform -s=2.11.1 -p=scalariformStyle.properties --quiet %s",
"match_files": [".*scala$"],
"print_filename": False,
"commit_changes": True,
},
]
def matches_file(file_name, match_files):
return any(re.compile(match_file).match(file_name) for match_file
in match_files)
def check_files(files, check):
result = 0
print(check["output"])
for file_name in files:
if not "match_files" in check or \
matches_file(file_name, check["match_files"]):
if not "ignore_files" in check or \
not matches_file(file_name, check["ignore_files"]):
process = subprocess.Popen(check["command"] % file_name,
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
shell=True)
out, err = process.communicate()
if out or err:
if check["print_filename"]:
prefix = "\t%s:" % file_name
else:
prefix = "\t"
output_lines = ["%s%s" % (prefix, line) for
line in out.splitlines()]
print("\n".join(output_lines))
if err:
print(err)
result = 1
elif check["commit_changes"]:
p = subprocess.Popen(["git", "add", file_name],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p.communicate()
return result
def main(all_files):
# Check that the required linters and code checkers are all present
for check in CHECKS:
p = subprocess.Popen(["which", check["exe"]], stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
out, err = p.communicate()
if not out:
print("Required commit hook executable '%s' not found." % check["exe"])
sys.exit(1)
# Stash any changes to the working tree that are not going to be committed
subprocess.call(["git", "stash", "-u", "--keep-index"], stdout=subprocess.PIPE)
files = []
if all_files:
for root, dirs, file_names in os.walk("."):
for file_name in file_names:
files.append(os.path.join(root, file_name))
else:
p = subprocess.Popen(["git", "status", "--porcelain"],
stdout=subprocess.PIPE)
out, err = p.communicate()
for line in out.splitlines():
match = modified.match(line)
if match:
files.append(match.group("name"))
result = 0
for check in CHECKS:
result = check_files(files, check) or result
# Strategy:
# - Check if the linters made any changes
# - If there are no changes, pop the stash and commit
# - Otherwise:
# - Stash the change
# - Pop stash@{1}
# - Checkout stash@{0}
# - Drop stash@{0} (cannot pop directly since stash may conflict)
# - Commit
# This is because the initial stash will conflict with any possible
# changes made by the linters
p = subprocess.Popen(["git", "status", "--porcelain"],
stdout=subprocess.PIPE)
out, err = p.communicate()
if not out.strip():
subprocess.call(["git", "stash", "pop"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
else:
subprocess.call(["git", "stash"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
subprocess.call(["git", "stash", "pop", "--quiet", "--index", "stash@{1}"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
subprocess.call(["git", "checkout", "stash", "--", "."],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
subprocess.call(["git", "stash", "drop"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
sys.exit(result)
if __name__ == "__main__":
all_files = False
if len(sys.argv) > 1 and sys.argv[1] == "--all-files":
all_files = True
main(all_files)
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment