summaryrefslogtreecommitdiff
path: root/BaseTools/Source/Python/fpd2dsc/EdkIIWorkspaceGuidsInfo.py
blob: 528dbf3ddb464cc684d0ebb2f5680ea6d7df7179 (plain)
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
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
## @file
# Collects the Guid Information in current workspace.
#
# Copyright (c) 2007, Intel Corporation
# All rights reserved. This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution.  The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#

##
# Import Modules
#
import os
import fnmatch
from Common.EdkIIWorkspace import EdkIIWorkspace
from Common.MigrationUtilities import *

## A class for EdkII work space to resolve Guids
#
# This class inherits from EdkIIWorkspace and collects the Guids information
# in current workspace. The Guids information is important to translate the
# package Guids and recommended library instances Guids to relative file path
# (to workspace directory) in MSA files.
#
class EdkIIWorkspaceGuidsInfo(EdkIIWorkspace):

    ## The classconstructor
    #
    # The constructor initialize workspace directory. It does not collect
    # pakage and module Guids info at initialization; instead, it collects them
    # on the fly.
    #
    # @param  self           The object pointer
    #
    def __init__(self):
        # Initialize parent class.
        EdkIIWorkspace.__init__(self)
        # The internal map from Guid to FilePath.
        self.__GuidToFilePath = {}
        # The internal package directory list.
        self.__PackageDirList = []
        # The internal flag to indicate whether package Guids info has been initialized
        # to avoid re-collection collected.
        self.__PackageGuidInitialized = False
        # The internal flag to indicate whether module Guids info has been initialized
        # to avoid re-collection collected.
        self.__ModuleGuidInitialized = False

    ## Add Guid, Version and FilePath to Guids database
    #
    # Add Guid, Version and FilePath to Guids database. It constructs a map
    # table from Guid, Version to FilePath internally. If also detects possible
    # Guid collision. For now, the version information is simply ignored and
    # Guid value itself acts as master key.
    #
    # @param  self           The object pointer
    # @param  Guid           The Guid Value
    # @param  Version        The version information
    # @param  FilePath       The Guid related file path
    #
    # @retval True           The Guid value is successfully added to map table
    # @retval False          The Guid is an empty string or the map table
    #                        already contains a same Guid
    #
    def __AddGuidToFilePath(self, Guid, Version, FilePath):
        if Guid == "":
            EdkLogger.info("Cannot find Guid in file %s" % FilePath)
            return False
        #Add the Guid value to map table to ensure case insensitive comparison.
        OldFilePath = self.__GuidToFilePath.setdefault(Guid.lower(), FilePath)
        if OldFilePath == FilePath:
            EdkLogger.verbose("File %s has new Guid '%s'" % (FilePath, Guid))
            return True
        else:
            EdkLogger.info("File %s has duplicate Guid with & %s" % (FilePath, OldFilePath))
            return False
        

    ## Gets file information from a module description file
    #
    # Extracts Module Name, File Guid and Version number from INF, MSA and NMSA
    # file. It supports to exact such information from text based INF file or
    # XML based (N)MSA file.
    #
    # @param  self           The object pointer
    # @param  FileName       The input module file name
    #
    # @retval True           This module file represents a new module discovered
    #                        in current workspace
    # @retval False          This module file is not regarded as a valid module
    #                        The File Guid cannot be extracted or the another
    #                        file with the same Guid already exists
    #
    def __GetModuleFileInfo(self, FileName):
        if fnmatch.fnmatch(FileName, "*.inf"):
            TagTuple = ("BASE_NAME", "FILE_GUID", "VERSION_STRING")
            (Name, Guid, Version) = GetTextFileInfo(FileName, TagTuple)
        else :
            XmlTag1 = "ModuleSurfaceArea/MsaHeader/ModuleName"
            XmlTag2 = "ModuleSurfaceArea/MsaHeader/GuidValue"
            XmlTag3 = "ModuleSurfaceArea/MsaHeader/Version"
            TagTuple = (XmlTag1, XmlTag2, XmlTag3)
            (Name, Guid, Version) = GetXmlFileInfo(FileName, TagTuple)

        return self.__AddGuidToFilePath(Guid, Version, FileName)
    
    
    ## Gets file information from a package description file
    #
    # Extracts Package Name, File Guid and Version number from INF, SPD and NSPD
    # file. It supports to exact such information from text based DEC file or
    # XML based (N)SPD file. EDK Compatibility Package is hardcoded to be
    # ignored since no EDKII INF file depends on that package.
    #
    # @param  self           The object pointer
    # @param  FileName       The input package file name
    #
    # @retval True           This package file represents a new package
    #                        discovered in current workspace
    # @retval False          This package is not regarded as a valid package
    #                        The File Guid cannot be extracted or the another
    #                        file with the same Guid already exists
    #
    def __GetPackageFileInfo(self, FileName):
        if fnmatch.fnmatch(FileName, "*.dec"):
            TagTuple = ("PACKAGE_NAME", "PACKAGE_GUID", "PACKAGE_VERSION")
            (Name, Guid, Version) = GetTextFileInfo(FileName, TagTuple)
        else:
            XmlTag1 = "PackageSurfaceArea/SpdHeader/PackageName"
            XmlTag2 = "PackageSurfaceArea/SpdHeader/GuidValue"
            XmlTag3 = "PackageSurfaceArea/SpdHeader/Version"
            TagTuple = (XmlTag1, XmlTag2, XmlTag3)
            (Name, Guid, Version) = GetXmlFileInfo(FileName, TagTuple)
                
        if Name == "EdkCompatibilityPkg":
            # Do not scan EDK compatibitilty package to avoid Guid collision
            # with those in EDK Glue Library.
            EdkLogger.verbose("Bypass EDK Compatibility Pkg")
            return False
        
        return self.__AddGuidToFilePath(Guid, Version, FileName)

    ## Iterate on all package files listed in framework database file
    #
    # Yields all package description files listed in framework database files.
    # The framework database file describes the packages current workspace
    # includes.
    #
    # @param  self           The object pointer
    #
    def __FrameworkDatabasePackageFiles(self):
        XmlFrameworkDb = XmlParseFile(self.WorkspaceFile)
        XmlTag = "FrameworkDatabase/PackageList/Filename"
        for PackageFile in XmlElementList(XmlFrameworkDb, XmlTag):
            yield os.path.join(self.WorkspaceDir, PackageFile)
    
    
    ## Iterate on all package files in current workspace directory
    #
    # Yields all package description files listed in current workspace
    # directory. This happens when no framework database file exists.
    #
    # @param  self           The object pointer
    #
    def __TraverseAllPackageFiles(self):
        for Path, Dirs, Files in os.walk(self.WorkspaceDir):
            # Ignore svn version control directory.
            if ".svn" in Dirs:
                Dirs.remove(".svn")
            if "Build" in Dirs:
                Dirs.remove("Build")
            # Assume priority from high to low: DEC, NSPD, SPD.
            PackageFiles = fnmatch.filter(Files, "*.dec")
            if len(PackageFiles) == 0:
                PackageFiles = fnmatch.filter(Files, "*.nspd")
                if len(PackageFiles) == 0:
                    PackageFiles = fnmatch.filter(Files, "*.spd")

            for File in PackageFiles:
                # Assume no more package decription file in sub-directory.
                del Dirs[:]
                yield os.path.join(Path, File)

    ## Iterate on all module files in current package directory
    #
    # Yields all module description files listed in current package
    # directory.
    #
    # @param  self           The object pointer
    #
    def __TraverseAllModuleFiles(self):
        for PackageDir in self.__PackageDirList:
            for Path, Dirs, Files in os.walk(PackageDir):
                # Ignore svn version control directory.
                if ".svn" in Dirs:
                    Dirs.remove(".svn")
                # Assume priority from high to low: INF, NMSA, MSA.
                ModuleFiles = fnmatch.filter(Files, "*.inf")
                if len(ModuleFiles) == 0:
                    ModuleFiles = fnmatch.filter(Files, "*.nmsa")
                    if len(ModuleFiles) == 0:
                        ModuleFiles = fnmatch.filter(Files, "*.msa")

                for File in ModuleFiles:
                    yield os.path.join(Path, File)

    ## Initialize package Guids info mapping table
    #
    # Collects all package guids map to package decription file path. This
    # function is invokes on demand to avoid unnecessary directory scan.
    #
    # @param  self           The object pointer
    #
    def __InitializePackageGuidInfo(self):
        if self.__PackageGuidInitialized:
            return

        EdkLogger.verbose("Start to collect Package Guids Info.")
   
        WorkspaceFile = os.path.join("Conf", "FrameworkDatabase.db")
        self.WorkspaceFile = os.path.join(self.WorkspaceDir, WorkspaceFile)
        
        # Try to find the frameworkdatabase file to discover package lists
        if os.path.exists(self.WorkspaceFile):
            TraversePackage = self.__FrameworkDatabasePackageFiles
            EdkLogger.verbose("Package list bases on: %s" % self.WorkspaceFile)
        else:
            TraversePackage = self.__TraverseAllPackageFiles
            EdkLogger.verbose("Package list in: %s" % self.WorkspaceDir)

        for FileName in TraversePackage():
            if self.__GetPackageFileInfo(FileName):
                PackageDir = os.path.dirname(FileName)
                EdkLogger.verbose("Find new package directory %s" % PackageDir)
                self.__PackageDirList.append(PackageDir)
                
        self.__PackageGuidInitialized = True

    ## Initialize module Guids info mapping table
    #
    # Collects all module guids map to module decription file path. This
    # function is invokes on demand to avoid unnecessary directory scan.
    #
    # @param  self           The object pointer
    #
    def __InitializeModuleGuidInfo(self):
        if self.__ModuleGuidInitialized:
            return
        EdkLogger.verbose("Start to collect Module Guids Info")
        
        self.__InitializePackageGuidInfo()
        for FileName in self.__TraverseAllModuleFiles():
            if self.__GetModuleFileInfo(FileName):
                EdkLogger.verbose("Find new module %s" % FileName)
                
        self.__ModuleGuidInitialized = True

    ## Get Package file path by Package Guid and Version
    #
    # Translates the Package Guid and Version to a file path relative
    # to workspace directory. If no package in current workspace match the
    # input Guid, an empty file path is returned. For now, the version
    # value is simply ignored.
    #
    # @param  self           The object pointer
    # @param  Guid           The Package Guid value to look for
    # @param  Version        The Package Version value to look for
    #
    def ResolvePackageFilePath(self, Guid, Version = ""):
        self.__InitializePackageGuidInfo()
        
        EdkLogger.verbose("Resolve Package Guid '%s'" % Guid)
        FileName = self.__GuidToFilePath.get(Guid.lower(), "")
        if FileName == "":
            EdkLogger.info("Cannot resolve Package Guid '%s'" % Guid)
        else:
            FileName = self.WorkspaceRelativePath(FileName)
            FileName = os.path.splitext(FileName)[0] + ".dec"
            FileName = FileName.replace("\\", "/")
        return FileName

    ## Get Module file path by Module Guid and Version
    #
    # Translates the Module Guid and Version to a file path relative
    # to workspace directory. If no module in current workspace match the
    # input Guid, an empty file path is returned. For now, the version
    # value is simply ignored.
    #
    # @param  self           The object pointer
    # @param  Guid           The Module Guid value to look for
    # @param  Version        The Module Version value to look for
    #
    def ResolveModuleFilePath(self, Guid, Version = ""):
        self.__InitializeModuleGuidInfo()
        
        EdkLogger.verbose("Resolve Module Guid '%s'" % Guid)
        FileName = self.__GuidToFilePath.get(Guid.lower(), "")
        if FileName == "":
            EdkLogger.info("Cannot resolve Module Guid '%s'" % Guid)
        else:
            FileName = self.WorkspaceRelativePath(FileName)
            FileName = os.path.splitext(FileName)[0] + ".inf"
            FileName = FileName.replace("\\", "/")
        return FileName

# A global class object of EdkIIWorkspaceGuidsInfo for external reference.
gEdkIIWorkspaceGuidsInfo = EdkIIWorkspaceGuidsInfo()

# This acts like the main() function for the script, unless it is 'import'ed
# into another script.
if __name__ == '__main__':
    # Test the translation of package Guid.
#    MdePkgGuid = "1E73767F-8F52-4603-AEB4-F29B510B6766"
#    OldMdePkgGuid = "5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"
#    print gEdkIIWorkspaceGuidsInfo.ResolveModuleFilePath(MdePkgGuid)
#    print gEdkIIWorkspaceGuidsInfo.ResolveModuleFilePath(OldMdePkgGuid)
    
    # Test the translation of module Guid.
#    UefiLibGuid = "3a004ba5-efe0-4a61-9f1a-267a46ae5ba9"
#    UefiDriverModelLibGuid = "52af22ae-9901-4484-8cdc-622dd5838b09"
#    print gEdkIIWorkspaceGuidsInfo.ResolvePlatformFilePath(UefiLibGuid)
#    print gEdkIIWorkspaceGuidsInfo.ResolvePlatformFilePath(UefiDriverModelLibGuid)
    pass