From 46ffe30e0942d321c58c240adeb84fd1dee02fcb Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Thu, 3 May 2012 13:44:40 -0400 Subject: [PATCH 1/4] bug 654448 - refactor pyxpt to accept file-like objects for Typelib.{read,write}. r=khuey --- xpcom/typelib/xpt/tools/runtests.py | 51 +++++++----- xpcom/typelib/xpt/tools/xpt.py | 123 ++++++++++++++++------------ 2 files changed, 101 insertions(+), 73 deletions(-) diff --git a/xpcom/typelib/xpt/tools/runtests.py b/xpcom/typelib/xpt/tools/runtests.py index 48a6e98d8a5..66040c48ed3 100644 --- a/xpcom/typelib/xpt/tools/runtests.py +++ b/xpcom/typelib/xpt/tools/runtests.py @@ -173,9 +173,14 @@ class TypelibCompareMixin: self.assertEqual(t1.size_is_arg_num, t2.size_is_arg_num) self.assertEqual(t1.length_is_arg_num, t2.length_is_arg_num) -#TODO: test flags in various combinations -class TestTypelibRoundtrip(unittest.TestCase, TypelibCompareMixin): - def checkRoundtrip(self, t): +class TestTypelibReadWrite(unittest.TestCase, TypelibCompareMixin): + def test_read_file(self): + """ + Test that a Typelib can be read/written from/to a file. + """ + t = xpt.Typelib() + # add an unresolved interface + t.interfaces.append(xpt.Interface("IFoo")) fd, f = tempfile.mkstemp() os.close(fd) t.write(f) @@ -183,6 +188,17 @@ class TestTypelibRoundtrip(unittest.TestCase, TypelibCompareMixin): os.remove(f) self.assert_(t2 is not None) self.assertEqualTypelibs(t, t2) + + +#TODO: test flags in various combinations +class TestTypelibRoundtrip(unittest.TestCase, TypelibCompareMixin): + def checkRoundtrip(self, t): + s = StringIO() + t.write(s) + s.seek(0) + t2 = xpt.Typelib.read(s) + self.assert_(t2 is not None) + self.assertEqualTypelibs(t, t2) def test_simple(self): t = xpt.Typelib() @@ -747,17 +763,6 @@ class TestTypelibMerge(unittest.TestCase): t1.interfaces[0].methods[0].params[0].type.element_type.iface) class TestXPTLink(unittest.TestCase): - def setUp(self): - self.tempdir = tempfile.mkdtemp() - - def tearDown(self): - shutil.rmtree(self.tempdir, True) - - def gettempfile(self): - fd, f = tempfile.mkstemp(dir=self.tempdir) - os.close(fd) - return f - def test_xpt_link(self): """ Test the xpt_link method. @@ -766,17 +771,20 @@ class TestXPTLink(unittest.TestCase): t1 = xpt.Typelib() # add an unresolved interface t1.interfaces.append(xpt.Interface("IFoo")) - f1 = self.gettempfile() + f1 = StringIO() t1.write(f1) + f1.seek(0) t2 = xpt.Typelib() # add an unresolved interface t2.interfaces.append(xpt.Interface("IBar")) - f2 = self.gettempfile() + f2 = StringIO() t2.write(f2) + f2.seek(0) - f3 = self.gettempfile() + f3 = StringIO() xpt.xpt_link(f3, [f1, f2]) + f3.seek(0) t3 = xpt.Typelib.read(f3) self.assertEqual(2, len(t3.interfaces)) @@ -788,17 +796,20 @@ class TestXPTLink(unittest.TestCase): t1 = xpt.Typelib() # add an unresolved interface t1.interfaces.append(xpt.Interface("IFoo", iid="11223344-5566-7788-9900-aabbccddeeff")) - f1 = self.gettempfile() + 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 = self.gettempfile() + f2 = StringIO() t2.write(f2) + f2.seek(0) - f3 = self.gettempfile() + f3 = StringIO() xpt.xpt_link(f3, [f1, f2]) + f3.seek(0) t3 = xpt.Typelib.read(f3) self.assertEqual(2, len(t3.interfaces)) diff --git a/xpcom/typelib/xpt/tools/xpt.py b/xpcom/typelib/xpt/tools/xpt.py index f751782a6c1..0cf3db9d9a5 100644 --- a/xpcom/typelib/xpt/tools/xpt.py +++ b/xpcom/typelib/xpt/tools/xpt.py @@ -43,8 +43,8 @@ a typelib in a high-level manner, as well as methods for reading and writing them from files. The usable public interfaces are currently: -Typelib.read(filename) - read a typelib from a file on disk, return - a Typelib object. +Typelib.read(input_file) - read a typelib from a file on disk or file-like + object, return a Typelib object. xpt_dump(filename) - read a typelib from a file on disk, dump the contents to stdout in a human-readable @@ -1051,55 +1051,68 @@ class Typelib(object): return map[data_pool + offset - 1:sz] @staticmethod - def read(filename): + def read(input_file): """ - Read a typelib from the file named |filename| and return - the constructed Typelib object. + Read a typelib from |input_file| and return + the constructed Typelib object. |input_file| can be a filename + or a file-like object. """ - with open(filename, "r+b") as f: - st = os.fstat(f.fileno()) - map = f.read(st.st_size) - data = Typelib._header.unpack(map[:Typelib._header.size]) - if data[0] != XPT_MAGIC: - raise FileFormatError, "Bad magic: %s" % data[0] - xpt = Typelib((data[1], data[2])) - xpt.filename = filename - num_interfaces = data[3] - file_length = data[4] - if file_length != st.st_size: - raise FileFormatError, "File is of wrong length, got %d bytes, expected %d" % (st.st_size, file_length) - #XXX: by spec this is a zero-based file offset. however, - # the xpt_xdr code always subtracts 1 from data offsets - # (because that's what you do in the data pool) so it - # winds up accidentally treating this as 1-based. - # Filed as: https://bugzilla.mozilla.org/show_bug.cgi?id=575343 - interface_directory_offset = data[5] - 1 - data_pool_offset = data[6] - # make a half-hearted attempt to read Annotations, - # since XPIDL doesn't produce any anyway. - start = Typelib._header.size - (anno, ) = struct.unpack(">B", map[start:start + struct.calcsize(">B")]) - islast = anno & 0x80 - tag = anno & 0x7F - if tag == 0: # EmptyAnnotation - xpt.annotations.append(None) - # We don't bother handling PrivateAnnotations or anything - - for i in range(num_interfaces): - # iid, name, namespace, interface_descriptor - start = interface_directory_offset + i * Interface._direntry.size - end = interface_directory_offset + (i+1) * Interface._direntry.size - ide = Interface._direntry.unpack(map[start:end]) - iid = Typelib.iid_to_string(ide[0]) - name = Typelib.read_string(map, data_pool_offset, ide[1]) - namespace = Typelib.read_string(map, data_pool_offset, ide[2]) - iface = Interface(name, iid, namespace) - iface._descriptor_offset = ide[3] - iface.xpt_filename = xpt.filename - xpt.interfaces.append(iface) - for iface in xpt.interfaces: - iface.read_descriptor(xpt, map, data_pool_offset) + filename = "" + data = None + expected_size = None + if isinstance(input_file, basestring): + filename = input_file + with open(input_file, "r+b") as f: + st = os.fstat(f.fileno()) + data = f.read(st.st_size) + expected_size = st.st_size + else: + data = input_file.read() + + (magic, + major_ver, + minor_ver, + num_interfaces, + file_length, + interface_directory_offset, + data_pool_offset) = Typelib._header.unpack(data[:Typelib._header.size]) + if magic != XPT_MAGIC: + raise FileFormatError, "Bad magic: %s" % magic + xpt = Typelib((major_ver, minor_ver)) + xpt.filename = filename + if expected_size and file_length != expected_size: + raise FileFormatError, "File is of wrong length, got %d bytes, expected %d" % (expected_size, file_length) + #XXX: by spec this is a zero-based file offset. however, + # the xpt_xdr code always subtracts 1 from data offsets + # (because that's what you do in the data pool) so it + # winds up accidentally treating this as 1-based. + # Filed as: https://bugzilla.mozilla.org/show_bug.cgi?id=575343 + interface_directory_offset -= 1 + # make a half-hearted attempt to read Annotations, + # since XPIDL doesn't produce any anyway. + start = Typelib._header.size + (anno, ) = struct.unpack(">B", data[start:start + struct.calcsize(">B")]) + islast = anno & 0x80 + tag = anno & 0x7F + if tag == 0: # EmptyAnnotation + xpt.annotations.append(None) + # We don't bother handling PrivateAnnotations or anything + + for i in range(num_interfaces): + # iid, name, namespace, interface_descriptor + start = interface_directory_offset + i * Interface._direntry.size + end = interface_directory_offset + (i+1) * Interface._direntry.size + ide = Interface._direntry.unpack(data[start:end]) + iid = Typelib.iid_to_string(ide[0]) + name = Typelib.read_string(data, data_pool_offset, ide[1]) + namespace = Typelib.read_string(data, data_pool_offset, ide[2]) + iface = Interface(name, iid, namespace) + iface._descriptor_offset = ide[3] + iface.xpt_filename = xpt.filename + xpt.interfaces.append(iface) + for iface in xpt.interfaces: + iface.read_descriptor(xpt, data, data_pool_offset) return xpt def __repr__(self): @@ -1160,14 +1173,18 @@ class Typelib(object): for i in self.interfaces: i.write_directory_entry(fd) - def write(self, filename): + def write(self, output_file): """ - Write the contents of this typelib to the file named |filename|. + Write the contents of this typelib to |output_file|, + which can be either a filename or a file-like object. """ self._sanityCheck() - with open(filename, "wb") as f: - self.writefd(f) + if isinstance(output_file, basestring): + with open(output_file, "wb") as f: + self.writefd(f) + else: + self.writefd(output_file) def merge(self, other, sanitycheck=True): """ @@ -1321,7 +1338,7 @@ def xpt_dump(file): def xpt_link(dest, inputs): """ Link all of the xpt files in |inputs| together and write the - result ot |dest|. + result to |dest|. All parameters may be filenames or file-like objects. """ if not inputs: From 051bc98d76134e348441896bb3db89a8ae51353e Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Thu, 3 May 2012 13:44:43 -0400 Subject: [PATCH 2/4] bug 654448 - remove xpt.py's Typelib.merge, move all the logic into xpt_link (also make it a lot faster). r=khuey --- xpcom/typelib/xpt/tools/runtests.py | 265 +++++++++++----------------- xpcom/typelib/xpt/tools/xpt.py | 220 ++++++++++++----------- 2 files changed, 226 insertions(+), 259 deletions(-) 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]) + From afe3be12bc861f071846f12097cc2e825b87858d Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Thu, 3 May 2012 13:45:25 -0400 Subject: [PATCH 3/4] bug 707577 - add fast-package target for mobile/android. r=khuey --- mobile/android/build.mk | 3 +++ mobile/xul/build.mk | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/mobile/android/build.mk b/mobile/android/build.mk index 1517dcf79ce..7786c9aa2d1 100644 --- a/mobile/android/build.mk +++ b/mobile/android/build.mk @@ -72,6 +72,9 @@ installer: package: @$(MAKE) -C mobile/android/installer +fast-package: + @$(MAKE) package MOZ_FAST_PACKAGE=1 + ifeq ($(OS_TARGET),Android) ifeq ($(MOZ_ANDROID_INSTALL_TARGET),) # Determine if there's more than one device connected diff --git a/mobile/xul/build.mk b/mobile/xul/build.mk index e2414878f47..228335c2d2c 100644 --- a/mobile/xul/build.mk +++ b/mobile/xul/build.mk @@ -71,7 +71,7 @@ package: @$(MAKE) -C mobile/xul/installer fast-package: - @MOZ_FAST_PACKAGE=1 $(MAKE) package + @$(MAKE) package MOZ_FAST_PACKAGE=1 install:: @echo "Mobile can't be installed directly." From 95251b7169e1e7f76eac1e728ff8a7be6dfbeadf Mon Sep 17 00:00:00 2001 From: Richard Newman Date: Thu, 3 May 2012 12:08:35 -0700 Subject: [PATCH 4/4] Bug 718153 - Match Fennec's history URL blacklist. r=liuche, a=blocking-fennec --- ...roidBrowserBookmarksRepositorySession.java | 2 +- ...ndroidBrowserHistoryRepositorySession.java | 14 +++++- .../AndroidBrowserRepositorySession.java | 2 +- .../sync/repositories/android/RepoUtils.java | 43 ++++++++++++++++++- 4 files changed, 56 insertions(+), 5 deletions(-) diff --git a/mobile/android/base/sync/repositories/android/AndroidBrowserBookmarksRepositorySession.java b/mobile/android/base/sync/repositories/android/AndroidBrowserBookmarksRepositorySession.java index fde1dc60926..a83765178bd 100644 --- a/mobile/android/base/sync/repositories/android/AndroidBrowserBookmarksRepositorySession.java +++ b/mobile/android/base/sync/repositories/android/AndroidBrowserBookmarksRepositorySession.java @@ -498,7 +498,7 @@ public class AndroidBrowserBookmarksRepositorySession extends AndroidBrowserRepo } @Override - protected boolean shouldIgnore(Record record) { + public boolean shouldIgnore(Record record) { if (!(record instanceof BookmarkRecord)) { return true; } diff --git a/mobile/android/base/sync/repositories/android/AndroidBrowserHistoryRepositorySession.java b/mobile/android/base/sync/repositories/android/AndroidBrowserHistoryRepositorySession.java index df7a559b120..0e1dce52af5 100644 --- a/mobile/android/base/sync/repositories/android/AndroidBrowserHistoryRepositorySession.java +++ b/mobile/android/base/sync/repositories/android/AndroidBrowserHistoryRepositorySession.java @@ -70,6 +70,18 @@ public class AndroidBrowserHistoryRepositorySession extends AndroidBrowserReposi return hist.histURI; } + @Override + public boolean shouldIgnore(Record record) { + if (super.shouldIgnore(record)) { + return true; + } + if (!(record instanceof HistoryRecord)) { + return true; + } + HistoryRecord r = (HistoryRecord) record; + return !RepoUtils.isValidHistoryURI(r.histURI); + } + @Override protected Record transformRecord(Record record) throws NullCursorException { return addVisitsToRecord(record); @@ -242,4 +254,4 @@ public class AndroidBrowserHistoryRepositorySession extends AndroidBrowserReposi } }); } -} \ No newline at end of file +} diff --git a/mobile/android/base/sync/repositories/android/AndroidBrowserRepositorySession.java b/mobile/android/base/sync/repositories/android/AndroidBrowserRepositorySession.java index 81af3d72713..94e6efdef91 100644 --- a/mobile/android/base/sync/repositories/android/AndroidBrowserRepositorySession.java +++ b/mobile/android/base/sync/repositories/android/AndroidBrowserRepositorySession.java @@ -91,7 +91,7 @@ public abstract class AndroidBrowserRepositorySession extends StoreTrackingRepos * * For example, a session subclass might skip records of an unsupported type. */ - protected boolean shouldIgnore(Record record) { + public boolean shouldIgnore(Record record) { return false; } diff --git a/mobile/android/base/sync/repositories/android/RepoUtils.java b/mobile/android/base/sync/repositories/android/RepoUtils.java index 9c00af623a9..c838adcf352 100644 --- a/mobile/android/base/sync/repositories/android/RepoUtils.java +++ b/mobile/android/base/sync/repositories/android/RepoUtils.java @@ -119,6 +119,45 @@ public class RepoUtils { } } + /** + * Return true if the provided URI is non-empty and acceptable to Fennec + * (i.e., not an undesirable scheme). + * + * This code is pilfered from Fennec, which pilfered from Places. + */ + public static boolean isValidHistoryURI(String uri) { + if (uri == null || uri.length() == 0) { + return false; + } + + // First, check the most common cases (HTTP, HTTPS) to avoid most of the work. + if (uri.startsWith("http:") || uri.startsWith("https:")) { + return true; + } + + String scheme = Uri.parse(uri).getScheme(); + if (scheme == null) { + return false; + } + + // Now check for all bad things. + if (scheme.equals("about") || + scheme.equals("imap") || + scheme.equals("news") || + scheme.equals("mailbox") || + scheme.equals("moz-anno") || + scheme.equals("view-source") || + scheme.equals("chrome") || + scheme.equals("resource") || + scheme.equals("data") || + scheme.equals("wyciwyg") || + scheme.equals("javascript")) { + return false; + } + + return true; + } + /** * Create a HistoryRecord object from a cursor row. * @@ -133,8 +172,8 @@ public class RepoUtils { } final String historyURI = getStringFromCursor(cur, BrowserContract.History.URL); - if (historyURI == null || (historyURI.length() == 0)) { - Logger.debug(LOG_TAG, "Skipping history record " + guid + " with null or empty URI."); + if (!isValidHistoryURI(historyURI)) { + Logger.debug(LOG_TAG, "Skipping history record " + guid + " with unwanted/invalid URI " + historyURI); return null; }