public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Michael Kubacki" <mikuback@linux.microsoft.com>
To: "Kinney, Michael D" <michael.d.kinney@intel.com>,
	"devel@edk2.groups.io" <devel@edk2.groups.io>
Cc: Liming Gao <gaoliming@byosoft.com.cn>,
	Sean Brogan <sean.brogan@microsoft.com>,
	Bret Barkelew <Bret.Barkelew@microsoft.com>
Subject: Re: [PATCH v1 1/1] .pytool/Plugin/Uncrustify: Add Uncrustify plugin
Date: Tue, 23 Nov 2021 15:34:43 -0500	[thread overview]
Message-ID: <adad4f66-07f7-5974-7fac-cdc5aecdfc22@linux.microsoft.com> (raw)
In-Reply-To: <CO1PR11MB4929509F9EF433E691731DFDD2609@CO1PR11MB4929.namprd11.prod.outlook.com>

Response below.

On 11/23/2021 3:19 PM, Kinney, Michael D wrote:
> Hi Michael,
> 
> Comments below.
> 
> Mike
> 
>> -----Original Message-----
>> From: Michael Kubacki <mikuback@linux.microsoft.com>
>> Sent: Tuesday, November 23, 2021 12:07 PM
>> To: Kinney, Michael D <michael.d.kinney@intel.com>; devel@edk2.groups.io
>> Cc: Liming Gao <gaoliming@byosoft.com.cn>; Sean Brogan <sean.brogan@microsoft.com>; Bret Barkelew
>> <Bret.Barkelew@microsoft.com>
>> Subject: Re: [PATCH v1 1/1] .pytool/Plugin/Uncrustify: Add Uncrustify plugin
>>
>> I'll file a BZ and add it.
>>
>> I don't see a difference comparing my template file contents against the
>> corresponding files in the branch you linked. Am I missing something?
> 
> You are correct.  Please ignore.
> 
> I saw reference to Project Mu, but that is in the
> .pytool/Plugin/Uncrustify/uncrustify_ext_dep.yaml file, which is correct
> because that is where the fork of uncrustify tool with EDK II extensions
> is hosted.
> 
>>
>> I saw the temp file directory change recently added to those plugin
>> patches. My concern is that .pytool/ is tracked by git and Build/ is not.
> 
> My suggestion is to use Build/.pytool/Plugin/<PluginName> as a temp
> directory that is in Build output directory that is ignored by .gitignore.
> 
Okay, I missed this is relative to the Build directory. I can make that 
change.
>>
>> In the unlikely case the temp file removal fails (for whatever reason),
>> the git workspace does not pick up the left over files.
>>
>> Given the plugin is storing temp files in a "UncrustifyPlugin" directory
>> in each package's build directory, I don't anticipate conflicts (unless
>> the user has intentionally tried to do so). I've also taken time to
>> improve temp directory removal robustness in ways I haven't seen in
>> other plugins including doing so for cases like keyboard interrupts and
>> attempting multiple times for sporadic issues that might occur during
>> removal (that we've very rarely observed across many CI instances).
>>
>> Technically, since .pytool/ is tracked, the user could also have local
>> changes there that conflict with what the plugin produces as temporary
>> output.
>>
>> So I didn't see a strong practical benefit to changing it from
>> Build/{PackageName}/UncrustifyPlugin. Is there a benefit/issue I missed?
> 
> I have seen a difference between CRTL-C and CRTL-BREAK.  CRTL-C is caught
> by Python exception processing so the temp dir can be removed.  CRTL-BREAK
> or other OS specific actions to kill a process bypasses the Python exception
> handling and the temp dir will not be removed.
> 
> I recommend moving all temp dirs/files into locations that are guaranteed
> to never be seen as untracked files by git.
> 
>>
>> Thanks,
>> Michael
>>
>> On 11/23/2021 2:20 PM, Kinney, Michael D wrote:
>>> Hi Michael,
>>>
>>> Have you opened a BZ for this feature?  Can you do that and add REF: to the commit message?
>>>
>>> Also, the template files for uncrustify need to be updated to match the contents
>>> from the EDK II C Coding Standard.  Pease see the file and function header templates
>>> in this location:
>>>
>>>       https://github.com/mdkinney/edk2/tree/Bug_3737_ApplyUncrustifyChanges_V4/.uncrustify
>>>
>>> I also see you use a temp directory in Build output:
>>>
>>>> +        self._working_dir = os.path.join(
>>>> +            self._abs_workspace_path, "Build", self._package_name, "UncrustifyPlugin")
>>>
>>> In the EccCheck and LicenseCheck patches I sent earlier today, I decided to put all
>>> temp directories associated with pytools Plugins in the path:
>>>
>>>       Build/.pytool/Plugin/<PluginName>
>>>
>>> This provide a unique path for temp files associated with Plugins that matches
>>> the source path to the Plugin so plugins will never use the same temp dir path
>>> and each plugin can safely clean up its own temp directory.
>>>
>>> Thanks,
>>>
>>> Mike
>>>
>>>> -----Original Message-----
>>>> From: mikuback@linux.microsoft.com <mikuback@linux.microsoft.com>
>>>> Sent: Tuesday, November 23, 2021 8:54 AM
>>>> 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 v1 1/1] .pytool/Plugin/Uncrustify: Add Uncrustify plugin
>>>>
>>>> From: Michael Kubacki <michael.kubacki@microsoft.com>
>>>>
>>>> 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.
>>>>
>>>> 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.
>>>>
>>>> Note: A V2 is planned that will fail the Uncrustify plugin results
>>>> if a file or function template header is found in a formatted file.
>>>> This will be additional functionality added in the plugin and will
>>>> not change the way Uncrustify is invoked.
>>>>
>>>> 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>
>>>> ---
>>>>    .pytool/Plugin/Uncrustify/Readme.md                   | 116 ++++
>>>>    .pytool/Plugin/Uncrustify/Uncrustify.py               | 556 ++++++++++++++++++++
>>>>    .pytool/Plugin/Uncrustify/default_file_header.txt     |   9 +
>>>>    .pytool/Plugin/Uncrustify/default_function_header.txt |  15 +
>>>>    .pytool/Plugin/Uncrustify/uncrustify.cfg              | 466 ++++++++++++++++
>>>>    .pytool/Plugin/Uncrustify/uncrustify_ext_dep.yaml     |  16 +
>>>>    .pytool/Plugin/Uncrustify/uncrustify_plug_in.yaml     |  12 +
>>>>    .pytool/Readme.md                                     |   4 +
>>>>    8 files changed, 1194 insertions(+)
>>>>
>>>> diff --git a/.pytool/Plugin/Uncrustify/Readme.md b/.pytool/Plugin/Uncrustify/Readme.md
>>>> new file mode 100644
>>>> index 000000000000..46586d81c68c
>>>> --- /dev/null
>>>> +++ b/.pytool/Plugin/Uncrustify/Readme.md
>>>> @@ -0,0 +1,116 @@
>>>> +# Uncrustify Plugin
>>>> +
>>>> +This CiBuildPlugin scans all the files in a given package and checks for coding standard compliance issues.
>>>> +
>>>> +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
>>>> +  "Uncrustify": {
>>>> +      "AuditOnly": False,           # Don't fail the build if there are errors. Just log them.
>>>> +      "OutputFileDiffs": False      # Output chunks of formatting diffs in the test case log.
>>>> +                                    # This can significantly slow down the plugin on very large packages.
>>>> +      "ConfigFilePath": "",         # Custom path to an Uncrustify config file. Path is relative to the package.
>>>> +      "IgnoreStandardPaths": [],    # Standard Plugin defined paths that should be ignored.
>>>> +      "AdditionalIncludePaths": []  # Additional paths to check formatting (wildcards supported).
>>>> +  }
>>>> +```
>>>> +
>>>> +### `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/{package_name}`
>>>> +  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/Uncrustify/Uncrustify.py b/.pytool/Plugin/Uncrustify/Uncrustify.py
>>>> new file mode 100644
>>>> index 000000000000..b207b1df4cb1
>>>> --- /dev/null
>>>> +++ b/.pytool/Plugin/Uncrustify/Uncrustify.py
>>>> @@ -0,0 +1,556 @@
>>>> +# @file Uncrustify.py
>>>> +#
>>>> +# An edk2-pytool based plugin wrapper for Uncrustify
>>>> +#
>>>> +# Copyright (c) Microsoft Corporation.
>>>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>>>> +##
>>>> +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 Uncrustify(ICiBuildPlugin):
>>>> +    """
>>>> +    A CiBuildPlugin that uses Uncrustify to format 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:
>>>> +    "Uncrustify": {
>>>> +        "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 + ".Uncrustify")
>>>> +
>>>> +    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()
>>>> +
>>>> +            # 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"Uncrustify checks 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'*{Uncrustify.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'*{Uncrustify.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", self._package_name, "UncrustifyPlugin")
>>>> +
>>>> +        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
>>>> {Uncrustify.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 _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 Uncrustify.UNCRUSTIFY_PATH_ENV_KEY not in os.environ:
>>>> +            raise UncrustifyAppEnvVarNotFoundException(
>>>> +                f"Uncrustify environment variable {Uncrustify.UNCRUSTIFY_PATH_ENV_KEY} is not present.")
>>>> +
>>>> +        self._app_path = shutil.which('uncrustify', path=os.environ[Uncrustify.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 = Uncrustify.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._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(
>>>> +            Uncrustify.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'*{Uncrustify.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(Uncrustify.FORMATTED_FILE_EXTENSION)]
>>>> +
>>>> +            if self._output_file_diffs:
>>>> +                with open(pre_formatted_file) as pf, open(formatted_file) as ff:
>>>> +                    self._tc.LogStdError(
>>>> +                        f"Formatting errors in {os.path.relpath(pre_formatted_file, self._abs_package_path)}:\n")
>>>> +
>>>> +                    for line in difflib.unified_diff(pf.readlines(), ff.readlines(), 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:
>>>> +                print(dir_path)
>>>> +                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/Uncrustify/default_file_header.txt b/.pytool/Plugin/Uncrustify/default_file_header.txt
>>>> new file mode 100644
>>>> index 000000000000..2955a734dfe1
>>>> --- /dev/null
>>>> +++ b/.pytool/Plugin/Uncrustify/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/Uncrustify/default_function_header.txt
>> b/.pytool/Plugin/Uncrustify/default_function_header.txt
>>>> new file mode 100644
>>>> index 000000000000..66edc72e6731
>>>> --- /dev/null
>>>> +++ b/.pytool/Plugin/Uncrustify/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/Uncrustify/uncrustify.cfg b/.pytool/Plugin/Uncrustify/uncrustify.cfg
>>>> new file mode 100644
>>>> index 000000000000..d6e98dfa9c01
>>>> --- /dev/null
>>>> +++ b/.pytool/Plugin/Uncrustify/uncrustify.cfg
>>>> @@ -0,0 +1,466 @@
>>>> +## @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
>>>> +nl_func_call_start_multi_line   = true      # Whether to add a newline after '(' in a function call if '(' and ')' are
>>>> +                                            # in different lines.
>>>> +
>>>> +# - 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_call_args_multi_line                 = true
>>>> +nl_func_call_args_multi_line_ignore_closures = 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/Uncrustify/uncrustify_ext_dep.yaml b/.pytool/Plugin/Uncrustify/uncrustify_ext_dep.yaml
>>>> new file mode 100644
>>>> index 000000000000..d8c22403b4b1
>>>> --- /dev/null
>>>> +++ b/.pytool/Plugin/Uncrustify/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/Uncrustify/uncrustify_plug_in.yaml b/.pytool/Plugin/Uncrustify/uncrustify_plug_in.yaml
>>>> new file mode 100644
>>>> index 000000000000..25d9a8d37a30
>>>> --- /dev/null
>>>> +++ b/.pytool/Plugin/Uncrustify/uncrustify_plug_in.yaml
>>>> @@ -0,0 +1,12 @@
>>>> +## @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": "Uncrustify"
>>>> +}
>>>> +
>>>> diff --git a/.pytool/Readme.md b/.pytool/Readme.md
>>>> index f6505507966a..46d7248f7da3 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 - Uncrustify
>>>> +
>>>> +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
>>>

      reply	other threads:[~2021-11-23 20:34 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-11-23 16:53 [PATCH v1 1/1] .pytool/Plugin/Uncrustify: Add Uncrustify plugin Michael Kubacki
2021-11-23 19:20 ` Michael D Kinney
2021-11-23 20:06   ` Michael Kubacki
2021-11-23 20:19     ` Michael D Kinney
2021-11-23 20:34       ` Michael Kubacki [this message]

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=adad4f66-07f7-5974-7fac-cdc5aecdfc22@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