Subversion Repositories Scribus

Compare Revisions

Ignore whitespace Rev 12489 → Rev 12490

/tools/mrscribe/Svnwatch/plugin.py
0,0 → 1,139
###
# Copyright (c) 2007, Oleksandr Moskalenko
# All rights reserved.
#
# 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.
###
import svnxmlparser
 
import threading
import time
 
from supybot.commands import *
import supybot.conf as conf
import supybot.utils as utils
import supybot.plugins as plugins
import supybot.ircutils as ircutils
import supybot.ircmsgs as ircmsgs
import supybot.registry as registry
import supybot.callbacks as callbacks
 
class Svnwatch(callbacks.Plugin):
"""Main class of the plugin."""
threaded = True
def __init__(self, irc):
self.__parent = super(Svnwatch, self)
self.__parent.__init__(irc)
try:
self.xmluri = self.registryValue('xmluri')
self.wait = self.registryValue('fetchPeriod')
self.postfrequency = self.registryValue('postFrequency')
self.channels = self.registryValue('channels')
self.lastrev = self.registryValue('lastRevision')
self.lastfetch = time.time() - self.wait - 1
self.log.debug("%s; %s, %s, %s, %s" % (self.xmluri, self.wait, self.postfrequency, self.channels, self.lastrev))
except registry.NonExistentRegistryEntry:
self.log.debug('%s is not a registered URI.', self.xmluri)
irc.error('Can\'t get configuration variables.', Raise=True)
self.getCommit(irc)
 
def canGetNewCommit(self, irc):
"""Checks if more then fetchPeriod time lapsed since our last fetch.
Returns True is that's the case and False if we need to wait longer."""
self.now = time.time()
self.log.debug("Current time: %s; Last fetch: %s; Difference: %d sec" % (self.now, self.lastfetch, int(self.now - self.lastfetch)))
if self.now - self.lastfetch > self.wait:
self.log.debug("Enough time passed, fetching new commit...")
return True
else:
self.log.debug("Not enough time passed, standing by...")
return False
 
def getHead(self, xmluri):
"""Fetches the head revision number for internal processing. Returns 'HEAD'
in case of error or misconfiguration."""
self.xmluri = xmluri
self.rev = "HEAD"
self.rawxml = svnxmlparser.fetchXml(self.xmluri, self.rev)
self.commitdata = svnxmlparser.getCommit(self.rawxml)
if self.commitdata == None:
self.log.info("Cannot fetch revision %s" % (self.rev))
# raise "Cannot fetch head revision id"
return None
else:
return self.commitdata.keys()[0]
 
def getCommit(self, irc):
self.channels = self.registryValue('channels')
self.log.debug("Reporting channels: %s", self.channels)
self.lastrev = self.registryValue('lastRevision')
# if self.canGetNewCommit(irc):
try:
self.log.debug('Fetching HEAD revision number from %s', self.xmluri)
self.headid = self.getHead(self.xmluri)
self.log.debug('Current HEAD revision number: %s', self.headid)
if self.headid == None:
self.log.debug('Error occured while fetching HEAD revision from %s', self.xmluri)
self.now = time.time()
self.lastfetch = self.now
self.log.debug("Failed to fetch 'HEAD' at %s" % (self.now))
elif int(self.headid) == self.lastrev:
self.log.debug("Fetched 'HEAD' - no new commmits at %s", self.xmluri)
self.now = time.time()
self.lastfetch = self.now
self.log.debug("Fetched new 'HEAD' revision at %s" % (self.now))
else:
self.oldestnewrev = self.lastrev + 1
self.revid = "%s:HEAD" % self.oldestnewrev
self.revuri = self.xmluri + "?" + self.revid
self.log.debug("Fetching new commit(s) for %s" % self.revuri)
self.rawxml = svnxmlparser.fetchXml(self.xmluri, self.revid)
self.log.debug("Fetched xml %s" % self.rawxml)
self.resultcommitdata = svnxmlparser.getCommit(self.rawxml)
self.log.debug("Fetched data %s" % self.resultcommitdata)
self.shortdata = svnxmlparser.shortoutput(self.resultcommitdata)
self.log.debug("Short data: %s" % self.shortdata)
if len(self.shortdata) == 1:
self.revisiondata = " ".join(self.shortdata)
self.log.debug("Formatted data: %s" % self.revisiondata)
self.lastrev = int(self.revisiondata.split(" ")[1])
self.log.debug("Revision ID: %s" % self.lastrev)
for self.channel in self.channels:
irc.replies(self.revisiondata, joiner='', to=self.channel, prefixNick=False, private=True)
else:
for self.revisiondata in self.shortdata:
self.log.debug("Revision data: %s" % self.revisiondata)
self.lastrev = int(self.revisiondata.split(" ")[1])
self.log.debug("Last revision ID: %s" % self.lastrev)
for self.channel in self.channels:
irc.replies(self.revisiondata, joiner='', to=self.channel, prefixNick=False, private=True)
self.now = time.time()
self.lastfetch = self.now
conf.supybot.plugins.Svnwatch.lastRevision.setValue(self.lastrev)
self.log.debug("Fetched new commit(s) up to revision %s at %s"
% (self.lastrev, self.now))
except:
raise
 
