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}