• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2#coding: utf-8
3
4"""
5Copyright (c) 2021-2022 Huawei Device Co., Ltd.
6Licensed under the Apache License, Version 2.0 (the "License");
7you may not use this file except in compliance with the License.
8You may obtain a copy of the License at
9
10    http://www.apache.org/licenses/LICENSE-2.0
11
12Unless required by applicable law or agreed to in writing, software
13distributed under the License is distributed on an "AS IS" BASIS,
14WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15See the License for the specific language governing permissions and
16limitations under the License.
17
18Description: run script
19    expect_output will get run result,
20    expect_sub_output will catch pivotal sub output,
21    expect_file will get print string
22"""
23
24import argparse
25import os
26import subprocess
27import sys
28import time
29
30
31def get_env_path_from_rsp(script_file: str) -> list:
32    """get env path from response file recursively."""
33    rsp_file = "{0}{1}".format(script_file, ".rsp")
34    if not os.path.exists(rsp_file):
35        print(
36            "File \"{}\" does not exist!\n" \
37            "This indicates that its related shared_library is not compiled by this project, but there is an " \
38            "executable or shared_library depend on its related shared_library!".format(rsp_file))
39        sys.exit(1)
40
41    rsp_info_list = []
42    with open(rsp_file, "r") as fi:
43        rsp_info_str = fi.read()
44        rsp_info_list = rsp_info_str.split(" ")
45
46    env_path_list = []
47    for element in rsp_info_list:
48        if element.endswith(".so") or element.endswith(".dll"):
49            env_path_list.extend(get_env_path_from_rsp(element))
50            env_path_list.append(os.path.dirname(element))
51    return env_path_list
52
53
54def get_command_and_env_path(args: object) -> [str, str]:
55    """get command and environment path from args for running excutable."""
56    env_path_list = list(set(get_env_path_from_rsp(args.script_file)))
57    env_path_list.append(args.clang_lib_path)
58    env_path = ":".join(env_path_list)
59    if args.qemu_binary_path:
60        if not os.path.exists(args.qemu_binary_path):
61            print("Have you set up environment for running executables with qemu?\n" \
62                "If not, get set-up steps from https://gitee.com/ark_standalone_build/docs ," \
63                " append your build command of ark.py with option \"--clean-continue\"," \
64                " and execute the appended command after setting up the environment.\n" \
65                "If yes, the environment settings for qemu on your host machine may be different from what the link" \
66                " above shows, it is suggested to match your local environment settings with what the link shows.")
67            sys.exit(1)
68        cmd = \
69            "{}".format(args.qemu_binary_path) + \
70            " -L {}".format(args.qemu_ld_prefix) + \
71            " -E LD_LIBRARY_PATH={}".format(env_path) + \
72            " {}".format(args.script_file)
73    else:
74        cmd = "{}".format(args.script_file)
75    cmd += " {}".format(args.script_options) if args.script_options else ""
76    cmd += " {}".format(args.script_args) if args.script_args else ""
77    return [cmd, env_path]
78
79
80def parse_args() -> object:
81    """parse arguments."""
82    parser = argparse.ArgumentParser()
83    parser.add_argument('--script-file', help='execute script file')
84    parser.add_argument('--script-options', help='execute script options')
85    parser.add_argument('--script-args', help='args of script')
86    parser.add_argument('--expect-output', help='expect output')
87    parser.add_argument('--expect-sub-output', help='expect sub output')
88    parser.add_argument('--expect-file', help='expect file')
89    parser.add_argument('--env-path', help='LD_LIBRARY_PATH env')
90    parser.add_argument('--timeout-limit', help='timeout limit')
91    parser.add_argument('--clang-lib-path', help='part for LD_LIBRARY_PATH, it is not in .rsp file')
92    parser.add_argument('--qemu-binary-path', help='path to qemu binary, run executable with qemu if assigned')
93    parser.add_argument('--qemu-ld-prefix', help='elf interpreter prefix')
94    args = parser.parse_args()
95    return args
96
97
98def process_open(args: object) -> [str, object]:
99    """get command and open subprocess."""
100    if args.env_path:
101        # use the given env-path
102        cmd = args.script_file
103        cmd += " {}".format(args.script_options) if args.script_options else ""
104        cmd += " {}".format(args.script_args) if args.script_args else ""
105        # process for running executable directly
106        subp = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
107            env={'LD_LIBRARY_PATH': str(args.env_path)})
108    else:
109        # get env-path from response file recursively
110        [cmd, env_path] = get_command_and_env_path(args)
111        if args.qemu_binary_path:
112            # process for running executable with qemu
113            subp = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
114        else:
115            # process for running executable directly
116            subp = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
117                env={'LD_LIBRARY_PATH': str(env_path)})
118    return [cmd, subp]
119
120
121def judge_output(args: object):
122    """run executable and judge is success or not."""
123    start_time = time.time()
124    [cmd, subp] = process_open(args)
125    timeout_limit = int(args.timeout_limit) if args.timeout_limit else 150  # units: s
126
127    try:
128        out, err = subp.communicate(timeout=timeout_limit)
129    except subprocess.TimeoutExpired:
130        raise RuntimeError('Run [', cmd, '] timeout, timeout_limit = ', timeout_limit, 's')
131
132    if args.expect_output:
133        returncode = str(subp.returncode)
134        if returncode != args.expect_output:
135            out_str = out.decode('UTF-8')
136            err_str = err.decode('UTF-8')
137            print(out_str)
138            print(err_str)
139            print(">>>>> Expect return: [" + args.expect_output \
140                + "]\n>>>>> But got: [" + returncode + "]")
141            raise RuntimeError("Run [" + cmd + "] failed!")
142    elif args.expect_sub_output:
143        out_str = out.decode('UTF-8')
144        if out_str.find(args.expect_sub_output) == -1:
145            out_str = out.decode('UTF-8')
146            print(out_str)
147            print(">>>>> Expect contain: [" + args.expect_sub_output \
148                + "]\n>>>>> But got: [" + out_str + "]")
149            raise RuntimeError("Run [" + cmd + "] failed!")
150    elif args.expect_file:
151        with open(args.expect_file, mode='r') as file:
152            # skip license header
153            expect_output = ''.join(file.readlines()[13:])
154            file.close()
155            out_str = out.decode('UTF-8')
156            if out_str != expect_output:
157                err_str = err.decode('UTF-8')
158                print(err_str)
159                print(">>>>> Expect : [" + expect_output \
160                    + "]\n>>>>> But got: [" + out_str + "]")
161                raise RuntimeError("Run [" + cmd + "] failed!")
162    else:
163        raise RuntimeError("Run [" + cmd + "] with no expect !")
164
165    print("Run [" + cmd + "] success!")
166    print("used: %.5f seconds" % (time.time() - start_time))
167
168
169if __name__ == '__main__':
170    input_args = parse_args()
171    judge_output(input_args)
172