• 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        current_parentdir_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
80        xtstools_othersign_dir = os.path.join(current_parentdir_path, 'others', 'sign')
81        run_scripts1 = ",".join(
82            [os.path.join(xtstools_othersign_dir, "add_root.bat"),
83             os.path.join(xtstools_othersign_dir, "add_root.sh"),
84             os.path.join(xtstools_othersign_dir, "add_trust_root.py")])
85        ohos_dir = os.path.join(self.args.source_dir, 'plugins', 'ohos')
86        gen_dir0 = os.path.join(self.args.source_dir, 'dist')
87        gen_dir1 = os.path.join(ohos_dir, 'dist')
88        shutil.rmtree(gen_dir0, ignore_errors=True)
89        shutil.rmtree(gen_dir1, ignore_errors=True)
90        command0 = ["python", "setup.py", "sdist"]
91        command1 = ["python", "setup.py", "sdist"]
92        try:
93            subprocess.check_call(command0, cwd=self.args.source_dir)
94            subprocess.check_call(command1, cwd=ohos_dir)
95        except subprocess.CalledProcessError as exc:
96            print('returncode: {} cmd: {} output: {}'.format(
97                  exc.returncode, exc.cmd, exc.output))
98
99        run_scripts = ",".join(
100            [os.path.join(self.args.source_dir, "run.bat"),
101             os.path.join(self.args.source_dir, "run.sh")])
102
103        dist_tools_dir = os.path.join(self.args.suite_out_dir, 'tools')
104        utils.copy_file(output=dist_tools_dir, source_dirs=gen_dir0,
105                        to_dir=True)
106        utils.copy_file(output=dist_tools_dir, source_dirs=gen_dir1,
107                        to_dir=True)
108        utils.copy_file(output=self.args.suite_out_dir, sources=run_scripts,
109                        to_dir=True)
110        dist_sign_dir = os.path.join(self.args.suite_out_dir, 'sign')
111        utils.copy_file(output=dist_sign_dir, sources=run_scripts1,
112                        to_dir=True)
113        xtssuite_out_dir = self.args.suite_out_dir
114        if (xtssuite_out_dir.find('/acts/') != -1):
115            acts_validator_dir = os.path.join(self.args.suite_out_dir, '../acts-validator')
116            acts_validator_tools_dir = os.path.join(self.args.suite_out_dir, '../acts-validator/tools')
117            acts_validator_sign_dir = os.path.join(self.args.suite_out_dir, '../acts-validator/sign')
118            utils.copy_file(output=acts_validator_tools_dir, source_dirs=gen_dir0,
119                            to_dir=True)
120            utils.copy_file(output=acts_validator_tools_dir, source_dirs=gen_dir1,
121                            to_dir=True)
122            utils.copy_file(output=acts_validator_dir, sources=run_scripts,
123                            to_dir=True)
124            utils.copy_file(output=acts_validator_sign_dir, sources=run_scripts1,
125                            to_dir=True)
126
127
128        if self.args.configs_dir:
129            dist_configs_dir = os.path.join(self.args.suite_out_dir, 'config')
130            utils.copy_file(output=dist_configs_dir,
131                            source_dirs=self.args.configs_dir, to_dir=True)
132            if (xtssuite_out_dir.find('/acts/') != -1):
133                acts_validator_config_dir = os.path.join(self.args.suite_out_dir, '../acts-validator/config')
134                utils.copy_file(output=acts_validator_config_dir,
135                                source_dirs=self.args.configs_dir, to_dir=True)
136        if self.args.resources_dir:
137            dist_resources_dir = os.path.join(self.args.suite_out_dir,
138                                              'resource')
139            utils.copy_file(output=dist_resources_dir,
140                            source_dirs=self.args.resources_dir, to_dir=True)
141
142
143class SuiteArchiveBuilder:
144    def __init__(self, arguments):
145        self.module_info_dir = None
146        self.arguments = arguments
147
148    def archive_suite(self):
149        parser = argparse.ArgumentParser()
150        parser.add_argument('--suite_path', help='', required=True)
151        parser.add_argument('--prebuilts_resource', help='', required=True)
152        parser.add_argument('--suite_archive_dir', help='', required=True)
153        parser.add_argument('--make_archive', help='', required=True)
154        args = parser.parse_args(self.arguments)
155
156        if not args.make_archive.lower() == 'true':
157            print('make archive disabled')
158            return 0
159
160        suite_path = args.suite_path
161        if not os.path.isdir(suite_path):
162            raise Exception("[%s] does not exist" % suite_path)
163
164        copyfiles = args.prebuilts_resource.split(",")
165        for file_path in copyfiles:
166            subprocess.call(["cp", "-rf", file_path, suite_path])
167
168        archive_name = os.path.basename(suite_path)
169        archive_root_path = args.suite_archive_dir
170        if not os.path.isdir(archive_root_path):
171            os.mkdir(archive_root_path)
172        # remove the extra output of target "java_prebuilt"
173        # such as ztest-tradefed-common.interface.jar
174        subprocess.call(["find", suite_path, "-name", "*.interface.jar",
175                        "-exec", "rm", "{}", "+"])
176        shutil.make_archive(os.path.join(archive_root_path, archive_name),
177                            "zip", suite_path)
178        return 0
179
180
181class SuiteModuleWithTestbundleBuilder:
182
183    def __init__(self, arguments):
184        self.arguments = arguments
185        self.args = None
186
187    def build_module_with_testbundle(self):
188        parser = argparse.ArgumentParser()
189        parser.add_argument('--build_gen_dir', help='', required=True)
190        parser.add_argument('--build_target_name', help='', required=True)
191        parser.add_argument('--subsystem_name', help='',
192                            required=False)
193        parser.add_argument('--part_name', help='',
194                            required=False)
195        parser.add_argument('--buildgen_testfile', help='', required=True)
196        parser.add_argument('--project_path', help='', required=True)
197        parser.add_argument('--test_xml', help='', required=False)
198        parser.add_argument('--project_type', help='', required=True)
199        parser.add_argument('--suite_out_dir', help='', required=True)
200        parser.add_argument('--archive_testfile', help='', required=True)
201        parser.add_argument('--apilibrary_deps', help='', required=False)
202        parser.add_argument('--test_files', help='', required=False)
203
204        self.args = parser.parse_args(self.arguments)
205
206        self._create_testsuite(self.args)
207        return 0
208
209    def _create_testsuite(self, args):
210        _test_xml = args.test_xml
211        _testcases_dir = os.path.dirname(args.archive_testfile)
212        _testsuite_name = os.path.basename(args.archive_testfile)\
213            .replace('.hap', '').replace('module_', '')
214        _testcase_xml = os.path.join(_testcases_dir, _testsuite_name + ".xml")
215        _config_file = os.path.join(_testcases_dir,
216                                    _testsuite_name + ".config")
217        _json_file = os.path.join(_testcases_dir, _testsuite_name + ".json")
218
219        if args.project_type == "js_test_hap":
220            self._generate_json_by_template(_test_xml.replace(".xml", ".json"),
221                                            _testsuite_name, _json_file)
222            dest_file = os.path.join(
223                _testcases_dir, "{}.hap".format(_testsuite_name))
224            self._copy_file(args.buildgen_testfile, dest_file)
225            os.chmod(dest_file, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
226            return
227        if args.project_type == "pythontest":
228            self._generate_json_by_template(_test_xml.replace(".xml", ".json"),
229                                            _testsuite_name, os.path.join(
230                    args.archive_testfile, _testsuite_name + ".json"))
231            utils.copy_file(output=self.args.archive_testfile,
232                            source_dirs=self.args.test_files)
233            return
234        self._check_file_exist(args.buildgen_testfile)
235        self._copy_file(args.buildgen_testfile, args.archive_testfile)
236        if args.project_type == "app":
237            return
238        self._record_testmodule_info(args.build_target_name,
239                                     _testsuite_name,
240                                     _testcases_dir)
241        self._record_testpart_info(args.build_target_name,
242                                     _testsuite_name,
243                                     _testcases_dir,
244                                     args.subsystem_name,args.part_name)
245        if _test_xml and os.path.exists(_test_xml):
246            self._copy_file(_test_xml, _config_file)
247        elif _test_xml.replace(".xml", ".json") and \
248                os.path.exists(_test_xml.replace(".xml", ".json")):
249            self._generate_json_by_template(_test_xml.replace(".xml", ".json"),
250                                            _testsuite_name, _json_file)
251        else:
252            self._generate_xml_by_template(_test_xml, _testsuite_name,
253                                           _config_file)
254        _resource_srcroot = _get_resource_rootpath(args.project_path)
255        self._archive_test_file_to_testcase(_testcases_dir)
256
257    @staticmethod
258    def _record_testmodule_info(build_target_name, module_name, testcases_dir):
259        if not build_target_name or not module_name:
260            raise ValueError(
261                    'Ethire build_target_name or module_name is invalid')
262
263        module_info_list_file = os.path.join(testcases_dir, 'module_info.list')
264        lines = []
265        if os.path.isfile(module_info_list_file):
266            with open(module_info_list_file, 'r') as file_read:
267                for line in file_read:
268                    lines.append(line.strip())
269
270        new_lines = ['%s %s' % (build_target_name, module_name)]
271        for line in lines:
272            arr = line.strip().split(' ')
273            if len(arr) == 0 or arr[0] == build_target_name:
274                continue
275            new_lines.append(line)
276
277        # add module info
278        new_lines.sort()
279        with open(module_info_list_file, 'w') as file_write:
280            file_write.write('\n'.join(new_lines) + '\n')
281
282    @staticmethod
283    def _record_testpart_info(build_target_name, module_name, testcases_dir, subsystem_name, part_name):
284        if not build_target_name or not module_name:
285            raise ValueError(
286                    'Ethire build_target_name or module_name is invalid')
287
288        module_info_file = os.path.join(testcases_dir, module_name+'.moduleInfo')
289
290        if os.path.exists(module_info_file):
291            return
292        module_info_data = {'subsystem': subsystem_name, 'part': part_name,
293                            'module': module_name}
294        with open(module_info_file, 'w') as out_file:
295            json.dump(module_info_data, out_file)
296
297    @staticmethod
298    def _generate_json_by_template(source_file, module_name, dest_file):
299        source_content = utils.read_file(source_file)
300        values = {"module": module_name}
301        xml_content = Template(source_content).substitute(values)
302        utils.write_file(dest_file, xml_content, False)
303
304    @staticmethod
305    def _generate_xml_by_template(test_xml, module_name,
306                                  config_file):
307        # find the template file
308        index = test_xml.rfind(".xml")
309        tmpl_file = test_xml[:index] + ".tmpl"
310        if not os.path.exists(tmpl_file):
311            raise Exception("Can't find the Test.xml or "
312                            "Test.tmpl in the path %s " %
313                            os.path.dirname(test_xml))
314        tmpl_content = utils.read_file(tmpl_file)
315        values = {"module": module_name}
316        xml_content = Template(tmpl_content).substitute(values)
317        utils.write_file(config_file, xml_content, False)
318
319    def _copy_file(self, source, target):
320        if not os.path.exists(os.path.dirname(target)):
321            os.makedirs(os.path.dirname(target))
322        if not os.path.exists(target) or (
323                os.path.exists(target) and
324                (os.stat(target).st_mtime != os.stat(source).st_mtime)):
325            print('Trying to copy "%s" to "%s"' % (source, target))
326            subprocess.call(["rm", "-rf", target])
327            subprocess.call(["cp", "-rf", source, target])
328
329    def _copy_file_to_target(self, source_file, dest_file):
330        if not os.path.exists(source_file):
331            print("[ERROR] source_file is not exist. %s" % source_file,
332                  file=sys.stderr)
333            return
334        else:
335            self._copy_file(source_file, dest_file)
336
337    def _archive_test_resource(self, xml_file, root_dir, resource_dir):
338        _pattern = re.compile("[-=]>")
339        if os.path.exists(xml_file):
340            try:
341                dom = xml.dom.minidom.parse(xml_file)
342                childroot = dom.getElementsByTagName("target_preparer")
343                for child in childroot:
344                    for child_atrr in child.getElementsByTagName("option"):
345                        name = child_atrr.getAttribute("name")
346                        attr_value = child_atrr.getAttribute("value")
347                        value = _pattern.split(attr_value)[0].strip()
348                        if name != "" or value != "":
349                            if name == "push" and \
350                                    value.startswith("resource/"):
351                                self._copy_file_to_target(
352                                    os.path.join(root_dir, "../", value),
353                                    os.path.join(resource_dir, value))
354                        else:
355                            raise Exception("Test.xml node name and "
356                                            "value not is null")
357            except IOError as error:
358                print("IO Error: %s" % error, file=sys.stderr)
359            except ExpatError as error:
360                print("ExpatError Error: %s" % error, file=sys.stderr)
361            finally:
362                pass
363        else:
364            with open(xml_file.replace(".config", ".json"),
365                      "r", encoding="UTF-8") as json_file:
366                json_str = json.load(json_file)
367                kits = json_str["kits"]
368                for kit in kits:
369                    types = kit["type"]
370                    if types == "PushKit":
371                        push_resources = kit["push"]
372                        for resource in push_resources:
373                            value = _pattern.split(resource)[0].strip()
374                            if value.startswith("resource/"):
375                                self._copy_file_to_target(
376                                    os.path.join(root_dir, "../", value),
377                                    os.path.join(resource_dir, value))
378
379    def _archive_test_file_to_testcase(self, cases_dir):
380        if self.args.test_files is None:
381            return
382        arr_test_files = self.args.test_files.split(',')
383        for file in arr_test_files:
384            if file == "":
385                continue
386            self._copy_file_to_target(file,
387                                      os.path.join(cases_dir,
388                                                   os.path.basename(file)))
389
390    def _check_file_exist(self, file_path):
391        if not os.path.exists(file_path):
392            raise Exception("File [%s] does not exist!" % file_path)
393
394
395ACTION_MAP = {"build_module": "SuiteModuleBuilder",
396              "build_xdevice": "XDeviceBuilder",
397              "archive_suite": "SuiteArchiveBuilder",
398              "build_module_with_testbundle":
399                  "SuiteModuleWithTestbundleBuilder"}
400
401
402def _find_action(action, arguments):
403    class_name = ACTION_MAP[action]
404    if not class_name:
405        raise ValueError('Unsupported operation: %s' % action)
406
407    this_module = sys.modules[__name__]
408    class_def = getattr(this_module, class_name, None)
409    if not class_def:
410        raise ValueError(
411            'Unsupported operation(No Implementation Class): %s' % action)
412    class_obj = class_def(arguments)
413    func = getattr(class_obj, action, None)
414    if not func:
415        raise ValueError(
416            'Unsupported operation(No Implementation Method): %s' % action)
417    return func
418
419
420def main(arguments):
421    action = arguments[0]
422    args = arguments[1:]
423    func = _find_action(action, args)
424    func()
425    return 0
426
427
428if __name__ == '__main__':
429    sys.exit(main(sys.argv[1:]))
430