lp4all main module

#!/usr/bin/python
# -*- coding: utf-8 -*- 

# lp4all: literate programming embedded in source code as wiki comments
# Copyright (C) 2006 Jean-Marie Favreau, Frédéric Lehobey, David Mentré
#                    and Thomas Petazzoni
# 
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

Main program of Lp4all

It does the option parsing and perform the different phases of documentation generation.


import sys
import fileparser
import htmlbasicout
import getopt
import os
import index
import shutil
import fs_tools
from iface import Comment

from label_dict import *

Default values for options

outdir     = "."
commenttag = 'w'
project    = 'Project'
css        = None

Display usage of Lp4all

def usage():
    print "Usage: lp4all [-d outdir] [-t commenttag] [-p project] [-c css] filename1 [filename2 ...]"
    print " default outdir: '%s'" % outdir
    print " default commenttag: '%s'" % commenttag
    print " default project name: '%s'" % project

if len(sys.argv) < 2:
    usage()
    sys.exit(1)

Parse all arguments using Python getopt

try:
    opts, args = getopt.getopt(sys.argv[1:], "d:t:hp:c:",
                               ["help", "directory", "tag", "project", "css"])
except getopt.GetoptError:
    usage()
    sys.exit(1)

for o, a in opts:
    if o in ("-h", "--help"):
        usage()
        sys.exit(0)
    elif o in ("-d", "--directory"):
        outdir = a
    elif o in ("-t", "--tag"):
        commenttag = a
    elif o in ("-p", "--project"):
        project = a
    elif o in ("-c", "--css"):
        css = a

Check that source-highlight is available in the PATH

sourceHighlightFound = False
for path in os.getenv("PATH").split(':'):
    if os.path.exists(os.path.join(path, "source-highlight")):
        sourceHighlightFound = True
        break

if not sourceHighlightFound:
    print "source-highlight not found, please install."
    sys.exit(1)

Various checks on given paths

if os.path.exists(outdir) and not os.path.isdir(outdir):
    print "output directory '%s' is not a directory" % outdir
    sys.exit(1)

if css and not os.path.exists(css):
    print "CSS file '%s' not found" % css
    sys.exit(1)

Check that all files are really files and that they are given using relative paths

for file in args:
    if not os.path.isfile(file):
        print "only files are allowed, '%s' is not a file" % file
        sys.exit (1)
    if os.path.isabs(file):
        print "absolute filenames are not supported"
        sys.exit(1)

fp = fileparser.FileParser(commenttag)
ld = LabelDict.getSingleton()

First, split each file in blocks of comments and code (a list of objects Code and Comment). Then, parse all blocks to build the corresponding syntaxic tree (currently, it really does something only for comment blocks). Finally, fill the label dictionnary with the labels found in each comment block.

The result is file_blocks a list of tuples, where each tuple links a filename to the list of blocks that composes the file.

file_blocks = {}
for c, file in enumerate(args):
    file = os.path.normpath(file)
    print "Parsing code file %d/%d\r" % (c + 1, len(args)),
    blocks = fp.parse(file)
    for block in blocks:
        block.buildTree()
        labels = block.findLabels()
        for label in labels:
            ld.add(label, file, block.linestart, block.lineend)
    file_blocks[file] = blocks
print

Build input dir tree. To do so, we build a list of all filenames in which each filename is itself a list of each path element or file.

inputdirs = fs_tools.getdirs('.', args)

parse each .lp4all files, add comments blocks in file_blocks if filename is not index.lp4alland add founded labels to LabelDict.

lp4all_files = fs_tools.findLp4allFiles('.', inputdirs)
for c, lp4all_file in enumerate(lp4all_files):
    print "Parsing lp4all file %d/%d\r" % (c + 1, len(lp4all_files)),
    lpfile = open(lp4all_file + ".lp4all")
    cmt = Comment(0, lp4all_file, 0, 1, lpfile.read())
    cmt.buildTree()
    labels = cmt.findLabels()
    for label in labels:
        ld.add(label, lp4all_file, cmt.linestart, cmt.lineend)
    lpfile.close()
    if file_blocks.has_key(lp4all_file):
        file_blocks[lp4all_file].insert(0, cmt)
    else:
        file_blocks[lp4all_file] = [cmt]
print


make all output directories

fs_tools.mkdirs(outdir, inputdirs)

Generate an HTML page for each directory. It allows to browse through the different directories of the project, using inputdirs computed before.

index.build(outdir, project, '.', inputdirs, file_blocks)

Generate HTML for each .lp4all (except index.lp4all) and source file

c = 1
for file, blocks in file_blocks.iteritems():
    print "Generating file %d/%d\r" % (c, len(file_blocks)),
    htmlbasicout.file(outdir, project, blocks, file)
    c += 1
print

Copy the CSS to the output directory. If a CSS is given as argument, use it direcetly. Otherwise, use the default CSS. In this case, we suppose that the default CSS is available in the same directory where the Lp4all main script is.

if css:
    shutil.copyfile(css, os.path.join(outdir, 'lp4all.css'))
else:
    shutil.copyfile(os.path.join(os.path.dirname(sys.argv[0]), 'lp4all.css'),
                    os.path.join(outdir, 'lp4all.css'))