#! /usr/bin/python # -*- coding: utf-8 -*- # # Copyright (c) 2011 Grzegorz SobaƄski # # Version: 2.0 # # Git post receive script developed for mlabs # - adds the commits to trac # based on post-receive-email from git-contrib # import re import os import sys from subprocess import Popen, PIPE, call # config TRAC_ENV = '/home/www/alias' GIT_PATH = '/usr/bin/git' TRAC_ADMIN = '/usr/bin/trac-admin' REPO_NAME = '(default)' # communication with git def call_git(command, args, input=None): return Popen([GIT_PATH, command] + args, stdin=PIPE, stdout=PIPE).communicate(input)[0] def get_new_commits(ref_updates): """ Gets a list uf updates from git running post-receive, we want the list of new commits to the repo, that are part of the push. Even if the are in more then one ref in the push. Basically, we are running: git rev-list new1 ^old1 new2 ^old2 ^everything_else It returns a list of commits""" all_refs = set(call_git('for-each-ref', ['--format=%(refname)']).splitlines()) commands = [] for old, new, ref in ref_updates: # branch delete, skip it if re.match('0*$', new): continue commands += [new] all_refs.discard(ref) if not re.match('0*$', old): # update commands += ["^%s" % old] # else: new - do nothing more for ref in all_refs: commands += ["^%s" % ref] new_commits = call_git('rev-list', ['--stdin', '--reverse'], '\n'.join(commands)).splitlines() return new_commits def handle_trac(commits): if not (os.path.exists(TRAC_ENV) and os.path.isdir(TRAC_ENV)): print "Trac path (%s) is not a directory." % TRAC_ENV if len(commits) == 0: return args = [TRAC_ADMIN, TRAC_ENV, 'changeset', 'added', REPO_NAME] + commits call(args) # main if __name__ == '__main__': # gather all commits, to call trac-admin only once lines = sys.stdin.readlines() updates = [line.split() for line in lines] commits = get_new_commits(updates) # call trac-admin handle_trac(commits)