]>
git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Scripts/DetectNotUsedItem.py
2 # Detect unreferenced PCD and GUID/Protocols/PPIs.
4 # Copyright (c) 2019, Intel Corporation. All rights reserved.
6 # SPDX-License-Identifier: BSD-2-Clause-Patent
18 # Globals for help information
20 __prog__
= 'DetectNotUsedItem'
21 __version__
= '%s Version %s' % (__prog__
, '0.1')
22 __copyright__
= 'Copyright (c) 2019, Intel Corporation. All rights reserved.'
23 __description__
= "Detect unreferenced PCD and GUID/Protocols/PPIs.\n"
25 SectionList
= ["LibraryClasses", "Guids", "Ppis", "Protocols", "Pcd"]
28 class PROCESS(object):
30 def __init__(self
, DecPath
, InfDirs
):
32 self
.InfPath
= InfDirs
35 def ParserDscFdfInfFile(self
):
37 for File
in self
.SearchbyExt([".dsc", ".fdf", ".inf"]):
38 AllContentList
+= self
.ParseDscFdfInfContent(File
)
41 # Search File by extension name
42 def SearchbyExt(self
, ExtList
):
44 for path
in self
.InfPath
:
45 if type(ExtList
) == type(''):
46 for root
, _
, files
in os
.walk(path
, topdown
=True, followlinks
=False):
47 for filename
in files
:
48 if filename
.endswith(ExtList
):
49 FileList
.append(os
.path
.join(root
, filename
))
50 elif type(ExtList
) == type([]):
51 for root
, _
, files
in os
.walk(path
, topdown
=True, followlinks
=False):
52 for filename
in files
:
54 if filename
.endswith(Ext
):
55 FileList
.append(os
.path
.join(root
, filename
))
58 # Parse DEC file to get Line number and Name
59 # return section name, the Item Name and comments line number
60 def ParseDecContent(self
):
61 SectionRE
= re
.compile(r
'\[(.*)\]')
66 with
open(self
.Dec
, 'r') as F
:
67 for Index
, content
in enumerate(F
):
68 NotComment
= not content
.strip().startswith("#")
69 Section
= SectionRE
.findall(content
)
70 if Section
and NotComment
:
71 Flag
= self
.IsNeedParseSection(Section
[0])
73 Comment_Line
.append(Index
)
75 if content
!= "\n" and content
!= "\r\n":
76 ItemName
[Index
] = content
.split('=')[0].split('|')[0].split('#')[0].strip()
77 Comments
[Index
] = Comment_Line
79 return ItemName
, Comments
81 def IsNeedParseSection(self
, SectionName
):
82 for item
in SectionList
:
83 if item
in SectionName
:
87 # Parse DSC, FDF, INF File, remove comments, return Lines list
88 def ParseDscFdfInfContent(self
, File
):
89 with
open(File
, 'r') as F
:
91 for Index
in range(len(lines
) - 1, -1, -1):
92 if lines
[Index
].strip().startswith("#") or lines
[Index
] == "\n" or lines
[Index
] == "\r\n":
93 lines
.remove(lines
[Index
])
94 elif "#" in lines
[Index
]:
95 lines
[Index
] = lines
[Index
].split("#")[0].strip()
97 lines
[Index
] = lines
[Index
].strip()
100 def DetectNotUsedItem(self
):
102 DecItem
, DecComments
= self
.ParseDecContent()
103 InfDscFdfContent
= self
.ParserDscFdfInfFile()
104 for LineNum
in list(DecItem
.keys()):
105 DecItemName
= DecItem
[LineNum
]
106 Match_reg
= re
.compile("(?<![a-zA-Z0-9_-])%s(?![a-zA-Z0-9_-])" % DecItemName
)
108 for Line
in InfDscFdfContent
:
109 if Match_reg
.search(Line
):
113 NotUsedItem
[LineNum
] = DecItemName
114 self
.Display(NotUsedItem
)
115 return NotUsedItem
, DecComments
117 def Display(self
, UnuseDict
):
118 print("DEC File:\n%s\n%s%s" % (self
.Dec
, "{:<15}".format("Line Number"), "{:<0}".format("Unused Item")))
120 "DEC File:\n%s\n%s%s\n" % (self
.Dec
, "{:<15}".format("Line Number"), "{:<0}".format("Unused Item")))
121 for num
in list(sorted(UnuseDict
.keys())):
122 ItemName
= UnuseDict
[num
]
123 print("%s%s%s" % (" " * 3, "{:<12}".format(num
+ 1), "{:<1}".format(ItemName
)))
124 self
.Log
.append(("%s%s%s\n" % (" " * 3, "{:<12}".format(num
+ 1), "{:<1}".format(ItemName
))))
126 def Clean(self
, UnUseDict
, Comments
):
128 for num
in list(UnUseDict
.keys()):
129 if num
in list(Comments
.keys()):
130 removednum
+= Comments
[num
]
131 with
open(self
.Dec
, 'r') as Dec
:
132 lines
= Dec
.readlines()
134 with
open(self
.Dec
, 'w+') as T
:
135 for linenum
in range(len(lines
)):
136 if linenum
in removednum
:
139 T
.write(lines
[linenum
])
140 print("DEC File has been clean: %s" % (self
.Dec
))
141 except Exception as err
:
147 def mainprocess(self
, Dec
, Dirs
, Isclean
, LogPath
):
149 if not os
.path
.exists(dir):
150 print("Error: Invalid path for '--dirs': %s" % dir)
152 Pa
= PROCESS(Dec
, Dirs
)
153 unuse
, comment
= Pa
.DetectNotUsedItem()
155 Pa
.Clean(unuse
, comment
)
156 self
.Logging(Pa
.Log
, LogPath
)
158 def Logging(self
, content
, LogPath
):
161 if os
.path
.isdir(LogPath
):
162 FilePath
= os
.path
.dirname(LogPath
)
163 if not os
.path
.exists(FilePath
):
164 os
.makedirs(FilePath
)
165 with
open(LogPath
, 'w+') as log
:
168 print("Log save to file: %s" % LogPath
)
169 except Exception as e
:
170 print("Save log Error: %s" % e
)
174 parser
= argparse
.ArgumentParser(prog
=__prog__
,
175 description
=__description__
+ __copyright__
,
176 conflict_handler
='resolve')
177 parser
.add_argument('-i', '--input', metavar
="", dest
='InputDec', help="Input DEC file name.")
178 parser
.add_argument('--dirs', metavar
="", action
='append', dest
='Dirs',
179 help="The package directory. To specify more directories, please repeat this option.")
180 parser
.add_argument('--clean', action
='store_true', default
=False, dest
='Clean',
181 help="Clean the unreferenced items from DEC file.")
182 parser
.add_argument('--log', metavar
="", dest
="Logfile", default
=False,
183 help="Put log in specified file as well as on console.")
184 options
= parser
.parse_args()
186 if not (os
.path
.exists(options
.InputDec
) and options
.InputDec
.endswith(".dec")):
187 print("Error: Invalid DEC file input: %s" % options
.InputDec
)
190 M
.mainprocess(options
.InputDec
, options
.Dirs
, options
.Clean
, options
.Logfile
)
192 print("Error: the following argument is required:'--dirs'.")
194 print("Error: the following argument is required:'-i/--input'.")
197 if __name__
== '__main__':