#!/usr/bin/env python import subprocess import xml.etree.ElementTree as ET import sys all = len(sys.argv) == 2 and sys.argv[-1] == 'all' GIT_COMMIT_FIELDS = ['id', 'author_name', 'author_email', 'date', 'message', 'paths'] GIT_LOG_FORMAT = ['%H', '%an', '%ae', '%ad', '%s'] # # git's --format specifier doesn't cover the list of files (which can be generated # with '--name-only' and '--name-status'. # To be able to identify that path list we inject a '001e' character at the very # beginning of each entry. Then, the list of paths is the last chunk of each entry # following an empty line. GIT_LOG_FORMAT = '%x1e' + '%x1f'.join(GIT_LOG_FORMAT) command = ['git', 'log', '--format=%s' % GIT_LOG_FORMAT, '--name-only'] if not all: # Determine the last release tag and limit history to then. release = ['git', 'describe', '--tags', '--match', 'release/*', '--abbrev=0'] out = subprocess.check_output(release) out = out.strip() command.append('%s..HEAD'%out.decode(encoding='UTF-8')) out = subprocess.check_output(command) out = out.decode(encoding='UTF-8') entries = out.strip('\n\x1e').split('\x1e') entries = [row.strip().split('\x1f') for row in entries] # separate paths from message for entry in entries: t = entry[-1].rsplit('\n\n', 1) entry[-1] = t[0] entry.append(len(t) == 2 and t[1].split('\n') or '') entries = [dict(zip(GIT_COMMIT_FIELDS, entry)) for entry in entries] builder = ET.TreeBuilder() builder.start('log', {}) for e in entries: if not e['id']: continue builder.start('logentry', {'revision':e['id']}) builder.start('author', {}) builder.data(e['author_name']) builder.end('author') builder.start('date', {}) builder.data(e['date']) builder.end('date') builder.start('msg', {}) builder.data(e['message']) builder.end('msg') builder.start('paths', {}) for p in e['paths']: builder.start('path', {}) builder.data(p) builder.end('path') builder.end('paths') builder.end('logentry') builder.end('log') root = builder.close() print(ET.tostring(root, encoding='utf-8'))