#!/usr/bin/env python # # $Id: scanner.py,v 1.18 2003/01/18 20:01:02 doughellmann Exp $ # # Copyright 2002 Doug Hellmann. # # # All Rights Reserved # # Permission to use, copy, modify, and distribute this software and # its documentation for any purpose and without fee is hereby # granted, provided that the above copyright notice appear in all # copies and that both that copyright notice and this permission # notice appear in supporting documentation, and that the name of Doug # Hellmann not be used in advertising or publicity pertaining to # distribution of the software without specific, written prior # permission. # # DOUG HELLMANN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, # INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN # NO EVENT SHALL DOUG HELLMANN BE LIABLE FOR ANY SPECIAL, INDIRECT OR # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS # OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # """Scanner for Python source files. The scanner finds the files to be documented, and adds nodes to the package tree. """ __rcs_info__ = { # # Creation Information # 'module_name' : '$RCSfile: scanner.py,v $', 'rcs_id' : '$Id: scanner.py,v 1.18 2003/01/18 20:01:02 doughellmann Exp $', 'creator' : 'Doug Hellmann ', 'project' : 'HappyDoc', 'created' : 'Sat, 16-Nov-2002 17:38:31 EST', # # Current Information # 'author' : '$Author: doughellmann $', 'version' : '$Revision: 1.18 $', 'date' : '$Date: 2003/01/18 20:01:02 $', } try: __version__ = __rcs_info__['version'].split(' ')[1] except: __version__ = '0.0' # # Import system modules # import glob import mimetypes import os import re # # Import Local modules # import happydoclib from happydoclib.packagetree import PackageTree from happydoclib.parsers import ParserLoader from happydoclib.status import statusMessage from happydoclib.trace import trace from happydoclib.utils import getMimeType from happydoclib.cvsignore import CVSIgnoreList # # Module # TRACE_LEVEL=2 class Scanner: """Scanner for Python source files. The scanner finds the files to be documented, and adds nodes to the package tree. """ DEFAULT_IGNORE_PATTERNS = ['^(CVS|dist|build|docs?|.*pyc|.*~|tmp)$', 'trace.txt', ] def __init__(self, inputDirectories, ignorePatterns=DEFAULT_IGNORE_PATTERNS, includeComments=1, ): trace.into('Scanner', '__init__', inputDirectories=inputDirectories, ignorePatterns=ignorePatterns, includeComments=includeComments, outputLevel=TRACE_LEVEL, ) self._ignore_patterns = ignorePatterns self._ignore_res = [ re.compile(ip) for ip in ignorePatterns ] self._include_comments = includeComments self._package_trees = [] self.parser_loader = ParserLoader() # # Scan # for dir_name in inputDirectories: if not os.path.exists(dir_name): raise ValueError('No such directory %s' % dir_name) tree = self.buildPackageTree(dir_name) if tree: self._package_trees.append(tree) trace.outof(outputLevel=TRACE_LEVEL) return def _parseOne(self, packageTreeNode): packageTreeNode.parseInput() return def parsePackageTree(self): for package_tree in self.getPackageTrees(): package_tree.walk(self._parseOne) return def buildPackageTree(self, directoryName, parent=None): """Scan a directory and build a PackageTree representing its contents. Scans through the directory finding files and other directories. When a directory is found, recurses to scan it. Returns a single PackageTree instance rooted at directoryName. """ trace.into('Scanner', 'buildPackageTree', directoryName=directoryName, #parent=parent, outputLevel=TRACE_LEVEL, ) if parent is not None: trace.writeVar(parent=parent.getName(), outputLevel=TRACE_LEVEL) else: trace.writeVar(parent=parent, outputLevel=TRACE_LEVEL) package_tree_name = os.path.basename(directoryName) # # Make sure we are not ignoring this name # #if package_tree_name in self._ignore_names: for ignore_re in self._ignore_res: if ignore_re.search(package_tree_name): trace.write('Ignoring because "%s" matched %s' % (package_tree_name, ignore_re.pattern), outputLevel=TRACE_LEVEL, ) trace.outof(outputLevel=TRACE_LEVEL) return None # # Create the node for this name # mimetype, encoding = getMimeType(directoryName) try: parser_factory = self.parser_loader[mimetype] except KeyError: parser_factory = self.parser_loader['application/octet-stream'] parser = parser_factory() tree = parser(parent, directoryName) # # See if the name refers to a directory # if os.path.isdir(directoryName): # # Get directory contents # trace.write('Scanning %s' % directoryName, outputLevel=TRACE_LEVEL) pattern = os.path.join(directoryName, '*') contents = glob.glob(pattern) local_cvsignore_filename = os.path.join(directoryName, '.cvsignore') home_cvsignore_filename = os.path.join(os.environ['HOME'], '.cvsignore') cvsignore_list = CVSIgnoreList( (local_cvsignore_filename, home_cvsignore_filename, ) ) # # Recurse # for subnode_name in contents: if cvsignore_list.shouldIgnoreFile(subnode_name): trace.write('Skipping %s, found in .cvsignore' % subnode_name, outputLevel=TRACE_LEVEL) continue self.buildPackageTree(subnode_name, tree) trace.outof(outputLevel=TRACE_LEVEL) return tree def getPackageTrees(self): """Retrieve the list of PackageTrees found by the scanner. """ return self._package_trees def walk(self, callback): """Walk the PackageTree, calling the callback at each node. """ trees = self.getPackageTrees() for tree in trees: tree.walk(callback) return