public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Michael Kubacki" <mikuback@linux.microsoft.com>
To: devel@edk2.groups.io, michael.d.kinney@intel.com
Cc: Liming Gao <gaoliming@byosoft.com.cn>,
	Sean Brogan <sean.brogan@microsoft.com>,
	Bret Barkelew <Bret.Barkelew@microsoft.com>
Subject: Re: [edk2-devel] [PATCH v4 1/1] .pytool/Plugin/UncrustifyCheck: Add Uncrustify CI plugin
Date: Wed, 24 Nov 2021 20:25:06 -0500	[thread overview]
Message-ID: <8dbc6f60-dcb7-6a1f-c19e-3eb696c1afa3@linux.microsoft.com> (raw)
In-Reply-To: <16BAA253C971EED8.15594@groups.io>

I sent the v5 patch with the templates disabled:
https://edk2.groups.io/g/devel/message/84068

I also posted that patch on this branch:
https://github.com/makubacki/edk2/tree/add_uncrustify_ci_plugin_v5

I posted another branch that also has the commit to enable the templates 
here:
https://github.com/makubacki/edk2/commits/add_uncrustify_ci_plugin_v5_w_template_enable_commit

I will be out of office until Mon Nov. 29th for the US holiday.

Thanks,
Michael

On 11/24/2021 7:24 PM, Michael Kubacki wrote:
> Hi Mike,
> 
> How about I quickly send a v5 with the lines commented out and follow up 
> with a patch to uncomment them that we can review but merge when ready?
> 
> Thanks,
> Michael
> 
> On 11/24/2021 7:16 PM, Michael D Kinney wrote:
>> The 2nd option I listed won't work.  That will fail UncrustifyCheck as 
>> well because EDK II CI
>> will insert missing file/function headers and the files will not match.
>>
>> We will need to comment out these 2 lines and submit an extra commit 
>> to re-enable.
>>
>> Mike
>>
>>> -----Original Message-----
>>> From: Kinney, Michael D <michael.d.kinney@intel.com>
>>> Sent: Wednesday, November 24, 2021 4:08 PM
>>> To: devel@edk2.groups.io; mikuback@linux.microsoft.com; Kinney, 
>>> Michael D <michael.d.kinney@intel.com>
>>> Cc: Liming Gao <gaoliming@byosoft.com.cn>; Sean Brogan 
>>> <sean.brogan@microsoft.com>; Bret Barkelew
>>> <Bret.Barkelew@microsoft.com>
>>> Subject: RE: [edk2-devel] [PATCH v4 1/1] 
>>> .pytool/Plugin/UncrustifyCheck: Add Uncrustify CI plugin
>>>
>>> Hi Michael,
>>>
>>> Unfortunately, enabling the templates in the uncrustify.cfg files 
>>> modifies 340 files with missing
>>> file/function headers that will now fail UncrustifyCheck.
>>>
>>>      cmt_insert_file_header          = default_file_header.txt
>>>      cmt_insert_func_header          = default_function_header.txt
>>>
>>> Perhaps we should leave this feature off to get the uncrustify format 
>>> changes committed and
>>> enable this feature immediately after so patch reviews after that 
>>> will slowly fix these missing
>>> file/function headers.
>>>
>>> Or I can comment these two lines out when I generate the final 
>>> version of the patch series so
>>> we don’t have to do an extra commit to re-enable.
>>>
>>> Mike
>>>
>>>> -----Original Message-----
>>>> From: Kinney, Michael D <michael.d.kinney@intel.com>
>>>> Sent: Wednesday, November 24, 2021 3:06 PM
>>>> To: devel@edk2.groups.io; mikuback@linux.microsoft.com; Kinney, 
>>>> Michael D <michael.d.kinney@intel.com>
>>>> Cc: Liming Gao <gaoliming@byosoft.com.cn>; Sean Brogan 
>>>> <sean.brogan@microsoft.com>; Bret Barkelew
>>>> <Bret.Barkelew@microsoft.com>
>>>> Subject: RE: [edk2-devel] [PATCH v4 1/1] 
>>>> .pytool/Plugin/UncrustifyCheck: Add Uncrustify CI plugin
>>>>
>>>> Thanks.  That makes sense.
>>>>
>>>> Mike
>>>>
>>>>> -----Original Message-----
>>>>> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of 
>>>>> Michael Kubacki
>>>>> Sent: Wednesday, November 24, 2021 2:55 PM
>>>>> To: devel@edk2.groups.io; Kinney, Michael D 
>>>>> <michael.d.kinney@intel.com>
>>>>> Cc: Liming Gao <gaoliming@byosoft.com.cn>; Sean Brogan 
>>>>> <sean.brogan@microsoft.com>; Bret Barkelew
>>>>> <Bret.Barkelew@microsoft.com>
>>>>> Subject: Re: [edk2-devel] [PATCH v4 1/1] 
>>>>> .pytool/Plugin/UncrustifyCheck: Add Uncrustify CI plugin
>>>>>
>>>>> Yes. Those were redundant and detected by the Python configparser 
>>>>> module
>>>>> when I used it to parse the config file.
>>>>>
>>>>> Thanks,
>>>>> Michael
>>>>>
>>>>> On 11/24/2021 5:45 PM, Michael D Kinney wrote:
>>>>>> Hi Michael,
>>>>>>
>>>>>> I see a couple settings deleted from the uncrustify.cfg.  Was that 
>>>>>> in purpose?  Does it change the format?
>>>>>>
>>>>>>
>>>>>> -nl_func_call_start_multi_line   = true      # Whether to add a 
>>>>>> newline after '(' in a function call if '(' and ')'
>>>> are
>>>>>> -                                            # in different lines.
>>>>>>
>>>>>>
>>>>>> -nl_func_call_args_multi_line                 = true
>>>>>> -nl_func_call_args_multi_line_ignore_closures = false
>>>>>>
>>>>>>
>>>>>> Thanks,
>>>>>>
>>>>>> Mike
>>>>>>
>>>>>>> -----Original Message-----
>>>>>>> From: mikuback@linux.microsoft.com <mikuback@linux.microsoft.com>
>>>>>>> Sent: Wednesday, November 24, 2021 1:42 PM
>>>>>>> To: devel@edk2.groups.io
>>>>>>> Cc: Kinney, Michael D <michael.d.kinney@intel.com>; Liming Gao 
>>>>>>> <gaoliming@byosoft.com.cn>; Sean Brogan
>>>>>>> <sean.brogan@microsoft.com>; Bret Barkelew 
>>>>>>> <Bret.Barkelew@microsoft.com>
>>>>>>> Subject: [PATCH v4 1/1] .pytool/Plugin/UncrustifyCheck: Add 
>>>>>>> Uncrustify CI plugin
>>>>>>>
>>>>>>> From: Michael Kubacki <michael.kubacki@microsoft.com>
>>>>>>>
>>>>>>> REF:https://bugzilla.tianocore.org/show_bug.cgi?id=3748
>>>>>>>
>>>>>>> Adds a new CI plugin for Uncrustify. This is used to check
>>>>>>> coding standard compliance of source code to the EDK II C Coding
>>>>>>> Standards Specification.
>>>>>>>
>>>>>>> An external dependency is added in the plugin directory to retrieve
>>>>>>> the Uncrustify executable. Currently, the executable is from an edk2
>>>>>>> fork of the application host in this repository:
>>>>>>>
>>>>>>> https://dev.azure.com/projectmu/Uncrustify/
>>>>>>>
>>>>>>> Note that the Uncrustify application outputs the commit ID that the
>>>>>>> application was built from when given the --version parameter.
>>>>>>>
>>>>>>> This ID can be mapped to the version specified in the Uncrustify CI
>>>>>>> plugin external dependency file (uncrustify_ext_dep.yaml) such as
>>>>>>> 73.0.3 by visiting the Uncrustify edk2 fork release pipeline page
>>>>>>> which associates the NuGet package version with the commit ID it was
>>>>>>> built from:
>>>>>>>
>>>>>>> https://dev.azure.com/projectmu/Uncrustify/_build
>>>>>>>
>>>>>>> The default Uncrustify configuration files are added in the plugin
>>>>>>> directory. Additional details are in the Readme.md file added in
>>>>>>> the Uncrustify plugin directory.
>>>>>>>
>>>>>>> Cc: Michael D Kinney <michael.d.kinney@intel.com>
>>>>>>> Cc: Liming Gao <gaoliming@byosoft.com.cn>
>>>>>>> Cc: Sean Brogan <sean.brogan@microsoft.com>
>>>>>>> Cc: Bret Barkelew <Bret.Barkelew@microsoft.com>
>>>>>>> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com>
>>>>>>> ---
>>>>>>>
>>>>>>> Notes:
>>>>>>>       V4 changes:
>>>>>>>
>>>>>>>       1. Updated commit subject to use the new plugin name.
>>>>>>>       2. Enabled file and function header templates to be placed in
>>>>>>>          files missing a file or function header (comment block).
>>>>>>>       3. Added support to detect whether a file header or function
>>>>>>>          header is missing in a file by searching files modified by
>>>>>>>          Uncrustify for the template file text.
>>>>>>>       4. Updated the plugin name displayed in some log output 
>>>>>>> messages.
>>>>>>>
>>>>>>>       V3 changes:
>>>>>>>
>>>>>>>       1. Renamed the CI plugin to "UncrustifyCheck" from 
>>>>>>> "Uncrustify"
>>>>>>>          to follow similar naming conventions used in other plugins
>>>>>>>          that check files
>>>>>>>       2. Added a clarifying paragraph to the beginning of the 
>>>>>>> Uncrustify
>>>>>>>          CI plugin Readme.md file that the plugin is enabled by 
>>>>>>> default
>>>>>>>          and test results can be ignored by enabling "AuditOnly" 
>>>>>>> mode.
>>>>>>>       3. Added instructions in the commit message on how to map the
>>>>>>>          version reported by the Uncrustify application 
>>>>>>> (--version) to
>>>>>>>          the version specified in the CI plugin external dependency
>>>>>>>          YAML file.
>>>>>>>
>>>>>>>       V2 changes:
>>>>>>>
>>>>>>>       1. Changed plugin temp directory to 
>>>>>>> Build/.pytool/Plugin/Uncrustify
>>>>>>>       2. Added TCBZ REF in patch commit message
>>>>>>>
>>>>>>>    .pytool/Plugin/UncrustifyCheck/Readme.md                   | 
>>>>>>> 120 ++++
>>>>>>>    .pytool/Plugin/UncrustifyCheck/UncrustifyCheck.py          | 
>>>>>>> 617 ++++++++++++++++++++
>>>>>>>    .pytool/Plugin/UncrustifyCheck/default_file_header.txt     |   
>>>>>>> 9 +
>>>>>>>    .pytool/Plugin/UncrustifyCheck/default_function_header.txt |  
>>>>>>> 15 +
>>>>>>>    .pytool/Plugin/UncrustifyCheck/uncrustify.cfg              | 
>>>>>>> 462 +++++++++++++++
>>>>>>>    .pytool/Plugin/UncrustifyCheck/uncrustify_ext_dep.yaml     |  
>>>>>>> 16 +
>>>>>>>    .pytool/Plugin/UncrustifyCheck/uncrustify_plug_in.yaml     |  
>>>>>>> 11 +
>>>>>>>    .pytool/Readme.md                                          |   
>>>>>>> 4 +
>>>>>>>    8 files changed, 1254 insertions(+)
>>>>>>>
>>>>>>> diff --git a/.pytool/Plugin/UncrustifyCheck/Readme.md 
>>>>>>> b/.pytool/Plugin/UncrustifyCheck/Readme.md
>>>>>>> new file mode 100644
>>>>>>> index 000000000000..bb263bcc87d7
>>>>>>> --- /dev/null
>>>>>>> +++ b/.pytool/Plugin/UncrustifyCheck/Readme.md
>>>>>>> @@ -0,0 +1,120 @@
>>>>>>> +# UncrustifyCheck Plugin
>>>>>>> +
>>>>>>> +This CiBuildPlugin scans all the files in a given package and 
>>>>>>> checks for coding standard compliance issues.
>>>>>>> +
>>>>>>> +This plugin is enabled by default. If a package would like to 
>>>>>>> prevent the plugin from reporting errors, it can do
>>>>>>> +so by enabling [`AuditOnly`](#auditonly) mode.
>>>>>>> +
>>>>>>> +This plugin requires the directory containing the Uncrustify 
>>>>>>> executable that should be used for this plugin to
>>>>>>> +be specified in an environment variable named 
>>>>>>> `UNCRUSTIFY_CI_PATH`. This unique variable name is used to avoid
>>>>> confusion
>>>>>>> +with other paths to Uncrustify which might not be the expected 
>>>>>>> build for use by this plugin.
>>>>>>> +
>>>>>>> +By default, an Uncrustify configuration file named 
>>>>>>> "uncrustify.cfg" located in the same directory as the plugin is
>>>>>>> +used. The value can be overridden to a package-specific path 
>>>>>>> with the `ConfigFilePath` configuration file option.
>>>>>>> +
>>>>>>> +* Uncrustify source code and documentation: 
>>>>>>> https://github.com/uncrustify/uncrustify
>>>>>>> +* Project Mu Uncrustify fork source code and documentation: 
>>>>>>> https://dev.azure.com/projectmu/Uncrustify
>>>>>>> +
>>>>>>> +## Files Checked in a Package
>>>>>>> +
>>>>>>> +By default, this plugin will discover all files in the package 
>>>>>>> with the following default paths:
>>>>>>> +
>>>>>>> +```python
>>>>>>> +[
>>>>>>> +# C source
>>>>>>> +"*.c",
>>>>>>> +"*.h"
>>>>>>> +]
>>>>>>> +```
>>>>>>> +
>>>>>>> +From this list of files, any files ignored by Git or residing in 
>>>>>>> a Git submodule will be removed. If Git is not
>>>>>>> +found, submodules are not found, or ignored files are not found 
>>>>>>> no changes are made to the list of discovered
>>> files.
>>>>>>> +
>>>>>>> +To control the paths checked in a given package, review the 
>>>>>>> configuration options described in this file.
>>>>>>> +
>>>>>>> +## Configuration
>>>>>>> +
>>>>>>> +The plugin can be configured with a few optional configuration 
>>>>>>> options.
>>>>>>> +
>>>>>>> +``` yaml
>>>>>>> +  "UncrustifyCheck": {
>>>>>>> +      "AdditionalIncludePaths": [], # Additional paths to check 
>>>>>>> formatting (wildcards supported).
>>>>>>> +      "AuditOnly": False,           # Don't fail the build if 
>>>>>>> there are errors.  Just log them.
>>>>>>> +      "ConfigFilePath": "",         # Custom path to an 
>>>>>>> Uncrustify config file.
>>>>>>> +      "IgnoreStandardPaths": [],    # Standard Plugin defined 
>>>>>>> paths that should be ignored.
>>>>>>> +      "OutputFileDiffs": False,     # Output chunks of 
>>>>>>> formatting diffs in the test case log.
>>>>>>> +                                    # This can significantly 
>>>>>>> slow down the plugin on very large packages.
>>>>>>> +      "SkipGitExclusions": False    # Don't exclude git ignored 
>>>>>>> files and files in git submodules.
>>>>>>> +  }
>>>>>>> +```
>>>>>>> +
>>>>>>> +### `AdditionalIncludePaths`
>>>>>>> +
>>>>>>> +A package configuration file can specify any additional paths to 
>>>>>>> be included with this option.
>>>>>>> +
>>>>>>> +At this time, it is recommended all files run against the plugin 
>>>>>>> be written in the C or C++ language.
>>>>>>> +
>>>>>>> +### `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.
>>>>>>> +
>>>>>>> +### `ConfigFilePath`
>>>>>>> +
>>>>>>> +`String` - Default is `"uncrustify.cfg"`
>>>>>>> +
>>>>>>> +When specified in the config file, this is a package relative 
>>>>>>> path to the Uncrustify configuration file.
>>>>>>> +
>>>>>>> +### `IgnoreStandardPaths`
>>>>>>> +
>>>>>>> +This plugin by default will check the below standard paths. A 
>>>>>>> package configuration file can specify any of these
>>>>> paths
>>>>>>> +to be ignored.
>>>>>>> +
>>>>>>> +```python
>>>>>>> +[
>>>>>>> +# C source
>>>>>>> +"*.c",
>>>>>>> +"*.h"
>>>>>>> +]
>>>>>>> +```
>>>>>>> +
>>>>>>> +### `OutputFileDiffs`
>>>>>>> +
>>>>>>> +`Boolean` - Default is `False`.
>>>>>>> +
>>>>>>> +If `True`, output diffs of formatting changes into the test case 
>>>>>>> log. This is helpful to exactly understand what
>>>>> changes
>>>>>>> +need to be made to the source code in order to fix a coding 
>>>>>>> standard compliance issue.
>>>>>>> +
>>>>>>> +Note that calculating the file diffs on a very large set of of 
>>>>>>> results (e.g. >100 files) can significantly slow
>>> down
>>>>>>> +plugin execution.
>>>>>>> +
>>>>>>> +### `SkipGitExclusions`
>>>>>>> +
>>>>>>> +`Boolean` - Default is `False`.
>>>>>>> +
>>>>>>> +By default, files in paths matched in a .gitignore file or a 
>>>>>>> recognized git submodule are excluded. If this option
>>>>>>> +is `True`, the plugin will not attempt to recognize these files 
>>>>>>> and exclude them.
>>>>>>> +
>>>>>>> +## High-Level Plugin Operation
>>>>>>> +
>>>>>>> +This plugin generates two main sets of temporary files:
>>>>>>> +
>>>>>>> +  1. A working directory in the directory 
>>>>>>> `Build/.pytool/Plugin/Uncrustify`
>>>>>>> +  2. For each source file with formatting errors, a sibling file 
>>>>>>> with the `.uncrustify_plugin` extension
>>>>>>> +
>>>>>>> +The working directory contains temporary files unique to 
>>>>>>> operation of the plugin. All of these files are removed
>>> on
>>>>>>> +exit of the plugin including successful or unsuccessful 
>>>>>>> execution (such as a Python exception occurring). If for
>>> any
>>>>>>> +reason, any files in the package exist prior to running the 
>>>>>>> plugin with the `.uncrustify_plugin` extension, the
>>>> plugin
>>>>>>> +will inform the user to remove these files and exit before 
>>>>>>> running Uncrustify. This is to ensure the accuracy of
>>> the
>>>>>>> +results reported from each execution instance of the plugin.
>>>>>>> +
>>>>>>> +The plugin determines the list of relevant files to check with 
>>>>>>> Uncrustify and then invokes Uncrustify with that
>>> file
>>>>>>> +list. For any files not compliant to the configuration file 
>>>>>>> provided, Uncrustify will generate a corresponding
>>> file
>>>>>>> +with the `.uncrustify_plugin` extension. The plugin discovers 
>>>>>>> all of these files. If any such files are present,
>>>> this
>>>>>>> +indicates a formatting issue was found and the test is marked 
>>>>>>> failed (unless `AuditOnly` mode is enabled).
>>>>>>> +
>>>>>>> +The test case log will contain a report of which files failed to 
>>>>>>> format properly, allowing the user to run
>>>> Uncrustify
>>>>>>> +against the file locally to fix the issue. If the 
>>>>>>> `OutputFileDiffs` configuration option is set to `True`, the
>>>> plugin
>>>>>>> +will output diff chunks for all code formatting issues in the 
>>>>>>> test case log.
>>>>>>> diff --git a/.pytool/Plugin/UncrustifyCheck/UncrustifyCheck.py 
>>>>>>> b/.pytool/Plugin/UncrustifyCheck/UncrustifyCheck.py
>>>>>>> new file mode 100644
>>>>>>> index 000000000000..59534469a2d3
>>>>>>> --- /dev/null
>>>>>>> +++ b/.pytool/Plugin/UncrustifyCheck/UncrustifyCheck.py
>>>>>>> @@ -0,0 +1,617 @@
>>>>>>> +# @file UncrustifyCheck.py
>>>>>>> +#
>>>>>>> +# An edk2-pytool based plugin wrapper for Uncrustify
>>>>>>> +#
>>>>>>> +# Copyright (c) Microsoft Corporation.
>>>>>>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>>>>>>> +##
>>>>>>> +import configparser
>>>>>>> +import difflib
>>>>>>> +import errno
>>>>>>> +import logging
>>>>>>> +import os
>>>>>>> +import pathlib
>>>>>>> +import shutil
>>>>>>> +import timeit
>>>>>>> +from edk2toolext.environment import version_aggregator
>>>>>>> +from edk2toolext.environment.plugin_manager import PluginManager
>>>>>>> +from edk2toolext.environment.plugintypes.ci_build_plugin import 
>>>>>>> ICiBuildPlugin
>>>>>>> +from edk2toolext.environment.plugintypes.uefi_helper_plugin 
>>>>>>> import HelperFunctions
>>>>>>> +from edk2toolext.environment.var_dict import VarDict
>>>>>>> +from edk2toollib.log.junit_report_format import JunitReportTestCase
>>>>>>> +from edk2toollib.uefi.edk2.path_utilities import Edk2Path
>>>>>>> +from edk2toollib.utility_functions import  RunCmd
>>>>>>> +from io import StringIO
>>>>>>> +from typing import Any, Dict, List, Tuple
>>>>>>> +
>>>>>>> +#
>>>>>>> +# Provide more user friendly messages for certain scenarios
>>>>>>> +#
>>>>>>> +class UncrustifyException(Exception):
>>>>>>> +    def __init__(self, message, exit_code):
>>>>>>> +        super().__init__(message)
>>>>>>> +        self.exit_code = exit_code
>>>>>>> +
>>>>>>> +
>>>>>>> +class UncrustifyAppEnvVarNotFoundException(UncrustifyException):
>>>>>>> +    def __init__(self, message):
>>>>>>> +        super().__init__(message, -101)
>>>>>>> +
>>>>>>> +
>>>>>>> +class UncrustifyAppVersionErrorException(UncrustifyException):
>>>>>>> +    def __init__(self, message):
>>>>>>> +        super().__init__(message, -102)
>>>>>>> +
>>>>>>> +
>>>>>>> +class UncrustifyAppExecutionException(UncrustifyException):
>>>>>>> +    def __init__(self, message):
>>>>>>> +        super().__init__(message, -103)
>>>>>>> +
>>>>>>> +
>>>>>>> +class 
>>>>>>> UncrustifyStalePluginFormattedFilesException(UncrustifyException):
>>>>>>> +    def __init__(self, message):
>>>>>>> +        super().__init__(message, -120)
>>>>>>> +
>>>>>>> +
>>>>>>> +class 
>>>>>>> UncrustifyInputFileCreationErrorException(UncrustifyException):
>>>>>>> +    def __init__(self, message):
>>>>>>> +        super().__init__(message, -121)
>>>>>>> +
>>>>>>> +class 
>>>>>>> UncrustifyInvalidIgnoreStandardPathsException(UncrustifyException):
>>>>>>> +    def __init__(self, message):
>>>>>>> +        super().__init__(message, -122)
>>>>>>> +
>>>>>>> +class UncrustifyGitIgnoreFileException(UncrustifyException):
>>>>>>> +    def __init__(self, message):
>>>>>>> +        super().__init__(message, -140)
>>>>>>> +
>>>>>>> +
>>>>>>> +class UncrustifyGitSubmoduleException(UncrustifyException):
>>>>>>> +    def __init__(self, message):
>>>>>>> +        super().__init__(message, -141)
>>>>>>> +
>>>>>>> +
>>>>>>> +class UncrustifyCheck(ICiBuildPlugin):
>>>>>>> +    """
>>>>>>> +    A CiBuildPlugin that uses Uncrustify to check the source 
>>>>>>> files in the
>>>>>>> +    package being tested for coding standard issues.
>>>>>>> +
>>>>>>> +    By default, the plugin runs against standard C source file 
>>>>>>> extensions but
>>>>>>> +    its configuration can be modified through its configuration 
>>>>>>> file.
>>>>>>> +
>>>>>>> +    Configuration options:
>>>>>>> +    "UncrustifyCheck": {
>>>>>>> +        "AdditionalIncludePaths": [], # Additional paths to 
>>>>>>> check formatting (wildcards supported).
>>>>>>> +        "AuditOnly": False,           # Don't fail the build if 
>>>>>>> there are errors.  Just log them.
>>>>>>> +        "ConfigFilePath": "",         # Custom path to an 
>>>>>>> Uncrustify config file.
>>>>>>> +        "IgnoreStandardPaths": [],    # Standard Plugin defined 
>>>>>>> paths that should be ignored.
>>>>>>> +        "OutputFileDiffs": False,     # Output chunks of 
>>>>>>> formatting diffs in the test case log.
>>>>>>> +                                      # This can significantly 
>>>>>>> slow down the plugin on very large packages.
>>>>>>> +        "SkipGitExclusions": False    # Don't exclude git 
>>>>>>> ignored files and files in git submodules.
>>>>>>> +    }
>>>>>>> +    """
>>>>>>> +
>>>>>>> +    #
>>>>>>> +    # By default, use an "uncrustify.cfg" config file in the 
>>>>>>> plugin directory
>>>>>>> +    # A package can override this path via "ConfigFilePath"
>>>>>>> +    #
>>>>>>> +    # Note: Values specified via "ConfigFilePath" are relative 
>>>>>>> to the package
>>>>>>> +    #
>>>>>>> +    DEFAULT_CONFIG_FILE_PATH = os.path.join(
>>>>>>> +        pathlib.Path(__file__).parent.resolve(), "uncrustify.cfg")
>>>>>>> +
>>>>>>> +    #
>>>>>>> +    # The extension used for formatted files produced by this 
>>>>>>> plugin
>>>>>>> +    #
>>>>>>> +    FORMATTED_FILE_EXTENSION = ".uncrustify_plugin"
>>>>>>> +
>>>>>>> +    #
>>>>>>> +    # A package can add any additional paths with 
>>>>>>> "AdditionalIncludePaths"
>>>>>>> +    # A package can remove any of these paths with 
>>>>>>> "IgnoreStandardPaths"
>>>>>>> +    #
>>>>>>> +    STANDARD_PLUGIN_DEFINED_PATHS = ("*.c", "*.h")
>>>>>>> +
>>>>>>> +    #
>>>>>>> +    # The Uncrustify application path should set in this 
>>>>>>> environment variable
>>>>>>> +    #
>>>>>>> +    UNCRUSTIFY_PATH_ENV_KEY = "UNCRUSTIFY_CI_PATH"
>>>>>>> +
>>>>>>> +    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 file coding standard compliance in " + 
>>>>>>> packagename, packagename + ".UncrustifyCheck")
>>>>>>> +
>>>>>>> +    def RunBuildPlugin(self, package_rel_path: str, edk2_path: 
>>>>>>> Edk2Path, package_config: Dict[str, List[str]],
>>>>>>> environment_config: Any, plugin_manager: PluginManager, 
>>>>>>> plugin_manager_helper: HelperFunctions, tc:
>>>>> JunitReportTestCase,
>>>>>>> output_stream=None) -> int:
>>>>>>> +        """
>>>>>>> +        External function of plugin. This function is used to 
>>>>>>> perform the task of the CiBuild Plugin.
>>>>>>> +
>>>>>>> +        Args:
>>>>>>> +          - package_rel_path: edk2 workspace relative path to 
>>>>>>> the package
>>>>>>> +          - edk2_path: Edk2Path object with workspace and 
>>>>>>> packages paths
>>>>>>> +          - package_config: Dictionary with the package 
>>>>>>> configuration
>>>>>>> +          - environment_config: Environment configuration
>>>>>>> +          - plugin_manager: Plugin Manager Instance
>>>>>>> +          - plugin_manager_helper: Plugin Manager Helper Instance
>>>>>>> +          - tc: JUnit test case
>>>>>>> +          - output_stream: The StringIO output stream from this 
>>>>>>> plugin (logging)
>>>>>>> +
>>>>>>> +        Returns
>>>>>>> +          >0 : Number of errors found
>>>>>>> +          0  : Passed successfully
>>>>>>> +          -1 : Skipped for missing prereq
>>>>>>> +        """
>>>>>>> +        try:
>>>>>>> +            # Initialize plugin and check pre-requisites.
>>>>>>> +            self._initialize_environment_info(
>>>>>>> +                package_rel_path, edk2_path, package_config, tc)
>>>>>>> +            self._initialize_configuration()
>>>>>>> +            self._check_for_preexisting_formatted_files()
>>>>>>> +
>>>>>>> +            # Log important context information.
>>>>>>> +            self._log_uncrustify_app_info()
>>>>>>> +
>>>>>>> +            # Get template file contents if specified
>>>>>>> +            self._get_template_file_contents()
>>>>>>> +
>>>>>>> +            # Create meta input files & directories
>>>>>>> +            self._create_temp_working_directory()
>>>>>>> +            self._create_uncrustify_file_list_file()
>>>>>>> +
>>>>>>> +            self._run_uncrustify()
>>>>>>> +
>>>>>>> +            # Post-execution actions.
>>>>>>> +            self._process_uncrustify_results()
>>>>>>> +
>>>>>>> +        except UncrustifyException as e:
>>>>>>> +            self._tc.LogStdError(
>>>>>>> +                f"Uncrustify error {e.exit_code}. 
>>>>>>> Details:\n\n{str(e)}")
>>>>>>> +            logging.warning(
>>>>>>> +                f"Uncrustify error {e.exit_code}. 
>>>>>>> Details:\n\n{str(e)}")
>>>>>>> +            return -1
>>>>>>> +        else:
>>>>>>> +            if self._formatted_file_error_count > 0:
>>>>>>> +                if self._audit_only_mode:
>>>>>>> +                    logging.info(
>>>>>>> +                        "Setting test as skipped since AuditOnly 
>>>>>>> is enabled")
>>>>>>> +                    self._tc.SetSkipped()
>>>>>>> +                    return -1
>>>>>>> +                else:
>>>>>>> +                    self._tc.SetFailed(
>>>>>>> +                        f"{self._plugin_name} failed due to 
>>>>>>> {self._formatted_file_error_count} incorrectly
>>> formatted
>>>>>>> files.", "CHECK_FAILED")
>>>>>>> +            else:
>>>>>>> +                self._tc.SetSuccess()
>>>>>>> +            return self._formatted_file_error_count
>>>>>>> +        finally:
>>>>>>> +            self._cleanup_temporary_formatted_files()
>>>>>>> +            self._cleanup_temporary_directory()
>>>>>>> +
>>>>>>> +    def _initialize_configuration(self) -> None:
>>>>>>> +        """
>>>>>>> +        Initializes plugin configuration.
>>>>>>> +        """
>>>>>>> +        self._initialize_app_info()
>>>>>>> +        self._initialize_config_file_info()
>>>>>>> +        self._initialize_file_to_format_info()
>>>>>>> +        self._initialize_test_case_output_options()
>>>>>>> +
>>>>>>> +    def _check_for_preexisting_formatted_files(self) -> None:
>>>>>>> +        """
>>>>>>> +        Checks if any formatted files from prior execution are 
>>>>>>> present.
>>>>>>> +
>>>>>>> +        Existence of such files is an unexpected condition. This 
>>>>>>> might result
>>>>>>> +        from an error that occurred during a previous run or a 
>>>>>>> premature exit from a debug scenario. In any case,
>>>> the
>>>>>>> package should be clean before starting a new run.
>>>>>>> +        """
>>>>>>> +        pre_existing_formatted_file_count = len(
>>>>>>> +            [str(path.resolve()) for path in
>>>>>>> pathlib.Path(self._abs_package_path).rglob(f'*{UncrustifyCheck.FORMATTED_FILE_EXTENSION}')]) 
>>>>>>>
>>>>>>> +
>>>>>>> +        if pre_existing_formatted_file_count > 0:
>>>>>>> +            raise UncrustifyStalePluginFormattedFilesException(
>>>>>>> +                f"{pre_existing_formatted_file_count} formatted 
>>>>>>> files already exist. To prevent overwriting these
>>>>> files,
>>>>>>> please remove them before running this plugin.")
>>>>>>> +
>>>>>>> +    def _cleanup_temporary_directory(self) -> None:
>>>>>>> +        """
>>>>>>> +        Cleans up the temporary directory used for this 
>>>>>>> execution instance.
>>>>>>> +
>>>>>>> +        This removes the directory and all files created during 
>>>>>>> this instance.
>>>>>>> +        """
>>>>>>> +        if hasattr(self, '_working_dir'):
>>>>>>> +            self._remove_tree(self._working_dir)
>>>>>>> +
>>>>>>> +    def _cleanup_temporary_formatted_files(self) -> None:
>>>>>>> +        """
>>>>>>> +        Cleans up the temporary formmatted files produced by 
>>>>>>> Uncrustify.
>>>>>>> +
>>>>>>> +        This will recursively remove all formatted files 
>>>>>>> generated by Uncrustify
>>>>>>> +        during this execution instance.
>>>>>>> +        """
>>>>>>> +        if hasattr(self, '_abs_package_path'):
>>>>>>> +            formatted_files = [str(path.resolve()) for path in 
>>>>>>> pathlib.Path(
>>>>>>> +                
>>>>>>> self._abs_package_path).rglob(f'*{UncrustifyCheck.FORMATTED_FILE_EXTENSION}')] 
>>>>>>>
>>>>>>> +
>>>>>>> +            for formatted_file in formatted_files:
>>>>>>> +                os.remove(formatted_file)
>>>>>>> +
>>>>>>> +    def _create_temp_working_directory(self) -> None:
>>>>>>> +        """
>>>>>>> +        Creates the temporary directory used for this execution 
>>>>>>> instance.
>>>>>>> +        """
>>>>>>> +        self._working_dir = os.path.join(
>>>>>>> +            self._abs_workspace_path, "Build", ".pytool", 
>>>>>>> "Plugin", f"{self._plugin_name}")
>>>>>>> +
>>>>>>> +        try:
>>>>>>> +            pathlib.Path(self._working_dir).mkdir(parents=True, 
>>>>>>> exist_ok=True)
>>>>>>> +        except OSError as e:
>>>>>>> +            raise UncrustifyInputFileCreationErrorException(
>>>>>>> +                f"Error creating plugin directory 
>>>>>>> {self._working_dir}.\n\n{repr(e)}.")
>>>>>>> +
>>>>>>> +    def _create_uncrustify_file_list_file(self) -> None:
>>>>>>> +        """
>>>>>>> +        Creates the file with the list of source files for 
>>>>>>> Uncrustify to process.
>>>>>>> +        """
>>>>>>> +        self._app_input_file_path = os.path.join(
>>>>>>> +            self._working_dir, "uncrustify_file_list.txt")
>>>>>>> +
>>>>>>> +        with open(self._app_input_file_path, 'w', 
>>>>>>> encoding='utf8') as f:
>>>>>>> +            
>>>>>>> f.writelines(f"\n".join(self._abs_file_paths_to_format))
>>>>>>> +
>>>>>>> +    def _execute_uncrustify(self) -> None:
>>>>>>> +        """
>>>>>>> +        Executes Uncrustify with the initialized configuration.
>>>>>>> +        """
>>>>>>> +        output = StringIO()
>>>>>>> +        self._app_exit_code = RunCmd(
>>>>>>> +            self._app_path,
>>>>>>> +            f"-c {self._app_config_file} -F 
>>>>>>> {self._app_input_file_path} --if-changed --suffix
>>>>>>> {UncrustifyCheck.FORMATTED_FILE_EXTENSION}", outstream=output)
>>>>>>> +        self._app_output = output.getvalue().strip().splitlines()
>>>>>>> +
>>>>>>> +    def _get_git_ignored_paths(self) -> List[str]:
>>>>>>> +        """"
>>>>>>> +        Returns a list of file absolute path strings to all 
>>>>>>> files ignored in this git repository.
>>>>>>> +
>>>>>>> +        If git is not found, an empty list will be returned.
>>>>>>> +        """
>>>>>>> +        if not shutil.which("git"):
>>>>>>> +            logging.warn(
>>>>>>> +                "Git is not found on this system. Git submodule 
>>>>>>> paths will not be considered.")
>>>>>>> +            return []
>>>>>>> +
>>>>>>> +        outstream_buffer = StringIO()
>>>>>>> +        exit_code = RunCmd("git", "ls-files --other",
>>>>>>> +                           workingdir=self._abs_workspace_path, 
>>>>>>> outstream=outstream_buffer,
>>>>> logging_level=logging.NOTSET)
>>>>>>> +        if (exit_code != 0):
>>>>>>> +            raise UncrustifyGitIgnoreFileException(
>>>>>>> +                f"An error occurred reading git ignore settings. 
>>>>>>> This will prevent Uncrustify from running against
>>>> the
>>>>>>> expected set of files.")
>>>>>>> +
>>>>>>> +        # Note: This will potentially be a large list, but at 
>>>>>>> least sorted
>>>>>>> +        return outstream_buffer.getvalue().strip().splitlines()
>>>>>>> +
>>>>>>> +    def _get_git_submodule_paths(self) -> List[str]:
>>>>>>> +        """
>>>>>>> +        Returns a list of directory absolute path strings to the 
>>>>>>> root of each submodule in the workspace
>>> repository.
>>>>>>> +
>>>>>>> +        If git is not found, an empty list will be returned.
>>>>>>> +        """
>>>>>>> +        if not shutil.which("git"):
>>>>>>> +            logging.warn(
>>>>>>> +                "Git is not found on this system. Git submodule 
>>>>>>> paths will not be considered.")
>>>>>>> +            return []
>>>>>>> +
>>>>>>> +        if os.path.isfile(os.path.join(self._abs_workspace_path, 
>>>>>>> ".gitmodules")):
>>>>>>> +            logging.info(
>>>>>>> +                f".gitmodules file found. Excluding submodules 
>>>>>>> in {self._package_name}.")
>>>>>>> +
>>>>>>> +            outstream_buffer = StringIO()
>>>>>>> +            exit_code = RunCmd("git", "config --file .gitmodules 
>>>>>>> --get-regexp path",
>>>>> workingdir=self._abs_workspace_path,
>>>>>>> outstream=outstream_buffer, logging_level=logging.NOTSET)
>>>>>>> +            if (exit_code != 0):
>>>>>>> +                raise UncrustifyGitSubmoduleException(
>>>>>>> +                    f".gitmodule file detected but an error 
>>>>>>> occurred reading the file. Cannot proceed with unknown
>>>>>>> submodule paths.")
>>>>>>> +
>>>>>>> +            submodule_paths = []
>>>>>>> +            for line in 
>>>>>>> outstream_buffer.getvalue().strip().splitlines():
>>>>>>> +                submodule_paths.append(
>>>>>>> +                    
>>>>>>> os.path.normpath(os.path.join(self._abs_workspace_path, 
>>>>>>> line.split()[1])))
>>>>>>> +
>>>>>>> +            return submodule_paths
>>>>>>> +        else:
>>>>>>> +            return []
>>>>>>> +
>>>>>>> +    def _get_template_file_contents(self) -> None:
>>>>>>> +        """
>>>>>>> +        Gets the contents of Uncrustify template files if they 
>>>>>>> are specified
>>>>>>> +        in the Uncrustify configuration file.
>>>>>>> +        """
>>>>>>> +
>>>>>>> +        self._file_template_contents = None
>>>>>>> +        self._func_template_contents = None
>>>>>>> +
>>>>>>> +        # Allow no value to allow "set" statements in the config 
>>>>>>> file which do
>>>>>>> +        # not specify value assignment
>>>>>>> +        parser = configparser.ConfigParser(allow_no_value=True)
>>>>>>> +        with open(self._app_config_file, 'r') as cf:
>>>>>>> +            parser.read_string("[dummy_section]\n" + cf.read())
>>>>>>> +
>>>>>>> +        try:
>>>>>>> +            file_template_name = 
>>>>>>> parser["dummy_section"]["cmt_insert_file_header"]
>>>>>>> +
>>>>>>> +            file_template_path = pathlib.Path(file_template_name)
>>>>>>> +
>>>>>>> +            if not file_template_path.is_file():
>>>>>>> +                file_template_path = 
>>>>>>> pathlib.Path(os.path.join(self._plugin_path, file_template_name))
>>>>>>> +                self._file_template_contents = 
>>>>>>> file_template_path.read_text()
>>>>>>> +        except KeyError:
>>>>>>> +            logging.warn("A file header template is not 
>>>>>>> specified in the config file.")
>>>>>>> +        except FileNotFoundError:
>>>>>>> +            logging.warn("The specified file header template 
>>>>>>> file was not found.")
>>>>>>> +        try:
>>>>>>> +            func_template_name = 
>>>>>>> parser["dummy_section"]["cmt_insert_func_header"]
>>>>>>> +
>>>>>>> +            func_template_path = pathlib.Path(func_template_name)
>>>>>>> +
>>>>>>> +            if not func_template_path.is_file():
>>>>>>> +                func_template_path = 
>>>>>>> pathlib.Path(os.path.join(self._plugin_path, func_template_name))
>>>>>>> +                self._func_template_contents = 
>>>>>>> func_template_path.read_text()
>>>>>>> +        except KeyError:
>>>>>>> +            logging.warn("A function header template is not 
>>>>>>> specified in the config file.")
>>>>>>> +        except FileNotFoundError:
>>>>>>> +            logging.warn("The specified function header template 
>>>>>>> file was not found.")
>>>>>>> +
>>>>>>> +    def _initialize_app_info(self) -> None:
>>>>>>> +        """
>>>>>>> +        Initialize Uncrustify application information.
>>>>>>> +
>>>>>>> +        This function will determine the application path and 
>>>>>>> version.
>>>>>>> +        """
>>>>>>> +        # Verify Uncrustify is specified in the environment.
>>>>>>> +        if UncrustifyCheck.UNCRUSTIFY_PATH_ENV_KEY not in 
>>>>>>> os.environ:
>>>>>>> +            raise UncrustifyAppEnvVarNotFoundException(
>>>>>>> +                f"Uncrustify environment variable 
>>>>>>> {UncrustifyCheck.UNCRUSTIFY_PATH_ENV_KEY} is not present.")
>>>>>>> +
>>>>>>> +        self._app_path = shutil.which('uncrustify', 
>>>>>>> path=os.environ[UncrustifyCheck.UNCRUSTIFY_PATH_ENV_KEY])
>>>>>>> +
>>>>>>> +        if self._app_path is None:
>>>>>>> +            raise FileNotFoundError(
>>>>>>> +                errno.ENOENT, os.strerror(errno.ENOENT), 
>>>>>>> self._app_path)
>>>>>>> +
>>>>>>> +        self._app_path = 
>>>>>>> os.path.normcase(os.path.normpath(self._app_path))
>>>>>>> +
>>>>>>> +        if not os.path.isfile(self._app_path):
>>>>>>> +            raise FileNotFoundError(
>>>>>>> +                errno.ENOENT, os.strerror(errno.ENOENT), 
>>>>>>> self._app_path)
>>>>>>> +
>>>>>>> +        # Verify Uncrustify is present at the expected path.
>>>>>>> +        return_buffer = StringIO()
>>>>>>> +        ret = RunCmd(self._app_path, "--version", 
>>>>>>> outstream=return_buffer)
>>>>>>> +        if (ret != 0):
>>>>>>> +            raise UncrustifyAppVersionErrorException(
>>>>>>> +                f"Error occurred executing --version: {ret}.")
>>>>>>> +
>>>>>>> +        # Log Uncrustify version information.
>>>>>>> +        self._app_version = return_buffer.getvalue().strip()
>>>>>>> +        self._tc.LogStdOut(f"Uncrustify version: 
>>>>>>> {self._app_version}")
>>>>>>> +        version_aggregator.GetVersionAggregator().ReportVersion(
>>>>>>> +            "Uncrustify", self._app_version, 
>>>>>>> version_aggregator.VersionTypes.INFO)
>>>>>>> +
>>>>>>> +    def _initialize_config_file_info(self) -> None:
>>>>>>> +        """
>>>>>>> +        Initialize Uncrustify configuration file info.
>>>>>>> +
>>>>>>> +        The config file path is relative to the package root.
>>>>>>> +        """
>>>>>>> +        self._app_config_file = 
>>>>>>> UncrustifyCheck.DEFAULT_CONFIG_FILE_PATH
>>>>>>> +        if "ConfigFilePath" in self._package_config:
>>>>>>> +            self._app_config_file = 
>>>>>>> self._package_config["ConfigFilePath"].strip()
>>>>>>> +
>>>>>>> +            self._app_config_file = os.path.normpath(
>>>>>>> +                os.path.join(self._abs_package_path, 
>>>>>>> self._app_config_file))
>>>>>>> +
>>>>>>> +        if not os.path.isfile(self._app_config_file):
>>>>>>> +            raise FileNotFoundError(
>>>>>>> +                errno.ENOENT, os.strerror(errno.ENOENT), 
>>>>>>> self._app_config_file)
>>>>>>> +
>>>>>>> +    def _initialize_environment_info(self, package_rel_path: 
>>>>>>> str, edk2_path: Edk2Path, package_config: Dict[str,
>>>>>>> List[str]], tc: JunitReportTestCase) -> None:
>>>>>>> +        """
>>>>>>> +        Initializes plugin environment information.
>>>>>>> +        """
>>>>>>> +        self._abs_package_path = 
>>>>>>> edk2_path.GetAbsolutePathOnThisSytemFromEdk2RelativePath(
>>>>>>> +            package_rel_path)
>>>>>>> +        self._abs_workspace_path = edk2_path.WorkspacePath
>>>>>>> +        self._package_config = package_config
>>>>>>> +        self._package_name = os.path.basename(
>>>>>>> +            os.path.normpath(package_rel_path))
>>>>>>> +        self._plugin_name = self.__class__.__name__
>>>>>>> +        self._plugin_path = 
>>>>>>> os.path.dirname(os.path.realpath(__file__))
>>>>>>> +        self._rel_package_path = package_rel_path
>>>>>>> +        self._tc = tc
>>>>>>> +
>>>>>>> +    def _initialize_file_to_format_info(self) -> None:
>>>>>>> +        """
>>>>>>> +        Forms the list of source files for Uncrustify to process.
>>>>>>> +        """
>>>>>>> +        # Create a list of all the package relative file paths 
>>>>>>> in the package to run against Uncrustify.
>>>>>>> +        rel_file_paths_to_format = list(
>>>>>>> +            UncrustifyCheck.STANDARD_PLUGIN_DEFINED_PATHS)
>>>>>>> +
>>>>>>> +        # Allow the ci.yaml to remove any of the pre-defined 
>>>>>>> standard paths
>>>>>>> +        if "IgnoreStandardPaths" in self._package_config:
>>>>>>> +            for a in self._package_config["IgnoreStandardPaths"]:
>>>>>>> +                if a.strip() in rel_file_paths_to_format:
>>>>>>> +                    self._tc.LogStdOut(
>>>>>>> +                        f"Ignoring standard path due to ci.yaml 
>>>>>>> ignore: {a}")
>>>>>>> +                    rel_file_paths_to_format.remove(a.strip())
>>>>>>> +                else:
>>>>>>> +                    raise 
>>>>>>> UncrustifyInvalidIgnoreStandardPathsException(f"Invalid 
>>>>>>> IgnoreStandardPaths value: {a}")
>>>>>>> +
>>>>>>> +        # Allow the ci.yaml to specify additional include paths 
>>>>>>> for this package
>>>>>>> +        if "AdditionalIncludePaths" in self._package_config:
>>>>>>> +            rel_file_paths_to_format.extend(
>>>>>>> +                self._package_config["AdditionalIncludePaths"])
>>>>>>> +
>>>>>>> +        self._abs_file_paths_to_format = []
>>>>>>> +        for path in rel_file_paths_to_format:
>>>>>>> +            self._abs_file_paths_to_format.extend(
>>>>>>> +                [str(path.resolve()) for path in 
>>>>>>> pathlib.Path(self._abs_package_path).rglob(path)])
>>>>>>> +
>>>>>>> +        if not "SkipGitExclusions" in self._package_config or 
>>>>>>> not self._package_config["SkipGitExclusions"]:
>>>>>>> +            # Remove files ignored by git
>>>>>>> +            logging.info(
>>>>>>> +                f"{self._package_name} file count before git 
>>>>>>> ignore file exclusion:
>>>>>>> {len(self._abs_file_paths_to_format)}")
>>>>>>> +
>>>>>>> +            ignored_paths = self._get_git_ignored_paths()
>>>>>>> +            self._abs_file_paths_to_format = list(
>>>>>>> +                
>>>>>>> set(self._abs_file_paths_to_format).difference(ignored_paths))
>>>>>>> +
>>>>>>> +            logging.info(
>>>>>>> +                f"{self._package_name} file count after git 
>>>>>>> ignore file exclusion:
>>>>>>> {len(self._abs_file_paths_to_format)}")
>>>>>>> +
>>>>>>> +            # Remove files in submodules
>>>>>>> +            logging.info(
>>>>>>> +                f"{self._package_name} file count before 
>>>>>>> submodule exclusion:
>>>> {len(self._abs_file_paths_to_format)}")
>>>>>>> +
>>>>>>> +            submodule_paths = 
>>>>>>> tuple(self._get_git_submodule_paths())
>>>>>>> +            for path in submodule_paths:
>>>>>>> +                logging.info(f"  submodule path: {path}")
>>>>>>> +
>>>>>>> +            self._abs_file_paths_to_format = [
>>>>>>> +                f for f in self._abs_file_paths_to_format if not 
>>>>>>> f.startswith(submodule_paths)]
>>>>>>> +
>>>>>>> +            logging.info(
>>>>>>> +                f"{self._package_name} file count after 
>>>>>>> submodule exclusion:
>>> {len(self._abs_file_paths_to_format)}")
>>>>>>> +
>>>>>>> +        # Sort the files for more consistent results
>>>>>>> +        self._abs_file_paths_to_format.sort()
>>>>>>> +
>>>>>>> +    def _initialize_test_case_output_options(self) -> None:
>>>>>>> +        """
>>>>>>> +        Initializes options that influence test case output.
>>>>>>> +        """
>>>>>>> +        self._audit_only_mode = False
>>>>>>> +        self._output_file_diffs = False
>>>>>>> +
>>>>>>> +        if "AuditOnly" in self._package_config and 
>>>>>>> self._package_config["AuditOnly"]:
>>>>>>> +            self._audit_only_mode = True
>>>>>>> +
>>>>>>> +        if "OutputFileDiffs" in self._package_config and 
>>>>>>> self._package_config["OutputFileDiffs"]:
>>>>>>> +            self._output_file_diffs = True
>>>>>>> +
>>>>>>> +    def _log_uncrustify_app_info(self) -> None:
>>>>>>> +        """
>>>>>>> +        Logs Uncrustify application information.
>>>>>>> +        """
>>>>>>> +        self._tc.LogStdOut(f"Found Uncrustify at {self._app_path}")
>>>>>>> +        self._tc.LogStdOut(f"Uncrustify version: 
>>>>>>> {self._app_version}")
>>>>>>> +        self._tc.LogStdOut('\n')
>>>>>>> +        logging.info(f"Found Uncrustify at {self._app_path}")
>>>>>>> +        logging.info(f"Uncrustify version: {self._app_version}")
>>>>>>> +        logging.info('\n')
>>>>>>> +
>>>>>>> +    def _process_uncrustify_results(self) -> None:
>>>>>>> +        """
>>>>>>> +        Process the results from Uncrustify.
>>>>>>> +
>>>>>>> +        Determines whether formatting errors are present and 
>>>>>>> logs failures.
>>>>>>> +        """
>>>>>>> +        formatted_files = [str(path.resolve()) for path in 
>>>>>>> pathlib.Path(
>>>>>>> +            
>>>>>>> self._abs_package_path).rglob(f'*{UncrustifyCheck.FORMATTED_FILE_EXTENSION}')] 
>>>>>>>
>>>>>>> +
>>>>>>> +        self._formatted_file_error_count = len(formatted_files)
>>>>>>> +
>>>>>>> +        if self._formatted_file_error_count > 0:
>>>>>>> +            self._tc.LogStdError("Files with formatting errors:\n")
>>>>>>> +
>>>>>>> +            if self._output_file_diffs:
>>>>>>> +                logging.info("Calculating file diffs. This might 
>>>>>>> take a while...")
>>>>>>> +
>>>>>>> +        for formatted_file in formatted_files:
>>>>>>> +            pre_formatted_file = formatted_file[:-
>>>>>>> +                                                
>>>>>>> len(UncrustifyCheck.FORMATTED_FILE_EXTENSION)]
>>>>>>> +
>>>>>>> +            if (self._output_file_diffs or
>>>>>>> +                    self._file_template_contents is not None or
>>>>>>> +                    self._func_template_contents is not None):
>>>>>>> +                self._tc.LogStdError(
>>>>>>> +                    f"Formatting errors in 
>>>>>>> {os.path.relpath(pre_formatted_file, self._abs_package_path)}\n")
>>>>>>> +
>>>>>>> +                with open(formatted_file) as ff:
>>>>>>> +                    formatted_file_text = ff.read()
>>>>>>> +
>>>>>>> +                    if (self._file_template_contents is not None 
>>>>>>> and
>>>>>>> +                            self._file_template_contents in 
>>>>>>> formatted_file_text):
>>>>>>> +                        self._tc.LogStdError(f"File header is 
>>>>>>> missing in {os.path.relpath(pre_formatted_file,
>>>>>>> self._abs_package_path)}\n")
>>>>>>> +
>>>>>>> +                    if (self._func_template_contents is not None 
>>>>>>> and
>>>>>>> +                            self._func_template_contents in 
>>>>>>> formatted_file_text):
>>>>>>> +                        self._tc.LogStdError(f"A function header 
>>>>>>> is missing in
>>> {os.path.relpath(pre_formatted_file,
>>>>>>> self._abs_package_path)}\n")
>>>>>>> +
>>>>>>> +                    if self._output_file_diffs:
>>>>>>> +                        with open(pre_formatted_file) as pf:
>>>>>>> +                            pre_formatted_file_text = pf.read()
>>>>>>> +
>>>>>>> +                        for line in 
>>>>>>> difflib.unified_diff(pre_formatted_file_text.split('\n'),
>>>>>>> formatted_file_text.split('\n'), fromfile=pre_formatted_file, 
>>>>>>> tofile=formatted_file, n=3):
>>>>>>> +                            self._tc.LogStdError(line)
>>>>>>> +
>>>>>>> +                        self._tc.LogStdError('\n')
>>>>>>> +            else:
>>>>>>> +                self._tc.LogStdError(pre_formatted_file)
>>>>>>> +
>>>>>>> +    def _remove_tree(self, dir_path: str, ignore_errors: bool = 
>>>>>>> False) -> None:
>>>>>>> +        """
>>>>>>> +        Helper for removing a directory. Over time there have been
>>>>>>> +        many private implementations of this due to reliability 
>>>>>>> issues in the
>>>>>>> +        shutil implementations. To consolidate on a single 
>>>>>>> function this helper is added.
>>>>>>> +
>>>>>>> +        On error try to change file attributes. Also add retry 
>>>>>>> logic.
>>>>>>> +
>>>>>>> +        This function is temporarily borrowed from 
>>>>>>> edk2toollib.utility_functions
>>>>>>> +        since the version used in edk2 is not recent enough to 
>>>>>>> include the
>>>>>>> +        function.
>>>>>>> +
>>>>>>> +        This function should be replaced by "RemoveTree" when it 
>>>>>>> is available.
>>>>>>> +
>>>>>>> +        Args:
>>>>>>> +          - dir_path: Path to directory to remove.
>>>>>>> +          - ignore_errors: Whether to ignore errors during removal
>>>>>>> +        """
>>>>>>> +
>>>>>>> +        def _remove_readonly(func, path, _):
>>>>>>> +            """
>>>>>>> +            Private function to attempt to change permissions on 
>>>>>>> file/folder being deleted.
>>>>>>> +            """
>>>>>>> +            os.chmod(path, os.stat.S_IWRITE)
>>>>>>> +            func(path)
>>>>>>> +
>>>>>>> +        for _ in range(3):  # retry up to 3 times
>>>>>>> +            try:
>>>>>>> +                shutil.rmtree(dir_path, 
>>>>>>> ignore_errors=ignore_errors, onerror=_remove_readonly)
>>>>>>> +            except OSError as err:
>>>>>>> +                logging.warning(f"Failed to fully remove 
>>>>>>> {dir_path}: {err}")
>>>>>>> +            else:
>>>>>>> +                break
>>>>>>> +        else:
>>>>>>> +            raise RuntimeError(f"Failed to remove {dir_path}")
>>>>>>> +
>>>>>>> +    def _run_uncrustify(self) -> None:
>>>>>>> +        """
>>>>>>> +        Runs Uncrustify for this instance of plugin execution.
>>>>>>> +        """
>>>>>>> +        logging.info("Executing Uncrustify. This might take a 
>>>>>>> while...")
>>>>>>> +        start_time = timeit.default_timer()
>>>>>>> +        self._execute_uncrustify()
>>>>>>> +        end_time = timeit.default_timer() - start_time
>>>>>>> +
>>>>>>> +        execution_summary = f"Uncrustify executed against 
>>>>>>> {len(self._abs_file_paths_to_format)} files in
>>>>>>> {self._package_name} in {end_time:.2f} seconds.\n"
>>>>>>> +
>>>>>>> +        self._tc.LogStdOut(execution_summary)
>>>>>>> +        logging.info(execution_summary)
>>>>>>> +
>>>>>>> +        if self._app_exit_code != 0 and self._app_exit_code != 1:
>>>>>>> +            raise UncrustifyAppExecutionException(
>>>>>>> +                f"Error {str(self._app_exit_code)} returned from 
>>>>>>> Uncrustify:\n\n{str(self._app_output)}")
>>>>>>> diff --git a/.pytool/Plugin/UncrustifyCheck/default_file_header.txt
>>>>>>> b/.pytool/Plugin/UncrustifyCheck/default_file_header.txt
>>>>>>> new file mode 100644
>>>>>>> index 000000000000..2955a734dfe1
>>>>>>> --- /dev/null
>>>>>>> +++ b/.pytool/Plugin/UncrustifyCheck/default_file_header.txt
>>>>>>> @@ -0,0 +1,9 @@
>>>>>>> +/** @file
>>>>>>> +  Brief description of the file's purpose.
>>>>>>> +
>>>>>>> +  Detailed description of the file's contents and other useful
>>>>>>> +  information for a person viewing the file for the first time.
>>>>>>> +
>>>>>>> +  <<Copyright>>
>>>>>>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>>>>>>> +**/
>>>>>>> diff --git 
>>>>>>> a/.pytool/Plugin/UncrustifyCheck/default_function_header.txt
>>>>>>> b/.pytool/Plugin/UncrustifyCheck/default_function_header.txt
>>>>>>> new file mode 100644
>>>>>>> index 000000000000..66edc72e6731
>>>>>>> --- /dev/null
>>>>>>> +++ b/.pytool/Plugin/UncrustifyCheck/default_function_header.txt
>>>>>>> @@ -0,0 +1,15 @@
>>>>>>> +/**
>>>>>>> +  Brief description of this function's purpose.
>>>>>>> +
>>>>>>> +  Follow it immediately with the detailed description.
>>>>>>> +
>>>>>>> +  @param[in]      Arg1  Description of Arg1.
>>>>>>> +  @param[in]      Arg2  Description of Arg2 This is complicated 
>>>>>>> and requires
>>>>>>> +                        multiple lines to describe.
>>>>>>> +  @param[out]     Arg3  Description of Arg3.
>>>>>>> +  @param[in, out] Arg4  Description of Arg4.
>>>>>>> +
>>>>>>> +  @retval VAL_ONE  Description of what VAL_ONE signifies.
>>>>>>> +  @retval OTHER    This is the only other return value. If there 
>>>>>>> were other
>>>>>>> +                   return values, they would be listed.
>>>>>>> +**/
>>>>>>> diff --git a/.pytool/Plugin/UncrustifyCheck/uncrustify.cfg 
>>>>>>> b/.pytool/Plugin/UncrustifyCheck/uncrustify.cfg
>>>>>>> new file mode 100644
>>>>>>> index 000000000000..1a87295ec9f9
>>>>>>> --- /dev/null
>>>>>>> +++ b/.pytool/Plugin/UncrustifyCheck/uncrustify.cfg
>>>>>>> @@ -0,0 +1,462 @@
>>>>>>> +## @file
>>>>>>> +# Uncrustify Configuration File for EDK II C Code
>>>>>>> +#
>>>>>>> +# Coding Standard: 
>>>>>>> https://edk2-docs.gitbook.io/edk-ii-c-coding-standards-specification/ 
>>>>>>>
>>>>>>> +#
>>>>>>> +# This configuration file is meant to be a "best attempt" to 
>>>>>>> align with the
>>>>>>> +# definitions in the EDK II C Coding Standards Specification.
>>>>>>> +#
>>>>>>> +# Copyright (c) Microsoft Corporation.
>>>>>>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>>>>>>> +##
>>>>>>> +
>>>>>>> +# Force UTF-8 encoding (no UTF-16)
>>>>>>> +enable_digraphs                 = false
>>>>>>> +utf8_byte                       = false
>>>>>>> +utf8_force                      = true
>>>>>>> +
>>>>>>> +# Code width / line splitting
>>>>>>> +#code_width                      =120     # TODO: This causes 
>>>>>>> non-deterministic behaviour in some cases when code
>>>>> wraps
>>>>>>> +ls_code_width                   =false
>>>>>>> +ls_for_split_full               =true
>>>>>>> +ls_func_split_full              =true
>>>>>>> +pos_comma                       =trail
>>>>>>> +
>>>>>>> +# 5.1.7  All files must end with CRLF
>>>>>>> +newlines                        = crlf
>>>>>>> +
>>>>>>> +# 5.1.2 Do not use tab characters
>>>>>>> +
>>>>>>> +cmt_convert_tab_to_spaces       = true      # Whether to convert 
>>>>>>> all tabs to spaces in comments. If false, tabs in
>>>>>>> +                                            # comments are left 
>>>>>>> alone, unless used for indenting.
>>>>>>> +indent_columns                  = 2         # Number of spaces 
>>>>>>> for indentation
>>>>>>> +indent_with_tabs                = 0         # Do not use TAB 
>>>>>>> characters
>>>>>>> +string_replace_tab_chars        = true      # Replace TAB with 
>>>>>>> SPACE
>>>>>>> +                                            # Note: This will 
>>>>>>> break .robot files but is needed for edk2 style
>>>>>>> +
>>>>>>> +# 5.2.1.1 There shall be only one statement on a line (statement 
>>>>>>> ends with ;)
>>>>>>> +nl_multi_line_cond              = true      # Add a newline 
>>>>>>> between ')' and '{' if the ')' is on a different line
>>>> than
>>>>>>> +                                            # the if/for/etc.
>>>>>>> +nl_after_semicolon              = true      # Whether to add a 
>>>>>>> newline after semicolons, except in 'for'
>>> statements.
>>>>>>> +
>>>>>>> +# 5.2.1.3 An open brace '{' goes on the same line as the closing 
>>>>>>> parenthesis ')' of simple predicate expressions
>>>>>>> +mod_full_brace_do               = add       # Add or remove 
>>>>>>> braces on a single-line 'do' statement.
>>>>>>> +mod_full_brace_for              = add
>>>>>>> +mod_full_brace_function         = add       # Add or remove 
>>>>>>> braces on a single-line function definition.
>>>>>>> +mod_full_brace_if               = add       # Add or remove 
>>>>>>> braces on a single-line 'if' statement. Braces will
>>> not
>>>> be
>>>>>>> +                                            # removed if the 
>>>>>>> braced statement contains an 'else'.
>>>>>>> +mod_full_brace_if_chain         = false
>>>>>>> +mod_full_brace_while            = add
>>>>>>> +
>>>>>>> +# 5.2.1.4 A close brace '}' always goes at the beginning of the 
>>>>>>> last line of the body
>>>>>>> +eat_blanks_after_open_brace     = true
>>>>>>> +eat_blanks_before_close_brace   = true      # Whether to remove 
>>>>>>> blank lines before '}'.
>>>>>>> +
>>>>>>> +# 5.2.2.2 Always put space before and after binary operators.
>>>>>>> +sp_assign                       = add       # Add or remove 
>>>>>>> space around assignment operator '=', '+=', etc.
>>>>>>> +sp_assign_default               = add
>>>>>>> +sp_bool                         = add       # Add or remove 
>>>>>>> space around boolean operators '&&' and '||'.
>>>>>>> +sp_compare                      = add       # Add or remove 
>>>>>>> space around compare operator '<', '>', '==', etc.
>>>>>>> +
>>>>>>> +# 5.2.2.3 Do not put space between unary operators and their object
>>>>>>> +sp_addr                         = remove    # A or remove space 
>>>>>>> after the '&' (address-of) unary operator.
>>>>>>> +sp_incdec                       = remove    # Add or remove 
>>>>>>> space between '++' and '--' the word to which it is
>>>> being
>>>>>>> +                                            # applied, as in 
>>>>>>> '(--x)' or 'y++;'.
>>>>>>> +sp_inv                          = remove    # Add or remove 
>>>>>>> space after the '~' (invert) unary operator.
>>>>>>> +sp_not                          = remove    # Add or remove 
>>>>>>> space after the '!' (not) unary operator.
>>>>>>> +sp_sign                         = remove    # Add or remove 
>>>>>>> space after '+' or '-', as in 'x = -5' or 'y = +7'.
>>>>>>> +
>>>>>>> +# 5.2.2.4 Subsequent lines of multi-line function calls should 
>>>>>>> line up two spaces from the beginning of the
>>> function
>>>>>>> +#         name
>>>>>>> +nl_func_call_args_multi_line    = true      # Whether to add a 
>>>>>>> newline after each ',' in a function call if '('
>>> and
>>>>> ')'
>>>>>>> +                                            # are in different 
>>>>>>> lines.
>>>>>>> +nl_func_call_args_multi_line_ignore_closures = false
>>>>>>> +
>>>>>>> +# - Indent each argument 2 spaces from the start of the function 
>>>>>>> name. If a
>>>>>>> +#   function is called through a structure or union member, of type
>>>>>>> +#   pointer-to-function, then indent each argument 2 spaces from 
>>>>>>> the start of the
>>>>>>> +#   member name.
>>>>>>> +indent_func_call_edk2_style     = true      # Use EDK2 
>>>>>>> indentation style for function calls  (**CUSTOM SETTING**)
>>>>>>> +indent_paren_after_func_call    = true      # Whether to indent 
>>>>>>> the open parenthesis of a function call, if the
>>>>>>> +                                            # parenthesis is on 
>>>>>>> its own line.
>>>>>>> +
>>>>>>> +# - Align the close parenthesis with the start of the last argument
>>>>>>> +indent_paren_close              = 0         # How to indent a 
>>>>>>> close parenthesis after a newline.
>>>>>>> +                                            # (0: Body, 1: 
>>>>>>> Openparenthesis, 2: Brace level)
>>>>>>> +
>>>>>>> +
>>>>>>> +# 5.2.2.5 Always put space after commas or semicolons that 
>>>>>>> separate items
>>>>>>> +sp_after_comma                  = force     # Add or remove 
>>>>>>> space after ',', i.e. 'a,b' vs. 'a, b'.
>>>>>>> +sp_before_comma                 = remove    # Add or remove 
>>>>>>> space before ','.
>>>>>>> +
>>>>>>> +# 5.2.2.6 Always put space before an open parenthesis
>>>>>>> +sp_after_sparen                 = add       # Add or remove 
>>>>>>> space after ')' of control statements.
>>>>>>> +sp_attribute_paren              = add       # Add or remove 
>>>>>>> space between '__attribute__' and '('.
>>>>>>> +sp_before_sparen                = force     # Add or remove 
>>>>>>> space before '(' of control statements
>>>>>>> +                                            # ('if', 'for', 
>>>>>>> 'switch', 'while', etc.).
>>>>>>> +sp_defined_paren                = force     # Add or remove 
>>>>>>> space between 'defined' and '(' in '#if defined
>>> (FOO)'.
>>>>>>> +sp_func_call_paren              = force     # Add or remove 
>>>>>>> space between function name and '(' on function calls.
>>>>>>> +sp_func_call_paren_empty        = force     # Add or remove 
>>>>>>> space between function name and '()' on function calls
>>>>>>> +                                            # without 
>>>>>>> parameters. If set to ignore (the default),
>>> sp_func_call_paren
>>>>> is
>>>>>>> +                                            # used.
>>>>>>> +sp_func_def_paren               = add       # Add or remove 
>>>>>>> space between alias name and '(' of a non-pointer
>>>> function
>>>>>>> +                                            # type typedef.
>>>>>>> +sp_func_proto_paren             = add       # Add or remove 
>>>>>>> space between function name and '()' on function
>>>>> declaration
>>>>>>> +sp_sizeof_paren                 = force     # Add or remove 
>>>>>>> space between 'sizeof' and '('.
>>>>>>> +sp_type_func                    = add       # Add or remove 
>>>>>>> space between return type and function name. A minimum
>>>> of
>>>>> 1
>>>>>>> +                                            # is forced except 
>>>>>>> for pointer return types.
>>>>>>> +
>>>>>>> +# Not specified, but also good style to remove spaces inside 
>>>>>>> parentheses (Optional)
>>>>>>> +sp_cparen_oparen                = remove    # Add or remove 
>>>>>>> space between back-to-back parentheses, i.e. ')(' vs.
>>> ')
>>>>> ('.
>>>>>>> +sp_inside_fparen                = remove    # Add or remove 
>>>>>>> space inside function '(' and ')'.
>>>>>>> +sp_inside_fparens               = remove    # Add or remove 
>>>>>>> space inside empty function '()'.
>>>>>>> +sp_inside_paren                 = remove    # Add or remove 
>>>>>>> space inside '(' and ')'.
>>>>>>> +sp_inside_paren_cast            = remove    # Add or remove 
>>>>>>> spaces inside cast parentheses. '(int)x'
>>>>>>> +sp_inside_square                = remove    # Add or remove 
>>>>>>> space inside a non-empty '[' and ']'.
>>>>>>> +sp_paren_paren                  = remove    # Add or remove 
>>>>>>> space between nested parentheses, i.e. '((' vs. ') )'.
>>>>>>> +sp_square_fparen                = remove    # Add or remove 
>>>>>>> space between ']' and '(' when part of a function
>>> call.
>>>>>>> +
>>>>>>> +# 5.2.2.7 Put a space before an open brace if it is not on its 
>>>>>>> own line
>>>>>>> +sp_do_brace_open                = force     # Add or remove 
>>>>>>> space between 'do' and '{'.
>>>>>>> +sp_paren_brace                  = force     # Add or remove 
>>>>>>> space between ')' and '{'.
>>>>>>> +sp_sparen_brace                 = force     # Add or remove 
>>>>>>> space between ')' and '{' of of control statements.
>>>>>>> +
>>>>>>> +# 5.2.2.8 Do not put spaces around structure member and pointer 
>>>>>>> operators
>>>>>>> +sp_after_byref                  = remove    # Add or remove 
>>>>>>> space after reference sign '&', if followed by a word.
>>>>>>> +sp_before_byref                 = add       # Add or remove 
>>>>>>> space before a reference sign '&'.
>>>>>>> +sp_deref                        = remove    # Add or remove 
>>>>>>> space after the '*' (dereference) unary operator. This
>>>>> does
>>>>>>> +                                            # not affect the 
>>>>>>> spacing after a '*' that is part of a type.
>>>>>>> +sp_member                       = remove    # Add or remove 
>>>>>>> space around the '.' or '->' operators.
>>>>>>> +
>>>>>>> +# 5.2.2.9 Do not put spaces before open brackets of array 
>>>>>>> subscripts
>>>>>>> +sp_before_square                = remove    # Add or remove 
>>>>>>> space before '[' (except '[]').
>>>>>>> +sp_before_squares               = remove    # Add or remove 
>>>>>>> space before '[]'.
>>>>>>> +sp_before_vardef_square         = remove    # Add or remove 
>>>>>>> space before '[' for a variable definition.
>>>>>>> +
>>>>>>> +# 5.2.2.10 Use extra parentheses rather than depending on 
>>>>>>> in-depth knowledge of the order of precedence of C
>>>>>>> +mod_full_paren_if_bool          = true      # Whether to fully 
>>>>>>> parenthesize Boolean expressions in 'while' and
>>> 'if'
>>>>>>> +                                            # statement, as in 
>>>>>>> 'if (a && b > c)' => 'if (a && (b > c))'.
>>>>>>> +
>>>>>>> +# 5.2.2.11 Align a continuation line with the part of the line 
>>>>>>> that it continues.
>>>>>>> +use_indent_continue_only_once   = true
>>>>>>> +
>>>>>>> +# Additional '{}' bracing rules (Optional)
>>>>>>> +# NOTE - The style guide specifies two different styles for braces,
>>>>>>> +# so these are ignored for now to allow developers some 
>>>>>>> flexibility.
>>>>>>> +nl_after_brace_close            = true      # Whether to add a 
>>>>>>> newline after '}'. Does not apply if followed by a
>>>>>>> +                                            # necessary ';'.
>>>>>>> +nl_brace_else                   = remove    # Add or remove 
>>>>>>> newline between '}' and 'else'.
>>>>>>> +nl_brace_while                  = remove    # Add or remove 
>>>>>>> newline between '}' and 'while' of 'do' statement.
>>>>>>> +nl_do_brace                     = remove    # Add or remove 
>>>>>>> newline between 'do' and '{'.
>>>>>>> +nl_else_brace                   = remove    # Add or remove 
>>>>>>> newline between 'else' and '{'.
>>>>>>> +nl_else_if                      = remove    # Add or remove 
>>>>>>> newline between 'else' and 'if'.
>>>>>>> +nl_elseif_brace                 = remove    # Add or remove 
>>>>>>> newline between 'else if' and '{'.
>>>>>>> +nl_enum_brace                   = remove    # Add or remove 
>>>>>>> newline between 'enum' and '{'.
>>>>>>> +nl_fcall_brace                  = remove    # Add or remove 
>>>>>>> newline between a function call's ')' and '{',
>>>>>>> +                                            # as in 
>>>>>>> 'list_for_each(item, &list) { }'.
>>>>>>> +nl_for_brace                    = remove    # Add or remove 
>>>>>>> newline between 'for' and '{'.
>>>>>>> +nl_if_brace                     = remove    # Add or remove 
>>>>>>> newline between 'if' and '{'.
>>>>>>> +nl_struct_brace                 = remove    # Add or remove 
>>>>>>> newline between 'struct and '{'.
>>>>>>> +nl_switch_brace                 = remove    # Add or remove 
>>>>>>> newline between 'switch' and '{'.
>>>>>>> +nl_union_brace                  = remove    # Add or remove 
>>>>>>> newline between 'union' and '{'.
>>>>>>> +nl_while_brace                  = remove    # Add or remove 
>>>>>>> newline between 'while' and '{'.
>>>>>>> +
>>>>>>> +# Additional whitespace rules (Optional)
>>>>>>> +sp_after_ptr_star               = remove    # Add or remove 
>>>>>>> space after pointer star '*', if followed by a word.
>>>>>>> +                                            # Useful when paired 
>>>>>>> with align_var_def_star_style==2
>>>>>>> +sp_after_ptr_star_func          = remove    # Add or remove 
>>>>>>> space after a pointer star '*', if followed by a
>>>> function
>>>>>>> +                                            # prototype or 
>>>>>>> function definition.
>>>>>>> +sp_after_semi                   = remove    # Add or remove 
>>>>>>> space after ';', except when followed by a comment.
>>>>>>> +sp_before_case_colon            = remove    # Add or remove 
>>>>>>> space before case ':'.
>>>>>>> +sp_before_ptr_star              = add       # Add or remove 
>>>>>>> space before pointer star '*'.
>>>>>>> +sp_before_ptr_star_func         = add       # Add or remove 
>>>>>>> space before a pointer star '*', if followed by a
>>>> function
>>>>>>> +                                            # prototype or 
>>>>>>> function definition.
>>>>>>> +sp_before_semi                  = remove    # Add or remove 
>>>>>>> space before ';'
>>>>>>> +sp_before_semi_for              = remove    # Add or remove 
>>>>>>> space before ';' in non-empty 'for' statements.
>>>>>>> +sp_before_semi_for_empty        = add       # Add or remove 
>>>>>>> space before a semicolon of an empty part of a for
>>>>> statement
>>>>>>> +sp_between_ptr_star             = remove    # Add or remove 
>>>>>>> space between pointer stars '*'. (ie, 'VOID **')
>>>>>>> +sp_brace_close_while            = force     # Add or remove 
>>>>>>> space between '}' and 'while'.
>>>>>>> +
>>>>>>> +sp_after_cast                   = remove
>>>>>>> +sp_after_type                   = add
>>>>>>> +sp_balance_nested_parens        = false
>>>>>>> +sp_before_nl_cont               = add
>>>>>>> +sp_before_square_asm_block      = ignore
>>>>>>> +sp_before_unnamed_byref         = add
>>>>>>> +sp_brace_brace                  = ignore
>>>>>>> +sp_brace_else                   = force
>>>>>>> +sp_brace_typedef                = add
>>>>>>> +sp_case_label                   = force
>>>>>>> +sp_cmt_cpp_doxygen              = true
>>>>>>> +sp_cond_colon                   = add
>>>>>>> +sp_cond_question                = add
>>>>>>> +sp_cpp_cast_paren               = force
>>>>>>> +sp_else_brace                   = force
>>>>>>> +sp_endif_cmt                    = force
>>>>>>> +sp_enum_assign                  = add
>>>>>>> +sp_inside_braces                = force
>>>>>>> +sp_inside_braces_empty          = force
>>>>>>> +sp_inside_braces_enum           = force
>>>>>>> +sp_inside_braces_struct         = force
>>>>>>> +sp_pp_concat                    = add
>>>>>>> +sp_pp_stringify                 = add
>>>>>>> +sp_return_paren                 = add
>>>>>>> +sp_special_semi                 = force
>>>>>>> +sp_while_paren_open             = force
>>>>>>> +
>>>>>>> +# Additional Indentation Rules
>>>>>>> +indent_access_spec              = 1
>>>>>>> +indent_access_spec_body         = false
>>>>>>> +indent_align_assign             = true
>>>>>>> +indent_align_string             = true
>>>>>>> +indent_bool_paren               = true
>>>>>>> +indent_brace_parent             = false
>>>>>>> +indent_braces                   = false
>>>>>>> +indent_braces_no_class          = false
>>>>>>> +indent_braces_no_func           = true
>>>>>>> +indent_braces_no_struct         = false
>>>>>>> +indent_class                    = false
>>>>>>> +indent_class_colon              = false
>>>>>>> +indent_cmt_with_tabs            = false         # Whether to 
>>>>>>> indent comments that are not at a brace level with
>>> tabs
>>>>> on
>>>>>>> +                                                # a tabstop. 
>>>>>>> Requires indent_with_tabs=2. If false, will use
>>> spaces.
>>>>>>> +indent_col1_comment             = true
>>>>>>> +indent_col1_multi_string_literal= true
>>>>>>> +indent_comma_paren              = true
>>>>>>> +indent_else_if                  = true
>>>>>>> +indent_extern                   = false
>>>>>>> +indent_first_bool_expr          = true
>>>>>>> +
>>>>>>> +indent_func_def_param_paren_pos_threshold = 0
>>>>>>> +indent_func_param_double                  = false
>>>>>>> +indent_func_proto_param                   = true
>>>>>>> +indent_ignore_asm_block                   = true
>>>>>>> +indent_label                              = 1
>>>>>>> +indent_member                             = 2
>>>>>>> +indent_namespace                          = false
>>>>>>> +indent_param                              = 2
>>>>>>> +indent_paren_nl                           = false
>>>>>>> +indent_paren_open_brace                   = false
>>>>>>> +indent_preserve_sql                       = false
>>>>>>> +indent_relative_single_line_comments      = false
>>>>>>> +indent_sing_line_comments                 = 0
>>>>>>> +indent_single_newlines                    = false
>>>>>>> +indent_square_nl                          = false
>>>>>>> +indent_switch_case                        = 2
>>>>>>> +indent_template_param                     = true
>>>>>>> +indent_var_def_blk                        = 0
>>>>>>> +indent_var_def_cont                       = false
>>>>>>> +
>>>>>>> +# Tidy-up rules (Optional)
>>>>>>> +mod_move_case_break             = true      # Whether to move a 
>>>>>>> 'break' that appears after a fully braced 'case'
>>>>>>> +                                            # before the close 
>>>>>>> brace, as in 'case X: { ... } break;' =>
>>>>>>> +                                            # 'case X: { ... 
>>>>>>> break; }'.
>>>>>>> +mod_pawn_semicolon              = false
>>>>>>> +mod_remove_empty_return         = false     # Whether to remove 
>>>>>>> a void 'return;' that appears as the last
>>> statement
>>>>>>> +                                            # in a function.
>>>>>>> +mod_remove_extra_semicolon      = true
>>>>>>> +mod_sort_import                 = false
>>>>>>> +mod_sort_include                = false
>>>>>>> +mod_sort_using                  = false
>>>>>>> +nl_after_case                   = false     # Whether to add a 
>>>>>>> newline after a 'case' statement.
>>>>>>> +nl_end_of_file                  = force     # Add or remove 
>>>>>>> newline at the end of the file.
>>>>>>> +nl_end_of_file_min              = 1         # The minimum number 
>>>>>>> of newlines at the end of the file
>>>>>>> +nl_max                          = 2         # The maximum number 
>>>>>>> of consecutive newlines (3 = 2 blank lines).
>>>>>>> +nl_start_of_file                = remove    # Add or remove 
>>>>>>> newlines at the start of the file.
>>>>>>> +
>>>>>>> +# Code alignment rules (Optional)
>>>>>>> +align_asm_colon                 = false
>>>>>>> +align_assign_span               = 1         # The span for 
>>>>>>> aligning on '=' in assignments.
>>>>>>> +align_assign_thresh             = 4
>>>>>>> +align_edk2_style                = true      # Whether to apply 
>>>>>>> edk2-specific alignment formatting
>>>>>>> +align_enum_equ_span             = 1         # The span for 
>>>>>>> aligning on '=' in enums.
>>>>>>> +align_func_params               = true      # Whether to align 
>>>>>>> variable definitions in prototypes and functions.
>>>>>>> +align_func_params_gap           = 2
>>>>>>> +align_func_params_span          = 2         # The span for 
>>>>>>> aligning parameter definitions in function on parameter
>>>>> name.
>>>>>>> +align_func_params_thresh        = 0
>>>>>>> +align_func_proto_span           = 0
>>>>>>> +align_keep_tabs                 = false
>>>>>>> +align_left_shift                = false
>>>>>>> +align_mix_var_proto             = false
>>>>>>> +align_nl_cont                   = false
>>>>>>> +align_oc_decl_colon             = false
>>>>>>> +align_on_operator               = false
>>>>>>> +align_on_tabstop                = false
>>>>>>> +align_pp_define_gap             = 2
>>>>>>> +align_pp_define_span            = 1
>>>>>>> +align_right_cmt_at_col          = 0         # Align trailing 
>>>>>>> comment at or beyond column N; 'pulls in' comments as
>>>>>>> +                                            # a bonus side 
>>>>>>> effect (0=ignore)
>>>>>>> +align_right_cmt_gap             = 0         # If a trailing 
>>>>>>> comment is more than this number of columns away from
>>>> the
>>>>>>> +                                            # text it follows,
>>>>>>> +                                            # it will qualify 
>>>>>>> for being aligned. This has to be > 0 to do
>>> anything.
>>>>>>> +align_right_cmt_mix             = false     # If aligning 
>>>>>>> comments, mix with comments after '}' and #endif with
>>> less
>>>>>>> +                                            # than 3 spaces 
>>>>>>> before the comment
>>>>>>> +align_right_cmt_same_level      = true      # Whether to only 
>>>>>>> align trailing comments that are at the same brace
>>>>> level.
>>>>>>> +align_right_cmt_span            = 2         # The span for 
>>>>>>> aligning comments that end lines.
>>>>>>> +align_same_func_call_params     = false
>>>>>>> +align_single_line_brace         = true
>>>>>>> +align_single_line_func          = true
>>>>>>> +align_struct_init_span          = 1         # The span for 
>>>>>>> aligning struct initializer values.
>>>>>>> +align_typedef_amp_style         = 1
>>>>>>> +align_typedef_func              = 1         # How to align 
>>>>>>> typedef'd functions with other typedefs.
>>>>>>> +                                            # (0: No align, 1: 
>>>>>>> Align open paranthesis, 2: Align function type
>>> name)
>>>>>>> +align_typedef_gap               = 2
>>>>>>> +align_typedef_span              = 1         # The span for 
>>>>>>> aligning single-line typedefs.
>>>>>>> +align_typedef_star_style        = 1
>>>>>>> +align_var_def_amp_style         = 1
>>>>>>> +align_var_def_attribute         = true
>>>>>>> +align_var_def_colon             = true      # Whether to align 
>>>>>>> the colon in struct bit fields.
>>>>>>> +align_var_def_gap               = 2         # The gap (minimum 
>>>>>>> spacing for aligned items) for variable
>>> definitions.
>>>>>>> +align_var_def_inline            = false
>>>>>>> +align_var_def_span              = 1         # The span (lines 
>>>>>>> needed to align) for aligning variable definitions.
>>>>>>> +align_var_def_star_style        = 1         # How to consider 
>>>>>>> (or treat) the '*' in the alignment of variable
>>>>>>> +                                            # definitions.
>>>>>>> +                                            # 0: Part of the 
>>>>>>> type     'void *   foo;' (default)
>>>>>>> +                                            # 1: Part of the 
>>>>>>> variable 'void     *foo;'
>>>>>>> +                                            # 2: 
>>>>>>> Dangling             'void    *foo;'
>>>>>>> +                                            # (Note - should 
>>>>>>> also set sp_after_ptr_star=remove)
>>>>>>> +align_var_struct_gap            = 4
>>>>>>> +align_var_struct_span           = 8         # The span for 
>>>>>>> aligning struct/union member definitions.
>>>>>>> +align_var_struct_thresh         = 0
>>>>>>> +align_with_tabs                 = false
>>>>>>> +
>>>>>>> +# Comment formatting
>>>>>>> +cmt_align_doxygen_javadoc_tags  = true      # Whether to align 
>>>>>>> doxygen javadoc-style tags ('@param', '@return',
>>>> etc.)
>>>>>>> +                                            # TODO: Eats '[' in 
>>>>>>> '[in]'
>>>>>>> +cmt_c_group                     = false
>>>>>>> +cmt_c_nl_end                    = true      # Whether to add a 
>>>>>>> newline before the closing '*/' of the combined c-
>>>>> comment.
>>>>>>> +cmt_c_nl_start                  = true
>>>>>>> +cmt_cpp_group                   = false
>>>>>>> +cmt_cpp_nl_end                  = true
>>>>>>> +cmt_cpp_nl_start                = true
>>>>>>> +cmt_cpp_to_c                    = false
>>>>>>> +cmt_indent_multi                = false     # Whether to apply 
>>>>>>> changes to multi-line comments, including
>>> cmt_width,
>>>>>>> +                                            # keyword 
>>>>>>> substitution and leading chars.
>>>>>>> +cmt_insert_before_preproc       = false
>>>>>>> +cmt_insert_file_header          = default_file_header.txt
>>>>>>> +cmt_insert_func_header          = default_function_header.txt
>>>>>>> +cmt_multi_check_last            = false
>>>>>>> +cmt_multi_first_len_minimum     = 2
>>>>>>> +cmt_reflow_mode                 = 1         # How to reflow 
>>>>>>> comments.
>>>>>>> +                                            # (0:No reflow, 1:No 
>>>>>>> touching at all, 2: Full reflow)
>>>>>>> +cmt_sp_after_star_cont          = 0         # The number of 
>>>>>>> spaces to insert after the star on subsequent comment
>>>>> lines.
>>>>>>> +cmt_sp_before_star_cont         = 0         # The number of 
>>>>>>> spaces to insert at the start of subsequent comment
>>>> lines.
>>>>>>> +cmt_star_cont                   = false     # Whether to put a 
>>>>>>> star on subsequent comment lines.
>>>>>>> +cmt_width                       = 120       # Try to wrap 
>>>>>>> comments at N columns.
>>>>>>> +sp_cmt_cpp_start                = add       # Add or remove 
>>>>>>> space after the opening of a C++ comment, as in
>>>>>>> +                                            # '// <here> A'.  
>>>>>>> NOTE: Breaks indentation within comments.
>>>>>>> +
>>>>>>> +# Function definitions / declarations
>>>>>>> +indent_func_call_param          = false     # Whether to indent 
>>>>>>> continued function call parameters one indent
>>> level,
>>>>>>> +                                            # rather than 
>>>>>>> aligning parameters under the open parenthesis.
>>>>>>> +indent_func_class_param         = false     # Whether to indent 
>>>>>>> continued function call declaration one indent
>>>> level,
>>>>>>> +                                            # rather than 
>>>>>>> aligning parameters under the open parenthesis.
>>>>>>> +indent_func_ctor_var_param      = false     # Whether to indent 
>>>>>>> continued class variable constructors one indent
>>>>> level,
>>>>>>> +                                            # rather than 
>>>>>>> aligning parameters under the open parenthesis.
>>>>>>> +indent_func_def_param           = true      # Whether to indent 
>>>>>>> continued function definition parameters one
>>> indent
>>>>>>> +                                            # level, rather than 
>>>>>>> aligning parameters under the open parenthesis.
>>>>>>> +nl_fdef_brace                   = add       # Add or remove 
>>>>>>> newline between function signature and '{'.
>>>>>>> +nl_func_call_end_multi_line     = true      # Whether to add a 
>>>>>>> newline before ')' in a function call if '(' and
>>> ')'
>>>>> are
>>>>>>> +                                            # in different lines.
>>>>>>> +nl_func_call_paren              = remove    # Add or remove 
>>>>>>> newline between a function name and the opening '(' in
>>>> the
>>>>>>> +                                            # call.
>>>>>>> +nl_func_call_start_multi_line   = true      # Whether to add a 
>>>>>>> newline after '(' in a function call if '(' and ')'
>>>> are
>>>>>>> +                                            # in different lines.
>>>>>>> +nl_func_decl_args               = force     # Add or remove 
>>>>>>> newline after each ',' in a function declaration.
>>>>>>> +nl_func_decl_empty              = add       # Add or remove 
>>>>>>> newline between '()' in a function declaration.
>>>>>>> +nl_func_def_args                = force     # Add or remove 
>>>>>>> newline after each ',' in a function definition.
>>>>>>> +nl_func_def_empty               = add       # Add or remove 
>>>>>>> newline between '()' in a function definition.
>>>>>>> +nl_func_def_paren               = remove    # Add or remove 
>>>>>>> newline between a function name and the opening '('
>>>>>>> +                                            # in the definition.
>>>>>>> +nl_func_paren                   = remove    # Add or remove 
>>>>>>> newline between a function name and the opening '(' in
>>>>>>> +                                            # the declaration.
>>>>>>> +nl_func_type_name               = add       # Add or remove 
>>>>>>> newline between return type and function name in a
>>>>> function
>>>>>>> +                                            # definition.
>>>>>>> +sp_fparen_brace                 = force     # Add or remove 
>>>>>>> space between ')' and '{' of function.
>>>>>>> +use_indent_func_call_param      = true      # 
>>>>>>> indent_func_call_param will be used
>>>>>>> +
>>>>>>> +# Additional Newline Rules
>>>>>>> +nl_after_brace_open                          = true     # 
>>>>>>> Whether to add a newline after '{'. This also adds a
>>>> newline
>>>>>>> +                                                        # before 
>>>>>>> the matching '}'.
>>>>>>> +nl_after_brace_open_cmt                      = true     # 
>>>>>>> Whether to add a newline between the open brace and a
>>>>>>> +                                                        # 
>>>>>>> trailing single-line comment.
>>>>>>> +                                                        # 
>>>>>>> Requires nl_after_brace_open = true.
>>>>>>> +nl_after_do                                  = add      # Add or 
>>>>>>> remove blank line after 'do/while' statement.
>>>>>>> +nl_after_for                                 = add      # Add or 
>>>>>>> remove blank line after 'for' statement.
>>>>>>> +nl_after_func_body                           = 2        # The 
>>>>>>> number of newlines after '}' of a multi-line
>>> function
>>>>> body
>>>>>>> +nl_after_func_body_one_liner                 = 2
>>>>>>> +nl_after_func_proto                          = 2
>>>>>>> +nl_after_func_proto_group                    = 2
>>>>>>> +nl_after_if                                  = add
>>>>>>> +nl_after_multiline_comment                   = false
>>>>>>> +nl_after_return                              = false
>>>>>>> +nl_after_struct                              = 2
>>>>>>> +nl_after_switch                              = add
>>>>>>> +nl_after_vbrace_close                        = true
>>>>>>> +nl_after_vbrace_open                         = true
>>>>>>> +nl_after_vbrace_open_empty                   = true
>>>>>>> +nl_after_while                               = add
>>>>>>> +nl_assign_leave_one_liners                   = true
>>>>>>> +nl_before_block_comment                      = 2
>>>>>>> +nl_before_case                               = false
>>>>>>> +nl_before_do                                 = ignore
>>>>>>> +nl_before_for                                = ignore
>>>>>>> +nl_before_if                                 = ignore
>>>>>>> +nl_before_switch                             = ignore
>>>>>>> +nl_before_while                              = ignore
>>>>>>> +nl_before_whole_file_ifdef                   = 2
>>>>>>> +nl_brace_brace                               = force
>>>>>>> +nl_brace_struct_var                          = remove
>>>>>>> +nl_case_colon_brace                          = add
>>>>>>> +nl_class_leave_one_liners                    = false
>>>>>>> +nl_collapse_empty_body                       = false
>>>>>>> +nl_comment_func_def                          = 1
>>>>>>> +nl_create_for_one_liner                      = false
>>>>>>> +nl_create_if_one_liner                       = false
>>>>>>> +nl_create_while_one_liner                    = false
>>>>>>> +nl_define_macro                              = false
>>>>>>> +nl_ds_struct_enum_close_brace                = true
>>>>>>> +nl_ds_struct_enum_cmt                        = false
>>>>>>> +nl_enum_leave_one_liners                     = false
>>>>>>> +nl_func_decl_end                             = add
>>>>>>> +nl_func_decl_start                           = add
>>>>>>> +nl_func_def_end                              = add
>>>>>>> +nl_func_def_start                            = add
>>>>>>> +nl_func_leave_one_liners                     = false
>>>>>>> +nl_func_proto_type_name                      = add
>>>>>>> +nl_func_var_def_blk                          = 1
>>>>>>> +nl_getset_leave_one_liners                   = false
>>>>>>> +nl_if_leave_one_liners                       = false
>>>>>>> +nl_multi_line_define                         = false
>>>>>>> +nl_squeeze_ifdef                             = false
>>>>>>> +nl_var_def_blk_end                           = 0
>>>>>>> +nl_var_def_blk_start                         = 0
>>>>>>> +
>>>>>>> +# Preprocessor Rules
>>>>>>> +pp_define_at_level      = true
>>>>>>> +pp_if_indent_code       = false
>>>>>>> +pp_indent_func_def      = false
>>>>>>> +pp_indent_extern        = false
>>>>>>> +pp_ignore_define_body   = true                # Workaround: Turn 
>>>>>>> off processing for #define body
>>>>>>> +                                              # (current rules 
>>>>>>> do not work for some defines)
>>>>>>> +pp_indent               = add
>>>>>>> +pp_indent_at_level      = true
>>>>>>> +pp_indent_count         = 2
>>>>>>> +pp_indent_if            = 2
>>>>>>> +pp_indent_region        = 2
>>>>>>> +pp_region_indent_code   = false
>>>>>>> +pp_space                = remove
>>>>>>> +
>>>>>>> +#
>>>>>>> +# The tokens below are assigned specific types so they are 
>>>>>>> always recognized properly.
>>>>>>> +#
>>>>>>> +
>>>>>>> +# Explicitly define EDK II qualifiers
>>>>>>> +set QUALIFIER CONST
>>>>>>> +set QUALIFIER EFIAPI
>>>>>>> +set QUALIFIER IN
>>>>>>> +set QUALIFIER OPTIONAL
>>>>>>> +set QUALIFIER OUT
>>>>>>> +
>>>>>>> +# Explicitly define EDK II types
>>>>>>> +set TYPE EFI_STATUS
>>>>>>> +set TYPE VOID
>>>>>>> diff --git a/.pytool/Plugin/UncrustifyCheck/uncrustify_ext_dep.yaml
>>>>>>> b/.pytool/Plugin/UncrustifyCheck/uncrustify_ext_dep.yaml
>>>>>>> new file mode 100644
>>>>>>> index 000000000000..d8c22403b4b1
>>>>>>> --- /dev/null
>>>>>>> +++ b/.pytool/Plugin/UncrustifyCheck/uncrustify_ext_dep.yaml
>>>>>>> @@ -0,0 +1,16 @@
>>>>>>> +## @file
>>>>>>> +# Downloads the Uncrustify application from a Project Mu NuGet 
>>>>>>> package.
>>>>>>> +#
>>>>>>> +# Copyright (c) Microsoft Corporation.
>>>>>>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>>>>>>> +##
>>>>>>> +{
>>>>>>> +  "id": "uncrustify-ci-1",
>>>>>>> +  "scope": "cibuild",
>>>>>>> +  "type": "nuget",
>>>>>>> +  "name": "mu-uncrustify-release",
>>>>>>> +  "source": 
>>>>>>> "https://pkgs.dev.azure.com/projectmu/Uncrustify/_packaging/mu_uncrustify/nuget/v3/index.json", 
>>>>>>>
>>>>>>> +  "version": "73.0.3",
>>>>>>> +  "flags": ["set_shell_var", "host_specific"],
>>>>>>> +  "var_name": "UNCRUSTIFY_CI_PATH"
>>>>>>> +}
>>>>>>> diff --git a/.pytool/Plugin/UncrustifyCheck/uncrustify_plug_in.yaml
>>>>>>> b/.pytool/Plugin/UncrustifyCheck/uncrustify_plug_in.yaml
>>>>>>> new file mode 100644
>>>>>>> index 000000000000..06c76af02759
>>>>>>> --- /dev/null
>>>>>>> +++ b/.pytool/Plugin/UncrustifyCheck/uncrustify_plug_in.yaml
>>>>>>> @@ -0,0 +1,11 @@
>>>>>>> +## @file
>>>>>>> +# CiBuildPlugin used to check coding standard compliance of EDK 
>>>>>>> II style C source code
>>>>>>> +#
>>>>>>> +# Copyright (c) Microsoft Corporation.
>>>>>>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>>>>>>> +##
>>>>>>> +{
>>>>>>> +  "scope": "cibuild",
>>>>>>> +  "name": "Uncrustify Coding Standard Test",
>>>>>>> +  "module": "UncrustifyCheck"
>>>>>>> +}
>>>>>>> diff --git a/.pytool/Readme.md b/.pytool/Readme.md
>>>>>>> index f6505507966a..e0d07f317049 100644
>>>>>>> --- a/.pytool/Readme.md
>>>>>>> +++ b/.pytool/Readme.md
>>>>>>> @@ -264,6 +264,10 @@ BSD-2-Clause-Patent.
>>>>>>>    Run the Ecc tool on the package. The Ecc tool is available in 
>>>>>>> the BaseTools
>>>>>>>    package. It checks that the code complies to the EDKII coding 
>>>>>>> standard.
>>>>>>>
>>>>>>> +### Coding Standard Compliance - UncrustifyCheck
>>>>>>> +
>>>>>>> +Runs the Uncrustify application to check for coding standard 
>>>>>>> compliance issues.
>>>>>>> +
>>>>>>>    ## PyTool Scopes
>>>>>>>
>>>>>>>    Scopes are how the PyTool ext_dep, path_env, and plugins are 
>>>>>>> activated.  Meaning
>>>>>>> -- 
>>>>>>> 2.28.0.windows.1
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>
>>
>>
>>
>>
>>
> 
> 
> 
> 

  parent reply	other threads:[~2021-11-25  1:25 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-11-24 21:41 [PATCH v4 1/1] .pytool/Plugin/UncrustifyCheck: Add Uncrustify CI plugin Michael Kubacki
2021-11-24 22:45 ` Michael D Kinney
2021-11-24 22:54   ` [edk2-devel] " Michael Kubacki
2021-11-24 23:05     ` Michael D Kinney
2021-11-25  0:08       ` Michael D Kinney
2021-11-25  0:16         ` Michael D Kinney
2021-11-25  0:24           ` Michael Kubacki
     [not found]           ` <16BAA253C971EED8.15594@groups.io>
2021-11-25  1:25             ` Michael Kubacki [this message]
2021-11-25  2:05               ` Michael D Kinney

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=8dbc6f60-dcb7-6a1f-c19e-3eb696c1afa3@linux.microsoft.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