Commit 02b01937 authored by Vincent Pelletier's avatar Vincent Pelletier

update-hash: New executable.

Useful only for software-release development, not usage, so not adding it
to packaging, only to repository.
parent 9aa07980
#!/usr/bin/env python
"""
Suggested installation:
$ cp update-hash .git/hooks/
$ $EDITOR .git/hooks/pre-commit
#!/bin/bash
set -e
touch "$(git rev-parse --git-dir)/hooks/.need-post-commit"
$ $EDITOR .git/hooks/post-commit
#!/bin/bash
set -e
MARKER="$(git rev-parse --git-dir)/hooks/.need-post-commit"
UPDATE_HASH="$(git rev-parse --git-dir)/hooks/update-hash"
if [ -e "$MARKER" -a -x "$UPDATE_HASH" ]; then
rm "$MARKER"
if git diff-index --quiet HEAD -- ; then
# nothing
true
else
git stash save --keep-index --quiet "update-hash pre-commit hook"
trap "git stash pop" EXIT
fi
find "$(git rev-parse --show-toplevel)" -name "buildout.hash.cfg" | while IFS= read -r HASHFILE; do
"$UPDATE_HASH" "$HASHFILE"
git add "$HASHFILE"
done
git commit --amend --no-verify -C HEAD
fi
BEWARE: rebasing does not trigger this hook, so you have to commit each
change explicitely. Improvements welcome.
"""
import hashlib
import os
import shutil
import sys
import tempfile
# Note: this is an intentionally very restrictive and primitive
# ConfigParser-ish parser.
# buildout.hash.cfg files are ConfigParser-compatible, but they are *not*
# ConfigParser syntax in order to be strictly validated, to prevent misuse
# and allow easy extension (ex: to other hashes).
FILENAME_KEY = 'filename'
HASH_MAP = {
'md5sum': hashlib.md5,
}
def main():
for infile_path in sys.argv[1:] or ['buildout.hash.cfg']:
eol = None
hash_file_path = None
hash_name = None
current_section = None
infile_dirname = os.path.dirname(infile_path)
outfile_path = infile_path + '.tmp'
infile = open(infile_path, 'r')
outfile_fd = os.open(outfile_path, os.O_EXCL | os.O_CREAT | os.O_WRONLY)
try:
outfile = os.fdopen(outfile_fd, 'w')
write = outfile.write
nextLine = iter(infile).next
while True:
try:
line = nextLine()
except StopIteration:
line = None
if line is None or not line.startswith('#'):
if line is None or line.startswith('['):
if hash_file_path is not None:
current_section.insert(
2,
'%s = %s%s' % (
hash_name,
HASH_MAP[hash_name](
open(
os.path.join(
infile_dirname,
hash_file_path,
)
).read()
).hexdigest(),
eol,
),
)
outfile.writelines(current_section)
hash_file_path = hash_name = None
if line is None:
break
current_section = []
elif '=' in line:
assert current_section is not None, line
name, value = line.split('=', 1)
name = name.strip()
value = value.strip()
if name == FILENAME_KEY:
hash_file_path = value
current_section.append(line)
else:
for hash_name in HASH_MAP:
if name == hash_name:
break
else:
raise ValueError('Unknown key: %r' % (name, ))
# NOT appending this line, it will be re-generated from
# scratch
eol = ''.join(x for x in line if x in ('\r', '\n'))
continue
if current_section is None:
write(line)
else:
current_section.append(line)
outfile.close()
shutil.copymode(infile_path, outfile_path)
shutil.move(outfile_path, infile_path)
except Exception:
os.unlink(outfile_path)
raise
if __name__ == '__main__':
main()
Markdown is supported
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