#!/usr/bin/env python # -*- coding: UTF-8 -*- ########################################################################## # git2rss.py writen by Mario Izquierdo (mariodebian) # # # Copyright (c) 2006 Mario Izquierdo # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. ########################################################################### # root of git repos GITROOT="/home/mario/forja-rediris/git/" # CGIT url CGIT_URL="http://tcosproject.org/cgit/cgit.cgi" # title of RSS feed TITLE="TCOS project all GIT changes" # description of RSS feed DESCRIPTION="Thin Client operating system" # link of RSS feed LINK="http://www.tcosproject.org" # max items per git repos (more than 10 can cause overcpu usage) MAXITEMS_PROJECT=5 # total max items sorted by date descending MAXITEMS_TOTAL=20 # tmp dir to put some xml files TMPDIR="/tmp" # debug output DEBUG=False import datetime import time import PyRSS2Gen import sys import os import git import traceback def debug(txt): if DEBUG: print >> sys.stderr, "DEBUG: %s" %(txt) class NewCommit(git.Commit): @classmethod def list_from_string(cls, repo, text): """ Parse out commit information into a list of Commit objects ``repo`` is the Repo ``text`` is the text output from the git command (raw format) Returns git.Commit[] """ debug("list_from_string() ") lines = [l for l in text.splitlines() if l.strip()] commits = [] while lines: id = lines.pop(0).split()[1] tree = lines.pop(0).split()[1] parents = [] while lines and lines[0].startswith('parent'): parents.append(lines.pop(0).split()[-1]) author, authored_date = cls.actor(lines.pop(0)) committer, committed_date = cls.actor(lines.pop(0)) messages = [] while lines and lines[0].startswith(' '): messages.append(lines.pop(0).strip()) complete_message=messages #message = messages and messages[0] or '' message = messages commits.append(NewCommit(repo, id=id, parents=parents, tree=tree, author=author, authored_date=authored_date, committer=committer, committed_date=committed_date, message=message)) debug("returning commits ...") return commits def newcommit(self): pass class NewRepo(git.Repo): def log(self, commit = 'master', path = None, **kwargs): """ The commit log for a treeish Returns ``git.Commit[]`` """ options = {'pretty': 'raw'} options.update(kwargs) if path: arg = [commit, '--', path] else: arg = [commit] commits = self.git.log(*arg, **options) debug("NewRepo() call log()") return NewCommit.list_from_string(self, commits) #import git.repo #git.repo.Commit=NewCommit class TcosGit2RSS(object): def __init__(self, project, title, link, description, url, path, maxitems=7): self.project=project self.title=title self.link=link self.description=description self.url=url self.path=path self.maxitems=maxitems self.items=[] def build(self): rss = PyRSS2Gen.RSS2( title = "[%s] %s" %(self.project, self.title), link = self.link, description = self.description, lastBuildDate = datetime.datetime.now(), copyright = "TCOS project", categories = ["tcos", "thin client"], webMaster = "Mario Izquierdo (mariodebian)", items = self.items) return rss def convert_git_date(self, _date): #print _date # GIT (2009, 2, 1, 23, 58, 3, 6, 32, 0) # RSS Tue, 03 Feb 2009 12:37:14 GMT try: strdate=time.strftime("%a, %d %b %Y %H:%M:%S GMT", _date) except: strdate = str(_date) return strdate def add_items(self): commits=self.get_git_log() #return for commit in commits: #print "" #print commit #print "" #print commit['stats'] if not commit.has_key("diff"): commit['diff']="" item=PyRSS2Gen.RSSItem( title = "[%s] %s" %( self.project, commit['message'] ) , link = commit['url'], description = "
".join(commit['complete_message']) + "
==================================="+ "
Author: " + commit['author'] + "
GIT id: " + commit['id'] + "
Date: " + self.convert_git_date(commit['date']) + "
" + commit['diffurl'] + "

