]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/Workspace/WorkspaceDatabase.py
BaseTool: Filter out unused structure pcds
[mirror_edk2.git] / BaseTools / Source / Python / Workspace / WorkspaceDatabase.py
CommitLineData
52302d4d
LG
1## @file\r
2# This file is used to create a database used by build tool\r
3#\r
b9a6d9d7 4# Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>\r
77177984 5# (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
40d841f6 6# This program and the accompanying materials\r
52302d4d
LG
7# are licensed and made available under the terms and conditions of the BSD License\r
8# which accompanies this distribution. The full text of the license may be found at\r
9# http://opensource.org/licenses/bsd-license.php\r
10#\r
11# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13#\r
14\r
15##\r
16# Import Modules\r
17#\r
1ccc4d89 18from __future__ import absolute_import\r
52302d4d 19import sqlite3\r
5a57246e 20from Common.StringUtils import *\r
52302d4d
LG
21from Common.DataType import *\r
22from Common.Misc import *\r
23from types import *\r
24\r
1100bc5a
GL
25from .MetaDataTable import *\r
26from .MetaFileTable import *\r
27from .MetaFileParser import *\r
52302d4d 28\r
ae7b6df8
LG
29from Workspace.DecBuildData import DecBuildData\r
30from Workspace.DscBuildData import DscBuildData\r
31from Workspace.InfBuildData import InfBuildData\r
52302d4d
LG
32\r
33## Database\r
34#\r
e56468c0 35# This class defined the build database for all modules, packages and platform.\r
52302d4d
LG
36# It will call corresponding parser for the given file if it cannot find it in\r
37# the database.\r
38#\r
39# @param DbPath Path of database file\r
40# @param GlobalMacros Global macros used for replacement during file parsing\r
41# @prarm RenewDb=False Create new database file if it's already there\r
42#\r
43class WorkspaceDatabase(object):\r
52302d4d 44\r
52302d4d
LG
45 #\r
46 # internal class used for call corresponding file parser and caching the result\r
47 # to avoid unnecessary re-parsing\r
48 #\r
49 class BuildObjectFactory(object):\r
0d2711a6 50\r
52302d4d
LG
51 _FILE_TYPE_ = {\r
52 ".inf" : MODEL_FILE_INF,\r
53 ".dec" : MODEL_FILE_DEC,\r
54 ".dsc" : MODEL_FILE_DSC,\r
0d2711a6
LG
55 }\r
56\r
57 # file parser\r
58 _FILE_PARSER_ = {\r
59 MODEL_FILE_INF : InfParser,\r
60 MODEL_FILE_DEC : DecParser,\r
61 MODEL_FILE_DSC : DscParser,\r
52302d4d
LG
62 }\r
63\r
64 # convert to xxxBuildData object\r
65 _GENERATOR_ = {\r
66 MODEL_FILE_INF : InfBuildData,\r
67 MODEL_FILE_DEC : DecBuildData,\r
68 MODEL_FILE_DSC : DscBuildData,\r
52302d4d
LG
69 }\r
70\r
71 _CACHE_ = {} # (FilePath, Arch) : <object>\r
72\r
73 # constructor\r
74 def __init__(self, WorkspaceDb):\r
75 self.WorkspaceDb = WorkspaceDb\r
76\r
0d2711a6 77 # key = (FilePath, Arch=None)\r
52302d4d
LG
78 def __contains__(self, Key):\r
79 FilePath = Key[0]\r
52302d4d
LG
80 if len(Key) > 1:\r
81 Arch = Key[1]\r
0d2711a6
LG
82 else:\r
83 Arch = None\r
52302d4d
LG
84 return (FilePath, Arch) in self._CACHE_\r
85\r
0d2711a6 86 # key = (FilePath, Arch=None, Target=None, Toochain=None)\r
52302d4d
LG
87 def __getitem__(self, Key):\r
88 FilePath = Key[0]\r
0d2711a6
LG
89 KeyLength = len(Key)\r
90 if KeyLength > 1:\r
52302d4d 91 Arch = Key[1]\r
0d2711a6
LG
92 else:\r
93 Arch = None\r
94 if KeyLength > 2:\r
95 Target = Key[2]\r
96 else:\r
97 Target = None\r
98 if KeyLength > 3:\r
99 Toolchain = Key[3]\r
100 else:\r
101 Toolchain = None\r
52302d4d
LG
102\r
103 # if it's generated before, just return the cached one\r
0d2711a6 104 Key = (FilePath, Arch, Target, Toolchain)\r
52302d4d
LG
105 if Key in self._CACHE_:\r
106 return self._CACHE_[Key]\r
107\r
108 # check file type\r
34e733f2
FB
109 BuildObject = self.CreateBuildObject(FilePath, Arch, Target, Toolchain)\r
110 self._CACHE_[Key] = BuildObject\r
111 return BuildObject\r
112 def CreateBuildObject(self,FilePath, Arch, Target, Toolchain):\r
0d2711a6 113 Ext = FilePath.Type\r
52302d4d
LG
114 if Ext not in self._FILE_TYPE_:\r
115 return None\r
116 FileType = self._FILE_TYPE_[Ext]\r
117 if FileType not in self._GENERATOR_:\r
118 return None\r
119\r
0d2711a6
LG
120 # get the parser ready for this file\r
121 MetaFile = self._FILE_PARSER_[FileType](\r
f7496d71
LG
122 FilePath,\r
123 FileType,\r
cdd1b5e5 124 Arch,\r
0d2711a6
LG
125 MetaFileStorage(self.WorkspaceDb.Cur, FilePath, FileType)\r
126 )\r
127 # alwasy do post-process, in case of macros change\r
128 MetaFile.DoPostProcess()\r
129 # object the build is based on\r
52302d4d
LG
130 BuildObject = self._GENERATOR_[FileType](\r
131 FilePath,\r
132 MetaFile,\r
133 self,\r
134 Arch,\r
0d2711a6
LG
135 Target,\r
136 Toolchain\r
52302d4d 137 )\r
52302d4d
LG
138 return BuildObject\r
139\r
140 # placeholder for file format conversion\r
141 class TransformObjectFactory:\r
142 def __init__(self, WorkspaceDb):\r
143 self.WorkspaceDb = WorkspaceDb\r
144\r
145 # key = FilePath, Arch\r
146 def __getitem__(self, Key):\r
147 pass\r
148\r
149 ## Constructor of WorkspaceDatabase\r
150 #\r
151 # @param DbPath Path of database file\r
152 # @param GlobalMacros Global macros used for replacement during file parsing\r
153 # @prarm RenewDb=False Create new database file if it's already there\r
154 #\r
0d2711a6 155 def __init__(self, DbPath, RenewDb=False):\r
4234283c 156 self._DbClosedFlag = False\r
0d2711a6 157 if not DbPath:\r
05cc51ad 158 DbPath = os.path.normpath(mws.join(GlobalData.gWorkspace, 'Conf', GlobalData.gDatabasePath))\r
52302d4d
LG
159\r
160 # don't create necessary path for db in memory\r
161 if DbPath != ':memory:':\r
162 DbDir = os.path.split(DbPath)[0]\r
163 if not os.path.exists(DbDir):\r
164 os.makedirs(DbDir)\r
165\r
166 # remove db file in case inconsistency between db and file in file system\r
167 if self._CheckWhetherDbNeedRenew(RenewDb, DbPath):\r
168 os.remove(DbPath)\r
f7496d71 169\r
52302d4d 170 # create db with optimized parameters\r
1ccc4d89 171 self.Conn = sqlite3.connect(DbPath, isolation_level='DEFERRED')\r
52302d4d
LG
172 self.Conn.execute("PRAGMA synchronous=OFF")\r
173 self.Conn.execute("PRAGMA temp_store=MEMORY")\r
174 self.Conn.execute("PRAGMA count_changes=OFF")\r
175 self.Conn.execute("PRAGMA cache_size=8192")\r
176 #self.Conn.execute("PRAGMA page_size=8192")\r
177\r
178 # to avoid non-ascii character conversion issue\r
179 self.Conn.text_factory = str\r
180 self.Cur = self.Conn.cursor()\r
181\r
182 # create table for internal uses\r
183 self.TblDataModel = TableDataModel(self.Cur)\r
184 self.TblFile = TableFile(self.Cur)\r
0d2711a6 185 self.Platform = None\r
52302d4d
LG
186\r
187 # conversion object for build or file format conversion purpose\r
188 self.BuildObject = WorkspaceDatabase.BuildObjectFactory(self)\r
189 self.TransformObject = WorkspaceDatabase.TransformObjectFactory(self)\r
190\r
191 ## Check whether workspace database need to be renew.\r
192 # The renew reason maybe:\r
193 # 1) If user force to renew;\r
194 # 2) If user do not force renew, and\r
195 # a) If the time of last modified python source is newer than database file;\r
196 # b) If the time of last modified frozen executable file is newer than database file;\r
197 #\r
198 # @param force User force renew database\r
199 # @param DbPath The absolute path of workspace database file\r
200 #\r
201 # @return Bool value for whether need renew workspace databse\r
202 #\r
203 def _CheckWhetherDbNeedRenew (self, force, DbPath):\r
52302d4d
LG
204 # if database does not exist, we need do nothing\r
205 if not os.path.exists(DbPath): return False\r
f7496d71 206\r
52302d4d
LG
207 # if user force to renew database, then not check whether database is out of date\r
208 if force: return True\r
f7496d71
LG
209\r
210 #\r
52302d4d
LG
211 # Check the time of last modified source file or build.exe\r
212 # if is newer than time of database, then database need to be re-created.\r
213 #\r
214 timeOfToolModified = 0\r
215 if hasattr(sys, "frozen"):\r
216 exePath = os.path.abspath(sys.executable)\r
217 timeOfToolModified = os.stat(exePath).st_mtime\r
218 else:\r
219 curPath = os.path.dirname(__file__) # curPath is the path of WorkspaceDatabase.py\r
220 rootPath = os.path.split(curPath)[0] # rootPath is root path of python source, such as /BaseTools/Source/Python\r
4231a819 221 if rootPath == "" or rootPath is None:\r
52302d4d
LG
222 EdkLogger.verbose("\nFail to find the root path of build.exe or python sources, so can not \\r
223determine whether database file is out of date!\n")\r
f7496d71 224\r
52302d4d 225 # walk the root path of source or build's binary to get the time last modified.\r
f7496d71 226\r
52302d4d
LG
227 for root, dirs, files in os.walk (rootPath):\r
228 for dir in dirs:\r
f7496d71 229 # bypass source control folder\r
52302d4d
LG
230 if dir.lower() in [".svn", "_svn", "cvs"]:\r
231 dirs.remove(dir)\r
f7496d71 232\r
52302d4d
LG
233 for file in files:\r
234 ext = os.path.splitext(file)[1]\r
235 if ext.lower() == ".py": # only check .py files\r
236 fd = os.stat(os.path.join(root, file))\r
237 if timeOfToolModified < fd.st_mtime:\r
238 timeOfToolModified = fd.st_mtime\r
239 if timeOfToolModified > os.stat(DbPath).st_mtime:\r
240 EdkLogger.verbose("\nWorkspace database is out of data!")\r
241 return True\r
f7496d71 242\r
52302d4d 243 return False\r
f7496d71 244\r
52302d4d
LG
245 ## Initialize build database\r
246 def InitDatabase(self):\r
247 EdkLogger.verbose("\nInitialize build database started ...")\r
248\r
249 #\r
250 # Create new tables\r
251 #\r
252 self.TblDataModel.Create(False)\r
253 self.TblFile.Create(False)\r
254\r
255 #\r
256 # Initialize table DataModel\r
257 #\r
258 self.TblDataModel.InitTable()\r
259 EdkLogger.verbose("Initialize build database ... DONE!")\r
260\r
261 ## Query a table\r
262 #\r
263 # @param Table: The instance of the table to be queried\r
264 #\r
265 def QueryTable(self, Table):\r
266 Table.Query()\r
267\r
0d2711a6
LG
268 def __del__(self):\r
269 self.Close()\r
270\r
52302d4d
LG
271 ## Close entire database\r
272 #\r
273 # Commit all first\r
274 # Close the connection and cursor\r
275 #\r
276 def Close(self):\r
4234283c
LG
277 if not self._DbClosedFlag:\r
278 self.Conn.commit()\r
279 self.Cur.close()\r
280 self.Conn.close()\r
281 self._DbClosedFlag = True\r
52302d4d 282\r
52302d4d 283 ## Summarize all packages in the database\r
0d2711a6
LG
284 def GetPackageList(self, Platform, Arch, TargetName, ToolChainTag):\r
285 self.Platform = Platform\r
47fea6af 286 PackageList = []\r
b9a6d9d7 287 Pa = self.BuildObject[self.Platform, Arch, TargetName, ToolChainTag]\r
0d2711a6
LG
288 #\r
289 # Get Package related to Modules\r
290 #\r
291 for Module in Pa.Modules:\r
292 ModuleObj = self.BuildObject[Module, Arch, TargetName, ToolChainTag]\r
293 for Package in ModuleObj.Packages:\r
52302d4d
LG
294 if Package not in PackageList:\r
295 PackageList.append(Package)\r
0d2711a6
LG
296 #\r
297 # Get Packages related to Libraries\r
298 #\r
299 for Lib in Pa.LibraryInstances:\r
300 LibObj = self.BuildObject[Lib, Arch, TargetName, ToolChainTag]\r
301 for Package in LibObj.Packages:\r
302 if Package not in PackageList:\r
47fea6af
YZ
303 PackageList.append(Package)\r
304\r
52302d4d
LG
305 return PackageList\r
306\r
307 ## Summarize all platforms in the database\r
71cac3f7
CJ
308 def PlatformList(self):\r
309 RetVal = []\r
52302d4d
LG
310 for PlatformFile in self.TblFile.GetFileList(MODEL_FILE_DSC):\r
311 try:\r
71cac3f7 312 RetVal.append(self.BuildObject[PathClass(PlatformFile), TAB_COMMON])\r
52302d4d 313 except:\r
71cac3f7
CJ
314 pass\r
315 return RetVal\r
52302d4d 316\r
71cac3f7 317 def MapPlatform(self, Dscfile):\r
55c84777 318 Platform = self.BuildObject[PathClass(Dscfile), TAB_COMMON]\r
4231a819 319 if Platform is None:\r
d429fcd0 320 EdkLogger.error('build', PARSER_ERROR, "Failed to parser DSC file: %s" % Dscfile)\r
f0dc69e6
YZ
321 return Platform\r
322\r
52302d4d
LG
323##\r
324#\r
325# This acts like the main() function for the script, unless it is 'import'ed into another\r
326# script.\r
327#\r
328if __name__ == '__main__':\r
329 pass\r
330\r