1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# Copyright (c) 2021-2023 Huawei Device Co., Ltd.
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#     http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16import sys
17import os
18import stat
19import json
20import argparse
21import zipfile
22
23from collections import Counter
24
25sys.path.append(
26    os.path.dirname(
27        os.path.dirname(
28            os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
29
30from third_party.PyYAML.lib import yaml  # noqa: E402
31
32_DUPLICATE_KEY_DEF = "duplicate key definition"
33_EMPTY_YAML = "empty yaml file input"
34_INVALID_YAML = "invalid yaml format"
35_DUPLICATE_DOMAIN = "duplicate domain"
36_INVALID_DOMAIN_NUMBER = "invalid domain number"
37_INVALID_DOMAIN_LENGTH = "invalid domain length"
38_INVALID_DOMAIN_CHAR = "invalid domain character"
39_INVALID_DOMAIN_CHAR_HEAD = "invalid domain character head"
40_INVALID_EVENT_NUMBER = "invalid event number"
41_INVALID_EVENT_LENGTH = "invalid event length"
42_INVALID_EVENT_CHAR = "invalid event character"
43_INVALID_EVENT_CHAR_HEAD = "invalid event character head"
44_MISSING_EVENT_BASE = "missing event base"
45_MISSING_EVENT_TYPE = "missing event type"
46_INVALID_EVENT_TYPE = "invalid event type"
47_MISSING_EVENT_LEVEL = "missing event level"
48_INVALID_EVENT_LEVEL = "invalid event level"
49_MISSING_EVENT_DESC = "missing event desc"
50_INVALID_EVENT_DESC_LENGTH = "invalid event desc length"
51_INVALID_EVENT_TAG_NUM = "invalid event tag number"
52_INVALID_EVENT_TAG_LEN = "invalid event tag length"
53_INVALID_EVENT_TAG_CHAR = "invalid event tag character"
54_DUPLICATE_EVENT_TAG = "duplicate event tag"
55_INVALID_EVENT_BASE_KEY = "invalid event base key"
56_INVALID_EVENT_PARAM_NUM = "invalid event param number"
57_INVALID_EVENT_PARAM_LEN = "invalid event param length"
58_INVALID_EVENT_PARAM_CHAR = "invalid event param character"
59_INVALID_EVENT_PARAM_CHAR_HEAD = "invalid event param character head"
60_MISSING_EVENT_PARAM_TYPE = "missing event param type"
61_INVALID_EVENT_PARAM_TYPE = "invalid event param type"
62_INVALID_EVENT_PARAM_ARRSIZE = "invalid event param arrsize"
63_MISSING_EVENT_PARAM_DESC = "missing event param desc"
64_INVALID_EVENT_PARAM_DESC_LEN = "invalid event param desc length"
65_INVALID_EVENT_PARAM_KEY = "invalid event param key"
66_DEPRECATED_EVENT_NAME_PREFIX = "deprecated event name prefix"
67_DEPRECATED_PARAM_NAME_PREFIX = "deprecated param name prefix"
68_DEPRECATED_TAG_NAME = "deprecated tag name"
69_DEPRECATED_EVENT_DESC_NAME = "deprecated event desc name"
70_DEPRECATED_PARAM_DESC_NAME = "deprecated param desc name"
71_INVALID_DOMAIN_DEF = "invalid definition type for domain"
72_INVALID_EVENT_DEF = "invalid definition type for event"
73_INVALID_EVENT_BASE_DEF = "invalid definition type for event base"
74_INVALID_EVENT_TYPE_DEF = "invalid definition type for event type"
75_INVALID_EVENT_LEVEL_DEF = "invalid definition type for event level"
76_INVALID_EVENT_DESC_DEF = "invalid definition type for event desc"
77_INVALID_EVENT_TAG_DEF = "invalid definition type for event tag"
78_INVALID_EVENT_PRESERVE_DEF = "invalid definition type for event preserve"
79_INVALID_EVENT_PARAM_DEF = "invalid definition type for event param"
80_INVALID_PARAM_TYPE_DEF = "invalid definition type for param type"
81_INVALID_PARAM_ARRSIZE_DEF = "invalid definition type for param arrsize"
82_INVALID_PARAM_DESC_DEF = "invalid definition type for param desc"
83_WARNING_MAP = {
84    _EMPTY_YAML :
85        "The yaml file list is empty.",
86    _INVALID_YAML :
87        "Invalid yaml file, error message: <<%s>>.",
88    _DUPLICATE_DOMAIN :
89        "Domain <<%s>> is already defined in <<%s>>.",
90    _INVALID_DOMAIN_NUMBER :
91        "The domain definition is missing in the yaml file.",
92    _INVALID_DOMAIN_LENGTH :
93        "The length of the domain must be between [1, 16], "\
94        "but the actual length of the domain <<%s>> is <<%d>>.",
95    _INVALID_DOMAIN_CHAR :
96        "The character of the domain must be in [A-Z0-9_], "\
97        "but the domain <<%s>> actually has <<%c>>.",
98    _INVALID_DOMAIN_CHAR_HEAD :
99        "The header of the domain must be in [A-Z], "\
100        "but the actual header of the domain <<%s>> is <<%c>>.",
101    _INVALID_EVENT_NUMBER :
102        "The number of the events must be between [1, 4096], ."\
103        "but there are actually <<%d>> events.",
104    _INVALID_EVENT_LENGTH :
105        "The length of the event must be between [1, 32], "\
106        "but the actual length of the event <<%s>> is <<%d>>.",
107    _INVALID_EVENT_CHAR :
108        "The character of the event must be in [A-Z0-9_], "\
109        "but the event <<%s>> actually has <<%c>>.",
110    _INVALID_EVENT_CHAR_HEAD :
111        "The header of the event must be in [A-Z], "\
112        "but the actual header of the event <<%s>> is <<%c>>.",
113    _MISSING_EVENT_BASE :
114        "Event <<%s>> is missing __BASE definition.",
115    _MISSING_EVENT_TYPE :
116        "__BASE for event <<%s>> is missing type definition.",
117    _INVALID_EVENT_TYPE :
118        "The type of the event <<%s>> must be in "\
119        "[FAULT, STATISTIC, SECURITY, BEHAVIOR], "\
120        "but the actual event type is <<%s>>.",
121    _MISSING_EVENT_LEVEL :
122        "__BASE for event <<%s>> is missing level definition.",
123    _INVALID_EVENT_LEVEL :
124        "The level of the event <<%s>> must be in [CRITICAL, MINOR], "\
125        "but the actual event level is <<%s>>.",
126    _MISSING_EVENT_DESC :
127        "__BASE for event <<%s>> is missing desc definition.",
128    _INVALID_EVENT_DESC_LENGTH :
129        "The length of the event desc must be between [3, 128], "\
130        "but the actual length of the event <<%s>> desc <<%s>> is <<%d>>.",
131    _INVALID_EVENT_TAG_NUM :
132        "The number of the event tags must be between [0, 5], "\
133        "but actually the event <<%s>> tag <<%s>> has <<%d>> tags.",
134    _INVALID_EVENT_TAG_LEN :
135        "The length of the event tag must be between [1, 16], "\
136        "but the actual length of the event <<%s>> tag <<%s>> is <<%d>>.",
137    _INVALID_EVENT_TAG_CHAR :
138        "The character of the event tag must be in [A-Za-z0-9], "\
139        "but the event <<%s>> tag <<%s>> actually has <<%c>>.",
140    _DUPLICATE_EVENT_TAG :
141        "Event tag should not be duplicated, "\
142        "but tag <<%s>> for event <<%s>> has multiple identical.",
143    _INVALID_EVENT_BASE_KEY :
144        "Event <<%s>> __BASE key should be [type, level, tag, desc], "\
145        "but actually has an invalid key <<%s>>.",
146    _INVALID_EVENT_PARAM_NUM :
147        "The number of the event param must be between [0, 128], "\
148        "but actually the event <<%s>> has <<%d>> params.",
149    _INVALID_EVENT_PARAM_LEN :
150        "The length of the event param must be between [1, 32], "\
151        "but the actual length of the event <<%s>> param <<%s>> is <<%d>>.",
152    _INVALID_EVENT_PARAM_CHAR :
153        "The character of the event param must be in [A-Z0-9_], "\
154        "but the event <<%s>> param <<%s>> actually has <<%c>>.",
155    _INVALID_EVENT_PARAM_CHAR_HEAD:
156        "The header of the event param must be in [A-Z], "\
157        "but the actual header of the event <<%s>> param <<%s>> is <<%c>>.",
158    _MISSING_EVENT_PARAM_TYPE :
159        "Event <<%s>> param <<%s>> is missing type definition.",
160    _INVALID_EVENT_PARAM_TYPE :
161        "The type of the event <<%s>> param <<%s>> must be in "\
162        "[BOOL, INT8, UINT8, INT16, UINT16, INT32, UINT32, INT64, UINT64, "\
163        "FLOAT, DOUBLE, STRING], but the actual type is <<%s>>.",
164    _INVALID_EVENT_PARAM_ARRSIZE :
165        "The arrsize of the event param must be between [1, 100], "\
166        "but the actual arrsize of the event <<%s>> param <<%s>> is <<%d>>.",
167    _MISSING_EVENT_PARAM_DESC :
168        "Event <<%s>> param <<%s>> is missing desc definition.",
169    _INVALID_EVENT_PARAM_DESC_LEN :
170        "The length of the event param desc must be between [3, 128], "\
171        "but the actual length of the event <<%s>> param <<%s>> "\
172        "desc <<%s>> is <<%d>>.",
173    _INVALID_EVENT_PARAM_KEY :
174        "Event <<%s>> param <<%s>> key should be [type, arrsize, desc], "\
175        "but actually has an invalid key <<%s>>.",
176    _DEPRECATED_EVENT_NAME_PREFIX :
177        "Event <<%s>> should not start with domain <<%s>>.",
178    _DEPRECATED_PARAM_NAME_PREFIX :
179        "Event param <<%s>> should not start with event <<%s>>.",
180    _DEPRECATED_TAG_NAME :
181        "Event tag <<%s>> should not be same as %s <<%s>>.",
182    _DEPRECATED_EVENT_DESC_NAME :
183        "Event desc <<%s>> should not be same as event <<%s>> and "\
184        "should be more detailed.",
185    _DEPRECATED_PARAM_DESC_NAME :
186        "Event param desc <<%s>> should not be same as event <<%s>> "\
187        "param <<%s>> and should be more detailed.",
188    _INVALID_DOMAIN_DEF :
189        "The definition type of the domain must be string.",
190    _INVALID_EVENT_DEF :
191        "The definition type of the event <<%s>> must be dictionary.",
192    _INVALID_EVENT_BASE_DEF :
193        "The definition type of the event <<%s>> __BASE must be dictionary.",
194    _INVALID_EVENT_TYPE_DEF :
195        "The definition type of the event <<%s>> type must be string.",
196    _INVALID_EVENT_LEVEL_DEF :
197        "The definition type of the event <<%s>> level must be string.",
198    _INVALID_EVENT_DESC_DEF :
199        "The definition type of the event <<%s>> desc must be string.",
200    _INVALID_EVENT_TAG_DEF :
201        "The definition type of the event <<%s>> tag must be string.",
202    _INVALID_EVENT_PRESERVE_DEF :
203        "The definition type of the event <<%s>> preserve must be bool.",
204    _INVALID_EVENT_PARAM_DEF :
205        "The definition type of the event <<%s>> param <<%s>> "\
206        "must be dictionary.",
207    _INVALID_PARAM_TYPE_DEF :
208        "The definition type of the event <<%s>> param <<%s>> "\
209        "type must be string.",
210    _INVALID_PARAM_ARRSIZE_DEF :
211        "The definition type of the event <<%s>> param <<%s>> "\
212        "arrsize must be integer.",
213    _INVALID_PARAM_DESC_DEF :
214        "The definition type of the event <<%s>> param <<%s>> "\
215        "desc must be string.",
216    _DUPLICATE_KEY_DEF :
217        "Duplicate key <<%s>> exists%s.",
218}
219
220
221_domain_dict = {}
222_warning_dict = {}
223_warning_file_path = ""
224_yaml_file_path = ""
225_warning_file = None
226_hisysevent_parse_res = True
227_deprecated_dict = {}
228
229
230class _UniqueKeySafeLoader(yaml.SafeLoader):
231    def construct_mapping(self, node, deep=False):
232        mapping = []
233        for key_node, value_node in node.value:
234            key = self.construct_object(key_node, deep=deep)
235            if (key in mapping):
236                _build_warning_info(_DUPLICATE_KEY_DEF,
237                    (key, key_node.start_mark))
238                global _hisysevent_parse_res
239                _hisysevent_parse_res = False
240                continue
241            mapping.append(key)
242        return super().construct_mapping(node, deep)
243
244
245def _build_header(info_dict: dict):
246    table_header = "HiSysEvent yaml file: <<%s>>" % _yaml_file_path
247    info_dict[_yaml_file_path] = [table_header]
248    table_boundary = "-".rjust(100, '-')
249    info_dict[_yaml_file_path].append(table_boundary)
250    table_title = "Failed Item".ljust(50) + "|    " + "Failed Reason"
251    info_dict[_yaml_file_path].append(table_title)
252    info_dict[_yaml_file_path].append(table_boundary)
253
254
255def _build_warning_header():
256    global _warning_dict
257    _build_header(_warning_dict)
258
259
260def _build_deprecated_header():
261    global _deprecated_dict
262    _build_header(_deprecated_dict)
263
264
265def _build_warning_info(item, values):
266    detail = _WARNING_MAP[item] % values
267    content = item.ljust(50) + "|    " + detail
268    global _warning_dict
269    _warning_dict[_yaml_file_path].append(content)
270
271
272# Current set to warning, subsequent set to error.
273def _build_deprecated_info(item, values):
274    _build_deprecated_header()
275    detail = _WARNING_MAP[item] % values
276    content = item.ljust(50) + "|    " + detail
277    global _deprecated_dict
278    _deprecated_dict[_yaml_file_path].append(content)
279
280
281def _open_warning_file(output_path: str):
282    global _warning_file_path
283    _warning_file_path = os.path.join(output_path, 'hisysevent_warning.txt')
284    global _warning_file
285    _warning_file = open(_warning_file_path, 'w+')
286
287
288def _close_warning_file():
289    if not _warning_file:
290        _warning_file.close()
291
292
293def _output_warning():
294    for warning_list in _warning_dict.values():
295        if len(warning_list) > 4 or len(warning_list) == 1:
296            warning_list.append("")
297            for content in warning_list:
298                print(content)
299                print(content, file=_warning_file)
300
301
302def _output_deprecated(output_path: str):
303    deprecated_file = open(os.path.join(output_path, 'hisysevent_deprecated.txt'), 'w+')
304    for deprecated_list in _deprecated_dict.values():
305        deprecated_list.append("")
306        for content in deprecated_list:
307            print(content, file=deprecated_file)
308    if not deprecated_file:
309        deprecated_file.close()
310
311
312def _exit_sys():
313    print("Failed to parse the yaml file. For details about the error "\
314        "information, see file %s." % (_warning_file_path))
315    _output_warning()
316    _close_warning_file()
317    sys.exit(1)
318
319
320def _is_valid_length(content: str, len_min: int, len_max: int) -> bool:
321    return len(content) >= len_min and len(content) <= len_max
322
323
324def _is_valid_header(content: str) -> bool:
325    return len(content) == 0 or (content[0] >= 'A' and content[0] <= 'Z')
326
327
328def _is_invalid_char(ch) -> bool:
329    return (ch >= 'A' and ch <= 'Z') or (ch >= '0' and ch <= '9') or ch == '_'
330
331
332def _check_invalid_char(content: str):
333    for ch in iter(content):
334        if not _is_invalid_char(ch):
335            return ch
336    return None
337
338
339def _check_domain_duplicate(domain: str) -> bool:
340    if domain in _domain_dict:
341        _build_warning_info(_DUPLICATE_DOMAIN, (domain, _domain_dict[domain]))
342        return False
343    else:
344        _domain_dict[domain] = _yaml_file_path
345        return True
346
347
348def _check_event_domain(yaml_info: dict) -> bool:
349    if not "domain" in yaml_info:
350        _build_warning_info(_INVALID_DOMAIN_NUMBER, ())
351        return False
352    if not isinstance(yaml_info["domain"], str):
353        _build_warning_info(_INVALID_DOMAIN_DEF, ())
354        return False
355    domain = yaml_info["domain"]
356    check_res = True
357    if not _is_valid_length(domain, 1, 16):
358        _build_warning_info(_INVALID_DOMAIN_LENGTH, (domain, len(domain)))
359        check_res = False
360    if not _is_valid_header(domain):
361        _build_warning_info(_INVALID_DOMAIN_CHAR_HEAD, (domain, domain[0]))
362        check_res = False
363    invalid_ch = _check_invalid_char(domain)
364    if invalid_ch:
365        _build_warning_info(_INVALID_DOMAIN_CHAR, (domain, invalid_ch))
366        check_res = False
367    if not _check_domain_duplicate(domain):
368        check_res = False
369    return check_res
370
371
372def _check_yaml_format(yaml_info) -> bool:
373    if not yaml_info:
374        _build_warning_info(_INVALID_YAML, ("The yaml file is empty"))
375        return False
376    if not isinstance(yaml_info, dict):
377        _build_warning_info(_INVALID_YAML,
378            ("The content of yaml file is invalid"))
379        return False
380    return True
381
382
383def _check_event_name(domain: str, event_name: str) -> bool:
384    check_res = True
385    if not _is_valid_length(event_name, 1, 32):
386        _build_warning_info(_INVALID_EVENT_LENGTH,
387            (event_name, len(event_name)))
388        check_res = False
389    if len(domain) > 0 and event_name.startswith(domain):
390        _build_deprecated_info(_DEPRECATED_EVENT_NAME_PREFIX,
391            (event_name, domain))
392    if not _is_valid_header(event_name):
393        _build_warning_info(_INVALID_EVENT_CHAR_HEAD,
394            (event_name, event_name[0]))
395        check_res = False
396    invalid_ch = _check_invalid_char(event_name)
397    if invalid_ch:
398        _build_warning_info(_INVALID_DOMAIN_CHAR, (event_name, invalid_ch))
399        check_res = False
400    return check_res
401
402
403def _check_event_type(event_name: str, event_base: dict) -> bool:
404    if not "type" in event_base:
405        _build_warning_info(_MISSING_EVENT_TYPE, (event_name))
406        return False
407    else:
408        if not isinstance(event_base["type"], str):
409            _build_warning_info(_INVALID_EVENT_TYPE_DEF, event_name)
410            return False
411        type_list = ["FAULT", "STATISTIC", "SECURITY", "BEHAVIOR"]
412        if not event_base["type"] in type_list:
413            _build_warning_info(_INVALID_EVENT_TYPE,
414                (event_name, event_base["type"]))
415            return False
416    return True
417
418
419def _check_event_level(event_name: str, event_base: dict) -> bool:
420    if not "level" in event_base:
421        _build_warning_info(_MISSING_EVENT_LEVEL, (event_name))
422        return False
423    else:
424        if not isinstance(event_base["level"], str):
425            _build_warning_info(_INVALID_EVENT_LEVEL_DEF, event_name)
426            return False
427        level_list = ["CRITICAL", "MINOR"]
428        if not event_base["level"] in level_list:
429            _build_warning_info(_INVALID_EVENT_LEVEL,
430                (event_name, event_base["level"]))
431            return False
432    return True
433
434
435def _check_event_desc(event_name: str, event_base: dict) -> bool:
436    if not "desc" in event_base:
437        _build_warning_info(_MISSING_EVENT_DESC, (event_name))
438        return False
439    else:
440        event_desc = event_base["desc"]
441        if not isinstance(event_desc, str):
442            _build_warning_info(_INVALID_EVENT_DESC_DEF, event_name)
443            return False
444        check_res = True
445        if event_desc.lower() == event_name.lower():
446            _build_deprecated_info(_DEPRECATED_EVENT_DESC_NAME,
447                (event_desc, event_name))
448        if not _is_valid_length(event_desc, 3, 128):
449            _build_warning_info(_INVALID_EVENT_DESC_LENGTH,
450                (event_name, event_desc, len(event_desc)))
451            check_res = False
452        return check_res
453
454
455def _check_tag_char(event_tag: list):
456    for ch in iter(event_tag):
457        if not ch.isalnum():
458            return ch
459    return None
460
461
462def _check_tag_name(event_name: str, event_base: dict, tag_name: str) -> bool:
463    check_res = True
464    if tag_name.lower() == event_name.lower():
465        _build_deprecated_info(_DEPRECATED_TAG_NAME,
466            (tag_name, "event", event_name))
467    if "type" in event_base and tag_name.lower() == event_base["type"].lower():
468        _build_deprecated_info(_DEPRECATED_TAG_NAME,
469            (tag_name, "event type", event_base["type"]))
470    if not _is_valid_length(tag_name, 1, 16):
471        _build_warning_info(_INVALID_EVENT_TAG_LEN,
472            (event_name, tag_name, len(tag_name)))
473        check_res = False
474    invalid_ch = _check_tag_char(tag_name)
475    if invalid_ch:
476        _build_warning_info(_INVALID_EVENT_TAG_CHAR,
477            (event_name, tag_name, invalid_ch))
478        check_res = False
479    return check_res
480
481
482def _get_duplicate_tag(tag_list: list):
483    tag_dict = dict(Counter(tag_list))
484    for key, value in tag_dict.items():
485        if value > 1:
486            return key
487    return None
488
489
490def _check_event_tag(event_name: str, event_base: dict) -> bool:
491    if not "tag" in event_base:
492        return True
493    event_tag = event_base["tag"]
494    if not isinstance(event_tag, str):
495        _build_warning_info(_INVALID_EVENT_TAG_DEF, event_name)
496        return False
497    tag_list = event_tag.split()
498    if not _is_valid_length(tag_list, 1, 5):
499        _build_warning_info(_INVALID_EVENT_TAG_NUM,
500            (event_name, event_tag, len(tag_list)))
501        return False
502    check_res = True
503    for each_tag in tag_list:
504        if not _check_tag_name(event_name, event_base, each_tag):
505            check_res = False
506    dup_tag = _get_duplicate_tag(tag_list)
507    if dup_tag:
508        _build_warning_info(_DUPLICATE_EVENT_TAG, (dup_tag, event_name))
509        check_res = False
510    return check_res
511
512
513def _check_event_preserve(event_name: str, event_base: dict) -> bool:
514    if not "preserve" in event_base:
515        return True
516    event_preserve = event_base["preserve"]
517    if not isinstance(event_preserve, bool):
518        _build_warning_info(_INVALID_EVENT_PRESERVE_DEF, event_name)
519        return False
520    return True
521
522
523def _check_base_key(event_name: str, event_base: dict) -> bool:
524    key_list = ["type", "level", "tag", "desc", "preserve"]
525    for base_key in event_base.keys():
526        if not base_key in key_list:
527            _build_warning_info(_INVALID_EVENT_BASE_KEY,
528                (event_name, base_key))
529            return False
530    return True
531
532
533def _check_event_base(event_name: str, event_def: str) -> bool:
534    if not "__BASE" in event_def:
535        _build_warning_info(_MISSING_EVENT_BASE, (event_name))
536        return False
537    event_base = event_def["__BASE"]
538    if not isinstance(event_base, dict):
539        _build_warning_info(_INVALID_EVENT_BASE_DEF, (event_name))
540        return False
541    check_res = True
542    if not _check_event_type(event_name, event_base):
543        check_res = False
544    if not _check_event_level(event_name, event_base):
545        check_res = False
546    if not _check_event_desc(event_name, event_base):
547        check_res = False
548    if not _check_event_tag(event_name, event_base):
549        check_res = False
550    if not _check_event_preserve(event_name, event_base):
551        check_res = False
552    if not _check_base_key(event_name, event_base):
553        check_res = False
554    return check_res
555
556
557def _check_param_name(event_name: str, name: str) -> bool:
558    check_res = True
559    if not _is_valid_length(name, 1, 32):
560        _build_warning_info(_INVALID_EVENT_PARAM_LEN,
561            (event_name, name, len(name)))
562        check_res = False
563    if len(event_name) > 0 and name.startswith(event_name):
564        _build_deprecated_info(_DEPRECATED_PARAM_NAME_PREFIX, (name, event_name))
565    if not _is_valid_header(name):
566        _build_warning_info(_INVALID_EVENT_PARAM_CHAR_HEAD,
567            (event_name, name, name[0]))
568        check_res = False
569    invalid_ch = _check_invalid_char(name)
570    if invalid_ch:
571        _build_warning_info(_INVALID_EVENT_PARAM_CHAR,
572            (event_name, name, invalid_ch))
573        check_res = False
574    return check_res
575
576
577def _check_param_type(event_name: str, param_name: str, param_info: dict) -> bool:
578    if not "type" in param_info:
579        _build_warning_info(_MISSING_EVENT_PARAM_TYPE,
580            (event_name, param_name))
581        return False
582    else:
583        if not isinstance(param_info["type"], str):
584            _build_warning_info(_INVALID_PARAM_TYPE_DEF,
585                (event_name, param_name))
586            return False
587        type_list = ["BOOL", "INT8", "UINT8", "INT16", "UINT16", "INT32",
588            "UINT32", "INT64", "UINT64", "FLOAT", "DOUBLE", "STRING"]
589        if not param_info["type"] in type_list:
590            _build_warning_info(_INVALID_EVENT_PARAM_TYPE,
591                (event_name, param_name, param_info["type"]))
592            return False
593    return True
594
595
596def _check_param_arrsize(event_name: str, param_name: str, param_info: dict) -> bool:
597    if not "arrsize" in param_info:
598        return True
599    arrsize = param_info["arrsize"]
600    if not isinstance(arrsize, int):
601        _build_warning_info(_INVALID_PARAM_ARRSIZE_DEF,
602            (event_name, param_name))
603        return False
604    if not (arrsize >= 1 and arrsize <= 100):
605        _build_warning_info(_INVALID_EVENT_PARAM_ARRSIZE,
606            (event_name, param_name, arrsize))
607        return False
608    return True
609
610
611def _check_param_desc(event_name: str, param_name: str, param_info: dict) -> bool:
612    if not "desc" in param_info:
613        _build_warning_info(_MISSING_EVENT_PARAM_DESC,
614            (event_name, param_name))
615        return False
616    else:
617        param_desc = param_info["desc"]
618        if not isinstance(param_desc, str):
619            _build_warning_info(_INVALID_PARAM_DESC_DEF,
620                (event_name, param_name))
621            return False
622        check_res = True
623        if param_desc.lower() == param_name.lower():
624            _build_deprecated_info(_DEPRECATED_PARAM_DESC_NAME,
625                (param_desc, event_name, param_name))
626        if not _is_valid_length(param_desc, 3, 128):
627            _build_warning_info(_INVALID_EVENT_PARAM_DESC_LEN,
628                (event_name, param_name, param_desc, len(param_desc)))
629            check_res = False
630        return check_res
631
632
633def _check_param_key(event_name: str, param_name: str, param_info: dict) -> bool:
634    key_list = ["type", "arrsize", "desc"]
635    for key in param_info.keys():
636        if not key in key_list:
637            _build_warning_info(_INVALID_EVENT_PARAM_KEY,
638                (event_name, param_name, key))
639            return False
640    return True
641
642
643def _check_param_info(event_name: str, param_name: str, param_info: dict) -> bool:
644    check_res = True
645    if not _check_param_type(event_name, param_name, param_info):
646        check_res = False
647    if not _check_param_arrsize(event_name, param_name, param_info):
648        check_res = False
649    if not _check_param_desc(event_name, param_name, param_info):
650        check_res = False
651    if not _check_param_key(event_name, param_name, param_info):
652        check_res = False
653    return check_res
654
655
656def _check_event_param(event_name: str, event_def: str) -> bool:
657    sub_num = (0, 1)["__BASE" in event_def]
658    check_res = True
659    if not _is_valid_length(event_def, 0 + sub_num, 128 + sub_num):
660        _build_warning_info(_INVALID_EVENT_PARAM_NUM,
661            (event_name, (len(event_def) - sub_num)))
662        check_res = False
663    for param_name in event_def.keys():
664        if param_name == "__BASE":
665            continue
666        if not _check_param_name(event_name, param_name):
667            check_res = False
668        param_info = event_def[param_name]
669        if not isinstance(param_info, dict):
670            _build_warning_info(_INVALID_EVENT_PARAM_DEF,
671                (event_name, param_name))
672            check_res = False
673            continue
674        if not _check_param_info(event_name, param_name, param_info):
675            check_res = False
676    return check_res
677
678
679def _check_event_def(event_name: str, event_def: str) -> bool:
680    check_res = True
681    if not _check_event_base(event_name, event_def):
682        check_res = False
683    if not _check_event_param(event_name, event_def):
684        check_res = False
685    return check_res
686
687
688def _check_event_info(domain: str, event_info: list) -> bool:
689    event_name = event_info[0]
690    event_def = event_info[1]
691    check_res = True
692    if not isinstance(event_def, dict):
693        _build_warning_info(_INVALID_EVENT_DEF, (event_name))
694        return False
695    if not _check_event_name(domain, event_name):
696        check_res = False
697    if not _check_event_def(event_name, event_def):
698        check_res = False
699    return check_res
700
701
702def _check_events_info(domain: str, yaml_info: str) -> bool:
703    event_num = len(yaml_info)
704    if not (event_num >= 1 and event_num <= 4096):
705        _build_warning_info(_INVALID_EVENT_NUMBER, (event_num))
706        return False
707    check_res = True
708    for event_info in yaml_info.items():
709        if not _check_event_info(domain, event_info):
710            check_res = False
711    return check_res
712
713
714def merge_hisysevent_config(yaml_list: str, output_path: str) -> str:
715    if (len(output_path) == 0):
716        present_path = os.path.dirname(os.path.abspath(__file__))
717        output_path = present_path
718    if (len(yaml_list) == 0):
719        _build_warning_info(_EMPTY_YAML, ())
720        _exit_sys()
721    if not os.path.exists(output_path):
722        os.makedirs(output_path, exist_ok=True)
723    _open_warning_file(output_path)
724
725    yaml_info_dict = {}
726    global _hisysevent_parse_res
727    for yaml_path in yaml_list:
728        global _yaml_file_path
729        _yaml_file_path = yaml_path.replace("../", "")
730        _build_warning_header()
731        with os.fdopen(os.open(yaml_path, os.O_RDWR | os.O_CREAT, stat.S_IWUSR | stat.S_IRUSR),
732            'r', encoding='utf-8') as yaml_file:
733            yaml_info = yaml.load(yaml_file, Loader=_UniqueKeySafeLoader)
734        if not _check_yaml_format(yaml_info):
735            _hisysevent_parse_res = False
736            continue
737        if not _check_event_domain(yaml_info):
738            _hisysevent_parse_res = False
739            continue
740        domain = yaml_info["domain"]
741        del yaml_info["domain"]
742        if not _check_events_info(domain, yaml_info):
743            _hisysevent_parse_res = False
744            continue
745        yaml_info_dict[domain] = yaml_info
746    _output_deprecated(output_path)
747    if not _hisysevent_parse_res:
748        _exit_sys()
749
750    hisysevent_def_file = os.path.join(output_path, 'hisysevent.def')
751    with open(hisysevent_def_file, 'w') as j:
752        json.dump(yaml_info_dict, j, indent=4)
753    print("The hisysevent.def {} is generated successfully."
754        .format(hisysevent_def_file))
755    _close_warning_file()
756
757    # zip def file
758    hisysevent_def_zip_file = os.path.join(output_path, 'hisysevent.zip')
759    def_zip_file = zipfile.ZipFile(hisysevent_def_zip_file, "w", zipfile.ZIP_DEFLATED)
760    def_zip_file.write(hisysevent_def_file, arcname=os.path.basename(hisysevent_def_file))
761    def_zip_file.close()
762    # remove def file
763    os.remove(hisysevent_def_file)
764
765    return hisysevent_def_zip_file
766
767
768def main(argv) -> int:
769    parser = argparse.ArgumentParser(description='yaml list')
770    parser.add_argument("--yaml-list", nargs='+', required=True)
771    parser.add_argument("--def-path", required=True)
772    args = parser.parse_args(argv)
773    hisysevent_def_file = merge_hisysevent_config(args.yaml_list,
774        args.def_path)
775    print(hisysevent_def_file)
776    return 0
777
778
779if __name__ == '__main__':
780    sys.exit(main(sys.argv[1:]))
781