#!/usr/bin/env python """ convert PEP's to (X)HTML - courtesy of /F Usage: %(PROGRAM)s [options] [peps] Notes: The optional argument peps can be either pep numbers or .txt files. Options: -u/--user SF username -i/--install After generating the HTML, install it and the plain text source file (.txt) SourceForge. In that case the user's name is used in the scp and ssh commands, unless sf_username is given (in which case, it is used instead). Without -i, sf_username is ignored. -q/--quiet Turn off verbose messages. -h/--help Print this help message and exit. """ import sys import os import re import cgi import glob import getopt import errno PROGRAM = sys.argv[0] RFCURL = 'http://www.faqs.org/rfcs/rfc%d.html' PEPURL = 'pep-%04d.html' HOST = "shell.sourceforge.net" # host for update HDIR = "/home/groups/p/py/python/htdocs/peps" # target host directory LOCALVARS = "Local Variables:" # The generated HTML doesn't validate -- you cannot use
tags. But if I change that, the result doesn't look very nice... DTD = ('') fixpat = re.compile("((http|ftp):[-_a-zA-Z0-9/.+~:?#$=&]+)|(pep-\d+(.txt)?)|" "(RFC[- ]?(?P\d+))|" "(PEP\s+(?P \d+))|" ".") def usage(code, msg=''): sys.stderr.write(__doc__ % globals() + '\n') if msg: msg = str(msg) if msg[-1] <> '\n': msg = msg + '\n' sys.stderr.write(msg) sys.exit(code) def fixanchor(current, match): text = match.group(0) link = None if text[:5] == "http:" or text[:4] == "ftp:": link = text elif text[:4] == "pep-" and text != current: link = os.path.splitext(text)[0] + ".html" elif text[:3] == 'PEP': pepnum = int(match.group('pepnum')) link = PEPURL % pepnum elif text[:3] == 'RFC': rfcnum = int(match.group('rfcnum')) link = RFCURL % rfcnum if link: return "%s" % (link, cgi.escape(text)) return cgi.escape(match.group(0)) # really slow, but it works... def fixfile(infile, outfile): # convert plain text pep to minimal XHTML markup try: fi = open(infile) except IOError, e: if e.errno <> errno.ENOENT: raise print >> sys.stderr, 'Error: Skipping missing PEP file:', e.filename return fo = open(outfile, "w") fo.write(DTD + "\n\n\n") # head header = [] pep = "" title = "" while 1: line = fi.readline() if not line.strip(): break if line[0].strip(): if ":" not in line: break key, value = line.split(":", 1) value = value.strip() header.append((key, value)) else: # continuation line key, value = header[-1] value = value + line header[-1] = key, value if key.lower() == "title": title = value elif key.lower() == "pep": pep = value if pep: title = "PEP " + pep + " -- " + title if title: fo.write(" %s \n" ' \n' % cgi.escape(title)) fo.write("\n") # body fo.write('\n' ' \n' '\n\n\n') for k, v in header: if k.lower() in ('author', 'discussions-to'): mailtos = [] for addr in v.split(): if '@' in addr: mailtos.append( '%s' % (addr, pep, addr)) elif addr.startswith('http:'): mailtos.append( '%s' % (addr, addr)) else: mailtos.append(addr) v = ' '.join(mailtos) elif k.lower() in ('replaces', 'replaced-by'): peps = '' for pep in v.split(): pep = int(pep) peps += '%i ' % (pep, pep) v = peps else: v = cgi.escape(v) fo.write("
\n\n" % (cgi.escape(k), v)) title = 0 fo.write(" %s: %s
\n" "") while 1: line = fi.readline() if not line: break if line[0] != "\f": if line[0].strip(): if line.strip() == LOCALVARS: break fo.write("\n%s
\n" % line.strip()) title = 0 else: line = fixpat.sub(lambda x, c=infile: fixanchor(c, x), line) fo.write(line) fo.write("\n" "\n" "\n") fo.close() os.chmod(outfile, 0664) def find_pep(pep_str): """Find the .txt file indicated by a cmd line argument""" if os.path.exists(pep_str): return pep_str num = int(pep_str) return "pep-%04d.txt" % num def make_html(file, verbose=0): newfile = os.path.splitext(file)[0] + ".html" if verbose: print file, "->", newfile fixfile(file, newfile) return newfile SPACE = ' ' def push_pep(htmlfiles, txtfiles, username, verbose): if verbose: quiet = "" else: quiet = "-q" if username: username = username + "@" target = username + HOST + ":" + HDIR files = htmlfiles[:] files.extend(txtfiles) files.append("style.css") filelist = SPACE.join(files) rc = os.system("scp %s %s %s" % (quiet, filelist, target)) if rc: sys.exit(rc) rc = os.system("ssh %s%s chmod 664 %s/*" % (username, HOST, HDIR)) if rc: sys.exit(rc) def main(): # defaults update = 0 username = '' verbose = 1 try: opts, args = getopt.getopt(sys.argv[1:], 'ihqu:', ['install', 'help', 'quiet', 'user=']) except getopt.error, msg: usage(1, msg) for opt, arg in opts: if opt in ('-h', '--help'): usage(0) elif opt in ('-i', '--install'): update = 1 elif opt in ('-u', '--user'): username = arg elif opt in ('-q', '--quiet'): verbose = 0 if args: peptxt = [] html = [] for pep in args: file = find_pep(pep) peptxt.append(file) newfile = make_html(file, verbose=verbose) html.append(newfile) else: # do them all peptxt = [] for file in glob.glob("pep-*.txt"): peptxt.append(file) make_html(file, verbose=verbose) html = ["pep-*.html"] if update: push_pep(html, peptxt, username, verbose) if __name__ == "__main__": main()