forked from mirrors/gecko-dev
356 lines
9.6 KiB
Python
Executable file
356 lines
9.6 KiB
Python
Executable file
#!/usr/bin/env python
|
|
# Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
"""
|
|
IDLRelease for PPAPI
|
|
|
|
This file defines the behavior of the AST namespace which allows for resolving
|
|
a symbol as one or more AST nodes given a Release or range of Releases.
|
|
"""
|
|
|
|
import sys
|
|
|
|
from idl_log import ErrOut, InfoOut, WarnOut
|
|
from idl_option import GetOption, Option, ParseOptions
|
|
|
|
Option('release_debug', 'Debug Release data')
|
|
Option('wgap', 'Ignore Release gap warning')
|
|
|
|
|
|
#
|
|
# Module level functions and data used for testing.
|
|
#
|
|
error = None
|
|
warning = None
|
|
def ReportReleaseError(msg):
|
|
global error
|
|
error = msg
|
|
|
|
def ReportReleaseWarning(msg):
|
|
global warning
|
|
warning = msg
|
|
|
|
def ReportClear():
|
|
global error, warning
|
|
error = None
|
|
warning = None
|
|
|
|
#
|
|
# IDLRelease
|
|
#
|
|
# IDLRelease is an object which stores the association of a given symbol
|
|
# name, with an AST node for a range of Releases for that object.
|
|
#
|
|
# A vmin value of None indicates that the object begins at the earliest
|
|
# available Release number. The value of vmin is always inclusive.
|
|
|
|
# A vmax value of None indicates that the object is never deprecated, so
|
|
# it exists until it is overloaded or until the latest available Release.
|
|
# The value of vmax is always exclusive, representing the first Release
|
|
# on which the object is no longer valid.
|
|
class IDLRelease(object):
|
|
def __init__(self, rmin, rmax):
|
|
self.rmin = rmin
|
|
self.rmax = rmax
|
|
|
|
def __str__(self):
|
|
if not self.rmin:
|
|
rmin = '0'
|
|
else:
|
|
rmin = str(self.rmin)
|
|
if not self.rmax:
|
|
rmax = '+oo'
|
|
else:
|
|
rmax = str(self.rmax)
|
|
return '[%s,%s)' % (rmin, rmax)
|
|
|
|
def SetReleaseRange(self, rmin, rmax):
|
|
self.rmin = rmin
|
|
self.rmax = rmax
|
|
|
|
# True, if Release falls within the interval [self.vmin, self.vmax)
|
|
def IsRelease(self, release):
|
|
if self.rmax and self.rmax <= release:
|
|
return False
|
|
if self.rmin and self.rmin > release:
|
|
return False
|
|
if GetOption('release_debug'):
|
|
InfoOut.Log('%f is in %s' % (release, self))
|
|
return True
|
|
|
|
# True, if Release falls within the interval [self.vmin, self.vmax)
|
|
def InReleases(self, releases):
|
|
if not releases: return False
|
|
|
|
# Check last release first, since InRange does not match last item
|
|
if self.IsRelease(releases[-1]): return True
|
|
if len(releases) > 1:
|
|
return self.InRange(releases[0], releases[-1])
|
|
return False
|
|
|
|
# True, if interval [vmin, vmax) overlaps interval [self.vmin, self.vmax)
|
|
def InRange(self, rmin, rmax):
|
|
assert (rmin == None) or rmin < rmax
|
|
|
|
# An min of None always passes a min bound test
|
|
# An max of None always passes a max bound test
|
|
if rmin is not None and self.rmax is not None:
|
|
if self.rmax <= rmin:
|
|
return False
|
|
if rmax is not None and self.rmin is not None:
|
|
if self.rmin >= rmax:
|
|
return False
|
|
|
|
if GetOption('release_debug'):
|
|
InfoOut.Log('%f to %f is in %s' % (rmin, rmax, self))
|
|
return True
|
|
|
|
def GetMinMax(self, releases = None):
|
|
if not releases:
|
|
return self.rmin, self.rmax
|
|
|
|
if not self.rmin:
|
|
rmin = releases[0]
|
|
else:
|
|
rmin = str(self.rmin)
|
|
if not self.rmax:
|
|
rmax = releases[-1]
|
|
else:
|
|
rmax = str(self.rmax)
|
|
return (rmin, rmax)
|
|
|
|
def SetMin(self, release):
|
|
assert not self.rmin
|
|
self.rmin = release
|
|
|
|
def Error(self, msg):
|
|
ReportReleaseError(msg)
|
|
|
|
def Warn(self, msg):
|
|
ReportReleaseWarning(msg)
|
|
|
|
|
|
#
|
|
# IDLReleaseList
|
|
#
|
|
# IDLReleaseList is a list based container for holding IDLRelease
|
|
# objects in order. The IDLReleaseList can be added to, and searched by
|
|
# range. Objects are stored in order, and must be added in order.
|
|
#
|
|
class IDLReleaseList(object):
|
|
def __init__(self):
|
|
self._nodes = []
|
|
|
|
def GetReleases(self):
|
|
return self._nodes
|
|
|
|
def FindRelease(self, release):
|
|
for node in self._nodes:
|
|
if node.IsRelease(release):
|
|
return node
|
|
return None
|
|
|
|
def FindRange(self, rmin, rmax):
|
|
assert (rmin == None) or rmin != rmax
|
|
|
|
out = []
|
|
for node in self._nodes:
|
|
if node.InRange(rmin, rmax):
|
|
out.append(node)
|
|
return out
|
|
|
|
def AddNode(self, node):
|
|
if GetOption('release_debug'):
|
|
InfoOut.Log('\nAdding %s %s' % (node.Location(), node))
|
|
last = None
|
|
|
|
# Check current releases in that namespace
|
|
for cver in self._nodes:
|
|
if GetOption('release_debug'): InfoOut.Log(' Checking %s' % cver)
|
|
|
|
# We should only be missing a 'release' tag for the first item.
|
|
if not node.rmin:
|
|
node.Error('Missing release on overload of previous %s.' %
|
|
cver.Location())
|
|
return False
|
|
|
|
# If the node has no max, then set it to this one
|
|
if not cver.rmax:
|
|
cver.rmax = node.rmin
|
|
if GetOption('release_debug'): InfoOut.Log(' Update %s' % cver)
|
|
|
|
# if the max and min overlap, than's an error
|
|
if cver.rmax > node.rmin:
|
|
if node.rmax and cver.rmin >= node.rmax:
|
|
node.Error('Declarations out of order.')
|
|
else:
|
|
node.Error('Overlap in releases: %s vs %s when adding %s' %
|
|
(cver.rmax, node.rmin, node))
|
|
return False
|
|
last = cver
|
|
|
|
# Otherwise, the previous max and current min should match
|
|
# unless this is the unlikely case of something being only
|
|
# temporarily deprecated.
|
|
if last and last.rmax != node.rmin:
|
|
node.Warn('Gap in release numbers.')
|
|
|
|
# If we made it here, this new node must be the 'newest'
|
|
# and does not overlap with anything previously added, so
|
|
# we can add it to the end of the list.
|
|
if GetOption('release_debug'): InfoOut.Log('Done %s' % node)
|
|
self._nodes.append(node)
|
|
return True
|
|
|
|
#
|
|
# IDLReleaseMap
|
|
#
|
|
# A release map, can map from an float interface release, to a global
|
|
# release string.
|
|
#
|
|
class IDLReleaseMap(object):
|
|
def __init__(self, release_info):
|
|
self.version_to_release = {}
|
|
self.release_to_version = {}
|
|
self.release_to_channel = {}
|
|
for release, version, channel in release_info:
|
|
self.version_to_release[version] = release
|
|
self.release_to_version[release] = version
|
|
self.release_to_channel[release] = channel
|
|
self.releases = sorted(self.release_to_version.keys())
|
|
self.versions = sorted(self.version_to_release.keys())
|
|
|
|
def GetVersion(self, release):
|
|
return self.release_to_version.get(release, None)
|
|
|
|
def GetVersions(self):
|
|
return self.versions
|
|
|
|
def GetRelease(self, version):
|
|
return self.version_to_release.get(version, None)
|
|
|
|
def GetReleases(self):
|
|
return self.releases
|
|
|
|
def GetReleaseRange(self):
|
|
return (self.releases[0], self.releases[-1])
|
|
|
|
def GetVersionRange(self):
|
|
return (self.versions[0], self.version[-1])
|
|
|
|
def GetChannel(self, release):
|
|
return self.release_to_channel.get(release, None)
|
|
|
|
#
|
|
# Test Code
|
|
#
|
|
def TestReleaseNode():
|
|
FooXX = IDLRelease(None, None)
|
|
Foo1X = IDLRelease('M14', None)
|
|
Foo23 = IDLRelease('M15', 'M16')
|
|
|
|
assert FooXX.IsRelease('M13')
|
|
assert FooXX.IsRelease('M14')
|
|
assert FooXX.InRange('M13', 'M13A')
|
|
assert FooXX.InRange('M14','M15')
|
|
|
|
assert not Foo1X.IsRelease('M13')
|
|
assert Foo1X.IsRelease('M14')
|
|
assert Foo1X.IsRelease('M15')
|
|
|
|
assert not Foo1X.InRange('M13', 'M14')
|
|
assert not Foo1X.InRange('M13A', 'M14')
|
|
assert Foo1X.InRange('M14', 'M15')
|
|
assert Foo1X.InRange('M15', 'M16')
|
|
|
|
assert not Foo23.InRange('M13', 'M14')
|
|
assert not Foo23.InRange('M13A', 'M14')
|
|
assert not Foo23.InRange('M14', 'M15')
|
|
assert Foo23.InRange('M15', 'M16')
|
|
assert Foo23.InRange('M14', 'M15A')
|
|
assert Foo23.InRange('M15B', 'M17')
|
|
assert not Foo23.InRange('M16', 'M17')
|
|
print "TestReleaseNode - Passed"
|
|
|
|
|
|
def TestReleaseListWarning():
|
|
FooXX = IDLRelease(None, None)
|
|
Foo1X = IDLRelease('M14', None)
|
|
Foo23 = IDLRelease('M15', 'M16')
|
|
Foo45 = IDLRelease('M17', 'M18')
|
|
|
|
# Add nodes out of order should fail
|
|
ReportClear()
|
|
releases = IDLReleaseList()
|
|
assert releases.AddNode(Foo23)
|
|
assert releases.AddNode(Foo45)
|
|
assert warning
|
|
print "TestReleaseListWarning - Passed"
|
|
|
|
|
|
def TestReleaseListError():
|
|
FooXX = IDLRelease(None, None)
|
|
Foo1X = IDLRelease('M14', None)
|
|
Foo23 = IDLRelease('M15', 'M16')
|
|
Foo45 = IDLRelease('M17', 'M18')
|
|
|
|
# Add nodes out of order should fail
|
|
ReportClear()
|
|
releases = IDLReleaseList()
|
|
assert releases.AddNode(FooXX)
|
|
assert releases.AddNode(Foo23)
|
|
assert not releases.AddNode(Foo1X)
|
|
assert error
|
|
print "TestReleaseListError - Passed"
|
|
|
|
|
|
def TestReleaseListOK():
|
|
FooXX = IDLRelease(None, None)
|
|
Foo1X = IDLRelease('M14', None)
|
|
Foo23 = IDLRelease('M15', 'M16')
|
|
Foo45 = IDLRelease('M17', 'M18')
|
|
|
|
# Add nodes in order should work
|
|
ReportClear()
|
|
releases = IDLReleaseList()
|
|
assert releases.AddNode(FooXX)
|
|
assert releases.AddNode(Foo1X)
|
|
assert releases.AddNode(Foo23)
|
|
assert not error and not warning
|
|
assert releases.AddNode(Foo45)
|
|
assert warning
|
|
|
|
assert releases.FindRelease('M13') == FooXX
|
|
assert releases.FindRelease('M14') == Foo1X
|
|
assert releases.FindRelease('M15') == Foo23
|
|
assert releases.FindRelease('M16') == None
|
|
assert releases.FindRelease('M17') == Foo45
|
|
assert releases.FindRelease('M18') == None
|
|
|
|
assert releases.FindRange('M13','M14') == [FooXX]
|
|
assert releases.FindRange('M13','M17') == [FooXX, Foo1X, Foo23]
|
|
assert releases.FindRange('M16','M17') == []
|
|
assert releases.FindRange(None, None) == [FooXX, Foo1X, Foo23, Foo45]
|
|
|
|
# Verify we can find the correct versions
|
|
print "TestReleaseListOK - Passed"
|
|
|
|
|
|
def TestReleaseMap():
|
|
print "TestReleaseMap- Passed"
|
|
|
|
|
|
def Main(args):
|
|
TestReleaseNode()
|
|
TestReleaseListWarning()
|
|
TestReleaseListError()
|
|
TestReleaseListOK()
|
|
print "Passed"
|
|
return 0
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(Main(sys.argv[1:]))
|
|
|