Modules | Files | Inheritance Tree | Inheritance Graph | Name Index | Config
File: Synopsis/Formatter/HTML/FileLayout.py
    1| # $Id: FileLayout.py,v 1.21 2003/01/16 12:46:46 chalky Exp $
    2| #
    3| # This file is a part of Synopsis.
    4| # Copyright (C) 2000, 2001 Stephen Davies
    5| # Copyright (C) 2000, 2001 Stefan Seefeld
    6| #
    7| # Synopsis is free software; you can redistribute it and/or modify it
    8| # under the terms of the GNU General Public License as published by
    9| # the Free Software Foundation; either version 2 of the License, or
   10| # (at your option) any later version.
   11| #
   12| # This program is distributed in the hope that it will be useful,
   13| # but WITHOUT ANY WARRANTY; without even the implied warranty of
   14| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   15| # General Public License for more details.
   16| #
   17| # You should have received a copy of the GNU General Public License
   18| # along with this program; if not, write to the Free Software
   19| # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
   20| # 02111-1307, USA.
   21| #
   22| # $Log: FileLayout.py,v $
   23| # Revision 1.21  2003/01/16 12:46:46  chalky
   24| # Renamed FilePages to FileSource, FileTree to FileListing. Added FileIndexer
   25| # (used to be part of FileTree) and FileDetails.
   26| #
   27| # Revision 1.20  2002/11/13 04:10:48  chalky
   28| # Don't kill absolute filenames
   29| #
   30| # Revision 1.19  2002/11/13 02:29:24  chalky
   31| # Support exclude_glob option to exclude files from listings. Remove debug info.
   32| #
   33| # Revision 1.18  2002/11/13 01:01:49  chalky
   34| # Improvements to links when using the Nested file layout
   35| #
   36| # Revision 1.17  2002/11/02 06:37:37  chalky
   37| # Allow non-frames output, some refactoring of page layout, new modules.
   38| #
   39| # Revision 1.16  2002/11/01 07:21:15  chalky
   40| # More HTML formatting fixes eg: ampersands and stuff
   41| #
   42| # Revision 1.15  2002/10/25 03:43:10  chalky
   43| # Don't put spaces in url anchors
   44| #
   45| # Revision 1.14  2002/10/20 02:21:25  chalky
   46| # Move quote function to Core.Util
   47| #
   48| # Revision 1.13  2002/09/28 06:32:08  chalky
   49| # Ooops, removing print
   50| #
   51| # Revision 1.12  2002/09/28 06:15:51  chalky
   52| # Quote filenames to prevent angle brackets being used
   53| #
   54| # Revision 1.11  2002/07/19 14:26:32  chalky
   55| # Revert prefix in FileLayout but keep relative referencing elsewhere.
   56| #
   57| # Revision 1.9  2001/06/28 07:22:18  stefan
   58| # more refactoring/cleanup in the HTML formatter
   59| #
   60| # Revision 1.8  2001/06/26 04:32:16  stefan
   61| # A whole slew of changes mostly to fix the HTML formatter's output generation,
   62| # i.e. to make the output more robust towards changes in the layout of files.
   63| #
   64| # the rpm script now works, i.e. it generates source and binary packages.
   65| #
   66| # Revision 1.7  2001/06/16 01:29:42  stefan
   67| # change the HTML formatter to not use chdir, as this triggers a but in python's import implementation
   68| #
   69| # Revision 1.6  2001/02/05 07:58:39  chalky
   70| # Cleaned up image copying for *JS. Added synopsis logo to ScopePages.
   71| #
   72| # Revision 1.5  2001/02/01 18:36:55  chalky
   73| # Moved TOC out to Formatter/TOC.py
   74| #
   75| # Revision 1.4  2001/02/01 18:08:26  chalky
   76| # Added ext=".html" argument to nameOfScopedSpecial
   77| #
   78| # Revision 1.3  2001/02/01 18:06:06  chalky
   79| # Added nameOfScopedSpecial method
   80| #
   81| # Revision 1.2  2001/02/01 15:23:24  chalky
   82| # Copywritten brown paper bag edition.
   83| #
   84| #
   85| 
   86| """
   87| FileLayout module. This is the base class for the FileLayout interface. The
   88| default implementation stores everything in the same directory.
   89| """
   90| 
   91| # System modules
   92| import os, sys, stat, string, re
   93| 
   94| # Synopsis modules
   95| from Synopsis.Core import Util, AST
   96| from Synopsis.Formatter import TOC
   97| 
   98| # HTML modules
   99| import core
  100| from core import config
  101| from Tags import *
  102| 
  103| class FileLayout (TOC.Linker):
  104|     """Base class for naming files.
  105|     You may derive from this class an
  106|     reimplement any methods you like. The default implementation stores
  107|     everything in the same directory (specified by -o)."""
  108|     def __init__(self):
  109|         basename = config.basename
  110|         stylesheet = config.stylesheet
  111|         stylesheet_file = config.stylesheet_file
  112|         if basename is None:
  113|             print "ERROR: No output directory specified."
  114|             print "You must specify a base directory with the -o option."
  115|             sys.exit(1)
  116|         import os.path
  117|         if not os.path.exists(basename):
  118|             if config.verbose: print "Warning: Output directory does not exist. Creating."
  119|         try:
  120|                os.makedirs(basename, 0755)
  121|             except EnvironmentError, reason:
  122|                print "ERROR: Creating directory:",reason
  123|                sys.exit(2)
  124|         if stylesheet_file:
  125|             # Copy stylesheet in
  126|             self.copyFile(stylesheet_file, os.path.join(basename, stylesheet))
  127|         if not os.path.isdir(basename):
  128|             print "ERROR: Output must be a directory."
  129|             sys.exit(1)
  130|     def copyFile(self, orig_name, new_name):
  131|         """Copies file if newer. The file named by orig_name is compared to
  132|         new_name, and if newer or new_name doesn't exist, it is copied."""
  133|         try:
  134|             filetime = os.stat(orig_name)[stat.ST_MTIME]
  135|             if not os.path.exists(new_name) or \
  136|                filetime > os.stat(new_name)[stat.ST_MTIME]:
  137|                fin = open(orig_name,'r')
  138|                fout = Util.open(new_name)
  139|                fout.write(fin.read())
  140|                fin.close()
  141|                fout.close()
  142|         except EnvironmentError, reason:
  143|             import traceback
  144|             traceback.print_exc()
  145|             print "ERROR: ", reason
  146|             sys.exit(2)
  147|     
  148|     def _checkMain(self, filename):
  149|         """Checks whether the given filename is the main index page or not. If
  150|         it is, then it returns the filename from nameOfIndex(), else it returns
  151|         it unchanged"""
  152|         if filename == config.page_main: return self.nameOfIndex()
  153|         return filename
  154|         
  155|     def nameOfScope(self, scope):
  156|         """Return the filename of a scoped name (class or module).
  157|         The default implementation is to join the names with '-' and append
  158|         ".html" Additionally, special characters are Util.quoted in URL-style"""
  159|         if not len(scope): return self._checkMain(self.nameOfSpecial('global'))
  160|         return Util.quote(string.join(scope,'-')) + ".html"
  161|     def _stripFilename(self, file):
  162|         if len(file) and file[-1] == '/': file = file[:-1]
  163|         return file
  164|     def nameOfFileIndex(self, file):
  165|         """Return the filename for the index of an input file.
  166|         The base_dir config option is used.
  167|         Default implementation is to join the path with '-', prepend "_file-"
  168|         and append ".html" """
  169|         file = self._stripFilename(file)
  170|         return "_file-"+rel(config.base_dir, file).replace(os.sep, '-')+".html"
  171|     def nameOfFileSource(self, file):
  172|         """Return the filename for the source of an input file.
  173|         The base_dir config option is used.
  174|         Default implementation is to join the path with '-', prepend "_source-"
  175|         and append ".html" """
  176|         file = self._stripFilename(file)
  177|         return "_source-"+rel(config.base_dir, file).replace(os.sep, '-')+".html"
  178|     def nameOfFileDetails(self, file):
  179|         """Return the filename for the details of an input file.
  180|         The base_dir config option is used.
  181|         Default implementation is to join the path with '-', prepend
  182|         "_filedetail-" and append ".html" """
  183|         file = self._stripFilename(file)
  184|         return "_filedetail-"+rel(config.base_dir, file).replace(os.sep, '-')+".html"
  185|     def nameOfIndex(self):
  186|         """Return the name of the main index file. Default is index.html"""
  187|         return "index.html"
  188|     def nameOfSpecial(self, name):
  189|         """Return the name of a special file (tree, etc). Default is
  190|         _name.html"""
  191|         return self._checkMain("_" + name + ".html")
  192|     def nameOfScopedSpecial(self, name, scope, ext=".html"):
  193|         """Return the name of a special type of scope file. Default is to join
  194|         the scope with '-' and prepend '-'+name"""
  195|         return "_%s-%s%s"%(name, Util.quote(string.join(scope, '-')), ext)
  196|     def nameOfModuleTree(self):
  197|         """Return the name of the module tree index. Default is
  198|         _modules.html"""
  199|         return "_modules.html"
  200|     def nameOfModuleIndex(self, scope):
  201|         """Return the name of the index of the given module. Default is to
  202|         join the name with '-', prepend "_module_" and append ".html" """
  203|         # Prefer module index for frames
  204|         if config.using_module_index:
  205|             return "_module_" + Util.quote(string.join(scope, '-')) + ".html"
  206|         # Fall back to the scope page
  207|         return self.nameOfScope(scope)
  208|         
  209|     def link(self, decl):
  210|         """Create a link to the named declaration. This method may have to
  211|         deal with the directory layout."""
  212|         if isinstance(decl, AST.Scope):
  213|             # This is a class or module, so it has its own file
  214|             return self.nameOfScope(decl.name())
  215|         # Assume parent scope is class or module, and this is a <A> name in it
  216|         filename = self.nameOfScope(decl.name()[:-1])
  217|         anchor = anglebrackets(decl.name()[-1].replace(' ','-'))
  218|         return filename + "#" + anchor
  219| 
  220| class NestedFileLayout (FileLayout):
  221|     """generates a structured file system instead of a flat one"""
  222|     def __init__(self):
  223|         FileLayout.__init__(self)
  224| 
  225|     def nameOfScope(self, scope):
  226|         """Return the filename of a scoped name (class or module).
  227|         One subdirectory per scope"""
  228|         prefix = 'Scopes'
  229|         if not len(scope):
  230|             return self._checkMain(os.path.join(prefix, 'global') + '.html')
  231|         else: return Util.quote(reduce(os.path.join, scope, prefix)) + '.html'
  232| 
  233|     def nameOfFileIndex(self, file):
  234|         """Return the filename for the index of an input file.
  235|         The base_dir config option is used.
  236|         Default implementation is to join the path with '-', prepend "_file-"
  237|         and append ".html" """
  238|         file = self._stripFilename(file)
  239|         return os.path.join("File", rel(config.base_dir, file)+".html")
  240| 
  241|     def nameOfFileSource(self, file):
  242|         """Return the filename for the source of an input file.
  243|         The base_dir config option is used.
  244|         Default implementation is to join the path with '-', prepend "_source-"
  245|         and append ".html" """
  246|         file = self._stripFilename(file)
  247|         return os.path.join("Source", rel(config.base_dir, file)+".html")
  248| 
  249|     def nameOfFileDetails(self, file):
  250|         """Return the filename for the details of an input file.
  251|         The base_dir config option is used.
  252|         Returns the filename nested in the FileDetails directory and with
  253|         .html appended."""
  254|         file = self._stripFilename(file)
  255|         return os.path.join("FileDetails", rel(config.base_dir, file)+".html")
  256| 
  257|     def nameOfIndex(self):
  258|         """Return the name of the main index file."""
  259|         return "index.html"
  260| 
  261|     def nameOfSpecial(self, name):
  262|         """Return the name of a special file (tree, etc)."""
  263|         return self._checkMain(name + ".html")
  264|     
  265|     def nameOfScopedSpecial(self, name, scope, ext=".html"):
  266|         """Return the name of a special type of scope file"""
  267|         return Util.quote(reduce(os.path.join, scope, name)) + ext
  268| 
  269|     def nameOfModuleTree(self):
  270|         """Return the name of the module tree index"""
  271|         return "Modules.html"
  272| 
  273|     def nameOfModuleIndex(self, scope):
  274|         """Return the name of the index of the given module"""
  275|         return Util.quote(reduce(os.path.join, scope, 'Modules')) + '.html'