1 | # @file CharEncodingCheck.py
|
---|
2 | #
|
---|
3 | # Copyright (c) Microsoft Corporation.
|
---|
4 | # SPDX-License-Identifier: BSD-2-Clause-Patent
|
---|
5 | ##
|
---|
6 |
|
---|
7 |
|
---|
8 | import os
|
---|
9 | import logging
|
---|
10 | from edk2toolext.environment.plugintypes.ci_build_plugin import ICiBuildPlugin
|
---|
11 | from edk2toolext.environment.var_dict import VarDict
|
---|
12 |
|
---|
13 | ##
|
---|
14 | # map
|
---|
15 | ##
|
---|
16 | EcodingMap = {
|
---|
17 | ".md": 'utf-8',
|
---|
18 | ".dsc": 'utf-8',
|
---|
19 | ".dec": 'utf-8',
|
---|
20 | ".c": 'utf-8',
|
---|
21 | ".h": 'utf-8',
|
---|
22 | ".asm": 'utf-8',
|
---|
23 | ".masm": 'utf-8',
|
---|
24 | ".nasm": 'utf-8',
|
---|
25 | ".s": 'utf-8',
|
---|
26 | ".inf": 'utf-8',
|
---|
27 | ".asl": 'utf-8',
|
---|
28 | ".uni": 'utf-8',
|
---|
29 | ".py": 'utf-8'
|
---|
30 | }
|
---|
31 |
|
---|
32 |
|
---|
33 | class CharEncodingCheck(ICiBuildPlugin):
|
---|
34 | """
|
---|
35 | A CiBuildPlugin that scans each file in the code tree and confirms the encoding is correct.
|
---|
36 |
|
---|
37 | Configuration options:
|
---|
38 | "CharEncodingCheck": {
|
---|
39 | "IgnoreFiles": []
|
---|
40 | }
|
---|
41 | """
|
---|
42 |
|
---|
43 | def GetTestName(self, packagename: str, environment: VarDict) -> tuple:
|
---|
44 | """ Provide the testcase name and classname for use in reporting
|
---|
45 | testclassname: a descriptive string for the testcase can include whitespace
|
---|
46 | classname: should be patterned <packagename>.<plugin>.<optionally any unique condition>
|
---|
47 |
|
---|
48 | Args:
|
---|
49 | packagename: string containing name of package to build
|
---|
50 | environment: The VarDict for the test to run in
|
---|
51 | Returns:
|
---|
52 | a tuple containing the testcase name and the classname
|
---|
53 | (testcasename, classname)
|
---|
54 | """
|
---|
55 | return ("Check for valid file encoding for " + packagename, packagename + ".CharEncodingCheck")
|
---|
56 |
|
---|
57 | ##
|
---|
58 | # External function of plugin. This function is used to perform the task of the ci_build_plugin Plugin
|
---|
59 | #
|
---|
60 | # - package is the edk2 path to package. This means workspace/packagepath relative.
|
---|
61 | # - edk2path object configured with workspace and packages path
|
---|
62 | # - PkgConfig Object (dict) for the pkg
|
---|
63 | # - EnvConfig Object
|
---|
64 | # - Plugin Manager Instance
|
---|
65 | # - Plugin Helper Obj Instance
|
---|
66 | # - Junit Logger
|
---|
67 | # - output_stream the StringIO output stream from this plugin via logging
|
---|
68 | def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig, environment, PLM, PLMHelper, tc, output_stream=None):
|
---|
69 | overall_status = 0
|
---|
70 | files_tested = 0
|
---|
71 |
|
---|
72 | abs_pkg_path = Edk2pathObj.GetAbsolutePathOnThisSystemFromEdk2RelativePath(packagename)
|
---|
73 |
|
---|
74 | if abs_pkg_path is None:
|
---|
75 | tc.SetSkipped()
|
---|
76 | tc.LogStdError("No Package folder {0}".format(abs_pkg_path))
|
---|
77 | return 0
|
---|
78 |
|
---|
79 | for (ext, enc) in EcodingMap.items():
|
---|
80 | files = self.WalkDirectoryForExtension([ext], abs_pkg_path)
|
---|
81 | files = [Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(x) for x in files] # make edk2relative path so can process ignores
|
---|
82 |
|
---|
83 | if "IgnoreFiles" in pkgconfig:
|
---|
84 | for a in pkgconfig["IgnoreFiles"]:
|
---|
85 | a = a.replace(os.sep, "/")
|
---|
86 | try:
|
---|
87 | tc.LogStdOut("Ignoring File {0}".format(a))
|
---|
88 | files.remove(a)
|
---|
89 | except:
|
---|
90 | tc.LogStdError("CharEncodingCheck.IgnoreInf -> {0} not found in filesystem. Invalid ignore file".format(a))
|
---|
91 | logging.info("CharEncodingCheck.IgnoreInf -> {0} not found in filesystem. Invalid ignore file".format(a))
|
---|
92 |
|
---|
93 | files = [Edk2pathObj.GetAbsolutePathOnThisSystemFromEdk2RelativePath(x) for x in files]
|
---|
94 | for a in files:
|
---|
95 | files_tested += 1
|
---|
96 | if not self.TestEncodingOk(a, enc):
|
---|
97 | tc.LogStdError("Encoding Failure in {0}. Not {1}".format(a, enc))
|
---|
98 | overall_status += 1
|
---|
99 |
|
---|
100 | tc.LogStdOut("Tested Encoding on {0} files".format(files_tested))
|
---|
101 | if overall_status != 0:
|
---|
102 | tc.SetFailed("CharEncoding {0} Failed. Errors {1}".format(packagename, overall_status), "CHAR_ENCODING_CHECK_FAILED")
|
---|
103 | else:
|
---|
104 | tc.SetSuccess()
|
---|
105 | return overall_status
|
---|
106 |
|
---|
107 | def TestEncodingOk(self, apath, encodingValue):
|
---|
108 | try:
|
---|
109 | with open(apath, "rb") as fobj:
|
---|
110 | fobj.read().decode(encodingValue)
|
---|
111 | except Exception as exp:
|
---|
112 | logging.error("Encoding failure: file: {0} type: {1}".format(apath, encodingValue))
|
---|
113 | logging.debug("EXCEPTION: while processing {1} - {0}".format(exp, apath))
|
---|
114 | return False
|
---|
115 |
|
---|
116 | return True
|
---|