Add xtask for finding crates with missing licenses (#11776)

This PR adds a new `cargo xtask licenses` command for finding crates
with missing license files.

A number of crates were uncovered that were missing a license file, and
have had the appropriate license file added.

Release Notes:

- N/A
This commit is contained in:
Marshall Bowers 2024-05-13 18:52:12 -04:00 committed by GitHub
parent ff2eacead7
commit b01878aadf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 149 additions and 63 deletions

12
Cargo.lock generated
View File

@ -1887,6 +1887,16 @@ dependencies = [
"winx",
]
[[package]]
name = "cargo_toml"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8cb1d556b8b8f36e5ca74938008be3ac102f5dcb5b68a0477e4249ae2291cd3"
dependencies = [
"serde",
"toml 0.8.10",
]
[[package]]
name = "cast"
version = "0.3.0"
@ -12810,7 +12820,9 @@ name = "xtask"
version = "0.1.0"
dependencies = [
"anyhow",
"cargo_toml",
"clap 4.4.4",
"toml 0.8.10",
]
[[package]]

View File

@ -265,6 +265,7 @@ bitflags = "2.4.2"
blade-graphics = { git = "https://github.com/kvark/blade", rev = "e35b2d41f221a48b75f7cf2e78a81e7ecb7a383c" }
blade-macros = { git = "https://github.com/kvark/blade", rev = "e35b2d41f221a48b75f7cf2e78a81e7ecb7a383c" }
cap-std = "3.0"
cargo_toml = "0.20"
chrono = { version = "0.4", features = ["serde"] }
clap = { version = "4.4", features = ["derive"] }
clickhouse = { version = "0.11.6" }

View File

@ -0,0 +1 @@
../../LICENSE-GPL

View File

@ -0,0 +1 @@
../../LICENSE-GPL

1
crates/markdown/LICENSE-GPL Symbolic link
View File

@ -0,0 +1 @@
../../LICENSE-GPL

View File

@ -0,0 +1 @@
../../LICENSE-GPL

View File

@ -0,0 +1 @@
../../LICENSE-GPL

View File

@ -0,0 +1 @@
../../LICENSE-APACHE

View File

@ -10,4 +10,6 @@ workspace = true
[dependencies]
anyhow.workspace = true
cargo_toml.workspace = true
clap = { workspace = true, features = ["derive"] }
toml.workspace = true

View File

@ -1,6 +1,7 @@
use std::process::Command;
mod tasks;
mod workspace;
use anyhow::{bail, Context, Result};
use anyhow::Result;
use clap::{Parser, Subcommand};
#[derive(Parser)]
@ -13,72 +14,15 @@ struct Args {
#[derive(Subcommand)]
enum CliCommand {
/// Runs `cargo clippy`.
Clippy(ClippyArgs),
Clippy(tasks::clippy::ClippyArgs),
Licenses(tasks::licenses::LicensesArgs),
}
fn main() -> Result<()> {
let args = Args::parse();
match args.command {
CliCommand::Clippy(args) => run_clippy(args),
CliCommand::Clippy(args) => tasks::clippy::run_clippy(args),
CliCommand::Licenses(args) => tasks::licenses::run_licenses(args),
}
}
#[derive(Parser)]
struct ClippyArgs {
/// Automatically apply lint suggestions (`clippy --fix`).
#[arg(long)]
fix: bool,
/// The package to run Clippy against (`cargo -p <PACKAGE> clippy`).
#[arg(long, short)]
package: Option<String>,
}
fn run_clippy(args: ClippyArgs) -> Result<()> {
let cargo = std::env::var("CARGO").unwrap_or_else(|_| "cargo".to_string());
let mut clippy_command = Command::new(&cargo);
clippy_command.arg("clippy");
if let Some(package) = args.package.as_ref() {
clippy_command.args(["--package", package]);
} else {
clippy_command.arg("--workspace");
}
clippy_command
.arg("--release")
.arg("--all-targets")
.arg("--all-features");
if args.fix {
clippy_command.arg("--fix");
}
clippy_command.arg("--");
// Deny all warnings.
clippy_command.args(["--deny", "warnings"]);
eprintln!(
"running: {cargo} {}",
clippy_command
.get_args()
.map(|arg| arg.to_str().unwrap())
.collect::<Vec<_>>()
.join(" ")
);
let exit_status = clippy_command
.spawn()
.context("failed to spawn child process")?
.wait()
.context("failed to wait for child process")?;
if !exit_status.success() {
bail!("clippy failed: {}", exit_status);
}
Ok(())
}

View File

@ -0,0 +1,2 @@
pub mod clippy;
pub mod licenses;

View File

@ -0,0 +1,63 @@
use std::process::Command;
use anyhow::{bail, Context, Result};
use clap::Parser;
#[derive(Parser)]
pub struct ClippyArgs {
/// Automatically apply lint suggestions (`clippy --fix`).
#[arg(long)]
fix: bool,
/// The package to run Clippy against (`cargo -p <PACKAGE> clippy`).
#[arg(long, short)]
package: Option<String>,
}
pub fn run_clippy(args: ClippyArgs) -> Result<()> {
let cargo = std::env::var("CARGO").unwrap_or_else(|_| "cargo".to_string());
let mut clippy_command = Command::new(&cargo);
clippy_command.arg("clippy");
if let Some(package) = args.package.as_ref() {
clippy_command.args(["--package", package]);
} else {
clippy_command.arg("--workspace");
}
clippy_command
.arg("--release")
.arg("--all-targets")
.arg("--all-features");
if args.fix {
clippy_command.arg("--fix");
}
clippy_command.arg("--");
// Deny all warnings.
clippy_command.args(["--deny", "warnings"]);
eprintln!(
"running: {cargo} {}",
clippy_command
.get_args()
.map(|arg| arg.to_str().unwrap())
.collect::<Vec<_>>()
.join(" ")
);
let exit_status = clippy_command
.spawn()
.context("failed to spawn child process")?
.wait()
.context("failed to wait for child process")?;
if !exit_status.success() {
bail!("clippy failed: {}", exit_status);
}
Ok(())
}

View File

@ -0,0 +1,39 @@
use std::path::{Path, PathBuf};
use anyhow::Result;
use clap::Parser;
use crate::workspace::load_workspace;
#[derive(Parser)]
pub struct LicensesArgs {}
pub fn run_licenses(_args: LicensesArgs) -> Result<()> {
let workspace = load_workspace()?;
for member in workspace.members {
let crate_dir = PathBuf::from(&member);
if has_any_license_file(
&crate_dir,
&["LICENSE-APACHE", "LICENSE-GPL", "LICENSE-AGPL"],
) {
continue;
}
println!("Missing license: {member}");
}
Ok(())
}
fn has_any_license_file(path: &Path, license_files: &[&str]) -> bool {
for license_file in license_files {
let path_to_license = path.join(license_file);
if path_to_license.exists() {
return true;
}
}
false
}

View File

@ -0,0 +1,17 @@
use std::fs;
use anyhow::{anyhow, Result};
use cargo_toml::{Manifest, Workspace};
use toml;
/// Returns the Cargo workspace.
pub fn load_workspace() -> Result<Workspace> {
let workspace_cargo_toml = fs::read_to_string("Cargo.toml")?;
let workspace_cargo_toml: Manifest = toml::from_str(&workspace_cargo_toml)?;
let workspace = workspace_cargo_toml
.workspace
.ok_or_else(|| anyhow!("top-level Cargo.toml is not a Cargo workspace"))?;
Ok(workspace)
}