use_config.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. #!/usr/bin/env python
  2. # coding=utf-8
  3. # Mathieu Courtois - EDF R&D, 2013 - http://www.code-aster.org
  4. """
  5. When a project has a lot of options the 'waf configure' command line can be
  6. very long and it becomes a cause of error.
  7. This tool provides a convenient way to load a set of configuration parameters
  8. from a local file or from a remote url.
  9. The configuration parameters are stored in a Python file that is imported as
  10. an extra waf tool can be.
  11. Example:
  12. $ waf configure --use-config-dir=http://www.anywhere.org --use-config=myconf1 ...
  13. The file 'myconf1' will be downloaded from 'http://www.anywhere.org'
  14. (or 'http://www.anywhere.org/wafcfg').
  15. If the files are available locally, it could be:
  16. $ waf configure --use-config-dir=/somewhere/myconfigurations --use-config=myconf1 ...
  17. The configuration of 'myconf1.py' is automatically loaded by calling
  18. its 'configure' function. In this example, it defines environment variables and
  19. set options:
  20. def configure(self):
  21. self.env['CC'] = 'gcc-4.8'
  22. self.env.append_value('LIBPATH', [...])
  23. self.options.perlbinary = '/usr/local/bin/perl'
  24. self.options.pyc = False
  25. The corresponding command line should have been:
  26. $ CC=gcc-4.8 LIBPATH=... waf configure --nopyc --with-perl-binary=/usr/local/bin/perl
  27. This is an extra tool, not bundled with the default waf binary.
  28. To add the use_config tool to the waf file:
  29. $ ./waf-light --tools=use_config
  30. When using this tool, the wscript will look like:
  31. def options(opt):
  32. opt.load('use_config')
  33. def configure(conf):
  34. conf.load('use_config')
  35. """
  36. import sys
  37. import os.path as osp
  38. import os
  39. local_repo = ''
  40. """Local repository containing additional Waf tools (plugins)"""
  41. remote_repo = 'https://gitlab.com/ita1024/waf/raw/master/'
  42. """
  43. Remote directory containing downloadable waf tools. The missing tools can be downloaded by using::
  44. $ waf configure --download
  45. """
  46. remote_locs = ['waflib/extras', 'waflib/Tools']
  47. """
  48. Remote directories for use with :py:const:`waflib.extras.use_config.remote_repo`
  49. """
  50. try:
  51. from urllib import request
  52. except ImportError:
  53. from urllib import urlopen
  54. else:
  55. urlopen = request.urlopen
  56. from waflib import Errors, Context, Logs, Utils, Options, Configure
  57. try:
  58. from urllib.parse import urlparse
  59. except ImportError:
  60. from urlparse import urlparse
  61. DEFAULT_DIR = 'wafcfg'
  62. # add first the current wafcfg subdirectory
  63. sys.path.append(osp.abspath(DEFAULT_DIR))
  64. def options(self):
  65. group = self.add_option_group('configure options')
  66. group.add_option('--download', dest='download', default=False, action='store_true', help='try to download the tools if missing')
  67. group.add_option('--use-config', action='store', default=None,
  68. metavar='CFG', dest='use_config',
  69. help='force the configuration parameters by importing '
  70. 'CFG.py. Several modules may be provided (comma '
  71. 'separated).')
  72. group.add_option('--use-config-dir', action='store', default=DEFAULT_DIR,
  73. metavar='CFG_DIR', dest='use_config_dir',
  74. help='path or url where to find the configuration file')
  75. def download_check(node):
  76. """
  77. Hook to check for the tools which are downloaded. Replace with your function if necessary.
  78. """
  79. pass
  80. def download_tool(tool, force=False, ctx=None):
  81. """
  82. Download a Waf tool from the remote repository defined in :py:const:`waflib.extras.use_config.remote_repo`::
  83. $ waf configure --download
  84. """
  85. for x in Utils.to_list(remote_repo):
  86. for sub in Utils.to_list(remote_locs):
  87. url = '/'.join((x, sub, tool + '.py'))
  88. try:
  89. web = urlopen(url)
  90. try:
  91. if web.getcode() != 200:
  92. continue
  93. except AttributeError:
  94. pass
  95. except Exception:
  96. # on python3 urlopen throws an exception
  97. # python 2.3 does not have getcode and throws an exception to fail
  98. continue
  99. else:
  100. tmp = ctx.root.make_node(os.sep.join((Context.waf_dir, 'waflib', 'extras', tool + '.py')))
  101. tmp.write(web.read(), 'wb')
  102. Logs.warn('Downloaded %s from %s', tool, url)
  103. download_check(tmp)
  104. try:
  105. module = Context.load_tool(tool)
  106. except Exception:
  107. Logs.warn('The tool %s from %s is unusable', tool, url)
  108. try:
  109. tmp.delete()
  110. except Exception:
  111. pass
  112. continue
  113. return module
  114. raise Errors.WafError('Could not load the Waf tool')
  115. def load_tool(tool, tooldir=None, ctx=None, with_sys_path=True):
  116. try:
  117. module = Context.load_tool_default(tool, tooldir, ctx, with_sys_path)
  118. except ImportError as e:
  119. if not ctx or not hasattr(Options.options, 'download'):
  120. Logs.error('Could not load %r during options phase (download unavailable at this point)' % tool)
  121. raise
  122. if Options.options.download:
  123. module = download_tool(tool, ctx=ctx)
  124. if not module:
  125. ctx.fatal('Could not load the Waf tool %r or download a suitable replacement from the repository (sys.path %r)\n%s' % (tool, sys.path, e))
  126. else:
  127. ctx.fatal('Could not load the Waf tool %r from %r (try the --download option?):\n%s' % (tool, sys.path, e))
  128. return module
  129. Context.load_tool_default = Context.load_tool
  130. Context.load_tool = load_tool
  131. Configure.download_tool = download_tool
  132. def configure(self):
  133. opts = self.options
  134. use_cfg = opts.use_config
  135. if use_cfg is None:
  136. return
  137. url = urlparse(opts.use_config_dir)
  138. kwargs = {}
  139. if url.scheme:
  140. kwargs['download'] = True
  141. kwargs['remote_url'] = url.geturl()
  142. # search first with the exact url, else try with +'/wafcfg'
  143. kwargs['remote_locs'] = ['', DEFAULT_DIR]
  144. tooldir = url.geturl() + ' ' + DEFAULT_DIR
  145. for cfg in use_cfg.split(','):
  146. Logs.pprint('NORMAL', "Searching configuration '%s'..." % cfg)
  147. self.load(cfg, tooldir=tooldir, **kwargs)
  148. self.start_msg('Checking for configuration')
  149. self.end_msg(use_cfg)