2012-11-24 02:57:22 +08:00
#/usr/bin/env python
2011-07-08 23:00:11 +08:00
import os , sys , re , string , glob
2012-08-27 20:48:09 +08:00
from optparse import OptionParser
2011-07-11 23:03:42 +08:00
2012-12-19 16:53:44 +08:00
# Black list for classes and methods that does not implemented in Java API
# Created to exclude referencies to them in @see tag
JAVADOC_ENTITY_BLACK_LIST = set ( [ " org.opencv.core.Core#abs " , \
" org.opencv.core.Core#theRNG " , \
" org.opencv.core.Core#extractImageCOI " , \
" org.opencv.core.PCA " , \
" org.opencv.core.SVD " , \
" org.opencv.core.RNG " , \
" org.opencv.imgproc.Imgproc#createMorphologyFilter " , \
" org.opencv.imgproc.Imgproc#createLinearFilter " , \
" org.opencv.imgproc.Imgproc#createSeparableLinearFilter " , \
" org.opencv.imgproc.FilterEngine " ] )
2011-07-11 23:03:42 +08:00
class JavadocGenerator ( object ) :
2012-08-27 20:48:09 +08:00
def __init__ ( self , definitions = { } , modules = [ ] , javadoc_marker = " //javadoc: " ) :
2011-07-11 23:03:42 +08:00
self . definitions = definitions
self . javadoc_marker = javadoc_marker
self . markers_processed = 0
self . markers_documented = 0
self . params_documented = 0
self . params_undocumented = 0
2012-08-27 20:48:09 +08:00
self . known_modules = modules
self . verbose = False
self . show_warnings = True
self . show_errors = True
2011-07-11 23:03:42 +08:00
def parceJavadocMarker ( self , line ) :
assert line . lstrip ( ) . startswith ( self . javadoc_marker )
offset = line [ : line . find ( self . javadoc_marker ) ]
line = line . strip ( ) [ len ( self . javadoc_marker ) : ]
args_start = line . rfind ( " ( " )
args_end = line . rfind ( " ) " )
assert args_start * args_end > 0
if args_start > = 0 :
assert args_start < args_end
2011-08-02 18:58:26 +08:00
name = line [ : args_start ] . strip ( )
if name . startswith ( " java " ) :
name = name [ 4 : ]
return ( name , offset , filter ( None , list ( arg . strip ( ) for arg in line [ args_start + 1 : args_end ] . split ( " , " ) ) ) )
name = line . strip ( )
if name . startswith ( " java " ) :
name = name [ 4 : ]
return ( name , offset , [ ] )
2011-07-11 23:03:42 +08:00
def document ( self , infile , outfile ) :
inf = open ( infile , " rt " )
outf = open ( outfile , " wt " )
2011-07-26 17:13:30 +08:00
module = os . path . splitext ( os . path . basename ( infile ) ) [ 0 ] . split ( " + " ) [ 0 ]
2012-08-27 20:48:09 +08:00
if module not in self . known_modules :
2011-07-11 23:03:42 +08:00
module = " unknown "
try :
for l in inf . readlines ( ) :
2011-08-06 17:22:07 +08:00
org = l
l = l . replace ( " " , " " ) . replace ( " \t " , " " ) #remove all whitespace
if l . startswith ( self . javadoc_marker ) :
2011-07-11 23:03:42 +08:00
marker = self . parceJavadocMarker ( l )
self . markers_processed + = 1
decl = self . definitions . get ( marker [ 0 ] , None )
if decl :
javadoc = self . makeJavadoc ( decl , marker [ 2 ] )
2012-08-27 20:48:09 +08:00
if self . verbose :
2011-07-11 23:03:42 +08:00
print
print " Javadoc for \" %s \" File: %s (line %s ) " % ( decl [ " name " ] , decl [ " file " ] , decl [ " line " ] )
print javadoc
for line in javadoc . split ( " \n " ) :
outf . write ( marker [ 1 ] + line + " \n " )
self . markers_documented + = 1
2012-08-27 20:48:09 +08:00
elif self . show_errors :
2011-07-11 23:03:42 +08:00
print >> sys . stderr , " gen_javadoc error: could not find documentation for %s (module: %s ) " % ( l . lstrip ( ) [ len ( self . javadoc_marker ) : - 1 ] . strip ( ) , module )
2011-07-08 23:00:11 +08:00
else :
2011-08-06 17:22:07 +08:00
outf . write ( org . replace ( " \t " , " " ) . rstrip ( ) + " \n " )
2011-07-11 23:03:42 +08:00
except :
inf . close ( )
outf . close ( )
os . remove ( outfile )
raise
2011-07-08 23:00:11 +08:00
else :
2011-07-11 23:03:42 +08:00
inf . close ( )
outf . close ( )
2012-04-30 22:33:52 +08:00
def FinishParagraph ( self , text ) :
return text [ : - 1 ] + " </p> \n "
2011-07-11 23:03:42 +08:00
def ReformatForJavadoc ( self , s ) :
out = " "
2012-04-30 22:33:52 +08:00
in_paragraph = False
in_list = False
2011-07-11 23:03:42 +08:00
for term in s . split ( " \n " ) :
2012-04-30 22:33:52 +08:00
in_list_item = False
if term . startswith ( " * " ) :
in_list_item = True
if in_paragraph :
out = self . FinishParagraph ( out )
in_paragraph = False
if not in_list :
out + = " * <ul> \n "
in_list = True
term = " <li> " + term [ 1 : ]
if term . startswith ( " #. " ) :
in_list_item = True
if in_paragraph :
out = self . FinishParagraph ( out )
in_paragraph = False
if not in_list :
out + = " * <ul> \n "
in_list = True
term = " <li> " + term [ 2 : ]
2011-07-11 23:03:42 +08:00
if not term :
2012-04-30 22:33:52 +08:00
if in_paragraph :
out = self . FinishParagraph ( out )
in_paragraph = False
2011-07-11 23:03:42 +08:00
out + = " * \n "
else :
2012-04-30 22:33:52 +08:00
if in_list and not in_list_item :
in_list = False
if out . endswith ( " * \n " ) :
out = out [ : - 3 ] + " * </ul> \n * \n "
else :
out + = " * </ul> \n "
2011-07-11 23:03:42 +08:00
pos_start = 0
pos_end = min ( 77 , len ( term ) - 1 )
while pos_start < pos_end :
if pos_end - pos_start == 77 :
while pos_end > = pos_start + 60 :
2011-07-08 23:00:11 +08:00
if not term [ pos_end ] . isspace ( ) :
2011-07-11 23:03:42 +08:00
pos_end - = 1
2011-07-08 23:00:11 +08:00
else :
break
2011-07-11 23:03:42 +08:00
if pos_end < pos_start + 60 :
pos_end = min ( pos_start + 77 , len ( term ) - 1 )
while pos_end < len ( term ) :
if not term [ pos_end ] . isspace ( ) :
pos_end + = 1
else :
break
2012-04-30 22:33:52 +08:00
if in_paragraph or term . startswith ( " @ " ) or in_list_item :
out + = " * "
else :
in_paragraph = True
out + = " * <p> "
out + = term [ pos_start : pos_end + 1 ] . rstrip ( ) + " \n "
2011-07-11 23:03:42 +08:00
pos_start = pos_end + 1
pos_end = min ( pos_start + 77 , len ( term ) - 1 )
2012-04-30 22:33:52 +08:00
if in_paragraph :
out = self . FinishParagraph ( out )
if in_list :
out + = " * </ul> \n "
2011-07-11 23:03:42 +08:00
return out
2012-04-30 22:33:52 +08:00
def getJavaName ( self , decl , methodSeparator = " . " ) :
2011-07-11 23:03:42 +08:00
name = " org.opencv. "
name + = decl [ " module " ]
if " class " in decl :
name + = " . " + decl [ " class " ]
else :
name + = " . " + decl [ " module " ] . capitalize ( )
if " method " in decl :
2012-04-30 22:33:52 +08:00
name + = methodSeparator + decl [ " method " ]
2011-07-11 23:03:42 +08:00
return name
def getDocURL ( self , decl ) :
2012-04-30 22:33:52 +08:00
url = " http://docs.opencv.org/modules/ "
2011-07-11 23:03:42 +08:00
url + = decl [ " module " ]
url + = " /doc/ "
url + = os . path . basename ( decl [ " file " ] ) . replace ( " .rst " , " .html " )
url + = " # " + decl [ " name " ] . replace ( " :: " , " - " ) . replace ( " () " , " " ) . replace ( " = " , " " ) . strip ( ) . rstrip ( " _ " ) . replace ( " " , " - " ) . replace ( " _ " , " - " ) . lower ( )
return url
def makeJavadoc ( self , decl , args = None ) :
doc = " "
prefix = " /** \n "
if decl . get ( " isclass " , False ) :
decl_type = " class "
elif decl . get ( " isstruct " , False ) :
decl_type = " struct "
elif " class " in decl :
decl_type = " method "
else :
decl_type = " function "
# brief goes first
if " brief " in decl :
doc + = prefix + self . ReformatForJavadoc ( decl [ " brief " ] )
prefix = " * \n "
elif " long " not in decl :
2012-08-27 20:48:09 +08:00
if self . show_warnings :
2011-07-11 23:03:42 +08:00
print >> sys . stderr , " gen_javadoc warning: no description for " + decl_type + " \" %s \" File: %s (line %s ) " % ( func [ " name " ] , func [ " file " ] , func [ " line " ] )
doc + = prefix + self . ReformatForJavadoc ( " This " + decl_type + " is undocumented " )
prefix = " * \n "
2012-08-27 20:48:09 +08:00
2011-07-11 23:03:42 +08:00
# long goes after brief
if " long " in decl :
doc + = prefix + self . ReformatForJavadoc ( decl [ " long " ] )
prefix = " * \n "
# @param tags
if args and ( decl_type == " method " or decl_type == " function " ) :
documented_params = decl . get ( " params " , { } )
for arg in args :
arg_doc = documented_params . get ( arg , None )
if not arg_doc :
arg_doc = " a " + arg
2012-08-27 20:48:09 +08:00
if self . show_warnings :
2011-07-11 23:03:42 +08:00
print >> sys . stderr , " gen_javadoc warning: parameter \" %s \" of \" %s \" is undocumented. File: %s (line %s ) " % ( arg , decl [ " name " ] , decl [ " file " ] , decl [ " line " ] )
self . params_undocumented + = 1
else :
self . params_documented + = 1
doc + = prefix + self . ReformatForJavadoc ( " @param " + arg + " " + arg_doc )
prefix = " "
prefix = " * \n "
# @see tags
# always link to documentation
doc + = prefix + " * @see <a href= \" " + self . getDocURL ( decl ) + " \" > " + self . getJavaName ( decl ) + " </a> \n "
prefix = " "
# other links
if " seealso " in decl :
for see in decl [ " seealso " ] :
seedecl = self . definitions . get ( see , None )
if seedecl :
2012-12-19 16:53:44 +08:00
javadoc_name = self . getJavaName ( seedecl , " # " )
if ( javadoc_name not in JAVADOC_ENTITY_BLACK_LIST ) :
doc + = prefix + " * @see " + javadoc_name + " \n "
2011-07-08 23:00:11 +08:00
prefix = " * \n "
2011-07-11 23:03:42 +08:00
#doc += prefix + " * File: " + decl["file"] + " (line " + str(decl["line"]) + ")\n"
2011-07-08 23:00:11 +08:00
2011-07-11 23:03:42 +08:00
return ( doc + " */ " ) . replace ( " :: " , " . " )
2011-07-08 23:00:11 +08:00
2011-07-11 23:03:42 +08:00
def printSummary ( self ) :
print " Javadoc Generator Summary: "
print " Total markers: %s " % self . markers_processed
print " Undocumented markers: %s " % ( self . markers_processed - self . markers_documented )
print " Generated comments: %s " % self . markers_documented
2011-07-08 23:00:11 +08:00
2011-07-11 23:03:42 +08:00
print
print " Documented params: %s " % self . params_documented
print " Undocumented params: %s " % self . params_undocumented
print
2011-07-08 23:00:11 +08:00
if __name__ == " __main__ " :
2012-08-27 20:48:09 +08:00
2011-07-08 23:00:11 +08:00
selfpath = os . path . dirname ( os . path . abspath ( sys . argv [ 0 ] ) )
2012-06-21 19:44:31 +08:00
hdr_parser_path = os . path . join ( selfpath , " ../../python/src2 " )
2012-08-27 20:48:09 +08:00
2011-07-08 23:00:11 +08:00
sys . path . append ( selfpath )
sys . path . append ( hdr_parser_path )
import hdr_parser
import rst_parser
2012-08-27 20:48:09 +08:00
parser = OptionParser ( )
parser . add_option ( " -v " , " --verbose " , dest = " verbose " , help = " Print verbose log to stdout " , action = " store_true " , default = False )
parser . add_option ( " " , " --no-warnings " , dest = " warnings " , help = " Hide warning messages " , action = " store_false " , default = True )
parser . add_option ( " " , " --no-errors " , dest = " errors " , help = " Hide error messages " , action = " store_false " , default = True )
parser . add_option ( " " , " --modules " , dest = " modules " , help = " comma-separated list of modules to generate comments " , metavar = " MODS " , default = " , " . join ( rst_parser . allmodules ) )
( options , args ) = parser . parse_args ( sys . argv )
options . modules = options . modules . split ( " , " )
if len ( args ) < 2 or len ( options . modules ) < 1 :
parser . print_help ( )
exit ( 0 )
2011-07-11 23:03:42 +08:00
parser = rst_parser . RstParser ( hdr_parser . CppHeaderParser ( ) )
2012-08-27 20:48:09 +08:00
for m in options . modules :
2012-06-21 22:50:05 +08:00
parser . parse ( m , os . path . join ( selfpath , " ../../ " + m ) )
2012-08-27 20:48:09 +08:00
2011-07-11 21:33:05 +08:00
parser . printSummary ( )
2011-07-08 23:00:11 +08:00
2012-08-27 20:48:09 +08:00
generator = JavadocGenerator ( parser . definitions , options . modules )
generator . verbose = options . verbose
generator . show_warnings = options . warnings
generator . show_errors = options . errors
for path in args :
folder = os . path . abspath ( path )
2011-07-11 21:33:05 +08:00
for jfile in [ f for f in glob . glob ( os . path . join ( folder , " *.java " ) ) if not f . endswith ( " -jdoc.java " ) ] :
2011-07-08 23:00:11 +08:00
outfile = os . path . abspath ( os . path . basename ( jfile ) . replace ( " .java " , " -jdoc.java " ) )
2011-07-11 23:03:42 +08:00
generator . document ( jfile , outfile )
generator . printSummary ( )