blob: 1d4d7046f179ffbf141696a2f845bd252852e303 [file] [log] [blame]
// Copyright 2022 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.
use anyhow::{anyhow, Error};
use argh::FromArgs;
use std::{
env,
fs::File,
io::{self, BufRead, BufReader},
path::PathBuf,
process::Command,
};
mod allow;
mod fix;
mod lint;
mod owners;
mod span;
#[derive(Debug, FromArgs)]
/// Silence rustc and clippy lints with allow attributes and autofixes
struct Args {
#[argh(subcommand)]
action: Action,
/// don't modify source files
#[argh(switch)]
dryrun: bool,
/// modify files even if there are local uncommitted changes
#[argh(switch)]
force: bool,
/// lint (or category) to deal with e.g. clippy::needless_return
#[argh(option)]
lint: Vec<String>,
/// path to the root dir of the fuchsia source tree
#[argh(option)]
fuchsia_dir: Option<PathBuf>,
/// file containing json lints (uses stdin if not given)
#[argh(positional)]
lint_file: Option<PathBuf>,
}
#[derive(Debug, FromArgs)]
#[argh(subcommand)]
enum Action {
Fix(Fix),
Allow(Allow),
}
/// use rustfix to auto-fix the lints
#[derive(FromArgs, Debug)]
#[argh(subcommand, name = "fix")]
struct Fix {}
/// add allow attributes
#[derive(FromArgs, Debug)]
#[argh(subcommand, name = "allow")]
struct Allow {
/// emit markdown links rather than plaintext spans
#[argh(switch)]
markdown: bool,
}
fn main() -> Result<(), Error> {
let args: Args = argh::from_env();
if args.lint.is_empty() {
return Err(anyhow!("Must filter on at least one lint or category with '--lint'"));
}
let mut reader: Box<dyn BufRead> = if let Some(f) = &args.lint_file {
Box::new(BufReader::new(File::open(f).unwrap()))
} else {
Box::new(BufReader::new(io::stdin()))
};
let root = &args
.fuchsia_dir
.or_else(|| env::var("FUCHSIA_DIR").ok().map(Into::into))
.map(|d| {
env::set_current_dir(&d).expect("couldn't change dir");
d
})
.unwrap_or_else(|| std::env::current_dir().unwrap().canonicalize().unwrap());
let clean_tree = Command::new("jiri")
.args(["runp", "-exit-on-error", "git", "diff-index", "--quiet", "HEAD"])
.output()?
.status
.success();
if !(args.dryrun || args.force || clean_tree) {
return Err(anyhow!(
"The current directory is dirty, pass the --force flag or commit the local changes"
));
}
match args.action {
Action::Fix(_) => fix::fix(&mut reader, &args.lint, args.dryrun),
Action::Allow(Allow { markdown }) => {
allow::allow(&mut reader, &args.lint, &root, args.dryrun, markdown)
}
}
}