mirror of
https://github.com/ankitects/anki.git
synced 2025-09-19 06:22:22 -04:00
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
12 changed files with 226 additions and 27 deletions
11
Cargo.lock
generated
11
Cargo.lock
generated
|
@ -200,6 +200,14 @@ dependencies = [
|
||||||
"tempfile",
|
"tempfile",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anki_process"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"itertools",
|
||||||
|
"snafu",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anki_proto"
|
name = "anki_proto"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
@ -2331,6 +2339,8 @@ dependencies = [
|
||||||
name = "minilints"
|
name = "minilints"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"anki_io",
|
||||||
|
"anki_process",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"camino",
|
"camino",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
@ -5059,6 +5069,7 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha2",
|
"sha2",
|
||||||
"snafu",
|
"snafu",
|
||||||
|
"snafu-derive",
|
||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
"syn 2.0.12",
|
"syn 2.0.12",
|
||||||
"time",
|
"time",
|
||||||
|
|
|
@ -13,6 +13,7 @@ members = [
|
||||||
"rslib/linkchecker",
|
"rslib/linkchecker",
|
||||||
"rslib/proto",
|
"rslib/proto",
|
||||||
"rslib/io",
|
"rslib/io",
|
||||||
|
"rslib/process",
|
||||||
"pylib/rsbridge",
|
"pylib/rsbridge",
|
||||||
"build/configure",
|
"build/configure",
|
||||||
"build/ninja_gen",
|
"build/ninja_gen",
|
||||||
|
|
|
@ -185,6 +185,10 @@ pub fn check_minilints(build: &mut Build) -> Result<()> {
|
||||||
"$minilints_bin $fix"
|
"$minilints_bin $fix"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn bypass_runner(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn files(&mut self, build: &mut impl FilesHandle) {
|
fn files(&mut self, build: &mut impl FilesHandle) {
|
||||||
build.add_inputs("minilints_bin", inputs![":build:minilints"]);
|
build.add_inputs("minilints_bin", inputs![":build:minilints"]);
|
||||||
build.add_inputs("", &self.deps);
|
build.add_inputs("", &self.deps);
|
||||||
|
@ -206,10 +210,13 @@ pub fn check_minilints(build: &mut Build) -> Result<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let files = inputs![glob![
|
let files = inputs![
|
||||||
|
glob![
|
||||||
"**/*.{py,rs,ts,svelte,mjs}",
|
"**/*.{py,rs,ts,svelte,mjs}",
|
||||||
"{node_modules,qt/bundle/PyOxidizer}/**"
|
"{node_modules,qt/bundle/PyOxidizer}/**"
|
||||||
]];
|
],
|
||||||
|
"Cargo.lock"
|
||||||
|
];
|
||||||
|
|
||||||
build.add_action(
|
build.add_action(
|
||||||
"check:minilints",
|
"check:minilints",
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
This folder used to contain Bazel-specific Rust integration, but now only
|
This folder contains:
|
||||||
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
|
- a nightly toolchain definition for formatting
|
||||||
|
|
|
@ -1637,15 +1637,6 @@
|
||||||
"license_file": null,
|
"license_file": null,
|
||||||
"description": "A Rust crate for producing string-representations of numbers, formatted according to international standards"
|
"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",
|
"name": "num-traits",
|
||||||
"version": "0.2.15",
|
"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
|
/// Like [read_file], but skips the section that is potentially locked by
|
||||||
/// SQLite.
|
/// SQLite.
|
||||||
pub fn read_locked_db_file(path: impl AsRef<Path>) -> Result<Vec<u8>> {
|
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
|
rust-version.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
anki_io = { version = "0.0.0", path = "../../rslib/io" }
|
||||||
|
anki_process = { version = "0.0.0", path = "../../rslib/process" }
|
||||||
anyhow = "1.0.71"
|
anyhow = "1.0.71"
|
||||||
camino = "1.1.4"
|
camino = "1.1.4"
|
||||||
once_cell = "1.17.1"
|
once_cell = "1.17.1"
|
||||||
|
|
|
@ -10,6 +10,9 @@ use std::io::Write;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
|
use anki_io::read_to_string;
|
||||||
|
use anki_io::write_file;
|
||||||
|
use anki_process::CommandExt;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use camino::Utf8Path;
|
use camino::Utf8Path;
|
||||||
|
@ -43,6 +46,7 @@ fn main() -> Result<()> {
|
||||||
let want_fix = env::args().nth(1) == Some("fix".to_string());
|
let want_fix = env::args().nth(1) == Some("fix".to_string());
|
||||||
let mut ctx = LintContext::new(want_fix);
|
let mut ctx = LintContext::new(want_fix);
|
||||||
ctx.check_contributors()?;
|
ctx.check_contributors()?;
|
||||||
|
ctx.check_rust_licenses()?;
|
||||||
ctx.walk_folders(Path::new("."))?;
|
ctx.walk_folders(Path::new("."))?;
|
||||||
if ctx.found_problems {
|
if ctx.found_problems {
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
|
@ -147,7 +151,6 @@ impl LintContext {
|
||||||
println!("Dependabot whitelisted.");
|
println!("Dependabot whitelisted.");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
} else if all_contributors.contains(last_author.as_str()) {
|
} else if all_contributors.contains(last_author.as_str()) {
|
||||||
println!("Author found in CONTRIBUTORS");
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,6 +178,35 @@ impl LintContext {
|
||||||
|
|
||||||
std::process::exit(1);
|
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> {
|
fn head_of_file(path: &Utf8Path) -> Result<String> {
|
||||||
|
@ -223,3 +255,18 @@ fn check_for_unstaged_changes() {
|
||||||
std::process::exit(1);
|
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 = { version = "1", features = ["alloc", "derive", "rc"] }
|
||||||
serde_json = { version = "1", features = ["raw_value"] }
|
serde_json = { version = "1", features = ["raw_value"] }
|
||||||
sha2 = { version = "0.10" }
|
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"] }
|
time = { version = "0.3", features = ["formatting", "parsing"] }
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
tokio-util = { version = "0.7", features = ["codec", "io"] }
|
tokio-util = { version = "0.7", features = ["codec", "io"] }
|
||||||
|
@ -80,7 +80,8 @@ scopeguard = { version = "1" }
|
||||||
serde = { version = "1", features = ["alloc", "derive", "rc"] }
|
serde = { version = "1", features = ["alloc", "derive", "rc"] }
|
||||||
serde_json = { version = "1", features = ["raw_value"] }
|
serde_json = { version = "1", features = ["raw_value"] }
|
||||||
sha2 = { version = "0.10" }
|
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-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"] }
|
syn-f595c2ba2a3f28df = { package = "syn", version = "2", features = ["extra-traits", "full", "visit-mut"] }
|
||||||
time = { version = "0.3", features = ["formatting", "parsing"] }
|
time = { version = "0.3", features = ["formatting", "parsing"] }
|
||||||
|
|
Loading…
Reference in a new issue