From d46d5fd87a14f26b04c059e3f1596e4cd8c19e5b Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Sun, 9 May 2021 22:31:59 +0100 Subject: [PATCH] bundles: Reorganise bundle error handling Signed-off-by: Ian Jackson --- src/bundles.rs | 103 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 95 insertions(+), 8 deletions(-) diff --git a/src/bundles.rs b/src/bundles.rs index 904e6967..800bad04 100644 --- a/src/bundles.rs +++ b/src/bundles.rs @@ -245,7 +245,12 @@ impl MgmtBundleList { impl From for LoadError { fn from(ze: ZipError) -> LoadError { - LE::BadBundle(format!("bad zipfile: {}", ze)) + match ze { + ZipError::Io(ioe) => IE::from( + AE::from(ioe).context("zipfile io error") + ).into(), + _ => LE::BadBundle(format!("bad zipfile: {}", ze)) + } } } @@ -274,13 +279,91 @@ impl ZipArchive where R: Read + io::Seek { pub trait ReadSeek: Read + io::Seek { } impl ReadSeek for T where T: Read + io::Seek { } -#[throws(LoadError)] -fn parse_bundle(id: Id, file: &mut dyn ReadSeek, _zpath: &str) -> Parsed { +trait BundleParseError: Sized { + fn required(bpath: &str, f:F) -> Result + where XE: Into, + F: FnOnce() -> Result; + + fn besteffort(bpath: &str, f:F, g:G) -> Result + where XE: Into, + F: FnOnce() -> Result, + G: FnOnce() -> T; +} + +#[derive(Debug,Error)] +enum ReloadError { + IE(IE), + Unloadable(BadBundle), +} +display_as_debug!{ReloadError} + +impl BundleParseError for ReloadError { + fn required(bpath: &str, f:F) -> Result + where XE: Into, + F: FnOnce() -> Result + { + use ReloadError as RLE; + f().map_err(|xe| { + let le: LE = xe.into(); + match le { + LE::BadBundle(why) => RLE::Unloadable( + format!("{}: {}", bpath, &why) + ), + LE::IE(IE::Anyhow(ae)) => RLE::IE(IE::Anyhow( + ae.context(bpath.to_owned()) + )), + LE::IE(ie) => RLE::IE(ie), + } + }) + } + + fn besteffort(bpath: &str, f:F, g:G) -> Result + where XE: Into, + F: FnOnce() -> Result, + G: FnOnce() -> T, + { + Ok(f().unwrap_or_else(|e| { + match e.into() { + LE::IE(ie) => { + error!("reloading, error, partially skipping {}: {}", bpath, ie); + }, + LE::BadBundle(why) => { + warn!("reloading, partially skipping {}: {}", bpath, why); + }, + } + g() + })) + } +} + +impl BundleParseError for LoadError { + fn required(_bpath: &str, f:F) -> Result + where XE: Into, + F: FnOnce() -> Result + { + f().map_err(Into::into) + } + + fn besteffort(_bpath: &str, f:F, _:G) -> Result + where XE: Into, + F: FnOnce() -> Result, + G: FnOnce() -> T, + { + f().map_err(Into::into) + } +} + +#[throws(EH)] +fn parse_bundle(id: Id, file: &mut dyn ReadSeek, bpath: &str) -> Parsed + where EH: BundleParseError +{ let file = BufReader::new(file); match id.kind { Kind::Zip => () } - let mut za = ZipArchive::new(file)?; + let mut za = EH::required(bpath, ||{ + ZipArchive::new(file) + })?; - let meta = { + let meta = EH::besteffort(bpath, ||{ let mut mf = za.by_name_caseless("otter.toml")?; let mut meta = String::new(); mf.read_to_string(&mut meta).map_err( @@ -289,8 +372,12 @@ fn parse_bundle(id: Id, file: &mut dyn ReadSeek, _zpath: &str) -> Parsed { |e| LE::BadBundle(format!("parse zip member as toml: {}", e)))?; let meta = toml_de::from_value(&meta).map_err( |e| LE::BadBundle(format!("interpret zip member metadata: {}", e)))?; - meta - }; + Ok::<_,LE>(meta) + }, ||{ + BundleMeta { + title: "[bundle metadata could not be reloaded]".to_owned() + } + })?; // todo: do actual things, eg libraries and specs @@ -463,7 +550,7 @@ impl InstanceBundles { file.rewind().context("rewind"). map_err(IE::from)?; let mut file = BufReader::new(file); - let parsed = parse_bundle(id, &mut file, &install)?; + let parsed = parse_bundle::(id, &mut file, &install)?; incorporate_bundle(self, ig, id, parsed)?; self.updated(ig); -- 2.30.2