def __call__(self, irc, msg):
self.__parent.__call__(irc, msg)
irc = callbacks.SimpleProxy(irc, msg)
if self.canGetNewCommit(irc):
self.log.debug("Invoking __call__")
self.getCommit(irc)
 
Class = Svnwatch
 
 
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
/tools/mrscribe/Svnwatch/__init__.py
0,0 → 1,56
###
# Supybot plugin for querying SVN commits and posting commit log
# Copyright (c) 2007, Oleksandr Moskalenko
# All rights reserved.
#
# 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.
###
 
"""
This plugin posts SVN commit summary to a channell and allows queries for
specific revisions and partial commit data """
 
import supybot
import supybot.world as world
 
# Use this for the version of this plugin. You may wish to put a CVS keyword
# in here if you're keeping the plugin in CVS or some similar system.
__version__ = "0.1"
 
# Replace this with an appropriate author or supybot.Author instance.
__author__ = supybot.Author('Oleksandr Moskalenko', 'malex', 'malex@tagancha.org')
 
# This is a dictionary mapping supybot.Author instances to lists of
# contributions.
__contributors__ = {}
 
# This is a url where the most recent plugin package can be downloaded.
__url__ = 'http://linux.tagancha.org/software/supybot/Svnwatch'
 
import config
import plugin
import svnxmlparser
reload(plugin) # In case we're being reloaded.
reload(svnxmlparser) # In case we're being reloaded
# Add more reloads here if you add third-party modules and want them to be
# reloaded when this plugin is reloaded. Don't forget to import them as well!
 
if world.testing:
import test
 
Class = plugin.Class
configure = config.configure
 
 
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
/tools/mrscribe/Svnwatch/test.py
0,0 → 1,14
###
# Copyright (c) 2007, Oleksandr Moskalenko
# All rights reserved.
#
#
###
 
from supybot.test import *
 
class SvnwatchTestCase(PluginTestCase):
plugins = ('Svnwatch',)
 
 
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
/tools/mrscribe/Svnwatch/README.txt
0,0 → 1,4
This plugin will query a svn web front-end and fetch svn XML data related to
the commit information. It will immediately post the newest commit data to the
configured IRC channel(s). It will also create a local database of commits and
return full or partial commit data on request to registered users.
/tools/mrscribe/Svnwatch/svnxmlparser.py
0,0 → 1,209
#!/usr/bin/python
# Copyright (c) 2007, Oleksandr Moskalenko, Craig Ringer
# All rights reserved.
#
# 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.
###
"""Subversion XML parser
"""
__version__ = "0.1"
__license__ = "GPLv2"
__copyright__ = "Copyright 2007, Oleksandr Moskalenko"
__author__ = "Oleksandr Moskalenko <malex@tagancha.org>"
__contributors__ = ["Craig Ringer <craig@postnewspapers.com.au>"]
_debug = 1
 
