| 1 | #!/usr/bin/env python |
|---|
| 2 | |
|---|
| 3 | import os,sys,re,os.path,time |
|---|
| 4 | from cStringIO import StringIO |
|---|
| 5 | from datetime import date |
|---|
| 6 | from optparse import OptionParser |
|---|
| 7 | from string import Template |
|---|
| 8 | |
|---|
| 9 | module=None |
|---|
| 10 | |
|---|
| 11 | namespace={ |
|---|
| 12 | 'prog':None, |
|---|
| 13 | 'author':None, |
|---|
| 14 | 'author_email':None, |
|---|
| 15 | 'url':None, |
|---|
| 16 | 'description':None, |
|---|
| 17 | 'long_description': None, |
|---|
| 18 | 'packages': None, |
|---|
| 19 | 'cvs_version':None, |
|---|
| 20 | 'release_version':None, |
|---|
| 21 | 'version':None, |
|---|
| 22 | 'codename': None, |
|---|
| 23 | 'release_date':None, # should stat the file instead |
|---|
| 24 | 'release_file':None, |
|---|
| 25 | 'today':date.today().strftime("%d %B %Y"), |
|---|
| 26 | 'year':date.today().strftime("%Y"), |
|---|
| 27 | 'yearstart':'2006', |
|---|
| 28 | 'htmlBody':'', |
|---|
| 29 | 'preBody':'', |
|---|
| 30 | } |
|---|
| 31 | |
|---|
| 32 | def findLongDescription(): |
|---|
| 33 | # skip the opening one-line description and grab the first paragraph |
|---|
| 34 | # out of the module's docstring to use as the long description. |
|---|
| 35 | long_description = '' |
|---|
| 36 | lines = module.__doc__.splitlines() |
|---|
| 37 | for firstline in range(len(lines)): |
|---|
| 38 | # skip until we reach a blank line |
|---|
| 39 | if len(lines[firstline])==0 or lines[firstline].isspace(): |
|---|
| 40 | break |
|---|
| 41 | if firstline<len(lines): |
|---|
| 42 | firstline+=1 |
|---|
| 43 | for lastline in range(firstline,len(lines)): |
|---|
| 44 | # stop when we reach a blank line |
|---|
| 45 | if len(lines[lastline])==0 or lines[lastline].isspace(): |
|---|
| 46 | break |
|---|
| 47 | long_description = " ".join(lines[firstline:lastline]) |
|---|
| 48 | namespace['long_description'] = long_description |
|---|
| 49 | |
|---|
| 50 | def findPackages(mil=False): |
|---|
| 51 | packages = [] |
|---|
| 52 | |
|---|
| 53 | # find packages to be installed |
|---|
| 54 | path = os.path.dirname(module.__file__) |
|---|
| 55 | def addmodules(arg, dirname, names): |
|---|
| 56 | if '__init__.py' in names: |
|---|
| 57 | prefix = os.path.commonprefix((path, dirname)) |
|---|
| 58 | mod = "%s%s" % (module.__name__, dirname[len(prefix):].replace(os.sep,'.')) |
|---|
| 59 | if mod not in packages: |
|---|
| 60 | packages.append(mod) |
|---|
| 61 | os.path.walk(path, addmodules, None) |
|---|
| 62 | print "packages = %s" % packages |
|---|
| 63 | if mil == False and 'peppy.hsi.mil' in packages: |
|---|
| 64 | packages.remove('peppy.hsi.mil') |
|---|
| 65 | namespace['packages'] = str(packages) |
|---|
| 66 | |
|---|
| 67 | def setnamespace(mil=False): |
|---|
| 68 | if module: |
|---|
| 69 | defaults={ |
|---|
| 70 | 'prog':'__name__', |
|---|
| 71 | 'version': '__version__', |
|---|
| 72 | 'codename': '__codename__', |
|---|
| 73 | 'author':'__author__', |
|---|
| 74 | 'author_email':'__author_email__', |
|---|
| 75 | 'url':'__url__', |
|---|
| 76 | 'download_url':'__download_url__', |
|---|
| 77 | 'description':'__description__', |
|---|
| 78 | 'license': '__license__', |
|---|
| 79 | 'keywords': '__keywords__', |
|---|
| 80 | 'coconuts': '__sir_not_appearing_in_this_film__', |
|---|
| 81 | } |
|---|
| 82 | |
|---|
| 83 | for key,val in defaults.iteritems(): |
|---|
| 84 | if hasattr(module, val): |
|---|
| 85 | namespace[key]=getattr(module, val) |
|---|
| 86 | # print "%s=%s" % (key,val) |
|---|
| 87 | |
|---|
| 88 | findLongDescription() |
|---|
| 89 | findPackages(mil) |
|---|
| 90 | |
|---|
| 91 | if int(namespace['yearstart'])<int(namespace['year']): |
|---|
| 92 | namespace['yearrange']=namespace['yearstart']+'-'+namespace['year'] |
|---|
| 93 | else: |
|---|
| 94 | namespace['yearrange']=namespace['year'] |
|---|
| 95 | |
|---|
| 96 | |
|---|
| 97 | |
|---|
| 98 | def store(keyword,infile): |
|---|
| 99 | if isinstance(infile,str): |
|---|
| 100 | fh=open(infile) |
|---|
| 101 | else: |
|---|
| 102 | fh=infile |
|---|
| 103 | txt=fh.read() |
|---|
| 104 | t=Template(txt) |
|---|
| 105 | out=t.safe_substitute(namespace) |
|---|
| 106 | namespace[keyword]=out |
|---|
| 107 | |
|---|
| 108 | def remap(keyword,value): |
|---|
| 109 | if value.startswith('$'): |
|---|
| 110 | value=namespace[value[1:]] |
|---|
| 111 | namespace[keyword]=value |
|---|
| 112 | |
|---|
| 113 | def parse(infile): |
|---|
| 114 | if isinstance(infile,str): |
|---|
| 115 | fh=open(infile) |
|---|
| 116 | else: |
|---|
| 117 | fh=infile |
|---|
| 118 | txt=fh.read() |
|---|
| 119 | t=Template(txt) |
|---|
| 120 | out=t.safe_substitute(namespace) |
|---|
| 121 | return out |
|---|
| 122 | |
|---|
| 123 | def parsedocstring(infile): |
|---|
| 124 | if isinstance(infile,str): |
|---|
| 125 | fh=open(infile) |
|---|
| 126 | else: |
|---|
| 127 | fh=infile |
|---|
| 128 | doc=StringIO() |
|---|
| 129 | count=0 |
|---|
| 130 | while count<2: |
|---|
| 131 | line=fh.readline() |
|---|
| 132 | if line.find('"""')>=0: count+=1 |
|---|
| 133 | doc.write(line) |
|---|
| 134 | unparsed=fh.read() |
|---|
| 135 | t=Template(doc.getvalue()) |
|---|
| 136 | out=t.safe_substitute(namespace) |
|---|
| 137 | return out+unparsed |
|---|
| 138 | |
|---|
| 139 | def parsechangelog(infile): |
|---|
| 140 | if isinstance(infile, str): |
|---|
| 141 | fh = open(infile) |
|---|
| 142 | else: |
|---|
| 143 | fh = infile |
|---|
| 144 | doc=StringIO() |
|---|
| 145 | doc.write("<h2>ChangeLog</h2>") |
|---|
| 146 | release_date = '' |
|---|
| 147 | version = '' |
|---|
| 148 | show_items = False |
|---|
| 149 | for line in fh: |
|---|
| 150 | match=re.match('(\d+-\d+-\d+).*',line) |
|---|
| 151 | if match: |
|---|
| 152 | if show_items: |
|---|
| 153 | doc.write("</ul>\n") |
|---|
| 154 | show_items = False |
|---|
| 155 | print 'found date %s' % match.group(1) |
|---|
| 156 | release_date=date.fromtimestamp(time.mktime(time.strptime(match.group(1),'%Y-%m-%d'))).strftime('%d %B %Y') |
|---|
| 157 | else: |
|---|
| 158 | match=re.match('\s+\*\s*[Rr]eleased peppy-([\d\.]+)',line) |
|---|
| 159 | if match: |
|---|
| 160 | print 'found version %s' % match.group(1) |
|---|
| 161 | version=match.group(1) |
|---|
| 162 | doc.write("<h3>%s, released %s</h3>\n<ul>\n" % (version, release_date)) |
|---|
| 163 | show_items = True |
|---|
| 164 | else: |
|---|
| 165 | line = line.lstrip() |
|---|
| 166 | if line.startswith('*'): |
|---|
| 167 | doc.write("<li>%s " % line[1:]) |
|---|
| 168 | else: |
|---|
| 169 | doc.write(line) |
|---|
| 170 | return doc.getvalue() |
|---|
| 171 | |
|---|
| 172 | |
|---|
| 173 | if __name__=='__main__': |
|---|
| 174 | usage="usage: %prog [-m module] [-o file] [-n variablename file] [-t template] [files...]" |
|---|
| 175 | parser=OptionParser(usage=usage) |
|---|
| 176 | parser.add_option("-m", action="store", dest="module", |
|---|
| 177 | help="module to import") |
|---|
| 178 | |
|---|
| 179 | parser.add_option("-o", action="store", dest="outputfile", |
|---|
| 180 | help="output filename") |
|---|
| 181 | parser.add_option("-n", "--name", action="append", nargs=2, |
|---|
| 182 | dest="namespace", metavar="KEY FILENAME", |
|---|
| 183 | help="expand the named variable KEY with the contents of FILENAME") |
|---|
| 184 | parser.add_option("-r", "--remapkey", action="append", nargs=2, |
|---|
| 185 | dest="remapkey", metavar="KEY1 KEY2", |
|---|
| 186 | help="remap the named variable KEY1 with the value of the named variable KEY2") |
|---|
| 187 | parser.add_option("-k", "--keyvalue", action="append", nargs=2, |
|---|
| 188 | dest="keyvalue", metavar="KEY VALUE", |
|---|
| 189 | help="remap the named variable KEY with the supplied constant VALUE, or if VALUE begins with a $, with the value of that named variable. Note that you probably have to escape the $ from the shell with \\$") |
|---|
| 190 | parser.add_option("-t", "--template", action="store", dest="template", |
|---|
| 191 | help="filename of template file") |
|---|
| 192 | parser.add_option("-p", "--print-namespace", action="store_true", |
|---|
| 193 | dest="printnamespace", help="print namespace and exit without processing") |
|---|
| 194 | parser.add_option("--mil", action="store_true", default=False, |
|---|
| 195 | dest="mil", help="use mil modules") |
|---|
| 196 | parser.add_option("-d", "--docstring-only", action="store_true", |
|---|
| 197 | dest="docstringonly", help="only variable-expand the named file's docstring only; leave the remaining contents unchanged.") |
|---|
| 198 | parser.add_option("-c", "--changelog", action="store_true", |
|---|
| 199 | dest="changelog", help="create a changelog input file.") |
|---|
| 200 | (options, args) = parser.parse_args() |
|---|
| 201 | |
|---|
| 202 | all='' |
|---|
| 203 | |
|---|
| 204 | if options.module: |
|---|
| 205 | module=__import__(options.module) |
|---|
| 206 | |
|---|
| 207 | setnamespace(options.mil) |
|---|
| 208 | |
|---|
| 209 | # Static value setting should happen before anything |
|---|
| 210 | if options.keyvalue: |
|---|
| 211 | for keyword,value in options.keyvalue: |
|---|
| 212 | print "keyword=%s value=%s" % (keyword,value) |
|---|
| 213 | remap(keyword,value) |
|---|
| 214 | |
|---|
| 215 | if options.namespace: |
|---|
| 216 | for keyword,filename in options.namespace: |
|---|
| 217 | # print "keyword=%s filename=%s" % (keyword,filename) |
|---|
| 218 | store(keyword,filename) |
|---|
| 219 | |
|---|
| 220 | if options.remapkey: |
|---|
| 221 | for key1,key2 in options.remapkey: |
|---|
| 222 | value=namespace[key2] |
|---|
| 223 | print "keyword=%s value=%s" % (key1,value) |
|---|
| 224 | remap(key1,value) |
|---|
| 225 | |
|---|
| 226 | if options.template: |
|---|
| 227 | all=parse(options.template) |
|---|
| 228 | |
|---|
| 229 | if options.printnamespace: |
|---|
| 230 | print namespace |
|---|
| 231 | sys.exit() |
|---|
| 232 | |
|---|
| 233 | for filename in args: |
|---|
| 234 | if options.docstringonly: |
|---|
| 235 | txt = parsedocstring(filename) |
|---|
| 236 | elif options.changelog: |
|---|
| 237 | txt = parsechangelog(filename) |
|---|
| 238 | else: |
|---|
| 239 | txt = parse(filename) |
|---|
| 240 | if options.outputfile: |
|---|
| 241 | print 'saving to %s' % options.outputfile |
|---|
| 242 | all += txt |
|---|
| 243 | else: |
|---|
| 244 | if filename.endswith('.in'): |
|---|
| 245 | outfile = filename[:-3] |
|---|
| 246 | else: |
|---|
| 247 | outfile = filename+".out" |
|---|
| 248 | fh = open(outfile,"w") |
|---|
| 249 | fh.write(txt) |
|---|
| 250 | fh.close() |
|---|
| 251 | |
|---|
| 252 | if options.outputfile: |
|---|
| 253 | fh = open(options.outputfile,"w") |
|---|
| 254 | fh.write(all) |
|---|
| 255 | fh.close() |
|---|
| 256 | else: |
|---|
| 257 | print all |
|---|
| 258 | |
|---|