History

feat!: allow to ignore IO errors when reading configuration files. (#790)

Sometimes, IO errors can occour consistently when reading from certain paths (on Windows, really), and it should be possible to not only see which path that is but also to ignore them entirely. Now IO errors contain the path of the failed configuration file. There is also a new option flag to ignore errors (off by default).

Sebastian Thiel committed 3 years ago

Commit e55f4ee1 parent 8f2accd6 files · +53 −9Browse files

Unified · Split

6 files
  1. Cargo.lock +1 −0
  2. gix-config/Cargo.toml +1 −0
  3. gix-config/src/file/init/comfort.rs +1 −1
  4. gix-config/src/file/init/from_paths.rs +45 −7
  5. gix-config/src/file/init/types.rs +4 −0
  6. gix-config/tests/file/init/from_paths/mod.rs +1 −1
Cargo.lock+1−0
@@ -1447,6 +1447,7 @@ dependencies = [ · 1446 unmodified lines
14471447 "gix-path 0.7.2",
14481448 "gix-ref 0.27.1",
14491449 "gix-sec 0.6.2",
1450+ "log",
14501451 "memchr",
14511452 "nom",
14521453 "once_cell",
gix-config/Cargo.toml+1−0
@@ -24,6 +24,7 @@ gix-sec = { version = "^0.6.2", path = "../gix-sec" } · 23 unmodified lines
2424 gix-ref = { version = "^0.27.0", path = "../gix-ref" }
2525 gix-glob = { version = "^0.5.5", path = "../gix-glob" }
2626
27+log = "0.4.17"
2728 nom = { version = "7", default_features = false, features = [ "std" ] }
2829 memchr = "2"
2930 thiserror = "1.0.26"
gix-config/src/file/init/comfort.rs+1−1
@@ -122,7 +122,7 @@ impl File<'static> { · 121 unmodified lines
122122 branch_name: None,
123123 },
124124 ),
125− lossy: false,
125+ ..Default::default()
126126 };
127127
128128 let mut globals = Self::from_globals()?;
gix-config/src/file/init/from_paths.rs+45−7
@@ -9,8 +9,11 @@ use crate::{ · 8 unmodified lines
99 #[derive(Debug, thiserror::Error)]
1010 #[allow(missing_docs)]
1111 pub enum Error {
12− #[error(transparent)]
13− Io(#[from] std::io::Error),
12+ #[error("The configuration file at \"{}\" could not be read", path.display())]
13+ Io {
14+ source: std::io::Error,
15+ path: std::path::PathBuf,
16+ },
1417 #[error(transparent)]
1518 Init(#[from] init::Error),
1619 }
@@ -22,10 +25,22 @@ impl File<'static> { · 5 unmodified lines
2225 /// Note that the path will be checked for ownership to derive trust.
2326 pub fn from_path_no_includes(path: impl Into<std::path::PathBuf>, source: crate::Source) -> Result<Self, Error> {
2427 let path = path.into();
25− let trust = gix_sec::Trust::from_path_ownership(&path)?;
28+ let trust = match gix_sec::Trust::from_path_ownership(&path) {
29+ Ok(t) => t,
30+ Err(err) => return Err(Error::Io { source: err, path }),
31+ };
2632
2733 let mut buf = Vec::new();
28− std::io::copy(&mut std::fs::File::open(&path)?, &mut buf)?;
34+ match std::io::copy(
35+ &mut match std::fs::File::open(&path) {
36+ Ok(f) => f,
37+ Err(err) => return Err(Error::Io { source: err, path }),
38+ },
39+ &mut buf,
40+ ) {
41+ Ok(_) => {}
42+ Err(err) => return Err(Error::Io { source: err, path }),
43+ }
2944
3045 Ok(File::from_bytes_owned(
3146 &mut buf,
@@ -69,14 +84,37 @@ impl File<'static> { · 37 unmodified lines
6984 }
7085
7186 buf.clear();
72− std::io::copy(
87+ match std::io::copy(
7388 &mut match std::fs::File::open(&path) {
7489 Ok(f) => f,
7590 Err(err) if !err_on_non_existing_paths && err.kind() == std::io::ErrorKind::NotFound => continue,
76− Err(err) => return Err(err.into()),
91+ Err(err) => {
92+ let err = Error::Io { source: err, path };
93+ if options.ignore_io_errors {
94+ log::warn!("ignoring: {err:#?}");
95+ continue;
96+ } else {
97+ return Err(err);
98+ }
99+ }
77100 },
78101 buf,
79− )?;
102+ ) {
103+ Ok(_) => {}
104+ Err(err) => {
105+ if options.ignore_io_errors {
106+ log::warn!(
107+ "ignoring: {:#?}",
108+ Error::Io {
109+ source: err,
110+ path: path.clone()
111+ }
112+ );
113+ } else {
114+ return Err(Error::Io { source: err, path });
115+ }
116+ }
117+ };
80118 meta.path = Some(path);
81119
82120 let config = Self::from_bytes_owned(buf, meta, options)?;
gix-config/src/file/init/types.rs+4−0
@@ -22,6 +22,10 @@ pub struct Options<'a> { · 21 unmodified lines
2222 /// Note that doing so will degenerate [`write_to()`][crate::File::write_to()] and strip it off its comments
2323 /// and additional whitespace entirely, but will otherwise be a valid configuration file.
2424 pub lossy: bool,
25+ /// If true, any IO error happening when reading a configuration file will be ignored.
26+ ///
27+ /// That way it's possible to pass multiple files and read as many as possible, to have 'something' instead of nothing.
28+ pub ignore_io_errors: bool,
2529 }
2630
2731 impl Options<'_> {
gix-config/tests/file/init/from_paths/mod.rs+1−1
@@ -18,7 +18,7 @@ mod from_path_no_includes { · 17 unmodified lines
1818
1919 let err = gix_config::File::from_path_no_includes(config_path, gix_config::Source::Local).unwrap_err();
2020 assert!(
21− matches!(err, gix_config::file::init::from_paths::Error::Io(io_error) if io_error.kind() == std::io::ErrorKind::NotFound)
21+ matches!(err, gix_config::file::init::from_paths::Error::Io{source: io_error, ..} if io_error.kind() == std::io::ErrorKind::NotFound)
2222 );
2323 }
2424