# HTTP "User-Agent" header to send to servers when downloading Svn XML.
USER_AGENT = "SubversionXMLParser/%s +http://linux.tagancha.org/svnxmlparser" % __version__
# HTTP "Accept" header to send to servers when downloading Svn XML. If you don't
# want to send an Accept header, set this to None.
ACCEPT_HEADER = "text/xml"
 
# Default URI:
URI = "https://www.postnewspapers.com.au/cgi-bin/xmllog"
 
def fetchXml(uri, rev):
"""Fetches a document from the given URI (with gzip encoding). Returns the
document as a string, or an empty string in case of a transmission problem."""
import urllib2, gzip, StringIO
try:
revuri = "%s?%s" % (uri,rev)
request = urllib2.Request(revuri)
request.add_header('Accept-encoding', 'gzip')
opener = urllib2.build_opener()
handle = opener.open(request)
compressedData = handle.read()
# print 'Fetched ', len(compressedData), ' bytes.'
compressedStream = StringIO.StringIO(compressedData)
gzipper = gzip.GzipFile(fileobj=compressedStream,mode='r')
xml = gzipper.read()
if len(xml) <= 28:
print "No commit for this revision\n"
return None
return xml
except:
return None
 
def longest_common_prefix_for_paths(paths):
'''
Find the longest common prefix of `paths' and return it.
`paths' must be a list of strings, using / as a path component
separator.
'''
if len(paths) == 1:
# use just this path
return paths[0]
else:
# find common prefix
p = [ x.split('/') for x in paths ]
maxi = reduce( min, map( len, p ) )
for i in range(0, maxi):
if not reduce( lambda a,b: a and (b[i] == paths[0][i]),\
paths[1:], True):
break
return '/'.join(p[0][0:i])
 
def getText(nodelist):
rc = ""
for node in nodelist:
if node.nodeType == node.TEXT_NODE:
rc = rc + node.data
return rc
 
def getCommit (xml):
"""Parses Svn XML and returns a dictionary containing commit data."""
if xml == None:
return xml
from xml.dom import minidom, Node
xmltree = minidom.parseString(xml)
logentries = xmltree.getElementsByTagName('logentry')
logdata = {}
for logentry in logentries:
if logentry.hasAttributes():
revision = logentry.getAttribute('revision')
logdata[revision]= {}
logdata[revision]['author'] = logentry.getElementsByTagName('author')[0].childNodes[0].data
logdata[revision]['date'] = logentry.getElementsByTagName('date')[0].childNodes[0].data
try:
logdata[revision]['msg'] = logentry.getElementsByTagName('msg')[0].childNodes[0].data
except IndexError:
logdata[revision]['msg'] = ""
paths = []
for path in logentry.getElementsByTagName("paths")[0].childNodes:
if path.nodeType == Node.ELEMENT_NODE:
paths.append(path.childNodes[0].data)
logdata[revision]['paths'] = paths
common_path = longest_common_prefix_for_paths(paths)
logdata[revision]['common_path'] = common_path
short_paths = []
for path in paths:
try:
short_paths.append(path.split(common_path)[1][1:])
except IndexError:
pass
logdata[revision]['short_paths'] = short_paths
return logdata
 
def printoutput(commitdata):
datakeys = commitdata.keys()
datakeys.sort()
for i in datakeys:
logentry = commitdata[i]
logentry.keys().sort()
print "Revision: " + str(i)
for j in logentry.keys():
if type(logentry[j]) != list:
print "%s: \t %s" % (j,logentry[j].strip())
else:
print j+":"
for k in logentry[j]:
print "\t "+k
 
def getbranch(logentry):
import sys
fullpath = logentry['common_path']
pathelements = fullpath.split("/")
if pathelements[1] == 'trunk':
return 'trunk'
else:
return "%s" % pathelements[2]
 
