bug 654448 - remove xpt.py's Typelib.merge, move all the logic into xpt_link (also make it a lot faster). r=khuey

This commit is contained in:
Ted Mielczarek 2012-05-03 13:44:43 -04:00
Родитель df74054797
Коммит ad83523c70
2 изменённых файлов: 226 добавлений и 259 удалений

Просмотреть файл

@ -378,7 +378,7 @@ class TestInterfaceCmp(unittest.TestCase):
methods=[m])
self.assert_(i2 == i1)
class TestTypelibMerge(unittest.TestCase):
class TestXPTLink(unittest.TestCase):
def test_mergeDifferent(self):
"""
Test that merging two typelibs with completely different interfaces
@ -391,12 +391,12 @@ class TestTypelibMerge(unittest.TestCase):
t2 = xpt.Typelib()
# add an unresolved interface
t2.interfaces.append(xpt.Interface("IBar"))
t1.merge(t2)
t3 = xpt.xpt_link([t1, t2])
self.assertEqual(2, len(t1.interfaces))
self.assertEqual(2, len(t3.interfaces))
# Interfaces should wind up sorted
self.assertEqual("IBar", t1.interfaces[0].name)
self.assertEqual("IFoo", t1.interfaces[1].name)
self.assertEqual("IBar", t3.interfaces[0].name)
self.assertEqual("IFoo", t3.interfaces[1].name)
# Add some IID values
t1 = xpt.Typelib()
@ -405,12 +405,12 @@ class TestTypelibMerge(unittest.TestCase):
t2 = xpt.Typelib()
# add an unresolved interface
t2.interfaces.append(xpt.Interface("IBar", iid="44332211-6655-8877-0099-aabbccddeeff"))
t1.merge(t2)
t3 = xpt.xpt_link([t1, t2])
self.assertEqual(2, len(t1.interfaces))
self.assertEqual(2, len(t3.interfaces))
# Interfaces should wind up sorted
self.assertEqual("IFoo", t1.interfaces[0].name)
self.assertEqual("IBar", t1.interfaces[1].name)
self.assertEqual("IFoo", t3.interfaces[0].name)
self.assertEqual("IBar", t3.interfaces[1].name)
def test_mergeConflict(self):
"""
@ -425,7 +425,7 @@ class TestTypelibMerge(unittest.TestCase):
t2 = xpt.Typelib()
# add an unresolved interface, same name different IID
t2.interfaces.append(xpt.Interface("IFoo", iid="44332211-6655-8877-0099-aabbccddeeff"))
self.assertRaises(xpt.DataError, t1.merge, t2)
self.assertRaises(xpt.DataError, xpt.xpt_link, [t1, t2])
# Same IIDs, different names
t1 = xpt.Typelib()
@ -434,7 +434,7 @@ class TestTypelibMerge(unittest.TestCase):
t2 = xpt.Typelib()
# add an unresolved interface, same IID different name
t2.interfaces.append(xpt.Interface("IBar", iid="11223344-5566-7788-9900-aabbccddeeff"))
self.assertRaises(xpt.DataError, t1.merge, t2)
self.assertRaises(xpt.DataError, xpt.xpt_link, [t1, t2])
def test_mergeUnresolvedIID(self):
"""
@ -450,11 +450,11 @@ class TestTypelibMerge(unittest.TestCase):
t2 = xpt.Typelib()
# add an unresolved interface, no IID
t2.interfaces.append(xpt.Interface("IFoo"))
t1.merge(t2)
t3 = xpt.xpt_link([t1, t2])
self.assertEqual(1, len(t1.interfaces))
self.assertEqual("IFoo", t1.interfaces[0].name)
self.assertEqual("11223344-5566-7788-9900-aabbccddeeff", t1.interfaces[0].iid)
self.assertEqual(1, len(t3.interfaces))
self.assertEqual("IFoo", t3.interfaces[0].name)
self.assertEqual("11223344-5566-7788-9900-aabbccddeeff", t3.interfaces[0].iid)
# Unresolved in both, but t2 has an IID value
t1 = xpt.Typelib()
# add an unresolved interface, no IID
@ -462,11 +462,11 @@ class TestTypelibMerge(unittest.TestCase):
t2 = xpt.Typelib()
# add an unresolved interface with a valid IID
t2.interfaces.append(xpt.Interface("IFoo", iid="11223344-5566-7788-9900-aabbccddeeff"))
t1.merge(t2)
t3 = xpt.xpt_link([t1, t2])
self.assertEqual(1, len(t1.interfaces))
self.assertEqual("IFoo", t1.interfaces[0].name)
self.assertEqual("11223344-5566-7788-9900-aabbccddeeff", t1.interfaces[0].iid)
self.assertEqual(1, len(t3.interfaces))
self.assertEqual("IFoo", t3.interfaces[0].name)
self.assertEqual("11223344-5566-7788-9900-aabbccddeeff", t3.interfaces[0].iid)
def test_mergeResolvedUnresolved(self):
"""
@ -486,14 +486,14 @@ class TestTypelibMerge(unittest.TestCase):
m = xpt.Method("Bar", p)
t2.interfaces.append(xpt.Interface("IFoo", iid="11223344-5566-7788-9900-aabbccddeeff",
methods=[m]))
t1.merge(t2)
t3 = xpt.xpt_link([t1, t2])
self.assertEqual(1, len(t1.interfaces))
self.assertEqual("IFoo", t1.interfaces[0].name)
self.assertEqual("11223344-5566-7788-9900-aabbccddeeff", t1.interfaces[0].iid)
self.assert_(t1.interfaces[0].resolved)
self.assertEqual(1, len(t1.interfaces[0].methods))
self.assertEqual("Bar", t1.interfaces[0].methods[0].name)
self.assertEqual(1, len(t3.interfaces))
self.assertEqual("IFoo", t3.interfaces[0].name)
self.assertEqual("11223344-5566-7788-9900-aabbccddeeff", t3.interfaces[0].iid)
self.assert_(t3.interfaces[0].resolved)
self.assertEqual(1, len(t3.interfaces[0].methods))
self.assertEqual("Bar", t3.interfaces[0].methods[0].name)
# t1 has a resolved interface, t2 has an unresolved version
t1 = xpt.Typelib()
@ -505,14 +505,14 @@ class TestTypelibMerge(unittest.TestCase):
t2 = xpt.Typelib()
# add an unresolved interface
t2.interfaces.append(xpt.Interface("IFoo"))
t1.merge(t2)
t3 = xpt.xpt_link([t1, t2])
self.assertEqual(1, len(t1.interfaces))
self.assertEqual("IFoo", t1.interfaces[0].name)
self.assertEqual("11223344-5566-7788-9900-aabbccddeeff", t1.interfaces[0].iid)
self.assert_(t1.interfaces[0].resolved)
self.assertEqual(1, len(t1.interfaces[0].methods))
self.assertEqual("Bar", t1.interfaces[0].methods[0].name)
self.assertEqual(1, len(t3.interfaces))
self.assertEqual("IFoo", t3.interfaces[0].name)
self.assertEqual("11223344-5566-7788-9900-aabbccddeeff", t3.interfaces[0].iid)
self.assert_(t3.interfaces[0].resolved)
self.assertEqual(1, len(t3.interfaces[0].methods))
self.assertEqual("Bar", t3.interfaces[0].methods[0].name)
def test_mergeReplaceParents(self):
"""
@ -536,17 +536,17 @@ class TestTypelibMerge(unittest.TestCase):
m = xpt.Method("Bar", p)
t2.interfaces.append(xpt.Interface("IFoo", iid="11223344-5566-7788-9900-aabbccddeeff",
methods=[m]))
t1.merge(t2)
t3 = xpt.xpt_link([t1, t2])
self.assertEqual(2, len(t1.interfaces))
self.assertEqual("IChild", t1.interfaces[0].name)
self.assertEqual("11111111-1111-1111-1111-111111111111", t1.interfaces[0].iid)
self.assertEqual("IFoo", t1.interfaces[1].name)
self.assertEqual("11223344-5566-7788-9900-aabbccddeeff", t1.interfaces[1].iid)
self.assert_(t1.interfaces[0].resolved)
self.assertEqual(2, len(t3.interfaces))
self.assertEqual("IChild", t3.interfaces[0].name)
self.assertEqual("11111111-1111-1111-1111-111111111111", t3.interfaces[0].iid)
self.assertEqual("IFoo", t3.interfaces[1].name)
self.assertEqual("11223344-5566-7788-9900-aabbccddeeff", t3.interfaces[1].iid)
self.assert_(t3.interfaces[0].resolved)
# Ensure that IChild's parent has been updated
self.assertEqual(t1.interfaces[1], t1.interfaces[0].parent)
self.assert_(t1.interfaces[0].parent.resolved)
self.assertEqual(t3.interfaces[1], t3.interfaces[0].parent)
self.assert_(t3.interfaces[0].parent.resolved)
# t1 has a resolved interface, t2 has an unresolved version,
# but t2 also has another interface whose parent is the unresolved
@ -564,17 +564,17 @@ class TestTypelibMerge(unittest.TestCase):
# add a child of the unresolved interface
t2.interfaces.append(xpt.Interface("IChild", iid="11111111-1111-1111-1111-111111111111",
resolved=True, parent=pi))
t1.merge(t2)
t3 = xpt.xpt_link([t1, t2])
self.assertEqual(2, len(t1.interfaces))
self.assertEqual("IChild", t1.interfaces[0].name)
self.assertEqual("11111111-1111-1111-1111-111111111111", t1.interfaces[0].iid)
self.assertEqual("IFoo", t1.interfaces[1].name)
self.assertEqual("11223344-5566-7788-9900-aabbccddeeff", t1.interfaces[1].iid)
self.assert_(t1.interfaces[0].resolved)
self.assertEqual(2, len(t3.interfaces))
self.assertEqual("IChild", t3.interfaces[0].name)
self.assertEqual("11111111-1111-1111-1111-111111111111", t3.interfaces[0].iid)
self.assertEqual("IFoo", t3.interfaces[1].name)
self.assertEqual("11223344-5566-7788-9900-aabbccddeeff", t3.interfaces[1].iid)
self.assert_(t3.interfaces[0].resolved)
# Ensure that IChild's parent has been updated
self.assertEqual(t1.interfaces[1], t1.interfaces[0].parent)
self.assert_(t1.interfaces[0].parent.resolved)
self.assertEqual(t3.interfaces[1], t3.interfaces[0].parent)
self.assert_(t3.interfaces[0].parent.resolved)
def test_mergeReplaceRetval(self):
"""
@ -601,19 +601,19 @@ class TestTypelibMerge(unittest.TestCase):
m = xpt.Method("Bar", p)
t2.interfaces.append(xpt.Interface("IFoo", iid="11223344-5566-7788-9900-aabbccddeeff",
methods=[m]))
t1.merge(t2)
t3 = xpt.xpt_link([t1, t2])
self.assertEqual(2, len(t1.interfaces))
self.assertEqual("IRetval", t1.interfaces[0].name)
self.assertEqual("11111111-1111-1111-1111-111111111111", t1.interfaces[0].iid)
self.assertEqual("IFoo", t1.interfaces[1].name)
self.assertEqual("11223344-5566-7788-9900-aabbccddeeff", t1.interfaces[1].iid)
self.assert_(t1.interfaces[1].resolved)
self.assertEqual(2, len(t3.interfaces))
self.assertEqual("IRetval", t3.interfaces[0].name)
self.assertEqual("11111111-1111-1111-1111-111111111111", t3.interfaces[0].iid)
self.assertEqual("IFoo", t3.interfaces[1].name)
self.assertEqual("11223344-5566-7788-9900-aabbccddeeff", t3.interfaces[1].iid)
self.assert_(t3.interfaces[1].resolved)
# Ensure that IRetval's method's return value type has been updated.
self.assertEqual(1, len(t1.interfaces[0].methods))
self.assert_(t1.interfaces[0].methods[0].result.type.iface.resolved)
self.assertEqual(t1.interfaces[1],
t1.interfaces[0].methods[0].result.type.iface)
self.assertEqual(1, len(t3.interfaces[0].methods))
self.assert_(t3.interfaces[0].methods[0].result.type.iface.resolved)
self.assertEqual(t3.interfaces[1],
t3.interfaces[0].methods[0].result.type.iface)
# t1 has a resolved interface. t2 has an unresolved version and
# an interface that uses the unresolved interface as a return value
@ -634,19 +634,19 @@ class TestTypelibMerge(unittest.TestCase):
m = xpt.Method("ReturnIface", p)
t2.interfaces.append(xpt.Interface("IRetval", iid="11111111-1111-1111-1111-111111111111",
methods=[m]))
t1.merge(t2)
t3 = xpt.xpt_link([t1, t2])
self.assertEqual(2, len(t1.interfaces))
self.assertEqual("IRetval", t1.interfaces[0].name)
self.assertEqual("11111111-1111-1111-1111-111111111111", t1.interfaces[0].iid)
self.assertEqual("IFoo", t1.interfaces[1].name)
self.assertEqual("11223344-5566-7788-9900-aabbccddeeff", t1.interfaces[1].iid)
self.assert_(t1.interfaces[1].resolved)
self.assertEqual(2, len(t3.interfaces))
self.assertEqual("IRetval", t3.interfaces[0].name)
self.assertEqual("11111111-1111-1111-1111-111111111111", t3.interfaces[0].iid)
self.assertEqual("IFoo", t3.interfaces[1].name)
self.assertEqual("11223344-5566-7788-9900-aabbccddeeff", t3.interfaces[1].iid)
self.assert_(t3.interfaces[1].resolved)
# Ensure that IRetval's method's return value type has been updated.
self.assertEqual(1, len(t1.interfaces[0].methods))
self.assert_(t1.interfaces[0].methods[0].result.type.iface.resolved)
self.assertEqual(t1.interfaces[1],
t1.interfaces[0].methods[0].result.type.iface)
self.assertEqual(1, len(t3.interfaces[0].methods))
self.assert_(t3.interfaces[0].methods[0].result.type.iface.resolved)
self.assertEqual(t3.interfaces[1],
t3.interfaces[0].methods[0].result.type.iface)
def test_mergeReplaceParams(self):
"""
@ -673,19 +673,19 @@ class TestTypelibMerge(unittest.TestCase):
m = xpt.Method("Bar", vp)
t2.interfaces.append(xpt.Interface("IFoo", iid="11223344-5566-7788-9900-aabbccddeeff",
methods=[m]))
t1.merge(t2)
t3 = xpt.xpt_link([t1, t2])
self.assertEqual(2, len(t1.interfaces))
self.assertEqual("IParam", t1.interfaces[0].name)
self.assertEqual("11111111-1111-1111-1111-111111111111", t1.interfaces[0].iid)
self.assertEqual("IFoo", t1.interfaces[1].name)
self.assertEqual("11223344-5566-7788-9900-aabbccddeeff", t1.interfaces[1].iid)
self.assert_(t1.interfaces[1].resolved)
self.assertEqual(2, len(t3.interfaces))
self.assertEqual("IParam", t3.interfaces[0].name)
self.assertEqual("11111111-1111-1111-1111-111111111111", t3.interfaces[0].iid)
self.assertEqual("IFoo", t3.interfaces[1].name)
self.assertEqual("11223344-5566-7788-9900-aabbccddeeff", t3.interfaces[1].iid)
self.assert_(t3.interfaces[1].resolved)
# Ensure that IRetval's method's param type has been updated.
self.assertEqual(1, len(t1.interfaces[0].methods))
self.assert_(t1.interfaces[0].methods[0].params[0].type.iface.resolved)
self.assertEqual(t1.interfaces[1],
t1.interfaces[0].methods[0].params[0].type.iface)
self.assertEqual(1, len(t3.interfaces[0].methods))
self.assert_(t3.interfaces[0].methods[0].params[0].type.iface.resolved)
self.assertEqual(t3.interfaces[1],
t3.interfaces[0].methods[0].params[0].type.iface)
# t1 has a resolved interface. t2 has an unresolved version
# and an interface that uses the unresolved interface as a
@ -706,19 +706,19 @@ class TestTypelibMerge(unittest.TestCase):
m = xpt.Method("IfaceParam", vp, params=[p])
t2.interfaces.append(xpt.Interface("IParam", iid="11111111-1111-1111-1111-111111111111",
methods=[m]))
t1.merge(t2)
t3 = xpt.xpt_link([t1, t2])
self.assertEqual(2, len(t1.interfaces))
self.assertEqual("IParam", t1.interfaces[0].name)
self.assertEqual("11111111-1111-1111-1111-111111111111", t1.interfaces[0].iid)
self.assertEqual("IFoo", t1.interfaces[1].name)
self.assertEqual("11223344-5566-7788-9900-aabbccddeeff", t1.interfaces[1].iid)
self.assert_(t1.interfaces[1].resolved)
self.assertEqual(2, len(t3.interfaces))
self.assertEqual("IParam", t3.interfaces[0].name)
self.assertEqual("11111111-1111-1111-1111-111111111111", t3.interfaces[0].iid)
self.assertEqual("IFoo", t3.interfaces[1].name)
self.assertEqual("11223344-5566-7788-9900-aabbccddeeff", t3.interfaces[1].iid)
self.assert_(t3.interfaces[1].resolved)
# Ensure that IRetval's method's param type has been updated.
self.assertEqual(1, len(t1.interfaces[0].methods))
self.assert_(t1.interfaces[0].methods[0].params[0].type.iface.resolved)
self.assertEqual(t1.interfaces[1],
t1.interfaces[0].methods[0].params[0].type.iface)
self.assertEqual(1, len(t3.interfaces[0].methods))
self.assert_(t3.interfaces[0].methods[0].params[0].type.iface.resolved)
self.assertEqual(t3.interfaces[1],
t3.interfaces[0].methods[0].params[0].type.iface)
def test_mergeReplaceArrayTypeParams(self):
@ -748,74 +748,19 @@ class TestTypelibMerge(unittest.TestCase):
m = xpt.Method("Bar", vp)
t2.interfaces.append(xpt.Interface("IFoo", iid="11223344-5566-7788-9900-aabbccddeeff",
methods=[m]))
t1.merge(t2)
self.assertEqual(2, len(t1.interfaces))
self.assertEqual("IParam", t1.interfaces[0].name)
self.assertEqual("11111111-1111-1111-1111-111111111111", t1.interfaces[0].iid)
self.assertEqual("IFoo", t1.interfaces[1].name)
self.assertEqual("11223344-5566-7788-9900-aabbccddeeff", t1.interfaces[1].iid)
self.assert_(t1.interfaces[1].resolved)
# Ensure that IRetval's method's param type has been updated.
self.assertEqual(1, len(t1.interfaces[0].methods))
self.assert_(t1.interfaces[0].methods[0].params[0].type.element_type.iface.resolved)
self.assertEqual(t1.interfaces[1],
t1.interfaces[0].methods[0].params[0].type.element_type.iface)
class TestXPTLink(unittest.TestCase):
def test_xpt_link(self):
"""
Test the xpt_link method.
"""
t1 = xpt.Typelib()
# add an unresolved interface
t1.interfaces.append(xpt.Interface("IFoo"))
f1 = StringIO()
t1.write(f1)
f1.seek(0)
t2 = xpt.Typelib()
# add an unresolved interface
t2.interfaces.append(xpt.Interface("IBar"))
f2 = StringIO()
t2.write(f2)
f2.seek(0)
f3 = StringIO()
xpt.xpt_link(f3, [f1, f2])
f3.seek(0)
t3 = xpt.Typelib.read(f3)
t3 = xpt.xpt_link([t1, t2])
self.assertEqual(2, len(t3.interfaces))
# Interfaces should wind up sorted
self.assertEqual("IBar", t3.interfaces[0].name)
self.assertEqual("IParam", t3.interfaces[0].name)
self.assertEqual("11111111-1111-1111-1111-111111111111", t3.interfaces[0].iid)
self.assertEqual("IFoo", t3.interfaces[1].name)
# Add some IID values
t1 = xpt.Typelib()
# add an unresolved interface
t1.interfaces.append(xpt.Interface("IFoo", iid="11223344-5566-7788-9900-aabbccddeeff"))
f1 = StringIO()
t1.write(f1)
f1.seek(0)
t2 = xpt.Typelib()
# add an unresolved interface
t2.interfaces.append(xpt.Interface("IBar", iid="44332211-6655-8877-0099-aabbccddeeff"))
f2 = StringIO()
t2.write(f2)
f2.seek(0)
f3 = StringIO()
xpt.xpt_link(f3, [f1, f2])
f3.seek(0)
t3 = xpt.Typelib.read(f3)
self.assertEqual(2, len(t3.interfaces))
# Interfaces should wind up sorted
self.assertEqual("IFoo", t3.interfaces[0].name)
self.assertEqual("IBar", t3.interfaces[1].name)
self.assertEqual("11223344-5566-7788-9900-aabbccddeeff", t3.interfaces[1].iid)
self.assert_(t3.interfaces[1].resolved)
# Ensure that IRetval's method's param type has been updated.
self.assertEqual(1, len(t3.interfaces[0].methods))
self.assert_(t3.interfaces[0].methods[0].params[0].type.element_type.iface.resolved)
self.assertEqual(t3.interfaces[1],
t3.interfaces[0].methods[0].params[0].type.element_type.iface)
if __name__ == '__main__':
unittest.main()

Просмотреть файл

@ -68,6 +68,7 @@ InterfaceType() - construct a new object representing a type that
from __future__ import with_statement
import os, sys
import struct
import operator
# header magic
XPT_MAGIC = "XPCOM\nTypeLib\r\n\x1a"
@ -878,6 +879,9 @@ class Interface(object):
def __str__(self):
return "Interface(name='%s', iid='%s')" % (self.name, self.iid)
def __hash__(self):
return hash((self.name, self.iid))
def __cmp__(self, other):
c = cmp(self.iid, other.iid)
if c != 0:
@ -1186,94 +1190,6 @@ class Typelib(object):
else:
self.writefd(output_file)
def merge(self, other, sanitycheck=True):
"""
Merge the contents of Typelib |other| into this typelib.
If |sanitycheck| is False, don't sort the interface table
after merging.
"""
# This will be a list of (replaced interface, replaced with)
# containing interfaces that were replaced with interfaces from
# another typelib, and the interface that replaced them.
merged_interfaces = []
for i in other.interfaces:
if i in self.interfaces:
continue
# See if there's a copy of this interface with different
# resolved status or IID value.
merged = False
for j in self.interfaces:
if i.name == j.name:
if i.resolved != j.resolved:
# prefer resolved interfaces over unresolved
if j.resolved:
# keep j
merged_interfaces.append((i, j))
merged = True
# Fixup will happen after processing all interfaces.
else:
# replace j with i
merged_interfaces.append((j, i))
merged = True
self.interfaces[self.interfaces.index(j)] = i
elif i.iid != j.iid:
# Prefer unresolved interfaces with valid IIDs
if j.iid == Interface.UNRESOLVED_IID:
# replace j with i
merged_interfaces.append((j, i))
merged = True
self.interfaces[self.interfaces.index(j)] = i
elif i.iid == Interface.UNRESOLVED_IID:
# keep j
merged_interfaces.append((i, j))
merged = True
# Fixup will happen after processing all interfaces.
else:
# Same name but different IIDs: raise an exception.
# self.* is the (target) Typelib being merged into,
# not the one which j.iid was from.
raise DataError, \
"Typelibs contain definitions of interface %s" \
" with different IIDs (%s (%s) vs %s (%s))!" % \
(i.name, i.iid, i.xpt_filename or other.filename, \
j.iid, j.xpt_filename or self.filename)
elif i.iid == j.iid and i.iid != Interface.UNRESOLVED_IID:
# Same IID but different names: raise an exception.
# self.* is the (target) Typelib being merged into,
# not the one which j.name was from.
raise DataError, \
"Typelibs contain definitions of interface %s" \
" with different names (%s (%s) vs %s (%s))!" % \
(i.iid, i.name, i.xpt_filename or other.filename, \
j.name, j.xpt_filename or self.filename)
if not merged:
# No partially matching interfaces, so just take this interface
self.interfaces.append(i)
# Now fixup any merged interfaces
def checkType(t, replaced_from, replaced_to):
if isinstance(t, InterfaceType) and t.iface == replaced_from:
t.iface = replaced_to
elif isinstance(t, ArrayType) and \
isinstance(t.element_type, InterfaceType) and \
t.element_type.iface == replaced_from:
t.element_type.iface = replaced_to
for replaced_from, replaced_to in merged_interfaces:
for i in self.interfaces:
# Replace parent references
if i.parent is not None and i.parent == replaced_from:
i.parent = replaced_to
for m in i.methods:
# Replace InterfaceType params and return values
checkType(m.result.type, replaced_from, replaced_to)
for p in m.params:
checkType(p.type, replaced_from, replaced_to)
if sanitycheck:
self._sanityCheck()
#TODO: do we care about annotations? probably not
def dump(self, out):
"""
Print a human-readable listing of the contents of this typelib
@ -1335,21 +1251,126 @@ def xpt_dump(file):
t = Typelib.read(file)
t.dump(sys.stdout)
def xpt_link(dest, inputs):
def xpt_link(inputs):
"""
Link all of the xpt files in |inputs| together and write the
result to |dest|. All parameters may be filenames or file-like objects.
Link all of the xpt files in |inputs| together and return the result
as a Typelib object. All entries in inputs may be filenames or
file-like objects.
"""
def read_input(i):
if isinstance(i, Typelib):
return i
return Typelib.read(i)
if not inputs:
print >>sys.stderr, "Usage: xpt_link <destination file> <input files>"
return
t1 = Typelib.read(inputs[0])
for f in inputs[1:]:
t2 = Typelib.read(f)
# write will call sanitycheck, so skip it here.
t1.merge(t2, sanitycheck=False)
t1.write(dest)
return None
# This is the aggregate list of interfaces.
interfaces = []
# This will be a dict of replaced interface -> replaced with
# containing interfaces that were replaced with interfaces from
# another typelib, and the interface that replaced them.
merged_interfaces = {}
for f in inputs:
t = read_input(f)
interfaces.extend(t.interfaces)
# Sort interfaces by name so we can merge adjacent duplicates
interfaces.sort(key=operator.attrgetter('name'))
Result = enum('Equal', # Interfaces the same, doesn't matter
'NotEqual', # Interfaces differ, keep both
'KeepFirst', # Replace second interface with first
'KeepSecond')# Replace first interface with second
def compare(i, j):
"""
Compare two interfaces, determine if they're equal or
completely different, or should be merged (and indicate which
one to keep in that case).
"""
if i == j:
# Arbitrary, just pick one
return Result.Equal
if i.name != j.name:
if i.iid == j.iid and i.iid != Interface.UNRESOLVED_IID:
# Same IID but different names: raise an exception.
raise DataError, \
"Typelibs contain definitions of interface %s" \
" with different names (%s (%s) vs %s (%s))!" % \
(i.iid, i.name, i.xpt_filename, j.name, j.xpt_filename)
# Otherwise just different interfaces.
return Result.NotEqual
# Interfaces have the same name, so either they need to be merged
# or there's a data error. Sort out which one to keep
if i.resolved != j.resolved:
# prefer resolved interfaces over unresolved
if j.resolved:
assert i.iid == j.iid or i.iid == Interface.UNRESOLVED_IID
# keep j
return Result.KeepSecond
else:
assert i.iid == j.iid or j.iid == Interface.UNRESOLVED_IID
# replace j with i
return Result.KeepFirst
elif i.iid != j.iid:
# Prefer unresolved interfaces with valid IIDs
if j.iid == Interface.UNRESOLVED_IID:
# replace j with i
assert not j.resolved
return Result.KeepFirst
elif i.iid == Interface.UNRESOLVED_IID:
# keep j
assert not i.resolved
return Result.KeepSecond
else:
# Same name but different IIDs: raise an exception.
raise DataError, \
"Typelibs contain definitions of interface %s" \
" with different IIDs (%s (%s) vs %s (%s))!" % \
(i.name, i.iid, i.xpt_filename, \
j.iid, j.xpt_filename)
raise DataError, "No idea what happened here: %s:%s (%s), %s:%s (%s)" % \
(i.name, i.iid, i.xpt_filename, j.name, j.iid, j.xpt_filename)
# Compare interfaces pairwise to find duplicates that should be merged.
i = 1
while i < len(interfaces):
res = compare(interfaces[i-1], interfaces[i])
if res == Result.NotEqual:
i += 1
elif res == Result.Equal:
# Need to drop one but it doesn't matter which
del interfaces[i]
elif res == Result.KeepFirst:
merged_interfaces[interfaces[i]] = interfaces[i-1]
del interfaces[i]
elif res == Result.KeepSecond:
merged_interfaces[interfaces[i-1]] = interfaces[i]
del interfaces[i-1]
# Now fixup any merged interfaces
def checkType(t):
if isinstance(t, InterfaceType) and t.iface in merged_interfaces:
t.iface = merged_interfaces[t.iface]
elif isinstance(t, ArrayType) and \
isinstance(t.element_type, InterfaceType) and \
t.element_type.iface in merged_interfaces:
t.element_type.iface = merged_interfaces[t.element_type.iface]
for i in interfaces:
# Replace parent references
if i.parent in merged_interfaces:
i.parent = merged_interfaces[i.parent]
for m in i.methods:
# Replace InterfaceType params and return values
checkType(m.result.type)
for p in m.params:
checkType(p.type)
# Re-sort interfaces (by IID)
interfaces.sort()
return Typelib(interfaces=interfaces)
if __name__ == '__main__':
if len(sys.argv) < 3:
@ -1358,4 +1379,5 @@ if __name__ == '__main__':
if sys.argv[1] == 'dump':
xpt_dump(sys.argv[2])
elif sys.argv[1] == 'link':
xpt_link(sys.argv[2], sys.argv[3:])
xpt_link(sys.argv[3:]).write(sys.argv[2])