feat: improve error messages

This commit is contained in:
2021-04-21 00:40:13 +02:00
parent 54e174eb0a
commit 5cf98b3c17
3 changed files with 54 additions and 44 deletions

View File

@@ -148,7 +148,7 @@ pub fn config() -> Result<Config> {
.subcommand(SubCommand::with_name("init").about("writes an example config")) .subcommand(SubCommand::with_name("init").about("writes an example config"))
.get_matches(); .get_matches();
let current_dir = std::env::current_dir().context("could not get current directory")?; let current_dir = std::env::current_dir().context("Could not get current directory")?;
let config_path = arg_matches.value_of_os("config"); let config_path = arg_matches.value_of_os("config");
let force_load = config_path.is_some(); let force_load = config_path.is_some();
@@ -163,17 +163,17 @@ pub fn config() -> Result<Config> {
.create_new(true) .create_new(true)
.open(&config_path) .open(&config_path)
.and_then(|mut f| f.write_all(std::include_bytes!("../example.audio-conv.yaml"))) .and_then(|mut f| f.write_all(std::include_bytes!("../example.audio-conv.yaml")))
.with_context(|| format!("unable to write config file to {}", config_path.display()))?; .with_context(|| format!("Unable to write config file to {}", config_path.display()))?;
std::process::exit(0); std::process::exit(0);
} }
let config_dir = config_path let config_dir = config_path
.parent() .parent()
.context("could not get parent directory of the config file")?; .context("Could not get parent directory of the config file")?;
let config_file = load_config_file(&config_path) let config_file = load_config_file(&config_path)
.with_context(|| format!("failed loading config file \"{}\"", config_path.display()))?; .with_context(|| format!("Failed loading config file {}", config_path.display()))?;
if force_load && config_file.is_none() { if force_load && config_file.is_none() {
return Err(Error::msg(format!( return Err(Error::msg(format!(
@@ -185,7 +185,7 @@ pub fn config() -> Result<Config> {
let default_regex = RegexBuilder::new("\\.(flac|wav)$") let default_regex = RegexBuilder::new("\\.(flac|wav)$")
.case_insensitive(true) .case_insensitive(true)
.build() .build()
.expect("failed compiling default match regex"); .expect("Failed compiling default match regex");
let transcode_matches = config_file let transcode_matches = config_file
.as_ref() .as_ref()
@@ -198,8 +198,8 @@ pub fn config() -> Result<Config> {
let glob = GlobBuilder::new(glob) let glob = GlobBuilder::new(glob)
.case_insensitive(true) .case_insensitive(true)
.build() .build()
.context("failed building glob")?; .context("Failed building glob")?;
let regex = Regex::new(glob.regex()).context("failed compiling regex")?; let regex = Regex::new(glob.regex()).context("Failed compiling regex")?;
Ok(regex) Ok(regex)
}); });
@@ -207,7 +207,7 @@ pub fn config() -> Result<Config> {
let regex = RegexBuilder::new(regex) let regex = RegexBuilder::new(regex)
.case_insensitive(true) .case_insensitive(true)
.build() .build()
.context("failed compiling regex")?; .context("Failed compiling regex")?;
Ok(regex) Ok(regex)
}); });
@@ -219,7 +219,7 @@ pub fn config() -> Result<Config> {
let regex = RegexBuilder::new(&ext) let regex = RegexBuilder::new(&ext)
.case_insensitive(true) .case_insensitive(true)
.build() .build()
.context("failed compiling regex")?; .context("Failed compiling regex")?;
Ok(regex) Ok(regex)
}); });
@@ -262,7 +262,7 @@ pub fn config() -> Result<Config> {
}) })
.ok_or_else(|| Error::msg("\"from\" not configured"))? .ok_or_else(|| Error::msg("\"from\" not configured"))?
.canonicalize() .canonicalize()
.context("could not canonicalize \"from\" path")? .context("Could not canonicalize \"from\" path")?
}, },
to: arg_matches to: arg_matches
.value_of_os("to") .value_of_os("to")
@@ -276,7 +276,7 @@ pub fn config() -> Result<Config> {
}) })
.ok_or_else(|| Error::msg("\"to\" not configured"))? .ok_or_else(|| Error::msg("\"to\" not configured"))?
.canonicalize() .canonicalize()
.context("could not canonicalize \"to\" path")?, .context("Could not canonicalize \"to\" path")?,
matches: transcode_matches, matches: transcode_matches,
}) })
} }
@@ -288,6 +288,6 @@ fn load_config_file(path: &Path) -> Result<Option<ConfigFile>> {
Err(err) => return Err(Error::new(err)), Err(err) => return Err(Error::new(err)),
}; };
let config: ConfigFile = let config: ConfigFile =
serde_yaml::from_reader(&mut file).context("could not parse config file")?; serde_yaml::from_reader(&mut file).context("Could not parse config file")?;
Ok(Some(config)) Ok(Some(config))
} }

View File

