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: mikub...@linux.microsoft.com <mikub...@linux.microsoft.com> > Sent: Wednesday, November 24, 2021 1:42 PM > To: devel@edk2.groups.io > Cc: Kinney, Michael D <michael.d.kin...@intel.com>; Liming Gao > <gaolim...@byosoft.com.cn>; Sean Brogan > <sean.bro...@microsoft.com>; Bret Barkelew <bret.barke...@microsoft.com> > Subject: [PATCH v4 1/1] .pytool/Plugin/UncrustifyCheck: Add Uncrustify CI > plugin > > From: Michael Kubacki <michael.kuba...@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.kin...@intel.com> > Cc: Liming Gao <gaolim...@byosoft.com.cn> > Cc: Sean Brogan <sean.bro...@microsoft.com> > Cc: Bret Barkelew <bret.barke...@microsoft.com> > Signed-off-by: Michael Kubacki <michael.kuba...@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 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#84059): https://edk2.groups.io/g/devel/message/84059 Mute This Topic: https://groups.io/mt/87290954/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-