ON Semiconductor / mbed-os

Dependents:   mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers build_test.py Source File

build_test.py

00001 #!/usr/bin/env python
00002 """
00003 mbed SDK
00004 Copyright (c) 2011-2016 ARM Limited
00005 
00006 Licensed under the Apache License, Version 2.0 (the "License");
00007 you may not use this file except in compliance with the License.
00008 You may obtain a copy of the License at
00009 
00010     http://www.apache.org/licenses/LICENSE-2.0
00011 
00012 Unless required by applicable law or agreed to in writing, software
00013 distributed under the License is distributed on an "AS IS" BASIS,
00014 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015 See the License for the specific language governing permissions and
00016 limitations under the License.
00017 """
00018 
00019 import sys
00020 from os import remove, rename
00021 from os.path import join, dirname, exists, abspath
00022 ROOT = abspath(join(dirname(__file__), "..", "..", ".."))
00023 sys.path.insert(0, ROOT)
00024 import argparse
00025 import os
00026 from argparse import ArgumentTypeError
00027 import sys
00028 from shutil import rmtree
00029 from collections import namedtuple
00030 from copy import copy
00031 
00032 
00033 from tools.paths import EXPORT_DIR
00034 from tools.tests import TESTS
00035 from tools.build_api import get_mbed_official_release, RELEASE_VERSIONS
00036 from tools.test_api import find_tests
00037 from tools.project import export
00038 from Queue import Queue
00039 from threading import Thread, Lock
00040 from tools.project_api import print_results, get_exporter_toolchain
00041 from tools.tests import test_name_known, test_known
00042 from tools.export import EXPORTERS
00043 from tools.utils import argparse_force_lowercase_type, \
00044                         argparse_many, columnate, args_error, \
00045                         argparse_filestring_type
00046 from tools.options import extract_profile
00047 
00048 print_lock = Lock()
00049 
00050 def do_queue(Class, function, interable) :
00051     q = Queue()
00052     threads = [Class(q, function) for each in range(20)]
00053     for thing in interable :
00054         q.put(thing)
00055     for each in threads :
00056         each.setDaemon(True)
00057         each.start()
00058     q.join()
00059 
00060 
00061 class Reader (Thread) :
00062     def __init__(self, queue, func) :
00063         Thread.__init__(self)
00064         self.queue = queue
00065         self.func = func
00066 
00067     def start(self) :
00068         sys.stdout.flush()
00069         while not self.queue.empty() :
00070             test = self.queue.get()
00071             self.func(test)
00072             self.queue.task_done()
00073 
00074 
00075 class ExportBuildTest (object):
00076     """Object to encapsulate logic for progen build testing"""
00077     def __init__ (self, tests, parser, options):
00078         """
00079         Initialize an instance of class ProgenBuildTest
00080         Args:
00081             tests: array of TestCase instances
00082         """
00083         self.total  = len(tests)
00084         self.parser  = parser
00085         self.options  = options
00086         self.counter  = 0
00087         self.successes  = []
00088         self.failures  = []
00089         self.skips  = []
00090         self.tests  = [ExportBuildTest.test_case(test) for test in tests]
00091         self.build_queue  = Queue()
00092 
00093     @staticmethod
00094     def test_case(case):
00095         TestCase = namedtuple('TestCase', case.keys())
00096         return TestCase(**case)
00097 
00098     def handle_log(self,log):
00099         try:
00100             with open(log, 'r') as in_log:
00101                 print in_log.read()
00102                 sys.stdout.flush()
00103             log_name = join(EXPORT_DIR, dirname(log) + "_log.txt")
00104             if exists(log_name):
00105                 # delete it if so
00106                 remove(log_name)
00107             rename(log, log_name)
00108         except IOError:
00109             pass
00110 
00111     def batch_tests (self, clean=False):
00112         """Performs all exports of self.tests
00113         Peroform_exports will fill self.build_queue.
00114         This function will empty self.build_queue and call the test's
00115         IDE's build function."""
00116         do_queue(Reader, self.perform_exports , self.tests )
00117         self.counter  = 0
00118         self.total  = self.build_queue .qsize()
00119         while not self.build_queue .empty():
00120             build = self.build_queue .get()
00121             self.counter  +=1
00122             exporter = build[0]
00123             test_case = build[1]
00124             self.display_counter ("Building test case  %s::%s\t%s"
00125                                  % (test_case.mcu,
00126                                     test_case.ide,
00127                                     test_case.name))
00128 
00129             cwd = os.getcwd()
00130             os.chdir(exporter.export_dir)
00131             res = EXPORTERS[exporter.NAME.lower()].build(exporter.project_name, cleanup=False)
00132             os.chdir(cwd)
00133             if res:
00134                 self.failures .append("%s::%s\t%s" % (test_case.mcu,
00135                                                      test_case.ide,
00136                                                      test_case.name))
00137             else:
00138                 self.successes .append("%s::%s\t%s" % (test_case.mcu,
00139                                                       test_case.ide,
00140                                                       test_case.name))
00141             self.handle_log (exporter.generated_files[-1])
00142             if clean:
00143                 rmtree(exporter.export_dir)
00144 
00145     def display_counter (self, message) :
00146         with print_lock:
00147             sys.stdout.write("{}/{} {}".format(self.counter , self.total ,
00148                                                message) +"\n")
00149             sys.stdout.flush()
00150 
00151     def perform_exports (self, test_case):
00152         """
00153         Generate the project file for test_case and fill self.build_queue
00154         Args:
00155             test_case: object of type TestCase
00156         """
00157         sys.stdout.flush()
00158         self.counter  += 1
00159         name_str = ('%s_%s_%s') % (test_case.mcu, test_case.ide, test_case.name)
00160         self.display_counter ("Exporting test case  %s::%s\t%s" % (test_case.mcu,
00161                                                                   test_case.ide,
00162                                                                   test_case.name))
00163         exporter, toolchain = get_exporter_toolchain(test_case.ide)
00164         if test_case.mcu not in exporter.TARGETS:
00165             self.skips .append("%s::%s\t%s" % (test_case.mcu, test_case.ide,
00166                                               test_case.name))
00167             return
00168         profile = extract_profile(self.parser , self.options , toolchain)
00169         exporter = export(test_case.mcu, test_case.ide,
00170                           project_id=test_case.id, zip_proj=None,
00171                           src=test_case.src,
00172                           export_path=join(EXPORT_DIR, name_str),
00173                           silent=True, build_profile=profile)
00174         exporter.generated_files.append(join(EXPORT_DIR,name_str,test_case.log))
00175         self.build_queue .put((exporter,test_case))
00176             # Check if the specified name is in all_os_tests
00177 
00178 
00179 def check_valid_mbed_os(test):
00180     """Check if the specified name is in all_os_tests
00181     args:
00182         test: string name to index all_os_tests
00183     returns: tuple of test_name and source location of test,
00184         as given by find_tests"""
00185     all_os_tests = find_tests(ROOT, "K64F", "ARM")
00186     if test in all_os_tests.keys():
00187         return (test, all_os_tests[test])
00188     else:
00189         supported = columnate([t for t in all_os_tests.keys()])
00190         raise ArgumentTypeError("Program with name '{0}' not found. "
00191                                 "Supported tests are: \n{1}".format(test,supported))
00192 
00193 
00194 def check_version(version):
00195     """Check if the specified version is valid
00196     args:
00197         version: integer versio of mbed
00198     returns:
00199         version if it is valid"""
00200     if version not in RELEASE_VERSIONS:
00201         raise ArgumentTypeError("Choose from versions : %s"%", ".join(RELEASE_VERSIONS))
00202     return version
00203 
00204 
00205 def main():
00206     """Entry point"""
00207 
00208     ide_list = ["iar", "uvision"]
00209 
00210     default_v2 = [test_name_known("MBED_BLINKY")]
00211     default_v5 = [check_valid_mbed_os('tests-mbedmicro-rtos-mbed-basic')]
00212 
00213     parser = argparse.ArgumentParser(description=
00214                                      "Test progen builders. Leave any flag off"
00215                                      " to run with all possible options.")
00216     parser.add_argument("-i",
00217                         dest="ides",
00218                         default=ide_list,
00219                         type=argparse_many(argparse_force_lowercase_type(
00220                             ide_list, "toolchain")),
00221                         help="The target IDE: %s"% str(ide_list))
00222 
00223     parser.add_argument( "-p",
00224                         type=argparse_many(test_known),
00225                         dest="programs",
00226                         help="The index of the desired test program: [0-%d]"
00227                              % (len(TESTS) - 1))
00228 
00229     parser.add_argument("-n",
00230                         type=argparse_many(test_name_known),
00231                         dest="programs",
00232                         help="The name of the desired test program")
00233 
00234     parser.add_argument("-m", "--mcu",
00235                         help=("Generate projects for the given MCUs"),
00236                         metavar="MCU",
00237                         type=argparse_many(str.upper))
00238 
00239     parser.add_argument("-os-tests",
00240                         type=argparse_many(check_valid_mbed_os),
00241                         dest="os_tests",
00242                         help="Mbed-os tests")
00243 
00244     parser.add_argument("-c", "--clean",
00245                         dest="clean",
00246                         action="store_true",
00247                         help="clean up the exported project files",
00248                         default=False)
00249 
00250     parser.add_argument("--release",
00251                         dest="release",
00252                         type=check_version,
00253                         help="Which version of mbed to test",
00254                         default=RELEASE_VERSIONS[-1])
00255 
00256     parser.add_argument("--profile",
00257                         dest="profile",
00258                         action="append",
00259                         type=argparse_filestring_type,
00260                         default=[])
00261 
00262     options = parser.parse_args()
00263     # targets in chosen release
00264     targetnames = [target[0] for target in
00265                    get_mbed_official_release(options.release)]
00266     # all targets in release are default
00267     test_targets = options.mcu or targetnames
00268     if not all([t in targetnames for t in test_targets]):
00269         args_error(parser, "Only specify targets in release %s:\n%s"
00270                    %(options.release, columnate(sorted(targetnames))))
00271 
00272     v2_tests, v5_tests = [],[]
00273     if options.release == '5':
00274         v5_tests = options.os_tests or default_v5
00275     elif options.release == '2':
00276         v2_tests = options.programs or default_v2
00277 
00278     tests = []
00279     default_test = {key:None for key in ['ide', 'mcu', 'name', 'id', 'src', 'log']}
00280     for mcu in test_targets:
00281         for ide in options.ides:
00282             log = "build_log.txt" if ide == 'iar' \
00283                 else join('build', 'build_log.txt')
00284             # add each test case to the tests array
00285             default_test.update({'mcu': mcu, 'ide': ide, 'log':log})
00286             for test in v2_tests:
00287                 default_test.update({'name':TESTS[test]["id"], 'id':test})
00288                 tests.append(copy(default_test))
00289             for test in v5_tests:
00290                 default_test.update({'name':test[0],'src':[test[1],ROOT]})
00291                 tests.append(copy(default_test))
00292     test = ExportBuildTest(tests, parser, options)
00293     test.batch_tests(clean=options.clean)
00294     print_results(test.successes, test.failures, test.skips)
00295     sys.exit(len(test.failures))
00296 
00297 if __name__ == "__main__":
00298     main()