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