-
Notifications
You must be signed in to change notification settings - Fork 211
/
Copy pathfile.rs
105 lines (96 loc) · 3.43 KB
/
file.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
//! Simple module to store files in database.
//!
//! docs.rs supports two ways of storing files: in a postgres database and in an S3 bucket.
//! It does not support storing files on disk because of the sheer number of files:
//! doing so would quickly run into file descriptor limits when running the web server.
//!
//! It's recommended that you use the S3 bucket in production to avoid running out of disk space.
//! However, postgres is still available for testing and backwards compatibility.
use crate::error::Result;
use crate::{
db::mimes,
storage::{AsyncStorage, CompressionAlgorithm},
};
use mime::Mime;
use serde_json::Value;
use std::ffi::OsStr;
use std::path::{Path, PathBuf};
use tracing::instrument;
/// represents a file path from our source or documentation builds.
/// Used to return metadata about the file.
#[derive(Debug)]
pub struct FileEntry {
pub(crate) path: PathBuf,
pub(crate) size: u64,
}
impl FileEntry {
pub(crate) fn mime(&self) -> Mime {
detect_mime(&self.path)
}
}
pub(crate) fn detect_mime(file_path: impl AsRef<Path>) -> Mime {
let mime = mime_guess::from_path(file_path.as_ref())
.first()
.unwrap_or(mime::TEXT_PLAIN);
match mime.as_ref() {
"text/plain" | "text/troff" | "text/x-markdown" | "text/x-rust" | "text/x-toml" => {
match file_path.as_ref().extension().and_then(OsStr::to_str) {
Some("md") => mimes::TEXT_MARKDOWN.clone(),
Some("rs") => mimes::TEXT_RUST.clone(),
Some("markdown") => mimes::TEXT_MARKDOWN.clone(),
Some("css") => mime::TEXT_CSS,
Some("toml") => mimes::TEXT_TOML.clone(),
Some("js") => mime::TEXT_JAVASCRIPT,
Some("json") => mime::APPLICATION_JSON,
_ => mime,
}
}
"image/svg" => mime::IMAGE_SVG,
_ => mime,
}
}
/// Store all files in a directory and return [[mimetype, filename]] as Json
///
/// If there is an S3 Client configured, store files into an S3 bucket;
/// otherwise, stores files into the 'files' table of the local database.
///
/// The mimetype is detected using `magic`.
///
/// Note that this function is used for uploading both sources
/// and files generated by rustdoc.
pub async fn add_path_into_database<P: AsRef<Path>>(
storage: &AsyncStorage,
prefix: impl AsRef<Path>,
path: P,
) -> Result<(Vec<FileEntry>, CompressionAlgorithm)> {
storage.store_all(prefix.as_ref(), path.as_ref()).await
}
#[instrument(skip(storage))]
pub async fn add_path_into_remote_archive<P: AsRef<Path> + std::fmt::Debug>(
storage: &AsyncStorage,
archive_path: &str,
path: P,
public_access: bool,
) -> Result<(Vec<FileEntry>, CompressionAlgorithm)> {
let (file_list, algorithm) = storage
.store_all_in_archive(archive_path, path.as_ref())
.await?;
if public_access {
storage.set_public_access(archive_path, true).await?;
}
Ok((file_list, algorithm))
}
pub(crate) fn file_list_to_json(files: impl IntoIterator<Item = FileEntry>) -> Value {
Value::Array(
files
.into_iter()
.map(|info| {
Value::Array(vec![
Value::String(info.mime().as_ref().to_string()),
Value::String(info.path.into_os_string().into_string().unwrap()),
Value::Number(info.size.into()),
])
})
.collect(),
)
}