1c1ed15f1Sopenharmony_ci#!/usr/bin/env python
2c1ed15f1Sopenharmony_ci# coding: utf-8
3c1ed15f1Sopenharmony_ci
4c1ed15f1Sopenharmony_ci"""
5c1ed15f1Sopenharmony_ciCopyright (c) 2024 Huawei Device Co., Ltd.
6c1ed15f1Sopenharmony_ciLicensed under the Apache License, Version 2.0 (the "License");
7c1ed15f1Sopenharmony_ciyou may not use this file except in compliance with the License.
8c1ed15f1Sopenharmony_ciYou may obtain a copy of the License at
9c1ed15f1Sopenharmony_ci
10c1ed15f1Sopenharmony_ci    http://www.apache.org/licenses/LICENSE-2.0
11c1ed15f1Sopenharmony_ci
12c1ed15f1Sopenharmony_ciUnless required by applicable law or agreed to in writing, software
13c1ed15f1Sopenharmony_cidistributed under the License is distributed on an "AS IS" BASIS,
14c1ed15f1Sopenharmony_ciWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15c1ed15f1Sopenharmony_ciSee the License for the specific language governing permissions and
16c1ed15f1Sopenharmony_cilimitations under the License.
17c1ed15f1Sopenharmony_ci
18c1ed15f1Sopenharmony_ci"""
19c1ed15f1Sopenharmony_ci
20c1ed15f1Sopenharmony_ciimport os
21c1ed15f1Sopenharmony_ciimport argparse
22c1ed15f1Sopenharmony_ci
23c1ed15f1Sopenharmony_ci
24c1ed15f1Sopenharmony_cidef parse_args():
25c1ed15f1Sopenharmony_ci    parser = argparse.ArgumentParser()
26c1ed15f1Sopenharmony_ci    parser.add_argument("--dst-dir", help="the output dest path", required=True)
27c1ed15f1Sopenharmony_ci    parser.add_argument("--source-root-dir", help="project root path", required=True)
28c1ed15f1Sopenharmony_ci    parser.add_argument(
29c1ed15f1Sopenharmony_ci        "--policy-dir-list", help="policy dirs need to be included", required=True
30c1ed15f1Sopenharmony_ci    )
31c1ed15f1Sopenharmony_ci    parser.add_argument(
32c1ed15f1Sopenharmony_ci        "--components", help="system or vendor or default", required=True
33c1ed15f1Sopenharmony_ci    )
34c1ed15f1Sopenharmony_ci    return parser.parse_args()
35c1ed15f1Sopenharmony_ci
36c1ed15f1Sopenharmony_ci
37c1ed15f1Sopenharmony_cidef prepare_build_path(dir_list, root_dir, build_dir_list):
38c1ed15f1Sopenharmony_ci    build_ignore_cfg_list = [
39c1ed15f1Sopenharmony_ci        "base/security/selinux_adapter/sepolicy/base",
40c1ed15f1Sopenharmony_ci        "base/security/selinux_adapter/sepolicy/ohos_policy",
41c1ed15f1Sopenharmony_ci    ]
42c1ed15f1Sopenharmony_ci    build_ignore_cfg_list += dir_list.split(":")
43c1ed15f1Sopenharmony_ci
44c1ed15f1Sopenharmony_ci    for i in build_ignore_cfg_list:
45c1ed15f1Sopenharmony_ci        if not i or i == "default":
46c1ed15f1Sopenharmony_ci            continue
47c1ed15f1Sopenharmony_ci        path = os.path.join(root_dir, i)
48c1ed15f1Sopenharmony_ci        if os.path.exists(path):
49c1ed15f1Sopenharmony_ci            build_dir_list.append(path)
50c1ed15f1Sopenharmony_ci        else:
51c1ed15f1Sopenharmony_ci            raise Exception(f"following path not exists!! {path}")
52c1ed15f1Sopenharmony_ci
53c1ed15f1Sopenharmony_ci
54c1ed15f1Sopenharmony_cidef check_ignore_file(ignore_file, err_msg):
55c1ed15f1Sopenharmony_ci    """
56c1ed15f1Sopenharmony_ci    Check the format of ignore_cfg file.
57c1ed15f1Sopenharmony_ci    :param ignore_file: ignore_file
58c1ed15f1Sopenharmony_ci    :return:
59c1ed15f1Sopenharmony_ci    """
60c1ed15f1Sopenharmony_ci    err = ""
61c1ed15f1Sopenharmony_ci    lines = []
62c1ed15f1Sopenharmony_ci    with open(ignore_file, "rb") as fp:
63c1ed15f1Sopenharmony_ci        lines = fp.readlines()
64c1ed15f1Sopenharmony_ci    if len(lines) == 0:
65c1ed15f1Sopenharmony_ci        return
66c1ed15f1Sopenharmony_ci    last_line = lines[-1]
67c1ed15f1Sopenharmony_ci    if b"\n" not in last_line:
68c1ed15f1Sopenharmony_ci        err = "".join((ignore_file, " : need an empty line at end "))
69c1ed15f1Sopenharmony_ci    for line in lines:
70c1ed15f1Sopenharmony_ci        strip_line = line.strip()
71c1ed15f1Sopenharmony_ci        if not strip_line:
72c1ed15f1Sopenharmony_ci            continue
73c1ed15f1Sopenharmony_ci        if line.endswith(b"\r\n") or line.endswith(b"\r"):
74c1ed15f1Sopenharmony_ci            err = "".join((ignore_file, " : must be unix format"))
75c1ed15f1Sopenharmony_ci            break
76c1ed15f1Sopenharmony_ci        if strip_line in [b"/", b"/*"]:
77c1ed15f1Sopenharmony_ci            err = "".join((ignore_file, " : line must not be only / or /*"))
78c1ed15f1Sopenharmony_ci            break
79c1ed15f1Sopenharmony_ci        if not (strip_line.endswith(b"/") or strip_line.endswith(b"/*")):
80c1ed15f1Sopenharmony_ci            err = "".join((ignore_file, " : line must end with / or /*"))
81c1ed15f1Sopenharmony_ci            break
82c1ed15f1Sopenharmony_ci    if err:
83c1ed15f1Sopenharmony_ci        err_msg.append(err)
84c1ed15f1Sopenharmony_ci
85c1ed15f1Sopenharmony_ci
86c1ed15f1Sopenharmony_cidef traverse_folder_in_type(search_dir_list, file_suffix):
87c1ed15f1Sopenharmony_ci    """
88c1ed15f1Sopenharmony_ci    for special folder search_dir, find all files endwith file_suffix.
89c1ed15f1Sopenharmony_ci    :param search_dir: path to search
90c1ed15f1Sopenharmony_ci    :param file_suffix: postfix of file name
91c1ed15f1Sopenharmony_ci    :return: file list
92c1ed15f1Sopenharmony_ci    """
93c1ed15f1Sopenharmony_ci    err_msg = []
94c1ed15f1Sopenharmony_ci    ignore_cfg_file_list = []
95c1ed15f1Sopenharmony_ci    for item in search_dir_list:
96c1ed15f1Sopenharmony_ci        for root, _, files in sorted(os.walk(item)):
97c1ed15f1Sopenharmony_ci            filtered_files = [f for f in files if f == file_suffix]
98c1ed15f1Sopenharmony_ci            for each_file in filtered_files:
99c1ed15f1Sopenharmony_ci                file_list_path = os.path.join(root, each_file)
100c1ed15f1Sopenharmony_ci                check_ignore_file(file_list_path, err_msg)
101c1ed15f1Sopenharmony_ci                ignore_cfg_file_list.append(file_list_path)
102c1ed15f1Sopenharmony_ci    if err_msg:
103c1ed15f1Sopenharmony_ci        err_str = "\n{}".format("\n".join(err_msg))
104c1ed15f1Sopenharmony_ci        raise Exception(err_str)
105c1ed15f1Sopenharmony_ci    ignore_cfg_file_list.sort()
106c1ed15f1Sopenharmony_ci    return ignore_cfg_file_list
107c1ed15f1Sopenharmony_ci
108c1ed15f1Sopenharmony_ci
109c1ed15f1Sopenharmony_cidef check_and_add_line(lines, line):
110c1ed15f1Sopenharmony_ci    line = line.strip()
111c1ed15f1Sopenharmony_ci    if not line:
112c1ed15f1Sopenharmony_ci        return
113c1ed15f1Sopenharmony_ci    for existing_line in lines[:]:
114c1ed15f1Sopenharmony_ci        if len(line) >= len(existing_line) and line.startswith(existing_line):
115c1ed15f1Sopenharmony_ci            return
116c1ed15f1Sopenharmony_ci        elif len(line) < len(existing_line) and existing_line.startswith(line):
117c1ed15f1Sopenharmony_ci            lines.remove(existing_line)
118c1ed15f1Sopenharmony_ci            lines.append(line)
119c1ed15f1Sopenharmony_ci            return
120c1ed15f1Sopenharmony_ci    lines.append(line)
121c1ed15f1Sopenharmony_ci
122c1ed15f1Sopenharmony_ci
123c1ed15f1Sopenharmony_cidef get_path_lines(ignore_cfg_list):
124c1ed15f1Sopenharmony_ci    lines = []
125c1ed15f1Sopenharmony_ci    for ignore_cfg in ignore_cfg_list:
126c1ed15f1Sopenharmony_ci        with open(ignore_cfg, "r") as src_file:
127c1ed15f1Sopenharmony_ci            for line in src_file:
128c1ed15f1Sopenharmony_ci                check_and_add_line(lines, line)
129c1ed15f1Sopenharmony_ci    return lines
130c1ed15f1Sopenharmony_ci
131c1ed15f1Sopenharmony_ci
132c1ed15f1Sopenharmony_cidef filter_and_write_to_dst(lines, dst_file):
133c1ed15f1Sopenharmony_ci    fd = os.open(dst_file, os.O_WRONLY | os.O_CREAT, 0o664)
134c1ed15f1Sopenharmony_ci    with os.fdopen(fd, "w") as dst_f:
135c1ed15f1Sopenharmony_ci        dst_f.truncate(0)
136c1ed15f1Sopenharmony_ci        for line in lines:
137c1ed15f1Sopenharmony_ci            if line and not line.startswith("#"):
138c1ed15f1Sopenharmony_ci                line = "".join([line, "\n"])
139c1ed15f1Sopenharmony_ci                dst_f.write(line)
140c1ed15f1Sopenharmony_ci
141c1ed15f1Sopenharmony_ci
142c1ed15f1Sopenharmony_cidef combine_ignore_cfg(ignore_cfg_list, combined_ignore_cfg):
143c1ed15f1Sopenharmony_ci    lines = get_path_lines(ignore_cfg_list)
144c1ed15f1Sopenharmony_ci    filter_and_write_to_dst(lines, combined_ignore_cfg)
145c1ed15f1Sopenharmony_ci
146c1ed15f1Sopenharmony_ci
147c1ed15f1Sopenharmony_cidef traverse_folder_in_dir_name(search_dir, folder_suffix):
148c1ed15f1Sopenharmony_ci    folder_list = []
149c1ed15f1Sopenharmony_ci    for root, dirs, _ in sorted(os.walk(search_dir)):
150c1ed15f1Sopenharmony_ci        for dir_i in dirs:
151c1ed15f1Sopenharmony_ci            if dir_i == folder_suffix:
152c1ed15f1Sopenharmony_ci                folder_list.append(os.path.join(root, dir_i))
153c1ed15f1Sopenharmony_ci    return folder_list
154c1ed15f1Sopenharmony_ci
155c1ed15f1Sopenharmony_ci
156c1ed15f1Sopenharmony_cidef build_ignore_cfg(output_path, folder_list):
157c1ed15f1Sopenharmony_ci    combined_ignore_cfg = os.path.join(output_path, "ignore_cfg")
158c1ed15f1Sopenharmony_ci    ignore_cfg_list = traverse_folder_in_type(folder_list, "ignore_cfg")
159c1ed15f1Sopenharmony_ci    combine_ignore_cfg(ignore_cfg_list, combined_ignore_cfg)
160c1ed15f1Sopenharmony_ci
161c1ed15f1Sopenharmony_ci
162c1ed15f1Sopenharmony_cidef main(args):
163c1ed15f1Sopenharmony_ci    output_path = args.dst_dir
164c1ed15f1Sopenharmony_ci    print("output_path: ", output_path)
165c1ed15f1Sopenharmony_ci    policy_path = []
166c1ed15f1Sopenharmony_ci    prepare_build_path(args.policy_dir_list, args.source_root_dir, policy_path)
167c1ed15f1Sopenharmony_ci    print("policy_path: ", policy_path)
168c1ed15f1Sopenharmony_ci
169c1ed15f1Sopenharmony_ci    folder_list = []
170c1ed15f1Sopenharmony_ci    for item in policy_path:
171c1ed15f1Sopenharmony_ci        public_ = traverse_folder_in_dir_name(item, "public")
172c1ed15f1Sopenharmony_ci        if args.components == "system":
173c1ed15f1Sopenharmony_ci            system_policy = traverse_folder_in_dir_name(item, "system")
174c1ed15f1Sopenharmony_ci            folder_list += public_ + system_policy
175c1ed15f1Sopenharmony_ci        elif args.components == "vendor":
176c1ed15f1Sopenharmony_ci            vendor_policy = traverse_folder_in_dir_name(item, "vendor")
177c1ed15f1Sopenharmony_ci            folder_list += public_ + vendor_policy
178c1ed15f1Sopenharmony_ci        else:
179c1ed15f1Sopenharmony_ci            system_policy = traverse_folder_in_dir_name(item, "system")
180c1ed15f1Sopenharmony_ci            vendor_policy = traverse_folder_in_dir_name(item, "vendor")
181c1ed15f1Sopenharmony_ci            folder_list += public_ + system_policy + vendor_policy
182c1ed15f1Sopenharmony_ci
183c1ed15f1Sopenharmony_ci    build_ignore_cfg(output_path, folder_list)
184c1ed15f1Sopenharmony_ci    print("build_ignore_cfg done")
185c1ed15f1Sopenharmony_ci
186c1ed15f1Sopenharmony_ci
187c1ed15f1Sopenharmony_ciif __name__ == "__main__":
188c1ed15f1Sopenharmony_ci    input_args = parse_args()
189c1ed15f1Sopenharmony_ci    main(input_args)
190