@@ -52,12 +52,12 @@ struct GErrorMessage {
fn gmake<T: IsA<Element>>(factory_name: &str) -> Result<T> { fn gmake<T: IsA<Element>>(factory_name: &str) -> Result<T> {
let res = gstreamer::ElementFactory::make(factory_name, None) let res = gstreamer::ElementFactory::make(factory_name, None)
.with_context(|| format!("could not make gstreamer Element \"{}\"", factory_name))? .with_context(|| format!("Could not make gstreamer Element \"{}\"", factory_name))?
.downcast() .downcast()
.ok() .ok()
.with_context(|| { .with_context(|| {
format!( format!(
"could not cast gstreamer Element \"{}\" into `{}`", "Could not cast gstreamer Element \"{}\" into `{}`",
factory_name, factory_name,
std::any::type_name::<T>() std::any::type_name::<T>()
) )
@@ -97,7 +97,7 @@ fn get_conversion_args(config: &Config) -> impl Iterator<Item = Result<Conversio
let rel_path = e.path().strip_prefix(&config.from).with_context(|| { let rel_path = e.path().strip_prefix(&config.from).with_context(|| {
format!( format!(
"unable to get relative path for {} from {}", "Unable to get relative path for {} from {}",
e.path().display(), e.path().display(),
config.from.display() config.from.display()
) )
@@ -112,7 +112,10 @@ fn get_conversion_args(config: &Config) -> impl Iterator<Item = Result<Conversio
.map_err(Error::new) .map_err(Error::new)
.and_then(|md| md.modified().map_err(Error::new)) .and_then(|md| md.modified().map_err(Error::new))
.with_context(|| { .with_context(|| {
format!("unable to get mtime for from file {}", e.path().display()) format!(
"Unable to get mtime for \"from\" file {}",
e.path().display()
)
})?; })?;
let to_mtime = to.metadata().and_then(|md| md.modified()); let to_mtime = to.metadata().and_then(|md| md.modified());
match to_mtime { match to_mtime {
@@ -120,7 +123,7 @@ fn get_conversion_args(config: &Config) -> impl Iterator<Item = Result<Conversio
Err(err) if err.kind() == std::io::ErrorKind::NotFound => true, Err(err) if err.kind() == std::io::ErrorKind::NotFound => true,
Err(err) => { Err(err) => {
return Err(err).with_context(|| { return Err(err).with_context(|| {
format!("unable to get mtime for to file {}", to.display()) format!("Unable to get mtime for \"to\" file {}", to.display())
}) })
} }
} }
@@ -147,15 +150,15 @@ async fn main() -> Result<()> {
let main_handle = async move { let main_handle = async move {
let ok = task::spawn_local(main_loop(ui_queue)) let ok = task::spawn_local(main_loop(ui_queue))
.await .await
.context("main task failed")??; .context("Main task failed")??;
Result::<_>::Ok(ok) Result::<_>::Ok(ok)
}; };
let ui_handle = async move { let ui_handle = async move {
let ok = task::spawn_local(ui_fut) let ok = task::spawn_local(ui_fut)
.await .await
.context("ui task failed")? .context("Ui task failed")?
.context("ui failed")?; .context("Ui failed")?;
Result::<_>::Ok(ok) Result::<_>::Ok(ok)
}; };
@@ -168,20 +171,20 @@ async fn main() -> Result<()> {
async fn main_loop(ui_queue: ui::MsgQueue) -> Result<()> { async fn main_loop(ui_queue: ui::MsgQueue) -> Result<()> {
let (config, conv_args) = task::spawn_blocking(|| -> Result<_> { let (config, conv_args) = task::spawn_blocking(|| -> Result<_> {
gstreamer::init()?; gstreamer::init()?;
let config = config::config().context("could not get the config")?; let config = config::config().context("Could not get the config")?;
let conv_args = get_conversion_args(&config) let conv_args = get_conversion_args(&config)
.collect::<Result<Vec<_>>>() .collect::<Result<Vec<_>>>()
.context("failed loading dir structure")?; .context("Failed loading dir structure")?;
Ok((config, conv_args)) Ok((config, conv_args))
}) })
.await .await
.context("init task failed")??; .context("Init task failed")??;
let log_path = Path::new(".") let log_path = Path::new(".")
.canonicalize() .canonicalize()
.context("unable to canonicalize path to log file")? .context("Unable to canonicalize path to log file")?
.join("audio-conv.log"); .join("audio-conv.log");
ui_queue.push(ui::Msg::Init { ui_queue.push(ui::Msg::Init {
@@ -206,7 +209,7 @@ async fn main_loop(ui_queue: ui::MsgQueue) -> Result<()> {
Ok(()) => ui_queue.push(ui::Msg::TaskEnd { id: i }), Ok(()) => ui_queue.push(ui::Msg::TaskEnd { id: i }),
Err(err) => { Err(err) => {
let err = err.context(format!( let err = err.context(format!(
"failed transcoding \"{}\"", "Transcoding failed for {}",
args.rel_from_path.display() args.rel_from_path.display()
)); ));
@@ -268,7 +271,7 @@ async fn transcode(
fs::create_dir_all( fs::create_dir_all(
to_path to_path
.parent() .parent()
.with_context(|| format!("could not get parent dir for {}", to_path.display()))?, .with_context(|| format!("Could not get parent dir for {}", to_path.display()))?,
) )
.await?; .await?;
@@ -281,7 +284,7 @@ async fn transcode(
Transcode::Copy => { Transcode::Copy => {
fs::copy(&from_path, &to_path_tmp).await.with_context(|| { fs::copy(&from_path, &to_path_tmp).await.with_context(|| {
format!( format!(
"could not copy file from {} to {}", "Could not copy file from {} to {}",
from_path.display(), from_path.display(),
to_path_tmp.display() to_path_tmp.display()
) )
@@ -303,7 +306,7 @@ async fn transcode(
fs::rename(&to_path_tmp, &to_path).await.with_context(|| { fs::rename(&to_path_tmp, &to_path).await.with_context(|| {
format!( format!(
"could not rename temporary file {} to {}", "Could not rename temporary file {} to {}",
to_path_tmp.display(), to_path_tmp.display(),
to_path.display() to_path.display()
) )
@@ -385,7 +388,7 @@ async fn transcode_gstreamer(
"bitrate", "bitrate",
&i32::from(*bitrate) &i32::from(*bitrate)
.checked_mul(1_000) .checked_mul(1_000)
.context("bitrate overflowed")?, .context("Bitrate overflowed")?,
)?; )?;
encoder.set_property_from_str( encoder.set_property_from_str(
"bitrate-type", "bitrate-type",
@@ -468,7 +471,9 @@ async fn transcode_gstreamer(
} }
}); });
let bus = pipeline.get_bus().context("pipe get bus")?; let bus = pipeline
.get_bus()
.context("Could not get bus for pipeline")?;
pipeline pipeline
.set_state(gstreamer::State::Playing) .set_state(gstreamer::State::Playing)
@@ -489,11 +494,9 @@ async fn transcode_gstreamer(
Ok(false) Ok(false)
} }
MessageView::Error(err) => { MessageView::Error(err) => {
pipeline.set_state(gstreamer::State::Null).context( let pipe_stop_res = pipeline.set_state(gstreamer::State::Null);
"Unable to set the pipeline to the `Null` state, after error",
)?;
let err = err let err: Error = err
.get_details() .get_details()
.and_then(|details| { .and_then(|details| {
if details.get_name() != "error-details" { if details.get_name() != "error-details" {
@@ -519,7 +522,15 @@ async fn transcode_gstreamer(
} }
.into() .into()
}); });
Err(err)
if let Err(pipe_err) = pipe_stop_res {
let err = err.context(pipe_err).context(
"Unable to set the pipeline to the `Null` state, after error",
);
Err(err)
} else {
Err(err)
}
} }
_ => Ok(true), _ => Ok(true),
} }
@@ -532,8 +543,7 @@ async fn transcode_gstreamer(
} }
}) })
.try_for_each(|_| futures::future::ready(Ok(()))) .try_for_each(|_| futures::future::ready(Ok(())))
.await .await?;
.context("failed converting")?;
Result::<_>::Ok(()) Result::<_>::Ok(())
}; };
@@ -597,7 +607,7 @@ where
Err(fs_err) => { Err(fs_err) => {
let err = err let err = err
.context(fs_err) .context(fs_err)
.context(format!("removing {} failed", path.display())); .context(format!("Removing file {} failed", path.display()));
Err(err) Err(err)
} }
}, },

View File

@@ -88,7 +88,7 @@ impl State {
Msg::TaskEnd { id } => { Msg::TaskEnd { id } => {
self.running_tasks self.running_tasks
.remove(&id) .remove(&id)
.context("unable to remove finished task; could't find task")?; .context("Unable to remove finished task; could't find task")?;
self.ended_tasks += 1; self.ended_tasks += 1;
} }
Msg::TaskProgress { id, ratio } => { Msg::TaskProgress { id, ratio } => {
@@ -102,7 +102,7 @@ impl State {
// TODO // TODO
self.running_tasks self.running_tasks
.remove(&id) .remove(&id)
.context("unable to remove errored task; could't find task")?; .context("Unable to remove errored task; could't find task")?;
self.ended_tasks += 1; self.ended_tasks += 1;
self.has_errored = true; self.has_errored = true;
} }
@@ -136,7 +136,7 @@ impl State {
running_tasks.sort_by_key(|task| task.id); running_tasks.sort_by_key(|task| task.id);
if !self.has_rendered { if !self.has_rendered {
self.terminal.clear().context("cleaning ui failed")?; self.terminal.clear().context("Clearing ui failed")?;
self.has_rendered = true; self.has_rendered = true;
} }
@@ -222,7 +222,7 @@ impl State {
chunks[1], chunks[1],
); );
}) })
.context("rendering ui failed")?; .context("Rendering ui failed")?;
Ok(()) Ok(())
} }
@@ -267,8 +267,8 @@ pub fn init() -> (MsgQueue, impl Future<Output = Result<()>>) {
} }
}) })
.await .await
.context("ui update task failed")? .context("Ui update task failed")?
.context("ui update failed")?; .context("Ui update failed")?;
match render_res { match render_res {
Some(s) => wrapped = Some(s), Some(s) => wrapped = Some(s),