1use crate::Cli;
2use futures::StreamExt;
3use licensebat_core::{licrc::LicRc, FileCollector, RetrievedDependency};
4use std::sync::Arc;
5
6const LICENSE_CACHE: &[u8] = std::include_bytes!("../license-cache.bin.zstd");
7
8#[derive(Debug, thiserror::Error)]
9enum CheckError {
10 #[error("Error reading dependency file: {0}")]
11 DependencyFile(#[from] std::io::Error),
12}
13
14pub struct RunResult {
16 pub licrc: LicRc,
18 pub dependencies: Vec<RetrievedDependency>,
20}
21
22pub async fn run(cli: Cli) -> anyhow::Result<RunResult> {
32 tracing::info!(
33 dependency_file = %cli.dependency_file,
34 "Licensebat running! Using {}", cli.dependency_file
35 );
36
37 let store = Arc::new(askalono::Store::from_cache(LICENSE_CACHE).ok());
39 let client = reqwest::Client::builder()
40 .no_proxy()
41 .build()
44 .expect("Failed to build HTTP client");
45
46 tracing::debug!("Reading .licrc file");
48 let licrc = LicRc::from_relative_path(cli.licrc_file)?;
49
50 tracing::debug!("Getting dependency file content");
52 let dep_file_content = get_dep_file_content(&cli.dependency_file).await?;
53
54 tracing::debug!("Building collectors");
56 let npm_retriever = licensebat_js::retriever::Npm::new(client.clone());
57 let npm_collector = licensebat_js::collector::Npm::new(npm_retriever.clone());
58 let yarn_collector = licensebat_js::collector::Yarn::new(npm_retriever);
59 let rust_collector =
60 licensebat_rust::collector::Rust::with_docs_rs_retriever(client.clone(), store.clone());
61 let dart_collector = licensebat_dart::collector::Dart::with_hosted_retriever(client, store);
62
63 let file_collectors: Vec<Box<dyn FileCollector>> = vec![
64 Box::new(npm_collector),
65 Box::new(yarn_collector),
66 Box::new(rust_collector),
67 Box::new(dart_collector),
68 ];
69
70 let mut stream = file_collectors
72 .iter()
73 .find(|c| cli.dependency_file.contains(&c.get_dependency_filename()))
74 .and_then(|c| c.get_dependencies(&dep_file_content, &licrc).ok())
75 .expect(
76 format!(
77 "No collector found for dependency file {}",
78 cli.dependency_file
79 )
80 .as_str(),
81 )
82 .buffer_unordered(licrc.behavior.retriever_buffer_size.unwrap_or(100));
83
84 tracing::debug!("Validating dependencies");
86 let mut validated_deps = vec![];
87
88 while let Some(mut dependency) = stream.next().await {
89 licrc.validate(&mut dependency);
91 validated_deps.push(dependency);
92 }
93
94 tracing::info!("Done!");
95 Ok(RunResult {
96 licrc,
97 dependencies: validated_deps,
98 })
99}
100
101async fn get_dep_file_content(dependency_file: &str) -> Result<String, CheckError> {
102 async {
103 let dep_file_path = std::env::current_dir()?.join(dependency_file);
104 let dep_file_content = tokio::fs::read_to_string(dep_file_path).await?;
105 Ok(dep_file_content)
106 }
107 .await
108 .map_err(CheckError::DependencyFile)
109}