| #!/usr/bin/env python3 | |
| # Copyright 2021 The ChromiumOS Authors | |
| # Use of this source code is governed by a BSD-style license that can be | |
| # found in the LICENSE file. | |
| """Linter for *.mojom files.""" | |
| import json | |
| import os | |
| from pathlib import Path | |
| _HACK_VAR_TO_DISABLE_ISORT = "hack" | |
| # pylint: disable=wrong-import-position | |
| import chromite_init # pylint: disable=unused-import | |
| from chromite.lib import commandline | |
| from chromite.lib import constants | |
| from chromite.lib import cros_build_lib | |
| from chromite.lib import git | |
| TOP_DIR = Path(__file__).resolve().parent.parent | |
| CHECK_STABLE_MOJOM_COMPATIBILITY = os.path.join( | |
| constants.SOURCE_ROOT, | |
| "src", | |
| "platform", | |
| "libchrome", | |
| "mojo", | |
| "public", | |
| "tools", | |
| "mojom", | |
| "check_stable_mojom_compatibility.py", | |
| ) | |
| def GetDiffFiles(from_commit, to_commit): | |
| """Returns the changed file list.""" | |
| cmd = ["diff", "--name-only", from_commit, to_commit] | |
| res = git.RunGit(TOP_DIR, cmd) | |
| return res.stdout.splitlines() | |
| def GetRenameMap(from_commit, to_commit): | |
| """Returns a new name to old name mapping for renamed files.""" | |
| cmd = ["diff", "--name-status", "--diff-filter=R", from_commit, to_commit] | |
| res = git.RunGit(TOP_DIR, cmd) | |
| rename_map = {} | |
| for line in res.stdout.splitlines(): | |
| tokens = line.split("\t") | |
| rename_map[tokens[2]] = tokens[1] | |
| return rename_map | |
| def GetFileContent(commit, file): | |
| """Returns the content of a file in a commit.""" | |
| cmd = ["show", f"{commit}:{file}"] | |
| res = git.RunGit(TOP_DIR, cmd, check=False) | |
| return "" if res.returncode else res.stdout | |
| def CheckMojoStable(commit): | |
| """Checks if the mojom files follow the stable rules.""" | |
| last_commit = f"{commit}^" | |
| rename_map = GetRenameMap(last_commit, commit) | |
| delta = [] | |
| for file in GetDiffFiles(last_commit, commit): | |
| if not file.endswith(".mojom"): | |
| continue | |
| old_file = rename_map.get(file, file) | |
| old_file_content = GetFileContent(last_commit, old_file) | |
| new_file_content = GetFileContent(commit, file) | |
| if old_file != file: | |
| delta += [ | |
| { | |
| "filename": old_file, | |
| "old": old_file_content, | |
| "new": None, | |
| }, | |
| { | |
| "filename": file, | |
| "old": None, | |
| "new": new_file_content, | |
| }, | |
| ] | |
| else: | |
| delta.append( | |
| { | |
| "filename": file, | |
| "old": old_file_content, | |
| "new": new_file_content, | |
| } | |
| ) | |
| cmd = [CHECK_STABLE_MOJOM_COMPATIBILITY, "--src-root", TOP_DIR] | |
| res = cros_build_lib.run(cmd, input=json.dumps(delta), check=False) | |
| if res.returncode: | |
| cros_build_lib.Die("Please fix the mojom error.") | |
| def GetParser(): | |
| """Returns an argument parser.""" | |
| parser = commandline.ArgumentParser(description=__doc__) | |
| parser.add_argument( | |
| "--commit", | |
| required=True, | |
| help="The git commit to be checked. " | |
| 'Pass "pre-submit" for the pre-submit check.', | |
| ) | |
| return parser | |
| def main(argv): | |
| parser = GetParser() | |
| opts = parser.parse_args(argv) | |
| opts.Freeze() | |
| # If we are running a pre-submit check, check the HEAD. | |
| commit = opts.commit if opts.commit != "pre-submit" else "HEAD" | |
| return CheckMojoStable(commit) | |
| if __name__ == "__main__": | |
| commandline.ScriptWrapperMain(lambda _: main) |