blob: ed4833b2fb0510ba784959b133cd103ef498b3fd [file] [log] [blame]
#!/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())