1
1
#![ doc = include_str ! ( "../README.md" ) ]
2
2
3
+ mod error;
3
4
mod formatting;
4
5
6
+ pub use error:: OgImageError ;
7
+
5
8
use crate :: formatting:: { format_bytes, format_number} ;
6
- use anyhow:: { Context , anyhow} ;
7
9
use bytes:: Bytes ;
8
10
use crates_io_env_vars:: var;
9
11
use minijinja:: { Environment , context} ;
@@ -121,10 +123,10 @@ impl OgImageGenerator {
121
123
/// use crates_io_og_image::OgImageGenerator;
122
124
///
123
125
/// let generator = OgImageGenerator::from_environment()?;
124
- /// # Ok::<(), anyhow::Error >(())
126
+ /// # Ok::<(), crates_io_og_image::OgImageError >(())
125
127
/// ```
126
- pub fn from_environment ( ) -> anyhow :: Result < Self > {
127
- if let Some ( path) = var ( "TYPST_PATH" ) ? {
128
+ pub fn from_environment ( ) -> Result < Self , OgImageError > {
129
+ if let Some ( path) = var ( "TYPST_PATH" ) . map_err ( OgImageError :: EnvVarError ) ? {
128
130
Ok ( Self :: new ( PathBuf :: from ( path) ) )
129
131
} else {
130
132
Ok ( Self :: default ( ) )
@@ -140,7 +142,7 @@ impl OgImageGenerator {
140
142
& self ,
141
143
data : & ' a OgImageData < ' _ > ,
142
144
assets_dir : & std:: path:: Path ,
143
- ) -> anyhow :: Result < HashMap < & ' a str , String > > {
145
+ ) -> Result < HashMap < & ' a str , String > , OgImageError > {
144
146
let mut avatar_map = HashMap :: new ( ) ;
145
147
146
148
let client = reqwest:: Client :: new ( ) ;
@@ -155,18 +157,27 @@ impl OgImageGenerator {
155
157
Bytes :: from_static ( include_bytes ! ( "../assets/test-avatar.png" ) )
156
158
} else {
157
159
// Download the avatar from the URL
158
- let response = client. get ( * avatar) . send ( ) . await ;
159
- let response = response
160
- . with_context ( || format ! ( "Failed to download avatar from URL: {avatar}" ) ) ?;
161
-
162
- response. bytes ( ) . await . with_context ( || {
163
- format ! ( "Failed to read avatar bytes from URL: {avatar}" )
160
+ let response = client. get ( * avatar) . send ( ) . await . map_err ( |err| {
161
+ OgImageError :: AvatarDownloadError {
162
+ url : ( * avatar) . to_string ( ) ,
163
+ source : err,
164
+ }
165
+ } ) ?;
166
+
167
+ let bytes = response. bytes ( ) . await ;
168
+ bytes. map_err ( |err| OgImageError :: AvatarDownloadError {
169
+ url : ( * avatar) . to_string ( ) ,
170
+ source : err,
164
171
} ) ?
165
172
} ;
166
173
167
174
// Write the bytes to the avatar file
168
- let result = fs:: write ( & avatar_path, bytes) . await ;
169
- result. with_context ( || format ! ( "Failed to write avatar to {avatar_path:?}" ) ) ?;
175
+ fs:: write ( & avatar_path, bytes) . await . map_err ( |err| {
176
+ OgImageError :: AvatarWriteError {
177
+ path : avatar_path. clone ( ) ,
178
+ source : err,
179
+ }
180
+ } ) ?;
170
181
171
182
// Store the mapping from the avatar source to the numbered filename
172
183
avatar_map. insert ( * avatar, filename) ;
@@ -184,7 +195,7 @@ impl OgImageGenerator {
184
195
& self ,
185
196
data : & OgImageData < ' _ > ,
186
197
avatar_map : & HashMap < & str , String > ,
187
- ) -> anyhow :: Result < String > {
198
+ ) -> Result < String , OgImageError > {
188
199
let template = TEMPLATE_ENV . get_template ( "og-image.typ" ) ?;
189
200
let rendered = template. render ( context ! { data, avatar_map } ) ?;
190
201
Ok ( rendered)
@@ -199,10 +210,10 @@ impl OgImageGenerator {
199
210
/// # Examples
200
211
///
201
212
/// ```no_run
202
- /// use crates_io_og_image::{OgImageGenerator, OgImageData, OgImageAuthorData};
213
+ /// use crates_io_og_image::{OgImageGenerator, OgImageData, OgImageAuthorData, OgImageError };
203
214
///
204
215
/// # #[tokio::main]
205
- /// # async fn main() -> anyhow:: Result<()> {
216
+ /// # async fn main() -> Result<(), OgImageError > {
206
217
/// let generator = OgImageGenerator::default();
207
218
/// let data = OgImageData {
208
219
/// name: "my-crate",
@@ -220,9 +231,9 @@ impl OgImageGenerator {
220
231
/// # Ok(())
221
232
/// # }
222
233
/// ```
223
- pub async fn generate ( & self , data : OgImageData < ' _ > ) -> anyhow :: Result < NamedTempFile > {
234
+ pub async fn generate ( & self , data : OgImageData < ' _ > ) -> Result < NamedTempFile , OgImageError > {
224
235
// Create a temporary folder
225
- let temp_dir = tempfile:: tempdir ( ) ?;
236
+ let temp_dir = tempfile:: tempdir ( ) . map_err ( OgImageError :: TempDirError ) ?;
226
237
227
238
// Create assets directory and copy logo and icons
228
239
let assets_dir = temp_dir. path ( ) . join ( "assets" ) ;
@@ -253,7 +264,7 @@ impl OgImageGenerator {
253
264
fs:: write ( & typ_file_path, rendered) . await ?;
254
265
255
266
// Create a named temp file for the output PNG
256
- let output_file = NamedTempFile :: new ( ) ?;
267
+ let output_file = NamedTempFile :: new ( ) . map_err ( OgImageError :: TempFileError ) ?;
257
268
258
269
// Run typst compile command
259
270
let output = Command :: new ( & self . typst_binary_path )
@@ -263,11 +274,17 @@ impl OgImageGenerator {
263
274
. arg ( & typ_file_path)
264
275
. arg ( output_file. path ( ) )
265
276
. output ( )
266
- . await ?;
277
+ . await
278
+ . map_err ( OgImageError :: TypstNotFound ) ?;
267
279
268
280
if !output. status . success ( ) {
269
- let stderr = String :: from_utf8_lossy ( & output. stderr ) ;
270
- return Err ( anyhow ! ( "typst compile failed: {stderr}" ) ) ;
281
+ let stderr = String :: from_utf8_lossy ( & output. stderr ) . to_string ( ) ;
282
+ let stdout = String :: from_utf8_lossy ( & output. stdout ) . to_string ( ) ;
283
+ return Err ( OgImageError :: TypstCompilationError {
284
+ stderr,
285
+ stdout,
286
+ exit_code : output. status . code ( ) ,
287
+ } ) ;
271
288
}
272
289
273
290
Ok ( output_file)
0 commit comments