use crate::Cli;
use futures::StreamExt;
use licensebat_core::{licrc::LicRc, FileCollector, RetrievedDependency};
use std::sync::Arc;
const LICENSE_CACHE: &[u8] = std::include_bytes!("../license-cache.bin.zstd");
#[derive(Debug, thiserror::Error)]
enum CheckError {
#[error("Error reading dependency file: {0}")]
DependencyFile(#[from] std::io::Error),
}
pub struct RunResult {
pub licrc: LicRc,
pub dependencies: Vec<RetrievedDependency>,
}
pub async fn run(cli: Cli) -> anyhow::Result<RunResult> {
tracing::info!(
dependency_file = %cli.dependency_file,
"Licensebat running! Using {}", cli.dependency_file
);
let store = Arc::new(askalono::Store::from_cache(LICENSE_CACHE).ok());
let client = reqwest::Client::builder()
.no_proxy()
.build()
.expect("Failed to build HTTP client");
tracing::debug!("Reading .licrc file");
let licrc = LicRc::from_relative_path(cli.licrc_file)?;
tracing::debug!("Getting dependency file content");
let dep_file_content = get_dep_file_content(&cli.dependency_file).await?;
tracing::debug!("Building collectors");
let npm_retriever = licensebat_js::retriever::Npm::new(client.clone());
let npm_collector = licensebat_js::collector::Npm::new(npm_retriever.clone());
let yarn_collector = licensebat_js::collector::Yarn::new(npm_retriever);
let rust_collector =
licensebat_rust::collector::Rust::with_docs_rs_retriever(client.clone(), store.clone());
let dart_collector = licensebat_dart::collector::Dart::with_hosted_retriever(client, store);
let file_collectors: Vec<Box<dyn FileCollector>> = vec![
Box::new(npm_collector),
Box::new(yarn_collector),
Box::new(rust_collector),
Box::new(dart_collector),
];
let mut stream = file_collectors
.iter()
.find(|c| cli.dependency_file.contains(&c.get_dependency_filename()))
.and_then(|c| c.get_dependencies(&dep_file_content).ok())
.expect("No collector found for dependency file")
.buffer_unordered(licrc.behavior.retriever_buffer_size.unwrap_or(100));
tracing::debug!("Validating dependencies");
let mut validated_deps = vec![];
while let Some(mut dependency) = stream.next().await {
licrc.validate(&mut dependency);
validated_deps.push(dependency);
}
tracing::info!("Done!");
Ok(RunResult {
licrc,
dependencies: validated_deps,
})
}
async fn get_dep_file_content(dependency_file: &str) -> Result<String, CheckError> {
async {
let dep_file_path = std::env::current_dir()?.join(dependency_file);
let dep_file_content = tokio::fs::read_to_string(dep_file_path).await?;
Ok(dep_file_content)
}
.await
.map_err(CheckError::DependencyFile)
}