1pub mod api;
2mod doc_archive;
3pub mod doc_queue;
4pub mod doc_queue_response;
5pub mod docs_error;
6pub mod upload_response;
7
8use std::convert::TryFrom;
9use std::path::Path;
10
11use kellnr_common::version::Version;
12use kellnr_settings::Settings;
13
14pub fn get_latest_doc_url(crate_name: &str, settings: &Settings) -> Option<String> {
15 let version = get_latest_version_with_doc(crate_name, settings);
16 version.map(|v| compute_doc_url(crate_name, &v))
17}
18
19pub fn get_doc_url(crate_name: &str, crate_version: &Version, docs_path: &Path) -> Option<String> {
20 let docs_name = crate_name_to_docs_name(crate_name);
21
22 if doc_exists(crate_name, crate_version, docs_path) {
23 Some(format!(
24 "/docs/{crate_name}/{crate_version}/doc/{docs_name}/index.html"
25 ))
26 } else {
27 None
28 }
29}
30
31pub fn compute_doc_url(crate_name: &str, crate_version: &Version) -> String {
32 let docs_name = crate_name_to_docs_name(crate_name);
33 format!("/docs/{crate_name}/{crate_version}/doc/{docs_name}/index.html")
34}
35
36fn crate_name_to_docs_name(crate_name: &str) -> String {
37 crate_name.replace('-', "_")
40}
41
42fn doc_exists(crate_name: &str, crate_version: &str, docs_path: &Path) -> bool {
43 let docs_name = crate_name_to_docs_name(crate_name);
44 docs_path
45 .join(crate_name)
46 .join(crate_version)
47 .join("doc")
48 .join(docs_name)
49 .join("index.html")
50 .exists()
51}
52
53fn get_latest_version_with_doc(crate_name: &str, settings: &Settings) -> Option<Version> {
54 let versions_path = settings.docs_path().join(crate_name);
55 let Ok(version_folders) = std::fs::read_dir(versions_path) else {
56 return None;
57 };
58
59 let mut versions: Vec<Version> = version_folders
60 .flatten()
61 .filter(|entry| entry.path().is_dir())
62 .flat_map(|dir| Version::try_from(&dir.file_name().to_string_lossy().to_string()))
63 .collect();
64
65 versions.sort();
68 versions.reverse();
69 versions
70 .into_iter()
71 .find(|v| doc_exists(crate_name, &v.to_string(), &settings.docs_path()))
72}
73
74pub async fn delete(
75 crate_name: &str,
76 crate_version: &str,
77 settings: &Settings,
78) -> Result<(), std::io::Error> {
79 let docs_path = settings.docs_path().join(crate_name).join(crate_version);
81 if docs_path.exists() {
82 tokio::fs::remove_dir_all(docs_path).await?;
83 }
84
85 if get_latest_version_with_doc(crate_name, settings).is_none() {
87 let crate_path = settings.docs_path().join(crate_name);
88 if crate_path.exists() {
89 tokio::fs::remove_dir_all(crate_path).await?;
90 }
91 }
92
93 Ok(())
94}