1#!/usr/bin/env python
2# Copyright 2016 gRPC authors.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#     http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15"""Runs selected gRPC test/build tasks."""
16
17from __future__ import print_function
18
19import argparse
20import multiprocessing
21import sys
22
23import artifacts.artifact_targets as artifact_targets
24import artifacts.distribtest_targets as distribtest_targets
25import artifacts.package_targets as package_targets
26import python_utils.jobset as jobset
27import python_utils.report_utils as report_utils
28
29_TARGETS = []
30_TARGETS += artifact_targets.targets()
31_TARGETS += distribtest_targets.targets()
32_TARGETS += package_targets.targets()
33
34
35def _create_build_map():
36    """Maps task names and labels to list of tasks to be built."""
37    target_build_map = dict([(target.name, [target]) for target in _TARGETS])
38    if len(_TARGETS) > len(target_build_map.keys()):
39        raise Exception('Target names need to be unique')
40
41    label_build_map = {}
42    label_build_map['all'] = [t for t in _TARGETS]  # to build all targets
43    for target in _TARGETS:
44        for label in target.labels:
45            if label in label_build_map:
46                label_build_map[label].append(target)
47            else:
48                label_build_map[label] = [target]
49
50    if set(target_build_map.keys()).intersection(label_build_map.keys()):
51        raise Exception('Target names need to be distinct from label names')
52    return dict(list(target_build_map.items()) + list(label_build_map.items()))
53
54
55_BUILD_MAP = _create_build_map()
56
57argp = argparse.ArgumentParser(description='Runs build/test targets.')
58argp.add_argument('-b',
59                  '--build',
60                  choices=sorted(_BUILD_MAP.keys()),
61                  nargs='+',
62                  default=['all'],
63                  help='Target name or target label to build.')
64argp.add_argument('-f',
65                  '--filter',
66                  choices=sorted(_BUILD_MAP.keys()),
67                  nargs='+',
68                  default=[],
69                  help='Filter targets to build with AND semantics.')
70argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
71argp.add_argument('-t',
72                  '--travis',
73                  default=False,
74                  action='store_const',
75                  const=True)
76
77args = argp.parse_args()
78
79# Figure out which targets to build
80targets = []
81for label in args.build:
82    targets += _BUILD_MAP[label]
83
84# Among targets selected by -b, filter out those that don't match the filter
85targets = [t for t in targets if all(f in t.labels for f in args.filter)]
86targets = sorted(set(targets), key=lambda target: target.name)
87
88# Execute pre-build phase
89prebuild_jobs = []
90for target in targets:
91    prebuild_jobs += target.pre_build_jobspecs()
92if prebuild_jobs:
93    num_failures, _ = jobset.run(prebuild_jobs,
94                                 newline_on_success=True,
95                                 maxjobs=args.jobs)
96    if num_failures != 0:
97        jobset.message('FAILED', 'Pre-build phase failed.', do_newline=True)
98        sys.exit(1)
99
100build_jobs = []
101for target in targets:
102    build_jobs.append(target.build_jobspec())
103if not build_jobs:
104    print('Nothing to build.')
105    sys.exit(1)
106
107jobset.message('START', 'Building targets.', do_newline=True)
108num_failures, resultset = jobset.run(build_jobs,
109                                     newline_on_success=True,
110                                     maxjobs=args.jobs)
111report_utils.render_junit_xml_report(resultset,
112                                     'report_taskrunner_sponge_log.xml',
113                                     suite_name='tasks')
114if num_failures == 0:
115    jobset.message('SUCCESS',
116                   'All targets built successfully.',
117                   do_newline=True)
118else:
119    jobset.message('FAILED', 'Failed to build targets.', do_newline=True)
120    sys.exit(1)
121