Check for stale licenses.json in minilints
+ Add an anki_process library with some helpers for command running.
This commit is contained in:
parent
84b3abab6c
commit
dd95f6f749
11
Cargo.lock
generated
11
Cargo.lock
generated
@ -200,6 +200,14 @@ dependencies = [
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anki_process"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"snafu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anki_proto"
|
||||
version = "0.0.0"
|
||||
@ -2331,6 +2339,8 @@ dependencies = [
|
||||
name = "minilints"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anki_io",
|
||||
"anki_process",
|
||||
"anyhow",
|
||||
"camino",
|
||||
"once_cell",
|
||||
@ -5059,6 +5069,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"snafu",
|
||||
"snafu-derive",
|
||||
"syn 1.0.109",
|
||||
"syn 2.0.12",
|
||||
"time",
|
||||
|
@ -13,6 +13,7 @@ members = [
|
||||
"rslib/linkchecker",
|
||||
"rslib/proto",
|
||||
"rslib/io",
|
||||
"rslib/process",
|
||||
"pylib/rsbridge",
|
||||
"build/configure",
|
||||
"build/ninja_gen",
|
||||
|
@ -185,6 +185,10 @@ pub fn check_minilints(build: &mut Build) -> Result<()> {
|
||||
"$minilints_bin $fix"
|
||||
}
|
||||
|
||||
fn bypass_runner(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn files(&mut self, build: &mut impl FilesHandle) {
|
||||
build.add_inputs("minilints_bin", inputs![":build:minilints"]);
|
||||
build.add_inputs("", &self.deps);
|
||||
@ -206,10 +210,13 @@ pub fn check_minilints(build: &mut Build) -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
let files = inputs![glob![
|
||||
"**/*.{py,rs,ts,svelte,mjs}",
|
||||
"{node_modules,qt/bundle/PyOxidizer}/**"
|
||||
]];
|
||||
let files = inputs![
|
||||
glob![
|
||||
"**/*.{py,rs,ts,svelte,mjs}",
|
||||
"{node_modules,qt/bundle/PyOxidizer}/**"
|
||||
],
|
||||
"Cargo.lock"
|
||||
];
|
||||
|
||||
build.add_action(
|
||||
"check:minilints",
|
||||
|
@ -1,5 +1,4 @@
|
||||
This folder used to contain Bazel-specific Rust integration, but now only
|
||||
contains:
|
||||
This folder contains:
|
||||
|
||||
- our license-checking script, which should be run when using cargo update.
|
||||
- a list of Rust crate licenses, which is checked/updated with ./ninja [check|fix]:minilints
|
||||
- a nightly toolchain definition for formatting
|
||||
|
@ -1637,15 +1637,6 @@
|
||||
"license_file": null,
|
||||
"description": "A Rust crate for producing string-representations of numbers, formatted according to international standards"
|
||||
},
|
||||
{
|
||||
"name": "num-integer",
|
||||
"version": "0.1.45",
|
||||
"authors": "The Rust Project Developers",
|
||||
"repository": "https://github.com/rust-num/num-integer",
|
||||
"license": "Apache-2.0 OR MIT",
|
||||
"license_file": null,
|
||||
"description": "Integer traits and functions"
|
||||
},
|
||||
{
|
||||
"name": "num-traits",
|
||||
"version": "0.2.15",
|
||||
|
@ -1,8 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
cargo install cargo-license@0.5.1
|
||||
cargo-license --features rustls --features native-tls --json --manifest-path ../rslib/Cargo.toml >licenses.json
|
||||
|
||||
cargo install cargo-deny@0.13.5
|
||||
(cd .. && cargo deny check -A duplicate && cargo hakari generate)
|
||||
|
@ -75,6 +75,14 @@ pub fn read_file(path: impl AsRef<Path>) -> Result<Vec<u8>> {
|
||||
})
|
||||
}
|
||||
|
||||
/// See [std::fs::read_to_string].
|
||||
pub fn read_to_string(path: impl AsRef<Path>) -> Result<String> {
|
||||
std::fs::read_to_string(&path).context(FileIoSnafu {
|
||||
path: path.as_ref(),
|
||||
op: FileOp::Read,
|
||||
})
|
||||
}
|
||||
|
||||
/// Like [read_file], but skips the section that is potentially locked by
|
||||
/// SQLite.
|
||||
pub fn read_locked_db_file(path: impl AsRef<Path>) -> Result<Vec<u8>> {
|
||||
|
14
rslib/process/Cargo.toml
Normal file
14
rslib/process/Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "anki_process"
|
||||
publish = false
|
||||
description = "Utils for better process error reporting"
|
||||
|
||||
version.workspace = true
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
itertools = "0.10.5"
|
||||
snafu = "0.7.4"
|
126
rslib/process/src/lib.rs
Normal file
126
rslib/process/src/lib.rs
Normal file
@ -0,0 +1,126 @@
|
||||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
use std::ffi::OsStr;
|
||||
use std::process::Command;
|
||||
use std::string::FromUtf8Error;
|
||||
|
||||
use itertools::Itertools;
|
||||
use snafu::ensure;
|
||||
use snafu::ResultExt;
|
||||
use snafu::Snafu;
|
||||
|
||||
#[derive(Debug, Snafu)]
|
||||
pub enum Error {
|
||||
DidNotExecute {
|
||||
cmdline: String,
|
||||
source: std::io::Error,
|
||||
},
|
||||
ReturnedError {
|
||||
cmdline: String,
|
||||
code: Option<i32>,
|
||||
},
|
||||
InvalidUtf8 {
|
||||
cmdline: String,
|
||||
source: FromUtf8Error,
|
||||
},
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
pub struct Utf8Output {
|
||||
pub stdout: String,
|
||||
pub stderr: String,
|
||||
}
|
||||
|
||||
pub trait CommandExt {
|
||||
fn run<I, S>(cmd_and_args: I) -> Result<()>
|
||||
where
|
||||
I: IntoIterator<Item = S>,
|
||||
S: AsRef<OsStr>,
|
||||
{
|
||||
let mut all_args = cmd_and_args.into_iter();
|
||||
Command::new(all_args.next().unwrap())
|
||||
.args(all_args)
|
||||
.ensure_success()?;
|
||||
Ok(())
|
||||
}
|
||||
fn run_with_output<I, S>(cmd_and_args: I) -> Result<Utf8Output>
|
||||
where
|
||||
I: IntoIterator<Item = S>,
|
||||
S: AsRef<OsStr>,
|
||||
{
|
||||
let mut all_args = cmd_and_args.into_iter();
|
||||
Command::new(all_args.next().unwrap())
|
||||
.args(all_args)
|
||||
.utf8_output()
|
||||
}
|
||||
|
||||
fn ensure_success(&mut self) -> Result<&mut Self>;
|
||||
fn utf8_output(&mut self) -> Result<Utf8Output>;
|
||||
}
|
||||
|
||||
impl CommandExt for Command {
|
||||
fn ensure_success(&mut self) -> Result<&mut Self> {
|
||||
let status = self.status().with_context(|_| DidNotExecuteSnafu {
|
||||
cmdline: get_cmdline(self),
|
||||
})?;
|
||||
ensure!(
|
||||
status.success(),
|
||||
ReturnedSnafu {
|
||||
cmdline: get_cmdline(self),
|
||||
code: status.code(),
|
||||
}
|
||||
);
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn utf8_output(&mut self) -> Result<Utf8Output> {
|
||||
let output = self.output().with_context(|_| DidNotExecuteSnafu {
|
||||
cmdline: get_cmdline(self),
|
||||
})?;
|
||||
ensure!(
|
||||
output.status.success(),
|
||||
ReturnedSnafu {
|
||||
cmdline: get_cmdline(self),
|
||||
code: output.status.code(),
|
||||
}
|
||||
);
|
||||
Ok(Utf8Output {
|
||||
stdout: String::from_utf8(output.stdout).with_context(|_| InvalidUtf8Snafu {
|
||||
cmdline: get_cmdline(self),
|
||||
})?,
|
||||
stderr: String::from_utf8(output.stderr).with_context(|_| InvalidUtf8Snafu {
|
||||
cmdline: get_cmdline(self),
|
||||
})?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn get_cmdline(arg: &mut Command) -> String {
|
||||
[arg.get_program().to_string_lossy()]
|
||||
.into_iter()
|
||||
.chain(arg.get_args().map(|arg| arg.to_string_lossy()))
|
||||
.join(" ")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_run() {
|
||||
assert!(matches!(
|
||||
Command::run(["fakefake", "1", "2"]),
|
||||
Err(Error::DidNotExecute {
|
||||
cmdline,
|
||||
..
|
||||
}) if cmdline == "fakefake 1 2"
|
||||
));
|
||||
#[cfg(not(windows))]
|
||||
assert!(matches!(
|
||||
Command::new("false").ensure_success(),
|
||||
Err(Error::ReturnedError { code: Some(1), .. })
|
||||
));
|
||||
}
|
||||
}
|
@ -9,6 +9,8 @@ license.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
anki_io = { version = "0.0.0", path = "../../rslib/io" }
|
||||
anki_process = { version = "0.0.0", path = "../../rslib/process" }
|
||||
anyhow = "1.0.71"
|
||||
camino = "1.1.4"
|
||||
once_cell = "1.17.1"
|
||||
|
@ -10,6 +10,9 @@ use std::io::Write;
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
|
||||
use anki_io::read_to_string;
|
||||
use anki_io::write_file;
|
||||
use anki_process::CommandExt;
|
||||
use anyhow::Context;
|
||||
use anyhow::Result;
|
||||
use camino::Utf8Path;
|
||||
@ -43,6 +46,7 @@ fn main() -> Result<()> {
|
||||
let want_fix = env::args().nth(1) == Some("fix".to_string());
|
||||
let mut ctx = LintContext::new(want_fix);
|
||||
ctx.check_contributors()?;
|
||||
ctx.check_rust_licenses()?;
|
||||
ctx.walk_folders(Path::new("."))?;
|
||||
if ctx.found_problems {
|
||||
std::process::exit(1);
|
||||
@ -147,7 +151,6 @@ impl LintContext {
|
||||
println!("Dependabot whitelisted.");
|
||||
return Ok(());
|
||||
} else if all_contributors.contains(last_author.as_str()) {
|
||||
println!("Author found in CONTRIBUTORS");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@ -175,6 +178,35 @@ impl LintContext {
|
||||
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
fn check_rust_licenses(&mut self) -> Result<()> {
|
||||
let license_path = Path::new("cargo/licenses.json");
|
||||
let licenses = generate_licences()?;
|
||||
let existing_licenses = read_to_string(license_path)?;
|
||||
if licenses != existing_licenses {
|
||||
if self.want_fix {
|
||||
check_cargo_deny()?;
|
||||
update_hakari()?;
|
||||
write_file(license_path, licenses)?;
|
||||
} else {
|
||||
println!("cargo/licenses.json is out of date; run ./ninja fix:minilints");
|
||||
self.found_problems = true;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn check_cargo_deny() -> Result<()> {
|
||||
Command::run(["cargo", "install", "-q", "cargo-deny@0.13.5"])?;
|
||||
Command::run(["cargo", "deny", "check", "-A", "duplicate"])?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_hakari() -> Result<()> {
|
||||
Command::run(["cargo", "install", "-q", "cargo-hakari@0.9.23"])?;
|
||||
Command::run(["cargo", "hakari", "generate"])?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn head_of_file(path: &Utf8Path) -> Result<String> {
|
||||
@ -223,3 +255,18 @@ fn check_for_unstaged_changes() {
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_licences() -> Result<String> {
|
||||
Command::run(["cargo", "install", "-q", "cargo-license@0.5.1"])?;
|
||||
let output = Command::run_with_output([
|
||||
"cargo-license",
|
||||
"--features",
|
||||
"rustls",
|
||||
"--features",
|
||||
"native-tls",
|
||||
"--json",
|
||||
"--manifest-path",
|
||||
"rslib/Cargo.toml",
|
||||
])?;
|
||||
Ok(output.stdout)
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ scopeguard = { version = "1" }
|
||||
serde = { version = "1", features = ["alloc", "derive", "rc"] }
|
||||
serde_json = { version = "1", features = ["raw_value"] }
|
||||
sha2 = { version = "0.10" }
|
||||
snafu = { version = "0.7", features = ["backtraces"] }
|
||||
snafu = { version = "0.7", features = ["backtraces", "rust_1_61"] }
|
||||
time = { version = "0.3", features = ["formatting", "parsing"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tokio-util = { version = "0.7", features = ["codec", "io"] }
|
||||
@ -80,7 +80,8 @@ scopeguard = { version = "1" }
|
||||
serde = { version = "1", features = ["alloc", "derive", "rc"] }
|
||||
serde_json = { version = "1", features = ["raw_value"] }
|
||||
sha2 = { version = "0.10" }
|
||||
snafu = { version = "0.7", features = ["backtraces"] }
|
||||
snafu = { version = "0.7", features = ["backtraces", "rust_1_61"] }
|
||||
snafu-derive = { version = "0.7", default-features = false, features = ["rust_1_39", "rust_1_46", "rust_1_61"] }
|
||||
syn-dff4ba8e3ae991db = { package = "syn", version = "1", features = ["extra-traits", "fold", "full", "visit", "visit-mut"] }
|
||||
syn-f595c2ba2a3f28df = { package = "syn", version = "2", features = ["extra-traits", "full", "visit-mut"] }
|
||||
time = { version = "0.3", features = ["formatting", "parsing"] }
|
||||
|
Loading…
Reference in New Issue
Block a user