diff --git a/xpcom/typelib/xpt/tools/runtests.py b/xpcom/typelib/xpt/tools/runtests.py index 66040c48ed3..9c50ee58995 100644 --- a/xpcom/typelib/xpt/tools/runtests.py +++ b/xpcom/typelib/xpt/tools/runtests.py @@ -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() diff --git a/xpcom/typelib/xpt/tools/xpt.py b/xpcom/typelib/xpt/tools/xpt.py index 0cf3db9d9a5..fb64da35016 100644 --- a/xpcom/typelib/xpt/tools/xpt.py +++ b/xpcom/typelib/xpt/tools/xpt.py @@ -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 " - 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]) +