]> jfr.im git - irc/weechat/scripts.git/commitdiff
New script obsolete.py
authorSebastien Helleu <redacted>
Sat, 10 May 2008 17:39:59 +0000 (19:39 +0200)
committerSebastien Helleu <redacted>
Sat, 10 May 2008 17:39:59 +0000 (19:39 +0200)
python/obsolete.py [new file with mode: 0644]

diff --git a/python/obsolete.py b/python/obsolete.py
new file mode 100644 (file)
index 0000000..7ed33e6
--- /dev/null
@@ -0,0 +1,222 @@
+#!/usr/bin/python
+# -*- encoding: utf-8 -*-
+"""
+  Script to check if your scripts are up to date with list located at
+  http://weechat.flashtux.org/plugins.php, only loaded scripts are
+  checked.
+  Parsing the information related to loaded scripts is full of hacks, 
+  but it works somehow. :)
+
+  The script works with weechat 0.2.6 and needs curl to fetch data from
+  the website. Curl is used as I'm a bit afraid of using threads in 
+  weechat.
+  The script adds command /obsolete that will show you list of packages
+  that has different version and/or are not registered at the scrtips
+  repository.
+
+  The script is in the public domain.
+  Leonid Evdokimov (weechat at darkk dot net dot ru)
+  http://darkk.net.ru/weechat/obsolete.py
+
+0.1  - initial commit
+"""
+
+import weechat
+import sre
+import sys
+from subprocess import Popen
+from tempfile import TemporaryFile
+from xml.dom import Node
+from xml.dom.minidom import parse
+from itertools import ifilter
+
+NAME = 'obsolete'
+VERSION = '0.1'
+
+class WeePrint(object):
+    """ thanks EgS for cool idea (copy-paste from toggle.py)"""
+    def write(self, text):
+        text = text.rstrip(' \0\n')                                    # strip the null byte appended by pythons print
+        if text:
+            text = '[' + NAME + '] '+ text
+            weechat.prnt(text,'')
+
+def isPluginDiv(node):
+    return node.getAttributeNode('class') and node.getAttributeNode('class').nodeValue == u'pluginlist'
+
+def fmtAssert(bool):
+    if not bool:
+        raise RuntimeError, "webpage format changed"
+
+def getTextNodeChild(node):
+    fmtAssert(len(node.childNodes) == 1)
+    child = node.firstChild
+    fmtAssert(child.nodeType == Node.TEXT_NODE)
+    return child.nodeValue
+
+def xor(a, b):
+    return (a and not b) or (not a and b)
+
+downloaders = []
+def Downloader_poll():
+    if len(downloaders) == 0:
+        weechat.remove_timer_handler("Downloader_poll")
+
+    for d in downloaders[:]:
+        if d.poll() != None:
+            downloaders.remove(d)
+            d.run()
+
+    return weechat.PLUGIN_RC_OK
+        
+class Downloader(Popen):
+    def __init__(self, url, ok):
+        self._stdout = TemporaryFile()
+        self._stderr = TemporaryFile()
+        self._ok = ok
+        Popen.__init__(self, ['curl', '--silent', '--show-error', '--fail', url], stdout = self._stdout, stderr = self._stderr)
+        add_timer = not downloaders
+        downloaders.append(self)
+        if add_timer:
+            weechat.add_timer_handler(1, "Downloader_poll")
+
+    def run(self):
+        if self.poll() == 0:
+            f = self._ok
+        else:
+            def fail(stdout, stderr):
+                print "curl failed, exit code %i:" % self.poll()
+                for line in stderr:
+                    print line
+            f = fail
+        self._stdout.seek(0)
+        self._stderr.seek(0)
+        f(self._stdout, self._stderr)
+
+
+class Version:
+    def __init__(self, str):
+        self._ver = [int(chunk) for chunk in str.split('.')]
+    def __str__(self):
+        return '.'.join([str(chunk) for chunk in self._ver])
+    def __eq__(self, that):
+        return self._ver == that._ver
+    def __lt__(self, that):
+        return self._ver < that._ver
+
+class Plugin:
+    def __init__(self, name, ver, lang, url = None):
+        self.name = name
+        self.url = url
+        self.ver = Version(ver)
+        self.lang = lang
+    def __str__(self):
+        return "%s/%s" % (self.lang, self.name)
+
+def parse_published(fd):
+    plugins = {}
+    doc = parse(fd)
+    for div in ifilter(isPluginDiv, doc.getElementsByTagName('div')): 
+        for table in ifilter(lambda n: n.nodeName == u'table', div.childNodes):
+            for tr in ifilter(lambda n: n.nodeName == u'tr', table.childNodes):
+                ths = tuple(ifilter(lambda n: n.nodeName == u'th', tr.childNodes))
+                tds = tuple(ifilter(lambda n: n.nodeName == u'td', tr.childNodes))
+                fmtAssert(xor(ths, tds))
+                if ths:
+                    headers = []
+                    for th in ths[0:3]:
+                        fmtAssert(len(th.childNodes) == 1)
+                        a = th.childNodes[0]
+                        fmtAssert(a.nodeName == u'a')
+                        headers.append(getTextNodeChild(a))
+                    fmtAssert(tuple(headers) == (u'Name', u'Version', u'Language'))
+                if tds:
+                    fmtAssert(len(tds[0].childNodes) == 1)
+                    a = tds[0].firstChild
+                    fmtAssert(a.nodeName == u'a')
+                    href = a.getAttributeNode('href')
+                    fmtAssert(href)
+                    url = getTextNodeChild(href)
+                    name = getTextNodeChild(a)
+                    ver = getTextNodeChild(tds[1])
+                    lang = getTextNodeChild(tds[2])
+                    plugins.setdefault(lang.lower(), {})
+                    plugins[lang.lower()][name.lower()] = Plugin(name, ver, lang, url)
+    return plugins
+
+def get_cmd_output(cmd, serv, channel = ''):
+    offset = len(weechat.get_buffer_data(serv, channel))
+    weechat.command(cmd, channel, serv)
+    data = weechat.get_buffer_data(serv, channel)
+    data.reverse()
+    data = data[offset:]
+    return [l['data'] for l in data]
+
+def get_known_languages(serv):
+    lines = get_cmd_output('/plugin', serv)
+    pairs = {
+        '-P-   Perl v': 'Perl',
+        '-P-   Python v': 'Python',
+        '-P-   Lua v': 'Lua',
+        '-P-   Ruby v': 'Ruby',
+    }
+    retval = []
+    for line in lines:
+        for key, value in pairs.iteritems():
+            if line.lower().find(key.lower()) == 0:
+                retval.append(value)
+    return retval
+
+def get_installed(serv, lang):
+    cmd = '/%s' % lang.lower()
+    lines = get_cmd_output(cmd, serv)
+    parse = False
+    retval = []
+    for line in lines:
+        if parse:
+            match = sre.match(r'-P-   (.*) v([0-9\.]+) - .*', line)
+            if match:
+                name = match.group(1)
+                ver = match.group(2)
+                retval.append(Plugin(name, ver, lang))
+        if line == ('-P- Registered %s scripts:' % lang):
+            parse = True
+        if line == ('-P- %s message handlers:' % lang):
+            break
+    return retval
+
+
+
+def do_obsolete(serv, args):
+    def callback(stdout, stderr):
+        plugins = parse_published(stdout)
+        do_obsolete_finish(serv, plugins)
+    Downloader('http://weechat.flashtux.org/plugins.php', callback)
+    return weechat.PLUGIN_RC_OK
+
+def do_obsolete_finish(serv, plugins):
+    known_languages = get_known_languages(serv)
+
+    installed = {}
+    for lang in known_languages:
+        installed[lang.lower()] = get_installed(serv, lang)
+    
+    for lang in known_languages:
+        for script in installed[lang.lower()]:
+            last = plugins[lang.lower()].get(script.name.lower())
+            if last:
+                if last.ver > script.ver:
+                    print "%s is not up to date: %s installed, %s exists (%s)" % (script, script.ver, last.ver, last.url)
+                elif last.ver < script.ver:
+                    print "%s is newer then published one: %s installed, %s published" % (script, script.ver, last.ver)
+            else:
+                print "%s is not published at all" % (script)
+
+
+if weechat.register(NAME, VERSION, "", "tracks up to date information about scripts"):
+    sys.stdout = WeePrint()
+    weechat.add_command_handler("obsolete", "do_obsolete", "show loaded plugins that are obsolete")
+                    
+# vim:set tabstop=4 softtabstop=4 shiftwidth=4: 
+# vim:set foldmethod=marker foldlevel=32 foldmarker={{{,}}}: 
+# vim:set expandtab: