1e7e9171eSGeorge Keishing#!/usr/bin/env python3
23ba8ecdcSMichael Walsh
33ba8ecdcSMichael Walshr"""
4410b1787SMichael WalshThis module provides functions which are useful to plug-ins call-point programs that wish to make external
5410b1787SMichael Walshrobot program calls.
63ba8ecdcSMichael Walsh"""
73ba8ecdcSMichael Walsh
8e635ddc0SGeorge Keishingimport imp
920f38712SPatrick Williamsimport os
1020f38712SPatrick Williamsimport re
1120f38712SPatrick Williamsimport subprocess
1220f38712SPatrick Williamsimport sys
1320f38712SPatrick Williamsimport time
143ba8ecdcSMichael Walsh
1520f38712SPatrick Williamsimport gen_cmd as gc
1620f38712SPatrick Williamsimport gen_misc as gm
173ba8ecdcSMichael Walshimport gen_print as gp
183ba8ecdcSMichael Walshimport gen_valid as gv
193ba8ecdcSMichael Walsh
2020f38712SPatrick Williamsbase_path = (
2120f38712SPatrick Williams    os.path.dirname(os.path.dirname(imp.find_module("gen_robot_print")[1]))
2220f38712SPatrick Williams    + os.sep
2320f38712SPatrick Williams)
243ba8ecdcSMichael Walsh
253ba8ecdcSMichael Walsh
263ba8ecdcSMichael Walshdef init_robot_out_parms(extra_prefix=""):
273ba8ecdcSMichael Walsh    r"""
283ba8ecdcSMichael Walsh    Initialize robot output parms such as outputdir, output, etc.
293ba8ecdcSMichael Walsh
303ba8ecdcSMichael Walsh    This function will set global values for the following robot output parms.
313ba8ecdcSMichael Walsh
321f961b73SMichael Walsh    outputdir, output, log, report, loglevel, consolecolors, consolemarkers
333ba8ecdcSMichael Walsh
34410b1787SMichael Walsh    This function would typically be called prior to calling create_robot_cmd_string.
35f33140f6SMichael Walsh
36f33140f6SMichael Walsh    Description of argument(s):
37410b1787SMichael Walsh    extra_prefix                    An extra prefix to be appended to the default prefix for output file
38410b1787SMichael Walsh                                    names.
393ba8ecdcSMichael Walsh    """
403ba8ecdcSMichael Walsh
41a0ce75a7SMichael Walsh    gp.dprint_executing()
423ba8ecdcSMichael Walsh    AUTOBOOT_OPENBMC_NICKNAME = gm.get_mod_global("AUTOBOOT_OPENBMC_NICKNAME")
433ba8ecdcSMichael Walsh
443ba8ecdcSMichael Walsh    # Set values for call to create_robot_cmd_string.
45410b1787SMichael Walsh    # Environment variable TMP_ROBOT_DIR_PATH can be set by the user to indicate that robot-generated output
46410b1787SMichael Walsh    # should initially be written to the specified temporary directory and then moved to the normal output
47a0ce75a7SMichael Walsh    # location after completion.
4820f38712SPatrick Williams    outputdir = os.environ.get(
4920f38712SPatrick Williams        "TMP_ROBOT_DIR_PATH",
5020f38712SPatrick Williams        os.environ.get(
5120f38712SPatrick Williams            "STATUS_DIR_PATH", os.environ.get("HOME", ".") + "/status"
5220f38712SPatrick Williams        ),
5320f38712SPatrick Williams    )
54a0ce75a7SMichael Walsh    outputdir = gm.add_trailing_slash(outputdir)
553ba8ecdcSMichael Walsh    seconds = time.time()
563ba8ecdcSMichael Walsh    loc_time = time.localtime(seconds)
573ba8ecdcSMichael Walsh    time_string = time.strftime("%y%m%d.%H%M%S", loc_time)
5820f38712SPatrick Williams    file_prefix = (
5920f38712SPatrick Williams        AUTOBOOT_OPENBMC_NICKNAME + "." + extra_prefix + time_string + "."
6020f38712SPatrick Williams    )
61410b1787SMichael Walsh    # Environment variable SAVE_STATUS_POLICY governs when robot-generated output files (e.g. the log.html)
62410b1787SMichael Walsh    # will be moved from TMP_ROBOT_DIR_PATH to FFDC_DIR_PATH.  Valid values are "ALWAYS", "NEVER" and "FAIL".
63a0ce75a7SMichael Walsh    SAVE_STATUS_POLICY = os.environ.get("SAVE_STATUS_POLICY", "ALWAYS")
64a0ce75a7SMichael Walsh    if SAVE_STATUS_POLICY == "NEVER":
65a0ce75a7SMichael Walsh        output = "NONE"
66a0ce75a7SMichael Walsh        log = "NONE"
67a0ce75a7SMichael Walsh        report = "NONE"
68a0ce75a7SMichael Walsh    else:
693ba8ecdcSMichael Walsh        output = file_prefix + "output.xml"
703ba8ecdcSMichael Walsh        log = file_prefix + "log.html"
713ba8ecdcSMichael Walsh        report = file_prefix + "report.html"
723ba8ecdcSMichael Walsh    loglevel = "TRACE"
7320f38712SPatrick Williams    consolecolors = "off"
7420f38712SPatrick Williams    consolemarkers = "off"
753ba8ecdcSMichael Walsh
763ba8ecdcSMichael Walsh    # Make create_robot_cmd_string values global.
773ba8ecdcSMichael Walsh    gm.set_mod_global(outputdir)
783ba8ecdcSMichael Walsh    gm.set_mod_global(output)
793ba8ecdcSMichael Walsh    gm.set_mod_global(log)
803ba8ecdcSMichael Walsh    gm.set_mod_global(report)
813ba8ecdcSMichael Walsh    gm.set_mod_global(loglevel)
821f961b73SMichael Walsh    gm.set_mod_global(consolecolors)
831f961b73SMichael Walsh    gm.set_mod_global(consolemarkers)
841f961b73SMichael Walsh
8520f38712SPatrick Williams    return (
8620f38712SPatrick Williams        outputdir,
8720f38712SPatrick Williams        output,
8820f38712SPatrick Williams        log,
8920f38712SPatrick Williams        report,
9020f38712SPatrick Williams        loglevel,
9120f38712SPatrick Williams        consolecolors,
9220f38712SPatrick Williams        consolemarkers,
9320f38712SPatrick Williams    )
943ba8ecdcSMichael Walsh
953ba8ecdcSMichael Walsh
963ba8ecdcSMichael Walshdef init_robot_test_base_dir_path():
973ba8ecdcSMichael Walsh    r"""
98410b1787SMichael Walsh    Initialize and validate the environment variable, ROBOT_TEST_BASE_DIR_PATH and set corresponding global
99410b1787SMichael Walsh    variable ROBOT_TEST_RUNNING_FROM_SB.
1003ba8ecdcSMichael Walsh
101410b1787SMichael Walsh    If ROBOT_TEST_BASE_DIR_PATH is already set, this function will merely validate it.  This function will
102410b1787SMichael Walsh    also set environment variable ROBOT_TEST_RUNNING_FROM_SB when ROBOT_TEST_BASE_DIR_PATH is not pre-set.
1033ba8ecdcSMichael Walsh    """
1043ba8ecdcSMichael Walsh
1053ba8ecdcSMichael Walsh    # ROBOT_TEST_BASE_DIR_PATH will be set as follows:
106410b1787SMichael Walsh    # This function will determine whether we are running in a user sandbox or from a standard apolloxxx
107410b1787SMichael Walsh    # environment.
1083ba8ecdcSMichael Walsh    # - User sandbox:
109410b1787SMichael Walsh    # If there is a <developer's home dir>/git/openbmc-test-automation/, ROBOT_TEST_BASE_DIR_PATH will be
110410b1787SMichael Walsh    # set to that path.  Otherwise, we set it to <program dir path>/git/openbmc-test-automation/
1113ba8ecdcSMichael Walsh    # - Not in user sandbox:
112410b1787SMichael Walsh    #   ROBOT_TEST_BASE_DIR_PATH will be set to <program dir path>/git/openbmc-test-automation/
1133ba8ecdcSMichael Walsh
11420f38712SPatrick Williams    ROBOT_TEST_BASE_DIR_PATH = os.environ.get("ROBOT_TEST_BASE_DIR_PATH", "")
11520f38712SPatrick Williams    ROBOT_TEST_RUNNING_FROM_SB = int(
11620f38712SPatrick Williams        os.environ.get("ROBOT_TEST_RUNNING_FROM_SB", "0")
11720f38712SPatrick Williams    )
1183ba8ecdcSMichael Walsh    if ROBOT_TEST_BASE_DIR_PATH == "":
1193ba8ecdcSMichael Walsh        # ROBOT_TEST_BASE_DIR_PATH was not set by user/caller.
12020f38712SPatrick Williams        AUTOIPL_VERSION = os.environ.get("AUTOIPL_VERSION", "")
1213ba8ecdcSMichael Walsh        if AUTOIPL_VERSION == "":
1223ba8ecdcSMichael Walsh            ROBOT_TEST_BASE_DIR_PATH = base_path
1233ba8ecdcSMichael Walsh        else:
1243ba8ecdcSMichael Walsh            suffix = "git/openbmc-test-automation/"
1253ba8ecdcSMichael Walsh
126410b1787SMichael Walsh            # Determine whether we're running out of a developer sandbox or simply out of an apolloxxx/bin
127410b1787SMichael Walsh            # path.
12820f38712SPatrick Williams            shell_rc, out_buf = gc.shell_cmd(
12920f38712SPatrick Williams                "dirname $(which gen_print.py)",
13020f38712SPatrick Williams                quiet=(not debug),
13120f38712SPatrick Williams                print_output=0,
13220f38712SPatrick Williams            )
133bffaa1d5SMichael Walsh            executable_base_dir_path = os.path.realpath(out_buf.rstrip()) + "/"
13420f38712SPatrick Williams            apollo_dir_path = (
13520f38712SPatrick Williams                os.environ["AUTO_BASE_PATH"] + AUTOIPL_VERSION + "/bin/"
13620f38712SPatrick Williams            )
13720f38712SPatrick Williams            developer_home_dir_path = re.sub(
13820f38712SPatrick Williams                "/sandbox.*", "", executable_base_dir_path
13920f38712SPatrick Williams            )
14020f38712SPatrick Williams            developer_home_dir_path = gm.add_trailing_slash(
14120f38712SPatrick Williams                developer_home_dir_path
14220f38712SPatrick Williams            )
14320f38712SPatrick Williams            gp.dprint_vars(
14420f38712SPatrick Williams                executable_base_dir_path,
14520f38712SPatrick Williams                developer_home_dir_path,
14620f38712SPatrick Williams                apollo_dir_path,
14720f38712SPatrick Williams            )
1483ba8ecdcSMichael Walsh
1493ba8ecdcSMichael Walsh            ROBOT_TEST_RUNNING_FROM_SB = 0
1503ba8ecdcSMichael Walsh            if executable_base_dir_path != apollo_dir_path:
1513ba8ecdcSMichael Walsh                ROBOT_TEST_RUNNING_FROM_SB = 1
1523ba8ecdcSMichael Walsh                gp.dprint_vars(ROBOT_TEST_RUNNING_FROM_SB)
1533ba8ecdcSMichael Walsh                ROBOT_TEST_BASE_DIR_PATH = developer_home_dir_path + suffix
1543ba8ecdcSMichael Walsh                if not os.path.isdir(ROBOT_TEST_BASE_DIR_PATH):
15520f38712SPatrick Williams                    gp.dprint_timen(
15620f38712SPatrick Williams                        "NOTE: Sandbox directory "
15720f38712SPatrick Williams                        + ROBOT_TEST_BASE_DIR_PATH
15820f38712SPatrick Williams                        + " does not"
15920f38712SPatrick Williams                        + " exist."
16020f38712SPatrick Williams                    )
1613ba8ecdcSMichael Walsh                    # Fall back to the apollo dir path.
1623ba8ecdcSMichael Walsh                    ROBOT_TEST_BASE_DIR_PATH = apollo_dir_path + suffix
1633ba8ecdcSMichael Walsh            else:
1643ba8ecdcSMichael Walsh                # Use to the apollo dir path.
1653ba8ecdcSMichael Walsh                ROBOT_TEST_BASE_DIR_PATH = apollo_dir_path + suffix
1663ba8ecdcSMichael Walsh
1672ea965ceSMichael Walsh    gv.valid_value(ROBOT_TEST_BASE_DIR_PATH)
16820f38712SPatrick Williams    gp.dprint_vars(
16920f38712SPatrick Williams        ROBOT_TEST_RUNNING_FROM_SB,
17020f38712SPatrick Williams        ROBOT_TEST_BASE_DIR_PATH,
17120f38712SPatrick Williams    )
1722ea965ceSMichael Walsh    gv.valid_dir_path(ROBOT_TEST_BASE_DIR_PATH)
1733ba8ecdcSMichael Walsh
1743ba8ecdcSMichael Walsh    ROBOT_TEST_BASE_DIR_PATH = gm.add_trailing_slash(ROBOT_TEST_BASE_DIR_PATH)
1753ba8ecdcSMichael Walsh    gm.set_mod_global(ROBOT_TEST_BASE_DIR_PATH)
17620f38712SPatrick Williams    os.environ["ROBOT_TEST_BASE_DIR_PATH"] = ROBOT_TEST_BASE_DIR_PATH
1773ba8ecdcSMichael Walsh
1783ba8ecdcSMichael Walsh    gm.set_mod_global(ROBOT_TEST_RUNNING_FROM_SB)
17920f38712SPatrick Williams    os.environ["ROBOT_TEST_RUNNING_FROM_SB"] = str(ROBOT_TEST_RUNNING_FROM_SB)
1803ba8ecdcSMichael Walsh
1813ba8ecdcSMichael Walsh
18220f38712SPatrick Williamsraw_robot_file_search_path = (
18320f38712SPatrick Williams    "${ROBOT_TEST_BASE_DIR_PATH}:"
18420f38712SPatrick Williams    + "${ROBOT_TEST_BASE_DIR_PATH}tests:${ROBOT_TEST_BASE_DIR_PATH}extended:"
18520f38712SPatrick Williams    + "${ROBOT_TEST_BASE_DIR_PATH}scratch:${PATH}"
18620f38712SPatrick Williams)
1873ba8ecdcSMichael Walsh
1883ba8ecdcSMichael Walsh
1893ba8ecdcSMichael Walshdef init_robot_file_path(robot_file_path):
1903ba8ecdcSMichael Walsh    r"""
191410b1787SMichael Walsh    Determine full path name for the file path passed in robot_file_path and return it.
1923ba8ecdcSMichael Walsh
193410b1787SMichael Walsh    If robot_file_path contains a fully qualified path name, this function will verify that the file exists.
194410b1787SMichael Walsh    If robot_file_path contains a relative path, this function will search for the file and set
195410b1787SMichael Walsh    robot_file_path so that it contains the absolute path to the robot file.  This function will search for
196410b1787SMichael Walsh    the robot file using the raw_robot_file_search_path (defined above).  Note that if
197410b1787SMichael Walsh    ROBOT_TEST_BASE_DIR_PATH is not set, this function will call init_robot_test_base_dir_path to set it.
1983ba8ecdcSMichael Walsh
1993ba8ecdcSMichael Walsh    Description of arguments:
200410b1787SMichael Walsh    robot_file_path                 The absolute or relative path to a robot file.
2013ba8ecdcSMichael Walsh    """
2023ba8ecdcSMichael Walsh
2032ea965ceSMichael Walsh    gv.valid_value(robot_file_path)
2043ba8ecdcSMichael Walsh
2053ba8ecdcSMichael Walsh    try:
2063ba8ecdcSMichael Walsh        if ROBOT_TEST_BASE_DIR_PATH is NONE:
2073ba8ecdcSMichael Walsh            init_robot_test_base_dir_path()
2083ba8ecdcSMichael Walsh    except NameError:
2093ba8ecdcSMichael Walsh        init_robot_test_base_dir_path()
2103ba8ecdcSMichael Walsh
2113ba8ecdcSMichael Walsh    if not re.match(r".*\.(robot|py)$", robot_file_path):
2123ba8ecdcSMichael Walsh        # No suffix so we'll assign one of "\.robot".
2133ba8ecdcSMichael Walsh        robot_file_path = robot_file_path + ".robot"
2143ba8ecdcSMichael Walsh
2153ba8ecdcSMichael Walsh    abs_path = 0
2163ba8ecdcSMichael Walsh    if robot_file_path[0:1] == "/":
2173ba8ecdcSMichael Walsh        abs_path = 1
2183ba8ecdcSMichael Walsh
2193ba8ecdcSMichael Walsh    gp.dprint_vars(abs_path, robot_file_path)
2203ba8ecdcSMichael Walsh
2213ba8ecdcSMichael Walsh    if not abs_path:
22220f38712SPatrick Williams        cmd_buf = 'echo -n "' + raw_robot_file_search_path + '"'
22320f38712SPatrick Williams        shell_rc, out_buf = gc.shell_cmd(
22420f38712SPatrick Williams            cmd_buf, quiet=(not debug), print_output=0
22520f38712SPatrick Williams        )
2263ba8ecdcSMichael Walsh        robot_file_search_paths = out_buf
227a0ce75a7SMichael Walsh        gp.dprint_var(robot_file_search_paths)
22820f38712SPatrick Williams        robot_file_search_paths_list = robot_file_search_paths.split(":")
2293ba8ecdcSMichael Walsh        for search_path in robot_file_search_paths_list:
2303ba8ecdcSMichael Walsh            search_path = gm.add_trailing_slash(search_path)
2313ba8ecdcSMichael Walsh            candidate_file_path = search_path + robot_file_path
2323ba8ecdcSMichael Walsh            gp.dprint_var(candidate_file_path)
2333ba8ecdcSMichael Walsh            if os.path.isfile(candidate_file_path):
2343ba8ecdcSMichael Walsh                gp.dprint_timen("Found full path to " + robot_file_path + ".")
2353ba8ecdcSMichael Walsh                robot_file_path = candidate_file_path
2363ba8ecdcSMichael Walsh                break
2373ba8ecdcSMichael Walsh
2383ba8ecdcSMichael Walsh    gp.dprint_var(robot_file_path)
2392ea965ceSMichael Walsh    gv.valid_file_path(robot_file_path)
2403ba8ecdcSMichael Walsh
2413ba8ecdcSMichael Walsh    return robot_file_path
2423ba8ecdcSMichael Walsh
2433ba8ecdcSMichael Walsh
2443ba8ecdcSMichael Walshdef get_robot_parm_names():
2453ba8ecdcSMichael Walsh    r"""
246410b1787SMichael Walsh    Return a list containing all of the long parm names (e.g. --outputdir) supported by the robot program.
247410b1787SMichael Walsh    Double dashes are not included in the names returned.
2483ba8ecdcSMichael Walsh    """
2493ba8ecdcSMichael Walsh
25020f38712SPatrick Williams    cmd_buf = (
25120f38712SPatrick Williams        "robot -h | egrep "
25220f38712SPatrick Williams        + "'^([ ]\\-[a-zA-Z0-9])?[ ]+--[a-zA-Z0-9]+[ ]+' | sed -re"
25320f38712SPatrick Williams        + " s'/.*\\-\\-//g' -e s'/ .*//g' | sort -u"
25420f38712SPatrick Williams    )
255bffaa1d5SMichael Walsh    shell_rc, out_buf = gc.shell_cmd(cmd_buf, quiet=1, print_output=0)
2563ba8ecdcSMichael Walsh
2573ba8ecdcSMichael Walsh    return out_buf.split("\n")
2583ba8ecdcSMichael Walsh
2593ba8ecdcSMichael Walsh
2603ba8ecdcSMichael Walshdef create_robot_cmd_string(robot_file_path, *parms):
2613ba8ecdcSMichael Walsh    r"""
262410b1787SMichael Walsh    Create a robot command string and return it.  On failure, return an empty string.
2633ba8ecdcSMichael Walsh
2643ba8ecdcSMichael Walsh    Description of arguments:
2653ba8ecdcSMichael Walsh    robot_file_path                 The path to the robot file to be run.
266410b1787SMichael Walsh    parms                           The list of parms to be included in the command string.  The name of each
267410b1787SMichael Walsh                                    variable in this list must be the same as the name of the corresponding
268410b1787SMichael Walsh                                    parm.  This function figures out that name.  This function is also able
269410b1787SMichael Walsh                                    to distinguish robot parms (e.g. --outputdir) from robot program parms
270410b1787SMichael Walsh                                    (all other parms which will be passed as "-v PARM_NAME:parm_value")..
2713ba8ecdcSMichael Walsh
2723ba8ecdcSMichael Walsh    Example:
2733ba8ecdcSMichael Walsh
2743ba8ecdcSMichael Walsh    The following call to this function...
275410b1787SMichael Walsh    cmd_buf = create_robot_cmd_string("tools/start_sol_console.robot", OPENBMC_HOST, quiet, test_mode, debug,
276410b1787SMichael Walsh    outputdir, output, log, report)
2773ba8ecdcSMichael Walsh
2783ba8ecdcSMichael Walsh    Would return a string something like this.
2793ba8ecdcSMichael Walsh    robot -v OPENBMC_HOST:beye6 -v quiet:0 -v test_mode:1 -v debug:1
280410b1787SMichael Walsh    --outputdir=/gsa/ausgsa/projects/a/status --output=beye6.OS_Console.output.xml
281410b1787SMichael Walsh    --log=beye6.OS_Console.log.html --report=beye6.OS_Console.report.html tools/start_sol_console.robot
2823ba8ecdcSMichael Walsh    """
2833ba8ecdcSMichael Walsh
2843ba8ecdcSMichael Walsh    robot_file_path = init_robot_file_path(robot_file_path)
2853ba8ecdcSMichael Walsh
2863ba8ecdcSMichael Walsh    robot_parm_names = get_robot_parm_names()
2873ba8ecdcSMichael Walsh
2883ba8ecdcSMichael Walsh    robot_parm_list = []
2893ba8ecdcSMichael Walsh
2903ba8ecdcSMichael Walsh    stack_frame = 2
2913ba8ecdcSMichael Walsh    ix = 2
2923ba8ecdcSMichael Walsh    for arg in parms:
2933ba8ecdcSMichael Walsh        parm = arg
2943ba8ecdcSMichael Walsh        parm = gm.quote_bash_parm(gm.escape_bash_quotes(str(parm)))
2953ba8ecdcSMichael Walsh        var_name = gp.get_arg_name(None, ix, stack_frame)
2963ba8ecdcSMichael Walsh        if var_name in robot_parm_names:
2973ba8ecdcSMichael Walsh            p_string = "--" + var_name + "=" + str(parm)
2983ba8ecdcSMichael Walsh            robot_parm_list.append(p_string)
2993ba8ecdcSMichael Walsh        else:
3003ba8ecdcSMichael Walsh            p_string = "-v " + var_name + ":" + str(parm)
3013ba8ecdcSMichael Walsh            robot_parm_list.append(p_string)
3023ba8ecdcSMichael Walsh        ix += 1
3033ba8ecdcSMichael Walsh
30420f38712SPatrick Williams    robot_cmd_buf = (
30520f38712SPatrick Williams        "robot " + " ".join(robot_parm_list) + " " + robot_file_path
30620f38712SPatrick Williams    )
3073ba8ecdcSMichael Walsh
3083ba8ecdcSMichael Walsh    return robot_cmd_buf
3093ba8ecdcSMichael Walsh
3103ba8ecdcSMichael Walsh
311a0ce75a7SMichael Walsh# Global variables to aid in cleanup after running robot_cmd_fnc.
312a0ce75a7SMichael Walshgcr_last_robot_cmd_buf = ""
313a0ce75a7SMichael Walshgcr_last_robot_rc = 0
314a0ce75a7SMichael Walsh
315a0ce75a7SMichael Walsh
31620f38712SPatrick Williamsdef process_robot_output_files(robot_cmd_buf=None, robot_rc=None, gzip=None):
317a0ce75a7SMichael Walsh    r"""
318a0ce75a7SMichael Walsh    Process robot output files which can involve several operations:
319410b1787SMichael Walsh    - If the files are in a temporary location, using SAVE_STATUS_POLICY to decide whether to move them to a
320410b1787SMichael Walsh      permanent location or to delete them.
321a0ce75a7SMichael Walsh    - Gzipping them.
322a0ce75a7SMichael Walsh
323a0ce75a7SMichael Walsh    Description of argument(s):
324410b1787SMichael Walsh    robot_cmd_buf                   The complete command string used to invoke robot.
325410b1787SMichael Walsh    robot_rc                        The return code from running the robot command string.
326410b1787SMichael Walsh    gzip                            Indicates whether robot-generated output should be gzipped.
327a0ce75a7SMichael Walsh    """
328a0ce75a7SMichael Walsh
329a0ce75a7SMichael Walsh    robot_cmd_buf = gm.dft(robot_cmd_buf, gcr_last_robot_cmd_buf)
330a0ce75a7SMichael Walsh    robot_rc = gm.dft(robot_rc, gcr_last_robot_rc)
331f33140f6SMichael Walsh    gzip = gm.dft(gzip, int(os.environ.get("GZIP_ROBOT", "1")))
332a0ce75a7SMichael Walsh
333a0ce75a7SMichael Walsh    if robot_cmd_buf == "":
334410b1787SMichael Walsh        # This can legitimately occur if this function is called from an exit_function without the program
335410b1787SMichael Walsh        # having ever run robot_cmd_fnc.
336a0ce75a7SMichael Walsh        return
337a0ce75a7SMichael Walsh
338a0ce75a7SMichael Walsh    SAVE_STATUS_POLICY = os.environ.get("SAVE_STATUS_POLICY", "ALWAYS")
339a0ce75a7SMichael Walsh    gp.qprint_vars(SAVE_STATUS_POLICY)
340a0ce75a7SMichael Walsh
341410b1787SMichael Walsh    # When SAVE_STATUS_POLICY is "NEVER" robot output files don't even get generated.
342a0ce75a7SMichael Walsh    if SAVE_STATUS_POLICY == "NEVER":
343a0ce75a7SMichael Walsh        return
344a0ce75a7SMichael Walsh
345a0ce75a7SMichael Walsh    # Compose file_list based on robot command buffer passed in.
346a0ce75a7SMichael Walsh    robot_cmd_buf_dict = gc.parse_command_string(robot_cmd_buf)
34720f38712SPatrick Williams    outputdir = robot_cmd_buf_dict["outputdir"]
348a0ce75a7SMichael Walsh    outputdir = gm.add_trailing_slash(outputdir)
34920f38712SPatrick Williams    file_list = (
35020f38712SPatrick Williams        outputdir
35120f38712SPatrick Williams        + robot_cmd_buf_dict["output"]
35220f38712SPatrick Williams        + " "
35320f38712SPatrick Williams        + outputdir
35420f38712SPatrick Williams        + robot_cmd_buf_dict["log"]
35520f38712SPatrick Williams        + " "
35620f38712SPatrick Williams        + outputdir
35720f38712SPatrick Williams        + robot_cmd_buf_dict["report"]
35820f38712SPatrick Williams    )
359a0ce75a7SMichael Walsh
360a0ce75a7SMichael Walsh    # Double checking that files are present.
36120f38712SPatrick Williams    shell_rc, out_buf = gc.shell_cmd(
36220f38712SPatrick Williams        "ls -1 " + file_list + " 2>/dev/null", show_err=0
36320f38712SPatrick Williams    )
364a0ce75a7SMichael Walsh    file_list = re.sub("\n", " ", out_buf.rstrip("\n"))
365a0ce75a7SMichael Walsh
366a0ce75a7SMichael Walsh    if file_list == "":
36720f38712SPatrick Williams        gp.qprint_timen(
36820f38712SPatrick Williams            "No robot output files were found in " + outputdir + "."
36920f38712SPatrick Williams        )
370a0ce75a7SMichael Walsh        return
3710d5f96a4SMichael Walsh    gp.qprint_var(robot_rc, gp.hexa())
372a0ce75a7SMichael Walsh    if SAVE_STATUS_POLICY == "FAIL" and robot_rc == 0:
37320f38712SPatrick Williams        gp.qprint_timen(
37420f38712SPatrick Williams            "The call to robot produced no failures."
37520f38712SPatrick Williams            + "  Deleting robot output files."
37620f38712SPatrick Williams        )
377a0ce75a7SMichael Walsh        gc.shell_cmd("rm -rf " + file_list)
378a0ce75a7SMichael Walsh        return
379a0ce75a7SMichael Walsh
380a0ce75a7SMichael Walsh    if gzip:
381e53dfec9SMichael Walsh        gc.shell_cmd("gzip -f " + file_list)
382a0ce75a7SMichael Walsh        # Update the values in file_list.
383a0ce75a7SMichael Walsh        file_list = re.sub(" ", ".gz ", file_list) + ".gz"
384a0ce75a7SMichael Walsh
385410b1787SMichael Walsh    # It TMP_ROBOT_DIR_PATH is set, it means the caller wanted the robot output initially directed to
386410b1787SMichael Walsh    # TMP_ROBOT_DIR_PATH but later moved to FFDC_DIR_PATH.  Otherwise, we're done.
387a0ce75a7SMichael Walsh
388e7e9171eSGeorge Keishing    if os.environ.get("TMP_ROBOT_DIR_PATH", "") == "":
389a0ce75a7SMichael Walsh        return
390a0ce75a7SMichael Walsh
391410b1787SMichael Walsh    # We're directing these to the FFDC dir path so that they'll be subjected to FFDC cleanup.
39220f38712SPatrick Williams    target_dir_path = os.environ.get(
39320f38712SPatrick Williams        "FFDC_DIR_PATH", os.environ.get("HOME", ".") + "/ffdc"
39420f38712SPatrick Williams    )
395a0ce75a7SMichael Walsh    target_dir_path = gm.add_trailing_slash(target_dir_path)
396a0ce75a7SMichael Walsh
39720f38712SPatrick Williams    targ_file_list = [
39820f38712SPatrick Williams        re.sub(".*/", target_dir_path, x) for x in file_list.split(" ")
39920f38712SPatrick Williams    ]
400a0ce75a7SMichael Walsh
40120f38712SPatrick Williams    gc.shell_cmd(
40220f38712SPatrick Williams        "mv " + file_list + " " + target_dir_path + " >/dev/null", time_out=600
40320f38712SPatrick Williams    )
404a0ce75a7SMichael Walsh
405a0ce75a7SMichael Walsh    gp.qprint_timen("New robot log file locations:")
40620f38712SPatrick Williams    gp.qprintn("\n".join(targ_file_list))
407a0ce75a7SMichael Walsh
408a0ce75a7SMichael Walsh
40920f38712SPatrick Williamsdef robot_cmd_fnc(
41020f38712SPatrick Williams    robot_cmd_buf,
41120f38712SPatrick Williams    robot_jail=os.environ.get("ROBOT_JAIL", ""),
41220f38712SPatrick Williams    quiet=None,
41320f38712SPatrick Williams    test_mode=0,
41420f38712SPatrick Williams):
4153ba8ecdcSMichael Walsh    r"""
4163ba8ecdcSMichael Walsh    Run the robot command string.
4173ba8ecdcSMichael Walsh
418410b1787SMichael Walsh    This function will set the various PATH variables correctly so that you are running the proper version of
419410b1787SMichael Walsh    all imported files, etc.
4203ba8ecdcSMichael Walsh
4213ba8ecdcSMichael Walsh    Description of argument(s):
4223ba8ecdcSMichael Walsh    robot_cmd_buf                   The complete robot command string.
423410b1787SMichael Walsh    robot_jail                      Indicates that this is to run in "robot jail" meaning without visibility
424410b1787SMichael Walsh                                    to any apolloxxx import files, programs, etc.
4258dc99a36SMichael Walsh    test_mode                       If test_mode is set, this function will not actually run the command.
4263ba8ecdcSMichael Walsh    """
4273ba8ecdcSMichael Walsh
42820f38712SPatrick Williams    quiet = int(gm.dft(quiet, gp.get_stack_var("quiet", 0)))
4292ea965ceSMichael Walsh    gv.valid_value(robot_cmd_buf)
4303ba8ecdcSMichael Walsh
431a0ce75a7SMichael Walsh    # Set global variables to aid in cleanup with process_robot_output_files.
432a0ce75a7SMichael Walsh    global gcr_last_robot_cmd_buf
433a0ce75a7SMichael Walsh    global gcr_last_robot_rc
434a0ce75a7SMichael Walsh    gcr_last_robot_cmd_buf = robot_cmd_buf
435a0ce75a7SMichael Walsh
4363ba8ecdcSMichael Walsh    # Get globals set by init_robot_test_base_dir_path().
4373ba8ecdcSMichael Walsh    module = sys.modules["__main__"]
4383ba8ecdcSMichael Walsh    try:
4393ba8ecdcSMichael Walsh        ROBOT_TEST_BASE_DIR_PATH = getattr(module, "ROBOT_TEST_BASE_DIR_PATH")
4403ba8ecdcSMichael Walsh    except NameError:
4413ba8ecdcSMichael Walsh        init_robot_test_base_dir_path()
4423ba8ecdcSMichael Walsh        ROBOT_TEST_BASE_DIR_PATH = getattr(module, "ROBOT_TEST_BASE_DIR_PATH")
4433ba8ecdcSMichael Walsh
44420f38712SPatrick Williams    ROBOT_TEST_RUNNING_FROM_SB = gm.get_mod_global(
44520f38712SPatrick Williams        "ROBOT_TEST_RUNNING_FROM_SB"
44620f38712SPatrick Williams    )
4473ba8ecdcSMichael Walsh
4483ba8ecdcSMichael Walsh    if robot_jail == "":
4493ba8ecdcSMichael Walsh        if ROBOT_TEST_RUNNING_FROM_SB:
4503ba8ecdcSMichael Walsh            robot_jail = 0
4513ba8ecdcSMichael Walsh        else:
4523ba8ecdcSMichael Walsh            robot_jail = 1
4533ba8ecdcSMichael Walsh
4543ba8ecdcSMichael Walsh    robot_jail = int(robot_jail)
45520f38712SPatrick Williams    ROBOT_JAIL = os.environ.get("ROBOT_JAIL", "")
45620f38712SPatrick Williams    gp.dprint_vars(
45720f38712SPatrick Williams        ROBOT_TEST_BASE_DIR_PATH,
45820f38712SPatrick Williams        ROBOT_TEST_RUNNING_FROM_SB,
45920f38712SPatrick Williams        ROBOT_JAIL,
46020f38712SPatrick Williams        robot_jail,
46120f38712SPatrick Williams    )
4623ba8ecdcSMichael Walsh
4633ba8ecdcSMichael Walsh    # Save PATH and PYTHONPATH to be restored later.
4643ba8ecdcSMichael Walsh    os.environ["SAVED_PYTHONPATH"] = os.environ.get("PYTHONPATH", "")
4653ba8ecdcSMichael Walsh    os.environ["SAVED_PATH"] = os.environ.get("PATH", "")
4663ba8ecdcSMichael Walsh
4673ba8ecdcSMichael Walsh    if robot_jail:
468410b1787SMichael Walsh        # Make sure required programs like python and robot can be found in the new restricted PATH.
469a5d29bcaSMichael Walsh        required_programs = "python robot"
470410b1787SMichael Walsh        # It is expected that there will be a "python" program in the tool base bin path which is really a
471410b1787SMichael Walsh        # link to select_version.  Ditto for "robot".  Call each with the --print_only option to get the
472410b1787SMichael Walsh        # paths to the "real" programs.
47320f38712SPatrick Williams        cmd_buf = (
47420f38712SPatrick Williams            "for program in "
47520f38712SPatrick Williams            + required_programs
476a5d29bcaSMichael Walsh            + " ; do dirname $(${program} --print_only) ; done 2>/dev/null"
47720f38712SPatrick Williams        )
478a5d29bcaSMichael Walsh        rc, out_buf = gc.shell_cmd(cmd_buf, quiet=1, print_output=0)
4793ba8ecdcSMichael Walsh        PYTHONPATH = ROBOT_TEST_BASE_DIR_PATH + "lib"
4803ba8ecdcSMichael Walsh        NEW_PATH_LIST = [ROBOT_TEST_BASE_DIR_PATH + "bin"]
481a5d29bcaSMichael Walsh        NEW_PATH_LIST.extend(list(set(out_buf.rstrip("\n").split("\n"))))
48220f38712SPatrick Williams        NEW_PATH_LIST.extend(
48320f38712SPatrick Williams            [
48420f38712SPatrick Williams                "/usr/local/sbin",
48520f38712SPatrick Williams                "/usr/local/bin",
48620f38712SPatrick Williams                "/usr/sbin",
48720f38712SPatrick Williams                "/usr/bin",
48820f38712SPatrick Williams                "/sbin",
48920f38712SPatrick Williams                "/bin",
49020f38712SPatrick Williams            ]
49120f38712SPatrick Williams        )
4923ba8ecdcSMichael Walsh        PATH = ":".join(NEW_PATH_LIST)
4933ba8ecdcSMichael Walsh    else:
49420f38712SPatrick Williams        PYTHONPATH = (
49520f38712SPatrick Williams            os.environ.get("PYTHONPATH", "")
49620f38712SPatrick Williams            + ":"
49720f38712SPatrick Williams            + ROBOT_TEST_BASE_DIR_PATH
49820f38712SPatrick Williams            + "lib"
49920f38712SPatrick Williams        )
50020f38712SPatrick Williams        PATH = (
501*12de0947SGeorge Keishing            os.environ.get("PATH", "") + ":" + ROBOT_TEST_BASE_DIR_PATH + "bin"
50220f38712SPatrick Williams        )
5033ba8ecdcSMichael Walsh
50420f38712SPatrick Williams    os.environ["PYTHONPATH"] = PYTHONPATH
50520f38712SPatrick Williams    os.environ["PATH"] = PATH
5063ba8ecdcSMichael Walsh    gp.dprint_vars(PATH, PYTHONPATH)
5073ba8ecdcSMichael Walsh
50820f38712SPatrick Williams    os.environ["FFDC_DIR_PATH_STYLE"] = os.environ.get(
50920f38712SPatrick Williams        "FFDC_DIR_PATH_STYLE", "1"
51020f38712SPatrick Williams    )
5113ba8ecdcSMichael Walsh    gp.qpissuing(robot_cmd_buf, test_mode)
5123ba8ecdcSMichael Walsh    if test_mode:
5133ba8ecdcSMichael Walsh        os.environ["PATH"] = os.environ.get("SAVED_PATH", "")
5143ba8ecdcSMichael Walsh        os.environ["PYTHONPATH"] = os.environ.get("SAVED_PYTHONPATH", "")
5153ba8ecdcSMichael Walsh        return True
5163ba8ecdcSMichael Walsh
5173ba8ecdcSMichael Walsh    if quiet:
51820f38712SPatrick Williams        DEVNULL = open(os.devnull, "wb")
5193ba8ecdcSMichael Walsh        stdout = DEVNULL
5203ba8ecdcSMichael Walsh    else:
5213ba8ecdcSMichael Walsh        stdout = None
5223ba8ecdcSMichael Walsh    sub_proc = subprocess.Popen(robot_cmd_buf, stdout=stdout, shell=True)
5233ba8ecdcSMichael Walsh    sub_proc.communicate()
5243ba8ecdcSMichael Walsh    shell_rc = sub_proc.returncode
525a0ce75a7SMichael Walsh    os.environ["PATH"] = os.environ.get("SAVED_PATH", "")
526a0ce75a7SMichael Walsh    os.environ["PYTHONPATH"] = os.environ.get("SAVED_PYTHONPATH", "")
527a0ce75a7SMichael Walsh    gcr_last_robot_rc = shell_rc
528a0ce75a7SMichael Walsh    process_robot_output_files()
5293ba8ecdcSMichael Walsh    if shell_rc != 0:
5300d5f96a4SMichael Walsh        gp.print_var(shell_rc, gp.hexa())
5313ba8ecdcSMichael Walsh        return False
5323ba8ecdcSMichael Walsh
5333ba8ecdcSMichael Walsh    return True
534