def shortoutput(commitdata):
outlist = []
datakeys = commitdata.keys()
datakeys.sort()
for i in datakeys:
logentry = commitdata[i]
logentry.keys().sort()
from datetime import datetime
from time import strptime
indatetime = logentry["date"].split('.')[0]
rawdatetime = datetime(*strptime(indatetime, "%Y-%m-%dT%H:%M:%S")[0:6])
outdate,outtime = rawdatetime.strftime("%Y-%m-%d %H:%M:%S").split(" ")
branch = getbranch(logentry)
outstr = "revision %s by %s in %s on %s at %s - %s" % (i, logentry["author"], branch, outdate, outtime, logentry["msg"])
finalstr = outstr.replace("\n", " ")
outlist.append(finalstr)
return outlist
# for j in logentry.keys():
# #FIXME
# if type(logentry[j]) != list:
# print "%s: \t %s" % (j,logentry[j].strip())
# else:
# print j+":"
# for k in logentry[j]:
# print "\t "+k
 
def processUri(xmluri,rev):
print xmluri
rawxml = fetchXml(xmluri,rev)
commitdata = getCommit(rawxml)
if commitdata == None:
return None
else:
outdata = shortoutput(commitdata)
return outdata
 
def getHead(xmluri):
"""Fetches the head revision number for internal processing. Returns 'HEAD'
in case of error or misconfiguration."""
rev = "HEAD"
rawxml = fetchXml(xmluri,rev)
commitdata = getCommit(rawxml)
if commitdata == None:
return None
else:
return commitdata.keys()[0]
 
def Main ():
import sys
"""Called when the program is used interactively."""
if len(sys.argv)>1:
args = sys.argv[1:]
# print args
else:
args = ['HEAD']
for i in args:
print "Fetching commit information for '%s':" % i
xml = fetchXml(URI,i)
commitdata = getCommit(xml)
if commitdata == None:
sys.exit()
out = shortoutput(commitdata)
for i in out:
print i
sys.exit()
 
if __name__ == '__main__':
Main()
/tools/mrscribe/Svnwatch/config.py
0,0 → 1,59
###
# Copyright (c) 2007, Oleksandr Moskalenko
# All rights reserved.
#
# 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.
###
 
import supybot.conf as conf
import supybot.registry as registry
import supybot.callbacks as callbacks
 
def configure(advanced):
# This will be called by supybot to configure this module. advanced is
# a bool that specifies whether the user identified himself as an advanced
# user or not. You should effect your configuration by manipulating the
# registry as appropriate.
from supybot.questions import expect, anything, something, yn
conf.registerPlugin('Svnwatch', True)
output('The default SVN xml URI is https://www.postnewspapers.com.au/cgi-bin/xmllog')
if yn('Would you like to specify a SVN xml URI?'):
xmluri = something('SVN XML URI?')
conf.supybot.plugins.Svnwatch.set(xmluri)
 
#class PostChannels(registry.SpaceSeparated):
# List = callbacks.CanonicalNameSet
 
Svnwatch = conf.registerPlugin('Svnwatch')
# This is where your configuration variables (if any) should go. For example:
# conf.registerGlobalValue(Svnwatch, 'someConfigVariableName',
# registry.Boolean(False, """Help for someConfigVariableName."""))
conf.registerGlobalValue(Svnwatch, 'xmluri',
registry.String('https://www.postnewspapers.com.au/cgi-bin/xmllog',
"""The uri for the exported SVN XML source."""))
conf.registerGlobalValue(Svnwatch, 'fetchPeriod',
registry.PositiveInteger(60, """Indicates how many seconds the
bot will wait between retrieving new svn commit
information."""))
conf.registerGlobalValue(Svnwatch, 'lastRevision',
registry.PositiveInteger(1000, """Indicates the last revision published in
the channels."""))
conf.registerGlobalValue(Svnwatch, 'postFrequency', registry.PositiveInteger(5,
"""Indicates how many seconds the bot will wait between posting svn commit
information messages."""))
conf.registerGlobalValue(Svnwatch,
'channels', conf.SpaceSeparatedSetOfChannels([], """Determines
which channels the bot will post SVN commit information to."""))
 
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: