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