web_static_pack_packer/file_pack_path.rs
1//! Pack path (file and pack path combined) helpers. Contains [FilePackPath], a
2//! combination of [File] and [PackPath].
3
4use crate::{
5 common::{file::File, pack_path::PackPath},
6 file, pack_path,
7};
8use anyhow::{Context, Error};
9use std::path::Path;
10
11/// [File] (describing the content) + its [PackPath] (describing uri that the
12/// file will be accessible at).
13///
14/// This is the main item added to the `pack`.
15///
16/// It can be manually created by passing `file` and `pack_path` fields or using
17/// associated helpers methods.
18#[derive(Debug)]
19pub struct FilePackPath {
20 /// The file.
21 pub file: File,
22
23 /// The path inside the `pack`, corresponding to http path parameter.
24 pub pack_path: PackPath,
25}
26impl FilePackPath {
27 /// Creates [self] by reading file relative to given base directory.
28 ///
29 /// Given file path (`path`) to read and base directory path creates a
30 /// [self] by preparing:
31 /// - [File] with [file::build_from_path] using
32 /// [file::BuildFromPathOptions].
33 /// - [PackPath] with [pack_path::from_file_base_relative_path] (as relative
34 /// path between `path` and `base_directory_path`).
35 ///
36 /// # Examples
37 ///
38 /// ```
39 /// # use anyhow::{anyhow, Error};
40 /// # use std::path::PathBuf;
41 /// # use web_static_pack_packer::{file::BuildFromPathOptions, file_pack_path::FilePackPath};
42 /// #
43 /// # fn main() -> Result<(), Error> {
44 /// #
45 /// // base directory
46 /// let base_directory = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
47 /// .parent()
48 /// .ok_or_else(|| anyhow!("missing parent"))?
49 /// .join("tests")
50 /// .join("data")
51 /// .join("vcard-personal-portfolio");
52 ///
53 /// // file in base/directory/path/index.html should end up as /index.html
54 /// let file_pack_path_1 = FilePackPath::build_from_path(
55 /// &base_directory.join("index.html"),
56 /// &base_directory,
57 /// &BuildFromPathOptions::default(),
58 /// )?;
59 /// assert_eq!(
60 /// file_pack_path_1.file.content_type,
61 /// "text/html; charset=utf-8"
62 /// );
63 /// assert_eq!(&*file_pack_path_1.pack_path, "/index.html");
64 ///
65 /// // file in base/directory/path/website-demo-image/desktop.png should end up as /website-demo-image/desktop.png
66 /// let file_pack_path_2 = FilePackPath::build_from_path(
67 /// &base_directory.join("website-demo-image").join("desktop.png"),
68 /// &base_directory,
69 /// &BuildFromPathOptions::default(),
70 /// )?;
71 /// assert_eq!(
72 /// file_pack_path_2.file.content_type,
73 /// "image/png"
74 /// );
75 /// assert_eq!(&*file_pack_path_2.pack_path, "/website-demo-image/desktop.png");
76 /// #
77 /// # Ok(())
78 /// # }
79 /// ```
80 pub fn build_from_path(
81 path: &Path,
82 base_directory_path: &Path,
83 file_options: &file::BuildFromPathOptions,
84 ) -> Result<Self, Error> {
85 // strip prefix, so entry_path is relative to search root
86 let file_base_relative_path = path
87 .strip_prefix(base_directory_path)
88 .context("resolve file_base_relative_path")?;
89
90 // create path prefix
91 let pack_path = pack_path::from_file_base_relative_path(file_base_relative_path)?;
92
93 // read and build file
94 let file = file::build_from_path(path, file_options)?;
95
96 Ok(Self { file, pack_path })
97 }
98}