#!/usr/bin/env python
################################################################################################
# @(#) $Id: Subsystem.py,v 1.18 2011/10/28 14:39:18 hsommer Exp $
#
# ALMA - Atacama Large Millimiter Array
# (c) Associated Universities, Inc. Washington DC, USA, 2001
# (c) European Southern Observatory, 2002
# Copyright by ESO (in the framework of the ALMA collaboration)
# and Cosylab 2002, All rights reserved
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
###############################################################################
# -------- ---------- ----------------------------------------------
# acaproni 2005/02/08 Created.
#------------------------------------------------------------------------------
import glob, os, string, re, xml.parsers.expat, sys, time, fpformat
from ErrorDefinition import *
class Subsystem(object):
"""The object to scan a subsystem.
It assumes that the base directory contains
all the sources of the subsystem
name is the name of the subsystem
basedir is the base directory for the subsystem
min is the minimum allowed error number for this subsystem
max is the maximum allowed error number for this subsystem
ExaplesTestRange is the range for example and test errors
exclude is a list of directory trees to discard (CVS is a valid choice here)
include the directories to scan: if present only those folder
are scanned for the files (idl is a valide choice here)
"""
def __init__(self, name, basedir,min,max,exaplesAndTestsRange,exclude=["CVS"],include=None):
# The maximum and the minimum allowed number for the errors of
# this subsystem
self.min = min
self.max = max
#The name of this subsystem
self.subsystemName=name
#The base directory for the subsystem
self.baseDir = basedir
# The range for example and test errors
self.testErrorRange=exaplesAndTestsRange
# The times of start/end of this scan
self.startTime=time.ctime()
self.startFloatTime=time.time()
self.endTime=self.startTime
self.endFloatTime=self.startFloatTime
print self.startTime+', scanning',self.subsystemName,'....'
#The list of all the names of the files defining errors
self.files=[]
# The name of files and directory to exclude from the search path
# (also the subdirectory are discarded)
self.exclude=exclude
# The directories to include in the search
self.include=include
# The list of number of duplicated errors
self.duplicatedErrors=[]
#The list of number out of the allowed range
self.outOfRangeErrors=[]
# The list of number for test and examples
self.testAndExampleErrors = []
# Print some infos
print"Subsystem ",self.subsystemName,"with base dir",self.baseDir
# Scans the directory of the subsystem
self.scans(self.baseDir)
print "Found",len(self.files),"candidates"
self.candidates=len(self.files)
#Parse the candidates to build the list of errors of the subsystems
self.errors=self.parseXMLFiles(self.files)
print "Found",len(self.files),"error definition files"
print "Found",len(self.errors), "errors"
#Order the errors
self.orderErrors()
# Check for duplicated errors
self.checkSubsystemErrors()
# Print info about duplicated errors
if len(self.duplicatedErrors)==0:
print "The subsystem contains no duplicated errors"
else:
print "The subsystem contains the following duplicated error definitions:",
print self.duplicatedErrors
# Print info about errors out of range
if len(self.outOfRangeErrors)==0:
print "The subsystem contains no errors out of the allowed range"
else:
print "The subsystem contains the following errors with an invalid number:",
print self.outOfRangeErrors
# Print info about the errors for examples and tests
if len(self.testAndExampleErrors)==0:
print "The subsystem does not containes definitions for tests and examples"
else:
print "The following errors are used for test and examples:",
print self.testAndExampleErrors
# Store the time
self.endTime=time.ctime()
self.endFloatTime=time.time()
# Print the time
print self.endTime+ ", check terminated"
print fpformat.fix(self.endFloatTime-self.startFloatTime,3),"seconds requested to check this system"
def excluded(self, name):
"""Check if name is valid i.e. not part of the excluded"""
if self.exclude==None or self.exclude==[]:
return False
for n in self.exclude:
str = "/"+n
sstr = name[len(name)-len(str):len(name)]
if str == sstr:
return True
return False
def included(self,name):
"""Check if name is a directory defined in include"""
if self.include==None or self.include==[]:
return True
#Check if name is a directory
if not os.path.isdir(name):
return False
names = string.split(name,'/')
return self.include.count(names[len(names)-1])>0
def isErrorDefFile(self,fileName):
"""Check if fileName contains an error definition.
It must be an xml file with the right format"""
if os.path.isdir(fileName):
return False
if fileName[len(fileName)-4:len(fileName)]!=".xml":
return False
#The first line of an xml file contains something like
# So it doesn't work with included xml files....
try:
# Read the first line of the file
inF=open(fileName)
line=inF.readline().strip()
inF.close()
#Check if the line is of this kind:
return re.compile("<*\?xml.*\?>").match(line, 1)!=None
except IOError, e:
print "Unable to open",f
print "Exception",e
return False
def scans(self,dir):
"""Scans the base directory looking for the
xml files defining erros"""
for root, dirs, files in os.walk(dir):
# Check if some of the files in the directory is an xml files to be added
# to the list
for f in files:
if self.isErrorDefFile(os.path.join(root,f)) and self.included(root):
self.files.append(os.path.join(root,f))
#Checks if some of the directory must be excluded from the scan
for d in dirs:
if (self.excluded(os.path.join(root,d))):
dirs.remove(d)
def parseXMLFiles(self,xmlFiles):
"""Parse all the xml files and bild a list of error definitions
xmlFiles is the list of xml files to parse
return a list of ErrorDefinition objects"""
ret=[] # The errors
errorFiles=[]# The new list of files
for f in xmlFiles:
err = ErrorDefinition(f)
if err.isValid():
ret.append(err)
errorFiles.append(f)
self.files=errorFiles
return ret
def orderErrors(self):
"""Order the errors by their number"""
newList=[]
while len(self.errors)>0:
# Extract the error or with the lower type
# and insert it in the head of the new list
pos=0
min=self.errors[0].getNumber()
for s in range(0,len(self.errors)):
if self.errors[s].getNumber() Sorry, '+fileName+' is unreadable!'
return str
def generateHTMLPage(self,fileName):
"""Generate the main HTML page for the errors
The page is written into a file of the given name (filename)
If fileName is None the page is written in the stdout
For ach error described in this page there is a link to another HTML page
with the detailed info about that error"""
# count is used to generate the name of the sub pages describing
# the details of each error
count = 0
# The entire document is written into text
text=self.getHTMLHeader(None);
#Write the title of the page
text=text+' Generated scanning the basedir '+self.baseDir+' The subsystem contains no duplicated errors The subsystem contains the following duplicated error definitions:'
text=text+'\n'
for line in lines:
line = line.replace('&','&')
line = line.replace('<','<')
line = line.replace('>','>')
str=str+line
str=str+'\n
\n'
theFile.close()
else:
str=str+'Error definitions for '+self.subsystemName+'
\n'
text=text+'
\n'
text=text+'Generated at '+self.startTime+'
\n'
# Print some info about the duplicated errors
if len(self.duplicatedErrors)==0:
text=text+"'
for i in self.duplicatedErrors:
text=text+'
'
for err in self.errors:
if err.getNumber()==i:
text=text+'
'
text=text+'
All the number of the errors are in the right range ' else: text=text+'
The subsystem contains the following definition with an invalid number:' text=text+'
'+str(self.candidates)+' | parsed candidate xml files |
'+str(len(self.errors))+' | error definition files found |
'+str(totErrors)+' | errors defined |
'+str(totCodes)+' | codes defined |
The range of the error numbers for this subsystem is ['+str(self.min)+','+str(self.max)+']
' text=text+'The range for examples and tests is ['+str(self.testErrorRange["Min"])+','+str(self.testErrorRange["Max"])+']
' #Print all the errors (no examples and tests) into a table text=text+'Type definitions appear in bold
\n'
text=text+'Duplicated error types are printed in Red
\n'
text=text+'Errors with a number out of the allowed range appears Red italic underline
Subsystem scanned in '+fpformat.fix(self.endFloatTime-self.startFloatTime,3)+' seconds.
' #Close the document text=text+self.getHTMLFooter() #Write the page on disk self.writeHTMLOnFile(text, fileName) def generateHTMLForErrorMember(self,error,fontStyle,endFontStyle): """Return an HTML string of the Members of the error (if any)""" members=error['Members'] htmlText='Name | Type | Description | |||
'+m['name']+' | \n' else: htmlText+="\n" if m.has_key('type'): htmlText+=' | '+m['type']+' | \n' else: html+="\n" if m.has_key('description'): htmlText+=' | '+m['description']+' | \n' else: htmlText+="\n" htmlText+=' |
Error name: | '+error.getName()+' |
Error code: | '+str(error.getNumber())+' |
The error is defined in: | '+error.getFile()+' |
IDL | |
File name: | '+error.getName()+'.idl |
Module: | '+error.getName()+' |
C++ | |
Include file name: | #include <'+error.getName()+'.h> |
Namespace: | using namespace '+error.getName()+'; |
Exception for type: | '+error.getName()+'::'+error.getName()+'ExImpl |
Library file name: | lib'+error.getName()+'.so lib'+error.getName()+'.a |
Python | |
Python imports: | import '+error.getName()+'Impl |
Java | |
Jar file name: | '+error.getName()+'.jar |
Packages: | import alma.'+error.getName()+'.*; import alma.'+error.getName()+'.wrapper.*; |
Exception for type: | alma.'+error.getName()+'.'+error.getName()+'Ex |
Exception for type (wrapper): | alma.'+error.getName()+'.wrapper.AcsJ'+error.getName()+'Ex |
Short description | ' if t.has_key("shortDescription"): htmlText=htmlText+''+fontStyle+t["shortDescription"]+endFontStyle+' | \n' else: htmlText=htmlText+''+fontStyle+"N/A"+endFontStyle+' | \n' htmlText=htmlText+'
Description | ' if t.has_key("description"): htmlText=htmlText+''+fontStyle+t["description"]+endFontStyle+' | \n' else: htmlText=htmlText+''+fontStyle+"N/A"+endFontStyle+' | \n' if t.has_key('Members') and len(t['Members'])>0: htmlText=htmlText+'
Members | ' htmlText=htmlText+self.generateHTMLForErrorMember(t,fontStyle,endFontStyle) htmlText=htmlText+' | |
IDL | ||
File name: | '+error.getName()+'.idl | |
Module: | '+error.getName()+' | |
Error code: | '+t['name']+' | |
Exception: | '+t['name']+'Ex | |
C++ | ||
Include file name: | #include <'+error.getName()+'.h> | |
Namespace: | using namespace '+error.getName()+'; | |
Exception for error: | '+error.getName()+'::'+t['name']+'ExImpl | |
Completion: | '+error.getName()+'::'+t['name']+'Completion | |
Library file name: | lib'+error.getName()+'.so lib'+error.getName()+'.a | |
Python | ||
Imports: | import '+error.getName()+'Impl | |
Raise a local exception: | raise '+error.getName()+'Impl.'+t['name']+'ExImpl() | |
Catch exception: | except '+error.getName()+'Impl.'+t['name']+'Ex, e: | |
Java | ||
Jar file name: | '+error.getName()+'.jar | |
Packages: | import alma.'+error.getName()+'.*; import alma.'+error.getName()+'.wrapper.*; | |
Exception for error: | alma.'+error.getName()+'.'+t['name']+'Ex | |
Exception for error (wrapper): | alma.'+error.getName()+'.wrapper.AcsJ'+t['name']+'Ex |
Short description | ' if t.has_key("shortDescription"): htmlText=htmlText+''+fontStyle+t["shortDescription"]+endFontStyle+' | \n' else: htmlText=htmlText+''+fontStyle+"N/A"+endFontStyle+' | \n' htmlText=htmlText+'
Description | ' if t.has_key("description"): htmlText=htmlText+''+fontStyle+t["description"]+endFontStyle+' | \n' else: htmlText=htmlText+''+fontStyle+"N/A"+endFontStyle+' | \n' htmlText=htmlText+'
IDL | ||
File name: | '+error.getName()+'.idl | |
Module: | '+error.getName()+' | |
Error code: | '+t['name']+' | |
C++ | ||
Include file name: | include <'+error.getName()+'.h> | |
Namespace: | using namespace '+error.getName()+'; | |
Completion: | '+error.getName()+'::'+t['name']+'Completion | |
Library file name: | lib'+error.getName()+'.so lib'+error.getName()+'.a | |
Python | ||
Imports: | import '+error.getName()+'Impl | |
Java | ||
Jar file name: | '+error.getName()+'.jar | |
Packages: | import alma.'+error.getName()+'.*; import alma.'+error.getName()+'.wrapper.*; |
No codes defined>' # Insert the XML htmlText=htmlText+'
Generated scanning the basedir '+self.baseDir+'
\n'
page=page+'Generated at '+self.startTime+'
This error is used for test/examples
' else: if self.outOfRangeErrors.count(error.getNumber())>0: page=page+'The error number is out of the allowed range for this subsystem
' else: page=page+'The number is in the corrrect range
' if self.duplicatedErrors.count(error.getNumber())>0: page=page+'There is another error in this subsystem with the same number
' else: page=page+'The error is not duplicated
' # Final infos page=page+'Subsystem scanned in '+fpformat.fix(self.endFloatTime-self.startFloatTime,3)+' seconds.
' page=page+self.getHTMLFooter() self.writeHTMLOnFile(page, fileName) def writeHTMLOnFile(self,page,fileName): """page if an string with the HTML page to write in the file fileName is the name of the file If fileName is None the page is written in the stdout""" if fileName==None: print page # To stdout else: try: outF=open(fileName,"w+") outF.write(page) outF.flush() outF.close except IOError, e: print "Unable to open ",fileName, "for output" print "Exception",e return