#!/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
and

inside #
 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') 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" % (cgi.escape(k), v)) title = 0 fo.write("
%s:%s
\n
\n
\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()