1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3#
4# Copyright (c) 2024 Huawei Device Co., Ltd.
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17import argparse
18import datetime
19import os
20import shutil
21import stat
22import subprocess
23import time
24import zipfile
25
26
27def parse_args():
28    parser = argparse.ArgumentParser(description="Verify abc files in system app.")
29    parser.add_argument(
30        "--hap-dir", required=True, help="Path to the HAP files directory.")
31    parser.add_argument(
32        "--verifier-dir", required=True, help="Path to the ark_verifier directory.")
33    parser.add_argument(
34        "--keep-files", action="store_true", help="Keep extracted files after verification.")
35    return parser.parse_args()
36
37
38def copy_and_rename_hap_files(hap_folder, out_folder):
39    for file_path in os.listdir(hap_folder):
40        if file_path.endswith(".hap"):
41            destination_path = os.path.join(out_folder, file_path.replace(".hap", ".zip"))
42            shutil.copy(os.path.join(hap_folder, file_path), destination_path)
43
44
45def extract_zip(zip_path, extract_folder):
46    try:
47        with zipfile.ZipFile(zip_path, 'r') as zip_ref:
48            zip_ref.extractall(extract_folder)
49    except zipfile.BadZipFile as e:
50        print(f"Error extracting {zip_path}: {e}")
51
52
53def verify_file(file_path, ark_verifier_path):
54    verification_command = ["/usr/bin/time", "-v", ark_verifier_path, "--input_file", file_path]
55    result = subprocess.run(verification_command, capture_output=True, text=True)
56    status = 'pass' if result.returncode == 0 else 'fail'
57
58    memory_usage = None
59    user_time_ms = None
60
61    for line in result.stderr.splitlines():
62        if "Maximum resident set size" in line:
63            memory_usage = f"{line.split(':')[1].strip()} KB"
64        if "User time (seconds)" in line:
65            user_time_seconds = float(line.split(":")[1].strip())
66            user_time_ms = f"{user_time_seconds * 1000:.2f} ms"
67
68    file_size = os.path.getsize(file_path)
69    file_size_str = f"{file_size / 1024:.2f} KB" if file_size < 1024**2 else f"{file_size / 1024**2:.2f} MB"
70    report = {
71        "file": file_path,
72        "size": file_size_str,
73        "status": status,
74        "memory_usage": memory_usage,
75        "user_time": user_time_ms,
76    }
77    return report
78
79
80def process_directory(directory, ark_verifier_path):
81    total_count = 0
82    passed_count = 0
83    failed_abc_list = []
84    report_list = []
85
86    for root, dirs, files in os.walk(directory):
87        for file in files:
88            if not file.endswith(".abc"):
89                continue
90            abc_path = os.path.join(root, file)
91            print(f"Verifying file: {abc_path}")
92            report = verify_file(abc_path, ark_verifier_path)
93            report_list.append(report)
94            if report.get("status") == "pass":
95                passed_count += 1
96            else:
97                failed_abc_list.append(os.path.relpath(abc_path, directory))
98            total_count += 1
99
100    return total_count, passed_count, failed_abc_list, report_list
101
102
103def verify_hap(hap_folder, ark_verifier_path):
104    failed_abc_list = []
105    passed_count = 0
106    total_count = 0
107    report_list = []
108
109    for file in os.listdir(hap_folder):
110        if not file.endswith(".zip"):
111            continue
112
113        zip_path = os.path.join(hap_folder, file)
114        extract_folder = os.path.join(hap_folder, file.replace(".zip", ""))
115        print(f"Extracting {zip_path} to {extract_folder}")
116        extract_zip(zip_path, extract_folder)
117
118        ets_path = os.path.join(extract_folder, "ets")
119        if not os.path.exists(ets_path):
120            continue
121
122        modules_abc_path = os.path.join(ets_path, "modules.abc")
123        if os.path.isfile(modules_abc_path):
124            print(f"Verifying file: {modules_abc_path}")
125            report = verify_file(modules_abc_path, ark_verifier_path)
126            report_list.append(report)
127            if report.get("status") == "pass":
128                passed_count += 1
129            else:
130                failed_abc_list.append(os.path.relpath(modules_abc_path, hap_folder))
131            total_count += 1
132        else:
133            total_inc, passed_inc, failed_abc_inc, reports = process_directory(ets_path, ark_verifier_path)
134            total_count += total_inc
135            passed_count += passed_inc
136            failed_abc_list.extend(failed_abc_inc)
137            report_list.extend(reports)
138
139    return total_count, passed_count, len(failed_abc_list), failed_abc_list, report_list
140
141
142def save_report(report_list, report_file):
143    flags = os.O_RDWR | os.O_CREAT
144    mode = stat.S_IWUSR | stat.S_IRUSR
145    with os.fdopen(os.open(report_file, flags, mode), 'w') as f:
146        f.truncate()
147        f.write("<html><head><title>Verification Report</title>")
148        f.write("<style>")
149        f.write("body {font-family: Arial, sans-serif;}")
150        f.write("table {width: 100%; border-collapse: collapse;}")
151        f.write("th, td {border: 1px solid black; padding: 8px; text-align: left;}")
152        f.write("th {background-color: #f2f2f2;}")
153        f.write("tr:nth-child(even) {background-color: #f9f9f9;}")
154        f.write("tr:hover {background-color: #f1f1f1;}")
155        f.write("</style></head><body>\n")
156        f.write("<h1>Verification Report</h1>\n")
157        f.write(f"<p>Generated on: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>\n")
158        f.write("<table>\n")
159        f.write("<tr><th>File</th><th>Size</th><th>Status</th><th>Memory Usage</th><th>User Time</th></tr>\n")
160        for report in report_list:
161            f.write("<tr>")
162            f.write(f"<td>{report['file']}</td>")
163            f.write(f"<td>{report['size']}</td>")
164            f.write(f"<td>{report['status']}</td>")
165            f.write(f"<td>{report['memory_usage']}</td>")
166            f.write(f"<td>{report['user_time']}</td>")
167            f.write("</tr>\n")
168        f.write("</table>\n")
169        f.write("</body></html>\n")
170
171
172def main():
173    start_time = time.time()
174    args = parse_args()
175
176    hap_folder_path = os.path.abspath(args.hap_dir)
177    ark_verifier_path = os.path.abspath(os.path.join(args.verifier_dir, "ark_verifier"))
178
179    script_dir = os.path.dirname(os.path.abspath(__file__))
180    out_folder = os.path.join(script_dir, "out")
181    os.makedirs(out_folder, exist_ok=True)
182
183    copy_and_rename_hap_files(hap_folder_path, out_folder)
184
185    total_count, passed_count, failed_count, failed_abc_list, report_list = verify_hap(out_folder, ark_verifier_path)
186
187    print("Summary(abc verification):")
188    print(f"Total: {total_count}")
189    print(f"Passed: {passed_count}")
190    print(f"Failed: {failed_count}")
191
192    if failed_count > 0:
193        print("\nFailed abc files:")
194        for failed_abc in failed_abc_list:
195            print(f"  - {failed_abc}")
196
197    report_file = os.path.join(script_dir, "verification_report.html")
198    save_report(report_list, report_file)
199    print(f"\nDetailed report saved to: {report_file}")
200
201    if not args.keep_files:
202        if os.path.isdir(out_folder):
203            shutil.rmtree(out_folder)
204            print(f"\n'{out_folder}' directory has been deleted.")
205
206    end_time = time.time()
207    duration = end_time - start_time
208    completion_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(end_time))
209
210    print(f"\nExecution time: {duration:.2f} seconds")
211    print(f"Completion time: {completion_time}")
212
213
214if __name__ == "__main__":
215    main()
216