1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3"""
4Copyright (c) 2021 Huawei Device Co., Ltd.
5Licensed under the Apache License, Version 2.0 (the "License");
6you may not use this file except in compliance with the License.
7You may obtain a copy of the License at
8
9  http://www.apache.org/licenses/LICENSE-2.0
10
11Unless required by applicable law or agreed to in writing, software
12distributed under the License is distributed on an "AS IS" BASIS,
13WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14See the License for the specific language governing permissions and
15limitations under the License.
16"""
17
18import os
19import fnmatch
20import sys
21import argparse
22import json
23import platform
24import subprocess
25
26import distutils.dir_util as dir_util
27import distutils.file_util as file_util
28from distutils.errors import DistutilsError
29from string import Template
30
31# all sub system list, must be lowercase.
32_SUB_SYSTEM_LIST = [
33    "kernel",
34    "hiviewdfx",
35    "communication",
36    "security",
37    "update",
38    "sstsutils",
39    "commonlibrary",
40    "multimedia",
41    "hdf",
42    "ability",
43    "appexecfwk",
44    "distributed_schedule",
45    "startup",
46    "sensors",
47    "sample",
48    "iothardware",
49    "open_posix_testsuite",
50    "graphic",
51    "ace",
52    "applications",
53    "ai",
54    "global",
55    "telephony",
56    "dcts",
57    "distributeddatamgr",
58    "xts"
59]
60
61_NO_FILTE_SUB_SYSTEM_LIST = [
62    "appexecfwk",
63    "applications",
64    "kernel",
65    "open_posix_testsuite",
66    "sample",
67    "telephony",
68    "dcts",
69    "hiviewdfx",
70    "security",
71    "update",
72    "sstsutils",
73    "hdf",
74    "distributed_schedule",
75    "xts",
76    "commonlibrary",
77    "communication",
78    "distributeddatamgr",
79    "startup"
80]
81
82
83def main():
84    parser = argparse.ArgumentParser()
85    parser.add_argument('--method_name', help='', required=True)
86    parser.add_argument('--arguments', help='',
87                        required=True)  # format key=value#key=value
88    args = parser.parse_args()
89    this_module = sys.modules[__name__]
90    method = getattr(this_module, args.method_name)
91    arguments = {}
92    for argument in args.arguments.split("#"):
93        key_value = argument.strip().split("=")
94        if len(key_value) != 2:
95            raise ValueError(
96                "The arguments' format is 'key=value#key=value'. Wrong format:"
97                " {}".format(argument))
98        arguments.setdefault(key_value[0].strip(), key_value[1].strip())
99    method(**arguments)
100    return 0
101
102
103def read_file(input_file):
104    if not os.path.exists(input_file):
105        return ""
106
107    with open(input_file, 'r') as input_f:
108        content = input_f.read().strip()
109        return content
110
111
112def write_file(output_file, content, append):
113    file_dir = os.path.dirname(os.path.abspath(output_file))
114    if not os.path.exists(file_dir):
115        os.makedirs(file_dir)
116    mode = 'a+' if append else 'w'
117    with open(output_file, mode) as output_f:
118        output_f.write("%s\n" % content)
119
120
121def copy_file(output, sources="", source_dirs="", to_dir=True):
122    """
123    copy source files or source dir to output.
124    if sources is not empty, the output can be file(will be created
125    automatically)
126    or directory(must be exist).
127    :param output: If source_dirs is not empty, output must be directory.
128    :param sources: source files is separated by dot
129    :param source_dirs: source directory is separated by dot
130    :param to_dir: output is directory or not
131    :return:
132    """
133    if not sources and not source_dirs:
134        raise Exception(
135            "sources or source_dirs parameter must be specified one")
136    _output = output.strip()
137    _sources = sources.strip()
138    _source_dirs = source_dirs.strip()
139    _parent_output = os.path.dirname(_output)
140    try:
141        if to_dir and not os.path.exists(_output):
142            os.makedirs(_output)
143        if not to_dir and not os.path.exists(_parent_output):
144            os.makedirs(_parent_output)
145    except OSError:
146        if not os.path.isdir(_output):
147            raise
148    try:
149        if _sources:
150            _copy_files(_sources.split(","), _output)
151
152        if _source_dirs:
153            _copy_dir(_source_dirs.split(","), _output)
154    except DistutilsError:
155        print("ignore file exist error")
156    return 0
157
158
159def _copy_files(sources, output):
160    copy_set = set()
161    for source_file in sources:
162        source_file = source_file.strip()
163        if os.path.isfile(source_file) and os.path.exists(source_file):
164            # if same file name exist, add dir path
165            if os.path.basename(source_file) in copy_set:
166                new_output = os.path.join(output, os.path.dirname(source_file).
167                                          split(os.sep)[-1])
168                if not os.path.exists(new_output):
169                    os.makedirs(new_output)
170                file_util.copy_file(source_file, new_output)
171            else:
172                file_util.copy_file(source_file, output)
173            copy_set.add(os.path.basename(source_file))
174
175
176def _copy_dir(sources, output):
177    for source_file in sources:
178        source_file = source_file.strip()
179        if os.path.isdir(source_file):
180            dir_util.copy_tree(source_file, output)
181
182
183def gen_suite_out(suite_output_prefix, suite_names, out_suffix):
184    outputs = []
185    _suite_output_prefix = suite_output_prefix.strip()
186    _dirname_suffix = out_suffix.strip().rstrip(os.sep)
187    for suite in suite_names.split(","):
188        path = "%s%s/%s" % (
189            _suite_output_prefix, suite.strip(), _dirname_suffix)
190        outputs.append(path)
191        print(path)
192    return outputs
193
194
195def get_subsystem_name(path):
196    subsystem_name = ""
197    for subsystem in _SUB_SYSTEM_LIST:
198        subsystem_path = "/{}/".format(subsystem)
199        _path = path.lower()
200        if subsystem_path in _path:
201            subsystem_name = subsystem
202            break
203        subsystem_path = "/{}_lite/".format(subsystem)
204        if subsystem_path in _path:
205            subsystem_name = subsystem
206            break
207    sys.stdout.write(subsystem_name)
208    return subsystem_name
209
210
211def get_modulename_by_buildtarget(module_list_file, build_target):
212    if not os.path.exists(module_list_file):
213        return ""
214    with open(module_list_file, "r") as module_file:
215        module_info_data = json.load(module_file)
216    for module in module_info_data:
217        if module_info_data[module]["build_target_name"] == build_target:
218            sys.stdout.write(module)
219            return module
220    return ""
221
222
223def glob(path, filename_pattern):
224    files = []
225    for dir_path, _, files in os.walk(path):
226        for filename in fnmatch.filter(files, filename_pattern):
227            files.append(os.path.join(dir_path, filename))
228    return files
229
230
231def filter_by_subsystem(testsuites, product_json):
232    product_info = {}
233    filtered_features = []
234    subs_comps = {}
235    # parses product json to obtain all the subsystem name
236    if os.path.exists(product_json):
237        try:
238            with open(product_json, 'r') as product_info:
239                product_info = json.load(product_info)
240        except ValueError:
241            print("NO json object could be decoded.")
242        subsystem_info = product_info.get("subsystems")
243        for subsystem in subsystem_info:
244            subs_comps[subsystem.get("subsystem")] = \
245                subsystem.get("components", [])
246
247    feature_list = testsuites.split(",")
248    for feature in feature_list:
249        # if subsytem name match
250        subsystem = get_subsystem_name_no_output(feature)
251        if subsystem in _NO_FILTE_SUB_SYSTEM_LIST:
252            filtered_features.append(feature)
253            print(feature)
254        elif subsystem in subs_comps:
255            components = subs_comps.get(subsystem, [])
256            if check_component(feature, components):
257                filtered_features.append(feature)
258                print(feature)
259    return filtered_features
260
261
262def get_subsystem_name_no_output(path):
263    subsystem_name = ""
264    for subsystem in _SUB_SYSTEM_LIST:
265        subsystem_path = "/{}".format(subsystem)
266        _path = path.lower()
267        if subsystem_path in _path:
268            subsystem_name = subsystem
269            break
270        subsystem_path = "/{}_lite".format(subsystem)
271        if subsystem_path in _path:
272            subsystem_name = subsystem
273            break
274    return subsystem_name
275
276
277def check_component(path, components):
278    for component in components:
279        component_name = component.get("component", "")
280        if component_name != "kv_store_lite":
281            component_name = component_name.split('_lite')[0]
282        if component_name in path or "{}_hal".format(component_name) in path \
283                 or "{}_posix".format(component_name) in path:
284            return True
285    return False
286
287
288def get_python_cmd():
289    major, _, _ = platform.python_version_tuple()
290    if major == "3":
291        return "python"
292    else:
293        return "python3"
294
295
296def record_testmodule_info(build_target_name, module_name,
297                           subsystem_name, suite_out_dir, same_file=False):
298    if not build_target_name or not subsystem_name:
299        print(
300            'build_target_name or subsystem_name of testmodule "%s" '
301            'is invalid!' % module_name)
302        return
303    if same_file:
304        module_info_list_file = os.path.join(suite_out_dir, 'module_info.json')
305    else:
306        module_info_list_file = os.path.join(suite_out_dir,
307                                             '{}_module_info.json'.format
308                                             (build_target_name))
309    module_info_data = {}
310    if os.path.exists(module_info_list_file):
311        try:
312            with open(module_info_list_file, 'r') as module_file:
313                module_info_data = json.load(module_file)
314        except ValueError:
315            print("NO json object could be decoded but continue")
316    module_info = {'subsystem': subsystem_name,
317                   'build_target_name': build_target_name}
318    module_info_data[module_name] = module_info
319    with open(module_info_list_file, 'w') as out_file:
320        json.dump(module_info_data, out_file)
321
322
323def record_test_component_info(out_dir, version):
324    if not os.path.exists(out_dir):
325        os.makedirs(out_dir)
326    all_module_file = os.path.join(out_dir, 'module_info.json')
327    all_module_data = {}
328    for root, dirs, files in os.walk(out_dir):
329        for file in files:
330            if file.endswith("module_info.json"):
331                with open(os.path.join(root, file), 'r') as json_data:
332                    module_data = json.load(json_data)
333                    all_module_data.update(module_data)
334                os.remove(os.path.join(root, file))
335    with open(all_module_file, 'w') as out_file:
336        json.dump(all_module_data, out_file)
337
338    test_component_file = os.path.join(out_dir, 'test_component.json')
339    test_component_data = {'version': version, }
340    with open(test_component_file, 'w') as out_file:
341        json.dump(test_component_data, out_file)
342
343
344def get_target_modules(all_features):
345    feature_list = []
346    if all_features:
347        for feature in all_features.split(","):
348            if feature:
349                feature_list.append(feature)
350                print(feature)
351    return feature_list
352
353
354def cmd_popen(cmd):
355    proc = subprocess.Popen(cmd)
356    proc.wait()
357    ret_code = proc.returncode
358    if ret_code != 0:
359        raise Exception("{} failed, return code is {}".format(cmd, ret_code))
360
361
362def build_js_hap(project_path, out_put_dir, hap_name):
363    if not check_env():
364        return
365    gradle_dir = os.path.join(project_path, "gradle")
366    os.chdir(gradle_dir)
367    build_clean = ["gradle", "clean"]
368    cmd_popen(build_clean)
369    build_cmd = ["gradle", "entry:packageDebugHap"]
370    cmd_popen(build_cmd)
371    gralde_output_dir = os.path.join(gradle_dir, "entry", "build", "outputs")
372    if os.path.exists(gralde_output_dir):
373        for root, _, files in os.walk(gralde_output_dir):
374            for file in files:
375                if file.endswith(".hap"):
376                    file_util.copy_file(os.path.join(root, file),
377                                        os.path.join(out_put_dir.rstrip(','),
378                                                     hap_name))
379                    return
380
381
382
383def check_env():
384    """
385    check all the env for js hap build
386    return: return true if all env ready, otherwise return false
387    """
388    env_list = ['OHOS_SDK_HOME', 'NODE_HOME', 'GRADLE_HOME']
389    for env in env_list:
390        if not os.environ.get(env):
391            print("the env {} not set, skip build!".format(env))
392            return False
393    else:
394        return True
395
396
397def generate_allinone_testjson_by_template(tmpl_file, module_name, product_name, config_file):
398    if not os.path.exists(tmpl_file):
399        raise Exception(
400            "Can't find the Test.json or Test.tmpl in the "
401            "path %s " % os.path.dirname(
402                test_xml))
403    tmpl_content = read_file(tmpl_file)
404    values = {"module": module_name, "product": product_name}
405    xml_content = Template(tmpl_content).substitute(values)
406    write_file(config_file, xml_content, False)
407
408
409if __name__ == '__main__':
410    sys.exit(main())
411