public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Liming Gao" <liming.gao@intel.com>
To: "Kinney, Michael D" <michael.d.kinney@intel.com>,
	"devel@edk2.groups.io" <devel@edk2.groups.io>
Cc: Sean Brogan <sean.brogan@microsoft.com>,
	Bret Barkelew <Bret.Barkelew@microsoft.com>
Subject: Re: [Patch v4 07/22] .pytool/Plugin: Add CI plugins
Date: Thu, 7 Nov 2019 06:58:09 +0000	[thread overview]
Message-ID: <4A89E2EF3DFEDB4C8BFDE51014F606A14E539176@SHSMSX104.ccr.corp.intel.com> (raw)
In-Reply-To: <20191107011349.16524-8-michael.d.kinney@intel.com>

Mike and Sean:
  I have one minor comment. Please use the same file Readme.md. I see there are two files are named as readme.md. 
  With this change, Reviewed-by: Liming Gao <liming.gao@intel.com>

Thanks
Liming
>-----Original Message-----
>From: Kinney, Michael D
>Sent: Thursday, November 07, 2019 9:14 AM
>To: devel@edk2.groups.io
>Cc: Sean Brogan <sean.brogan@microsoft.com>; Bret Barkelew
><Bret.Barkelew@microsoft.com>; Gao, Liming <liming.gao@intel.com>
>Subject: [Patch v4 07/22] .pytool/Plugin: Add CI plugins
>
>From: Sean Brogan <sean.brogan@microsoft.com>
>
>Add .pytool directory to the edk2 repository with the
>following plugins.  These plugins are in a top level
>directory because that can be used with all packages
>and platforms.
>
>* CharEncodingCheck
>* CompilerPlugin
>* DependencyCheck
>* DscCompleteCheck
>* GuidCheck
>* LibraryClassCheck
>* SpellCheck
>
>Cc: Sean Brogan <sean.brogan@microsoft.com>
>Cc: Bret Barkelew <Bret.Barkelew@microsoft.com>
>Cc: Liming Gao <liming.gao@intel.com>
>Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com>
>---
> .../CharEncodingCheck/CharEncodingCheck.py    | 118 ++++++++
> .../CharEncodingCheck_plug_in.yaml            |  11 +
> .pytool/Plugin/CharEncodingCheck/Readme.md    |  13 +
> .../Plugin/CompilerPlugin/CompilerPlugin.py   | 102 +++++++
> .../CompilerPlugin/Compiler_plug_in.yaml      |  11 +
> .../Plugin/DependencyCheck/DependencyCheck.py | 120 +++++++++
> .../DependencyCheck_plug_in.yaml              |  13 +
> .../DscCompleteCheck/DscCompleteCheck.py      | 118 ++++++++
> .../DscCompleteCheck_plug_in.yaml             |  12 +
> .pytool/Plugin/DscCompleteCheck/readme.md     |  22 ++
> .pytool/Plugin/GuidCheck/GuidCheck.py         | 251 ++++++++++++++++++
> .../Plugin/GuidCheck/GuidCheck_plug_in.yaml   |  11 +
> .pytool/Plugin/GuidCheck/Readme.md            |  60 +++++
> .../LibraryClassCheck/LibraryClassCheck.py    | 153 +++++++++++
> .../LibraryClassCheck_plug_in.yaml            |  11 +
> .pytool/Plugin/LibraryClassCheck/readme.md    |  22 ++
> .pytool/Plugin/SpellCheck/Readme.md           | 100 +++++++
> .pytool/Plugin/SpellCheck/SpellCheck.py       | 216 +++++++++++++++
> .../Plugin/SpellCheck/SpellCheck_plug_in.yaml |  11 +
> .pytool/Plugin/SpellCheck/cspell.base.yaml    | 165 ++++++++++++
> 20 files changed, 1540 insertions(+)
> create mode
>100644 .pytool/Plugin/CharEncodingCheck/CharEncodingCheck.py
> create mode
>100644 .pytool/Plugin/CharEncodingCheck/CharEncodingCheck_plug_in.yaml
> create mode 100644 .pytool/Plugin/CharEncodingCheck/Readme.md
> create mode 100644 .pytool/Plugin/CompilerPlugin/CompilerPlugin.py
> create mode 100644 .pytool/Plugin/CompilerPlugin/Compiler_plug_in.yaml
> create mode 100644 .pytool/Plugin/DependencyCheck/DependencyCheck.py
> create mode
>100644 .pytool/Plugin/DependencyCheck/DependencyCheck_plug_in.yaml
> create mode
>100644 .pytool/Plugin/DscCompleteCheck/DscCompleteCheck.py
> create mode
>100644 .pytool/Plugin/DscCompleteCheck/DscCompleteCheck_plug_in.yaml
> create mode 100644 .pytool/Plugin/DscCompleteCheck/readme.md
> create mode 100644 .pytool/Plugin/GuidCheck/GuidCheck.py
> create mode 100644 .pytool/Plugin/GuidCheck/GuidCheck_plug_in.yaml
> create mode 100644 .pytool/Plugin/GuidCheck/Readme.md
> create mode 100644 .pytool/Plugin/LibraryClassCheck/LibraryClassCheck.py
> create mode
>100644 .pytool/Plugin/LibraryClassCheck/LibraryClassCheck_plug_in.yaml
> create mode 100644 .pytool/Plugin/LibraryClassCheck/readme.md
> create mode 100644 .pytool/Plugin/SpellCheck/Readme.md
> create mode 100644 .pytool/Plugin/SpellCheck/SpellCheck.py
> create mode 100644 .pytool/Plugin/SpellCheck/SpellCheck_plug_in.yaml
> create mode 100644 .pytool/Plugin/SpellCheck/cspell.base.yaml
>
>diff --git a/.pytool/Plugin/CharEncodingCheck/CharEncodingCheck.py
>b/.pytool/Plugin/CharEncodingCheck/CharEncodingCheck.py
>new file mode 100644
>index 0000000000..54a2424875
>--- /dev/null
>+++ b/.pytool/Plugin/CharEncodingCheck/CharEncodingCheck.py
>@@ -0,0 +1,118 @@
>+# @file CharEncodingCheck.py
>+#
>+# Copyright (c) Microsoft Corporation. All rights reserved.
>+# SPDX-License-Identifier: BSD-2-Clause-Patent
>+##
>+
>+
>+import os
>+import logging
>+from edk2toolext.environment.plugintypes.ci_build_plugin import
>ICiBuildPlugin
>+from edk2toolext.environment.var_dict import VarDict
>+
>+##
>+# map
>+##
>+EcodingMap = {
>+    ".md": 'utf-8',
>+    ".dsc": 'utf-8',
>+    ".dec": 'utf-8',
>+    ".c": 'utf-8',
>+    ".h": 'utf-8',
>+    ".asm": 'utf-8',
>+    ".masm": 'utf-8',
>+    ".nasm": 'utf-8',
>+    ".s": 'utf-8',
>+    ".inf": 'utf-8',
>+    ".asl": 'utf-8',
>+    ".uni": 'utf-8',
>+    ".py": 'utf-8'
>+}
>+
>+
>+class CharEncodingCheck(ICiBuildPlugin):
>+    """
>+    A CiBuildPlugin that scans each file in the code tree and confirms the
>encoding is correct.
>+
>+    Configuration options:
>+    "CharEncodingCheck": {
>+        "IgnoreFiles": []
>+    }
>+    """
>+
>+    def GetTestName(self, packagename: str, environment: VarDict) -> tuple:
>+        """ Provide the testcase name and classname for use in reporting
>+            testclassname: a descriptive string for the testcase can include
>whitespace
>+            classname: should be patterned <packagename>.<plugin>.<optionally
>any unique condition>
>+
>+            Args:
>+              packagename: string containing name of package to build
>+              environment: The VarDict for the test to run in
>+            Returns:
>+                a tuple containing the testcase name and the classname
>+                (testcasename, classname)
>+        """
>+        return ("Check for valid file encoding for " + packagename, packagename
>+ ".CharEncodingCheck")
>+
>+    ##
>+    # External function of plugin.  This function is used to perform the task of
>the ci_build_plugin Plugin
>+    #
>+    #   - package is the edk2 path to package.  This means
>workspace/packagepath relative.
>+    #   - edk2path object configured with workspace and packages path
>+    #   - PkgConfig Object (dict) for the pkg
>+    #   - EnvConfig Object
>+    #   - Plugin Manager Instance
>+    #   - Plugin Helper Obj Instance
>+    #   - Junit Logger
>+    #   - output_stream the StringIO output stream from this plugin via logging
>+    def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig,
>environment, PLM, PLMHelper, tc, output_stream=None):
>+        overall_status = 0
>+        files_tested = 0
>+
>+        abs_pkg_path =
>Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2RelativePath(packagen
>ame)
>+
>+        if abs_pkg_path is None:
>+            tc.SetSkipped()
>+            tc.LogStdError("No Package folder {0}".format(abs_pkg_path))
>+            return 0
>+
>+        for (ext, enc) in EcodingMap.items():
>+            files = self.WalkDirectoryForExtension([ext], abs_pkg_path)
>+            files = [Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(x) for x
>in files]  # make edk2relative path so can process ignores
>+
>+            if "IgnoreFiles" in pkgconfig:
>+                for a in pkgconfig["IgnoreFiles"]:
>+                    a = a.replace(os.sep, "/")
>+                    try:
>+                        tc.LogStdOut("Ignoring File {0}".format(a))
>+                        files.remove(a)
>+                    except:
>+                        tc.LogStdError("CharEncodingCheck.IgnoreInf -> {0} not found in
>filesystem.  Invalid ignore file".format(a))
>+                        logging.info("CharEncodingCheck.IgnoreInf -> {0} not found in
>filesystem.  Invalid ignore file".format(a))
>+
>+            files =
>[Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2RelativePath(x) for x in
>files]
>+            for a in files:
>+                files_tested += 1
>+                if(self.TestEncodingOk(a, enc)):
>+                    logging.debug("File {0} Passed Encoding Check {1}".format(a, enc))
>+                else:
>+                    tc.LogStdError("Encoding Failure in {0}.  Not {1}".format(a, enc))
>+                    overall_status += 1
>+
>+        tc.LogStdOut("Tested Encoding on {0} files".format(files_tested))
>+        if overall_status is not 0:
>+            tc.SetFailed("CharEncoding {0} Failed.  Errors {1}".format(packagename,
>overall_status), "CHAR_ENCODING_CHECK_FAILED")
>+        else:
>+            tc.SetSuccess()
>+        return overall_status
>+
>+    def TestEncodingOk(self, apath, encodingValue):
>+        try:
>+            with open(apath, "rb") as fobj:
>+                fobj.read().decode(encodingValue)
>+        except Exception as exp:
>+            logging.error("Encoding failure: file: {0} type: {1}".format(apath,
>encodingValue))
>+            logging.debug("EXCEPTION: while processing {1} - {0}".format(exp,
>apath))
>+            return False
>+
>+        return True
>diff --git
>a/.pytool/Plugin/CharEncodingCheck/CharEncodingCheck_plug_in.yaml
>b/.pytool/Plugin/CharEncodingCheck/CharEncodingCheck_plug_in.yaml
>new file mode 100644
>index 0000000000..915d3f4fdb
>--- /dev/null
>+++ b/.pytool/Plugin/CharEncodingCheck/CharEncodingCheck_plug_in.yaml
>@@ -0,0 +1,11 @@
>+##
>+# CiBuildPlugin used to check char encoding
>+#
>+# Copyright (c) 2019, Microsoft Corporation
>+# SPDX-License-Identifier: BSD-2-Clause-Patent
>+##
>+{
>+  "scope": "cibuild",
>+  "name": "Char Encoding Check Test",
>+  "module": "CharEncodingCheck"
>+}
>diff --git a/.pytool/Plugin/CharEncodingCheck/Readme.md
>b/.pytool/Plugin/CharEncodingCheck/Readme.md
>new file mode 100644
>index 0000000000..8350542966
>--- /dev/null
>+++ b/.pytool/Plugin/CharEncodingCheck/Readme.md
>@@ -0,0 +1,13 @@
>+# Character Encoding Check Plugin
>+
>+This CiBuildPlugin scans all the files in a package to make sure each file is
>correctly encoded and all characters can be read.  Improper encoding causes
>tools to fail in some situations especially in different locals.
>+
>+## Configuration
>+
>+The plugin can be configured to ignore certain files.
>+
>+``` yaml
>+"CharEncodingCheck": {
>+    "IgnoreFiles": [] # optional - list of files to ignore
>+}
>+```
>diff --git a/.pytool/Plugin/CompilerPlugin/CompilerPlugin.py
>b/.pytool/Plugin/CompilerPlugin/CompilerPlugin.py
>new file mode 100644
>index 0000000000..0a357309a4
>--- /dev/null
>+++ b/.pytool/Plugin/CompilerPlugin/CompilerPlugin.py
>@@ -0,0 +1,102 @@
>+# @file HostUnitTestCompiler_plugin.py
>+##
>+# Copyright (c) Microsoft Corporation. All rights reserved.
>+# SPDX-License-Identifier: BSD-2-Clause-Patent
>+##
>+
>+import logging
>+import os
>+import re
>+from edk2toollib.uefi.edk2.parsers.dsc_parser import DscParser
>+from edk2toolext.environment.plugintypes.ci_build_plugin import
>ICiBuildPlugin
>+from edk2toolext.environment.uefi_build import UefiBuilder
>+from edk2toolext import edk2_logging
>+from edk2toolext.environment.var_dict import VarDict
>+
>+
>+class CompilerPlugin(ICiBuildPlugin):
>+    """
>+    A CiBuildPlugin that compiles the package dsc
>+    from the package being tested.
>+
>+    Configuration options:
>+    "CompilerPlugin": {
>+        "DscPath": "<path to dsc from root of pkg>"
>+    }
>+    """
>+
>+    def GetTestName(self, packagename: str, environment: VarDict) -> tuple:
>+        """ Provide the testcase name and classname for use in reporting
>+
>+            Args:
>+              packagename: string containing name of package to build
>+              environment: The VarDict for the test to run in
>+            Returns:
>+                a tuple containing the testcase name and the classname
>+                (testcasename, classname)
>+        """
>+        target = environment.GetValue("TARGET")
>+        return ("Compile " + packagename + " " + target, packagename +
>".Compiler." + target)
>+
>+    def RunsOnTargetList(self):
>+        return ["DEBUG", "RELEASE"]
>+
>+    ##
>+    # External function of plugin.  This function is used to perform the task of
>the MuBuild Plugin
>+    #
>+    #   - package is the edk2 path to package.  This means
>workspace/packagepath relative.
>+    #   - edk2path object configured with workspace and packages path
>+    #   - PkgConfig Object (dict) for the pkg
>+    #   - EnvConfig Object
>+    #   - Plugin Manager Instance
>+    #   - Plugin Helper Obj Instance
>+    #   - Junit Logger
>+    #   - output_stream the StringIO output stream from this plugin via logging
>+    def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig,
>environment, PLM, PLMHelper, tc, output_stream=None):
>+        self._env = environment
>+
>+        # Parse the config for required DscPath element
>+        if "DscPath" not in pkgconfig:
>+            tc.SetSkipped()
>+            tc.LogStdError("DscPath not found in config file.  Nothing to compile.")
>+            return -1
>+
>+        AP =
>Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2RelativePath(packagen
>ame)
>+
>+        APDSC = os.path.join(AP, pkgconfig["DscPath"].strip())
>+        AP_Path = Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(APDSC)
>+        if AP is None or AP_Path is None or not os.path.isfile(APDSC):
>+            tc.SetSkipped()
>+            tc.LogStdError("Package Dsc not found.")
>+            return -1
>+
>+        logging.info("Building {0}".format(AP_Path))
>+        self._env.SetValue("ACTIVE_PLATFORM", AP_Path, "Set in Compiler
>Plugin")
>+
>+        # Parse DSC to check for SUPPORTED_ARCHITECTURES
>+        dp = DscParser()
>+        dp.SetBaseAbsPath(Edk2pathObj.WorkspacePath)
>+        dp.SetPackagePaths(Edk2pathObj.PackagePathList)
>+        dp.ParseFile(AP_Path)
>+        if "SUPPORTED_ARCHITECTURES" in dp.LocalVars:
>+            SUPPORTED_ARCHITECTURES =
>dp.LocalVars["SUPPORTED_ARCHITECTURES"].split('|')
>+            TARGET_ARCHITECTURES =
>environment.GetValue("TARGET_ARCH").split(' ')
>+
>+            # Skip if there is no intersection between
>SUPPORTED_ARCHITECTURES and TARGET_ARCHITECTURES
>+            if len(set(SUPPORTED_ARCHITECTURES) &
>set(TARGET_ARCHITECTURES)) == 0:
>+                tc.SetSkipped()
>+                tc.LogStdError("No supported architecutres to build")
>+                return -1
>+
>+        uefiBuilder = UefiBuilder()
>+        # do all the steps
>+        # WorkSpace, PackagesPath, PInHelper, PInManager
>+        ret = uefiBuilder.Go(Edk2pathObj.WorkspacePath,
>os.pathsep.join(Edk2pathObj.PackagePathList), PLMHelper, PLM)
>+        if ret != 0:  # failure:
>+            tc.SetFailed("Compile failed for {0}".format(packagename),
>"Compile_FAILED")
>+            tc.LogStdError("{0} Compile failed with error code {1}
>".format(AP_Path, ret))
>+            return 1
>+
>+        else:
>+            tc.SetSuccess()
>+            return 0
>diff --git a/.pytool/Plugin/CompilerPlugin/Compiler_plug_in.yaml
>b/.pytool/Plugin/CompilerPlugin/Compiler_plug_in.yaml
>new file mode 100644
>index 0000000000..4f9b3d3113
>--- /dev/null
>+++ b/.pytool/Plugin/CompilerPlugin/Compiler_plug_in.yaml
>@@ -0,0 +1,11 @@
>+##
>+# CiBuildPlugin used to compile each package
>+#
>+# Copyright (c) 2019, Microsoft Corporation
>+# SPDX-License-Identifier: BSD-2-Clause-Patent
>+##
>+{
>+  "scope": "cibuild",
>+  "name": "Compiler Plugin",
>+  "module": "CompilerPlugin"
>+}
>diff --git a/.pytool/Plugin/DependencyCheck/DependencyCheck.py
>b/.pytool/Plugin/DependencyCheck/DependencyCheck.py
>new file mode 100644
>index 0000000000..497914cf3a
>--- /dev/null
>+++ b/.pytool/Plugin/DependencyCheck/DependencyCheck.py
>@@ -0,0 +1,120 @@
>+# @file dependency_check.py
>+#
>+# Copyright (c) Microsoft Corporation. All rights reserved.
>+# SPDX-License-Identifier: BSD-2-Clause-Patent
>+##
>+
>+import logging
>+import os
>+from edk2toolext.environment.plugintypes.ci_build_plugin import
>ICiBuildPlugin
>+from edk2toollib.uefi.edk2.parsers.inf_parser import InfParser
>+from edk2toolext.environment.var_dict import VarDict
>+
>+
>+class DependencyCheck(ICiBuildPlugin):
>+    """
>+    A CiBuildPlugin that finds all modules (inf files) in a package and reviews
>the packages used
>+    to confirm they are acceptable.  This is to help enforce layering and identify
>improper
>+    dependencies between packages.
>+
>+    Configuration options:
>+    "DependencyCheck": {
>+        "AcceptableDependencies": [], # Package dec files that are allowed in all
>INFs.  Example: MdePkg/MdePkg.dec
>+        "AcceptableDependencies-<MODULE_TYPE>": [], # OPTIONAL Package
>dependencies for INFs that are HOST_APPLICATION
>+        "AcceptableDependencies-HOST_APPLICATION": [], # EXAMPLE Package
>dependencies for INFs that are HOST_APPLICATION
>+        "IgnoreInf": []  # Ignore INF if found in filesystem
>+    }
>+    """
>+
>+    def GetTestName(self, packagename: str, environment: VarDict) -> tuple:
>+        """ Provide the testcase name and classname for use in reporting
>+
>+            Args:
>+              packagename: string containing name of package to build
>+              environment: The VarDict for the test to run in
>+            Returns:
>+                a tuple containing the testcase name and the classname
>+                (testcasename, classname)
>+                testclassname: a descriptive string for the testcase can include
>whitespace
>+                classname: should be patterned
><packagename>.<plugin>.<optionally any unique condition>
>+        """
>+        return ("Test Package Dependencies for modules in " + packagename,
>packagename + ".DependencyCheck")
>+
>+    ##
>+    # External function of plugin.  This function is used to perform the task of
>the MuBuild Plugin
>+    #
>+    #   - package is the edk2 path to package.  This means
>workspace/packagepath relative.
>+    #   - edk2path object configured with workspace and packages path
>+    #   - PkgConfig Object (dict) for the pkg
>+    #   - EnvConfig Object
>+    #   - Plugin Manager Instance
>+    #   - Plugin Helper Obj Instance
>+    #   - Junit Logger
>+    #   - output_stream the StringIO output stream from this plugin via logging
>+    def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig,
>environment, PLM, PLMHelper, tc, output_stream=None):
>+        overall_status = 0
>+
>+        # Get current platform
>+        abs_pkg_path =
>Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2RelativePath(packagen
>ame)
>+
>+        # Get INF Files
>+        INFFiles = self.WalkDirectoryForExtension([".inf"], abs_pkg_path)
>+        INFFiles = [Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(x) for x
>in INFFiles]  # make edk2relative path so can compare with Ignore List
>+
>+        # Remove ignored INFs
>+        if "IgnoreInf" in pkgconfig:
>+            for a in pkgconfig["IgnoreInf"]:
>+                a = a.replace(os.sep, "/")  ## convert path sep in case ignore list is
>bad.  Can't change case
>+                try:
>+                    INFFiles.remove(a)
>+                    tc.LogStdOut("IgnoreInf {0}".format(a))
>+                except:
>+                    logging.info("DependencyConfig.IgnoreInf -> {0} not found in
>filesystem.  Invalid ignore file".format(a))
>+                    tc.LogStdError("DependencyConfig.IgnoreInf -> {0} not found in
>filesystem.  Invalid ignore file".format(a))
>+
>+
>+        # Get the AccpetableDependencies list
>+        if "AcceptableDependencies" not in pkgconfig:
>+            logging.info("DependencyCheck Skipped.  No Acceptable
>Dependencies defined.")
>+            tc.LogStdOut("DependencyCheck Skipped.  No Acceptable
>Dependencies defined.")
>+            tc.SetSkipped()
>+            return -1
>+
>+        # Log dependencies
>+        for k in pkgconfig.keys():
>+            if k.startswith("AcceptableDependencies"):
>+                pkgstring = "\n".join(pkgconfig[k])
>+                if ("-" in k):
>+                    _, _, mod_type = k.partition("-")
>+                    tc.LogStdOut(f"Additional dependencies for MODULE_TYPE
>{mod_type}:\n {pkgstring}")
>+                else:
>+                    tc.LogStdOut(f"Acceptable Dependencies:\n {pkgstring}")
>+
>+        # For each INF file
>+        for file in INFFiles:
>+            ip = InfParser()
>+            logging.debug("Parsing " + file)
>+
>ip.SetBaseAbsPath(Edk2pathObj.WorkspacePath).SetPackagePaths(Edk2path
>Obj.PackagePathList).ParseFile(file)
>+
>+            if("MODULE_TYPE" not in ip.Dict):
>+                tc.LogStdOut("Ignoring INF. Missing key for MODULE_TYPE
>{0}".format(file))
>+                continue
>+
>+            mod_type = ip.Dict["MODULE_TYPE"].upper()
>+            for p in ip.PackagesUsed:
>+                if p not in pkgconfig["AcceptableDependencies"]:
>+                    # If not in the main acceptable dependencies list then check
>module specific
>+                    mod_specific_key = "AcceptableDependencies-" + mod_type
>+                    if mod_specific_key in pkgconfig and p in
>pkgconfig[mod_specific_key]:
>+                        continue
>+
>+                    logging.error("Dependency Check: Invalid Dependency INF: {0}
>depends on pkg {1}".format(file, p))
>+                    tc.LogStdError("Dependency Check: Invalid Dependency INF: {0}
>depends on pkg {1}".format(file, p))
>+                    overall_status += 1
>+
>+        # If XML object exists, add results
>+        if overall_status is not 0:
>+            tc.SetFailed("Failed with {0} errors".format(overall_status),
>"DEPENDENCYCHECK_FAILED")
>+        else:
>+            tc.SetSuccess()
>+        return overall_status
>diff --git
>a/.pytool/Plugin/DependencyCheck/DependencyCheck_plug_in.yaml
>b/.pytool/Plugin/DependencyCheck/DependencyCheck_plug_in.yaml
>new file mode 100644
>index 0000000000..fdb96d625b
>--- /dev/null
>+++ b/.pytool/Plugin/DependencyCheck/DependencyCheck_plug_in.yaml
>@@ -0,0 +1,13 @@
>+##
>+# CiBuildPlugin used to check all infs within a package
>+# to confirm the packagesdependency are on the configured list of
>acceptable
>+# dependencies.
>+#
>+# Copyright (c) 2019, Microsoft Corporation
>+# SPDX-License-Identifier: BSD-2-Clause-Patent
>+##
>+{
>+  "scope": "cibuild",
>+  "name": "Dependency Check Test",
>+  "module": "DependencyCheck"
>+}
>diff --git a/.pytool/Plugin/DscCompleteCheck/DscCompleteCheck.py
>b/.pytool/Plugin/DscCompleteCheck/DscCompleteCheck.py
>new file mode 100644
>index 0000000000..dcd8946ca6
>--- /dev/null
>+++ b/.pytool/Plugin/DscCompleteCheck/DscCompleteCheck.py
>@@ -0,0 +1,118 @@
>+# @file DscCompleteCheck.py
>+#
>+# Copyright (c) Microsoft Corporation. All rights reserved.
>+# SPDX-License-Identifier: BSD-2-Clause-Patent
>+##
>+import logging
>+import os
>+from edk2toolext.environment.plugintypes.ci_build_plugin import
>ICiBuildPlugin
>+from edk2toollib.uefi.edk2.parsers.dsc_parser import DscParser
>+from edk2toollib.uefi.edk2.parsers.inf_parser import InfParser
>+from edk2toolext.environment.var_dict import VarDict
>+
>+
>+class DscCompleteCheck(ICiBuildPlugin):
>+    """
>+    A CiBuildPlugin that scans the package dsc file and confirms all modules (inf
>files) are
>+    listed in the components sections.
>+
>+    Configuration options:
>+    "DscCompleteCheck": {
>+        "DscPath": "<path to dsc from root of pkg>"
>+        "IgnoreInf": []  # Ignore INF if found in filesystem by not dsc
>+    }
>+    """
>+
>+    def GetTestName(self, packagename: str, environment: VarDict) -> tuple:
>+        """ Provide the testcase name and classname for use in reporting
>+
>+            Args:
>+              packagename: string containing name of package to build
>+              environment: The VarDict for the test to run in
>+            Returns:
>+                a tuple containing the testcase name and the classname
>+                (testcasename, classname)
>+                testclassname: a descriptive string for the testcase can include
>whitespace
>+                classname: should be patterned
><packagename>.<plugin>.<optionally any unique condition>
>+        """
>+        return ("Check the " + packagename + " DSC for a being complete",
>packagename + ".DscCompleteCheck")
>+
>+    ##
>+    # External function of plugin.  This function is used to perform the task of
>the MuBuild Plugin
>+    #
>+    #   - package is the edk2 path to package.  This means
>workspace/packagepath relative.
>+    #   - edk2path object configured with workspace and packages path
>+    #   - PkgConfig Object (dict) for the pkg
>+    #   - VarDict containing the shell environment Build Vars
>+    #   - Plugin Manager Instance
>+    #   - Plugin Helper Obj Instance
>+    #   - Junit Logger
>+    #   - output_stream the StringIO output stream from this plugin via logging
>+    def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig,
>environment, PLM, PLMHelper, tc, output_stream=None):
>+        overall_status = 0
>+
>+        # Parse the config for required DscPath element
>+        if "DscPath" not in pkgconfig:
>+            tc.SetSkipped()
>+            tc.LogStdError("DscPath not found in config file.  Nothing to check.")
>+            return -1
>+
>+        abs_pkg_path =
>Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2RelativePath(packagen
>ame)
>+        abs_dsc_path = os.path.join(abs_pkg_path, pkgconfig["DscPath"].strip())
>+        wsr_dsc_path =
>Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(abs_dsc_path)
>+
>+        if abs_dsc_path is None or wsr_dsc_path is "" or not
>os.path.isfile(abs_dsc_path):
>+            tc.SetSkipped()
>+            tc.LogStdError("Package Dsc not found")
>+            return 0
>+
>+        # Get INF Files
>+        INFFiles = self.WalkDirectoryForExtension([".inf"], abs_pkg_path)
>+        INFFiles = [Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(x) for x
>in INFFiles]  # make edk2relative path so can compare with DSC
>+
>+        # remove ignores
>+
>+        if "IgnoreInf" in pkgconfig:
>+            for a in pkgconfig["IgnoreInf"]:
>+                a = a.replace(os.sep, "/")
>+                try:
>+                    tc.LogStdOut("Ignoring INF {0}".format(a))
>+                    INFFiles.remove(a)
>+                except:
>+                    tc.LogStdError("DscCompleteCheck.IgnoreInf -> {0} not found in
>filesystem.  Invalid ignore file".format(a))
>+                    logging.info("DscCompleteCheck.IgnoreInf -> {0} not found in
>filesystem.  Invalid ignore file".format(a))
>+
>+        # DSC Parser
>+        dp = DscParser()
>+        dp.SetBaseAbsPath(Edk2pathObj.WorkspacePath)
>+        dp.SetPackagePaths(Edk2pathObj.PackagePathList)
>+        dp.SetInputVars(environment.GetAllBuildKeyValues())
>+        dp.ParseFile(wsr_dsc_path)
>+
>+        # Check if INF in component section
>+        for INF in INFFiles:
>+            if not any(INF.strip() in x for x in dp.ThreeMods) and \
>+               not any(INF.strip() in x for x in dp.SixMods) and \
>+               not any(INF.strip() in x for x in dp.OtherMods):
>+
>+                infp = InfParser().SetBaseAbsPath(Edk2pathObj.WorkspacePath)
>+                infp.SetPackagePaths(Edk2pathObj.PackagePathList)
>+                infp.ParseFile(INF)
>+                if("MODULE_TYPE" not in infp.Dict):
>+                    tc.LogStdOut("Ignoring INF. Missing key for MODULE_TYPE
>{0}".format(INF))
>+                    continue
>+
>+                if(infp.Dict["MODULE_TYPE"] == "HOST_APPLICATION"):
>+                    tc.LogStdOut("Ignoring INF.  Module type is HOST_APPLICATION
>{0}".format(INF))
>+                    continue
>+
>+                logging.critical(INF + " not in " + wsr_dsc_path)
>+                tc.LogStdError("{0} not in {1}".format(INF, wsr_dsc_path))
>+                overall_status = overall_status + 1
>+
>+        # If XML object exists, add result
>+        if overall_status is not 0:
>+            tc.SetFailed("DscCompleteCheck {0} Failed.  Errors
>{1}".format(wsr_dsc_path, overall_status), "CHECK_FAILED")
>+        else:
>+            tc.SetSuccess()
>+        return overall_status
>diff --git
>a/.pytool/Plugin/DscCompleteCheck/DscCompleteCheck_plug_in.yaml
>b/.pytool/Plugin/DscCompleteCheck/DscCompleteCheck_plug_in.yaml
>new file mode 100644
>index 0000000000..d84d57d973
>--- /dev/null
>+++ b/.pytool/Plugin/DscCompleteCheck/DscCompleteCheck_plug_in.yaml
>@@ -0,0 +1,12 @@
>+##
>+# CiBuildPlugin used to confirm all INFs are listed in
>+# the components section of package dsc
>+#
>+# Copyright (c) 2019, Microsoft Corporation
>+# SPDX-License-Identifier: BSD-2-Clause-Patent
>+##
>+{
>+  "scope": "cibuild",
>+  "name": "Dsc Complete Check Test",
>+  "module": "DscCompleteCheck"
>+}
>diff --git a/.pytool/Plugin/DscCompleteCheck/readme.md
>b/.pytool/Plugin/DscCompleteCheck/readme.md
>new file mode 100644
>index 0000000000..17e542b8d6
>--- /dev/null
>+++ b/.pytool/Plugin/DscCompleteCheck/readme.md
>@@ -0,0 +1,22 @@
>+# Dsc Complete Check Plugin
>+
>+This CiBuildPlugin scans all INF files from a package and confirms they are
>listed in the package level DSC file. The test considers it an error if any INF
>does not appear in the `Components` section of the package-level DSC
>(indicating that it would not be built if the package were built). This is critical
>because much of the CI infrastructure assumes that all modules will be listed
>in the DSC and compiled.
>+
>+## Configuration
>+
>+The plugin has a few configuration options to support the UEFI codebase.
>+
>+``` yaml
>+"DscCompleteCheck": {
>+        "DscPath": "",   # Path to dsc from root of package
>+        "IgnoreInf": []  # Ignore INF if found in filesystem by not dsc
>+    }
>+```
>+
>+### DscPath
>+
>+Path to DSC to consider platform dsc
>+
>+### IgnoreInf
>+
>+Ignore error if Inf file is not listed in DSC file
>diff --git a/.pytool/Plugin/GuidCheck/GuidCheck.py
>b/.pytool/Plugin/GuidCheck/GuidCheck.py
>new file mode 100644
>index 0000000000..467e17f3e8
>--- /dev/null
>+++ b/.pytool/Plugin/GuidCheck/GuidCheck.py
>@@ -0,0 +1,251 @@
>+# @file GuidCheck.py
>+#
>+# Copyright (c) Microsoft Corporation. All rights reserved.
>+# SPDX-License-Identifier: BSD-2-Clause-Patent
>+##
>+import logging
>+from edk2toolext.environment.plugintypes.ci_build_plugin import
>ICiBuildPlugin
>+from edk2toollib.uefi.edk2.guid_list import GuidList
>+from edk2toolext.environment.var_dict import VarDict
>+
>+
>+class GuidCheck(ICiBuildPlugin):
>+    """
>+    A CiBuildPlugin that scans the code tree and looks for duplicate guids
>+    from the package being tested.
>+
>+    Configuration options:
>+    "GuidCheck": {
>+        "IgnoreGuidName": [], # provide in format guidname=guidvalue or just
>guidname
>+        "IgnoreGuidValue": [],
>+        "IgnoreFoldersAndFiles": [],
>+        "IgnoreDuplicates": [] # Provide in format
>guidname=guidname=guidname...
>+    }
>+    """
>+
>+    def GetTestName(self, packagename: str, environment: VarDict) -> tuple:
>+        """ Provide the testcase name and classname for use in reporting
>+
>+            Args:
>+              packagename: string containing name of package to build
>+              environment: The VarDict for the test to run in
>+            Returns:
>+                a tuple containing the testcase name and the classname
>+                (testcasename, classname)
>+                testclassname: a descriptive string for the testcase can include
>whitespace
>+                classname: should be patterned
><packagename>.<plugin>.<optionally any unique condition>
>+        """
>+        return ("Confirm GUIDs are unique in " + packagename, packagename +
>".GuidCheck")
>+
>+    def _FindConflictingGuidValues(self, guidlist: list) -> list:
>+        """ Find all duplicate guids by guid value and report them as errors
>+        """
>+        # Sort the list by guid
>+        guidsorted = sorted(
>+            guidlist, key=lambda x: x.guid.upper(), reverse=True)
>+
>+        previous = None  # Store previous entry for comparison
>+        error = None
>+        errors = []
>+        for index in range(len(guidsorted)):
>+            i = guidsorted[index]
>+            if(previous is not None):
>+                if i.guid == previous.guid:  # Error
>+                    if(error is None):
>+                        # Catch errors with more than 1 conflict
>+                        error = ErrorEntry("guid")
>+                        error.entries.append(previous)
>+                        errors.append(error)
>+                    error.entries.append(i)
>+                else:
>+                    # no match.  clear error
>+                    error = None
>+            previous = i
>+        return errors
>+
>+    def _FindConflictingGuidNames(self, guidlist: list) -> list:
>+        """ Find all duplicate guids by name and if they are not all
>+        from inf files report them as errors.  It is ok to have
>+        BASE_NAME duplication.
>+
>+        Is this useful?  It would catch two same named guids in dec file
>+        that resolve to different values.
>+        """
>+        # Sort the list by guid
>+        namesorted = sorted(guidlist, key=lambda x: x.name.upper())
>+
>+        previous = None  # Store previous entry for comparison
>+        error = None
>+        errors = []
>+        for index in range(len(namesorted)):
>+            i = namesorted[index]
>+            if(previous is not None):
>+                # If name matches
>+                if i.name == previous.name:
>+                    if(error is None):
>+                        # Catch errors with more than 1 conflict
>+                        error = ErrorEntry("name")
>+                        error.entries.append(previous)
>+                        errors.append(error)
>+                    error.entries.append(i)
>+                else:
>+                    # no match.  clear error
>+                    error = None
>+            previous = i
>+
>+            # Loop thru and remove any errors where all files are infs as it is ok if
>+            # they have the same inf base name.
>+            for e in errors[:]:
>+                if len( [en for en in e.entries if not
>en.absfilepath.lower().endswith(".inf")]) == 0:
>+                    errors.remove(e)
>+
>+        return errors
>+
>+    ##
>+    # External function of plugin.  This function is used to perform the task of
>the MuBuild Plugin
>+    #
>+    #   - package is the edk2 path to package.  This means
>workspace/packagepath relative.
>+    #   - edk2path object configured with workspace and packages path
>+    #   - PkgConfig Object (dict) for the pkg
>+    #   - EnvConfig Object
>+    #   - Plugin Manager Instance
>+    #   - Plugin Helper Obj Instance
>+    #   - Junit Logger
>+    #   - output_stream the StringIO output stream from this plugin via logging
>+
>+    def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig,
>environment, PLM, PLMHelper, tc, output_stream=None):
>+        Errors = []
>+
>+        abs_pkg_path =
>Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2RelativePath(
>+            packagename)
>+
>+        if abs_pkg_path is None:
>+            tc.SetSkipped()
>+            tc.LogStdError("No package {0}".format(packagename))
>+            return -1
>+
>+        All_Ignores = ["/Build", "/Conf"]
>+        # Parse the config for other ignores
>+        if "IgnoreFoldersAndFiles" in pkgconfig:
>+            All_Ignores.extend(pkgconfig["IgnoreFoldersAndFiles"])
>+
>+        # Parse the workspace for all GUIDs
>+        gs = GuidList.guidlist_from_filesystem(
>+            Edk2pathObj.WorkspacePath, ignore_lines=All_Ignores)
>+
>+        # Remove ignored guidvalue
>+        if "IgnoreGuidValue" in pkgconfig:
>+            for a in pkgconfig["IgnoreGuidValue"]:
>+                try:
>+                    tc.LogStdOut("Ignoring Guid {0}".format(a.upper()))
>+                    for b in gs[:]:
>+                        if b.guid == a.upper():
>+                            gs.remove(b)
>+                except:
>+                    tc.LogStdError("GuidCheck.IgnoreGuid -> {0} not found.  Invalid
>ignore guid".format(a.upper()))
>+                    logging.info("GuidCheck.IgnoreGuid -> {0} not found.  Invalid
>ignore guid".format(a.upper()))
>+
>+        # Remove ignored guidname
>+        if "IgnoreGuidName" in pkgconfig:
>+            for a in pkgconfig["IgnoreGuidName"]:
>+                entry = a.split("=")
>+                if(len(entry) > 2):
>+                    tc.LogStdError("GuidCheck.IgnoreGuidName -> {0} Invalid
>Format.".format(a))
>+                    logging.info("GuidCheck.IgnoreGuidName -> {0} Invalid
>Format.".format(a))
>+                    continue
>+                try:
>+                    tc.LogStdOut("Ignoring Guid {0}".format(a))
>+                    for b in gs[:]:
>+                        if b.name == entry[0]:
>+                            if(len(entry) == 1):
>+                                gs.remove(b)
>+                            elif(len(entry) == 2 and b.guid.upper() == entry[1].upper()):
>+                                gs.remove(b)
>+                            else:
>+                                c.LogStdError("GuidCheck.IgnoreGuidName -> {0}
>incomplete match.  Invalid ignore guid".format(a))
>+
>+                except:
>+                    tc.LogStdError("GuidCheck.IgnoreGuidName -> {0} not found.
>Invalid ignore name".format(a))
>+                    logging.info("GuidCheck.IgnoreGuidName -> {0} not found.  Invalid
>ignore name".format(a))
>+
>+        # Find conflicting Guid Values
>+        Errors.extend(self._FindConflictingGuidValues(gs))
>+
>+        # Check if there are expected duplicates and remove it from the error list
>+        if "IgnoreDuplicates" in pkgconfig:
>+            for a in pkgconfig["IgnoreDuplicates"]:
>+                names = a.split("=")
>+                if len(names) < 2:
>+                    tc.LogStdError("GuidCheck.IgnoreDuplicates -> {0} invalid
>format".format(a))
>+                    logging.info("GuidCheck.IgnoreDuplicates -> {0} invalid
>format".format(a))
>+                    continue
>+
>+                for b in Errors[:]:
>+                    if b.type != "guid":
>+                        continue
>+                    ## Make a list of the names that are not in the names list.  If there
>+                    ## are any in the list then this error should not be ignored.
>+                    t = [x for x in b.entries if x.name not in names]
>+                    if(len(t) == len(b.entries)):
>+                        ## did not apply to any entry
>+                        continue
>+                    elif(len(t) == 0):
>+                        ## full match - ignore duplicate
>+                        tc.LogStdOut("GuidCheck.IgnoreDuplicates -> {0}".format(a))
>+                        Errors.remove(b)
>+                    elif(len(t) < len(b.entries)):
>+                        ## partial match
>+                        tc.LogStdOut("GuidCheck.IgnoreDuplicates -> {0} incomplete
>match".format(a))
>+                        logging.info("GuidCheck.IgnoreDuplicates -> {0} incomplete
>match".format(a))
>+                    else:
>+                        tc.LogStdOut("GuidCheck.IgnoreDuplicates -> {0} unknown
>error.".format(a))
>+                        logging.info("GuidCheck.IgnoreDuplicates -> {0} unknown
>error".format(a))
>+
>+
>+
>+        # Find conflicting Guid Names
>+        Errors.extend(self._FindConflictingGuidNames(gs))
>+
>+        # Log errors for anything within the package under test
>+        for er in Errors[:]:
>+            InMyPackage = False
>+            for a in er.entries:
>+                if abs_pkg_path in a.absfilepath:
>+                    InMyPackage = True
>+                    break
>+            if(not InMyPackage):
>+                Errors.remove(er)
>+            else:
>+                logging.error(str(er))
>+                tc.LogStdError(str(er))
>+
>+        # add result to test case
>+        overall_status = len(Errors)
>+        if overall_status is not 0:
>+            tc.SetFailed("GuidCheck {0} Failed.  Errors {1}".format(
>+                packagename, overall_status), "CHECK_FAILED")
>+        else:
>+            tc.SetSuccess()
>+        return overall_status
>+
>+
>+class ErrorEntry():
>+    """ Custom/private class for reporting errors in the GuidList
>+    """
>+
>+    def __init__(self, errortype):
>+        self.type = errortype  # 'guid' or 'name' depending on error type
>+        self.entries = []  # GuidListEntry that are in error condition
>+
>+    def __str__(self):
>+        a = f"Error Duplicate {self.type}: "
>+        if(self.type == "guid"):
>+            a += f" {self.entries[0].guid}"
>+        elif(self.type == "name"):
>+            a += f" {self.entries[0].name}"
>+
>+        a += f" ({len(self.entries)})\n"
>+
>+        for e in self.entries:
>+            a += "\t" + str(e) + "\n"
>+        return a
>diff --git a/.pytool/Plugin/GuidCheck/GuidCheck_plug_in.yaml
>b/.pytool/Plugin/GuidCheck/GuidCheck_plug_in.yaml
>new file mode 100644
>index 0000000000..531efb7885
>--- /dev/null
>+++ b/.pytool/Plugin/GuidCheck/GuidCheck_plug_in.yaml
>@@ -0,0 +1,11 @@
>+##
>+# CiBuildPlugin used to check guid uniqueness
>+#
>+# Copyright (c) 2019, Microsoft Corporation
>+# SPDX-License-Identifier: BSD-2-Clause-Patent
>+##
>+{
>+  "scope": "cibuild",
>+  "name": "Guid Check Test",
>+  "module": "GuidCheck"
>+}
>diff --git a/.pytool/Plugin/GuidCheck/Readme.md
>b/.pytool/Plugin/GuidCheck/Readme.md
>new file mode 100644
>index 0000000000..c1bf3d728e
>--- /dev/null
>+++ b/.pytool/Plugin/GuidCheck/Readme.md
>@@ -0,0 +1,60 @@
>+# Guid Check Plugin
>+
>+This CiBuildPlugin scans all the files in a code tree to find all the GUID
>definitions.  After collection it will then look for duplication in the package
>under test.  Uniqueness of all GUIDs are critical within the UEFI environment.
>Duplication can cause numerous issues including locating the wrong data
>structure, calling the wrong function, or decoding the wrong data members.
>+
>+Currently Scanned:
>+
>+* INF files are scanned for there Module guid
>+* DEC files are scanned for all of their Protocols, PPIs, and Guids as well as
>the one package GUID.
>+
>+Any GUID value being equal to two names or even just defined in two files is
>considered an error unless in the ignore list.
>+
>+Any GUID name that is found more than once is an error unless all
>occurrences are Module GUIDs.  Since the Module GUID is assigned to the
>Module name it is common to have numerous versions of the same module
>named the same.
>+
>+## Configuration
>+
>+The plugin has numerous configuration options to support the UEFI
>codebase.
>+
>+``` yaml
>+"GuidCheck": {
>+        "IgnoreGuidName": [],
>+        "IgnoreGuidValue": [],
>+        "IgnoreFoldersAndFiles": [],
>+        "IgnoreDuplicates": []
>+    }
>+```
>+
>+### IgnoreGuidName
>+
>+This list allows strings in two formats.
>+
>+* _GuidName_
>+  * This will remove any entry with this GuidName from the list of GUIDs
>therefore ignoring any error associated with this name.
>+* _GuidName=GuidValue_
>+  * This will also ignore the GUID by name but only if the value equals the
>GuidValue.
>+  * GuidValue should be in registry format.
>+  * This is the suggested format to use as it will limit the ignore to only the
>defined case.
>+
>+### IgnoreGuidValue
>+
>+This list allows strings in guid registry format _GuidValue_.
>+
>+* This will remove any entry with this GuidValue from the list of GUIDs
>therefore ignoring any error associated with this value.
>+* GuidValue must be in registry format xxxxxxxx-xxxx-xxxx-xxxx-
>xxxxxxxxxxxx
>+
>+### IgnoreFoldersAndFiles
>+
>+This supports .gitignore file and folder matching strings including wildcards
>+
>+* Any folder or file ignored will not be parsed and therefore any GUID
>defined will be ignored.
>+* The plugin will always ignores the following ["/Build", "/Conf"]
>+
>+### IgnoreDuplicates
>+
>+This supports strings in the format of
>_GuidName_=_GuidName_=_GuidName_
>+
>+* For the error with the GuidNames to be ignored the list must match
>completely with what is found during the code scan.
>+  * For example if there are two GUIDs that are by design equal within the
>code tree then it should be _GuidName_=_GuidName_
>+  * If instead there are three GUIDs then it must be
>_GuidName_=_GuidName_=_GuidName_
>+* This is the best ignore list to use because it is the most strict and will catch
>new problems when new conflicts are introduced.
>+* There are numerous places in the UEFI specification in which two GUID
>names are assigned the same value.  These names should be set in this ignore
>list so that they don't cause an error but any additional duplication would still
>be caught.
>diff --git a/.pytool/Plugin/LibraryClassCheck/LibraryClassCheck.py
>b/.pytool/Plugin/LibraryClassCheck/LibraryClassCheck.py
>new file mode 100644
>index 0000000000..33745dff11
>--- /dev/null
>+++ b/.pytool/Plugin/LibraryClassCheck/LibraryClassCheck.py
>@@ -0,0 +1,153 @@
>+# @file LibraryClassCheck.py
>+#
>+# Copyright (c) Microsoft Corporation. All rights reserved.
>+# SPDX-License-Identifier: BSD-2-Clause-Patent
>+##
>+import logging
>+import os
>+from edk2toolext.environment.plugintypes.ci_build_plugin import
>ICiBuildPlugin
>+from edk2toollib.uefi.edk2.parsers.dec_parser import DecParser
>+from edk2toollib.uefi.edk2.parsers.inf_parser import InfParser
>+from edk2toolext.environment.var_dict import VarDict
>+
>+
>+class LibraryClassCheck(ICiBuildPlugin):
>+    """
>+    A CiBuildPlugin that scans the code tree and library classes for undeclared
>+    files
>+
>+    Configuration options:
>+    "LibraryClassCheck": {
>+        IgnoreHeaderFile: [],  # Ignore a file found on disk
>+        IgnoreLibraryClass: [] # Ignore a declaration found in dec file
>+    }
>+    """
>+
>+    def GetTestName(self, packagename: str, environment: VarDict) -> tuple:
>+        """ Provide the testcase name and classname for use in reporting
>+            testclassname: a descriptive string for the testcase can include
>whitespace
>+            classname: should be patterned <packagename>.<plugin>.<optionally
>any unique condition>
>+
>+            Args:
>+              packagename: string containing name of package to build
>+              environment: The VarDict for the test to run in
>+            Returns:
>+                a tuple containing the testcase name and the classname
>+                (testcasename, classname)
>+        """
>+        return ("Check library class declarations in " + packagename,
>packagename + ".LibraryClassCheck")
>+
>+    def __GetPkgDec(self, rootpath):
>+        try:
>+            allEntries = os.listdir(rootpath)
>+            for entry in allEntries:
>+                if entry.lower().endswith(".dec"):
>+                    return(os.path.join(rootpath, entry))
>+        except Exception:
>+            logging.error("Unable to find DEC for package:{0}".format(rootpath))
>+
>+        return None
>+
>+    ##
>+    # External function of plugin.  This function is used to perform the task of
>the MuBuild Plugin
>+    #
>+    #   - package is the edk2 path to package.  This means
>workspace/packagepath relative.
>+    #   - edk2path object configured with workspace and packages path
>+    #   - PkgConfig Object (dict) for the pkg
>+    #   - EnvConfig Object
>+    #   - Plugin Manager Instance
>+    #   - Plugin Helper Obj Instance
>+    #   - Junit Logger
>+    #   - output_stream the StringIO output stream from this plugin via logging
>+    def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig,
>environment, PLM, PLMHelper, tc, output_stream=None):
>+        overall_status = 0
>+        LibraryClassIgnore = []
>+
>+        abs_pkg_path =
>Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2RelativePath(packagen
>ame)
>+        abs_dec_path = self.__GetPkgDec(abs_pkg_path)
>+        wsr_dec_path =
>Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(abs_dec_path)
>+
>+        if abs_dec_path is None or wsr_dec_path is "" or not
>os.path.isfile(abs_dec_path):
>+            tc.SetSkipped()
>+            tc.LogStdError("No DEC file {0} in package {1}".format(abs_dec_path,
>abs_pkg_path))
>+            return -1
>+
>+        # Get all include folders
>+        dec = DecParser()
>+
>dec.SetBaseAbsPath(Edk2pathObj.WorkspacePath).SetPackagePaths(Edk2pa
>thObj.PackagePathList)
>+        dec.ParseFile(wsr_dec_path)
>+
>+        AllHeaderFiles = []
>+
>+        for includepath in dec.IncludePaths:
>+            ## Get all header files in the library folder
>+            AbsLibraryIncludePath = os.path.join(abs_pkg_path, includepath,
>"Library")
>+            if(not os.path.isdir(AbsLibraryIncludePath)):
>+                continue
>+
>+            hfiles = self.WalkDirectoryForExtension([".h"], AbsLibraryIncludePath)
>+            hfiles = [os.path.relpath(x,abs_pkg_path) for x in hfiles]  # make
>package root relative path
>+            hfiles = [x.replace("\\", "/") for x in hfiles]  # make package relative
>path
>+
>+            AllHeaderFiles.extend(hfiles)
>+
>+        if len(AllHeaderFiles) == 0:
>+            tc.SetSkipped()
>+            tc.LogStdError(f"No Library include folder in any Include path")
>+            return -1
>+
>+        # Remove ignored paths
>+        if "IgnoreHeaderFile" in pkgconfig:
>+            for a in pkgconfig["IgnoreHeaderFile"]:
>+                try:
>+                    tc.LogStdOut("Ignoring Library Header File {0}".format(a))
>+                    AllHeaderFiles.remove(a)
>+                except:
>+                    tc.LogStdError("LibraryClassCheck.IgnoreHeaderFile -> {0} not
>found.  Invalid Header File".format(a))
>+                    logging.info("LibraryClassCheck.IgnoreHeaderFile -> {0} not found.
>Invalid Header File".format(a))
>+
>+        if "IgnoreLibraryClass" in pkgconfig:
>+            LibraryClassIgnore = pkgconfig["IgnoreLibraryClass"]
>+
>+
>+        ## Attempt to find library classes
>+        for lcd in dec.LibraryClasses:
>+            ## Check for correct file path separator
>+            if "\\" in lcd.path:
>+                tc.LogStdError("LibraryClassCheck.DecFilePathSeparator -> {0}
>invalid.".format(lcd.path))
>+                logging.error("LibraryClassCheck.DecFilePathSeparator -> {0}
>invalid.".format(lcd.path))
>+                overall_status += 1
>+                continue
>+
>+            if lcd.name in LibraryClassIgnore:
>+                tc.LogStdOut("Ignoring Library Class Name {0}".format(lcd.name))
>+                LibraryClassIgnore.remove(lcd.name)
>+                continue
>+
>+            logging.debug(f"Looking for Library Class {lcd.path}")
>+            try:
>+                AllHeaderFiles.remove(lcd.path)
>+
>+            except ValueError:
>+                tc.LogStdError(f"Library {lcd.name} with path {lcd.path} not found in
>package filesystem")
>+                logging.error(f"Library {lcd.name} with path {lcd.path} not found in
>package filesystem")
>+                overall_status += 1
>+
>+        ## any remaining AllHeaderFiles are not described in DEC
>+        for h in AllHeaderFiles:
>+            tc.LogStdError(f"Library Header File {h} not declared in package DEC
>{wsr_dec_path}")
>+            logging.error(f"Library Header File {h} not declared in package DEC
>{wsr_dec_path}")
>+            overall_status += 1
>+
>+        ## Warn about any invalid library class names in the ignore list
>+        for r in LibraryClassIgnore:
>+            tc.LogStdError("LibraryClassCheck.IgnoreLibraryClass -> {0} not found.
>Library Class not found".format(r))
>+            logging.info("LibraryClassCheck.IgnoreLibraryClass -> {0} not found.
>Library Class not found".format(r))
>+
>+
>+        # If XML object exists, add result
>+        if overall_status is not 0:
>+            tc.SetFailed("LibraryClassCheck {0} Failed.  Errors
>{1}".format(wsr_dec_path, overall_status), "CHECK_FAILED")
>+        else:
>+            tc.SetSuccess()
>+        return overall_status
>diff --git a/.pytool/Plugin/LibraryClassCheck/LibraryClassCheck_plug_in.yaml
>b/.pytool/Plugin/LibraryClassCheck/LibraryClassCheck_plug_in.yaml
>new file mode 100644
>index 0000000000..9174453a86
>--- /dev/null
>+++ b/.pytool/Plugin/LibraryClassCheck/LibraryClassCheck_plug_in.yaml
>@@ -0,0 +1,11 @@
>+##
>+# CiBuildPlugin used to check that all library classes are declared correctly in
>dec file
>+#
>+# Copyright (c) 2019, Microsoft Corporation
>+# SPDX-License-Identifier: BSD-2-Clause-Patent
>+##
>+{
>+  "scope": "cibuild",
>+  "name": "Library Class Check Test",
>+  "module": "LibraryClassCheck"
>+}
>diff --git a/.pytool/Plugin/LibraryClassCheck/readme.md
>b/.pytool/Plugin/LibraryClassCheck/readme.md
>new file mode 100644
>index 0000000000..dedee16988
>--- /dev/null
>+++ b/.pytool/Plugin/LibraryClassCheck/readme.md
>@@ -0,0 +1,22 @@
>+# Library Class Check Plugin
>+
>+This CiBuildPlugin scans at all library header files found in the `Library` folders
>in all of the package's declared include directories and ensures that all files
>have a matching LibraryClass declaration in the DEC file for the package. Any
>missing declarations will cause a failure.
>+
>+## Configuration
>+
>+The plugin has a few configuration options to support the UEFI codebase.
>+
>+``` yaml
>+"LibraryClassCheck": {
>+    IgnoreHeaderFile: [],  # Ignore a file found on disk
>+    IgnoreLibraryClass: [] # Ignore a declaration found in dec file
>+}
>+```
>+
>+### IgnoreHeaderFile
>+
>+Ignore a file found on disk
>+
>+### IgnoreLibraryClass
>+
>+Ignore a declaration found in dec file
>diff --git a/.pytool/Plugin/SpellCheck/Readme.md
>b/.pytool/Plugin/SpellCheck/Readme.md
>new file mode 100644
>index 0000000000..e0ac835191
>--- /dev/null
>+++ b/.pytool/Plugin/SpellCheck/Readme.md
>@@ -0,0 +1,100 @@
>+# Spell Check Plugin
>+
>+This CiBuildPlugin scans all the files in a given package and checks for spelling
>errors.
>+
>+This plugin requires NodeJs and cspell.  If the plugin doesn't find its required
>tools then it will mark the test as skipped.
>+
>+* NodeJS: https://nodejs.org/en/
>+* cspell: https://www.npmjs.com/package/cspell
>+  * Src and doc available: https://github.com/streetsidesoftware/cspell
>+
>+## Configuration
>+
>+The plugin has a few configuration options to support the UEFI codebase.
>+
>+``` yaml
>+  "SpellCheck": {
>+      "AuditOnly": False,          # If True, log all errors and then mark as skipped
>+      "IgnoreFiles": [],           # use gitignore syntax to ignore errors in matching
>files
>+      "ExtendWords": [],           # words to extend to the dictionary for this
>package
>+      "IgnoreStandardPaths": [],   # Standard Plugin defined paths that should
>be ignore
>+      "AdditionalIncludePaths": [] # Additional paths to spell check (wildcards
>supported)
>+  }
>+```
>+
>+### AuditOnly
>+
>+Boolean - Default is False.
>+If True run the test in an Audit only mode which will log all errors but instead
>of failing the build it will set the test as skipped.  This allows visibility into the
>failures without breaking the build.
>+
>+### IgnoreFiles
>+
>+This supports .gitignore file and folder matching strings including wildcards
>+
>+* All files will be parsed regardless but then any spelling errors found within
>ignored files will not be reported as an error.
>+* Errors in ignored files will still be output to the test results as informational
>comments.
>+
>+### ExtendWords
>+
>+This list allows words to be added to the dictionary for the spell checker
>when this package is tested.  These follow the rules of the cspell config words
>field.
>+
>+### IgnoreStandardPaths
>+
>+This plugin by default will check the below standard paths.  If the package
>would like to ignore any of them list that here.
>+
>+```python
>+[
>+# C source
>+"*.c",
>+"*.h",
>+
>+# Assembly files
>+"*.nasm",
>+"*.asm",
>+"*.masm",
>+"*.s",
>+
>+# ACPI source language
>+"*.asl",
>+
>+# Edk2 build files
>+"*.dsc", "*.dec", "*.fdf", "*.inf",
>+
>+# Documentation files
>+"*.md", "*.txt"
>+]
>+```
>+
>+### AdditionalIncludePaths
>+
>+If the package would to add additional path patterns to be included in
>spellchecking they can be defined here.
>+
>+## Other configuration
>+
>+In the cspell.base.json there are numerous other settings configured.  There
>is no support to override these on a per package basis but future features
>could make this available.  One interesting configuration option is
>`minWordLength`.  Currently it is set to _5_ which means all 2,3, and 4 letter
>words will be ignored.  This helps minimize the number of technical acronyms,
>register names, and other UEFI specific values that must be ignored .
>+
>+## False positives
>+
>+The cspell dictionary is not perfect and there are cases where technical
>words or acronyms are not found in the dictionary.  There are three ways to
>resolve false positives and the choice for which method should be based on
>how broadly the word should be accepted.
>+
>+### CSpell Base Config file
>+
>+If the change should apply to all UEFI code and documentation then it should
>be added to the base config file `words` section.  The base config file is
>adjacent to this file and titled `cspell.base.json`.  This is a list of accepted
>words for all spell checking operations on all packages.
>+
>+### Package Config
>+
>+In the package `*.ci.yaml` file there is a `SpellCheck` config section.  This
>section allows files to be ignored as well as words that should be considered
>valid for all files within this package.  Add the desired words to the
>"ExtendedWords" member.
>+
>+### In-line File
>+
>+CSpell supports numerous methods to annotate your files to ignore words,
>sections, etc.  This can be found in CSpell documentation.  Suggestion here is
>to use a c-style comment at the top of the file to add words that should be
>ignored just for this file.  Obviously this has the highest maintenance cost so it
>should only be used for file unique words.
>+
>+``` c
>+// spell-checker:ignore unenroll, word2, word3
>+```
>+
>+or
>+
>+```ini
>+# spell-checker:ignore unenroll, word2, word3
>+```
>diff --git a/.pytool/Plugin/SpellCheck/SpellCheck.py
>b/.pytool/Plugin/SpellCheck/SpellCheck.py
>new file mode 100644
>index 0000000000..94ca4cd071
>--- /dev/null
>+++ b/.pytool/Plugin/SpellCheck/SpellCheck.py
>@@ -0,0 +1,216 @@
>+# @file SpellCheck.py
>+#
>+# An edk2-pytool based plugin wrapper for cspell
>+#
>+# Copyright (c) Microsoft Corporation. All rights reserved.
>+# SPDX-License-Identifier: BSD-2-Clause-Patent
>+##
>+import logging
>+import json
>+import yaml
>+from io import StringIO
>+import os
>+from edk2toolext.environment.plugintypes.ci_build_plugin import
>ICiBuildPlugin
>+from edk2toollib.utility_functions import RunCmd
>+from edk2toolext.environment.var_dict import VarDict
>+from edk2toollib.gitignore_parser import parse_gitignore_lines
>+from edk2toolext.environment import version_aggregator
>+
>+
>+class SpellCheck(ICiBuildPlugin):
>+    """
>+    A CiBuildPlugin that uses the cspell node module to scan the files
>+    from the package being tested for spelling errors.  The plugin contains
>+    the base cspell.json file then thru the configuration options other settings
>+    can be changed or extended.
>+
>+    Configuration options:
>+    "SpellCheck": {
>+        "AuditOnly": False,          # Don't fail the build if there are errors.  Just log
>them
>+        "IgnoreFiles": [],           # use gitignore syntax to ignore errors in matching
>files
>+        "ExtendWords": [],           # words to extend to the dictionary for this
>package
>+        "IgnoreStandardPaths": [],   # Standard Plugin defined paths that should
>be ignore
>+        "AdditionalIncludePaths": [] # Additional paths to spell check (wildcards
>supported)
>+    }
>+    """
>+
>+    #
>+    # A package can remove any of these using IgnoreStandardPaths
>+    #
>+    STANDARD_PLUGIN_DEFINED_PATHS = ["*.c", "*.h",
>+                                     "*.nasm", "*.asm", "*.masm", "*.s",
>+                                     "*.asl",
>+                                     "*.dsc", "*.dec", "*.fdf", "*.inf",
>+                                     "*.md", "*.txt"
>+                                     ]
>+
>+    def GetTestName(self, packagename: str, environment: VarDict) -> tuple:
>+        """ Provide the testcase name and classname for use in reporting
>+
>+            Args:
>+              packagename: string containing name of package to build
>+              environment: The VarDict for the test to run in
>+            Returns:
>+                a tuple containing the testcase name and the classname
>+                (testcasename, classname)
>+                testclassname: a descriptive string for the testcase can include
>whitespace
>+                classname: should be patterned
><packagename>.<plugin>.<optionally any unique condition>
>+        """
>+        return ("Spell check files in " + packagename, packagename +
>".SpellCheck")
>+
>+    ##
>+    # External function of plugin.  This function is used to perform the task of
>the CiBuild Plugin
>+    #
>+    #   - package is the edk2 path to package.  This means
>workspace/packagepath relative.
>+    #   - edk2path object configured with workspace and packages path
>+    #   - PkgConfig Object (dict) for the pkg
>+    #   - EnvConfig Object
>+    #   - Plugin Manager Instance
>+    #   - Plugin Helper Obj Instance
>+    #   - Junit Logger
>+    #   - output_stream the StringIO output stream from this plugin via logging
>+
>+    def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig,
>environment, PLM, PLMHelper, tc, output_stream=None):
>+        Errors = []
>+
>+        abs_pkg_path =
>Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2RelativePath(
>+            packagename)
>+
>+        if abs_pkg_path is None:
>+            tc.SetSkipped()
>+            tc.LogStdError("No package {0}".format(packagename))
>+            return -1
>+
>+        # check for node
>+        return_buffer = StringIO()
>+        ret = RunCmd("node", "--version", outstream=return_buffer)
>+        if (ret != 0):
>+            tc.SetSkipped()
>+            tc.LogStdError("NodeJs not installed. Test can't run")
>+            logging.warning("NodeJs not installed. Test can't run")
>+            return -1
>+        node_version = return_buffer.getvalue().strip()  # format vXX.XX.XX
>+        tc.LogStdOut(f"Node version: {node_version}")
>+        version_aggregator.GetVersionAggregator().ReportVersion(
>+            "NodeJs", node_version, version_aggregator.VersionTypes.INFO)
>+
>+        # Check for cspell
>+        return_buffer = StringIO()
>+        ret = RunCmd("cspell", "--version", outstream=return_buffer)
>+        if (ret != 0):
>+            tc.SetSkipped()
>+            tc.LogStdError("cspell not installed.  Test can't run")
>+            logging.warning("cspell not installed.  Test can't run")
>+            return -1
>+        cspell_version = return_buffer.getvalue().strip()  # format XX.XX.XX
>+        tc.LogStdOut(f"CSpell version: {cspell_version}")
>+        version_aggregator.GetVersionAggregator().ReportVersion(
>+            "CSpell", cspell_version, version_aggregator.VersionTypes.INFO)
>+
>+        package_relative_paths_to_spell_check =
>SpellCheck.STANDARD_PLUGIN_DEFINED_PATHS
>+
>+        #
>+        # Allow the ci.yaml to remove any of the above standard paths
>+        #
>+        if("IgnoreStandardPaths" in pkgconfig):
>+            for a in pkgconfig["IgnoreStandardPaths"]:
>+                if(a in package_relative_paths_to_spell_check):
>+                    tc.LogStdOut(
>+                        f"ignoring standard path due to ci.yaml ignore: {a}")
>+                    package_relative_paths_to_spell_check.remove(a)
>+                else:
>+                    tc.LogStdOut(f"Invalid IgnoreStandardPaths value: {a}")
>+
>+        #
>+        # check for any additional include paths defined by package config
>+        #
>+        if("AdditionalIncludePaths" in pkgconfig):
>+            package_relative_paths_to_spell_check.extend(
>+                pkgconfig["AdditionalIncludePaths"])
>+
>+        #
>+        # Make the path string for cspell to check
>+        #
>+        relpath = os.path.relpath(abs_pkg_path)
>+        cpsell_paths = " ".join(
>+            [f"{relpath}/**/{x}" for x in package_relative_paths_to_spell_check])
>+
>+        # Make the config file
>+        config_file_path = os.path.join(
>+            Edk2pathObj.WorkspacePath, "Build", packagename,
>"cspell_actual_config.json")
>+        mydir = os.path.dirname(os.path.abspath(__file__))
>+        # load as yaml so it can have comments
>+        base = os.path.join(mydir, "cspell.base.yaml")
>+        with open(base, "r") as i:
>+            config = yaml.safe_load(i)
>+
>+        if("ExtendWords" in pkgconfig):
>+            config["words"].extend(pkgconfig["ExtendWords"])
>+        with open(config_file_path, "w") as o:
>+            json.dump(config, o)  # output as json so compat with cspell
>+
>+        All_Ignores = []
>+        # Parse the config for other ignores
>+        if "IgnoreFiles" in pkgconfig:
>+            All_Ignores.extend(pkgconfig["IgnoreFiles"])
>+
>+        # spell check all the files
>+        ignore = parse_gitignore_lines(All_Ignores, os.path.join(
>+            abs_pkg_path, "nofile.txt"), abs_pkg_path)
>+
>+        # result is a list of strings like this
>+        #  C:\src\sp-edk2\edk2\FmpDevicePkg\FmpDevicePkg.dec:53:9 -
>Unknown word (Capule)
>+        EasyFix = []
>+        results = self._check_spelling(cpsell_paths, config_file_path)
>+        for r in results:
>+            path, _, word = r.partition(" - Unknown word ")
>+            if len(word) == 0:
>+                # didn't find pattern
>+                continue
>+
>+            pathinfo = path.rsplit(":", 2)  # remove the line no info
>+            if(ignore(pathinfo[0])):  # check against ignore list
>+                tc.LogStdOut(f"ignoring error due to ci.yaml ignore: {r}")
>+                continue
>+
>+            # real error
>+            EasyFix.append(word.strip().strip("()"))
>+            Errors.append(r)
>+
>+        # Log all errors tc StdError
>+        for l in Errors:
>+            tc.LogStdError(l.strip())
>+
>+        # Helper - Log the syntax needed to add these words to dictionary
>+        if len(EasyFix) > 0:
>+            EasyFix = sorted(set(a.lower() for a in EasyFix))
>+            tc.LogStdOut("\n Easy fix:")
>+            OneString = "If these are not errors add this to your ci.yaml file.\n"
>+            OneString += '"SpellCheck": {\n  "ExtendWords": ['
>+            for a in EasyFix:
>+                tc.LogStdOut(f'\n"{a}",')
>+                OneString += f'\n    "{a}",'
>+            logging.info(OneString.rstrip(",") + '\n  ]\n}')
>+
>+        # add result to test case
>+        overall_status = len(Errors)
>+        if overall_status != 0:
>+            if "AuditOnly" in pkgconfig and pkgconfig["AuditOnly"]:
>+                # set as skipped if AuditOnly
>+                tc.SetSkipped()
>+                return -1
>+            else:
>+                tc.SetFailed("SpellCheck {0} Failed.  Errors {1}".format(
>+                    packagename, overall_status), "CHECK_FAILED")
>+        else:
>+            tc.SetSuccess()
>+        return overall_status
>+
>+    def _check_spelling(self, abs_file_to_check: str, abs_config_file_to_use:
>str) -> []:
>+        output = StringIO()
>+        ret = RunCmd(
>+            "cspell", f"--config {abs_config_file_to_use} {abs_file_to_check}",
>outstream=output)
>+        if ret == 0:
>+            return []
>+        else:
>+            return output.getvalue().strip().splitlines()
>diff --git a/.pytool/Plugin/SpellCheck/SpellCheck_plug_in.yaml
>b/.pytool/Plugin/SpellCheck/SpellCheck_plug_in.yaml
>new file mode 100644
>index 0000000000..161045e19e
>--- /dev/null
>+++ b/.pytool/Plugin/SpellCheck/SpellCheck_plug_in.yaml
>@@ -0,0 +1,11 @@
>+##
>+# CiBuildPlugin used to check spelling
>+#
>+# Copyright (c) 2019, Microsoft Corporation
>+# SPDX-License-Identifier: BSD-2-Clause-Patent
>+##
>+{
>+  "scope": "cibuild",
>+  "name": "Spell Check Test",
>+  "module": "SpellCheck"
>+}
>diff --git a/.pytool/Plugin/SpellCheck/cspell.base.yaml
>b/.pytool/Plugin/SpellCheck/cspell.base.yaml
>new file mode 100644
>index 0000000000..da6c5e5da7
>--- /dev/null
>+++ b/.pytool/Plugin/SpellCheck/cspell.base.yaml
>@@ -0,0 +1,165 @@
>+##
>+# CSpell configuration
>+#
>+# Copyright (c) Microsoft Corporation
>+# SPDX-License-Identifier: BSD-2-Clause-Patent
>+##
>+{
>+    "version": "0.1",
>+    "language": "en",
>+    "dictionaries": [
>+        "companies ",
>+        "softwareTerms",
>+        "python",
>+        "cpp"
>+    ],
>+    "ignorePaths": [
>+        "*.pdb",
>+        "**/*_extdep/**",
>+        "*.pdf",
>+        "*.exe",
>+        "*.jpg"
>+    ],
>+    "minWordLength": 5,
>+    "allowCompoundWords": false,
>+    "ignoreWords": [
>+        "muchange"
>+    ],
>+    "words": [
>+        "MTRRs",
>+        "Microarchitecture",
>+        "Goldmont",
>+        "cpuid",
>+        "mwait",
>+        "cstate",
>+        "smram",
>+        "scrtm",
>+        "smbus",
>+        "selftest",
>+        "socket",
>+        "MMRAM",
>+        "qword",
>+        "ENDBR",
>+        "SMBASE",
>+        "FXSAVE",
>+        "FXRSTOR",
>+        "RDRAND",
>+        "IOAPIC",
>+        "ATAPI",
>+        "movsb",
>+        "iretw",
>+        "XENSTORE",
>+        "cdrom",
>+        "oprom",
>+        "oproms",
>+        "varstore",
>+        "EKU",
>+        "ascii",
>+        "nmake",
>+        "NVDIMM",
>+        "nasmb",
>+        "Mtftp",
>+        "Hypercall",
>+        "hypercalls",
>+        "IOMMU",
>+        "QEMU",
>+        "qemus",
>+        "OVMF",
>+        "tiano",
>+        "tianocore",
>+        "edkii",
>+        "coreboot",
>+        "uefipayload",
>+        "bootloader",
>+        "bootloaders",
>+        "mdepkg",
>+        "skuid",
>+        "dxefv",
>+        "toolchain",
>+        "libraryclass",
>+        "preboot",
>+        "pythonpath",
>+        "cygpath",
>+        "nuget",
>+        "basetools",
>+        "prepi",
>+        "OPTEE",
>+        "stringid",
>+        "peims",
>+        "memmap",
>+        "guids",
>+        "uuids",
>+        "smbios",
>+        "certdb",
>+        "certdbv",
>+        "EfiSigList",
>+        "depex",
>+        "IHANDLE",
>+        "Virtio",
>+        "Mbytes",
>+        "Citrix",
>+        "initrd",
>+        "semihost",
>+        "Semihosting",
>+        "Trustzone",
>+        "Fastboot",
>+        "framebuffer",
>+        "genfw",
>+        "TTYTERM",
>+        "miniport",
>+        "LFENCE",
>+        "PCANSI",
>+        "submodule",
>+        "submodules",
>+        "brotli",
>+        "PCCTS",
>+        "softfloat",
>+        "whitepaper",
>+        "ACPICA",
>+        "plugfest",
>+        "bringup",
>+        "formset", #VFR
>+        "ideqvallist",
>+        "numberof",
>+        "oneof",
>+        "endformset",
>+        "endnumeric",
>+        "endoneof",
>+        "disableif",
>+        "guidid",
>+        "classguid",
>+        "efivarstore",
>+        "formsetguid",
>+        "formid",
>+        "suppressif",
>+        "grayoutif",
>+        "ideqval",
>+        "endform",
>+        "endcheckbox",
>+        "questionid",
>+        "questionref",
>+        "enddate",
>+        "endstring",
>+        "guidop",
>+        "endguidop",
>+        "langdef",
>+        "dynamicex",
>+        "tokenspace",
>+        "tokenguid",
>+        "pcd's", #seems like cspell bug
>+        "peim's",
>+        "autogen",
>+        "Disasm",
>+        "Torito",
>+        "SRIOV",
>+        "MRIOV",
>+        "UARTs",
>+        "Consplitter", # common module in UEFI
>+        "FIFOs",
>+        "ACPINVS",
>+        "Endof",  # due to of not being uppercase
>+        "bootability",
>+        "Sdhci",
>+        "inmodule",
>+    ]
>+}
>--
>2.21.0.windows.1


  reply	other threads:[~2019-11-07  6:58 UTC|newest]

Thread overview: 51+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-11-07  1:13 [Patch v4 00/22] Enable Phase 1 of EDK II CI Michael D Kinney
2019-11-07  1:13 ` [Patch v4 01/22] Maintainers.txt: Add continuous integration(CI) directories Michael D Kinney
2019-11-07  1:13 ` [Patch v4 02/22] .gitignore: Ignore python compiled files, extdeps, and vscode Michael D Kinney
2019-11-07 10:26   ` Laszlo Ersek
2019-11-07  1:13 ` [Patch v4 03/22] requirements.txt: Add python pip requirements file Michael D Kinney
2019-11-07 10:39   ` Laszlo Ersek
2019-11-07 15:43     ` Leif Lindholm
2019-11-07 17:44     ` Michael D Kinney
2019-11-08 13:12       ` Laszlo Ersek
2019-11-08 16:58         ` Michael D Kinney
2019-11-07 10:49   ` Laszlo Ersek
2019-11-07  1:13 ` [Patch v4 04/22] BaseTools: Add RC_PATH define for VS2017/2019 Michael D Kinney
2019-11-07  1:13 ` [Patch v4 05/22] BaseTools: Add YAML files with path env and tool extdeps Michael D Kinney
2019-11-07  1:13 ` [Patch v4 06/22] BaseTools: Add BaseTools plugins to support CI Michael D Kinney
2019-11-07  1:13 ` [Patch v4 07/22] .pytool/Plugin: Add CI plugins Michael D Kinney
2019-11-07  6:58   ` Liming Gao [this message]
2019-11-07  1:13 ` [Patch v4 08/22] CryptoPkg: Add YAML file for CI builds Michael D Kinney
2019-11-07  5:06   ` Wang, Jian J
2019-11-07  1:13 ` [Patch v4 09/22] FatPkg: " Michael D Kinney
2019-11-07  2:12   ` Ni, Ray
2019-11-07  1:13 ` [Patch v4 10/22] FmpDevicePkg: " Michael D Kinney
2019-11-07  1:13 ` [Patch v4 11/22] MdeModulePkg: " Michael D Kinney
2019-11-07  3:03   ` Wu, Hao A
2019-11-07 20:02     ` Michael D Kinney
2019-11-07  1:13 ` [Patch v4 12/22] MdePkg: " Michael D Kinney
2019-11-07  1:13 ` [Patch v4 13/22] NetworkPkg: " Michael D Kinney
2019-11-07  1:13 ` [Patch v4 14/22] PcAtChipsetPkg: Add YAML files " Michael D Kinney
2019-11-07  2:12   ` Ni, Ray
2019-11-07  1:13 ` [Patch v4 15/22] SecurityPkg: " Michael D Kinney
2019-11-07  5:08   ` Wang, Jian J
2019-11-07  1:13 ` [Patch v4 16/22] ShellPkg: Add YAML file " Michael D Kinney
2019-11-07  2:12   ` Ni, Ray
2019-11-07  1:13 ` [Patch v4 17/22] UefiCpuPkg: " Michael D Kinney
2019-11-07  2:12   ` Ni, Ray
2019-11-07 10:42   ` Laszlo Ersek
2019-11-07 10:48     ` Laszlo Ersek
2019-11-07 19:23       ` [edk2-devel] " Michael D Kinney
2019-11-07 19:33         ` Sean
2019-11-08 14:43           ` Laszlo Ersek
2019-11-07  1:13 ` [Patch v4 18/22] SignedCapsulePkg: Use BaseCryptLibNull to reduce package CI time Michael D Kinney
2019-11-07  1:13 ` [Patch v4 19/22] .pytool: Add CISettings.py and Readme.md Michael D Kinney
2019-11-07 16:16   ` [edk2-devel] " rebecca
2019-11-07  1:13 ` [Patch v4 20/22] .azurepipelines: Add Azure Pipelines YML configuration files Michael D Kinney
2019-11-07  1:13 ` [Patch v4 21/22] .mergify: Add Mergify YML pull request rules configuration file Michael D Kinney
2019-11-07  1:13 ` [Patch v4 22/22] Readme.md: Add CI build status badges Michael D Kinney
2019-11-07 10:44   ` Laszlo Ersek
2019-11-07 16:00   ` Leif Lindholm
2019-11-07 19:42     ` Michael D Kinney
2019-11-07 23:16       ` Leif Lindholm
2019-11-08  9:24       ` Leif Lindholm
2019-11-07 15:35 ` [Patch v4 00/22] Enable Phase 1 of EDK II CI Liming Gao

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4A89E2EF3DFEDB4C8BFDE51014F606A14E539176@SHSMSX104.ccr.corp.intel.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox