| #!/usr/bin/env python | |
| # Copyright 2019 The Fuchsia Authors. All rights reserved. | |
| # Use of this source code is governed by a BSD-style license that can be | |
| # found in the LICENSE file. | |
| ### Runs `cargo clippy` on a target or on a set of files. | |
| import argparse | |
| import json | |
| import os | |
| import subprocess | |
| import sys | |
| from contextlib import contextmanager | |
| import rust | |
| from rust import FUCHSIA_BUILD_DIR, HOST_PLATFORM, PREBUILT_THIRD_PARTY_DIR, \ | |
| get_rust_target_from_file | |
| PATH = os.environ["PATH"] | |
| THIRD_PARTY_DEPS_DATA = os.path.join( | |
| FUCHSIA_BUILD_DIR, 'rust_third_party_crates', 'deps_data.json') | |
| HOST_THIRD_PARTY_DEPS_DATA = os.path.join( | |
| FUCHSIA_BUILD_DIR, 'host_x64', 'rust_third_party_crates', 'deps_data.json') | |
| # Cargo args to ignore from the deps_data.json files. | |
| CARGO_IGNORE_ARGS = ['--frozen', '--locked'] | |
| @contextmanager | |
| def cwd(dir): | |
| previous = os.getcwd() | |
| os.chdir(dir) | |
| try: | |
| yield | |
| finally: | |
| os.chdir(previous) | |
| def main(): | |
| parser = argparse.ArgumentParser("Run cargo clippy on a file or target.") | |
| parser.add_argument( | |
| "--target", | |
| help="GN target on which to run clippy", | |
| default=None) | |
| parser.add_argument( | |
| "--file", | |
| dest="files", | |
| help="file on which to run clippy", | |
| action="append", | |
| default=[]) | |
| parser.add_argument( | |
| "-v", help="verbose", action="store_true", default=False) | |
| args = parser.parse_args() | |
| targets = set() | |
| if args.target: | |
| try: | |
| targets.add(rust.GnTarget(target)) | |
| except ValueError as e: | |
| # The target may not be a Rust one, so it's okay if it didn't find the Cargo.toml. | |
| if args.v: | |
| print "No Rust target found for %s: %s" % (target, e) | |
| for file in args.files: | |
| # Skip non-rust files. | |
| if not file.endswith(".rs"): | |
| continue | |
| try: | |
| target = get_rust_target_from_file(file) | |
| if not target: | |
| return 1 | |
| except ValueError as e: | |
| # The target should be a Rust one, so any error is bad. | |
| print "No Rust target found for %s: %s" % (file, e) | |
| return 1 | |
| targets.add(target) | |
| cargos = set() | |
| for target in targets: | |
| cargo = target.manifest_path(FUCHSIA_BUILD_DIR) | |
| if cargo and os.path.isfile(cargo): | |
| cargos.add(cargo) | |
| else: | |
| print "Cargo.toml file not found for %s, try running fx build." % target | |
| return 1 | |
| rust_tool_prebuilts = \ | |
| os.path.join(PREBUILT_THIRD_PARTY_DIR, "rust_tools", HOST_PLATFORM, "bin") | |
| rust_prebuilts = os.path.join(PREBUILT_THIRD_PARTY_DIR, "rust", HOST_PLATFORM, "bin") | |
| # The third_party build records the arguments it used to invoke cargo. Use the same ones for | |
| # the clippy invocation. | |
| third_party_deps_data = json.load(open(THIRD_PARTY_DEPS_DATA, 'r')) | |
| host_third_party_deps_data = json.load( | |
| open(HOST_THIRD_PARTY_DEPS_DATA, 'r')) | |
| env = {} | |
| env['PATH'] = ":".join([rust_tool_prebuilts, rust_prebuilts, PATH]) | |
| call_args = [ | |
| "cargo", | |
| "clippy", | |
| ] | |
| if args.v: | |
| call_args.append("-v") | |
| for cargo in cargos: | |
| if 'host_x64' in cargo: | |
| cargo_args = host_third_party_deps_data['cargo_args'] | |
| else: | |
| cargo_args = third_party_deps_data['cargo_args'] | |
| cargo_args = filter(lambda arg: arg not in CARGO_IGNORE_ARGS, cargo_args) | |
| # Some crates use #![deny(warnings)], which will cause clippy to fail entirely if it finds | |
| # issues in those crates. Cap all lints at `warn` to avoid this. | |
| cargo_args += ['--', '--cap-lints', 'warn'] | |
| if args.v: | |
| print " ".join(call_args + cargo_args) | |
| with cwd(os.path.dirname(cargo)): | |
| return subprocess.call(call_args + cargo_args, env=env) | |
| return 0 | |
| if __name__ == '__main__': | |
| sys.exit(main()) |