ra.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. # -*- coding: utf-8; mode: Python -*-
  2. # (c) Daniel Llorens - 2016, 2017-2019
  3. # This library is free software; you can redistribute it and/or modify it under
  4. # the terms of the GNU Lesser General Public License as published by the Free
  5. # Software Foundation; either version 3 of the License, or (at your option) any
  6. # later version.
  7. # Utilities for SConstructs
  8. import os, string
  9. # These are colorama names, but the dependence is a bother.
  10. class Fore: RED = '\x1b[31m'; YELLOW ='\x1b[33m'; RESET = '\x1b[39m'
  11. class Style: BRIGHT = '\x1b[1m'; RESET_ALL = '\x1b[0m';
  12. from os.path import join, abspath, split
  13. from subprocess import call
  14. def ensure_ext(s, ext):
  15. "if s doesn't end with ext, append it."
  16. p = s.rfind(ext)
  17. return s if p+len(ext) == len(s) else s + ext
  18. def remove_ext(s):
  19. "clip string from the last dot until the end."
  20. p = s.rfind('.')
  21. assert p>=0, 'source must have an extension'
  22. return s[0:p]
  23. def path_parts(path):
  24. path, tail = split(path)
  25. return ([path] if path == os.sep else path_parts(path) if path else []) \
  26. + ([tail] if tail else [])
  27. def take_from_environ(env, var, wrapper=(lambda x: x), default=None):
  28. if var in os.environ and os.environ[var]!='':
  29. env[var] = wrapper(os.environ[var])
  30. elif default is not None:
  31. env[var] = default
  32. def get_value_wo_error(dictionary, key, default = ''):
  33. if key in dictionary:
  34. return dictionary[key]
  35. else:
  36. return default
  37. def dict_index_list(dictionary, list_of_keys):
  38. return dict([ (k, get_value_wo_error(dictionary, k))
  39. for k in list_of_keys ])
  40. def to_test(env, variant_dir, source, args):
  41. """
  42. Run program with args to produce a check stamp. The name of the first source
  43. is used to generate the name of the stamp.
  44. """
  45. class tester:
  46. def __init__(self, args):
  47. self.args = args
  48. def __call__(self, target, source, env):
  49. print("-> running %s \n___________________" % str(self.args))
  50. r = os.spawnl(os.P_WAIT, self.args[0], self.args[0], *self.args[1:])
  51. print("^^^^^^^^^^^^^^^^^^^")
  52. print('r ', r)
  53. if not r:
  54. print("PASSED %s" % str(self.args))
  55. call(['touch', target[0].abspath])
  56. else:
  57. print("FAILED %s" % str(self.args))
  58. return r
  59. stamp = env.File(join(variant_dir, str(source[0])) + string.join(args[1:]) + '.check')
  60. return env.Command(stamp, source, tester(args))
  61. # def to_source(env, targets, source):
  62. # main = source[0]
  63. # for target in targets: env.Notangle(target, remove_ext(main)+'.nw')
  64. # env.Noweave(remove_ext(main)+'.tex', remove_ext(main)+'.nw')
  65. # env.PDF(remove_ext(main), remove_ext(main)+'.tex')
  66. def to_source_from_noweb(env, targets, source):
  67. main = source[0]
  68. env.Noweave(remove_ext(main) + '.tex', remove_ext(main) + '.nw')
  69. env.PDF(remove_ext(main), remove_ext(main) + '.tex')
  70. return [env.Notangle(target, remove_ext(main) + '.nw') for target in targets]
  71. def to_test_ra(env_, variant_dir):
  72. def f(source, target='', cxxflags=[], cppdefines=[]):
  73. if len(cxxflags)==0 or len(cppdefines)==0:
  74. env = env_
  75. else:
  76. env = env_.Clone()
  77. env.Append(CXXFLAGS=cxxflags + ['-U' + k for k in cppdefines.keys()], CPPDEFINES=cppdefines)
  78. if len(target)==0:
  79. target = source
  80. obj = env.Object(target, [source + '.C'])
  81. test = env.Program(target, obj)
  82. to_test(env, variant_dir, test, [test[0].abspath])
  83. return f
  84. def print_summary(GetBuildFailures, tag):
  85. test_item_tally = 0
  86. test_tally = 0
  87. build_tally = 0
  88. print('\n' + Style.BRIGHT + 'Summary for ' + tag + Style.RESET_ALL + '\n--------')
  89. for bf in GetBuildFailures():
  90. if str(bf.node).endswith('.check') and (bf.status > 0):
  91. print((Style.BRIGHT + Fore.RED + '%s ' + Style.RESET_ALL + Fore.RESET + ' failed (%d)') \
  92. % (bf.node, bf.status))
  93. test_item_tally += bf.status
  94. test_tally += 1
  95. else:
  96. print((Style.BRIGHT + Fore.YELLOW + '%s ' + Style.RESET_ALL + Fore.RESET + ' failed (%s)') \
  97. % (bf.node, bf.errstr))
  98. build_tally += 1
  99. print('%d targets failed to build.' % build_tally)
  100. print('%d tests failed with %d total failures.' % (test_tally, test_item_tally))