blob: cc2c80f85893e42592b4c84a2887336dcb149aef [file] [log] [blame]
#!/usr/bin/env python3
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
r"""
Utility functions common across dvsim.
"""
import logging as log
import os
import pprint
import re
import shlex
import subprocess
import sys
import time
from collections import OrderedDict
import hjson
# For verbose logging
VERBOSE = 15
# Run a command and get the result. Exit with error if the command did not
# succeed. This is a simpler version of the run_cmd function below.
def run_cmd(cmd):
(status, output) = subprocess.getstatusoutput(cmd)
if status:
sys.stderr.write("cmd " + cmd + " returned with status " + str(status))
sys.exit(status)
return output
# Run a command with a specified timeout. If the command does not finish before
# the timeout, then it returns -1. Else it returns the command output. If the
# command fails, it throws an exception and returns the stderr.
def run_cmd_with_timeout(cmd, timeout=-1, exit_on_failure=1):
args = shlex.split(cmd)
p = subprocess.Popen(args,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
# If timeout is set, poll for the process to finish until timeout
result = ""
status = -1
if timeout == -1:
p.wait()
else:
start = time.time()
while time.time() - start < timeout:
if p.poll() is not None:
break
time.sleep(0.2)
# Capture output and status if cmd exited, else kill it
if p.poll() is not None:
result = p.communicate()[0]
status = p.returncode
else:
log.error("cmd \"%s\" timed out!", cmd)
p.kill()
if status != 0:
log.error("cmd \"%s\" exited with status %d", cmd, status)
if exit_on_failure == 1: sys.exit(status)
return (result, status)
def subst_wildcards(var, mdict, ignored_wildcards=[]):
'''
If var has wildcards specified within {..}, find and substitute them.
'''
def subst(wildcard, mdict):
if wildcard in mdict.keys(): return mdict[wildcard]
else: return None
if "{eval_cmd}" in var:
idx = var.find("{eval_cmd}") + 11
var = subst_wildcards(var[idx:], mdict, ignored_wildcards)
var = run_cmd(var)
else:
match = re.findall(r"{([A-Za-z0-9\_]+)}", var)
if len(match) > 0:
subst_list = {}
for item in match:
if item not in ignored_wildcards:
log.debug("Found wildcard in \"%s\": \"%s\"", var, item)
found = subst(item, mdict)
if found is not None:
if type(found) is str:
found = subst_wildcards(found, mdict,
ignored_wildcards)
if type(found) is bool:
found = int(found)
subst_list[item] = found
else:
# Check if the wildcard exists as an environment variable
env_var = os.environ.get(item)
if env_var is not None: subst_list[item] = env_var
else:
log.error(
"Substitution for the wildcard \"%s\" not found",
item)
sys.exit(1)
for item in subst_list:
var = var.replace("{" + item + "}", str(subst_list[item]))
return var
def find_and_substitute_wildcards(sub_dict, full_dict, ignored_wildcards=[]):
'''
Recursively find key values containing wildcards in sub_dict in full_dict
and return resolved sub_dict.
'''
for key in sub_dict.keys():
if type(sub_dict[key]) in [dict, OrderedDict]:
# Recursively call this funciton in sub-dicts
sub_dict[key] = find_and_substitute_wildcards(
sub_dict[key], full_dict, ignored_wildcards)
elif type(sub_dict[key]) is list:
sub_dict_key_values = list(sub_dict[key])
# Loop through the list of key's values and substitute each var
# in case it contains a wildcard
for i in range(len(sub_dict_key_values)):
if type(sub_dict_key_values[i]) in [dict, OrderedDict]:
# Recursively call this funciton in sub-dicts
sub_dict_key_values[i] = \
find_and_substitute_wildcards(sub_dict_key_values[i],
full_dict, ignored_wildcards)
elif type(sub_dict_key_values[i]) is str:
sub_dict_key_values[i] = subst_wildcards(
sub_dict_key_values[i], full_dict, ignored_wildcards)
# Set the substituted key values back
sub_dict[key] = sub_dict_key_values
elif type(sub_dict[key]) is str:
sub_dict[key] = subst_wildcards(sub_dict[key], full_dict,
ignored_wildcards)
return sub_dict