boost_wide_report.py 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835
  1. # Copyright (c) MetaCommunications, Inc. 2003-2007
  2. #
  3. # Distributed under the Boost Software License, Version 1.0.
  4. # (See accompanying file LICENSE_1_0.txt or copy at
  5. # http://www.boost.org/LICENSE_1_0.txt)
  6. import shutil
  7. import codecs
  8. import xml.sax.handler
  9. import xml.sax.saxutils
  10. import glob
  11. import re
  12. import os.path
  13. import os
  14. import string
  15. import time
  16. import sys
  17. import ftplib
  18. import utils
  19. report_types = [ 'us', 'ds', 'ud', 'dd', 'l', 'p', 'i', 'n', 'ddr', 'dsr', 'udr', 'usr' ]
  20. if __name__ == '__main__':
  21. run_dir = os.path.abspath( os.path.dirname( sys.argv[ 0 ] ) )
  22. else:
  23. run_dir = os.path.abspath( os.path.dirname( sys.modules[ __name__ ].__file__ ) )
  24. def map_path( path ):
  25. return os.path.join( run_dir, path )
  26. def xsl_path( xsl_file_name ):
  27. return map_path( os.path.join( 'xsl/v2', xsl_file_name ) )
  28. class file_info:
  29. def __init__( self, file_name, file_size, file_date ):
  30. self.name = file_name
  31. self.size = file_size
  32. self.date = file_date
  33. def __repr__( self ):
  34. return "name: %s, size: %s, date %s" % ( self.name, self.size, self.date )
  35. #
  36. # Find the mod time from unix format directory listing line
  37. #
  38. def get_date( words ):
  39. date = words[ 5: -1 ]
  40. t = time.localtime()
  41. month_names = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]
  42. year = time.localtime()[0] # If year is not secified is it the current year
  43. month = month_names.index( date[0] ) + 1
  44. day = int( date[1] )
  45. hours = 0
  46. minutes = 0
  47. if date[2].find( ":" ) != -1:
  48. ( hours, minutes ) = [ int(x) for x in date[2].split( ":" ) ]
  49. else:
  50. # there is no way to get seconds for not current year dates
  51. year = int( date[2] )
  52. return ( year, month, day, hours, minutes, 0, 0, 0, 0 )
  53. def list_ftp( f ):
  54. # f is an ftp object
  55. utils.log( "listing source content" )
  56. lines = []
  57. # 1. get all lines
  58. f.dir( lambda x: lines.append( x ) )
  59. # 2. split lines into words
  60. word_lines = [ x.split( None, 8 ) for x in lines ]
  61. # we don't need directories
  62. result = [ file_info( l[-1], None, get_date( l ) ) for l in word_lines if l[0][0] != "d" ]
  63. for f in result:
  64. utils.log( " %s" % f )
  65. return result
  66. def list_dir( dir ):
  67. utils.log( "listing destination content %s" % dir )
  68. result = []
  69. for file_path in glob.glob( os.path.join( dir, "*.zip" ) ):
  70. if os.path.isfile( file_path ):
  71. mod_time = time.localtime( os.path.getmtime( file_path ) )
  72. mod_time = ( mod_time[0], mod_time[1], mod_time[2], mod_time[3], mod_time[4], mod_time[5], 0, 0, mod_time[8] )
  73. # no size (for now)
  74. result.append( file_info( os.path.basename( file_path ), None, mod_time ) )
  75. for fi in result:
  76. utils.log( " %s" % fi )
  77. return result
  78. def find_by_name( d, name ):
  79. for dd in d:
  80. if dd.name == name:
  81. return dd
  82. return None
  83. def diff( source_dir_content, destination_dir_content ):
  84. utils.log( "Finding updated files" )
  85. result = ( [], [] ) # ( changed_files, obsolete_files )
  86. for source_file in source_dir_content:
  87. found = find_by_name( destination_dir_content, source_file.name )
  88. if found is None: result[0].append( source_file.name )
  89. elif time.mktime( found.date ) != time.mktime( source_file.date ): result[0].append( source_file.name )
  90. else:
  91. pass
  92. for destination_file in destination_dir_content:
  93. found = find_by_name( source_dir_content, destination_file.name )
  94. if found is None: result[1].append( destination_file.name )
  95. utils.log( " Updated files:" )
  96. for f in result[0]:
  97. utils.log( " %s" % f )
  98. utils.log( " Obsolete files:" )
  99. for f in result[1]:
  100. utils.log( " %s" % f )
  101. return result
  102. def _modtime_timestamp( file ):
  103. return os.stat( file ).st_mtime
  104. root_paths = []
  105. def shorten( file_path ):
  106. root_paths.sort( lambda x, y: cmp( len(y ), len( x ) ) )
  107. for root in root_paths:
  108. if file_path.lower().startswith( root.lower() ):
  109. return file_path[ len( root ): ].replace( "\\", "/" )
  110. return file_path.replace( "\\", "/" )
  111. class action:
  112. def __init__( self, file_path ):
  113. self.file_path_ = file_path
  114. self.relevant_paths_ = [ self.file_path_ ]
  115. self.boost_paths_ = []
  116. self.dependencies_ = []
  117. self.other_results_ = []
  118. def run( self ):
  119. utils.log( "%s: run" % shorten( self.file_path_ ) )
  120. __log__ = 2
  121. for dependency in self.dependencies_:
  122. if not os.path.exists( dependency ):
  123. utils.log( "%s doesn't exists, removing target" % shorten( dependency ) )
  124. self.clean()
  125. return
  126. if not os.path.exists( self.file_path_ ):
  127. utils.log( "target doesn't exists, building" )
  128. self.update()
  129. return
  130. dst_timestamp = _modtime_timestamp( self.file_path_ )
  131. utils.log( " target: %s [%s]" % ( shorten( self.file_path_ ), dst_timestamp ) )
  132. needs_updating = 0
  133. utils.log( " dependencies:" )
  134. for dependency in self.dependencies_:
  135. dm = _modtime_timestamp( dependency )
  136. update_mark = ""
  137. if dm > dst_timestamp:
  138. needs_updating = 1
  139. utils.log( ' %s [%s] %s' % ( shorten( dependency ), dm, update_mark ) )
  140. if needs_updating:
  141. utils.log( "target needs updating, rebuilding" )
  142. self.update()
  143. return
  144. else:
  145. utils.log( "target is up-to-date" )
  146. def clean( self ):
  147. to_unlink = self.other_results_ + [ self.file_path_ ]
  148. for result in to_unlink:
  149. utils.log( ' Deleting obsolete "%s"' % shorten( result ) )
  150. if os.path.exists( result ):
  151. os.unlink( result )
  152. class merge_xml_action( action ):
  153. def __init__( self, source, destination, expected_results_file, failures_markup_file, tag ):
  154. action.__init__( self, destination )
  155. self.source_ = source
  156. self.destination_ = destination
  157. self.tag_ = tag
  158. self.expected_results_file_ = expected_results_file
  159. self.failures_markup_file_ = failures_markup_file
  160. self.dependencies_.extend( [
  161. self.source_
  162. , self.expected_results_file_
  163. , self.failures_markup_file_
  164. ]
  165. )
  166. self.relevant_paths_.extend( [ self.source_ ] )
  167. self.boost_paths_.extend( [ self.expected_results_file_, self.failures_markup_file_ ] )
  168. def update( self ):
  169. def filter_xml( src, dest ):
  170. class xmlgen( xml.sax.saxutils.XMLGenerator ):
  171. def __init__( self, writer ):
  172. xml.sax.saxutils.XMLGenerator.__init__( self, writer )
  173. self.trimmed = 0
  174. self.character_content = ""
  175. def startElement( self, name, attrs):
  176. self.flush()
  177. xml.sax.saxutils.XMLGenerator.startElement( self, name, attrs )
  178. def endElement( self, name ):
  179. self.flush()
  180. xml.sax.saxutils.XMLGenerator.endElement( self, name )
  181. def flush( self ):
  182. content = self.character_content
  183. self.character_content = ""
  184. self.trimmed = 0
  185. xml.sax.saxutils.XMLGenerator.characters( self, content )
  186. def characters( self, content ):
  187. if not self.trimmed:
  188. max_size = pow( 2, 16 )
  189. self.character_content += content
  190. if len( self.character_content ) > max_size:
  191. self.character_content = self.character_content[ : max_size ] + "...\n\n[The content has been trimmed by the report system because it exceeds %d bytes]" % max_size
  192. self.trimmed = 1
  193. o = open( dest, "w" )
  194. try:
  195. gen = xmlgen( o )
  196. xml.sax.parse( src, gen )
  197. finally:
  198. o.close()
  199. return dest
  200. utils.log( 'Merging "%s" with expected results...' % shorten( self.source_ ) )
  201. try:
  202. trimmed_source = filter_xml( self.source_, '%s-trimmed.xml' % os.path.splitext( self.source_ )[0] )
  203. utils.libxslt(
  204. utils.log
  205. , trimmed_source
  206. , xsl_path( 'add_expected_results.xsl' )
  207. , self.file_path_
  208. , {
  209. "expected_results_file" : self.expected_results_file_
  210. , "failures_markup_file": self.failures_markup_file_
  211. , "source" : self.tag_
  212. }
  213. )
  214. os.unlink( trimmed_source )
  215. except Exception, msg:
  216. utils.log( ' Skipping "%s" due to errors (%s)' % ( self.source_, msg ) )
  217. if os.path.exists( self.file_path_ ):
  218. os.unlink( self.file_path_ )
  219. def _xml_timestamp( xml_path ):
  220. class timestamp_reader( xml.sax.handler.ContentHandler ):
  221. def startElement( self, name, attrs ):
  222. if name == 'test-run':
  223. self.timestamp = attrs.getValue( 'timestamp' )
  224. raise self
  225. try:
  226. xml.sax.parse( xml_path, timestamp_reader() )
  227. raise 'Cannot extract timestamp from "%s". Invalid XML file format?' % xml_path
  228. except timestamp_reader, x:
  229. return x.timestamp
  230. class make_links_action( action ):
  231. def __init__( self, source, destination, output_dir, tag, run_date, comment_file, failures_markup_file ):
  232. action.__init__( self, destination )
  233. self.dependencies_.append( source )
  234. self.source_ = source
  235. self.output_dir_ = output_dir
  236. self.tag_ = tag
  237. self.run_date_ = run_date
  238. self.comment_file_ = comment_file
  239. self.failures_markup_file_ = failures_markup_file
  240. self.links_file_path_ = os.path.join( output_dir, 'links.html' )
  241. def update( self ):
  242. utils.makedirs( os.path.join( os.path.dirname( self.links_file_path_ ), "output" ) )
  243. utils.makedirs( os.path.join( os.path.dirname( self.links_file_path_ ), "developer", "output" ) )
  244. utils.makedirs( os.path.join( os.path.dirname( self.links_file_path_ ), "user", "output" ) )
  245. utils.log( ' Making test output files...' )
  246. try:
  247. utils.libxslt(
  248. utils.log
  249. , self.source_
  250. , xsl_path( 'links_page.xsl' )
  251. , self.links_file_path_
  252. , {
  253. 'source': self.tag_
  254. , 'run_date': self.run_date_
  255. , 'comment_file': self.comment_file_
  256. , 'explicit_markup_file': self.failures_markup_file_
  257. }
  258. )
  259. except Exception, msg:
  260. utils.log( ' Skipping "%s" due to errors (%s)' % ( self.source_, msg ) )
  261. open( self.file_path_, "w" ).close()
  262. class unzip_action( action ):
  263. def __init__( self, source, destination, unzip_func ):
  264. action.__init__( self, destination )
  265. self.dependencies_.append( source )
  266. self.source_ = source
  267. self.unzip_func_ = unzip_func
  268. def update( self ):
  269. try:
  270. utils.log( ' Unzipping "%s" ... into "%s"' % ( shorten( self.source_ ), os.path.dirname( self.file_path_ ) ) )
  271. self.unzip_func_( self.source_, os.path.dirname( self.file_path_ ) )
  272. except Exception, msg:
  273. utils.log( ' Skipping "%s" due to errors (%s)' % ( self.source_, msg ) )
  274. def ftp_task( site, site_path , destination ):
  275. __log__ = 1
  276. utils.log( '' )
  277. utils.log( 'ftp_task: "ftp://%s/%s" -> %s' % ( site, site_path, destination ) )
  278. utils.log( ' logging on ftp site %s' % site )
  279. f = ftplib.FTP( site )
  280. f.login()
  281. utils.log( ' cwd to "%s"' % site_path )
  282. f.cwd( site_path )
  283. source_content = list_ftp( f )
  284. source_content = [ x for x in source_content if re.match( r'.+[.](?<!log[.])zip', x.name ) and x.name.lower() != 'boostbook.zip' ]
  285. destination_content = list_dir( destination )
  286. d = diff( source_content, destination_content )
  287. def synchronize():
  288. for source in d[0]:
  289. utils.log( 'Copying "%s"' % source )
  290. result = open( os.path.join( destination, source ), 'wb' )
  291. f.retrbinary( 'RETR %s' % source, result.write )
  292. result.close()
  293. mod_date = find_by_name( source_content, source ).date
  294. m = time.mktime( mod_date )
  295. os.utime( os.path.join( destination, source ), ( m, m ) )
  296. for obsolete in d[1]:
  297. utils.log( 'Deleting "%s"' % obsolete )
  298. os.unlink( os.path.join( destination, obsolete ) )
  299. utils.log( " Synchronizing..." )
  300. __log__ = 2
  301. synchronize()
  302. f.quit()
  303. def unzip_archives_task( source_dir, processed_dir, unzip_func ):
  304. utils.log( '' )
  305. utils.log( 'unzip_archives_task: unpacking updated archives in "%s" into "%s"...' % ( source_dir, processed_dir ) )
  306. __log__ = 1
  307. target_files = [ os.path.join( processed_dir, os.path.basename( x.replace( ".zip", ".xml" ) ) ) for x in glob.glob( os.path.join( source_dir, "*.zip" ) ) ] + glob.glob( os.path.join( processed_dir, "*.xml" ) )
  308. actions = [ unzip_action( os.path.join( source_dir, os.path.basename( x.replace( ".xml", ".zip" ) ) ), x, unzip_func ) for x in target_files ]
  309. for a in actions:
  310. a.run()
  311. def merge_xmls_task( source_dir, processed_dir, merged_dir, expected_results_file, failures_markup_file, tag ):
  312. utils.log( '' )
  313. utils.log( 'merge_xmls_task: merging updated XMLs in "%s"...' % source_dir )
  314. __log__ = 1
  315. utils.makedirs( merged_dir )
  316. target_files = [ os.path.join( merged_dir, os.path.basename( x ) ) for x in glob.glob( os.path.join( processed_dir, "*.xml" ) ) ] + glob.glob( os.path.join( merged_dir, "*.xml" ) )
  317. actions = [ merge_xml_action( os.path.join( processed_dir, os.path.basename( x ) )
  318. , x
  319. , expected_results_file
  320. , failures_markup_file
  321. , tag ) for x in target_files ]
  322. for a in actions:
  323. a.run()
  324. def make_links_task( input_dir, output_dir, tag, run_date, comment_file, extended_test_results, failures_markup_file ):
  325. utils.log( '' )
  326. utils.log( 'make_links_task: make output files for test results in "%s"...' % input_dir )
  327. __log__ = 1
  328. target_files = [ x + ".links" for x in glob.glob( os.path.join( input_dir, "*.xml" ) ) ] + glob.glob( os.path.join( input_dir, "*.links" ) )
  329. actions = [ make_links_action( x.replace( ".links", "" )
  330. , x
  331. , output_dir
  332. , tag
  333. , run_date
  334. , comment_file
  335. , failures_markup_file
  336. ) for x in target_files ]
  337. for a in actions:
  338. a.run()
  339. class xmlgen( xml.sax.saxutils.XMLGenerator ):
  340. document_started = 0
  341. def startDocument( self ):
  342. if not self.document_started:
  343. xml.sax.saxutils.XMLGenerator.startDocument( self )
  344. self.document_started = 1
  345. def merge_processed_test_runs( test_runs_dir, tag, writer ):
  346. utils.log( '' )
  347. utils.log( 'merge_processed_test_runs: merging processed test runs from %s into a single XML...' % test_runs_dir )
  348. __log__ = 1
  349. all_runs_xml = xmlgen( writer, encoding='utf-8' )
  350. all_runs_xml.startDocument()
  351. all_runs_xml.startElement( 'all-test-runs', {} )
  352. files = glob.glob( os.path.join( test_runs_dir, '*.xml' ) )
  353. for test_run in files:
  354. #file_pos = writer.stream.tell()
  355. file_pos = writer.tell()
  356. try:
  357. utils.log( ' Writing "%s" into the resulting XML...' % test_run )
  358. xml.sax.parse( test_run, all_runs_xml )
  359. except Exception, msg:
  360. utils.log( ' Skipping "%s" due to errors (%s)' % ( test_run, msg ) )
  361. #writer.stream.seek( file_pos )
  362. #writer.stream.truncate()
  363. writer.seek( file_pos )
  364. writer.truncate()
  365. all_runs_xml.endElement( 'all-test-runs' )
  366. all_runs_xml.endDocument()
  367. def execute_tasks(
  368. tag
  369. , user
  370. , run_date
  371. , comment_file
  372. , results_dir
  373. , output_dir
  374. , reports
  375. , warnings
  376. , extended_test_results
  377. , dont_collect_logs
  378. , expected_results_file
  379. , failures_markup_file
  380. ):
  381. incoming_dir = os.path.join( results_dir, 'incoming', tag )
  382. processed_dir = os.path.join( incoming_dir, 'processed' )
  383. merged_dir = os.path.join( processed_dir, 'merged' )
  384. if not os.path.exists( incoming_dir ):
  385. os.makedirs( incoming_dir )
  386. if not os.path.exists( processed_dir ):
  387. os.makedirs( processed_dir )
  388. if not os.path.exists( merged_dir ):
  389. os.makedirs( merged_dir )
  390. if not dont_collect_logs:
  391. ftp_site = 'boost.cowic.de'
  392. site_path = '/boost/do-not-publish-this-url/results/%s' % tag
  393. ftp_task( ftp_site, site_path, incoming_dir )
  394. unzip_archives_task( incoming_dir, processed_dir, utils.unzip )
  395. merge_xmls_task( incoming_dir, processed_dir, merged_dir, expected_results_file, failures_markup_file, tag )
  396. make_links_task( merged_dir
  397. , output_dir
  398. , tag
  399. , run_date
  400. , comment_file
  401. , extended_test_results
  402. , failures_markup_file )
  403. results_xml_path = os.path.join( output_dir, 'extended_test_results.xml' )
  404. #writer = codecs.open( results_xml_path, 'w', 'utf-8' )
  405. writer = open( results_xml_path, 'w' )
  406. merge_processed_test_runs( merged_dir, tag, writer )
  407. writer.close()
  408. make_result_pages(
  409. extended_test_results
  410. , expected_results_file
  411. , failures_markup_file
  412. , tag
  413. , run_date
  414. , comment_file
  415. , output_dir
  416. , reports
  417. , warnings
  418. )
  419. def make_result_pages(
  420. extended_test_results
  421. , expected_results_file
  422. , failures_markup_file
  423. , tag
  424. , run_date
  425. , comment_file
  426. , output_dir
  427. , reports
  428. , warnings
  429. ):
  430. utils.log( 'Producing the reports...' )
  431. __log__ = 1
  432. warnings_text = '+'.join( warnings )
  433. if comment_file != '':
  434. comment_file = os.path.abspath( comment_file )
  435. links = os.path.join( output_dir, 'links.html' )
  436. utils.makedirs( os.path.join( output_dir, 'output' ) )
  437. for mode in ( 'developer', 'user' ):
  438. utils.makedirs( os.path.join( output_dir, mode , 'output' ) )
  439. issues = os.path.join( output_dir, 'developer', 'issues.html' )
  440. if 'i' in reports:
  441. utils.log( ' Making issues list...' )
  442. utils.libxslt(
  443. utils.log
  444. , extended_test_results
  445. , xsl_path( 'issues_page.xsl' )
  446. , issues
  447. , {
  448. 'source': tag
  449. , 'run_date': run_date
  450. , 'warnings': warnings_text
  451. , 'comment_file': comment_file
  452. , 'expected_results_file': expected_results_file
  453. , 'explicit_markup_file': failures_markup_file
  454. , 'release': "yes"
  455. }
  456. )
  457. for mode in ( 'developer', 'user' ):
  458. if mode[0] + 'd' in reports:
  459. utils.log( ' Making detailed %s report...' % mode )
  460. utils.libxslt(
  461. utils.log
  462. , extended_test_results
  463. , xsl_path( 'result_page.xsl' )
  464. , os.path.join( output_dir, mode, 'index.html' )
  465. , {
  466. 'links_file': 'links.html'
  467. , 'mode': mode
  468. , 'source': tag
  469. , 'run_date': run_date
  470. , 'warnings': warnings_text
  471. , 'comment_file': comment_file
  472. , 'expected_results_file': expected_results_file
  473. , 'explicit_markup_file' : failures_markup_file
  474. }
  475. )
  476. for mode in ( 'developer', 'user' ):
  477. if mode[0] + 's' in reports:
  478. utils.log( ' Making summary %s report...' % mode )
  479. utils.libxslt(
  480. utils.log
  481. , extended_test_results
  482. , xsl_path( 'summary_page.xsl' )
  483. , os.path.join( output_dir, mode, 'summary.html' )
  484. , {
  485. 'mode' : mode
  486. , 'source': tag
  487. , 'run_date': run_date
  488. , 'warnings': warnings_text
  489. , 'comment_file': comment_file
  490. , 'explicit_markup_file' : failures_markup_file
  491. }
  492. )
  493. for mode in ( 'developer', 'user' ):
  494. if mode[0] + 'dr' in reports:
  495. utils.log( ' Making detailed %s release report...' % mode )
  496. utils.libxslt(
  497. utils.log
  498. , extended_test_results
  499. , xsl_path( 'result_page.xsl' )
  500. , os.path.join( output_dir, mode, 'index_release.html' )
  501. , {
  502. 'links_file': 'links.html'
  503. , 'mode': mode
  504. , 'source': tag
  505. , 'run_date': run_date
  506. , 'warnings': warnings_text
  507. , 'comment_file': comment_file
  508. , 'expected_results_file': expected_results_file
  509. , 'explicit_markup_file' : failures_markup_file
  510. , 'release': "yes"
  511. }
  512. )
  513. for mode in ( 'developer', 'user' ):
  514. if mode[0] + 'sr' in reports:
  515. utils.log( ' Making summary %s release report...' % mode )
  516. utils.libxslt(
  517. utils.log
  518. , extended_test_results
  519. , xsl_path( 'summary_page.xsl' )
  520. , os.path.join( output_dir, mode, 'summary_release.html' )
  521. , {
  522. 'mode' : mode
  523. , 'source': tag
  524. , 'run_date': run_date
  525. , 'warnings': warnings_text
  526. , 'comment_file': comment_file
  527. , 'explicit_markup_file' : failures_markup_file
  528. , 'release': 'yes'
  529. }
  530. )
  531. if 'e' in reports:
  532. utils.log( ' Generating expected_results ...' )
  533. utils.libxslt(
  534. utils.log
  535. , extended_test_results
  536. , xsl_path( 'produce_expected_results.xsl' )
  537. , os.path.join( output_dir, 'expected_results.xml' )
  538. )
  539. if 'n' in reports:
  540. utils.log( ' Making runner comment files...' )
  541. utils.libxslt(
  542. utils.log
  543. , extended_test_results
  544. , xsl_path( 'runners.xsl' )
  545. , os.path.join( output_dir, 'runners.html' )
  546. )
  547. shutil.copyfile(
  548. xsl_path( 'html/master.css' )
  549. , os.path.join( output_dir, 'master.css' )
  550. )
  551. fix_file_names( output_dir )
  552. def fix_file_names( dir ):
  553. """
  554. The current version of xslproc doesn't correctly handle
  555. spaces. We have to manually go through the
  556. result set and decode encoded spaces (%20).
  557. """
  558. utils.log( 'Fixing encoded file names...' )
  559. for root, dirs, files in os.walk( dir ):
  560. for file in files:
  561. if file.find( "%20" ) > -1:
  562. new_name = file.replace( "%20", " " )
  563. utils.rename(
  564. utils.log
  565. , os.path.join( root, file )
  566. , os.path.join( root, new_name )
  567. )
  568. def build_xsl_reports(
  569. locate_root_dir
  570. , tag
  571. , expected_results_file
  572. , failures_markup_file
  573. , comment_file
  574. , results_dir
  575. , result_file_prefix
  576. , dont_collect_logs = 0
  577. , reports = report_types
  578. , warnings = []
  579. , user = None
  580. , upload = False
  581. ):
  582. ( run_date ) = time.strftime( '%Y-%m-%dT%H:%M:%SZ', time.gmtime() )
  583. root_paths.append( locate_root_dir )
  584. root_paths.append( results_dir )
  585. bin_boost_dir = os.path.join( locate_root_dir, 'bin', 'boost' )
  586. output_dir = os.path.join( results_dir, result_file_prefix )
  587. utils.makedirs( output_dir )
  588. if expected_results_file != '':
  589. expected_results_file = os.path.abspath( expected_results_file )
  590. else:
  591. expected_results_file = os.path.abspath( map_path( 'empty_expected_results.xml' ) )
  592. extended_test_results = os.path.join( output_dir, 'extended_test_results.xml' )
  593. execute_tasks(
  594. tag
  595. , user
  596. , run_date
  597. , comment_file
  598. , results_dir
  599. , output_dir
  600. , reports
  601. , warnings
  602. , extended_test_results
  603. , dont_collect_logs
  604. , expected_results_file
  605. , failures_markup_file
  606. )
  607. if upload:
  608. upload_dir = 'regression-logs/'
  609. utils.log( 'Uploading results into "%s" [connecting as %s]...' % ( upload_dir, user ) )
  610. archive_name = '%s.tar.gz' % result_file_prefix
  611. utils.tar(
  612. os.path.join( results_dir, result_file_prefix )
  613. , archive_name
  614. )
  615. utils.sourceforge.upload( os.path.join( results_dir, archive_name ), upload_dir, user )
  616. utils.sourceforge.untar( os.path.join( upload_dir, archive_name ), user, background = True )
  617. def accept_args( args ):
  618. args_spec = [
  619. 'locate-root='
  620. , 'tag='
  621. , 'expected-results='
  622. , 'failures-markup='
  623. , 'comment='
  624. , 'results-dir='
  625. , 'results-prefix='
  626. , 'dont-collect-logs'
  627. , 'reports='
  628. , 'user='
  629. , 'upload'
  630. , 'help'
  631. ]
  632. options = {
  633. '--comment': ''
  634. , '--expected-results': ''
  635. , '--failures-markup': ''
  636. , '--reports': string.join( report_types, ',' )
  637. , '--tag': None
  638. , '--user': None
  639. , 'upload': False
  640. }
  641. utils.accept_args( args_spec, args, options, usage )
  642. if not options.has_key( '--results-dir' ):
  643. options[ '--results-dir' ] = options[ '--locate-root' ]
  644. if not options.has_key( '--results-prefix' ):
  645. options[ '--results-prefix' ] = 'all'
  646. return (
  647. options[ '--locate-root' ]
  648. , options[ '--tag' ]
  649. , options[ '--expected-results' ]
  650. , options[ '--failures-markup' ]
  651. , options[ '--comment' ]
  652. , options[ '--results-dir' ]
  653. , options[ '--results-prefix' ]
  654. , options.has_key( '--dont-collect-logs' )
  655. , options[ '--reports' ].split( ',' )
  656. , options[ '--user' ]
  657. , options.has_key( '--upload' )
  658. )
  659. def usage():
  660. print 'Usage: %s [options]' % os.path.basename( sys.argv[0] )
  661. print '''
  662. \t--locate-root the same as --locate-root in compiler_status
  663. \t--tag the tag for the results (i.e. 'trunk')
  664. \t--expected-results the file with the results to be compared with
  665. \t the current run
  666. \t--failures-markup the file with the failures markup
  667. \t--comment an html comment file (will be inserted in the reports)
  668. \t--results-dir the directory containing -links.html, -fail.html
  669. \t files produced by compiler_status (by default the
  670. \t same as specified in --locate-root)
  671. \t--results-prefix the prefix of -links.html, -fail.html
  672. \t files produced by compiler_status
  673. \t--user SourceForge user name for a shell account
  674. \t--upload upload reports to SourceForge
  675. The following options are useful in debugging:
  676. \t--dont-collect-logs dont collect the test logs
  677. \t--reports produce only the specified reports
  678. \t us - user summary
  679. \t ds - developer summary
  680. \t ud - user detailed
  681. \t dd - developer detailed
  682. \t l - links
  683. \t p - patches
  684. \t x - extended results file
  685. \t i - issues
  686. \t n - runner comment files
  687. '''
  688. def main():
  689. build_xsl_reports( *accept_args( sys.argv[ 1 : ] ) )
  690. if __name__ == '__main__':
  691. main()
粤ICP备19079148号