15f9996aaSopenharmony_ci#!/usr/bin/env python
25f9996aaSopenharmony_ci# -*- coding: utf-8 -*-
35f9996aaSopenharmony_ci# Copyright (c) 2021 Huawei Device Co., Ltd.
45f9996aaSopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License");
55f9996aaSopenharmony_ci# you may not use this file except in compliance with the License.
65f9996aaSopenharmony_ci# You may obtain a copy of the License at
75f9996aaSopenharmony_ci#
85f9996aaSopenharmony_ci#     http://www.apache.org/licenses/LICENSE-2.0
95f9996aaSopenharmony_ci#
105f9996aaSopenharmony_ci# Unless required by applicable law or agreed to in writing, software
115f9996aaSopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS,
125f9996aaSopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135f9996aaSopenharmony_ci# See the License for the specific language governing permissions and
145f9996aaSopenharmony_ci# limitations under the License.
155f9996aaSopenharmony_ci
165f9996aaSopenharmony_ciimport argparse
175f9996aaSopenharmony_ciimport sys
185f9996aaSopenharmony_ciimport os
195f9996aaSopenharmony_ciimport subprocess
205f9996aaSopenharmony_ciimport fnmatch
215f9996aaSopenharmony_ciimport glob
225f9996aaSopenharmony_ciimport re
235f9996aaSopenharmony_ciimport errno
245f9996aaSopenharmony_ciimport codecs
255f9996aaSopenharmony_ci
265f9996aaSopenharmony_cisys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
275f9996aaSopenharmony_cifrom scripts.util import build_utils  # noqa: E402,E501 pylint: disable=E0401,C0413
285f9996aaSopenharmony_ci
295f9996aaSopenharmony_ciALL_NDK_TARGETS_TEMPLATE = '''
305f9996aaSopenharmony_cigroup("all_ndk_targets") {{
315f9996aaSopenharmony_ci deps = [ {} ]
325f9996aaSopenharmony_ci}}
335f9996aaSopenharmony_ci'''
345f9996aaSopenharmony_ci
355f9996aaSopenharmony_ciALL_NDK_TEMPLATES_NAMES = [
365f9996aaSopenharmony_ci    "ohos_ndk_headers", "ohos_ndk_library",
375f9996aaSopenharmony_ci    "ohos_ndk_prebuilt_library", "ohos_ndk_copy"
385f9996aaSopenharmony_ci]
395f9996aaSopenharmony_ci
405f9996aaSopenharmony_ci
415f9996aaSopenharmony_cidef remove_comment(file: str):
425f9996aaSopenharmony_ci    contents = []
435f9996aaSopenharmony_ci    with open(file, 'r') as in_file:
445f9996aaSopenharmony_ci        for line in in_file:
455f9996aaSopenharmony_ci            # Strip comments in gn file.
465f9996aaSopenharmony_ci            # If someone uses # as part of a string, ignore it.
475f9996aaSopenharmony_ci            if re.match(r'.*?("\S*#\S*")', line):
485f9996aaSopenharmony_ci                pass
495f9996aaSopenharmony_ci            else:
505f9996aaSopenharmony_ci                line = re.sub(r'(#.*?)\n', '', line)
515f9996aaSopenharmony_ci            contents.append(line)
525f9996aaSopenharmony_ci    return contents
535f9996aaSopenharmony_ci
545f9996aaSopenharmony_ci
555f9996aaSopenharmony_cidef do_dos2unix(in_file: str, out_file: str):
565f9996aaSopenharmony_ci    contents = ''
575f9996aaSopenharmony_ci    with open(in_file, 'r+b') as fin:
585f9996aaSopenharmony_ci        contents = fin.read()
595f9996aaSopenharmony_ci    # Remove BOM header.
605f9996aaSopenharmony_ci    if contents.startswith(codecs.BOM_UTF8):
615f9996aaSopenharmony_ci        contents = contents[len(codecs.BOM_UTF8):]
625f9996aaSopenharmony_ci    contents = re.sub(r'\r\n', '\n', contents.decode())
635f9996aaSopenharmony_ci    with open(out_file, 'w') as fout:
645f9996aaSopenharmony_ci        fout.write(contents)
655f9996aaSopenharmony_ci
665f9996aaSopenharmony_ci
675f9996aaSopenharmony_cidef do_gn_format(gn_file: str, org_file: str):
685f9996aaSopenharmony_ci    cmd = ['gn', 'format', gn_file]
695f9996aaSopenharmony_ci    child = subprocess.Popen(cmd)
705f9996aaSopenharmony_ci    child.communicate()
715f9996aaSopenharmony_ci    if child.returncode:
725f9996aaSopenharmony_ci        print(
735f9996aaSopenharmony_ci            'Error: Something is wrong with {}, please check file encoding or format'
745f9996aaSopenharmony_ci            .format(org_file))
755f9996aaSopenharmony_ci
765f9996aaSopenharmony_ci
775f9996aaSopenharmony_cidef get_ndk_targets(file: str, options):
785f9996aaSopenharmony_ci    ndk_targets = []
795f9996aaSopenharmony_ci    with build_utils.temp_dir() as tmp:
805f9996aaSopenharmony_ci        gn_file = os.path.join(tmp, os.path.basename(file))
815f9996aaSopenharmony_ci        do_dos2unix(file, gn_file)
825f9996aaSopenharmony_ci        do_gn_format(gn_file, file)
835f9996aaSopenharmony_ci        contents = remove_comment(gn_file)
845f9996aaSopenharmony_ci        for template_name in ALL_NDK_TEMPLATES_NAMES:
855f9996aaSopenharmony_ci            pattern = re.escape(template_name) + r"\(\"(.*)\"\)"
865f9996aaSopenharmony_ci            targets = re.findall(pattern, ''.join(contents))
875f9996aaSopenharmony_ci            for target in targets:
885f9996aaSopenharmony_ci                ndk_targets.append('\"//{}:{}\",'.format(
895f9996aaSopenharmony_ci                    os.path.relpath(os.path.dirname(file), options.root_dir),
905f9996aaSopenharmony_ci                    target))
915f9996aaSopenharmony_ci    return ndk_targets
925f9996aaSopenharmony_ci
935f9996aaSopenharmony_ci
945f9996aaSopenharmony_cidef main():
955f9996aaSopenharmony_ci    parser = argparse.ArgumentParser()
965f9996aaSopenharmony_ci    parser.add_argument('--output', required=True)
975f9996aaSopenharmony_ci    parser.add_argument('--root-dir', required=True)
985f9996aaSopenharmony_ci
995f9996aaSopenharmony_ci    options = parser.parse_args()
1005f9996aaSopenharmony_ci
1015f9996aaSopenharmony_ci    paths = glob.glob(os.path.join(options.root_dir, "*"))
1025f9996aaSopenharmony_ci    dirs = [
1035f9996aaSopenharmony_ci        d for d in paths if os.path.isdir(d)
1045f9996aaSopenharmony_ci        and not fnmatch.fnmatch(d, os.path.join(options.root_dir, ".repo"))
1055f9996aaSopenharmony_ci        and not fnmatch.fnmatch(d, os.path.join(options.root_dir, "out"))
1065f9996aaSopenharmony_ci    ]
1075f9996aaSopenharmony_ci
1085f9996aaSopenharmony_ci    gn_list = []
1095f9996aaSopenharmony_ci    for d in dirs:
1105f9996aaSopenharmony_ci        gn_list += glob.glob(os.path.join(d, "**/BUILD.gn"), recursive=True)
1115f9996aaSopenharmony_ci
1125f9996aaSopenharmony_ci    ndk_targets = []
1135f9996aaSopenharmony_ci    for gn_file in gn_list:
1145f9996aaSopenharmony_ci        # Skip dead link.
1155f9996aaSopenharmony_ci        try:
1165f9996aaSopenharmony_ci            os.stat(gn_file)
1175f9996aaSopenharmony_ci        except OSError as err:
1185f9996aaSopenharmony_ci            if err.errno == errno.ENOENT:
1195f9996aaSopenharmony_ci                continue
1205f9996aaSopenharmony_ci            else:
1215f9996aaSopenharmony_ci                raise Exception("Error: failed to stat {}".format(gn_file))
1225f9996aaSopenharmony_ci        ndk_targets.extend(get_ndk_targets(gn_file, options))
1235f9996aaSopenharmony_ci
1245f9996aaSopenharmony_ci    ndk_contents = ALL_NDK_TARGETS_TEMPLATE.format('\n'.join(ndk_targets))
1255f9996aaSopenharmony_ci
1265f9996aaSopenharmony_ci    os.makedirs(os.path.dirname(options.output), exist_ok=True)
1275f9996aaSopenharmony_ci    with open(options.output, 'w') as f:
1285f9996aaSopenharmony_ci        f.write(ndk_contents)
1295f9996aaSopenharmony_ci
1305f9996aaSopenharmony_ci    # Call gn format to make the output gn file prettier.
1315f9996aaSopenharmony_ci    cmd = ['gn', 'format', options.output]
1325f9996aaSopenharmony_ci    subprocess.check_output(cmd)
1335f9996aaSopenharmony_ci    return 0
1345f9996aaSopenharmony_ci
1355f9996aaSopenharmony_ci
1365f9996aaSopenharmony_ciif __name__ == '__main__':
1375f9996aaSopenharmony_ci    sys.exit(main())
138