Skip to content

Commit f443154

Browse files
authored
Feature: Error Handling with thiserror & anyhow (#15)
1 parent d48a4dd commit f443154

File tree

6 files changed

+104
-34
lines changed

6 files changed

+104
-34
lines changed

Cargo.lock

Lines changed: 60 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ bin-dir = "{ name }-{ version }-{ target }/{ bin }{ binary-ext }"
1717
pkg-fmt = "tgz"
1818

1919
[dependencies]
20+
anyhow = { version = "1.0.77", features = ["backtrace"] }
2021
clap = { version = "4.4.6", features = ["derive", "wrap_help"] }
2122
clap_complete = { version = "4.4.4", optional = true }
2223
clap-verbosity-flag = "2.1.0"
@@ -32,6 +33,7 @@ serde = { version = "1.0.188", features = ["derive"] }
3233
serde_json = { version = "1.0.107", features = ["preserve_order"] }
3334
serde_jsonc = { version = "1.0.107", features = ["preserve_order"] }
3435
tar = "0.4.40"
36+
thiserror = "1.0.52"
3537

3638
[target.'cfg(windows)'.dependencies]
3739
ascii_table = "4.0.3"

src/init.rs

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use std::collections::HashMap;
22
use std::env;
3-
use std::error::Error;
43
use std::fmt::{self, Display};
54
use std::fs::{self, File};
65
use std::io::{self, Read, Write};
@@ -48,10 +47,31 @@ pub struct InitArgs {
4847
workspace_folder: Option<PathBuf>,
4948
}
5049

50+
#[allow(clippy::enum_variant_names)]
51+
#[derive(thiserror::Error, Debug)]
52+
pub enum InitError {
53+
#[error(transparent)]
54+
ParseBoolError(#[from] std::str::ParseBoolError),
55+
#[error(transparent)]
56+
IOError(#[from] std::io::Error),
57+
#[error(transparent)]
58+
SystemTimeError(#[from] std::time::SystemTimeError),
59+
#[error(transparent)]
60+
RegexBuildError(#[from] regex::Error),
61+
#[error(transparent)]
62+
JsonError(#[from] serde_json::error::Error),
63+
#[error(transparent)]
64+
JsonWithCommentsError(#[from] serde_jsonc::error::Error),
65+
#[error(transparent)]
66+
PromptError(#[from] inquire::error::InquireError),
67+
#[error(transparent)]
68+
OciPkgError(#[from] ocipkg::error::Error),
69+
}
70+
5171
fn get_feature(
5272
index: &registry::DevcontainerIndex,
5373
feature_ref: &OciReference,
54-
) -> Result<registry::Feature, Box<dyn Error>> {
74+
) -> ocipkg::error::Result<registry::Feature> {
5575
log::debug!("get_feature");
5676

5777
match index.get_feature(&feature_ref.id()) {
@@ -60,7 +80,7 @@ fn get_feature(
6080
}
6181
}
6282

63-
fn pull_feature_configuration(feature_ref: &OciReference) -> Result<registry::Feature, Box<dyn Error>> {
83+
fn pull_feature_configuration(feature_ref: &OciReference) -> ocipkg::error::Result<registry::Feature> {
6484
log::debug!("pull_feature_configuration");
6585
let bytes = registry::pull_archive_bytes(feature_ref)?;
6686
let mut archive = Archive::new(bytes.as_slice());
@@ -166,7 +186,7 @@ impl<'t> DevOptionPrompt<'t> {
166186
}
167187
}
168188

169-
fn display_prompt(&self) -> Result<DevOptionPromptValue, Box<dyn Error>> {
189+
fn display_prompt(&self) -> Result<DevOptionPromptValue, InitError> {
170190
let dev_option = self.inner;
171191
let default = dev_option.configured_default();
172192

@@ -276,7 +296,7 @@ impl FeatureEntryBuilder {
276296
}
277297
}
278298

279-
fn use_prompt_values(&mut self, feature: &registry::Feature) -> Result<(), Box<dyn Error>> {
299+
fn use_prompt_values(&mut self, feature: &registry::Feature) -> Result<(), InitError> {
280300
log::debug!("FeatureEntryBuilder::use_prompt_values");
281301
let key = format!("{}:{}", feature.id, feature.major_version);
282302
let value = {
@@ -335,7 +355,7 @@ struct TemplateBuilder {
335355
}
336356

337357
impl TemplateBuilder {
338-
fn new(template_ref: &OciReference, config: Option<registry::Template>) -> Result<Self, Box<dyn Error>> {
358+
fn new(template_ref: &OciReference, config: Option<registry::Template>) -> ocipkg::error::Result<Self> {
339359
log::debug!("TemplateBuilder::new");
340360
let archive_bytes = registry::pull_archive_bytes(template_ref)?;
341361
let template_archive = TemplateBuilder {
@@ -352,7 +372,7 @@ impl TemplateBuilder {
352372
Archive::new(self.archive_bytes.as_slice())
353373
}
354374

355-
fn replace_config(&mut self) -> Result<(), Box<dyn Error>> {
375+
fn replace_config(&mut self) -> std::io::Result<()> {
356376
log::debug!("TemplateBuilder::replace_config");
357377
let mut tar = self.as_archive();
358378
let entries = tar.entries()?;
@@ -380,7 +400,7 @@ impl TemplateBuilder {
380400
))?
381401
}
382402

383-
fn use_prompt_values(&mut self) -> Result<(), Box<dyn Error>> {
403+
fn use_prompt_values(&mut self) -> Result<(), InitError> {
384404
log::debug!("TemplateBuilder::use_prompt_values");
385405
let config = self
386406
.config
@@ -400,7 +420,7 @@ impl TemplateBuilder {
400420
Ok(())
401421
}
402422

403-
fn use_default_values(&mut self) -> Result<(), Box<dyn Error>> {
423+
fn use_default_values(&mut self) -> std::io::Result<()> {
404424
log::debug!("TemplateBuilder::use_default_values");
405425
let config = self
406426
.config
@@ -447,11 +467,7 @@ impl TemplateBuilder {
447467
false
448468
}
449469

450-
fn apply_context_and_features(
451-
&mut self,
452-
attempt_single_file: bool,
453-
workspace: &Path,
454-
) -> Result<(), Box<dyn Error>> {
470+
fn apply_context_and_features(&mut self, attempt_single_file: bool, workspace: &Path) -> Result<(), InitError> {
455471
log::debug!("TemplateBuilder::apply_context_and_features");
456472
let template_option_re = Regex::new(r"\$\{templateOption:\s*(?<name>\w+)\s*\}")?;
457473
let apply_context = |captures: &Captures| -> &[u8] {
@@ -548,7 +564,7 @@ impl TemplateBuilder {
548564
Ok(())
549565
}
550566

551-
fn create_empty_start_point() -> Result<Self, Box<dyn Error>> {
567+
fn create_empty_start_point() -> Result<Self, InitError> {
552568
let template_value = serde_json::json!({
553569
"id": "tyedev-base-template",
554570
"version": "1.0.0",
@@ -695,7 +711,7 @@ pub fn init(
695711
include_deprecated,
696712
workspace_folder,
697713
}: InitArgs,
698-
) -> Result<(), Box<dyn Error>> {
714+
) -> Result<(), InitError> {
699715
log::debug!("init");
700716
// Do this evaluation of the `env` first so that it can error early.
701717
let workspace = workspace_folder.map_or_else(env::current_dir, Ok)?;
@@ -818,12 +834,11 @@ pub fn init(
818834
// TODO these are more *proof of concept* than actual tests...
819835
#[cfg(test)]
820836
mod tests {
821-
use super::{FeatureEntryBuilder, TemplateBuilder};
837+
use super::{FeatureEntryBuilder, InitError, TemplateBuilder};
822838
use serde_json::{self, Map, Value};
823-
use std::error::Error;
824839

825840
#[test]
826-
fn test_feature_entry_builder_as_value() -> Result<(), Box<dyn Error>> {
841+
fn test_feature_entry_builder_as_value() -> serde_json::error::Result<()> {
827842
let mut feature_entry_builder = FeatureEntryBuilder::default();
828843

829844
let git_id = "ghcr.io/devcontainers/git:1";
@@ -843,7 +858,7 @@ mod tests {
843858
}
844859

845860
#[test]
846-
fn test_create_empty_start_point() -> Result<(), Box<dyn Error>> {
861+
fn test_create_empty_start_point() -> Result<(), InitError> {
847862
let _template_builder = TemplateBuilder::create_empty_start_point()?;
848863
Ok(())
849864
}

src/inspect.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use std::error::Error;
21
use std::fmt::{self, Display};
32
use std::io::{self, Read, Write};
43

@@ -85,7 +84,7 @@ impl TableData {
8584
}
8685

8786
trait Displayable: serde::Serialize {
88-
fn display_json(&self) -> Result<(), Box<dyn Error>> {
87+
fn display_json(&self) -> serde_json::error::Result<()> {
8988
let json = serde_json::to_string_pretty(self)?;
9089
println!("{json}");
9190
Ok(())
@@ -206,7 +205,7 @@ impl Displayable for registry::Template {
206205
}
207206
}
208207

209-
fn display<T: ?Sized + Displayable>(value: &T, format: &InspectDisplay) -> Result<(), Box<dyn Error>> {
208+
fn display<T: ?Sized + Displayable>(value: &T, format: &InspectDisplay) -> serde_json::error::Result<()> {
210209
log::debug!("display: as {}", format);
211210

212211
match format {
@@ -218,7 +217,7 @@ fn display<T: ?Sized + Displayable>(value: &T, format: &InspectDisplay) -> Resul
218217
Ok(())
219218
}
220219

221-
fn display_files(oci_ref: &OciReference) -> Result<(), Box<dyn Error>> {
220+
fn display_files(oci_ref: &OciReference) -> ocipkg::error::Result<()> {
222221
log::debug!("display_files");
223222

224223
let bytes = registry::pull_archive_bytes(oci_ref)?;
@@ -242,7 +241,7 @@ fn display_files(oci_ref: &OciReference) -> Result<(), Box<dyn Error>> {
242241
Ok(())
243242
}
244243

245-
fn display_install_sh(oci_ref: &OciReference) -> Result<(), Box<dyn Error>> {
244+
fn display_install_sh(oci_ref: &OciReference) -> ocipkg::error::Result<()> {
246245
log::debug!("display_install_sh");
247246

248247
let bytes = registry::pull_archive_bytes(oci_ref)?;
@@ -277,7 +276,7 @@ pub fn inspect(
277276
install_sh,
278277
show_files,
279278
}: InspectArgs,
280-
) -> Result<(), Box<dyn Error>> {
279+
) -> ocipkg::error::Result<()> {
281280
log::debug!("inspect");
282281

283282
let id = oci_ref.id();

src/main.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use std::env;
2-
use std::error::Error;
32
use std::ffi::OsStr;
43
use std::fs;
54
use std::io;
@@ -71,7 +70,7 @@ fn data_directory<P: AsRef<Path>>(namespace: P) -> io::Result<PathBuf> {
7170
}
7271
}
7372

74-
fn main() -> Result<(), Box<dyn Error>> {
73+
fn main() -> Result<(), anyhow::Error> {
7574
let args = Args::parse();
7675

7776
env_logger::Builder::new()

src/search.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use std::error::Error;
21
use std::fmt;
32

43
use clap::builder::PossibleValue;
@@ -165,7 +164,7 @@ pub fn search(
165164
fields,
166165
include_deprecated,
167166
}: SearchArgs,
168-
) -> Result<(), Box<dyn Error>> {
167+
) -> serde_json::error::Result<()> {
169168
log::debug!("search");
170169

171170
let search_fields =

0 commit comments

Comments
 (0)