1use std::{
2 collections::HashMap,
3 io::{Cursor, SeekFrom},
4};
5
6use anyhow::{anyhow, Result};
7use octocrab::Octocrab;
8use url::Url;
9
10use crate::{
11 analyzers::SpdxFileAnalyzeSuccess,
12 packages::{GitPackage, TarPackage, ZipPackage},
13 spdx::SpdxDocument,
14};
15
16mod analyzers;
17mod packages;
18mod spdx;
19
20fn file_name_from_url(url: &Url) -> Result<String> {
21 let segments = url
22 .path_segments()
23 .ok_or_else(|| anyhow!("can not take to path segments from url {}", url))?;
24 let last_segment = segments
25 .last()
26 .ok_or_else(|| anyhow!("can not take a last segment from url : {}", url))?;
27 Ok(last_segment.to_string())
28}
29
30async fn download_file_from_url<W: std::io::Write + std::io::Seek>(
31 url: &Url,
32 file: &mut W,
33) -> Result<()> {
34 let http_client = reqwest::Client::default();
35 let response = http_client.get(url.as_str()).send().await?;
36 let mut content = Cursor::new(response.bytes().await?);
37 std::io::copy(&mut content, file)?;
38 file.seek(SeekFrom::Start(0))?;
39 Ok(())
40}
41
42#[derive(clap::Args, Debug)]
43pub struct DescribeArgs {
44 owner: String,
45 repo: String,
46 tag: String,
47}
48
49type Files = HashMap<String, SpdxFileAnalyzeSuccess>;
50
51impl DescribeArgs {
52 async fn analyze_tar(tar_url: &Url) -> Result<Files> {
53 let mut file = tempfile::tempfile()?;
54 download_file_from_url(tar_url, &mut file).await?;
55 let files_from_tar = TarPackage::from_read(file).analyze_files()?;
56 Ok(files_from_tar)
57 }
58
59 async fn analyze_zip(tar_url: &Url) -> Result<Files> {
60 let mut file = tempfile::tempfile()?;
61 download_file_from_url(tar_url, &mut file).await?;
62 let files_from_tar = ZipPackage::from_read(file)?.analyze_files()?;
63 Ok(files_from_tar)
64 }
65
66 fn analyze_git(clone_url: Url, tag: String) -> Result<Files> {
67 let package = GitPackage::checkout(&clone_url, &tag)?;
68 Ok(package.analyze_files()?)
69 }
70
71 pub async fn run(self) -> Result<()> {
72 let mut spdx_doc = SpdxDocument::new(&format!("{}_{}", self.repo, self.tag));
73 let octocrab = Octocrab::builder().build()?;
74 let repo_client = octocrab.repos(self.owner, self.repo);
75 let repo = repo_client.get().await?;
76 let release = repo_client.releases().get_by_tag(&self.tag).await?;
77 println!("procesing release : {:?}", release);
78 let git_analyze_task = {
79 let clone_url = repo.clone_url.unwrap().clone();
80 tokio::spawn(async move { Self::analyze_git(clone_url, self.tag) })
81 };
82 let tar_analyze_task = if let Some(ref tar_url) = release.tarball_url {
83 let tar_url = tar_url.clone();
84 Some(tokio::spawn(
85 async move { Self::analyze_tar(&tar_url).await },
86 ))
87 } else {
88 None
89 };
90 let zip_analyze_task = if let Some(ref zip_url) = release.zipball_url {
91 let zip_url = zip_url.clone();
92 Some(tokio::spawn(
93 async move { Self::analyze_zip(&zip_url).await },
94 ))
95 } else {
96 None
97 };
98
99 let git_result = git_analyze_task.await?;
100
101 let zip_result = if let Some(zip_task) = zip_analyze_task {
102 Some(zip_task.await?)
103 } else {
104 None
105 };
106 let tar_result = if let Some(tar_task) = tar_analyze_task {
107 Some(tar_task.await?)
108 } else {
109 None
110 };
111
112 for asset in release.assets {
113 println!("processing asset : {:?}", asset);
114 }
115
116 Ok(())
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 #[test]
123 fn it_works() {
124 let result = 2 + 2;
125 assert_eq!(result, 4);
126 }
127}