regression.py 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893
  1. #!/usr/bin/python
  2. # Copyright MetaCommunications, Inc. 2003-2007
  3. # Copyright Redshift Software, Inc. 2007
  4. #
  5. # Distributed under the Boost Software License, Version 1.0.
  6. # (See accompanying file LICENSE_1_0.txt or copy at
  7. # http://www.boost.org/LICENSE_1_0.txt)
  8. import glob
  9. import optparse
  10. import os
  11. import os.path
  12. import platform
  13. import sys
  14. import time
  15. #~ Place holder for xsl_reports/util module
  16. utils = None
  17. repo_root = {
  18. 'anon' : 'http://svn.boost.org/svn/boost/',
  19. 'user' : 'https://svn.boost.org/svn/boost/'
  20. }
  21. repo_path = {
  22. 'trunk' : 'trunk',
  23. 'release' : 'branches/release',
  24. 'build' : 'trunk/tools/build/v2',
  25. 'jam' : 'tags/tools/jam/Boost_Jam_3_1_17/src',
  26. 'regression' : 'trunk/tools/regression',
  27. 'boost-build.jam'
  28. : 'trunk/boost-build.jam'
  29. }
  30. class runner:
  31. def __init__(self,root):
  32. commands = map(
  33. lambda m: m[8:].replace('_','-'),
  34. filter(
  35. lambda m: m.startswith('command_'),
  36. runner.__dict__.keys())
  37. )
  38. commands.sort()
  39. commands = "commands: %s" % ', '.join(commands)
  40. opt = optparse.OptionParser(
  41. usage="%prog [options] [commands]",
  42. description=commands)
  43. #~ Base Options:
  44. opt.add_option( '--runner',
  45. help="runner ID (e.g. 'Metacomm')" )
  46. opt.add_option( '--comment',
  47. help="an HTML comment file to be inserted in the reports" )
  48. opt.add_option( '--tag',
  49. help="the tag for the results" )
  50. opt.add_option( '--toolsets',
  51. help="comma-separated list of toolsets to test with" )
  52. opt.add_option( '--incremental',
  53. help="do incremental run (do not remove previous binaries)",
  54. action='store_true' )
  55. opt.add_option( '--timeout',
  56. help="specifies the timeout, in minutes, for a single test run/compilation",
  57. type='int' )
  58. opt.add_option( '--bjam-options',
  59. help="options to pass to the regression test" )
  60. opt.add_option( '--bjam-toolset',
  61. help="bootstrap toolset for 'bjam' executable" )
  62. opt.add_option( '--pjl-toolset',
  63. help="bootstrap toolset for 'process_jam_log' executable" )
  64. opt.add_option( '--platform' )
  65. #~ Source Options:
  66. opt.add_option( '--user',
  67. help="Boost SVN user ID" )
  68. opt.add_option( '--local',
  69. help="the name of the boost tarball" )
  70. opt.add_option( '--force-update',
  71. help="do an SVN update (if applicable) instead of a clean checkout, even when performing a full run",
  72. action='store_true' )
  73. opt.add_option( '--have-source',
  74. help="do neither a tarball download nor an SVN update; used primarily for testing script changes",
  75. action='store_true' )
  76. #~ Connection Options:
  77. opt.add_option( '--ftp',
  78. help="FTP URL to upload results to." )
  79. opt.add_option( '--proxy',
  80. help="HTTP proxy server address and port (e.g.'http://www.someproxy.com:3128')" )
  81. opt.add_option( '--ftp-proxy',
  82. help="FTP proxy server (e.g. 'ftpproxy')" )
  83. opt.add_option( '--dart-server',
  84. help="the dart server to send results to" )
  85. #~ Debug Options:
  86. opt.add_option( '--debug-level',
  87. help="debugging level; controls the amount of debugging output printed",
  88. type='int' )
  89. opt.add_option( '--send-bjam-log',
  90. help="send full bjam log of the regression run",
  91. action='store_true' )
  92. opt.add_option( '--mail',
  93. help="email address to send run notification to" )
  94. opt.add_option( '--smtp-login',
  95. help="STMP server address/login information, in the following form: <user>:<password>@<host>[:<port>]" )
  96. opt.add_option( '--skip-tests',
  97. help="do not run bjam; used for testing script changes",
  98. action='store_true' )
  99. #~ Defaults
  100. self.runner = None
  101. self.comment='comment.html'
  102. self.tag='trunk'
  103. self.toolsets=None
  104. self.incremental=False
  105. self.timeout=5
  106. self.bjam_options=''
  107. self.bjam_toolset=''
  108. self.pjl_toolset=''
  109. self.platform=self.platform_name()
  110. self.user='anonymous'
  111. self.local=None
  112. self.force_update=False
  113. self.have_source=False
  114. self.ftp=None
  115. self.proxy=None
  116. self.ftp_proxy=None
  117. self.dart_server=None
  118. self.debug_level=0
  119. self.send_bjam_log=False
  120. self.mail=None
  121. self.smtp_login=None
  122. self.skip_tests=False
  123. ( _opt_, self.actions ) = opt.parse_args(None,self)
  124. if not self.actions or self.actions == []:
  125. self.actions = [ 'regression' ]
  126. #~ Initialize option dependent values.
  127. self.regression_root = root
  128. self.boost_root = os.path.join( self.regression_root, 'boost' )
  129. self.regression_results = os.path.join( self.regression_root, 'results' )
  130. if self.pjl_toolset != 'python':
  131. self.regression_log = os.path.join( self.regression_results, 'bjam.log' )
  132. else:
  133. self.regression_log = os.path.join( self.regression_results, 'bjam.xml' )
  134. self.tools_bb_root = os.path.join( self.regression_root,'tools_bb' )
  135. self.tools_bjam_root = os.path.join( self.regression_root,'tools_bjam' )
  136. self.tools_regression_root = os.path.join( self.regression_root,'tools_regression' )
  137. self.xsl_reports_dir = os.path.join( self.tools_regression_root, 'xsl_reports' )
  138. self.timestamp_path = os.path.join( self.regression_root, 'timestamp' )
  139. if sys.platform == 'win32':
  140. self.patch_boost = 'patch_boost.bat'
  141. self.bjam = { 'name' : 'bjam.exe' }
  142. self.process_jam_log = { 'name' : 'process_jam_log.exe' }
  143. elif sys.platform == 'cygwin':
  144. self.patch_boost = 'patch_boost'
  145. self.bjam = { 'name' : 'bjam.exe' }
  146. self.process_jam_log = { 'name' : 'process_jam_log.exe' }
  147. else:
  148. self.patch_boost = 'patch_boost'
  149. self.bjam = { 'name' : 'bjam' }
  150. self.process_jam_log = { 'name' : 'process_jam_log' }
  151. self.bjam = {
  152. 'name' : self.bjam['name'],
  153. 'build_cmd' : self.bjam_build_cmd,
  154. 'path' : os.path.join(self.regression_root,self.bjam['name']),
  155. 'source_dir' : self.tools_bjam_root,
  156. 'build_dir' : self.tools_bjam_root,
  157. 'build_args' : ''
  158. }
  159. self.process_jam_log = {
  160. 'name' : self.process_jam_log['name'],
  161. 'build_cmd' : self.bjam_cmd,
  162. 'path' : os.path.join(self.regression_root,self.process_jam_log['name']),
  163. 'source_dir' : os.path.join(self.tools_regression_root,'build'),
  164. 'build_dir' : os.path.join(self.tools_regression_root,'build'),
  165. 'build_args' : 'process_jam_log -d2'
  166. }
  167. if self.debug_level > 0:
  168. self.log('Regression root = %s'%self.regression_root)
  169. self.log('Boost root = %s'%self.boost_root)
  170. self.log('Regression results = %s'%self.regression_results)
  171. self.log('Regression log = %s'%self.regression_log)
  172. self.log('BB root = %s'%self.tools_bb_root)
  173. self.log('Bjam root = %s'%self.tools_bjam_root)
  174. self.log('Tools root = %s'%self.tools_regression_root)
  175. self.log('XSL reports dir = %s'%self.xsl_reports_dir)
  176. self.log('Timestamp = %s'%self.timestamp_path)
  177. self.log('Patch Boost script = %s'%self.patch_boost)
  178. self.main()
  179. #~ The various commands that make up the testing sequence...
  180. def command_cleanup(self,*args):
  181. if not args or args == None or args == []: args = [ 'source', 'bin' ]
  182. if 'source' in args:
  183. self.log( 'Cleaning up "%s" directory ...' % self.boost_root )
  184. self.rmtree( self.boost_root )
  185. if 'bin' in args:
  186. boost_bin_dir = os.path.join( self.boost_root, 'bin' )
  187. self.log( 'Cleaning up "%s" directory ...' % boost_bin_dir )
  188. self.rmtree( boost_bin_dir )
  189. boost_binv2_dir = os.path.join( self.boost_root, 'bin.v2' )
  190. self.log( 'Cleaning up "%s" directory ...' % boost_binv2_dir )
  191. self.rmtree( boost_binv2_dir )
  192. self.log( 'Cleaning up "%s" directory ...' % self.regression_results )
  193. self.rmtree( self.regression_results )
  194. def command_get_tools(self):
  195. #~ Get Boost.Build v2...
  196. self.log( 'Getting Boost.Build v2...' )
  197. if self.user and self.user != '':
  198. os.chdir( os.path.dirname(self.tools_bb_root) )
  199. self.svn_command( 'co %s %s' % (
  200. self.svn_repository_url(repo_path['build']),
  201. os.path.basename(self.tools_bb_root) ) )
  202. else:
  203. self.retry( lambda: self.download_tarball(
  204. os.path.basename(self.tools_bb_root)+".tar.bz2",
  205. self.tarball_url(repo_path['build']) ) )
  206. self.unpack_tarball(
  207. self.tools_bb_root+".tar.bz2",
  208. os.path.basename(self.tools_bb_root) )
  209. #~ Get Boost.Jam...
  210. self.log( 'Getting Boost.Jam...' )
  211. if self.user and self.user != '':
  212. os.chdir( os.path.dirname(self.tools_bjam_root) )
  213. self.svn_command( 'co %s %s' % (
  214. self.svn_repository_url(repo_path['jam']),
  215. os.path.basename(self.tools_bjam_root) ) )
  216. else:
  217. self.retry( lambda: self.download_tarball(
  218. os.path.basename(self.tools_bjam_root)+".tar.bz2",
  219. self.tarball_url(repo_path['jam']) ) )
  220. self.unpack_tarball(
  221. self.tools_bjam_root+".tar.bz2",
  222. os.path.basename(self.tools_bjam_root) )
  223. #~ Get the regression tools and utilities...
  224. self.log( 'Getting regression tools an utilities...' )
  225. if self.user and self.user != '':
  226. os.chdir( os.path.dirname(self.tools_regression_root) )
  227. self.svn_command( 'co %s %s' % (
  228. self.svn_repository_url(repo_path['regression']),
  229. os.path.basename(self.tools_regression_root) ) )
  230. else:
  231. self.retry( lambda: self.download_tarball(
  232. os.path.basename(self.tools_regression_root)+".tar.bz2",
  233. self.tarball_url(repo_path['regression']) ) )
  234. self.unpack_tarball(
  235. self.tools_regression_root+".tar.bz2",
  236. os.path.basename(self.tools_regression_root) )
  237. #~ We get a boost-build.jam to make the tool build work even if there's
  238. #~ and existing boost-build.jam above the testing root.
  239. self.log( 'Getting boost-build.jam...' )
  240. self.http_get(
  241. self.svn_repository_url(repo_path['boost-build.jam']),
  242. os.path.join( self.regression_root, 'boost-build.jam' ) )
  243. def command_get_source(self):
  244. self.refresh_timestamp()
  245. self.log( 'Getting sources (%s)...' % self.timestamp() )
  246. if self.user and self.user != '':
  247. self.retry( self.svn_checkout )
  248. else:
  249. self.retry( self.get_tarball )
  250. pass
  251. def command_update_source(self):
  252. if self.user and self.user != '' \
  253. or os.path.exists( os.path.join( self.boost_root, '.svn' ) ):
  254. open( self.timestamp_path, 'w' ).close()
  255. self.log( 'Updating sources from SVN (%s)...' % self.timestamp() )
  256. self.retry( self.svn_update )
  257. else:
  258. self.command_get_source( )
  259. pass
  260. def command_patch(self):
  261. self.import_utils()
  262. patch_boost_path = os.path.join( self.regression_root, self.patch_boost )
  263. if os.path.exists( patch_boost_path ):
  264. self.log( 'Found patch file "%s". Executing it.' % patch_boost_path )
  265. os.chdir( self.regression_root )
  266. utils.system( [ patch_boost_path ] )
  267. pass
  268. def command_setup(self):
  269. self.command_patch()
  270. self.build_if_needed(self.bjam,self.bjam_toolset)
  271. if self.pjl_toolset != 'python':
  272. self.build_if_needed(self.process_jam_log,self.pjl_toolset)
  273. def command_test(self, *args):
  274. if not args or args == None or args == []: args = [ "test", "process" ]
  275. self.import_utils()
  276. self.log( 'Making "%s" directory...' % self.regression_results )
  277. utils.makedirs( self.regression_results )
  278. results_libs = os.path.join( self.regression_results, 'libs' )
  279. results_status = os.path.join( self.regression_results, 'status' )
  280. if "clean" in args:
  281. self.command_test_clean()
  282. if "test" in args:
  283. self.command_test_run()
  284. self.command_test_boost_build()
  285. if "process" in args:
  286. if self.pjl_toolset != 'python':
  287. self.command_test_process()
  288. def command_test_clean(self):
  289. results_libs = os.path.join( self.regression_results, 'libs' )
  290. results_status = os.path.join( self.regression_results, 'status' )
  291. self.rmtree( results_libs )
  292. self.rmtree( results_status )
  293. def command_test_run(self):
  294. self.import_utils()
  295. if self.pjl_toolset != 'python':
  296. test_cmd = '%s -d2 preserve-test-targets=off --dump-tests %s "--build-dir=%s" >>"%s" 2>&1' % (
  297. self.bjam_cmd( self.toolsets ),
  298. self.bjam_options,
  299. self.regression_results,
  300. self.regression_log )
  301. else:
  302. test_cmd = '%s -d1 preserve-test-targets=off --dump-tests --verbose-test %s "--build-dir=%s" "--out-xml=%s"' % (
  303. self.bjam_cmd( self.toolsets ),
  304. self.bjam_options,
  305. self.regression_results,
  306. self.regression_log )
  307. self.log( 'Starting tests (%s)...' % test_cmd )
  308. cd = os.getcwd()
  309. os.chdir( os.path.join( self.boost_root, 'status' ) )
  310. utils.system( [ test_cmd ] )
  311. os.chdir( cd )
  312. def command_test_boost_build(self):
  313. self.import_utils()
  314. self.log( 'Running Boost.Build tests' )
  315. # Find the true names of the toolsets used for testing
  316. toolsets = os.listdir(os.path.join(self.regression_results,
  317. "boost/bin.v2/libs/any/test/any_test.test"));
  318. for t in toolsets:
  319. d = os.path.join(self.regression_results, ("boost-build-%s" % (t)))
  320. utils.makedirs (d)
  321. fn = os.path.join(d, "test_log.xml")
  322. cd = os.getcwd()
  323. try:
  324. os.chdir (os.path.join (self.boost_root, 'tools/build/v2/test'));
  325. bjam_path = os.path.dirname (self.tool_path( self.bjam ))
  326. self.log( "Using bjam binary in '%s'" % (bjam_path))
  327. os.putenv('PATH', bjam_path + os.pathsep + os.environ['PATH'])
  328. utils.system ( [ "%s test_all.py --verbose --default-bjam --xml %s > %s" % (sys.executable, t, fn) ] )
  329. finally:
  330. os.chdir( cd )
  331. def command_test_process(self):
  332. self.import_utils()
  333. self.log( 'Getting test case results out of "%s"...' % self.regression_log )
  334. cd = os.getcwd()
  335. os.chdir( os.path.join( self.boost_root, 'status' ) )
  336. utils.checked_system( [
  337. '"%s" "%s" <"%s"' % (
  338. self.tool_path(self.process_jam_log),
  339. self.regression_results,
  340. self.regression_log )
  341. ] )
  342. os.chdir( cd )
  343. def command_collect_logs(self):
  344. self.import_utils()
  345. comment_path = os.path.join( self.regression_root, self.comment )
  346. if not os.path.exists( comment_path ):
  347. self.log( 'Comment file "%s" not found; creating default comment.' % comment_path )
  348. f = open( comment_path, 'w' )
  349. f.write( '<p>Tests are run on %s platform.</p>' % self.platform_name() )
  350. f.close()
  351. source = 'tarball'
  352. revision = ''
  353. svn_root_file = os.path.join( self.boost_root, '.svn' )
  354. svn_info_file = os.path.join( self.boost_root, 'svn_info.txt' )
  355. if os.path.exists( svn_root_file ):
  356. source = 'SVN'
  357. self.svn_command( 'info --xml "%s" >"%s"' % (self.boost_root,svn_info_file) )
  358. if os.path.exists( svn_info_file ):
  359. f = open( svn_info_file, 'r' )
  360. svn_info = f.read()
  361. f.close()
  362. i = svn_info.find( 'Revision:' )
  363. if i < 0: i = svn_info.find( 'revision=' ) # --xml format
  364. if i >= 0:
  365. i += 10
  366. while svn_info[i] >= '0' and svn_info[i] <= '9':
  367. revision += svn_info[i]
  368. i += 1
  369. if self.pjl_toolset != 'python':
  370. from collect_and_upload_logs import collect_logs
  371. if self.incremental:
  372. run_type = 'incremental'
  373. else:
  374. run_type = 'full'
  375. collect_logs(
  376. self.regression_results,
  377. self.runner, self.tag, self.platform, comment_path,
  378. self.timestamp_path,
  379. self.user,
  380. source, run_type,
  381. self.dart_server, self.proxy,
  382. revision )
  383. else:
  384. from process_jam_log import BJamLog2Results
  385. if self.incremental:
  386. run_type = '--incremental'
  387. else:
  388. run_type = ''
  389. BJamLog2Results([
  390. '--output='+os.path.join(self.regression_results,self.runner+'.xml'),
  391. '--runner='+self.runner,
  392. '--comment='+comment_path,
  393. '--tag='+self.tag,
  394. '--platform='+self.platform,
  395. '--source='+source,
  396. '--revision='+revision,
  397. run_type,
  398. self.regression_log
  399. ])
  400. self.compress_file(
  401. os.path.join(self.regression_results,self.runner+'.xml'),
  402. os.path.join(self.regression_results,self.runner+'.zip')
  403. )
  404. def command_upload_logs(self):
  405. self.import_utils()
  406. from collect_and_upload_logs import upload_logs
  407. if self.ftp:
  408. self.retry(
  409. lambda:
  410. upload_logs(
  411. self.regression_results,
  412. self.runner, self.tag,
  413. self.user,
  414. self.ftp_proxy,
  415. self.debug_level, self.send_bjam_log,
  416. self.timestamp_path,
  417. self.dart_server,
  418. ftp_url = self.ftp )
  419. )
  420. else:
  421. self.retry(
  422. lambda:
  423. upload_logs(
  424. self.regression_results,
  425. self.runner, self.tag,
  426. self.user,
  427. self.ftp_proxy,
  428. self.debug_level, self.send_bjam_log,
  429. self.timestamp_path,
  430. self.dart_server )
  431. )
  432. def command_regression(self):
  433. import socket
  434. import string
  435. try:
  436. mail_subject = 'Boost regression for %s on %s' % ( self.tag,
  437. string.split(socket.gethostname(), '.')[0] )
  438. start_time = time.localtime()
  439. if self.mail:
  440. self.log( 'Sending start notification to "%s"' % self.mail )
  441. self.send_mail(
  442. '%s started at %s.' % ( mail_subject, format_time( start_time ) )
  443. )
  444. self.command_get_tools()
  445. if self.local is not None:
  446. self.log( 'Using local file "%s"' % self.local )
  447. b = os.path.basename( self.local )
  448. tag = b[ 0: b.find( '.' ) ]
  449. self.log( 'Tag: "%s"' % tag )
  450. self.unpack_tarball( self.local, self.boost_root )
  451. elif self.have_source:
  452. if not self.incremental: self.command_cleanup( [ 'bin' ] )
  453. else:
  454. if self.incremental or self.force_update:
  455. if not self.incremental: self.command_cleanup( [ 'bin' ] )
  456. else:
  457. self.command_cleanup()
  458. self.command_get_source()
  459. self.command_setup()
  460. # Not specifying --toolset in command line is not enough
  461. # that would mean to use Boost.Build default ones
  462. # We can skip test only we were explictly
  463. # told to have no toolsets in command line "--toolset="
  464. if self.toolsets != '': # --toolset=,
  465. if not self.skip_tests:
  466. self.command_test()
  467. self.command_collect_logs()
  468. self.command_upload_logs()
  469. if self.mail:
  470. self.log( 'Sending report to "%s"' % self.mail )
  471. end_time = time.localtime()
  472. self.send_mail(
  473. '%s completed successfully at %s.' % ( mail_subject, format_time( end_time ) )
  474. )
  475. except:
  476. if self.mail:
  477. self.log( 'Sending report to "%s"' % self.mail )
  478. traceback_ = '\n'.join( apply( traceback.format_exception, sys.exc_info() ) )
  479. end_time = time.localtime()
  480. self.send_mail(
  481. '%s failed at %s.' % ( mail_subject, format_time( end_time ) ),
  482. traceback_ )
  483. raise
  484. def command_show_revision(self):
  485. modified = '$Date$'
  486. revision = '$Revision$'
  487. import re
  488. re_keyword_value = re.compile( r'^\$\w+:\s+(.*)\s+\$$' )
  489. print '\n\tRevision: %s' % re_keyword_value.match( revision ).group( 1 )
  490. print '\tLast modified on: %s\n' % re_keyword_value.match( modified ).group( 1 )
  491. #~ Utilities...
  492. def main(self):
  493. for action in self.actions:
  494. action_m = "command_"+action.replace('-','_')
  495. if hasattr(self,action_m):
  496. getattr(self,action_m)()
  497. def platform_name(self):
  498. # See http://article.gmane.org/gmane.comp.lib.boost.testing/933
  499. if sys.platform == 'win32':
  500. return 'Windows'
  501. elif sys.platform == 'cygwin':
  502. return 'Windows/Cygwin'
  503. return platform.system()
  504. def log(self,message):
  505. sys.stdout.flush()
  506. sys.stderr.flush()
  507. sys.stderr.write( '# %s\n' % message )
  508. sys.stderr.flush()
  509. def rmtree(self,path):
  510. if os.path.exists( path ):
  511. import shutil
  512. #~ shutil.rmtree( unicode( path ) )
  513. if sys.platform == 'win32':
  514. os.system( 'del /f /s /q "%s" >nul 2>&1' % path )
  515. shutil.rmtree( unicode( path ) )
  516. else:
  517. os.system( 'rm -f -r "%s"' % path )
  518. def refresh_timestamp( self ):
  519. if os.path.exists( self.timestamp_path ):
  520. os.unlink( self.timestamp_path )
  521. open( self.timestamp_path, 'w' ).close()
  522. def timestamp( self ):
  523. return time.strftime(
  524. '%Y-%m-%dT%H:%M:%SZ',
  525. time.gmtime( os.stat( self.timestamp_path ).st_mtime ) )
  526. def retry( self, f, max_attempts=5, sleep_secs=10 ):
  527. for attempts in range( max_attempts, -1, -1 ):
  528. try:
  529. return f()
  530. except Exception, msg:
  531. self.log( '%s failed with message "%s"' % ( f.__name__, msg ) )
  532. if attempts == 0:
  533. self.log( 'Giving up.' )
  534. raise
  535. self.log( 'Retrying (%d more attempts).' % attempts )
  536. time.sleep( sleep_secs )
  537. def http_get( self, source_url, destination_file ):
  538. import urllib
  539. proxies = None
  540. if hasattr(self,'proxy') and self.proxy is not None:
  541. proxies = { 'http' : self.proxy }
  542. src = urllib.urlopen( source_url, proxies = proxies )
  543. f = open( destination_file, 'wb' )
  544. while True:
  545. data = src.read( 16*1024 )
  546. if len( data ) == 0: break
  547. f.write( data )
  548. f.close()
  549. src.close()
  550. def import_utils(self):
  551. global utils
  552. if utils is None:
  553. sys.path.append( self.xsl_reports_dir )
  554. import utils as utils_module
  555. utils = utils_module
  556. def build_if_needed( self, tool, toolset ):
  557. self.import_utils()
  558. if os.path.exists( tool[ 'path' ] ):
  559. self.log( 'Found preinstalled "%s"; will use it.' % tool[ 'path' ] )
  560. return
  561. self.log( 'Preinstalled "%s" is not found; building one...' % tool[ 'path' ] )
  562. if toolset is None:
  563. if self.toolsets is not None:
  564. toolset = string.split( self.toolsets, ',' )[0]
  565. else:
  566. toolset = tool[ 'default_toolset' ]
  567. self.log( 'Warning: No bootstrap toolset for "%s" was specified.' % tool[ 'name' ] )
  568. self.log( ' Using default toolset for the platform (%s).' % toolset )
  569. if os.path.exists( tool[ 'source_dir' ] ):
  570. self.log( 'Found "%s" source directory "%s"' % ( tool[ 'name' ], tool[ 'source_dir' ] ) )
  571. build_cmd = tool[ 'build_cmd' ]( toolset, tool['build_args'] )
  572. self.log( 'Building "%s" (%s)...' % ( tool[ 'name'], build_cmd ) )
  573. utils.system( [ 'cd "%s"' % tool[ 'source_dir' ], build_cmd ] )
  574. else:
  575. raise 'Could not find "%s" source directory "%s"' % ( tool[ 'name' ], tool[ 'source_dir' ] )
  576. if not tool.has_key( 'build_path' ):
  577. tool[ 'build_path' ] = self.tool_path( tool )
  578. if not os.path.exists( tool[ 'build_path' ] ):
  579. raise 'Failed to find "%s" after build.' % tool[ 'build_path' ]
  580. self.log( '%s succesfully built in "%s" location' % ( tool[ 'name' ], tool[ 'build_path' ] ) )
  581. def tool_path( self, name_or_spec ):
  582. if isinstance( name_or_spec, basestring ):
  583. return os.path.join( self.regression_root, name_or_spec )
  584. if os.path.exists( name_or_spec[ 'path' ] ):
  585. return name_or_spec[ 'path' ]
  586. if name_or_spec.has_key( 'build_path' ):
  587. return name_or_spec[ 'build_path' ]
  588. build_dir = name_or_spec[ 'build_dir' ]
  589. self.log( 'Searching for "%s" in "%s"...' % ( name_or_spec[ 'name' ], build_dir ) )
  590. for root, dirs, files in os.walk( build_dir ):
  591. if name_or_spec[ 'name' ] in files:
  592. return os.path.join( root, name_or_spec[ 'name' ] )
  593. raise Exception( 'Cannot find "%s" in any of the following locations:\n%s' % (
  594. name_or_spec[ 'name' ]
  595. , '\n'.join( [ name_or_spec[ 'path' ], build_dir ] )
  596. ) )
  597. def bjam_build_cmd( self, *rest ):
  598. if sys.platform == 'win32':
  599. cmd = 'build.bat %s' % self.bjam_toolset
  600. else:
  601. cmd = './build.sh %s' % self.bjam_toolset
  602. env_setup_key = 'BJAM_ENVIRONMENT_SETUP'
  603. if os.environ.has_key( env_setup_key ):
  604. return '%s & %s' % ( os.environ[env_setup_key], cmd )
  605. return cmd
  606. def bjam_cmd( self, toolsets, args = '', *rest ):
  607. build_path = self.regression_root
  608. if build_path[-1] == '\\': build_path += '\\'
  609. if self.timeout > 0:
  610. args += ' -l%s' % (self.timeout*60)
  611. cmd = '"%(bjam)s"' +\
  612. ' "-sBOOST_BUILD_PATH=%(bbpath)s"' +\
  613. ' "-sBOOST_ROOT=%(boost)s"' +\
  614. ' "--boost=%(boost)s"' +\
  615. ' "--boost-build=%(bb)s"' +\
  616. ' "--debug-configuration"' +\
  617. ' %(arg)s'
  618. cmd %= {
  619. 'bjam' : self.tool_path( self.bjam ),
  620. 'bbpath' : os.pathsep.join([build_path,self.tools_bb_root]),
  621. 'bb' : self.tools_bb_root,
  622. 'boost' : self.boost_root,
  623. 'arg' : args }
  624. if toolsets:
  625. import string
  626. cmd += ' ' + string.join(string.split( toolsets, ',' ), ' ' )
  627. return cmd
  628. def send_mail( self, subject, msg = '' ):
  629. import smtplib
  630. if not self.smtp_login:
  631. server_name = 'mail.%s' % mail.split( '@' )[-1]
  632. user_name = None
  633. password = None
  634. else:
  635. server_name = self.smtp_login.split( '@' )[-1]
  636. ( user_name, password ) = string.split( self.smtp_login.split( '@' )[0], ':' )
  637. log( ' Sending mail through "%s"...' % server_name )
  638. smtp_server = smtplib.SMTP( server_name )
  639. smtp_server.set_debuglevel( self.debug_level )
  640. if user_name:
  641. smtp_server.login( user_name, password )
  642. smtp_server.sendmail( self.mail, [ self.mail ],
  643. 'Subject: %s\nTo: %s\n\n%s' % ( subject, self.mail, msg ) )
  644. def compress_file( self, file_path, archive_path ):
  645. self.import_utils()
  646. utils.log( 'Compressing "%s"...' % file_path )
  647. try:
  648. import zipfile
  649. z = zipfile.ZipFile( archive_path, 'w', zipfile.ZIP_DEFLATED )
  650. z.write( file_path, os.path.basename( file_path ) )
  651. z.close()
  652. utils.log( 'Done writing "%s".'% archive_path )
  653. except Exception, msg:
  654. utils.log( 'Warning: Compressing falied (%s)' % msg )
  655. utils.log( ' Trying to compress using a platform-specific tool...' )
  656. try:
  657. import zip_cmd
  658. except ImportError:
  659. script_dir = os.path.dirname( os.path.abspath( sys.argv[0] ) )
  660. utils.log( 'Could not find \'zip_cmd\' module in the script directory (%s).' % script_dir )
  661. raise Exception( 'Compressing failed!' )
  662. else:
  663. if os.path.exists( archive_path ):
  664. os.unlink( archive_path )
  665. utils.log( 'Removing stale "%s".' % archive_path )
  666. zip_cmd.main( file_path, archive_path )
  667. utils.log( 'Done compressing "%s".' % archive_path )
  668. #~ Dowloading source, from SVN...
  669. def svn_checkout( self ):
  670. os.chdir( self.regression_root )
  671. self.svn_command( 'co %s %s' % (self.svn_repository_url(self.tag),'boost') )
  672. def svn_update( self ):
  673. os.chdir( self.boost_root )
  674. self.svn_command( 'update' )
  675. def svn_command( self, command ):
  676. svn_anonymous_command_line = 'svn --non-interactive %(command)s'
  677. svn_command_line = 'svn --non-interactive --username=%(user)s %(command)s'
  678. if not hasattr(self,'user') or self.user is None or self.user == 'anonymous':
  679. cmd = svn_anonymous_command_line % { 'command': command }
  680. else:
  681. cmd = svn_command_line % { 'user': self.user, 'command': command }
  682. self.log( 'Executing SVN command "%s"' % cmd )
  683. rc = os.system( cmd )
  684. if rc != 0:
  685. raise Exception( 'SVN command "%s" failed with code %d' % ( cmd, rc ) )
  686. def svn_repository_url( self, path ):
  687. if self.user != 'anonymous' and self.user != '':
  688. return '%s%s' % (repo_root['user'],path)
  689. else:
  690. return '%s%s' % (repo_root['anon'],path)
  691. #~ Downloading and extracting source archives, from tarballs or zipballs...
  692. def get_tarball( self, *args ):
  693. if not args or args == []:
  694. args = [ 'download', 'unpack' ]
  695. tarball_path = None
  696. if hasattr(self,'local') and self.local is not None:
  697. tarball_path = self.local
  698. elif 'download' in args:
  699. tarball_path = self.download_tarball(self.boost_tarball_name(),self.boost_tarball_url())
  700. if not tarball_path:
  701. tarball_path = os.path.join( self.regression_root, self.boost_tarball_url() )
  702. if 'unpack' in args:
  703. self.unpack_tarball( tarball_path, self.boost_root )
  704. pass
  705. def download_tarball( self, tarball_name, tarball_url ):
  706. tarball_path = os.path.join( self.regression_root, tarball_name )
  707. self.log( 'Downloading "%s" to "%s"...' % ( tarball_url, os.path.dirname( tarball_path ) ) )
  708. if os.path.exists( tarball_path ):
  709. os.unlink( tarball_path )
  710. self.http_get( tarball_url, tarball_path )
  711. return tarball_path
  712. def tarball_url( self, path ):
  713. return 'http://beta.boost.org/development/snapshot.php/%s' % path
  714. def boost_tarball_name( self ):
  715. return 'boost-%s.tar.bz2' % self.tag.split( '/' )[-1]
  716. def boost_tarball_url( self ):
  717. return self.tarball_url( self.tag )
  718. def unpack_tarball( self, tarball_path, target_path ):
  719. self.log( 'Looking for old unpacked archives...' )
  720. old_boost_dirs = self.find_boost_dirs( )
  721. for old_boost_dir in old_boost_dirs:
  722. if old_boost_dir != tarball_path:
  723. self.log( 'Deleting old directory %s.' % old_boost_dir )
  724. self.rmtree( old_boost_dir )
  725. self.log( 'Unpacking boost tarball ("%s")...' % tarball_path )
  726. tarball_name = os.path.basename( tarball_path )
  727. extension = tarball_name[ tarball_name.find( '.' ) : ]
  728. if extension in ( ".tar.gz", ".tar.bz2" ):
  729. import tarfile
  730. import stat
  731. mode = os.path.splitext( extension )[1][1:]
  732. tar = tarfile.open( tarball_path, 'r:%s' % mode )
  733. for tarinfo in tar:
  734. tar.extract( tarinfo, self.regression_root )
  735. if sys.platform == 'win32' and not tarinfo.isdir():
  736. # workaround what appears to be a Win32-specific bug in 'tarfile'
  737. # (modification times for extracted files are not set properly)
  738. f = os.path.join( self.regression_root, tarinfo.name )
  739. os.chmod( f, stat.S_IWRITE )
  740. os.utime( f, ( tarinfo.mtime, tarinfo.mtime ) )
  741. tar.close()
  742. elif extension in ( ".zip" ):
  743. import zipfile
  744. z = zipfile.ZipFile( tarball_path, 'r', zipfile.ZIP_DEFLATED )
  745. for f in z.infolist():
  746. destination_file_path = os.path.join( self.regression_root, f.filename )
  747. if destination_file_path[-1] == "/": # directory
  748. if not os.path.exists( destination_file_path ):
  749. os.makedirs( destination_file_path )
  750. else: # file
  751. result = open( destination_file_path, 'wb' )
  752. result.write( z.read( f.filename ) )
  753. result.close()
  754. z.close()
  755. else:
  756. raise 'Do not know how to unpack archives with extension \"%s\"' % extension
  757. boost_dir = self.find_boost_dirs()[0]
  758. self.log( ' Unpacked into directory "%s"' % boost_dir )
  759. if os.path.exists( target_path ):
  760. self.log( 'Deleting "%s" directory...' % target_path )
  761. self.rmtree( target_path )
  762. self.log( 'Renaming "%s" into "%s"' % ( boost_dir, target_path ) )
  763. os.rename( boost_dir, target_path )
  764. def find_boost_dirs( self ):
  765. return [
  766. x for x in
  767. glob.glob( os.path.join( self.regression_root, 'boost[-_]*' ) )
  768. if os.path.isdir( x )
  769. ]
粤ICP备19079148号