| 1 | """ |
|---|
| 2 | Trac macros for Twisted. |
|---|
| 3 | """ |
|---|
| 4 | |
|---|
| 5 | from StringIO import StringIO |
|---|
| 6 | from urlparse import urlparse |
|---|
| 7 | |
|---|
| 8 | from trac.core import TracError |
|---|
| 9 | from trac.util.html import Markup |
|---|
| 10 | from trac.wiki.formatter import OneLinerFormatter |
|---|
| 11 | from trac.wiki.macros import WikiMacroBase |
|---|
| 12 | |
|---|
| 13 | from twisted.python.versions import Version |
|---|
| 14 | from twisted.python.filepath import FilePath |
|---|
| 15 | |
|---|
| 16 | |
|---|
| 17 | RELEASES = FilePath('/srv/www-data/twisted/Releases/') |
|---|
| 18 | |
|---|
| 19 | |
|---|
| 20 | |
|---|
| 21 | class ProjectVersionMacro(WikiMacroBase): |
|---|
| 22 | """ |
|---|
| 23 | Macro that knows the current [http://twistedmatrix.com Twisted] version number. |
|---|
| 24 | |
|---|
| 25 | The version information is loaded from a folder containing text files with |
|---|
| 26 | md5sums for each released package/installer. Also see the |
|---|
| 27 | [http://twistedmatrix.com/trac/wiki/Downloads#SignedMD5Sums Twisted downloads] |
|---|
| 28 | page. |
|---|
| 29 | |
|---|
| 30 | '''Standalone''' |
|---|
| 31 | {{{ |
|---|
| 32 | [[ProjectVersion]] |
|---|
| 33 | }}} |
|---|
| 34 | |
|---|
| 35 | produces: |
|---|
| 36 | |
|---|
| 37 | [[ProjectVersion]] |
|---|
| 38 | |
|---|
| 39 | '''URL''' |
|---|
| 40 | |
|---|
| 41 | {{{ |
|---|
| 42 | [[ProjectVersion(http://twistedmatrix.com/Releases/Twisted/%(major)s.%(minor)s/Twisted-%(base)s.win32-py2.7.msi Twisted %(base)s for Python 2.7)]] |
|---|
| 43 | }}} |
|---|
| 44 | |
|---|
| 45 | produces: |
|---|
| 46 | |
|---|
| 47 | [[ProjectVersion(http://twistedmatrix.com/Releases/Twisted/%(major)s.%(minor)s/Twisted-%(base)s.win32-py2.7.msi Twisted %(base)s for Python 2.7)]] |
|---|
| 48 | |
|---|
| 49 | Including the MD5 hash (eg. `b568b504524fda2440c62aa1616b3fe5`): |
|---|
| 50 | |
|---|
| 51 | {{{ |
|---|
| 52 | - [[ProjectVersion(http://pypi.python.org/packages/source/T/Twisted/Twisted-%(base)s.tar.bz2#md5=%(md5)s Twisted %(base)s tar)]] |
|---|
| 53 | - [[ProjectVersion(http://pypi.python.org/packages/2.7/T/Twisted/Twisted-%(base)s.win32-py2.7.msi#md5=%(md5)s Twisted %(base)s for Python 2.7)]] |
|---|
| 54 | }}} |
|---|
| 55 | |
|---|
| 56 | produces: |
|---|
| 57 | |
|---|
| 58 | - [[ProjectVersion(http://pypi.python.org/packages/source/T/Twisted/Twisted-%(base)s.tar.bz2#md5=%(md5)s Twisted %(base)s tar)]] |
|---|
| 59 | - [[ProjectVersion(http://pypi.python.org/packages/2.7/T/Twisted/Twisted-%(base)s.win32-py2.7.msi#md5=%(md5)s Twisted %(base)s for Python 2.7)]] |
|---|
| 60 | |
|---|
| 61 | '''Source browser''' |
|---|
| 62 | |
|---|
| 63 | {{{ |
|---|
| 64 | [[ProjectVersion(source:/tags/releases/twisted-%(base)s/ Tag for Twisted %(base)s)]] |
|---|
| 65 | }}} |
|---|
| 66 | |
|---|
| 67 | produces: |
|---|
| 68 | |
|---|
| 69 | [[ProjectVersion(source:/tags/releases/twisted-%(base)s/ Tag for Twisted %(base)s)]] |
|---|
| 70 | """ |
|---|
| 71 | |
|---|
| 72 | |
|---|
| 73 | revision = "$Rev$" |
|---|
| 74 | url = "$URL$" |
|---|
| 75 | |
|---|
| 76 | def getVersion(self): |
|---|
| 77 | versions = [] |
|---|
| 78 | pattern = 'twisted-%s-md5sums.txt' |
|---|
| 79 | for md5sums in RELEASES.globChildren(pattern % '*'): |
|---|
| 80 | try: |
|---|
| 81 | components = map(int, md5sums.basename().split('-')[1].split('.')) |
|---|
| 82 | except ValueError: |
|---|
| 83 | pass |
|---|
| 84 | else: |
|---|
| 85 | versions.append(components) |
|---|
| 86 | |
|---|
| 87 | version = Version('Twisted', *max(versions)) |
|---|
| 88 | md5sums_file = RELEASES.child(pattern % version.base()) |
|---|
| 89 | return version, md5sums_file |
|---|
| 90 | |
|---|
| 91 | |
|---|
| 92 | def expand_macro(self, formatter, name, args): |
|---|
| 93 | """ |
|---|
| 94 | Return output that will be displayed in the Wiki content. |
|---|
| 95 | |
|---|
| 96 | @param name: the actual name of the macro |
|---|
| 97 | @param args: the text enclosed in parenthesis at the call of the macro. |
|---|
| 98 | Note that if there are ''no'' parenthesis (like in, e.g. |
|---|
| 99 | [[ProjectVersion]]), then `args` is `None`. |
|---|
| 100 | """ |
|---|
| 101 | if not RELEASES.exists(): |
|---|
| 102 | self.log.error("The specified RELEASES directory does not exist at %s" % RELEASES.path) |
|---|
| 103 | raise TracError("Error loading Twisted version information") |
|---|
| 104 | |
|---|
| 105 | v, md5sums = self.getVersion() |
|---|
| 106 | md5sum = '' |
|---|
| 107 | |
|---|
| 108 | if args is None: |
|---|
| 109 | text = v.base() |
|---|
| 110 | else: |
|---|
| 111 | uc = unicode(args).replace('%28', '(').replace('%29', ')') |
|---|
| 112 | if uc.find('%(md5)s') > -1: |
|---|
| 113 | sep = '-----BEGIN PGP SIGNATURE-----\n' |
|---|
| 114 | lines = md5sums.open().readlines() |
|---|
| 115 | path = urlparse(uc).path % dict(base=v.base()) |
|---|
| 116 | filename = path.split('/')[-1] |
|---|
| 117 | for entry in lines[3:lines.index(sep)]: |
|---|
| 118 | entry = entry.rstrip('\n').split(' ') |
|---|
| 119 | if entry[1] == filename: |
|---|
| 120 | md5sum = entry[0] |
|---|
| 121 | break |
|---|
| 122 | |
|---|
| 123 | url = urlparse(uc).netloc |
|---|
| 124 | text = uc % dict(major=v.major, minor=v.minor, micro=v.micro, base=v.base(), |
|---|
| 125 | md5=md5sum) |
|---|
| 126 | |
|---|
| 127 | # handle links |
|---|
| 128 | if args.startswith('source:') or url != '': |
|---|
| 129 | text = "[%s]" % text |
|---|
| 130 | |
|---|
| 131 | out = StringIO() |
|---|
| 132 | OneLinerFormatter(self.env, formatter.context).format(text, out) |
|---|
| 133 | |
|---|
| 134 | return Markup(out.getvalue()) |
|---|