"+ #"
Stats: " + "
".join(commit['stats']) + "
" + commit['difftxt'] + "
", guid=commit['id'], author=commit['author'], #pubDate = self.convert_git_date(commit['date']) pubDate = commit['date'] ) debug(" added item in feed %s" %self.project) self.items.append(item) def get_git_commit_info(self, commit): #print "get_git_commit_info( %s )" %commit_id stats=[] for f in commit.stats.files: stats.append("%s => %s" %(f, commit.stats.files[f]) ) stats.append( str(commit.stats.total) ) # commit.committed_date (2009, 2, 1, 23, 58, 3, 6, 32, 0) #print dir(commit.message) diff=[] # build diffs try: for d in commit.diffs: #debug(str(d.diff)) diff.append(str(d.diff)) diff.append("

") except Exception, err: debug("Exception getting diff, project=%s.\nError: %s" %(self.project, err)) if DEBUG: traceback.print_exc(file=sys.stderr) difftxt="" #debug( diff ) for d in diff: difftxt=difftxt+self.clean(d) data={ "author" : str(commit.author), "date" : commit.authored_date, "message": commit.message[0], "complete_message" : commit.message, "stats" : stats, "id" : commit.id, "repo" : commit.repo, "url" : "%s/commit/?id=%s"%(self.url, commit.id), "date" : self.convert_git_date(commit.authored_date), "difftxt": difftxt, "diffurl": "Commit diff"%(self.url, commit.id), } #print data return data def onlyascii(self, char): if ord(char) in [10, 9]: return char elif ord(char) < 30 or ord(char) > 128: #debug( "WARNING: deleting unknow char '%s' => %s" %(char, ord(char)) ) return '' else: #debug(" returning %s => '%s'" %(ord(char), char) ) return char def clean(self, txt): filtered=filter(self.onlyascii, txt) return filtered def get_git_log(self): log=[] repo=NewRepo(self.path) commits=repo.log()[0:self.maxitems] for i in range(len(commits)): if i>0: old_commit=commits[i-1] else: old_commit=None log.append( self.get_git_commit_info( commits[i] ) ) debug("Number of commits in project %s => %s"%( self.project, len(log) ) ) return log if __name__ == "__main__": o=os.walk(GITROOT) # get dirs from gitroot dirs=o.next()[1] # for testing #dirs=["gnome-pulse-applet"] def generate_feed(project): rss=TcosGit2RSS(project=project, title=TITLE, link=LINK, description=DESCRIPTION, url="%s/%s.git" %(CGIT_URL, project), path="%s/%s" %(GITROOT, project), maxitems=MAXITEMS_PROJECT) debug("getting stats from GIT project '%s'" %(project) ) rss.add_items() debug("build xml now of %s"%project) debug( rss.items ) for i in range(len(rss.items)): it=rss.items[i] try: it.to_xml() except: rss.items[i].description=unicode(it.description, errors='replace') xml=rss.build().to_xml(encoding = "utf-8") debug("saving feed '%s/%s.xml'" %(TMPDIR, project) ) f=open("%s/%s.xml"%(TMPDIR, project) , "w") f.write(xml) f.close() import feedparser feeds=[] for pro in dirs: # generate feed try: generate_feed(pro) except Exception, err: debug("Exception generating %s feed.\n\t ERROR %s " %(pro, err)) if DEBUG: traceback.print_exc(file=sys.stderr) continue feeds.append( feedparser.parse("%s/%s.xml" %(TMPDIR, pro) ) ) # remote temp xml os.unlink( "%s/%s.xml"%(TMPDIR, pro) ) debug("Number of feeds %s"%(len(feeds)) ) entries = [] for feed in feeds: entries.extend( feed[ "items" ] ) decorated = [(entry["date_parsed"], entry) for entry in entries] decorated.sort() decorated.reverse() # for most recent entries first _sorted = [entry for (date,entry) in decorated] #print _sorted items=[] for s in _sorted[0:MAXITEMS_TOTAL]: item=PyRSS2Gen.RSSItem( title=s['title'], link=s['link'], description=s['description'], guid=s['id'], pubDate = s['date'], author = s['author'], ) #debug("title '%s'"%s['title'] ) #debug("link '%s'"%s['link']) #debug("date '%s'"%s['date']) items.append(item) rss = PyRSS2Gen.RSS2( title = TITLE, link = LINK, description = DESCRIPTION, lastBuildDate = datetime.datetime.now(), items=items) print rss.to_xml(encoding = "utf-8")