]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Scripts/DetectNotUsedItem.py
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / BaseTools / Scripts / DetectNotUsedItem.py
CommitLineData
401507c7
FZ
1## @file\r
2# Detect unreferenced PCD and GUID/Protocols/PPIs.\r
3#\r
4# Copyright (c) 2019, Intel Corporation. All rights reserved.\r
5#\r
6# SPDX-License-Identifier: BSD-2-Clause-Patent\r
7#\r
8\r
9'''\r
10DetectNotUsedItem\r
11'''\r
12import re\r
13import os\r
14import sys\r
15import argparse\r
16\r
17#\r
18# Globals for help information\r
19#\r
20__prog__ = 'DetectNotUsedItem'\r
21__version__ = '%s Version %s' % (__prog__, '0.1')\r
22__copyright__ = 'Copyright (c) 2019, Intel Corporation. All rights reserved.'\r
23__description__ = "Detect unreferenced PCD and GUID/Protocols/PPIs.\n"\r
24\r
25SectionList = ["LibraryClasses", "Guids", "Ppis", "Protocols", "Pcd"]\r
26\r
27\r
28class PROCESS(object):\r
29\r
30 def __init__(self, DecPath, InfDirs):\r
31 self.Dec = DecPath\r
32 self.InfPath = InfDirs\r
33 self.Log = []\r
34\r
35 def ParserDscFdfInfFile(self):\r
36 AllContentList = []\r
37 for File in self.SearchbyExt([".dsc", ".fdf", ".inf"]):\r
38 AllContentList += self.ParseDscFdfInfContent(File)\r
39 return AllContentList\r
40\r
41 # Search File by extension name\r
42 def SearchbyExt(self, ExtList):\r
43 FileList = []\r
44 for path in self.InfPath:\r
45 if type(ExtList) == type(''):\r
46 for root, _, files in os.walk(path, topdown=True, followlinks=False):\r
47 for filename in files:\r
48 if filename.endswith(ExtList):\r
49 FileList.append(os.path.join(root, filename))\r
50 elif type(ExtList) == type([]):\r
51 for root, _, files in os.walk(path, topdown=True, followlinks=False):\r
52 for filename in files:\r
53 for Ext in ExtList:\r
54 if filename.endswith(Ext):\r
55 FileList.append(os.path.join(root, filename))\r
56 return FileList\r
57\r
58 # Parse DEC file to get Line number and Name\r
59 # return section name, the Item Name and comments line number\r
60 def ParseDecContent(self):\r
61 SectionRE = re.compile(r'\[(.*)\]')\r
62 Flag = False\r
63 Comments = {}\r
64 Comment_Line = []\r
65 ItemName = {}\r
66 with open(self.Dec, 'r') as F:\r
67 for Index, content in enumerate(F):\r
68 NotComment = not content.strip().startswith("#")\r
69 Section = SectionRE.findall(content)\r
70 if Section and NotComment:\r
71 Flag = self.IsNeedParseSection(Section[0])\r
72 if Flag:\r
73 Comment_Line.append(Index)\r
74 if NotComment:\r
75 if content != "\n" and content != "\r\n":\r
76 ItemName[Index] = content.split('=')[0].split('|')[0].split('#')[0].strip()\r
77 Comments[Index] = Comment_Line\r
78 Comment_Line = []\r
79 return ItemName, Comments\r
80\r
81 def IsNeedParseSection(self, SectionName):\r
82 for item in SectionList:\r
83 if item in SectionName:\r
84 return True\r
85 return False\r
86\r
87 # Parse DSC, FDF, INF File, remove comments, return Lines list\r
88 def ParseDscFdfInfContent(self, File):\r
89 with open(File, 'r') as F:\r
90 lines = F.readlines()\r
91 for Index in range(len(lines) - 1, -1, -1):\r
92 if lines[Index].strip().startswith("#") or lines[Index] == "\n" or lines[Index] == "\r\n":\r
93 lines.remove(lines[Index])\r
94 elif "#" in lines[Index]:\r
95 lines[Index] = lines[Index].split("#")[0].strip()\r
96 else:\r
97 lines[Index] = lines[Index].strip()\r
98 return lines\r
99\r
100 def DetectNotUsedItem(self):\r
101 NotUsedItem = {}\r
102 DecItem, DecComments = self.ParseDecContent()\r
103 InfDscFdfContent = self.ParserDscFdfInfFile()\r
104 for LineNum in list(DecItem.keys()):\r
105 DecItemName = DecItem[LineNum]\r
106 Match_reg = re.compile("(?<![a-zA-Z0-9_-])%s(?![a-zA-Z0-9_-])" % DecItemName)\r
107 MatchFlag = False\r
108 for Line in InfDscFdfContent:\r
109 if Match_reg.search(Line):\r
110 MatchFlag = True\r
111 break\r
112 if not MatchFlag:\r
113 NotUsedItem[LineNum] = DecItemName\r
114 self.Display(NotUsedItem)\r
115 return NotUsedItem, DecComments\r
116\r
117 def Display(self, UnuseDict):\r
118 print("DEC File:\n%s\n%s%s" % (self.Dec, "{:<15}".format("Line Number"), "{:<0}".format("Unused Item")))\r
119 self.Log.append(\r
120 "DEC File:\n%s\n%s%s\n" % (self.Dec, "{:<15}".format("Line Number"), "{:<0}".format("Unused Item")))\r
121 for num in list(sorted(UnuseDict.keys())):\r
122 ItemName = UnuseDict[num]\r
123 print("%s%s%s" % (" " * 3, "{:<12}".format(num + 1), "{:<1}".format(ItemName)))\r
124 self.Log.append(("%s%s%s\n" % (" " * 3, "{:<12}".format(num + 1), "{:<1}".format(ItemName))))\r
125\r
126 def Clean(self, UnUseDict, Comments):\r
127 removednum = []\r
128 for num in list(UnUseDict.keys()):\r
129 if num in list(Comments.keys()):\r
130 removednum += Comments[num]\r
131 with open(self.Dec, 'r') as Dec:\r
132 lines = Dec.readlines()\r
133 try:\r
134 with open(self.Dec, 'w+') as T:\r
135 for linenum in range(len(lines)):\r
136 if linenum in removednum:\r
137 continue\r
138 else:\r
139 T.write(lines[linenum])\r
140 print("DEC File has been clean: %s" % (self.Dec))\r
141 except Exception as err:\r
142 print(err)\r
143\r
144\r
145class Main(object):\r
146\r
147 def mainprocess(self, Dec, Dirs, Isclean, LogPath):\r
148 for dir in Dirs:\r
149 if not os.path.exists(dir):\r
150 print("Error: Invalid path for '--dirs': %s" % dir)\r
151 sys.exit(1)\r
152 Pa = PROCESS(Dec, Dirs)\r
153 unuse, comment = Pa.DetectNotUsedItem()\r
154 if Isclean:\r
155 Pa.Clean(unuse, comment)\r
156 self.Logging(Pa.Log, LogPath)\r
157\r
158 def Logging(self, content, LogPath):\r
159 if LogPath:\r
160 try:\r
161 if os.path.isdir(LogPath):\r
162 FilePath = os.path.dirname(LogPath)\r
163 if not os.path.exists(FilePath):\r
164 os.makedirs(FilePath)\r
165 with open(LogPath, 'w+') as log:\r
166 for line in content:\r
167 log.write(line)\r
168 print("Log save to file: %s" % LogPath)\r
169 except Exception as e:\r
170 print("Save log Error: %s" % e)\r
171\r
172\r
173def main():\r
174 parser = argparse.ArgumentParser(prog=__prog__,\r
175 description=__description__ + __copyright__,\r
176 conflict_handler='resolve')\r
177 parser.add_argument('-i', '--input', metavar="", dest='InputDec', help="Input DEC file name.")\r
178 parser.add_argument('--dirs', metavar="", action='append', dest='Dirs',\r
179 help="The package directory. To specify more directories, please repeat this option.")\r
180 parser.add_argument('--clean', action='store_true', default=False, dest='Clean',\r
181 help="Clean the unreferenced items from DEC file.")\r
182 parser.add_argument('--log', metavar="", dest="Logfile", default=False,\r
183 help="Put log in specified file as well as on console.")\r
184 options = parser.parse_args()\r
185 if options.InputDec:\r
186 if not (os.path.exists(options.InputDec) and options.InputDec.endswith(".dec")):\r
187 print("Error: Invalid DEC file input: %s" % options.InputDec)\r
188 if options.Dirs:\r
189 M = Main()\r
190 M.mainprocess(options.InputDec, options.Dirs, options.Clean, options.Logfile)\r
191 else:\r
192 print("Error: the following argument is required:'--dirs'.")\r
193 else:\r
194 print("Error: the following argument is required:'-i/--input'.")\r
195\r
196\r
197if __name__ == '__main__':\r
198 main()\r