• 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        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('--part_name', help='',
167                            required=False)
168        parser.add_argument('--buildgen_testfile', help='', required=True)
169        parser.add_argument('--project_path', help='', required=True)
170        parser.add_argument('--test_xml', help='', required=False)
171        parser.add_argument('--project_type', help='', required=True)
172        parser.add_argument('--suite_out_dir', help='', required=True)
173        parser.add_argument('--archive_testfile', help='', required=True)
174        parser.add_argument('--apilibrary_deps', help='', required=False)
175        parser.add_argument('--test_files', help='', required=False)
176
177        self.args = parser.parse_args(self.arguments)
178
179        self._create_testsuite(self.args)
180        return 0
181
182    def _create_testsuite(self, args):
183        _test_xml = args.test_xml
184        _testcases_dir = os.path.dirname(args.archive_testfile)
185        _testsuite_name = os.path.basename(args.archive_testfile)\
186            .replace('.hap', '').replace('module_', '')
187        _testcase_xml = os.path.join(_testcases_dir, _testsuite_name + ".xml")
188        _config_file = os.path.join(_testcases_dir,
189                                    _testsuite_name + ".config")
190        _json_file = os.path.join(_testcases_dir, _testsuite_name + ".json")
191
192        if args.project_type == "js_test_hap":
193            self._generate_json_by_template(_test_xml.replace(".xml", ".json"),
194                                            _testsuite_name, _json_file)
195            dest_file = os.path.join(
196                _testcases_dir, "{}.hap".format(_testsuite_name))
197            self._copy_file(args.buildgen_testfile, dest_file)
198            os.chmod(dest_file, stat.S_IRWXU|stat.S_IRWXG|stat.S_IRWXO)
199            return
200        if args.project_type == "pythontest":
201            self._generate_json_by_template(_test_xml.replace(".xml", ".json"),
202                                            _testsuite_name, os.path.join(
203                    args.archive_testfile, _testsuite_name + ".json"))
204            utils.copy_file(output=self.args.archive_testfile,
205                            source_dirs=self.args.test_files)
206            return
207        self._check_file_exist(args.buildgen_testfile)
208        self._copy_file(args.buildgen_testfile, args.archive_testfile)
209        if args.project_type == "app":
210            return
211        self._record_testmodule_info(args.build_target_name,
212                                     _testsuite_name,
213                                     _testcases_dir)
214        self._record_testpart_info(args.build_target_name,
215                                     _testsuite_name,
216                                     _testcases_dir,args.subsystem_name,args.part_name)
217        if _test_xml and os.path.exists(_test_xml):
218            self._copy_file(_test_xml, _config_file)
219        elif _test_xml.replace(".xml", ".json") and \
220                os.path.exists(_test_xml.replace(".xml", ".json")):
221            self._generate_json_by_template(_test_xml.replace(".xml", ".json"),
222                                            _testsuite_name, _json_file)
223        else:
224            self._generate_xml_by_template(_test_xml, _testsuite_name,
225                                           _config_file)
226        _resource_srcroot = _get_resource_rootpath(args.project_path)
227        self._archive_test_file_to_testcase(_testcases_dir)
228
229    @staticmethod
230    def _record_testmodule_info(build_target_name, module_name, testcases_dir):
231        if not build_target_name or not module_name:
232            raise ValueError(
233                    'Ethire build_target_name or module_name is invalid')
234
235        module_info_list_file = os.path.join(testcases_dir, 'module_info.list')
236        lines = []
237        if os.path.isfile(module_info_list_file):
238            with open(module_info_list_file, 'r') as file_read:
239                for line in file_read:
240                    lines.append(line.strip())
241
242        new_lines = ['%s %s' % (build_target_name, module_name)]
243        for line in lines:
244            arr = line.strip().split(' ')
245            if len(arr) == 0 or arr[0] == build_target_name:
246                continue
247            new_lines.append(line)
248
249        # add module info
250        new_lines.sort()
251        with open(module_info_list_file, 'w') as file_write:
252            file_write.write('\n'.join(new_lines) + '\n')
253
254    @staticmethod
255    def _record_testpart_info(build_target_name, module_name, testcases_dir, subsystem_name, part_name):
256        if not build_target_name or not module_name:
257            raise ValueError(
258                    'Ethire build_target_name or module_name is invalid')
259
260        module_info_file = os.path.join(testcases_dir, module_name+'.moduleInfo')
261
262        if os.path.exists(module_info_file):
263            return
264        module_info_data = {'subsystem': subsystem_name, 'part': part_name,
265                            'module': module_name}
266        with open(module_info_file, 'w') as out_file:
267            json.dump(module_info_data, out_file)
268
269    @staticmethod
270    def _generate_json_by_template(source_file, module_name, dest_file):
271        source_content = utils.read_file(source_file)
272        values = {"module": module_name}
273        xml_content = Template(source_content).substitute(values)
274        utils.write_file(dest_file, xml_content, False)
275
276    @staticmethod
277    def _generate_xml_by_template(test_xml, module_name,
278                                  config_file):
279        # find the template file
280        index = test_xml.rfind(".xml")
281        tmpl_file = test_xml[:index] + ".tmpl"
282        if not os.path.exists(tmpl_file):
283            raise Exception("Can't find the Test.xml or "
284                            "Test.tmpl in the path %s " %
285                            os.path.dirname(test_xml))
286        tmpl_content = utils.read_file(tmpl_file)
287        values = {"module": module_name}
288        xml_content = Template(tmpl_content).substitute(values)
289        utils.write_file(config_file, xml_content, False)
290
291    def _copy_file(self, source, target):
292        if not os.path.exists(os.path.dirname(target)):
293            os.makedirs(os.path.dirname(target))
294        if not os.path.exists(target) or (
295                os.path.exists(target) and
296                (os.stat(target).st_mtime != os.stat(source).st_mtime)):
297            print('Trying to copy "%s" to "%s"' % (source, target))
298            subprocess.call(["rm", "-rf", target])
299            subprocess.call(["cp", "-rf", source, target])
300
301    def _copy_file_to_target(self, source_file, dest_file):
302        if not os.path.exists(source_file):
303            print("[ERROR] source_file is not exist. %s" % source_file,
304                  file=sys.stderr)
305            return
306        else:
307            self._copy_file(source_file, dest_file)
308
309    def _archive_test_resource(self, xml_file, root_dir, resource_dir):
310        _pattern = re.compile("[-=]>")
311        if os.path.exists(xml_file):
312            try:
313                dom = xml.dom.minidom.parse(xml_file)
314                childroot = dom.getElementsByTagName("target_preparer")
315                for child in childroot:
316                    for child_atrr in child.getElementsByTagName("option"):
317                        name = child_atrr.getAttribute("name")
318                        attr_value = child_atrr.getAttribute("value")
319                        value = _pattern.split(attr_value)[0].strip()
320                        if name != "" or value != "":
321                            if name == "push" and \
322                                    value.startswith("resource/"):
323                                self._copy_file_to_target(
324                                    os.path.join(root_dir, "../", value),
325                                    os.path.join(resource_dir, value))
326                        else:
327                            raise Exception("Test.xml node name and "
328                                            "value not is null")
329            except IOError as error:
330                print("IO Error: %s" % error, file=sys.stderr)
331            except ExpatError as error:
332                print("ExpatError Error: %s" % error, file=sys.stderr)
333            finally:
334                pass
335        else:
336            with open(xml_file.replace(".config", ".json"),
337                      "r", encoding="UTF-8") as json_file:
338                json_str = json.load(json_file)
339                kits = json_str["kits"]
340                for kit in kits:
341                    types = kit["type"]
342                    if types == "PushKit":
343                        push_resources = kit["push"]
344                        for resource in push_resources:
345                            value = _pattern.split(resource)[0].strip()
346                            if value.startswith("resource/"):
347                                self._copy_file_to_target(
348                                    os.path.join(root_dir, "../", value),
349                                    os.path.join(resource_dir, value))
350
351    def _archive_test_file_to_testcase(self, cases_dir):
352        if self.args.test_files is None:
353            return
354        arr_test_files = self.args.test_files.split(',')
355        for file in arr_test_files:
356            if file == "":
357                continue
358            self._copy_file_to_target(file,
359                                      os.path.join(cases_dir,
360                                                   os.path.basename(file)))
361
362    def _check_file_exist(self, file_path):
363        if not os.path.exists(file_path):
364            raise Exception("File [%s] does not exist!" % file_path)
365
366
367ACTION_MAP = {"build_module": "SuiteModuleBuilder",
368              "build_xdevice": "XDeviceBuilder",
369              "archive_suite": "SuiteArchiveBuilder",
370              "build_module_with_testbundle":
371                  "SuiteModuleWithTestbundleBuilder"}
372
373
374def _find_action(action, arguments):
375    class_name = ACTION_MAP[action]
376    if not class_name:
377        raise ValueError('Unsupported operation: %s' % action)
378
379    this_module = sys.modules[__name__]
380    class_def = getattr(this_module, class_name, None)
381    if not class_def:
382        raise ValueError(
383            'Unsupported operation(No Implementation Class): %s' % action)
384    class_obj = class_def(arguments)
385    func = getattr(class_obj, action, None)
386    if not func:
387        raise ValueError(
388            'Unsupported operation(No Implementation Method): %s' % action)
389    return func
390
391
392def main(arguments):
393    action = arguments[0]
394    args = arguments[1:]
395    func = _find_action(action, args)
396    func()
397    return 0
398
399
400if __name__ == '__main__':
401    sys.exit(main(sys.argv[1:]))
402