Skip to content

Commit

Permalink
boulder/draft: Add support for license matching when running boulder new
Browse files Browse the repository at this point in the history
  • Loading branch information
joebonrichie committed Feb 7, 2025
1 parent cb1207e commit 85cde4f
Show file tree
Hide file tree
Showing 7 changed files with 272 additions and 13 deletions.
50 changes: 50 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ strum = { version = "0.26.3", features = ["derive"] }
thiserror = "2.0.3"
thread-priority = "1.1.0"
tokio = { version = "1.38.0", features = ["full"] }
tokio-stream = { version = "0.1.15", features = ["time"] }
tokio-util = { version = "0.7.11", features = ["io"] }
url = { version = "2.5.2", features = ["serde"] }
xxhash-rust = { version = "0.8.11", features = ["xxh3"] }
Expand Down
3 changes: 3 additions & 0 deletions boulder/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ thread-priority.workspace = true
tokio.workspace = true
url.workspace = true
mailparse.workspace = true
rayon.workspace = true
rapidfuzz = "0.5.0"
jwalk = "0.8.1"

[lints]
workspace = true
6 changes: 3 additions & 3 deletions boulder/src/cli/recipe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ fn parse_upstream(s: &str) -> Result<Upstream, String> {
pub fn handle(command: Command, env: Env) -> Result<(), Error> {
match command.subcommand {
Subcommand::Bump { recipe, release } => bump(recipe, release),
Subcommand::New { output, upstreams } => new(output, upstreams),
Subcommand::New { output, upstreams } => new(output, upstreams, env),
Subcommand::Update {
recipe,
overwrite,
Expand Down Expand Up @@ -145,14 +145,14 @@ fn bump(recipe: PathBuf, release: Option<u64>) -> Result<(), Error> {
Ok(())
}

fn new(output: PathBuf, upstreams: Vec<Url>) -> Result<(), Error> {
fn new(output: PathBuf, upstreams: Vec<Url>, env: Env) -> Result<(), Error> {
// We use async to fetch upstreams
let _guard = runtime::init();

const RECIPE_FILE: &str = "stone.yaml";
const MONITORING_FILE: &str = "monitoring.yaml";

let drafter = Drafter::new(upstreams);
let drafter = Drafter::new(upstreams, env.data_dir);
let draft = drafter.run()?;

if !output.is_dir() {
Expand Down
44 changes: 39 additions & 5 deletions boulder/src/draft.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use std::{io, path::PathBuf};

use fs_err as fs;
use itertools::Itertools;
use licenses::match_licences;
use moss::Dependency;
use thiserror::Error;
use tui::Styled;
Expand All @@ -19,12 +20,14 @@ use self::monitoring::Monitoring;
use self::upstream::Upstream;

mod build;
mod licenses;
mod metadata;
mod monitoring;
mod upstream;

pub struct Drafter {
upstreams: Vec<Url>,
datadir: PathBuf,
}

pub struct Draft {
Expand All @@ -33,8 +36,8 @@ pub struct Draft {
}

impl Drafter {
pub fn new(upstreams: Vec<Url>) -> Self {
Self { upstreams }
pub fn new(upstreams: Vec<Url>, datadir: PathBuf) -> Self {
Self { upstreams, datadir }
}

pub fn run(&self) -> Result<Draft, Error> {
Expand Down Expand Up @@ -62,6 +65,10 @@ impl Drafter {
// Analyze files to determine build system / collect deps
let build = build::analyze(&files).map_err(Error::AnalyzeBuildSystem)?;

let licences_dir = &self.datadir.join("licenses");

let licenses = format_licenses(match_licences(&extract_root, licences_dir).unwrap_or_default());

// Remove temp extract dir
fs::remove_dir_all(extract_root)?;

Expand Down Expand Up @@ -97,9 +104,8 @@ upstreams :
summary : UPDATE SUMMARY
description : |
UPDATE DESCRIPTION
license : UPDATE LICENSE
{options}{builddeps}{environment}{phases}
",
license : {licenses}
{options}{builddeps}{environment}{phases}",
metadata.source.name,
metadata.source.version,
metadata.source.homepage,
Expand All @@ -123,6 +129,30 @@ fn builddeps(deps: impl IntoIterator<Item = Dependency>) -> String {
}
}

fn format_licenses(licenses: Vec<String>) -> String {
let formatted = licenses
.into_iter()
.map(|license| format!(" - {license}"))
.sorted_by(|a, b| {
// HACK: Ensure -or-later for GNU licenses comes before -only
// to match 90% of cases. We need to read the standard license
// header to figure out the actual variant.
if a.contains("-only") {
std::cmp::Ordering::Greater
} else if b.contains("-only") {
std::cmp::Ordering::Less
} else {
a.cmp(b)
}
})
.join("\n");
if formatted.is_empty() {
format!("UPDATE LICENSE")

Check warning on line 150 in boulder/src/draft.rs

View workflow job for this annotation

GitHub Actions / clippy

[clippy] boulder/src/draft.rs#L150

warning: useless use of `format!` --> boulder/src/draft.rs:150:9 | 150 | format!("UPDATE LICENSE") | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"UPDATE LICENSE".to_string()` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_format = note: `#[warn(clippy::useless_format)]` on by default
Raw output
boulder/src/draft.rs:150:9:w:warning: useless use of `format!`
   --> boulder/src/draft.rs:150:9
    |
150 |         format!("UPDATE LICENSE")
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"UPDATE LICENSE".to_string()`
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_format
    = note: `#[warn(clippy::useless_format)]` on by default


__END__
} else {
format!("\n{formatted}")
}
}

pub struct File<'a> {
pub path: PathBuf,
pub extract_root: &'a Path,
Expand Down Expand Up @@ -150,8 +180,12 @@ pub enum Error {
Upstream(#[from] upstream::Error),
#[error("monitoring")]
Monitoring(#[from] monitoring::Error),
#[error("licensing")]
Licenses(#[from] licenses::Error),
#[error("io")]
Io(#[from] io::Error),
#[error("walkdir")]
WalkDir(#[from] jwalk::Error),
}

#[cfg(test)]
Expand Down
Loading

0 comments on commit 85cde4f

Please sign in to comment.