--- /dev/null
+# @file LicenseCheck.py\r
+#\r
+# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+##\r
+\r
+import os\r
+import logging\r
+import re\r
+from io import StringIO\r
+from typing import List, Tuple\r
+from edk2toolext.environment.plugintypes.ci_build_plugin import ICiBuildPlugin\r
+from edk2toolext.environment.var_dict import VarDict\r
+from edk2toollib.utility_functions import RunCmd\r
+\r
+\r
+class LicenseCheck(ICiBuildPlugin):\r
+\r
+ """\r
+ A CiBuildPlugin to check the license for new added files.\r
+\r
+ Configuration options:\r
+ "LicenseCheck": {\r
+ "IgnoreFiles": []\r
+ },\r
+ """\r
+\r
+ license_format_preflix = 'SPDX-License-Identifier'\r
+\r
+ bsd2_patent = 'BSD-2-Clause-Patent'\r
+\r
+ Readdedfileformat = re.compile(r'\+\+\+ b\/(.*)')\r
+\r
+ file_extension_list = [".c", ".h", ".inf", ".dsc", ".dec", ".py", ".bat", ".sh", ".uni", ".yaml",\r
+ ".fdf", ".inc", "yml", ".asm", ".asm16", ".asl", ".vfr", ".s", ".S", ".aslc",\r
+ ".nasm", ".nasmb", ".idf", ".Vfr", ".H"]\r
+\r
+ def GetTestName(self, packagename: str, environment: VarDict) -> tuple:\r
+ """ Provide the testcase name and classname for use in reporting\r
+ testclassname: a descriptive string for the testcase can include whitespace\r
+ classname: should be patterned <packagename>.<plugin>.<optionally any unique condition>\r
+\r
+ Args:\r
+ packagename: string containing name of package to build\r
+ environment: The VarDict for the test to run in\r
+ Returns:\r
+ a tuple containing the testcase name and the classname\r
+ (testcasename, classname)\r
+ """\r
+ return ("Check for license for " + packagename, packagename + ".LicenseCheck")\r
+\r
+ ##\r
+ # External function of plugin. This function is used to perform the task of the ci_build_plugin Plugin\r
+ #\r
+ # - package is the edk2 path to package. This means workspace/packagepath relative.\r
+ # - edk2path object configured with workspace and packages path\r
+ # - PkgConfig Object (dict) for the pkg\r
+ # - EnvConfig Object\r
+ # - Plugin Manager Instance\r
+ # - Plugin Helper Obj Instance\r
+ # - Junit Logger\r
+ # - output_stream the StringIO output stream from this plugin via logging\r
+ def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig, environment, PLM, PLMHelper, tc, output_stream=None):\r
+ return_buffer = StringIO()\r
+ params = "diff --unified=0 origin/master HEAD"\r
+ RunCmd("git", params, outstream=return_buffer)\r
+ p = return_buffer.getvalue().strip()\r
+ patch = p.split("\n")\r
+ return_buffer.close()\r
+\r
+ ignore_files = []\r
+ if "IgnoreFiles" in pkgconfig:\r
+ ignore_files = pkgconfig["IgnoreFiles"]\r
+\r
+ self.ok = True\r
+ self.startcheck = False\r
+ self.license = True\r
+ self.all_file_pass = True\r
+ count = len(patch)\r
+ line_index = 0\r
+ for line in patch:\r
+ if line.startswith('--- /dev/null'):\r
+ nextline = patch[line_index + 1]\r
+ added_file = self.Readdedfileformat.search(nextline).group(1)\r
+ added_file_extension = os.path.splitext(added_file)[1]\r
+ if added_file_extension in self.file_extension_list and packagename in added_file:\r
+ if (self.IsIgnoreFile(added_file, ignore_files)):\r
+ line_index = line_index + 1\r
+ continue\r
+ self.startcheck = True\r
+ self.license = False\r
+ if self.startcheck and self.license_format_preflix in line:\r
+ if self.bsd2_patent in line:\r
+ self.license = True\r
+ if line_index + 1 == count or patch[line_index + 1].startswith('diff --') and self.startcheck:\r
+ if not self.license:\r
+ self.all_file_pass = False\r
+ error_message = "Invalid license in: " + added_file + " Hint: Only BSD-2-Clause-Patent is accepted."\r
+ logging.error(error_message)\r
+ self.startcheck = False\r
+ self.license = True\r
+ line_index = line_index + 1\r
+\r
+ if self.all_file_pass:\r
+ tc.SetSuccess()\r
+ return 0\r
+ else:\r
+ tc.SetFailed("License Check {0} Failed. ".format(packagename), "LICENSE_CHECK_FAILED")\r
+ return 1\r
+\r
+ def IsIgnoreFile(self, file: str, ignore_files: List[str]) -> bool:\r
+ for f in ignore_files:\r
+ if f in file:\r
+ return True\r
+ return False\r