From 787967106ca614037cace3fc876f06aad0f5cd49 Mon Sep 17 00:00:00 2001 From: "Azzam S.A" Date: Wed, 4 Jan 2023 05:58:42 +0700 Subject: [PATCH] feat: print config snippets of error location --- src/config.rs | 30 ++++++++++++++++++------------ src/error.rs | 10 ++++++++-- src/main.rs | 3 ++- src/output.rs | 6 +++--- 4 files changed, 31 insertions(+), 18 deletions(-) diff --git a/src/config.rs b/src/config.rs index b525b10..3cdfb86 100755 --- a/src/config.rs +++ b/src/config.rs @@ -4,6 +4,7 @@ use std::{ path::{Path, PathBuf}, }; +use miette::{NamedSource, Result, SourceOffset}; use serde::Deserialize; use crate::error::Error; @@ -21,26 +22,31 @@ pub struct Config { pub fn read

(filename: P) -> Result where - P: AsRef + AsRef, + P: AsRef, + P: AsRef, { let file_content = fs::read_to_string(&filename).map_err(|_| Error::ConfigNotFound { path: PathBuf::from(&filename), })?; - deserialize(&file_content) + deserialize(&file_content, &filename) } /// Deserialize config intro struct. -/// # Errors -/// -/// Will return `Err` if deserialization error. -/// Possibly the error contains a position (line number) of the occurred error -/// But this is not accurate. All the other apps that depend on toml.rs -/// share the same faith. -fn deserialize(content: &str) -> Result { +fn deserialize

(content: &str, filename: P) -> Result +where + P: AsRef, + P: AsRef, +{ match toml::from_str(content) { Ok(config) => Ok(config), - Err(e) => Err(Error::InvalidConfig { - message: e.to_string(), - }), + Err(e) => { + let (line, column) = &e.line_col().unwrap_or((0, 0)); + let filename = Path::new(&filename); + Err(Error::InvalidConfig { + src: NamedSource::new(filename.to_string_lossy(), content.to_owned()), + bad_bit: SourceOffset::from_location(content, line + 1, column + 1), + message: e.to_string(), + })? + } } } diff --git a/src/error.rs b/src/error.rs index 7586af2..33f6be4 100755 --- a/src/error.rs +++ b/src/error.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use miette::Diagnostic; +use miette::{Diagnostic, NamedSource, SourceOffset}; use thiserror::Error; /// all possible errors returned by the app. @@ -29,7 +29,13 @@ pub enum Error { url(docsrs), help("See the configuration example https://github.com/BiznetGIO/digs#usage") )] - InvalidConfig { message: String }, + InvalidConfig { + #[source_code] + src: NamedSource, + #[label("{message}")] + bad_bit: SourceOffset, + message: String, + }, } impl std::convert::From for Error { diff --git a/src/main.rs b/src/main.rs index 3a5f3a1..b44bc68 100755 --- a/src/main.rs +++ b/src/main.rs @@ -20,7 +20,8 @@ fn run() -> Result<()> { cli::RecordType::TXT => RecordType::TXT, }; - let printer = Printer::new(domain, record_type, opts.config); + let config_file = opts.config; + let printer = Printer::new(domain, record_type, config_file); printer.print()?; Ok(()) } diff --git a/src/output.rs b/src/output.rs index 21e5373..7ec55f2 100644 --- a/src/output.rs +++ b/src/output.rs @@ -10,7 +10,7 @@ use crate::{config, dns}; pub struct Printer { domain: String, record_type: RecordType, - config: PathBuf, + config_file: PathBuf, } impl Printer { @@ -18,11 +18,11 @@ impl Printer { Self { domain, record_type, - config, + config_file: config, } } pub fn print(&self) -> Result<(), Error> { - let config = config::read(&self.config)?; + let config = config::read(&self.config_file)?; for server in config.servers { let response = dns::query(&self.domain, self.record_type, &server.ip);