#!/usr/bin/env python
#
# $Id: scanner.py,v 1.19 2006/12/05 13:10:45 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.19 2006/12/05 13:10:45 doughellmann Exp $',
'creator' : 'Doug Hellmann',
'project' : 'HappyDoc',
'created' : 'Sat, 16-Nov-2002 17:38:31 EST',
#
# Current Information
#
'author' : '$Author: doughellmann $',
'version' : '$Revision: 1.19 $',
'date' : '$Date: 2006/12/05 13:10:45 $',
}
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
|