blob: 5e1cb5ec68a63fc87107100a4cb288ec3469df77 [file] [log] [blame]
Srikrishna Iyer09a81e92019-12-30 10:47:57 -08001#!/usr/bin/env python3
2# Copyright lowRISC contributors.
3# Licensed under the Apache License, Version 2.0, see LICENSE for details.
4# SPDX-License-Identifier: Apache-2.0
Rupert Swarbrickb7aacc12020-06-02 11:04:55 +01005"""dvsim is a command line tool to deploy ASIC tool flows such as regressions
6for design verification (DV), formal property verification (FPV), linting and
7synthesis.
8
9It uses hjson as the format for specifying what to build and run. It is an
10end-to-end regression manager that can deploy multiple builds (where some tests
11might need different set of compile time options requiring a uniquely build sim
12executable) in parallel followed by tests in parallel using the load balancer
13of your choice.
14
15dvsim is built to be tool-agnostic so that you can easily switch between the
16tools at your disposal. dvsim uses fusesoc as the starting step to resolve all
17inter-package dependencies and provide us with a filelist that will be consumed
18by the sim tool.
19
Srikrishna Iyer09a81e92019-12-30 10:47:57 -080020"""
21
22import argparse
Srikrishna Iyer544da8d2020-01-14 23:51:41 -080023import datetime
Srikrishna Iyer09a81e92019-12-30 10:47:57 -080024import logging as log
25import os
26import subprocess
27import sys
Rupert Swarbrickb7aacc12020-06-02 11:04:55 +010028import textwrap
Weicai Yangfc2ff3b2020-03-19 18:05:14 -070029from signal import SIGINT, signal
Srikrishna Iyer09a81e92019-12-30 10:47:57 -080030
Udi Jonnalagaddadf49fb82020-03-17 11:05:17 -070031import Deploy
32import LintCfg
33import SimCfg
Michael Schaffner3d160992020-03-31 18:37:53 -070034import SynCfg
Udi Jonnalagaddadf49fb82020-03-17 11:05:17 -070035import utils
Srikrishna Iyer09a81e92019-12-30 10:47:57 -080036
37# TODO: add dvsim_cfg.hjson to retrieve this info
38version = 0.1
39
Rupert Swarbricke83b55e2020-05-12 11:44:04 +010040# The different categories that can be passed to the --list argument.
41_LIST_CATEGORIES = ["build_modes", "run_modes", "tests", "regressions"]
42
Srikrishna Iyer09a81e92019-12-30 10:47:57 -080043
44# Function to resolve the scratch root directory among the available options:
45# If set on the command line, then use that as a preference.
46# Else, check if $SCRATCH_ROOT env variable exists and is a directory.
47# Else use the default (<cwd>/scratch)
48# Try to create the directory if it does not already exist.
49def resolve_scratch_root(arg_scratch_root):
50 scratch_root = os.environ.get('SCRATCH_ROOT')
Rupert Swarbrick06383682020-03-24 15:56:41 +000051 if not arg_scratch_root:
52 if scratch_root is None:
Srikrishna Iyer544da8d2020-01-14 23:51:41 -080053 arg_scratch_root = os.getcwd() + "/scratch"
Srikrishna Iyer09a81e92019-12-30 10:47:57 -080054 else:
55 # Scratch space could be mounted in a filesystem (such as NFS) on a network drive.
56 # If the network is down, it could cause the access access check to hang. So run a
57 # simple ls command with a timeout to prevent the hang.
58 (out,
59 status) = utils.run_cmd_with_timeout(cmd="ls -d " + scratch_root,
Srikrishna Iyer544da8d2020-01-14 23:51:41 -080060 timeout=1,
Srikrishna Iyer09a81e92019-12-30 10:47:57 -080061 exit_on_failure=0)
62 if status == 0 and out != "":
63 arg_scratch_root = scratch_root
64 else:
Srikrishna Iyer544da8d2020-01-14 23:51:41 -080065 arg_scratch_root = os.getcwd() + "/scratch"
Srikrishna Iyer09a81e92019-12-30 10:47:57 -080066 log.warning(
Rupert Swarbrick06383682020-03-24 15:56:41 +000067 "Env variable $SCRATCH_ROOT=\"{}\" is not accessible.\n"
68 "Using \"{}\" instead.".format(scratch_root,
69 arg_scratch_root))
Srikrishna Iyer544da8d2020-01-14 23:51:41 -080070 else:
71 arg_scratch_root = os.path.realpath(arg_scratch_root)
72
Srikrishna Iyer09a81e92019-12-30 10:47:57 -080073 try:
74 os.system("mkdir -p " + arg_scratch_root)
Rupert Swarbrick06383682020-03-24 15:56:41 +000075 except OSError:
Srikrishna Iyer09a81e92019-12-30 10:47:57 -080076 log.fatal(
77 "Invalid --scratch-root=\"%s\" switch - failed to create directory!",
78 arg_scratch_root)
79 sys.exit(1)
80 return (arg_scratch_root)
81
82
Rupert Swarbrick536ab202020-06-09 16:37:12 +010083def read_max_parallel(arg):
84 '''Take value for --max-parallel as an integer'''
85 try:
86 int_val = int(arg)
87 if int_val <= 0:
88 raise ValueError('bad value')
89 return int_val
90
91 except ValueError:
92 raise argparse.ArgumentTypeError('Bad argument for --max-parallel '
93 '({!r}): must be a positive integer.'
94 .format(arg))
95
96
97def resolve_max_parallel(arg):
98 '''Pick a value of max_parallel, defaulting to 16 or $DVSIM_MAX_PARALLEL'''
99 if arg is not None:
100 assert arg > 0
101 return arg
102
103 from_env = os.environ.get('DVSIM_MAX_PARALLEL')
104 if from_env is not None:
105 try:
106 return read_max_parallel(from_env)
107 except argparse.ArgumentTypeError:
108 log.warning('DVSIM_MAX_PARALLEL environment variable has value '
109 '{!r}, which is not a positive integer. Using default '
110 'value (16).'
111 .format(from_env))
112
113 return 16
114
115
Rupert Swarbricke83b55e2020-05-12 11:44:04 +0100116def resolve_branch(branch):
117 '''Choose a branch name for output files
118
119 If the --branch argument was passed on the command line, the branch
120 argument is the branch name to use. Otherwise it is None and we use git to
121 find the name of the current branch in the working directory.
122
123 '''
124
125 if branch is not None:
126 return branch
127
128 result = subprocess.run(["git", "rev-parse", "--abbrev-ref", "HEAD"],
129 stdout=subprocess.PIPE)
130 branch = result.stdout.decode("utf-8").strip()
131 if not branch:
132 log.warning("Failed to find current git branch. "
133 "Setting it to \"default\"")
134 branch = "default"
135
136 return branch
137
138
139def make_config(args, proj_root):
140 '''A factory method for FlowCfg objects'''
141
142 # Look up the tool in a dictionary, defaulting to SimCfg.
143 #
144 # If --tool was not passed (so args.tool is None), we have to figure out
145 # the tool by reading the config file. At the moment, this forces a
146 # simulation target (TODO?)
147 factories = {
148 'ascentlint': LintCfg.LintCfg,
149 'veriblelint': LintCfg.LintCfg,
150 'dc': SynCfg.SynCfg
151 }
152
153 factory = factories.get(args.tool, SimCfg.SimCfg)
154 return factory(args.cfg, proj_root, args)
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800155
Rupert Swarbrick6cc20112020-04-24 09:44:35 +0100156
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800157# Get the project root directory path - this is used to construct the full paths
158def get_proj_root():
Rupert Swarbrick06383682020-03-24 15:56:41 +0000159 cmd = ["git", "rev-parse", "--show-toplevel"]
160 result = subprocess.run(cmd,
Rupert Swarbrick1dd327bd2020-03-24 15:14:00 +0000161 stdout=subprocess.PIPE,
162 stderr=subprocess.PIPE)
Udi Jonnalagaddaa122dda2020-03-13 16:56:45 -0700163 proj_root = result.stdout.decode("utf-8").strip()
Rupert Swarbrick06383682020-03-24 15:56:41 +0000164 if not proj_root:
Udi Jonnalagaddaa122dda2020-03-13 16:56:45 -0700165 log.error(
Rupert Swarbrick06383682020-03-24 15:56:41 +0000166 "Attempted to find the root of this GitHub repository by running:\n"
167 "{}\n"
168 "But this command has failed:\n"
169 "{}".format(' '.join(cmd), result.stderr.decode("utf-8")))
Udi Jonnalagaddaa122dda2020-03-13 16:56:45 -0700170 sys.exit(1)
171 return (proj_root)
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800172
173
Weicai Yangfc2ff3b2020-03-19 18:05:14 -0700174def sigint_handler(signal_received, frame):
175 # Kill processes and background jobs.
176 log.debug('SIGINT or CTRL-C detected. Exiting gracefully')
177 cfg.kill()
178 log.info('Exit due to SIGINT or CTRL-C ')
179 exit(1)
180
181
Rupert Swarbrickb7aacc12020-06-02 11:04:55 +0100182def wrapped_docstring():
183 '''Return a text-wrapped version of the module docstring'''
184 paras = []
185 para = []
186 for line in __doc__.strip().split('\n'):
187 line = line.strip()
188 if not line:
189 if para:
190 paras.append('\n'.join(para))
191 para = []
192 else:
193 para.append(line)
194 if para:
195 paras.append('\n'.join(para))
196
197 return '\n\n'.join(textwrap.fill(p) for p in paras)
198
199
200def parse_args():
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800201 parser = argparse.ArgumentParser(
Rupert Swarbrickb7aacc12020-06-02 11:04:55 +0100202 description=wrapped_docstring(),
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800203 formatter_class=argparse.RawDescriptionHelpFormatter)
204
Srikrishna Iyer7cf7cad2020-01-08 11:32:53 -0800205 parser.add_argument("cfg",
206 metavar="<cfg-hjson-file>",
207 help="""Configuration hjson file.""")
208
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800209 parser.add_argument("--version",
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800210 action='store_true',
211 help="Print version and exit")
212
Rupert Swarbrickb7aacc12020-06-02 11:04:55 +0100213 parser.add_argument("--tool", "-t",
214 default="",
215 help=("Explicitly set the tool to use. This is "
216 "optional for running simulations (where it can "
217 "be set in an .hjson file), but is required for "
218 "other flows. Possible tools include: vcs, "
219 "xcelium, ascentlint, verible, dc."))
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800220
Rupert Swarbrickb7aacc12020-06-02 11:04:55 +0100221 parser.add_argument("--list", "-l",
222 nargs="*",
223 metavar='CAT',
224 choices=_LIST_CATEGORIES,
225 help=('Parse the the given .hjson config file, list '
226 'the things that can be run, then exit. The '
227 'list can be filtered with a space-separated '
228 'of categories from: {}.'
229 .format(', '.join(_LIST_CATEGORIES))))
Srikrishna Iyer64009052020-01-13 11:27:39 -0800230
Rupert Swarbrickb7aacc12020-06-02 11:04:55 +0100231 whatg = parser.add_argument_group('Choosing what to run')
Srikrishna Iyer4f0b0902020-01-25 02:28:47 -0800232
Rupert Swarbrickb7aacc12020-06-02 11:04:55 +0100233 whatg.add_argument("-i",
234 "--items",
235 nargs="*",
236 default=["sanity"],
237 help=('Specify the regressions or tests to run. '
238 'Defaults to "sanity", but can be a '
239 'space separated list of test or regression '
240 'names.'))
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800241
Rupert Swarbrickb7aacc12020-06-02 11:04:55 +0100242 whatg.add_argument("--select-cfgs",
243 nargs="*",
244 metavar="CFG",
245 help=('The .hjson file is a master config. Only run '
246 'the given configs from it. If this argument is '
247 'not used, dvsim will process all configs listed '
248 'in a master config.'))
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800249
Rupert Swarbrickb7aacc12020-06-02 11:04:55 +0100250 disg = parser.add_argument_group('Dispatch options')
251
252 disg.add_argument("--job-prefix",
253 default="",
254 metavar="PFX",
255 help=('Prepend this string when running each tool '
256 'command.'))
257
258 disg.add_argument("--max-parallel", "-mp",
Rupert Swarbrick536ab202020-06-09 16:37:12 +0100259 type=read_max_parallel,
Rupert Swarbrickb7aacc12020-06-02 11:04:55 +0100260 metavar="N",
261 help=('Run only up to N builds/tests at a time. '
Rupert Swarbrick536ab202020-06-09 16:37:12 +0100262 'Default value 16, unless the DVSIM_MAX_PARALLEL '
263 'environment variable is set, in which case that '
264 'is used.'))
Rupert Swarbrickb7aacc12020-06-02 11:04:55 +0100265
266 pathg = parser.add_argument_group('File management')
267
268 pathg.add_argument("--scratch-root", "-sr",
269 metavar="PATH",
270 help=('Destination for build / run directories. If not '
271 'specified, uses the path in the SCRATCH_ROOT '
272 'environment variable, if set, or ./scratch '
273 'otherwise.'))
274
275 pathg.add_argument("--proj-root", "-pr",
276 metavar="PATH",
277 help=('The root directory of the project. If not '
278 'specified, dvsim will search for a git '
279 'repository containing the current directory.'))
280
281 pathg.add_argument("--branch", "-br",
282 metavar='B',
283 help=('By default, dvsim creates files below '
284 '{scratch-root}/{dut}.{flow}.{tool}/{branch}. '
285 'If --branch is not specified, dvsim assumes the '
286 'current directory is a git repository and uses '
287 'the name of the current branch.'))
288
289 pathg.add_argument("--max-odirs", "-mo",
290 type=int,
291 default=5,
292 metavar="N",
293 help=('When tests are run, older runs are backed '
294 'up. Discard all but the N most recent (defaults '
295 'to 5).'))
296
297 pathg.add_argument("--purge",
298 action='store_true',
299 help="Clean the scratch directory before running.")
300
301 buildg = parser.add_argument_group('Options for building')
302
303 buildg.add_argument("--build-only",
304 action='store_true',
305 help=('Stop after building executables for the given '
306 'items.'))
307
308 buildg.add_argument("--build-unique", "-bu",
309 action='store_true',
310 help=('Append a timestamp to the directory in which '
311 'files are built. This is suitable for the case '
312 'when another test is already running and you '
313 'want to run something else from a different '
314 'terminal without affecting it.'))
315
316 buildg.add_argument("--build-opts", "-bo",
317 nargs="+",
318 default=[],
319 metavar="OPT",
320 help=('Additional options passed on the command line '
321 'each time a build tool is run.'))
322
323 buildg.add_argument("--build-modes", "-bm",
324 nargs="+",
325 default=[],
326 metavar="MODE",
327 help=('The options for each build_mode in this list '
328 'are applied to all build and run targets.'))
329
330 rung = parser.add_argument_group('Options for running')
331
332 rung.add_argument("--run-only",
333 action='store_true',
334 help=('Skip the build step (assume that simulation '
335 'executables have already been built).'))
336
337 rung.add_argument("--run-opts", "-ro",
338 nargs="+",
339 default=[],
340 metavar="OPT",
341 help=('Additional options passed on the command line '
342 'each time a test is run.'))
343
344 rung.add_argument("--run-modes", "-rm",
345 nargs="+",
346 default=[],
347 metavar="MODE",
348 help=('The options for each run_mode in this list are '
349 'applied to each simulation run.'))
350
351 rung.add_argument("--profile", "-p",
352 choices=['time', 'mem'],
353 metavar="P",
354 help=('Turn on simulation profiling (where P is time '
355 'or mem).'))
356
357 rung.add_argument("--xprop-off",
358 action='store_true',
359 help="Turn off X-propagation in simulation.")
360
361 rung.add_argument("--no-rerun",
362 action='store_true',
363 help=("Disable the default behaviour, where failing "
364 "tests are automatically rerun with waves "
365 "enabled."))
366
367 rung.add_argument("--verbosity", "-v",
368 default="l",
369 choices=['n', 'l', 'm', 'h', 'd'],
370 metavar='V',
371 help=('Set UVM verbosity to none (n), low (l; the '
372 'default), medium (m), high (h) or debug (d). '
373 'This overrides any setting in the config files.'))
374
375 seedg = parser.add_argument_group('Test seeds')
376
377 seedg.add_argument("--seeds", "-s",
378 nargs="+",
379 default=[],
380 metavar="S",
381 help=('A list of seeds for tests. Note that these '
382 'specific seeds are applied to items being run '
383 'in the order they are passed.'))
384
385 seedg.add_argument("--fixed-seed",
386 type=int,
387 metavar='S',
388 help=('Run all items with the seed S. This implies '
389 '--reseed 1.'))
390
391 seedg.add_argument("--reseed", "-r",
392 type=int,
Rupert Swarbrickb7aacc12020-06-02 11:04:55 +0100393 metavar="N",
394 help=('Override any reseed value in the test '
395 'configuration and run each test N times, with '
396 'a new seed each time.'))
397
398 seedg.add_argument("--reseed-multiplier", "-rx",
399 type=int,
400 default=1,
401 metavar="N",
402 help=('Scale each reseed value in the test '
403 'configuration by N. This allows e.g. running '
404 'the tests 10 times as much as normal while '
405 'maintaining the ratio of numbers of runs '
406 'between different tests.'))
407
408 waveg = parser.add_argument_group('Dumping waves')
409
410 waveg.add_argument("--waves", "-w",
411 action='store_true',
412 help="Enable dumping of waves")
413
414 waveg.add_argument("-d",
415 "--dump",
416 choices=["fsdb", "shm", "vpd"],
417 help=("Format to dump waves for simulation. The default "
418 "format depends on the tool. With VCS, this "
419 "defaults to fsdb if Verdi is installed, else "
420 "vpd. With Xcelium, defaults to shm."))
421
422 waveg.add_argument("--max-waves", "-mw",
423 type=int,
424 default=5,
425 metavar="N",
426 help=('Only dump waves for the first N tests run. This '
427 'includes both tests scheduled for run and those '
428 'that are automatically rerun.'))
429
430 covg = parser.add_argument_group('Generating simulation coverage')
431
432 covg.add_argument("--cov", "-c",
433 action='store_true',
434 help="Enable collection of coverage data.")
435
436 covg.add_argument("--cov-merge-previous",
437 action='store_true',
438 help=('Only applicable with --cov. Merge any previous '
439 'coverage database directory with the new '
440 'coverage database.'))
441
442 covg.add_argument("--cov-analyze",
443 action='store_true',
444 help=('Rather than building or running any tests, '
445 'analyze the coverage from the last run.'))
446
447 pubg = parser.add_argument_group('Generating and publishing results')
448
449 pubg.add_argument("--map-full-testplan",
450 action='store_true',
451 help=("Show complete testplan annotated results "
452 "at the end."))
453
454 pubg.add_argument("--publish",
455 action='store_true',
456 help="Publish results to reports.opentitan.org.")
457
458 dvg = parser.add_argument_group('Controlling DVSim itself')
459
460 dvg.add_argument("--print-interval", "-pi",
461 type=int,
462 default=10,
463 metavar="N",
464 help="Print status every N seconds.")
465
466 dvg.add_argument("--verbose",
467 nargs="?",
468 choices=['default', 'debug'],
469 default=None,
470 const="default",
471 metavar="D",
472 help=('With no argument, print verbose dvsim tool '
473 'messages. With --verbose=debug, the volume of '
474 'messages is even higher.'))
475
476 dvg.add_argument("--dry-run", "-n",
477 action='store_true',
478 help=("Print dvsim tool messages but don't actually "
479 "run any command"))
480
Rupert Swarbrick536ab202020-06-09 16:37:12 +0100481 args = parser.parse_args()
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800482
483 if args.version:
484 print(version)
485 sys.exit()
486
Rupert Swarbricke83b55e2020-05-12 11:44:04 +0100487 # We want the --list argument to default to "all categories", but allow
488 # filtering. If args.list is None, then --list wasn't supplied. If it is
489 # [], then --list was supplied with no further arguments and we want to
490 # list all categories.
491 if args.list == []:
492 args.list = _LIST_CATEGORIES
493
Rupert Swarbrick536ab202020-06-09 16:37:12 +0100494 # Get max_parallel from environment if it wasn't specified on the command
495 # line.
496 args.max_parallel = resolve_max_parallel(args.max_parallel)
497 assert args.max_parallel > 0
498
499 return args
500
501
502def main():
503 args = parse_args()
504
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800505 # Add log level 'VERBOSE' between INFO and DEBUG
506 log.addLevelName(utils.VERBOSE, 'VERBOSE')
507
508 log_format = '%(levelname)s: [%(module)s] %(message)s'
509 log_level = log.INFO
Rupert Swarbrick06383682020-03-24 15:56:41 +0000510 if args.verbose == "default":
511 log_level = utils.VERBOSE
512 elif args.verbose == "debug":
513 log_level = log.DEBUG
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800514 log.basicConfig(format=log_format, level=log_level)
515
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800516 if not os.path.exists(args.cfg):
Michael Schaffner8ac6c4c2020-03-03 15:00:20 -0800517 log.fatal("Path to config file %s appears to be invalid.", args.cfg)
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800518 sys.exit(1)
519
Srikrishna Iyer4f0b0902020-01-25 02:28:47 -0800520 # If publishing results, then force full testplan mapping of results.
Rupert Swarbrick06383682020-03-24 15:56:41 +0000521 if args.publish:
522 args.map_full_testplan = True
Srikrishna Iyer4f0b0902020-01-25 02:28:47 -0800523
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800524 args.scratch_root = resolve_scratch_root(args.scratch_root)
525 args.branch = resolve_branch(args.branch)
526 args.cfg = os.path.abspath(args.cfg)
527
Srikrishna Iyer544da8d2020-01-14 23:51:41 -0800528 # Add timestamp to args that all downstream objects can use.
529 # Static variables - indicate timestamp.
Eunchan Kim46125cd2020-04-09 09:26:52 -0700530 ts_format_long = "%A %B %d %Y %I:%M:%S%p UTC"
Srikrishna Iyer544da8d2020-01-14 23:51:41 -0800531 ts_format = "%a.%m.%d.%y__%I.%M.%S%p"
Eunchan Kim46125cd2020-04-09 09:26:52 -0700532 curr_ts = datetime.datetime.utcnow()
Srikrishna Iyer544da8d2020-01-14 23:51:41 -0800533 timestamp_long = curr_ts.strftime(ts_format_long)
534 timestamp = curr_ts.strftime(ts_format)
535 setattr(args, "ts_format_long", ts_format_long)
536 setattr(args, "ts_format", ts_format)
537 setattr(args, "timestamp_long", timestamp_long)
538 setattr(args, "timestamp", timestamp)
539
540 # Register the seeds from command line with RunTest class.
541 Deploy.RunTest.seeds = args.seeds
Srikrishna Iyer96e54102020-03-12 22:46:50 -0700542 # If we are fixing a seed value, no point in tests having multiple reseeds.
Rupert Swarbrick06383682020-03-24 15:56:41 +0000543 if args.fixed_seed:
544 args.reseed = 1
Srikrishna Iyer96e54102020-03-12 22:46:50 -0700545 Deploy.RunTest.fixed_seed = args.fixed_seed
Srikrishna Iyer544da8d2020-01-14 23:51:41 -0800546
547 # Register the common deploy settings.
548 Deploy.Deploy.print_interval = args.print_interval
549 Deploy.Deploy.max_parallel = args.max_parallel
550 Deploy.Deploy.max_odirs = args.max_odirs
551
Srikrishna Iyer7cf7cad2020-01-08 11:32:53 -0800552 # Build infrastructure from hjson file and create the list of items to
553 # be deployed.
Udi Jonnalagaddaa122dda2020-03-13 16:56:45 -0700554
555 # Sets the project root directory: either specified from the command line
556 # or set by automatically assuming we are in a GitHub repository and
557 # automatically finding the root of this repository.
558 if args.proj_root:
559 proj_root = args.proj_root
560 else:
561 proj_root = get_proj_root()
562
Weicai Yangfc2ff3b2020-03-19 18:05:14 -0700563 global cfg
Rupert Swarbricke83b55e2020-05-12 11:44:04 +0100564 cfg = make_config(args, proj_root)
565
Weicai Yangfc2ff3b2020-03-19 18:05:14 -0700566 # Handle Ctrl-C exit.
567 signal(SIGINT, sigint_handler)
Udi Jonnalagaddaa122dda2020-03-13 16:56:45 -0700568
Srikrishna Iyer64009052020-01-13 11:27:39 -0800569 # List items available for run if --list switch is passed, and exit.
Rupert Swarbricke83b55e2020-05-12 11:44:04 +0100570 if args.list is not None:
Srikrishna Iyer64009052020-01-13 11:27:39 -0800571 cfg.print_list()
572 sys.exit(0)
573
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800574 # In simulation mode: if --cov-analyze switch is passed, then run the GUI
575 # tool.
576 if args.cov_analyze:
577 cfg.cov_analyze()
Srikrishna Iyer39ffebd2020-03-30 11:53:12 -0700578 cfg.deploy_objects()
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800579 sys.exit(0)
580
581 # Purge the scratch path if --purge option is set.
582 if args.purge:
583 cfg.purge()
Srikrishna Iyer544da8d2020-01-14 23:51:41 -0800584
Srikrishna Iyer7cf7cad2020-01-08 11:32:53 -0800585 # Deploy the builds and runs
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800586 if args.items != []:
587 # Create deploy objects.
588 cfg.create_deploy_objects()
589 cfg.deploy_objects()
Srikrishna Iyer7cf7cad2020-01-08 11:32:53 -0800590
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800591 # Generate results.
Weicai Yangfd2c22e2020-02-11 18:37:14 -0800592 cfg.gen_results()
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800593
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800594 # Publish results
Rupert Swarbrick06383682020-03-24 15:56:41 +0000595 if args.publish:
596 cfg.publish_results()
Weicai Yangfd2c22e2020-02-11 18:37:14 -0800597
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800598 else:
599 log.info("No items specified to be run.")
Srikrishna Iyer4f0b0902020-01-25 02:28:47 -0800600
Srikrishna Iyer442d8db2020-03-05 15:17:17 -0800601 # Exit with non-zero status if there were errors or failures.
602 if cfg.has_errors():
603 log.error("Errors were encountered in this run.")
604 sys.exit(1)
605
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800606
607if __name__ == '__main__':
608 main()