]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/predef/tools/ci/common.py
3 # Copyright Rene Rivera 2016
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)
22 'ppa' : ["ppa:h-rayflood/llvm"],
23 'package' : 'clang-3.4',
24 'command' : 'clang++-3.4',
29 'ppa' : ["ppa:h-rayflood/llvm"],
30 'package' : 'clang-3.5',
31 'command' : 'clang++-3.5',
36 'ppa' : ["ppa:h-rayflood/llvm"],
37 'package' : 'clang-3.6',
38 'command' : 'clang++-3.6',
43 'deb' : ["http://apt.llvm.org/trusty/","llvm-toolchain-trusty-3.7","main"],
44 'apt-key' : ['http://apt.llvm.org/llvm-snapshot.gpg.key'],
45 'package' : 'clang-3.7',
46 'command' : 'clang++-3.7',
51 'deb' : ["http://apt.llvm.org/trusty/","llvm-toolchain-trusty-3.8","main"],
52 'apt-key' : ['http://apt.llvm.org/llvm-snapshot.gpg.key'],
53 'package' : 'clang-3.8',
54 'command' : 'clang++-3.8',
59 'deb' : ["http://apt.llvm.org/trusty/","llvm-toolchain-trusty-3.9","main"],
60 'apt-key' : ['http://apt.llvm.org/llvm-snapshot.gpg.key'],
61 'package' : 'clang-3.9',
62 'command' : 'clang++-3.9',
67 'deb' : ["http://apt.llvm.org/trusty/","llvm-toolchain-trusty-4.0","main"],
68 'apt-key' : ['http://apt.llvm.org/llvm-snapshot.gpg.key'],
69 'package' : 'clang-4.0',
70 'command' : 'clang++-4.0',
75 'deb' : ["http://apt.llvm.org/trusty/","llvm-toolchain-trusty-5.0","main"],
76 'apt-key' : ['http://apt.llvm.org/llvm-snapshot.gpg.key'],
77 'package' : 'clang-5.0',
78 'command' : 'clang++-5.0',
83 'deb' : ["http://apt.llvm.org/trusty/","llvm-toolchain-trusty-6.0","main"],
84 'apt-key' : ['http://apt.llvm.org/llvm-snapshot.gpg.key'],
85 'package' : 'clang-6.0',
86 'command' : 'clang++-6.0',
91 'ppa' : ["ppa:ubuntu-toolchain-r/test"],
92 'package' : 'g++-4.7',
93 'command' : 'g++-4.7',
99 'ppa' : ["ppa:ubuntu-toolchain-r/test"],
100 'package' : 'g++-4.8',
101 'command' : 'g++-4.8',
106 'ppa' : ["ppa:ubuntu-toolchain-r/test"],
107 'package' : 'g++-4.9',
108 'command' : 'g++-4.9',
113 'ppa' : ["ppa:ubuntu-toolchain-r/test"],
120 'ppa' : ["ppa:ubuntu-toolchain-r/test"],
127 'ppa' : ["ppa:ubuntu-toolchain-r/test"],
134 'ppa' : ["ppa:ubuntu-toolchain-r/test"],
141 'ppa' : ["ppa:ubuntu-toolchain-r/test"],
149 'command' : 'C:\\\\MinGW\\\\bin\\\\g++.exe',
154 'command' : 'C:\\\\mingw-w64\\\\x86_64-6.3.0-posix-seh-rt_v5-rev1\\\\mingw64\\\\bin\\\\g++.exe',
188 'command' : 'clang++',
193 'command' : 'clang++',
198 'command' : 'clang++',
203 'command' : 'clang++',
208 'command' : 'clang++',
213 'command' : 'clang++',
218 'command' : 'clang++',
223 'command' : 'clang++',
228 'command' : 'clang++',
233 'command' : 'clang++',
238 'command' : 'clang++',
243 'command' : 'clang++',
248 'command' : 'clang++',
253 'command' : 'clang++',
258 'command' : 'clang++',
263 'command' : 'clang++',
268 'command' : 'clang++',
273 'command' : 'clang++',
279 class SystemCallError(Exception):
280 def __init__(self
, command
, result
):
281 self
.command
= command
283 def __str__(self
, *args
, **kwargs
):
284 return "'%s' ==> %s"%("' '".join(self
.command
), self
.result
)
291 def call(*command
, **kargs
):
292 utils
.log( "%s> '%s'"%(os
.getcwd(), "' '".join(command
)) )
294 result
= subprocess
.call(command
, **kargs
)
297 print "Failed: '%s' ERROR = %s"%("' '".join(command
), result
)
298 utils
.call_stats
.append((t
,os
.getcwd(),command
,result
))
299 utils
.log( "%s> '%s' execution time %s seconds"%(os
.getcwd(), "' '".join(command
), t
) )
303 def print_call_stats():
304 utils
.log("================================================================================")
305 for j
in sorted(utils
.call_stats
, reverse
=True):
306 utils
.log("{:>12.4f}\t{}> {} ==> {}".format(*j
))
307 utils
.log("================================================================================")
310 def check_call(*command
, **kargs
):
312 result
= utils
.call(*command
, **kargs
)
314 raise(SystemCallError([cwd
].extend(command
), result
))
317 def makedirs( path
):
318 if not os
.path
.exists( path
):
323 frames
= inspect
.stack()
325 for i
in frames
[ 3: ]:
326 if i
[0].f_locals
.has_key( '__log__' ):
327 level
= level
+ i
[0].f_locals
[ '__log__' ]
334 sys
.stderr
.write( '# ' + ' ' * utils
.log_level() + message
+ '\n' )
339 if os
.path
.exists( path
):
340 #~ shutil.rmtree( unicode( path ) )
341 if sys
.platform
== 'win32':
342 os
.system( 'del /f /s /q "%s" >nul 2>&1' % path
)
343 shutil
.rmtree( unicode( path
) )
345 os
.system( 'rm -f -r "%s"' % path
)
348 def retry( f
, max_attempts
=5, sleep_secs
=10 ):
349 for attempts
in range( max_attempts
, -1, -1 ):
352 except Exception, msg
:
353 utils
.log( '%s failed with message "%s"' % ( f
.__name
__, msg
) )
355 utils
.log( 'Giving up.' )
358 utils
.log( 'Retrying (%d more attempts).' % attempts
)
359 time
.sleep( sleep_secs
)
362 def web_get( source_url
, destination_file
, proxy
= None ):
366 if proxy
is not None:
372 src
= urllib
.urlopen( source_url
, proxies
= proxies
)
374 f
= open( destination_file
, 'wb' )
376 data
= src
.read( 16*1024 )
377 if len( data
) == 0: break
384 def unpack_archive( archive_path
):
385 utils
.log( 'Unpacking archive ("%s")...' % archive_path
)
387 archive_name
= os
.path
.basename( archive_path
)
388 extension
= archive_name
[ archive_name
.find( '.' ) : ]
390 if extension
in ( ".tar.gz", ".tar.bz2" ):
394 mode
= os
.path
.splitext( extension
)[1][1:]
395 tar
= tarfile
.open( archive_path
, 'r:%s' % mode
)
397 tar
.extract( tarinfo
)
398 if sys
.platform
== 'win32' and not tarinfo
.isdir():
399 # workaround what appears to be a Win32-specific bug in 'tarfile'
400 # (modification times for extracted files are not set properly)
401 f
= os
.path
.join( os
.curdir
, tarinfo
.name
)
402 os
.chmod( f
, stat
.S_IWRITE
)
403 os
.utime( f
, ( tarinfo
.mtime
, tarinfo
.mtime
) )
405 elif extension
in ( ".zip" ):
408 z
= zipfile
.ZipFile( archive_path
, 'r', zipfile
.ZIP_DEFLATED
)
409 for f
in z
.infolist():
410 destination_file_path
= os
.path
.join( os
.curdir
, f
.filename
)
411 if destination_file_path
[-1] == "/": # directory
412 if not os
.path
.exists( destination_file_path
):
413 os
.makedirs( destination_file_path
)
415 result
= open( destination_file_path
, 'wb' )
416 result
.write( z
.read( f
.filename
) )
420 raise 'Do not know how to unpack archives with extension \"%s\"' % extension
423 def make_file(filename
, *text
):
424 text
= string
.join( text
, '\n' )
425 with codecs
.open( filename
, 'w', 'utf-8' ) as f
:
429 def append_file(filename
, *text
):
430 with codecs
.open( filename
, 'a', 'utf-8' ) as f
:
431 f
.write( string
.join( text
, '\n' ) )
435 if sys
.platform
== "darwin":
436 utils
.call("top","-l","1","-s","0","-n","0")
437 elif sys
.platform
.startswith("linux"):
438 utils
.call("free","-m","-l")
441 def query_boost_version(boost_root
):
443 Read in the Boost version from a given boost_root.
446 if os
.path
.exists(os
.path
.join(boost_root
,'Jamroot')):
447 with codecs
.open(os
.path
.join(boost_root
,'Jamroot'), 'r', 'utf-8') as f
:
448 for line
in f
.readlines():
450 if len(parts
) >= 5 and parts
[1] == 'BOOST_VERSION':
451 boost_version
= parts
[3]
453 if not boost_version
:
454 boost_version
= 'default'
458 def git_clone(owner
, repo
, branch
, commit
= None, repo_dir
= None, submodules
= False, url_format
= "https://github.com/%(owner)s/%(repo)s.git"):
460 This clone mimicks the way Travis-CI clones a project's repo. So far
461 Travis-CI is the most limiting in the sense of only fetching partial
465 repo_dir
= os
.path
.join(os
.getcwd(), owner
+','+repo
)
466 utils
.makedirs(os
.path
.dirname(repo_dir
))
467 if not os
.path
.exists(os
.path
.join(repo_dir
,'.git')):
468 utils
.check_call("git","clone",
470 "--branch=%s"%(branch),
471 url_format
%{'owner':owner
,'repo':repo
},
476 utils
.check_call("git","pull",
477 # "--depth=1", # Can't do depth as we get merge errors.
478 "--quiet","--no-recurse-submodules")
480 utils
.check_call("git","checkout","-qf",commit
)
481 if os
.path
.exists(os
.path
.join('.git','modules')):
482 if sys
.platform
== 'win32':
483 utils
.check_call('dir',os
.path
.join('.git','modules'))
485 utils
.check_call('ls','-la',os
.path
.join('.git','modules'))
487 utils
.check_call("git","submodule","--quiet","update",
488 "--quiet","--init","--recursive",
490 utils
.check_call("git","submodule","--quiet","foreach","git","fetch")
493 class parallel_call(threading
.Thread
):
495 Runs a synchronous command in a thread waiting for it to complete.
498 def __init__(self
, *command
, **kargs
):
499 super(parallel_call
,self
).__init
__()
500 self
.command
= command
501 self
.command_kargs
= kargs
505 self
.result
= utils
.call(*self
.command
, **self
.command_kargs
)
508 super(parallel_call
,self
).join()
510 raise(SystemCallError(self
.command
, self
.result
))
512 def set_arg(args
, k
, v
= None):
517 class script_common(object):
519 Main script to run continuous integration.
522 def __init__(self
, ci_klass
, **kargs
):
523 self
.ci
= ci_klass(self
)
525 opt
= optparse
.OptionParser(
526 usage
="%prog [options] [commands]")
529 opt
.add_option( '--debug-level',
530 help="debugging level; controls the amount of debugging output printed",
532 opt
.add_option( '-j',
533 help="maximum number of parallel jobs to use for building with b2",
534 type='int', dest
='jobs')
535 opt
.add_option('--branch')
536 opt
.add_option('--commit')
537 kargs
= self
.init(opt
,kargs
)
538 kargs
= self
.ci
.init(opt
, kargs
)
539 set_arg(kargs
,'debug_level',0)
540 set_arg(kargs
,'jobs',2)
541 set_arg(kargs
,'branch',None)
542 set_arg(kargs
,'commit',None)
543 set_arg(kargs
,'repo',None)
544 set_arg(kargs
,'repo_dir',None)
545 set_arg(kargs
,'actions',None)
546 set_arg(kargs
,'pull_request', None)
549 for (k
,v
) in kargs
.iteritems():
551 ( _opt_
, self
.actions
) = opt
.parse_args(None,self
)
552 if not self
.actions
or self
.actions
== []:
553 self
.actions
= kargs
.get('actions',None)
554 if not self
.actions
or self
.actions
== []:
555 self
.actions
= [ 'info' ]
556 if not self
.repo_dir
:
557 self
.repo_dir
= os
.getcwd()
558 self
.build_dir
= os
.path
.join(os
.path
.dirname(self
.repo_dir
), "build")
561 self
.bintray_key
= os
.getenv('BINTRAY_KEY')
567 utils
.print_call_stats()
569 utils
.print_call_stats()
572 def init(self
, opt
, kargs
):
579 for action
in self
.actions
:
580 action_m
= "command_"+action
.replace('-','_')
581 ci_command
= getattr(self
.ci
, action_m
, None)
582 ci_script
= getattr(self
, action_m
, None)
583 if ci_command
or ci_script
:
584 utils
.log( "### %s.."%(action) )
585 if os
.path
.exists(self
.repo_dir
):
586 os
.chdir(self
.repo_dir
)
592 def b2( self
, *args
, **kargs
):
593 cmd
= ['b2','--debug-configuration', '-j%s'%(self
.jobs
)]
596 if 'toolset' in kargs
:
597 cmd
.append('toolset=' + kargs
['toolset'])
599 if 'parallel' in kargs
:
600 return parallel_call(*cmd
)
602 return utils
.check_call(*cmd
)
604 # Common test commands in the order they should be executed..
606 def command_info(self
):
609 def command_install(self
):
610 utils
.makedirs(self
.build_dir
)
611 os
.chdir(self
.build_dir
)
613 def command_install_toolset(self
, toolset
):
614 if self
.ci
and hasattr(self
.ci
,'install_toolset'):
615 self
.ci
.install_toolset(toolset
)
617 def command_before_build(self
):
620 def command_build(self
):
623 def command_before_cache(self
):
626 def command_after_success(self
):
629 class ci_cli(object):
631 This version of the script provides a way to do manual building. It sets up
632 additional environment and adds fetching of the git repos that would
633 normally be done by the CI system.
635 The common way to use this variant is to invoke something like:
639 python path-to/library_test.py --branch=develop [--repo=mylib] ...
641 Status: In working order.
644 def __init__(self
,script
):
645 if sys
.platform
== 'darwin':
646 # Requirements for running on OSX:
647 # https://www.stack.nl/~dimitri/doxygen/download.html#srcbin
648 # https://tug.org/mactex/morepackages.html
649 doxygen_path
= "/Applications/Doxygen.app/Contents/Resources"
650 if os
.path
.isdir(doxygen_path
):
651 os
.environ
["PATH"] = doxygen_path
+':'+os
.environ
['PATH']
653 self
.repo_dir
= os
.getcwd()
656 def init(self
, opt
, kargs
):
667 def finish(self
, result
):
668 self
.exit_result
= result
670 def command_finish(self
):
671 exit(self
.exit_result
)
673 class ci_travis(object):
675 This variant build releases in the context of the Travis-CI service.
678 def __init__(self
,script
):
681 def init(self
, opt
, kargs
):
682 set_arg(kargs
,'repo_dir', os
.getenv("TRAVIS_BUILD_DIR"))
683 set_arg(kargs
,'branch', os
.getenv("TRAVIS_BRANCH"))
684 set_arg(kargs
,'commit', os
.getenv("TRAVIS_COMMIT"))
685 set_arg(kargs
,'repo', os
.getenv("TRAVIS_REPO_SLUG").split("/")[1])
686 set_arg(kargs
,'pull_request',
687 os
.getenv('TRAVIS_PULL_REQUEST') \
688 if os
.getenv('TRAVIS_PULL_REQUEST') != 'false' else None)
691 def finish(self
, result
):
694 def install_toolset(self
, toolset
):
696 Installs specific toolset on CI system.
698 info
= toolset_info
[toolset
]
699 if sys
.platform
.startswith('linux'):
700 os
.chdir(self
.script
.build_dir
)
702 for ppa
in info
['ppa']:
704 'sudo','add-apt-repository','--yes',ppa
)
706 utils
.make_file('sources.list',
707 "deb %s"%(' '.join(info
['deb'])),
708 "deb-src %s"%(' '.join(info
['deb'])))
709 utils
.check_call('sudo','bash','-c','cat sources.list >> /etc/apt/sources.list')
710 if 'apt-key' in info
:
711 for key
in info
['apt-key']:
712 utils
.check_call('wget',key
,'-O','apt.key')
713 utils
.check_call('sudo','apt-key','add','apt.key')
715 'sudo','apt-get','update','-qq')
717 'sudo','apt-get','install','-qq',info
['package'])
718 if 'debugpackage' in info
and info
['debugpackage']:
720 'sudo','apt-get','install','-qq',info
['debugpackage'])
722 # Travis-CI commands in the order they are executed. We need
723 # these to forward to our common commands, if they are different.
725 def command_before_install(self
):
728 def command_install(self
):
729 self
.script
.command_install()
731 def command_before_script(self
):
732 self
.script
.command_before_build()
734 def command_script(self
):
735 self
.script
.command_build()
737 def command_before_cache(self
):
738 self
.script
.command_before_cache()
740 def command_after_success(self
):
741 self
.script
.command_after_success()
743 def command_after_failure(self
):
746 def command_before_deploy(self
):
749 def command_after_deploy(self
):
752 def command_after_script(self
):
755 class ci_circleci(object):
757 This variant build releases in the context of the CircleCI service.
760 def __init__(self
,script
):
763 def init(self
, opt
, kargs
):
764 set_arg(kargs
,'repo_dir', os
.path
.join(os
.getenv("HOME"),os
.getenv("CIRCLE_PROJECT_REPONAME")))
765 set_arg(kargs
,'branch', os
.getenv("CIRCLE_BRANCH"))
766 set_arg(kargs
,'commit', os
.getenv("CIRCLE_SHA1"))
767 set_arg(kargs
,'repo', os
.getenv("CIRCLE_PROJECT_REPONAME").split("/")[1])
768 set_arg(kargs
,'pull_request', os
.getenv('CIRCLE_PR_NUMBER'))
771 def finish(self
, result
):
774 def command_machine_post(self
):
775 # Apt update for the pckages installs we'll do later.
776 utils
.check_call('sudo','apt-get','-qq','update')
777 # Need PyYAML to read Travis yaml in a later step.
778 utils
.check_call("pip","install","--user","PyYAML")
780 def command_checkout_post(self
):
781 os
.chdir(self
.script
.repo_dir
)
782 utils
.check_call("git","submodule","update","--quiet","--init","--recursive")
784 def command_dependencies_pre(self
):
785 # Read in .travis.yml for list of packages to install
786 # as CircleCI doesn't have a convenient apt install method.
788 utils
.check_call('sudo','-E','apt-get','-yqq','update')
789 utils
.check_call('sudo','apt-get','-yqq','purge','texlive*')
790 with
open(os
.path
.join(self
.script
.repo_dir
,'.travis.yml')) as yml
:
791 travis_yml
= yaml
.load(yml
)
792 utils
.check_call('sudo','apt-get','-yqq',
793 '--no-install-suggests','--no-install-recommends','--force-yes','install',
794 *travis_yml
['addons']['apt']['packages'])
796 def command_dependencies_override(self
):
797 self
.script
.command_install()
799 def command_dependencies_post(self
):
802 def command_database_pre(self
):
805 def command_database_override(self
):
808 def command_database_post(self
):
811 def command_test_pre(self
):
812 self
.script
.command_install()
813 self
.script
.command_before_build()
815 def command_test_override(self
):
816 # CircleCI runs all the test subsets. So in order to avoid
817 # running the after_success we do it here as the build step
818 # will halt accordingly.
819 self
.script
.command_build()
820 self
.script
.command_before_cache()
821 self
.script
.command_after_success()
823 def command_test_post(self
):
826 class ci_appveyor(object):
828 def __init__(self
,script
):
831 def init(self
, opt
, kargs
):
832 set_arg(kargs
,'repo_dir',os
.getenv("APPVEYOR_BUILD_FOLDER"))
833 set_arg(kargs
,'branch',os
.getenv("APPVEYOR_REPO_BRANCH"))
834 set_arg(kargs
,'commit',os
.getenv("APPVEYOR_REPO_COMMIT"))
835 set_arg(kargs
,'repo',os
.getenv("APPVEYOR_REPO_NAME").split("/")[1])
836 set_arg(kargs
,'address_model',os
.getenv("PLATFORM",None))
837 set_arg(kargs
,'variant',os
.getenv("CONFIGURATION","debug"))
838 set_arg(kargs
,'pull_request', os
.getenv('APPVEYOR_PULL_REQUEST_NUMBER'))
841 def finish(self
, result
):
844 # Appveyor commands in the order they are executed. We need
845 # these to forward to our common commands, if they are different.
847 def command_install(self
):
848 self
.script
.command_install()
850 def command_before_build(self
):
851 os
.chdir(self
.script
.repo_dir
)
852 utils
.check_call("git","submodule","update","--quiet","--init","--recursive")
853 self
.script
.command_before_build()
855 def command_build_script(self
):
856 self
.script
.command_build()
858 def command_after_build(self
):
859 self
.script
.command_before_cache()
861 def command_before_test(self
):
864 def command_test_script(self
):
867 def command_after_test(self
):
870 def command_on_success(self
):
871 self
.script
.command_after_success()
873 def command_on_failure(self
):
876 def command_on_finish(self
):
879 def main(script_klass
):
880 if os
.getenv('TRAVIS', False):
881 script_klass(ci_travis
)
882 elif os
.getenv('CIRCLECI', False):
883 script_klass(ci_circleci
)
884 elif os
.getenv('APPVEYOR', False):
885 script_klass(ci_appveyor
)