Commit 58c0eb9c authored by Mario Sanchez Prada's avatar Mario Sanchez Prada Committed by Commit Bot

New script to downgrade .mojom files from the new to the old mojo types

Following the discussion in chromium-mojo and platform-architecture-dev,
we're proposing to add this script to the chromium repository so that
external repositories that still depend on the old mojo types (e.g.
Android's and ChromeOS's libchrome repos) have a simple and maintained
way to downgrade Chromium's .mojom files to the old syntax, while they
can't support the new one.

This CL includes a new mojom_types_downgrader.py script that can be
integrates with those external builds requiring it, plus the necessary
unit tests to guarantee that the downgraded files can still be parsed
correctly by the bindings generator (i.e. mojom_bindings_generator.py).

For extra context, see the relevant discussion in the chromium-mojo ML:
https://groups.google.com/a/chromium.org/d/msg/chromium-mojo/BRK0Xeu7bgQ/z00hkpaGEQAJ

Bug: 1035484
Change-Id: I4c92345e82a188052b06efce9a1bc749d561cca1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2041759
Commit-Queue: Mario Sanchez Prada <mario@igalia.com>
Reviewed-by: default avatarKen Rockot <rockot@google.com>
Cr-Commit-Position: refs/heads/master@{#745386}
parent b3e60c3d
...@@ -34,6 +34,7 @@ source_set("tests") { ...@@ -34,6 +34,7 @@ source_set("tests") {
"message_queue.h", "message_queue.h",
"message_quota_checker_unittest.cc", "message_quota_checker_unittest.cc",
"message_unittest.cc", "message_unittest.cc",
"mojom_types_downgrader_unittest.cc",
"multiplex_router_unittest.cc", "multiplex_router_unittest.cc",
"native_struct_unittest.cc", "native_struct_unittest.cc",
"new_endpoint_types_unittest.cc", "new_endpoint_types_unittest.cc",
...@@ -61,6 +62,7 @@ source_set("tests") { ...@@ -61,6 +62,7 @@ source_set("tests") {
] ]
deps = [ deps = [
":downgraded_mojom",
":mojo_public_bindings_test_utils", ":mojo_public_bindings_test_utils",
":test_extra_cpp_template_mojom", ":test_extra_cpp_template_mojom",
":test_mojom", ":test_mojom",
...@@ -209,3 +211,20 @@ mojom("generated_test_mojom") { ...@@ -209,3 +211,20 @@ mojom("generated_test_mojom") {
sources = [ "$target_gen_dir/generated.test-mojom" ] sources = [ "$target_gen_dir/generated.test-mojom" ]
parser_deps = [ ":generate_test_mojom" ] parser_deps = [ ":generate_test_mojom" ]
} }
action("mojom_types_downgrader") {
script = "//mojo/public/tools/bindings/mojom_types_downgrader.py"
sources = [ "module_to_downgrade.test-mojom" ]
outputs = [ "$target_gen_dir/module_to_downgrade.test-mojom" ]
args = [
"--outdir",
rebase_path(target_gen_dir),
rebase_path("module_to_downgrade.test-mojom"),
]
}
mojom("downgraded_mojom") {
testonly = true
sources = [ "$target_gen_dir/module_to_downgrade.test-mojom" ]
parser_deps = [ ":mojom_types_downgrader" ]
}
module mojo.test.mojom_types_downgrader_unittest.mojom;
interface Foo {
DummyMethod();
};
interface DowngradedTestInterface {
// Old Mojo Types
InterfaceRequest(Foo& request);
InterfacePtr(Foo ptr);
AssociatedInterfacePtrInfo(associated Foo associated_ptr_info);
AssociatedInterfaceRequest(associated Foo& associated_request);
// New Mojo types
PendingReceiver(pending_receiver<Foo> receiver);
PendingRemote(pending_remote<Foo> remote);
PendingAssociatedReceiver(pending_associated_receiver<Foo> associated_remote);
PendingAssociatedRemote(pending_associated_remote<Foo> associated_receiver);
// Multiple parameters in both one line or across multiple lines
MultipleParams2(pending_remote<Foo> remote, pending_receiver<Foo> receiver);
MultipleParams3(pending_remote<Foo> remote, pending_receiver<Foo> receiver,
pending_associated_remote<Foo> associated_remote);
MultipleParams4(pending_remote<Foo> remote, pending_receiver<Foo> receiver,
pending_associated_remote<Foo> associated_remote,
pending_associated_receiver<Foo> associated_receiver);
// Methods with a response callback defined
MethodWithResponseCallbackOneLine(pending_remote<Foo> data) => ();
MethodWithResponseCallbackTwoLines(pending_remote<Foo> data)
=> (pending_receiver<Foo> receiver);
// Odd number of spaces and line breaks and
OddSpaces( pending_remote < Foo > remote, pending_receiver<Foo > receiver);
OddSpacesAndLineBreak( pending_remote < Foo > remote, pending_receiver<
Foo > receiver);
};
// Copyright 2020 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.
#include "base/bind.h"
#include "base/callback.h"
#include "mojo/public/cpp/bindings/tests/module_to_downgrade.test-mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace mojo {
namespace test {
namespace mojom_types_downgrader_unittest {
class DowngradedTestInterfaceImpl : public mojom::DowngradedTestInterface {
public:
DowngradedTestInterfaceImpl() = default;
~DowngradedTestInterfaceImpl() override = default;
void InterfaceRequest(mojom::FooRequest request) override {}
void InterfacePtr(mojom::FooPtr ptr) override {}
void AssociatedInterfacePtrInfo(
mojom::FooAssociatedPtrInfo associated_ptr_info) override {}
void AssociatedInterfaceRequest(
mojom::FooAssociatedRequest associated_request) override {}
void PendingReceiver(mojom::FooRequest receiver) override {}
void PendingRemote(mojom::FooPtr remote) override {}
void PendingAssociatedReceiver(
mojom::FooAssociatedRequest associated_remote) override {}
void PendingAssociatedRemote(
mojom::FooAssociatedPtrInfo associated_receiver) override {}
void MultipleParams2(mojom::FooPtr remote,
mojom::FooRequest receiver) override {}
void MultipleParams3(mojom::FooPtr remote,
mojom::FooRequest receiver,
mojom::FooAssociatedPtrInfo associated_remote) override {
}
void MultipleParams4(
mojom::FooPtr remote,
mojom::FooRequest receiver,
mojom::FooAssociatedPtrInfo associated_remote,
mojom::FooAssociatedRequest associated_receiver) override {}
void MethodWithResponseCallbackOneLine(
mojom::FooPtr data,
MethodWithResponseCallbackOneLineCallback callback) override {}
void MethodWithResponseCallbackTwoLines(
mojom::FooPtr data,
MethodWithResponseCallbackTwoLinesCallback callback) override {}
void OddSpaces(mojom::FooPtr remote, mojom::FooRequest receiver) override {}
void OddSpacesAndLineBreak(mojom::FooPtr remote,
mojom::FooRequest receiver) override {}
};
using DowngradedInterfaceTest = testing::Test;
TEST_F(DowngradedInterfaceTest, DowngradedInterfaceCompiles) {
// Simply check that this test compiles (it will fail to compile if the
// mojom_types_downgrader.py script failed to produce the right output).
DowngradedTestInterfaceImpl test;
// Methods already declared with the old types in the mojom interface.
base::OnceCallback<void(mojom::FooRequest)> foo_request_callback =
base::BindOnce(&mojom_types_downgrader_unittest::mojom::
DowngradedTestInterface::InterfaceRequest,
base::Unretained(&test));
base::OnceCallback<void(mojom::FooPtr)> foo_ptr_callback =
base::BindOnce(&mojom_types_downgrader_unittest::mojom::
DowngradedTestInterface::InterfacePtr,
base::Unretained(&test));
base::OnceCallback<void(mojom::FooAssociatedPtrInfo)>
foo_associated_ptr_info_callback = base::BindOnce(
&mojom_types_downgrader_unittest::mojom::DowngradedTestInterface::
AssociatedInterfacePtrInfo,
base::Unretained(&test));
base::OnceCallback<void(mojom::FooAssociatedRequest)>
foo_associated_request_callback = base::BindOnce(
&mojom_types_downgrader_unittest::mojom::DowngradedTestInterface::
AssociatedInterfaceRequest,
base::Unretained(&test));
// Methods declared with the new types in the mojom interface. Note that these
// assignments won't compile unless the module_to_downgrade.test-mojom has
// been properly downgraded via the mojom_types_downgrader.py script.
base::OnceCallback<void(mojom::FooRequest)> foo_pending_receiver_callback =
base::BindOnce(&mojom_types_downgrader_unittest::mojom::
DowngradedTestInterface::PendingReceiver,
base::Unretained(&test));
base::OnceCallback<void(mojom::FooPtr)> foo_pending_remote_callback =
base::BindOnce(&mojom_types_downgrader_unittest::mojom::
DowngradedTestInterface::PendingRemote,
base::Unretained(&test));
base::OnceCallback<void(mojom::FooAssociatedRequest)>
foo_pending_associated_receiver_callback =
base::BindOnce(&mojom_types_downgrader_unittest::mojom::
DowngradedTestInterface::PendingAssociatedReceiver,
base::Unretained(&test));
base::OnceCallback<void(mojom::FooAssociatedPtrInfo)>
foo_pending_associated_remote_callback =
base::BindOnce(&mojom_types_downgrader_unittest::mojom::
DowngradedTestInterface::PendingAssociatedRemote,
base::Unretained(&test));
}
} // namespace mojom_types_downgrader_unittest
} // namespace test
} // namespace mojo
#!/usr/bin/env python
# Copyright 2020 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.
"""Downgrades *.mojom files to the old mojo types for remotes and receivers."""
import argparse
import fnmatch
import os
import re
import shutil
import sys
import tempfile
# List of patterns and replacements to match and use against the contents of a
# mojo file. Each replacement string will be used with Python string's format()
# function, so the '{}' substring is used to mark where the mojo type should go.
_MOJO_REPLACEMENTS = {
r'pending_remote': r'{}',
r'pending_receiver': r'{}&',
r'pending_associated_remote': r'associated {}',
r'pending_associated_receiver': r'associated {}&',
}
# Pre-compiled regular expression that matches against any of the replacements.
_REGEXP_PATTERN = re.compile(
r'|'.join(
['{}\s*<\s*(.*?)\s*>'.format(k) for k in _MOJO_REPLACEMENTS.keys()]),
flags=re.DOTALL)
def ReplaceFunction(match_object):
"""Returns the right replacement for the string matched against the regexp."""
for index, (match, repl) in enumerate(_MOJO_REPLACEMENTS.items(), 1):
if match_object.group(0).startswith(match):
return repl.format(match_object.group(index))
def DowngradeFile(path, output_dir=None):
"""Downgrades the mojom file specified by |path| to the old mojo types.
Optionally pass |output_dir| to place the result under a separate output
directory, preserving the relative path to the file included in |path|.
"""
# Use a temporary file to dump the new contents after replacing the patterns.
with open(path) as src_mojo_file:
with tempfile.NamedTemporaryFile(mode='w', delete=False) as tmp_mojo_file:
tmp_contents = _REGEXP_PATTERN.sub(ReplaceFunction, src_mojo_file.read())
tmp_mojo_file.write(tmp_contents)
# Files should be placed in the desired output directory
if output_dir:
output_filepath = os.path.join(output_dir, os.path.basename(path))
if not os.path.exists(output_dir):
os.makedirs(output_dir)
else:
output_filepath = path
# Write the new contents preserving the original file's attributes.
shutil.copystat(path, tmp_mojo_file.name)
shutil.move(tmp_mojo_file.name, output_filepath)
def DowngradeDirectory(path, output_dir=None):
"""Downgrades mojom files inside directory |path| to the old mojo types.
Optionally pass |output_dir| to place the result under a separate output
directory, preserving the relative path to the file included in |path|.
"""
# We don't have recursive glob.glob() nor pathlib.Path.rglob() in Python 2.7
mojom_filepaths = []
for dir_path, _, filenames in os.walk(path):
for filename in fnmatch.filter(filenames, "*mojom"):
mojom_filepaths.append(os.path.join(dir_path, filename))
for path in mojom_filepaths:
absolute_dirpath = os.path.dirname(os.path.abspath(path))
if output_dir:
dest_dirpath = output_dir + absolute_dirpath
else:
dest_dirpath = absolute_dirpath
DowngradeFile(path, dest_dirpath)
def DowngradePath(src_path, output_dir=None):
"""Downgrades the mojom files pointed by |src_path| to the old mojo types.
Optionally pass |output_dir| to place the result under a separate output
directory, preserving the relative path to the file included in |path|.
"""
if os.path.isdir(src_path):
DowngradeDirectory(src_path, output_dir)
elif os.path.isfile(src_path):
DowngradeFile(src_path, output_dir)
else:
print(">>> {} not pointing to a valid file or directory".format(src_path))
sys.exit(1)
def main():
parser = argparse.ArgumentParser(
description="Downgrade *.mojom files to use the old mojo types.")
parser.add_argument(
"srcpath", help="path to the file or directory to apply the conversion")
parser.add_argument(
"--outdir", help="the directory to place the converted file(s) under")
args = parser.parse_args()
DowngradePath(args.srcpath, args.outdir)
if __name__ == "__main__":
sys.exit(main())
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment