1#!/usr/bin/env python3
2#coding: utf-8
3"""
4Copyright (c) 2024 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
17Description: run script
18    input: input file
19    output: output file
20    prefix: prefix
21"""
22
23import os
24import sys
25import argparse
26
27replace_config1 = [
28    {"id": "REPLACE_FUNC_FOO1", "start": 0, "end": 31608},
29    {"id": "REPLACE_FUNC_FOO2", "start": 31609, "end": 65535},
30]
31replace_config2 = [
32    {"id": "REPLACE_FUNC_FOO1", "start": 0, "end": 65488},
33    {"id": "REPLACE_FUNC_FOO2", "start": 65489, "end": 65535},
34]
35replace_config3 = [
36    {"id": "REPLACE_FUNC_FOO1", "start": 0, "end": 65488},
37    {"id": "REPLACE_FUNC_FOO2", "start": 65489, "end": 65536},
38]
39replace_config4 = [
40    {"id": "REPLACE_FUNC_FOO1", "start": 35004, "end": 40153},
41    {"id": "REPLACE_FUNC_FOO2", "start": 1, "end": 34999, "isFunc": True, "msg": "base"},
42]
43replace_config5 = [
44    {"id": "REPLACE_FUNC_FOO1", "start": 35004, "end": 40153},
45    {"id": "REPLACE_FUNC_FOO2", "start": 1, "end": 34999, "isFunc": True, "msg": "patch"},
46]
47
48AOT_MULTI_CONSTANTPOOL_TEST_PATH = "ets_runtime/test/aottest/aot_multi_constantpool_test/"
49
50file_list = [
51    {
52        "file_name": "ets_runtime/test/quickfix/multi_funcconstpool/base_modify.js",
53        "replace_config": replace_config1,
54    },
55    {
56        "file_name": "ets_runtime/test/quickfix/multi_funcconstpool/base.js",
57        "replace_config": replace_config1,
58    },
59    {
60        "file_name": "ets_runtime/test/quickfix/multi_funccallconstpool/base_modify.js",
61        "replace_config": replace_config1,
62    },
63    {
64        "file_name": "ets_runtime/test/quickfix/multi_funccallconstpool/base.js",
65        "replace_config": replace_config1,
66    },
67    {
68        "file_name": "ets_runtime/test/quickfix/multi_constructorconstpool/base_modify.js",
69        "replace_config": replace_config1,
70    },
71    {
72        "file_name": "ets_runtime/test/quickfix/multi_constructorconstpool/base.js",
73        "replace_config": replace_config1,
74    },
75    {
76        "file_name": "ets_runtime/test/quickfix/multi_closureconstpool/base_modify.js",
77        "replace_config": replace_config3,
78    },
79    {
80        "file_name": "ets_runtime/test/quickfix/multi_closureconstpool/base.js",
81        "replace_config": replace_config3,
82    },
83    {
84        "file_name": "ets_runtime/test/quickfix/multi_classconstpool/base_modify.js",
85        "replace_config": replace_config2,
86    },
87    {
88        "file_name": "ets_runtime/test/quickfix/multi_classconstpool/base.js",
89        "replace_config": replace_config2,
90    },
91    {
92        "file_name": "ets_runtime/test/quickfix/multiconstpool_multifunc/base.js",
93        "replace_config": replace_config4,
94    },
95    {
96        "file_name": "ets_runtime/test/quickfix/multiconstpool_multifunc/base_modify.js",
97        "replace_config": replace_config5,
98    },
99    {
100        "file_name": "ets_runtime/test/moduletest/multiconstpoolobj/multiconstpoolobj.js",
101        "replace_config": replace_config2,
102    },
103    {
104        "file_name": "ets_runtime/test/moduletest/multiconstpoolfunc/multiconstpoolfunc.js",
105        "replace_config": replace_config2,
106    },
107    {
108        "file_name": "ets_runtime/test/moduletest/multiconstpoolconstructor/multiconstpoolconstructor.js",
109        "replace_config": replace_config2,
110    },
111    {
112        "file_name": "ets_runtime/test/moduletest/multiconstpoolclass/multiconstpoolclass.js",
113        "replace_config": replace_config2,
114    },
115    {
116        "file_name": "ets_runtime/test/moduletest/multiconstpoolarray/multiconstpoolarray.js",
117        "replace_config": replace_config2,
118    },
119    {
120        "file_name": AOT_MULTI_CONSTANTPOOL_TEST_PATH
121            + "multi_constantpool_func/multi_constantpool_func.ts",
122        "replace_config": replace_config1,
123    },
124    {
125        "file_name": AOT_MULTI_CONSTANTPOOL_TEST_PATH
126            + "multi_constantpool_constructor/multi_constantpool_constructor.ts",
127        "replace_config": replace_config2,
128    },
129    {
130        "file_name": AOT_MULTI_CONSTANTPOOL_TEST_PATH
131            + "multi_constantpool_class/multi_constantpool_class.ts",
132        "replace_config": replace_config2,
133    },
134    {
135        "file_name": AOT_MULTI_CONSTANTPOOL_TEST_PATH
136            + "multi_constantpool_funccall/multi_constantpool_funccall.ts",
137        "replace_config": replace_config1,
138    },
139    {
140        "file_name": AOT_MULTI_CONSTANTPOOL_TEST_PATH
141            + "multi_constantpool_closure/multi_constantpool_closure.ts",
142        "replace_config": replace_config3,
143    },
144]
145
146
147def generate_var(var_begin, var_end):
148    str_var_list = []
149    for i in range(var_begin, var_end + 1):
150        str_var_list.append('var a{0} = "{1}";'.format(i, i))
151        if (i + 1) % 6 == 0:
152            str_var_list.append("\n")
153    return ''.join(str_var_list)
154
155
156def generate_funcs(var_begin, var_end, msg):
157    str_func_list = []
158    for i in range(var_begin, var_end + 1):
159        str_func_list.append('function foo{0}()'.format(i))
160        str_func_list.append('{\n\t')
161        str_func_list.append('var a{0} = "{1}";\n\tprint("{2} foo{3}")\n'.format(i, i, msg, i))
162        str_func_list.append('}\n')
163    return ''.join(str_func_list)
164
165
166def read_file_content(input_file):
167    input_fd = os.open(input_file, os.O_RDONLY, 0o755)
168    with os.fdopen(input_fd, 'r') as fp:
169        return fp.read()
170
171
172def write_file_content(output_file, data):
173    output_fd = os.open(output_file, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o755)
174    if os.path.exists(output_file):
175        with os.fdopen(output_fd, 'w') as fp:
176            fp.write(data)
177
178
179def replace_in_data(data, replace_config):
180    for cfg in replace_config:
181        if cfg["id"] in data:
182            if "isFunc" in cfg:
183                str_func = generate_funcs(cfg["start"], cfg["end"], cfg["msg"])
184                data = data.replace(cfg["id"], str_func)
185            else:
186                str_var = generate_var(cfg["start"], cfg["end"])
187                data = data.replace(cfg["id"], str_var)
188    return data
189
190
191def replace_js(input_file, output_file):
192    for file in file_list:
193        file_name = file.get("file_name")
194        if not input_file.endswith(file_name):
195            continue
196        data = read_file_content(input_file)
197        replace_config = file.get("replace_config")
198        data = replace_in_data(data, replace_config)
199        write_file_content(output_file, data)
200        return output_file
201    return None
202
203
204def is_file_in_list(file_path):
205    input_dir_path = (
206        os.path.dirname(file_path)
207        if os.path.isfile(file_path)
208        else file_path
209    )
210
211    for item in file_list:
212        file_name = item.get("file_name")
213        list_dir_path = os.path.dirname(file_name)
214        if list_dir_path in input_dir_path:
215            return True
216    return False
217
218
219def process_with_prefix(input_file, output_file, prefix):
220    input_fd = os.open(input_file, os.O_RDONLY, 0o755)
221    output_fd = os.open(output_file, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o755)
222    with os.fdopen(input_fd, 'r') as inputfp, os.fdopen(output_fd, 'w') as outputfp:
223        for line in inputfp:
224            outputfp.write(prefix + line)
225
226
227def handle_files(input_file, output_file, prefix):
228    input_fd = os.open(input_file, os.O_RDONLY, 0o755)
229    output_fd = os.open(output_file, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o755)
230    output_file_dir = os.path.dirname(output_file)
231
232    with os.fdopen(input_fd, "r") as fp, os.fdopen(output_fd, "w") as outputfp:
233        lines = fp.readlines()
234        for line in lines:
235            ll = line.split(";")
236            original_js_filename = os.path.basename(ll[0])
237            js_fn = replace_js(prefix + ll[0], os.path.join(output_file_dir, original_js_filename))
238            if js_fn and os.path.exists(js_fn):
239                ll[0] = js_fn
240            else:
241                ll[0] = prefix + ll[0]
242            outputfp.write(";".join(ll))
243
244
245def replace_merge_file(input_file, output_file, prefix):
246    if input_file.endswith(("base.txt", "patch.txt")) and is_file_in_list(prefix):
247        handle_files(input_file, output_file, prefix)
248    else:
249        process_with_prefix(input_file, output_file, prefix)
250
251
252def replace_var(input_file, output_file, prefix):
253    if prefix:
254        replace_merge_file(input_file, output_file, prefix)
255    else:
256        replace_js(input_file, output_file)
257
258
259def main():
260    parser = argparse.ArgumentParser()
261    parser.add_argument("--input", type=str, required=True)
262    parser.add_argument("--output", type=str, required=True)
263    parser.add_argument("--prefix", type=str)
264
265    args = parser.parse_args()
266    replace_var(os.path.abspath(args.input), args.output, args.prefix)
267
268
269if __name__ == "__main__":
270    sys.exit(main())
271