diff options
Diffstat (limited to 'tools/migration/ctoolchain_comparator.py')
-rw-r--r-- | tools/migration/ctoolchain_comparator.py | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/tools/migration/ctoolchain_comparator.py b/tools/migration/ctoolchain_comparator.py new file mode 100644 index 0000000..5143e02 --- /dev/null +++ b/tools/migration/ctoolchain_comparator.py @@ -0,0 +1,127 @@ +# Copyright 2018 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +r"""A script that compares 2 CToolchains from proto format. + +This script accepts two files in either a CROSSTOOL proto text format or a +CToolchain proto text format. It then locates the CToolchains with the given +toolchain_identifier and checks if the resulting CToolchain objects in Java +are the same. + +Example usage: + +bazel run \ +@rules_cc//tools/migration:ctoolchain_comparator -- \ +--before=/path/to/CROSSTOOL1 \ +--after=/path/to/CROSSTOOL2 \ +--toolchain_identifier=id +""" + +import os +from absl import app +from absl import flags +from google.protobuf import text_format +from third_party.com.github.bazelbuild.bazel.src.main.protobuf import crosstool_config_pb2 +from tools.migration.ctoolchain_comparator_lib import compare_ctoolchains + +flags.DEFINE_string( + "before", None, + ("A text proto file containing the relevant CTooclchain before the change, " + "either a CROSSTOOL file or a single CToolchain proto text")) +flags.DEFINE_string( + "after", None, + ("A text proto file containing the relevant CToolchain after the change, " + "either a CROSSTOOL file or a single CToolchain proto text")) +flags.DEFINE_string("toolchain_identifier", None, + "The identifier of the CToolchain that is being compared.") +flags.mark_flag_as_required("before") +flags.mark_flag_as_required("after") + + +def _to_absolute_path(path): + path = os.path.expanduser(path) + if os.path.isabs(path): + return path + else: + if "BUILD_WORKING_DIRECTORY" in os.environ: + return os.path.join(os.environ["BUILD_WORKING_DIRECTORY"], path) + else: + return path + + +def _find_toolchain(crosstool, toolchain_identifier): + for toolchain in crosstool.toolchain: + if toolchain.toolchain_identifier == toolchain_identifier: + return toolchain + return None + + +def _read_crosstool_or_ctoolchain_proto(input_file, toolchain_identifier=None): + """Reads a proto file and finds the CToolchain with the given identifier.""" + with open(input_file, "r") as f: + text = f.read() + crosstool_release = crosstool_config_pb2.CrosstoolRelease() + c_toolchain = crosstool_config_pb2.CToolchain() + try: + text_format.Merge(text, crosstool_release) + if toolchain_identifier is None: + print("CROSSTOOL proto needs a 'toolchain_identifier' specified in " + "order to be able to select the right toolchain for comparison.") + return None + toolchain = _find_toolchain(crosstool_release, toolchain_identifier) + if toolchain is None: + print(("Cannot find a CToolchain with an identifier '%s' in CROSSTOOL " + "file") % toolchain_identifier) + return None + return toolchain + except text_format.ParseError as crosstool_error: + try: + text_format.Merge(text, c_toolchain) + if (toolchain_identifier is not None and + c_toolchain.toolchain_identifier != toolchain_identifier): + print(("Expected CToolchain with identifier '%s', got CToolchain with " + "identifier '%s'" % (toolchain_identifier, + c_toolchain.toolchain_identifier))) + return None + return c_toolchain + except text_format.ParseError as toolchain_error: + print(("Error parsing file '%s':" % input_file)) # pylint: disable=superfluous-parens + print("Attempt to parse it as a CROSSTOOL proto:") # pylint: disable=superfluous-parens + print(crosstool_error) # pylint: disable=superfluous-parens + print("Attempt to parse it as a CToolchain proto:") # pylint: disable=superfluous-parens + print(toolchain_error) # pylint: disable=superfluous-parens + return None + + +def main(unused_argv): + + before_file = _to_absolute_path(flags.FLAGS.before) + after_file = _to_absolute_path(flags.FLAGS.after) + toolchain_identifier = flags.FLAGS.toolchain_identifier + + toolchain_before = _read_crosstool_or_ctoolchain_proto( + before_file, toolchain_identifier) + toolchain_after = _read_crosstool_or_ctoolchain_proto(after_file, + toolchain_identifier) + + if not toolchain_before or not toolchain_after: + print("There was an error getting the required toolchains.") + exit(1) + + found_difference = compare_ctoolchains(toolchain_before, toolchain_after) + if found_difference: + exit(1) + + +if __name__ == "__main__": + app.run(main) |