Skip to main content

webserver_base/assets/
error.rs

1//! Failures from building or writing the asset cache.
2
3use std::path::PathBuf;
4
5/// Why the asset cache could not be built.
6///
7/// All boot-time failures. Lookups afterwards never fail —
8/// [`CacheBuster::get_file`](super::CacheBuster::get_file) falls back to the
9/// unhashed path rather than taking a page down over one image.
10#[derive(Debug, thiserror::Error)]
11pub enum CacheBusterError {
12    /// A directory under the asset root could not be read.
13    #[error("failed to read asset directory `{path}`")]
14    ReadDirectory {
15        path: PathBuf,
16        #[source]
17        source: std::io::Error,
18    },
19
20    /// A file could not be read in order to hash it.
21    #[error("failed to read asset `{path}`")]
22    ReadFile {
23        path: PathBuf,
24        #[source]
25        source: std::io::Error,
26    },
27
28    /// A file could not be renamed to its content-hashed name.
29    #[error("failed to rename asset `{from}` to `{to}`")]
30    Rename {
31        from: PathBuf,
32        to: PathBuf,
33        #[source]
34        source: std::io::Error,
35    },
36
37    /// A `.js` file's `sourceMappingURL` comment could not be rewritten.
38    #[error("failed to rewrite the source map reference in `{path}`")]
39    SourceMap {
40        path: PathBuf,
41        #[source]
42        source: std::io::Error,
43    },
44
45    /// The static-asset pipeline was run somewhere without a `static/`.
46    #[error(
47        "`{path}` does not exist. The static-asset pipeline runs from the \
48         project root, where `static/` lives."
49    )]
50    MissingStaticDirectory { path: PathBuf },
51
52    /// A frontend shipped no source icon.
53    #[error(
54        "no icon source. Provide `static/image/favicon/favicon.svg`, or a \
55         512x512 `static/image/favicon/favicon-512.png` if the art cannot be \
56         vectorised. The .ico, apple-touch icon and web-manifest icons are \
57         generated from whichever you provide."
58    )]
59    MissingFavicon,
60
61    /// A frontend shipped both icon sources.
62    #[error(
63        "both `favicon.svg` and `favicon-512.png` exist. Delete one: two \
64         sources drift the moment somebody updates only one of them."
65    )]
66    AmbiguousFavicon,
67
68    /// The icon directory holds something that is neither a source nor derived.
69    #[error(
70        "`{directory}` contains {count} file(s) that do not belong:{unexpected}\n\n\
71         Only these are allowed: {allowed}.\n\
72         Provide exactly one source — `favicon.svg`, or a 512x512 \
73         `favicon-512.png` — and let the rest be generated."
74    )]
75    UnexpectedFavicons {
76        directory: &'static str,
77        count: usize,
78        unexpected: String,
79        allowed: String,
80    },
81
82    /// The raster icon source is not the required size.
83    #[error("`{path}` must be exactly {expected}x{expected}, but it is {width}x{height}")]
84    FaviconDimensions {
85        path: PathBuf,
86        expected: u32,
87        width: u32,
88        height: u32,
89    },
90
91    /// An image's dimensions could not be read.
92    #[error("failed to read the dimensions of `{path}`: {reason}")]
93    ReadImage { path: PathBuf, reason: String },
94
95    /// A declared asset is not in the manifest, so its URL would 404.
96    #[error(
97        "{count} declared asset(s) are missing from the manifest, so every URL \
98         pointing at them would 404:{missing}\n\nRun the static-asset pipeline, \
99         or correct the paths."
100    )]
101    UnresolvedAssets { count: usize, missing: String },
102
103    /// A generated icon is absent or the wrong size.
104    #[error("`{path}` should be {expected}x{expected} but is {found}")]
105    IconMismatch {
106        path: String,
107        expected: u32,
108        found: String,
109    },
110
111    /// `favicon.svg` could not be parsed.
112    #[error(
113        "failed to parse `favicon.svg`. Note that it must not rely on system \
114         fonts — convert any text to paths."
115    )]
116    RenderIcon {
117        #[source]
118        source: resvg::usvg::Error,
119    },
120
121    /// A pixel buffer of the requested size could not be allocated.
122    #[error("cannot rasterise an icon at {size}x{size}")]
123    IconDimensions { size: u32 },
124
125    /// A rendered icon could not be encoded. Carried as text because the
126    /// encoder's error type belongs to a crate this one does not name directly.
127    #[error("failed to encode a generated icon: {reason}")]
128    EncodeIcon { reason: String },
129
130    /// A generated icon could not be written.
131    #[error("failed to write the generated icon `{path}`")]
132    WriteIcon {
133        path: PathBuf,
134        #[source]
135        source: std::io::Error,
136    },
137
138    /// The manifest exists but is not valid JSON.
139    #[error("failed to parse the cache manifest at `{path}`")]
140    ParseManifest {
141        path: PathBuf,
142        #[source]
143        source: serde_json::Error,
144    },
145
146    /// A site has static assets but no manifest, so every hashed URL would 404.
147    #[error(
148        "`{path}` is missing but `static/` exists. Run `make gen_static_assets` \
149         — asset hashing happens at build time, not at startup."
150    )]
151    MissingManifest { path: PathBuf },
152
153    /// The cache manifest could not be written.
154    #[error("failed to write the cache manifest to `{path}`")]
155    WriteManifest {
156        path: PathBuf,
157        #[source]
158        source: std::io::Error,
159    },
160
161    /// The manifest could not be serialized.
162    #[error("failed to serialize the cache manifest")]
163    SerializeManifest(#[source] serde_json::Error),
164}