]>
git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/Workspace/WorkspaceDatabase.py
2 # This file is used to create a database used by build tool
4 # Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
5 # (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
6 # This program and the accompanying materials
7 # are licensed and made available under the terms and conditions of the BSD License
8 # which accompanies this distribution. The full text of the license may be found at
9 # http://opensource.org/licenses/bsd-license.php
11 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 from __future__
import absolute_import
20 from Common
.StringUtils
import *
21 from Common
.DataType
import *
22 from Common
.Misc
import *
25 from .MetaDataTable
import *
26 from .MetaFileTable
import *
27 from .MetaFileParser
import *
29 from Workspace
.DecBuildData
import DecBuildData
30 from Workspace
.DscBuildData
import DscBuildData
31 from Workspace
.InfBuildData
import InfBuildData
35 # This class defined the build database for all modules, packages and platform.
36 # It will call corresponding parser for the given file if it cannot find it in
39 # @param DbPath Path of database file
40 # @param GlobalMacros Global macros used for replacement during file parsing
41 # @prarm RenewDb=False Create new database file if it's already there
43 class WorkspaceDatabase(object):
46 # internal class used for call corresponding file parser and caching the result
47 # to avoid unnecessary re-parsing
49 class BuildObjectFactory(object):
52 ".inf" : MODEL_FILE_INF
,
53 ".dec" : MODEL_FILE_DEC
,
54 ".dsc" : MODEL_FILE_DSC
,
59 MODEL_FILE_INF
: InfParser
,
60 MODEL_FILE_DEC
: DecParser
,
61 MODEL_FILE_DSC
: DscParser
,
64 # convert to xxxBuildData object
66 MODEL_FILE_INF
: InfBuildData
,
67 MODEL_FILE_DEC
: DecBuildData
,
68 MODEL_FILE_DSC
: DscBuildData
,
71 _CACHE_
= {} # (FilePath, Arch) : <object>
74 def __init__(self
, WorkspaceDb
):
75 self
.WorkspaceDb
= WorkspaceDb
77 # key = (FilePath, Arch=None)
78 def __contains__(self
, Key
):
84 return (FilePath
, Arch
) in self
._CACHE
_
86 # key = (FilePath, Arch=None, Target=None, Toochain=None)
87 def __getitem__(self
, Key
):
103 # if it's generated before, just return the cached one
104 Key
= (FilePath
, Arch
, Target
, Toolchain
)
105 if Key
in self
._CACHE
_:
106 return self
._CACHE
_[Key
]
109 BuildObject
= self
.CreateBuildObject(FilePath
, Arch
, Target
, Toolchain
)
110 self
._CACHE
_[Key
] = BuildObject
112 def CreateBuildObject(self
,FilePath
, Arch
, Target
, Toolchain
):
114 if Ext
not in self
._FILE
_TYPE
_:
116 FileType
= self
._FILE
_TYPE
_[Ext
]
117 if FileType
not in self
._GENERATOR
_:
120 # get the parser ready for this file
121 MetaFile
= self
._FILE
_PARSER
_[FileType
](
125 MetaFileStorage(self
.WorkspaceDb
.Cur
, FilePath
, FileType
)
127 # alwasy do post-process, in case of macros change
128 MetaFile
.DoPostProcess()
129 # object the build is based on
130 BuildObject
= self
._GENERATOR
_[FileType
](
140 # placeholder for file format conversion
141 class TransformObjectFactory
:
142 def __init__(self
, WorkspaceDb
):
143 self
.WorkspaceDb
= WorkspaceDb
145 # key = FilePath, Arch
146 def __getitem__(self
, Key
):
149 ## Constructor of WorkspaceDatabase
151 # @param DbPath Path of database file
152 # @param GlobalMacros Global macros used for replacement during file parsing
153 # @prarm RenewDb=False Create new database file if it's already there
155 def __init__(self
, DbPath
, RenewDb
=False):
156 self
._DbClosedFlag
= False
158 DbPath
= os
.path
.normpath(mws
.join(GlobalData
.gWorkspace
, 'Conf', GlobalData
.gDatabasePath
))
160 # don't create necessary path for db in memory
161 if DbPath
!= ':memory:':
162 DbDir
= os
.path
.split(DbPath
)[0]
163 if not os
.path
.exists(DbDir
):
166 # remove db file in case inconsistency between db and file in file system
167 if self
._CheckWhetherDbNeedRenew
(RenewDb
, DbPath
):
170 # create db with optimized parameters
171 self
.Conn
= sqlite3
.connect(DbPath
, isolation_level
='DEFERRED')
172 self
.Conn
.execute("PRAGMA synchronous=OFF")
173 self
.Conn
.execute("PRAGMA temp_store=MEMORY")
174 self
.Conn
.execute("PRAGMA count_changes=OFF")
175 self
.Conn
.execute("PRAGMA cache_size=8192")
176 #self.Conn.execute("PRAGMA page_size=8192")
178 # to avoid non-ascii character conversion issue
179 self
.Conn
.text_factory
= str
180 self
.Cur
= self
.Conn
.cursor()
182 # create table for internal uses
183 self
.TblDataModel
= TableDataModel(self
.Cur
)
184 self
.TblFile
= TableFile(self
.Cur
)
187 # conversion object for build or file format conversion purpose
188 self
.BuildObject
= WorkspaceDatabase
.BuildObjectFactory(self
)
189 self
.TransformObject
= WorkspaceDatabase
.TransformObjectFactory(self
)
191 ## Check whether workspace database need to be renew.
192 # The renew reason maybe:
193 # 1) If user force to renew;
194 # 2) If user do not force renew, and
195 # a) If the time of last modified python source is newer than database file;
196 # b) If the time of last modified frozen executable file is newer than database file;
198 # @param force User force renew database
199 # @param DbPath The absolute path of workspace database file
201 # @return Bool value for whether need renew workspace databse
203 def _CheckWhetherDbNeedRenew (self
, force
, DbPath
):
204 # if database does not exist, we need do nothing
205 if not os
.path
.exists(DbPath
): return False
207 # if user force to renew database, then not check whether database is out of date
208 if force
: return True
211 # Check the time of last modified source file or build.exe
212 # if is newer than time of database, then database need to be re-created.
214 timeOfToolModified
= 0
215 if hasattr(sys
, "frozen"):
216 exePath
= os
.path
.abspath(sys
.executable
)
217 timeOfToolModified
= os
.stat(exePath
).st_mtime
219 curPath
= os
.path
.dirname(__file__
) # curPath is the path of WorkspaceDatabase.py
220 rootPath
= os
.path
.split(curPath
)[0] # rootPath is root path of python source, such as /BaseTools/Source/Python
221 if rootPath
== "" or rootPath
is None:
222 EdkLogger
.verbose("\nFail to find the root path of build.exe or python sources, so can not \
223 determine whether database file is out of date!\n")
225 # walk the root path of source or build's binary to get the time last modified.
227 for root
, dirs
, files
in os
.walk (rootPath
):
229 # bypass source control folder
230 if dir.lower() in [".svn", "_svn", "cvs"]:
234 ext
= os
.path
.splitext(file)[1]
235 if ext
.lower() == ".py": # only check .py files
236 fd
= os
.stat(os
.path
.join(root
, file))
237 if timeOfToolModified
< fd
.st_mtime
:
238 timeOfToolModified
= fd
.st_mtime
239 if timeOfToolModified
> os
.stat(DbPath
).st_mtime
:
240 EdkLogger
.verbose("\nWorkspace database is out of data!")
245 ## Initialize build database
246 def InitDatabase(self
):
247 EdkLogger
.verbose("\nInitialize build database started ...")
252 self
.TblDataModel
.Create(False)
253 self
.TblFile
.Create(False)
256 # Initialize table DataModel
258 self
.TblDataModel
.InitTable()
259 EdkLogger
.verbose("Initialize build database ... DONE!")
263 # @param Table: The instance of the table to be queried
265 def QueryTable(self
, Table
):
271 ## Close entire database
274 # Close the connection and cursor
277 if not self
._DbClosedFlag
:
281 self
._DbClosedFlag
= True
283 ## Summarize all packages in the database
284 def GetPackageList(self
, Platform
, Arch
, TargetName
, ToolChainTag
):
285 self
.Platform
= Platform
287 Pa
= self
.BuildObject
[self
.Platform
, Arch
, TargetName
, ToolChainTag
]
289 # Get Package related to Modules
291 for Module
in Pa
.Modules
:
292 ModuleObj
= self
.BuildObject
[Module
, Arch
, TargetName
, ToolChainTag
]
293 for Package
in ModuleObj
.Packages
:
294 if Package
not in PackageList
:
295 PackageList
.append(Package
)
297 # Get Packages related to Libraries
299 for Lib
in Pa
.LibraryInstances
:
300 LibObj
= self
.BuildObject
[Lib
, Arch
, TargetName
, ToolChainTag
]
301 for Package
in LibObj
.Packages
:
302 if Package
not in PackageList
:
303 PackageList
.append(Package
)
307 ## Summarize all platforms in the database
308 def PlatformList(self
):
310 for PlatformFile
in self
.TblFile
.GetFileList(MODEL_FILE_DSC
):
312 RetVal
.append(self
.BuildObject
[PathClass(PlatformFile
), TAB_COMMON
])
317 def MapPlatform(self
, Dscfile
):
318 Platform
= self
.BuildObject
[PathClass(Dscfile
), TAB_COMMON
]
320 EdkLogger
.error('build', PARSER_ERROR
, "Failed to parser DSC file: %s" % Dscfile
)
325 # This acts like the main() function for the script, unless it is 'import'ed into another
328 if __name__
== '__main__':