• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3"""
4Copyright (c) 2020-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
18
19import os
20import sys
21import argparse
22import re
23import subprocess
24import xml.dom.minidom
25from xml.parsers.expat import ExpatError
26from string import Template
27import utils
28import json
29import shutil
30import glob
31import stat
32
33
34XTS_RESOURCE_ROOT = 'ivbxfj`qspqsjfubsz0sftpvsdf'
35
36
37def _get_xts_rootpath(project_path):
38    if project_path is not None:
39        return project_path[0:project_path.find('/xts/') + len('/xts/')]
40    raise ValueError('Illegal xts project path ' + project_path)
41
42
43def _get_subsystem_name(project_path):
44    if '/hits/' in  project_path:
45        index0 = project_path.find('/hits/') + len('/hits/')
46    elif '/acts/' in  project_path:
47        index0 = project_path.find('/acts/') + len('/acts/')
48    else:
49        raise ValueError('Illegal xts project path ' + project_path)
50    index1 = project_path.find('/', index0)
51    return project_path[index0:index1]
52
53
54def _get_resource_rootpath(project_path):
55    xts_root = _get_xts_rootpath(project_path)
56    resource_reldir = ''.join(chr(ord(ch) - 1) for ch in XTS_RESOURCE_ROOT)
57    return os.path.join(xts_root, resource_reldir)
58
59
60class XDeviceBuilder:
61    """
62    To build XTS as an egg package
63    @arguments(project_dir, output_dirs)
64    """
65
66    def __init__(self, arguments):
67        parser = argparse.ArgumentParser()
68        parser.add_argument('--source_dir', help='', required=True)
69        parser.add_argument('--configs_dir', help='', required=False)
70        parser.add_argument('--resources_dir', help='', required=False)
71        parser.add_argument('--suite_out_dir', help='', required=True)
72        self.args = parser.parse_args(arguments)
73
74    def build_xdevice(self):
75        """
76        build xdevice package
77        :return:
78        """
79        extension_dir = os.path.join(self.args.source_dir, 'extension')
80        gen_dir0 = os.path.join(self.args.source_dir, 'dist')
81        gen_dir1 = os.path.join(extension_dir, 'dist')
82        shutil.rmtree(gen_dir0, ignore_errors=True)
83        shutil.rmtree(gen_dir1, ignore_errors=True)
84        command0 = ["python", "setup.py", "sdist"]
85        command1 = ["python", "setup.py", "sdist"]
86        try:
87            subprocess.check_call(command0, cwd=self.args.source_dir)
88            subprocess.check_call(command1, cwd=extension_dir)
89        except subprocess.CalledProcessError as exc:
90            print('returncode: {} cmd: {} output: {}'.format(
91                  exc.returncode, exc.cmd, exc.output))
92
93        run_scripts = ",".join(
94            [os.path.join(self.args.source_dir, "run.bat"),
95             os.path.join(self.args.source_dir, "run.sh")])
96
97        dist_tools_dir = os.path.join(self.args.suite_out_dir, 'tools')
98        utils.copy_file(output=dist_tools_dir, source_dirs=gen_dir0,
99                        to_dir=True)
100        utils.copy_file(output=dist_tools_dir, source_dirs=gen_dir1,
101                        to_dir=True)
102        utils.copy_file(output=self.args.suite_out_dir, sources=run_scripts,
103                        to_dir=True)
104
105        if self.args.configs_dir:
106            dist_configs_dir = os.path.join(self.args.suite_out_dir, 'config')
107            utils.copy_file(output=dist_configs_dir,
108                            source_dirs=self.args.configs_dir, to_dir=True)
109        if self.args.resources_dir:
110            dist_resources_dir = os.path.join(self.args.suite_out_dir,
111                                              'resource')
112            utils.copy_file(output=dist_resources_dir,
113                            source_dirs=self.args.resources_dir, to_dir=True)
114
115
116class SuiteArchiveBuilder:
117    def __init__(self, arguments):
118        self.module_info_dir = None
119        self.arguments = arguments
120
121    def archive_suite(self):
122        parser = argparse.ArgumentParser()
123        parser.add_argument('--suite_path', help='', required=True)
124        parser.add_argument('--prebuilts_resource', help='', required=True)
125        parser.add_argument('--suite_archive_dir', help='', required=True)
126        parser.add_argument('--make_archive', help='', required=True)
127        args = parser.parse_args(self.arguments)
128
129        if not args.make_archive.lower() == 'true':
130            print('make archive disabled')
131            return 0
132
133        suite_path = args.suite_path
134        if not os.path.isdir(suite_path):
135            raise Exception("[%s] does not exist" % suite_path)
136
137        copyfiles = args.prebuilts_resource.split(",")
138        for file_path in copyfiles:
139            subprocess.call(["cp", "-rf", file_path, suite_path])
140
141        archive_name = os.path.basename(suite_path)
142        archive_root_path = args.suite_archive_dir
143        if not os.path.isdir(archive_root_path):
144            os.mkdir(archive_root_path)
145        # remove the extra output of target "java_prebuilt"
146        # such as ztest-tradefed-common.interface.jar
147        subprocess.call(["find", suite_path, "-name", "*.interface.jar",
148                        "-exec", "rm", "{}", "+"])
149        shutil.make_archive(os.path.join(archive_root_path, archive_name),
150                            "zip", suite_path)
151        return 0
152
153
154class SuiteModuleWithTestbundleBuilder:
155
156    def __init__(self, arguments):
157        self.arguments = arguments
158        self.args = None
159
160    def build_module_with_testbundle(self):
161        parser = argparse.ArgumentParser()
162        parser.add_argument('--build_gen_dir', help='', required=True)
163        parser.add_argument('--build_target_name', help='', required=True)
164        parser.add_argument('--subsystem_name', help='',
165                            required=False)
166        parser.add_argument('--buildgen_testfile', help='', required=True)
167        parser.add_argument('--project_path', help='', required=True)
168        parser.add_argument('--test_xml', help='', required=False)
169        parser.add_argument('--project_type', help='', required=True)
170        parser.add_argument('--suite_out_dir', help='', required=True)
171        parser.add_argument('--archive_testfile', help='', required=True)
172        parser.add_argument('--apilibrary_deps', help='', required=False)
173        parser.add_argument('--test_files', help='', required=False)
174
175        self.args = parser.parse_args(self.arguments)
176
177        self._create_testsuite(self.args)
178        return 0
179
180    def _create_testsuite(self, args):
181        _test_xml = args.test_xml
182        _testcases_dir = os.path.dirname(args.archive_testfile)
183        _testsuite_name = os.path.basename(args.archive_testfile)\
184            .replace('.hap', '').replace('module_', '')
185        _testcase_xml = os.path.join(_testcases_dir, _testsuite_name + ".xml")
186        _config_file = os.path.join(_testcases_dir,
187                                    _testsuite_name + ".config")
188        _json_file = os.path.join(_testcases_dir, _testsuite_name + ".json")
189
190        if args.project_type == "js_test_hap":
191            self._generate_json_by_template(_test_xml.replace(".xml", ".json"),
192                                            _testsuite_name, _json_file)
193            dest_file = os.path.join(
194                _testcases_dir, "{}.hap".format(_testsuite_name))
195            self._copy_file(args.buildgen_testfile, dest_file)
196            os.chmod(dest_file, stat.S_IRWXU|stat.S_IRWXG|stat.S_IRWXO)
197            return
198        if args.project_type == "pythontest":
199            self._generate_json_by_template(_test_xml.replace(".xml", ".json"),
200                                            _testsuite_name, os.path.join(
201                    args.archive_testfile, _testsuite_name + ".json"))
202            utils.copy_file(output=self.args.archive_testfile,
203                            source_dirs=self.args.test_files)
204            return
205        self._check_file_exist(args.buildgen_testfile)
206        self._copy_file(args.buildgen_testfile, args.archive_testfile)
207        if args.project_type == "app":
208            return
209        self._record_testmodule_info(args.build_target_name,
210                                     _testsuite_name,
211                                     _testcases_dir)
212        if _test_xml and os.path.exists(_test_xml):
213            self._copy_file(_test_xml, _config_file)
214        elif _test_xml.replace(".xml", ".json") and \
215                os.path.exists(_test_xml.replace(".xml", ".json")):
216            self._generate_json_by_template(_test_xml.replace(".xml", ".json"),
217                                            _testsuite_name, _json_file)
218        else:
219            self._generate_xml_by_template(_test_xml, _testsuite_name,
220                                           _config_file)
221        #self._generate_testcase_xml(args)
222        _resource_srcroot = _get_resource_rootpath(args.project_path)
223        self._archive_test_file_to_testcase(_testcases_dir)
224
225    @staticmethod
226    def _record_testmodule_info(build_target_name, module_name, testcases_dir):
227        if not build_target_name or not module_name:
228            raise ValueError(
229                    'Ethire build_target_name or module_name is invalid')
230
231        module_info_list_file = os.path.join(testcases_dir, 'module_info.list')
232        lines = []
233        if os.path.isfile(module_info_list_file):
234            with open(module_info_list_file, 'r') as file_read:
235                for line in file_read:
236                    lines.append(line.strip())
237
238        new_lines = ['%s %s' % (build_target_name, module_name)]
239        for line in lines:
240            arr = line.strip().split(' ')
241            if len(arr) == 0 or arr[0] == build_target_name:
242                continue
243            new_lines.append(line)
244
245        # add module info
246        with open(module_info_list_file, 'w') as file_write:
247            file_write.write('\n'.join(new_lines) + '\n')
248
249
250    @staticmethod
251    def _generate_json_by_template(source_file, module_name, dest_file):
252        source_content = utils.read_file(source_file)
253        values = {"module": module_name}
254        xml_content = Template(source_content).substitute(values)
255        utils.write_file(dest_file, xml_content, False)
256
257    @staticmethod
258    def _generate_xml_by_template(test_xml, module_name,
259                                  config_file):
260        # find the template file
261        index = test_xml.rfind(".xml")
262        tmpl_file = test_xml[:index] + ".tmpl"
263        if not os.path.exists(tmpl_file):
264            raise Exception("Can't find the Test.xml or "
265                            "Test.tmpl in the path %s " %
266                            os.path.dirname(test_xml))
267        tmpl_content = utils.read_file(tmpl_file)
268        values = {"module": module_name}
269        xml_content = Template(tmpl_content).substitute(values)
270        utils.write_file(config_file, xml_content, False)
271
272    def _copy_file(self, source, target):
273        if not os.path.exists(os.path.dirname(target)):
274            os.makedirs(os.path.dirname(target))
275        if not os.path.exists(target) or (
276                os.path.exists(target) and
277                (os.stat(target).st_mtime != os.stat(source).st_mtime)):
278            print('Trying to copy "%s" to "%s"' % (source, target))
279            subprocess.call(["rm", "-rf", target])
280            subprocess.call(["cp", "-rf", source, target])
281
282    def _copy_file_to_target(self, source_file, dest_file):
283        if not os.path.exists(source_file):
284            print("[ERROR] source_file is not exist. %s" % source_file,
285                  file=sys.stderr)
286            return
287        else:
288            self._copy_file(source_file, dest_file)
289
290    def _archive_test_resource(self, xml_file, root_dir, resource_dir):
291        _pattern = re.compile("[-=]>")
292        if os.path.exists(xml_file):
293            try:
294                dom = xml.dom.minidom.parse(xml_file)
295                childroot = dom.getElementsByTagName("target_preparer")
296                for child in childroot:
297                    for child_atrr in child.getElementsByTagName("option"):
298                        name = child_atrr.getAttribute("name")
299                        attr_value = child_atrr.getAttribute("value")
300                        value = _pattern.split(attr_value)[0].strip()
301                        if name != "" or value != "":
302                            if name == "push" and \
303                                    value.startswith("resource/"):
304                                self._copy_file_to_target(
305                                    os.path.join(root_dir, "../", value),
306                                    os.path.join(resource_dir, value))
307                        else:
308                            raise Exception("Test.xml node name and "
309                                            "value not is null")
310            except IOError as error:
311                print("IO Error: %s" % error, file=sys.stderr)
312            except ExpatError as error:
313                print("ExpatError Error: %s" % error, file=sys.stderr)
314            finally:
315                pass
316        else:
317            with open(xml_file.replace(".config", ".json"),
318                      "r", encoding="UTF-8") as json_file:
319                json_str = json.load(json_file)
320                kits = json_str["kits"]
321                for kit in kits:
322                    types = kit["type"]
323                    if types == "PushKit":
324                        push_resources = kit["push"]
325                        for resource in push_resources:
326                            value = _pattern.split(resource)[0].strip()
327                            if value.startswith("resource/"):
328                                self._copy_file_to_target(
329                                    os.path.join(root_dir, "../", value),
330                                    os.path.join(resource_dir, value))
331
332    def _archive_test_file_to_testcase(self, cases_dir):
333        if self.args.test_files is None:
334            return
335        arr_test_files = self.args.test_files.split(',')
336        for file in arr_test_files:
337            if file == "":
338                continue
339            self._copy_file_to_target(file,
340                                      os.path.join(cases_dir,
341                                                   os.path.basename(file)))
342
343    def _check_file_exist(self, file_path):
344        if not os.path.exists(file_path):
345            raise Exception("File [%s] does not exist!" % file_path)
346
347
348ACTION_MAP = {"build_module": "SuiteModuleBuilder",
349              "build_xdevice": "XDeviceBuilder",
350              "archive_suite": "SuiteArchiveBuilder",
351              "build_module_with_testbundle":
352                  "SuiteModuleWithTestbundleBuilder"}
353
354
355def _find_action(action, arguments):
356    class_name = ACTION_MAP[action]
357    if not class_name:
358        raise ValueError('Unsupported operation: %s' % action)
359
360    this_module = sys.modules[__name__]
361    class_def = getattr(this_module, class_name, None)
362    if not class_def:
363        raise ValueError(
364            'Unsupported operation(No Implementation Class): %s' % action)
365    class_obj = class_def(arguments)
366    func = getattr(class_obj, action, None)
367    if not func:
368        raise ValueError(
369            'Unsupported operation(No Implementation Method): %s' % action)
370    return func
371
372
373def main(arguments):
374    action = arguments[0]
375    args = arguments[1:]
376    func = _find_action(action, args)
377    func()
378    return 0
379
380
381if __name__ == '__main__':
382    sys.exit(main(sys.argv[1:]))
383