1## @file
2# This file is used to create/update/query/erase a meta file table
3#
4# Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR>
5# This program and the accompanying materials
6# are licensed and made available under the terms and conditions of the BSD License
7# which accompanies this distribution.  The full text of the license may be found at
8# http://opensource.org/licenses/bsd-license.php
9#
10# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12#
13
14##
15# Import Modules
16#
17import uuid
18
19import Common.EdkLogger as EdkLogger
20from Common.BuildToolError import FORMAT_INVALID
21
22from MetaDataTable import Table, TableFile
23from MetaDataTable import ConvertToSqlString
24from CommonDataClass.DataClass import MODEL_FILE_DSC, MODEL_FILE_DEC, MODEL_FILE_INF, \
25                                      MODEL_FILE_OTHERS
26
27class MetaFileTable(Table):
28    # TRICK: use file ID as the part before '.'
29    _ID_STEP_ = 0.00000001
30    _ID_MAX_ = 0.99999999
31
32    ## Constructor
33    def __init__(self, Cursor, MetaFile, FileType, Temporary):
34        self.MetaFile = MetaFile
35
36        self._FileIndexTable = TableFile(Cursor)
37        self._FileIndexTable.Create(False)
38
39        FileId = self._FileIndexTable.GetFileId(MetaFile)
40        if not FileId:
41            FileId = self._FileIndexTable.InsertFile(MetaFile, FileType)
42
43        if Temporary:
44            TableName = "_%s_%s_%s" % (FileType, FileId, uuid.uuid4().hex)
45        else:
46            TableName = "_%s_%s" % (FileType, FileId)
47
48        #Table.__init__(self, Cursor, TableName, FileId, False)
49        Table.__init__(self, Cursor, TableName, FileId, Temporary)
50        self.Create(not self.IsIntegrity())
51
52    def IsIntegrity(self):
53        try:
54            TimeStamp = self.MetaFile.TimeStamp
55            Result = self.Cur.execute("select ID from %s where ID<0" % (self.Table)).fetchall()
56            if not Result:
57                # update the timestamp in database
58                self._FileIndexTable.SetFileTimeStamp(self.IdBase, TimeStamp)
59                return False
60
61            if TimeStamp != self._FileIndexTable.GetFileTimeStamp(self.IdBase):
62                # update the timestamp in database
63                self._FileIndexTable.SetFileTimeStamp(self.IdBase, TimeStamp)
64                return False
65        except Exception, Exc:
66            EdkLogger.debug(EdkLogger.DEBUG_5, str(Exc))
67            return False
68        return True
69
70## Python class representation of table storing module data
71class ModuleTable(MetaFileTable):
72    _ID_STEP_ = 0.00000001
73    _ID_MAX_  = 0.99999999
74    _COLUMN_ = '''
75        ID REAL PRIMARY KEY,
76        Model INTEGER NOT NULL,
77        Value1 TEXT NOT NULL,
78        Value2 TEXT,
79        Value3 TEXT,
80        Scope1 TEXT,
81        Scope2 TEXT,
82        BelongsToItem REAL NOT NULL,
83        StartLine INTEGER NOT NULL,
84        StartColumn INTEGER NOT NULL,
85        EndLine INTEGER NOT NULL,
86        EndColumn INTEGER NOT NULL,
87        Enabled INTEGER DEFAULT 0
88        '''
89    # used as table end flag, in case the changes to database is not committed to db file
90    _DUMMY_ = "-1, -1, '====', '====', '====', '====', '====', -1, -1, -1, -1, -1, -1"
91
92    ## Constructor
93    def __init__(self, Cursor, MetaFile, Temporary):
94        MetaFileTable.__init__(self, Cursor, MetaFile, MODEL_FILE_INF, Temporary)
95
96    ## Insert a record into table Inf
97    #
98    # @param Model:          Model of a Inf item
99    # @param Value1:         Value1 of a Inf item
100    # @param Value2:         Value2 of a Inf item
101    # @param Value3:         Value3 of a Inf item
102    # @param Scope1:         Arch of a Inf item
103    # @param Scope2          Platform os a Inf item
104    # @param BelongsToItem:  The item belongs to which another item
105    # @param StartLine:      StartLine of a Inf item
106    # @param StartColumn:    StartColumn of a Inf item
107    # @param EndLine:        EndLine of a Inf item
108    # @param EndColumn:      EndColumn of a Inf item
109    # @param Enabled:        If this item enabled
110    #
111    def Insert(self, Model, Value1, Value2, Value3, Scope1='COMMON', Scope2='COMMON',
112               BelongsToItem=-1, StartLine=-1, StartColumn=-1, EndLine=-1, EndColumn=-1, Enabled=0):
113        (Value1, Value2, Value3, Scope1, Scope2) = ConvertToSqlString((Value1, Value2, Value3, Scope1, Scope2))
114        return Table.Insert(
115                        self,
116                        Model,
117                        Value1,
118                        Value2,
119                        Value3,
120                        Scope1,
121                        Scope2,
122                        BelongsToItem,
123                        StartLine,
124                        StartColumn,
125                        EndLine,
126                        EndColumn,
127                        Enabled
128                        )
129
130    ## Query table
131    #
132    # @param    Model:      The Model of Record
133    # @param    Arch:       The Arch attribute of Record
134    # @param    Platform    The Platform attribute of Record
135    #
136    # @retval:       A recordSet of all found records
137    #
138    def Query(self, Model, Arch=None, Platform=None, BelongsToItem=None):
139        ConditionString = "Model=%s AND Enabled>=0" % Model
140        ValueString = "Value1,Value2,Value3,Scope1,Scope2,ID,StartLine"
141
142        if Arch != None and Arch != 'COMMON':
143            ConditionString += " AND (Scope1='%s' OR Scope1='COMMON')" % Arch
144        if Platform != None and Platform != 'COMMON':
145            ConditionString += " AND (Scope2='%s' OR Scope2='COMMON' OR Scope2='DEFAULT')" % Platform
146        if BelongsToItem != None:
147            ConditionString += " AND BelongsToItem=%s" % BelongsToItem
148
149        SqlCommand = "SELECT %s FROM %s WHERE %s" % (ValueString, self.Table, ConditionString)
150        return self.Exec(SqlCommand)
151
152## Python class representation of table storing package data
153class PackageTable(MetaFileTable):
154    _COLUMN_ = '''
155        ID REAL PRIMARY KEY,
156        Model INTEGER NOT NULL,
157        Value1 TEXT NOT NULL,
158        Value2 TEXT,
159        Value3 TEXT,
160        Scope1 TEXT,
161        Scope2 TEXT,
162        BelongsToItem REAL NOT NULL,
163        StartLine INTEGER NOT NULL,
164        StartColumn INTEGER NOT NULL,
165        EndLine INTEGER NOT NULL,
166        EndColumn INTEGER NOT NULL,
167        Enabled INTEGER DEFAULT 0
168        '''
169    # used as table end flag, in case the changes to database is not committed to db file
170    _DUMMY_ = "-1, -1, '====', '====', '====', '====', '====', -1, -1, -1, -1, -1, -1"
171
172    ## Constructor
173    def __init__(self, Cursor, MetaFile, Temporary):
174        MetaFileTable.__init__(self, Cursor, MetaFile, MODEL_FILE_DEC, Temporary)
175
176    ## Insert table
177    #
178    # Insert a record into table Dec
179    #
180    # @param Model:          Model of a Dec item
181    # @param Value1:         Value1 of a Dec item
182    # @param Value2:         Value2 of a Dec item
183    # @param Value3:         Value3 of a Dec item
184    # @param Scope1:         Arch of a Dec item
185    # @param Scope2:         Module type of a Dec item
186    # @param BelongsToItem:  The item belongs to which another item
187    # @param StartLine:      StartLine of a Dec item
188    # @param StartColumn:    StartColumn of a Dec item
189    # @param EndLine:        EndLine of a Dec item
190    # @param EndColumn:      EndColumn of a Dec item
191    # @param Enabled:        If this item enabled
192    #
193    def Insert(self, Model, Value1, Value2, Value3, Scope1='COMMON', Scope2='COMMON',
194               BelongsToItem=-1, StartLine=-1, StartColumn=-1, EndLine=-1, EndColumn=-1, Enabled=0):
195        (Value1, Value2, Value3, Scope1, Scope2) = ConvertToSqlString((Value1, Value2, Value3, Scope1, Scope2))
196        return Table.Insert(
197                        self,
198                        Model,
199                        Value1,
200                        Value2,
201                        Value3,
202                        Scope1,
203                        Scope2,
204                        BelongsToItem,
205                        StartLine,
206                        StartColumn,
207                        EndLine,
208                        EndColumn,
209                        Enabled
210                        )
211
212    ## Query table
213    #
214    # @param    Model:  The Model of Record
215    # @param    Arch:   The Arch attribute of Record
216    #
217    # @retval:       A recordSet of all found records
218    #
219    def Query(self, Model, Arch=None):
220        ConditionString = "Model=%s AND Enabled>=0" % Model
221        ValueString = "Value1,Value2,Value3,Scope1,ID,StartLine"
222
223        if Arch != None and Arch != 'COMMON':
224            ConditionString += " AND (Scope1='%s' OR Scope1='COMMON')" % Arch
225
226        SqlCommand = "SELECT %s FROM %s WHERE %s" % (ValueString, self.Table, ConditionString)
227        return self.Exec(SqlCommand)
228
229    def GetValidExpression(self, TokenSpaceGuid, PcdCName):
230        SqlCommand = "select Value1,StartLine from %s WHERE Value2='%s' and Value3='%s'" % (self.Table, TokenSpaceGuid, PcdCName)
231        self.Cur.execute(SqlCommand)
232        validateranges = []
233        validlists = []
234        expressions = []
235        try:
236            for row in self.Cur:
237                comment = row[0]
238
239                LineNum = row[1]
240                comment = comment.strip("#")
241                comment = comment.strip()
242                oricomment = comment
243                if comment.startswith("@ValidRange"):
244                    comment = comment.replace("@ValidRange", "", 1)
245                    validateranges.append(comment.split("|")[1].strip())
246                if comment.startswith("@ValidList"):
247                    comment = comment.replace("@ValidList", "", 1)
248                    validlists.append(comment.split("|")[1].strip())
249                if comment.startswith("@Expression"):
250                    comment = comment.replace("@Expression", "", 1)
251                    expressions.append(comment.split("|")[1].strip())
252        except Exception, Exc:
253            ValidType = ""
254            if oricomment.startswith("@ValidRange"):
255                ValidType = "@ValidRange"
256            if oricomment.startswith("@ValidList"):
257                ValidType = "@ValidList"
258            if oricomment.startswith("@Expression"):
259                ValidType = "@Expression"
260            EdkLogger.error('Parser', FORMAT_INVALID, "The syntax for %s of PCD %s.%s is incorrect" % (ValidType,TokenSpaceGuid, PcdCName),
261                            ExtraData=oricomment,File=self.MetaFile, Line=LineNum)
262            return set(), set(), set()
263        return set(validateranges), set(validlists), set(expressions)
264## Python class representation of table storing platform data
265class PlatformTable(MetaFileTable):
266    _COLUMN_ = '''
267        ID REAL PRIMARY KEY,
268        Model INTEGER NOT NULL,
269        Value1 TEXT NOT NULL,
270        Value2 TEXT,
271        Value3 TEXT,
272        Scope1 TEXT,
273        Scope2 TEXT,
274        BelongsToItem REAL NOT NULL,
275        FromItem REAL NOT NULL,
276        StartLine INTEGER NOT NULL,
277        StartColumn INTEGER NOT NULL,
278        EndLine INTEGER NOT NULL,
279        EndColumn INTEGER NOT NULL,
280        Enabled INTEGER DEFAULT 0
281        '''
282    # used as table end flag, in case the changes to database is not committed to db file
283    _DUMMY_ = "-1, -1, '====', '====', '====', '====', '====', -1, -1, -1, -1, -1, -1, -1"
284
285    ## Constructor
286    def __init__(self, Cursor, MetaFile, Temporary):
287        MetaFileTable.__init__(self, Cursor, MetaFile, MODEL_FILE_DSC, Temporary)
288
289    ## Insert table
290    #
291    # Insert a record into table Dsc
292    #
293    # @param Model:          Model of a Dsc item
294    # @param Value1:         Value1 of a Dsc item
295    # @param Value2:         Value2 of a Dsc item
296    # @param Value3:         Value3 of a Dsc item
297    # @param Scope1:         Arch of a Dsc item
298    # @param Scope2:         Module type of a Dsc item
299    # @param BelongsToItem:  The item belongs to which another item
300    # @param FromItem:       The item belongs to which dsc file
301    # @param StartLine:      StartLine of a Dsc item
302    # @param StartColumn:    StartColumn of a Dsc item
303    # @param EndLine:        EndLine of a Dsc item
304    # @param EndColumn:      EndColumn of a Dsc item
305    # @param Enabled:        If this item enabled
306    #
307    def Insert(self, Model, Value1, Value2, Value3, Scope1='COMMON', Scope2='COMMON', BelongsToItem=-1,
308               FromItem=-1, StartLine=-1, StartColumn=-1, EndLine=-1, EndColumn=-1, Enabled=1):
309        (Value1, Value2, Value3, Scope1, Scope2) = ConvertToSqlString((Value1, Value2, Value3, Scope1, Scope2))
310        return Table.Insert(
311                        self,
312                        Model,
313                        Value1,
314                        Value2,
315                        Value3,
316                        Scope1,
317                        Scope2,
318                        BelongsToItem,
319                        FromItem,
320                        StartLine,
321                        StartColumn,
322                        EndLine,
323                        EndColumn,
324                        Enabled
325                        )
326
327    ## Query table
328    #
329    # @param Model:          The Model of Record
330    # @param Scope1:         Arch of a Dsc item
331    # @param Scope2:         Module type of a Dsc item
332    # @param BelongsToItem:  The item belongs to which another item
333    # @param FromItem:       The item belongs to which dsc file
334    #
335    # @retval:       A recordSet of all found records
336    #
337    def Query(self, Model, Scope1=None, Scope2=None, BelongsToItem=None, FromItem=None):
338        ConditionString = "Model=%s AND Enabled>0" % Model
339        ValueString = "Value1,Value2,Value3,Scope1,Scope2,ID,StartLine"
340
341        if Scope1 != None and Scope1 != 'COMMON':
342            ConditionString += " AND (Scope1='%s' OR Scope1='COMMON')" % Scope1
343        if Scope2 != None and Scope2 != 'COMMON':
344            ConditionString += " AND (Scope2='%s' OR Scope2='COMMON' OR Scope2='DEFAULT')" % Scope2
345
346        if BelongsToItem != None:
347            ConditionString += " AND BelongsToItem=%s" % BelongsToItem
348        else:
349            ConditionString += " AND BelongsToItem<0"
350
351        if FromItem != None:
352            ConditionString += " AND FromItem=%s" % FromItem
353
354        SqlCommand = "SELECT %s FROM %s WHERE %s" % (ValueString, self.Table, ConditionString)
355        return self.Exec(SqlCommand)
356
357## Factory class to produce different storage for different type of meta-file
358class MetaFileStorage(object):
359    _FILE_TABLE_ = {
360        MODEL_FILE_INF      :   ModuleTable,
361        MODEL_FILE_DEC      :   PackageTable,
362        MODEL_FILE_DSC      :   PlatformTable,
363        MODEL_FILE_OTHERS   :   MetaFileTable,
364    }
365
366    _FILE_TYPE_ = {
367        ".inf"  : MODEL_FILE_INF,
368        ".dec"  : MODEL_FILE_DEC,
369        ".dsc"  : MODEL_FILE_DSC,
370    }
371
372    ## Constructor
373    def __new__(Class, Cursor, MetaFile, FileType=None, Temporary=False):
374        # no type given, try to find one
375        if not FileType:
376            if MetaFile.Type in self._FILE_TYPE_:
377                FileType = Class._FILE_TYPE_[MetaFile.Type]
378            else:
379                FileType = MODEL_FILE_OTHERS
380
381        # don't pass the type around if it's well known
382        if FileType == MODEL_FILE_OTHERS:
383            Args = (Cursor, MetaFile, FileType, Temporary)
384        else:
385            Args = (Cursor, MetaFile, Temporary)
386
387        # create the storage object and return it to caller
388        return Class._FILE_TABLE_[FileType](*Args)
389
390