#! /usr/local/bin/python2.3
"""Simple version repository for SpamBayes core, and our main apps.
Also has the ability to load this version information from a remote location
(in that case, we actually load a "ConfigParser" version of the file to
avoid importing code we can't trust.) This allows any app to check if there
is a later version available.
The makefile process for the website will execute this as a script, which
will generate the "ConfigParser" version for the web.
"""
# See bug 806238: urllib2 fails in Outlook new-version chk.
# A reason for why the spambayes.org URL fails is given in a comment there.
#LATEST_VERSION_HOME="http://www.spambayes.org/download/Version.cfg"
# The SF URL instead works for Tim and xenogeist.
LATEST_VERSION_HOME="http://spambayes.sourceforge.net/download/Version.cfg"
# This module is part of the spambayes project, which is Copyright 2002-4
# The Python Software Foundation and is covered by the Python Software
# Foundation license.
versions = {
# Non app specific - changed when "spambayes\*" changes significantly
"Version": 0.3,
"Description": "SpamBayes Engine",
"Date": "January 2004",
"Full Description": "%(Description)s Version %(Version)s (%(Date)s)",
# Sub-dict for application specific version strings.
"Apps": {
"sb_filter" : {
"Version": 0.3,
"Description": "SpamBayes Command Line Filter",
"Date": "April 2004",
"Full Description": "%(Description)s Version %(Version)s (%(Date)s)",
},
"Outlook" : {
# Note these version numbers currently don't appear in the
# "description" strings below - they just need to increment
# so automated version checking works.
"Version": 1.04,
"BinaryVersion": 1.04,
"Description": "SpamBayes Outlook Addin",
"Date": "March 2005",
"Full Description": "%(Description)s Version 1.0.4 (%(Date)s)",
"Full Description Binary":
"%(Description)s Binary Version 1.0.4 (%(Date)s)",
# Note this means we can change the download page later, and old
# versions will still go to the new page.
# We may also like to have a "Release Notes Page" item later?
"Download Page": "http://spambayes.sourceforge.net/windows.html"
},
"POP3 Proxy" : {
# Note these version numbers also currently don't appear in the
# "description" strings below - see above
"Version": 1.04,
"BinaryVersion": 1.04,
"Description": "SpamBayes POP3 Proxy",
"Date": "March 2005",
"Full Description": """%(Description)s Version 1.0.4 (%(Date)s)""",
"Full Description Binary":
"""%(Description)s Binary Version 1.0.4 (%(Date)s)""",
# Note this means we can change the download page later, and old
# versions will still go to the new page.
# We may also like to have a "Release Notes Page" item later?
"Download Page": "http://spambayes.sourceforge.net/windows.html"
},
"Lotus Notes Filter" : {
"Version": 0.02,
"Description": "SpamBayes Lotus Notes Filter",
"Date": "February 2004",
"Full Description": "%(Description)s Version %(Version)s (%(Date)s)",
},
"IMAP Filter" : {
"Version": 0.6,
"Description": "SpamBayes IMAP Filter",
"Date": "January 2005",
"Full Description": """%(Description)s Version %(Version)s (%(Date)s)""",
},
"IMAP Server" : {
"Version": 0.02,
"Description": "SpamBayes IMAP Server",
"Date": "January 2004",
"Full Description": """%(Description)s Version %(Version)s (%(Date)s)""",
},
},
}
def get_version_string(app = None,
description_key = "Full Description",
version_dict = None):
"""Get a pretty version string, generally just to log or show in a UI"""
if version_dict is None: version_dict = versions
if app is None:
dict = version_dict
else:
dict = version_dict["Apps"][app]
return dict[description_key] % dict
def get_version_number(app = None,
version_key = "Version",
version_dict = None):
"""Get a version number, as a float. This would primarily be used so some
app or extension can determine if we are later than a specific version
of either the engine or a specific app.
Maybe YAGNI.
"""
if version_dict is None: version_dict = versions
if app is None:
dict = version_dict
else:
dict = version_dict["Apps"][app]
return dict[version_key]
# Utilities to check the "latest" version of an app.
# Assumes that a 'config' version of this file exists at the given URL
# No exceptions are caught
try:
import ConfigParser
class MySafeConfigParser(ConfigParser.SafeConfigParser):
def optionxform(self, optionstr):
return optionstr # no lower!
except AttributeError: # No SafeConfigParser!
MySafeConfigParser = None
def fetch_latest_dict(url=LATEST_VERSION_HOME):
if MySafeConfigParser is None:
raise RuntimeError, \
"Sorry, but only Python 2.3 can trust remote config files"
import urllib2
from spambayes.Options import options
server = options["globals", "proxy_server"]
if server != "":
if ':' in server:
server, port = server.split(':', 1)
port = int(port)
else:
port = 8080
if options["globals", "proxy_username"]:
user_pass_string = "%s:%s" % \
(options["globals", "proxy_username"],
options["globals", "proxy_password"])
else:
user_pass_string = ""
proxy_support = urllib2.ProxyHandler({"http" :
"http://%s@%s:%d" % \
(user_pass_string, server,
port)})
opener = urllib2.build_opener(proxy_support, urllib2.HTTPHandler)
urllib2.install_opener(opener)
stream = urllib2.urlopen(url)
cfg = MySafeConfigParser()
cfg.readfp(stream)
ret_dict = {}
apps_dict = ret_dict["Apps"] = {}
for sect in cfg.sections():
if sect=="SpamBayes":
target_dict = ret_dict
else:
target_dict = apps_dict.setdefault(sect, {})
for opt in cfg.options(sect):
val = cfg.get(sect, opt)
# some butchering
try:
val = float(val)
except ValueError:
pass
target_dict[opt] = val
return ret_dict
# Utilities for generating a 'config' version of this file.
# The output of this should exist at the URL above.
def _make_cfg_section(stream, key, this_dict):
stream.write("[%s]\n" % key)
for name, val in this_dict.items():
if type(val)==type(''):
val_str = repr(val)[1:-1]
elif type(val)==type(0.0):
val_str = str(val)
elif type(val)==type({}):
val_str = None # sub-dict
else:
print "Skipping unknown value type: %r" % val
val_str = None
if val_str is not None:
stream.write("%s:%s\n" % (name, val_str))
stream.write("\n")
def make_cfg(stream):
stream.write("# This file is generated from spambayes/Version.py" \
" - do not edit\n")
_make_cfg_section(stream, "SpamBayes", versions)
for appname in versions["Apps"]:
_make_cfg_section(stream, appname, versions["Apps"][appname])
def main(args):
import sys
if '-g' in args:
make_cfg(sys.stdout)
sys.exit(0)
print "SpamBayes engine version:", get_version_string()
# Enumerate applications
print
print "Application versions:"
for app in versions["Apps"]:
print "\n%s: %s" % (app, get_version_string(app))
print
print "Fetching the lastest version information..."
try:
latest_dict = fetch_latest_dict()
except:
print "FAILED to fetch the latest version"
import traceback
traceback.print_exc()
sys.exit(1)
print
print "SpamBayes engine version:", get_version_string(version_dict=latest_dict)
# Enumerate applications
print
print "Application versions:"
for app in latest_dict["Apps"]:
print "\n%s: %s" % (app, get_version_string(app, version_dict=latest_dict))
if __name__=='__main__':
import sys
main(sys.argv)
syntax highlighted by Code2HTML, v. 0.9.1