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