comparison rust/hg-core/src/errors.rs @ 46638:1f55cd5b292f

rust: Add a log file rotation utility This is ported to Rust from `mercurial/loggingutil.py`. The "builder" pattern is used to make it visible at call sites what the two numeric parameters mean. In Python they might simply by keyword arguments. Differential Revision: https://phab.mercurial-scm.org/D10010
author Simon Sapin <simon.sapin@octobus.net>
date Thu, 11 Feb 2021 15:51:11 +0100
parents bc08c2331f99
children 3d692e724d06
comparison
equal deleted inserted replaced
46637:bc08c2331f99 46638:1f55cd5b292f
39 #[from] 39 #[from]
40 ConfigValueParseError(ConfigValueParseError), 40 ConfigValueParseError(ConfigValueParseError),
41 } 41 }
42 42
43 /// Details about where an I/O error happened 43 /// Details about where an I/O error happened
44 #[derive(Debug, derive_more::From)] 44 #[derive(Debug)]
45 pub enum IoErrorContext { 45 pub enum IoErrorContext {
46 /// A filesystem operation for the given file 46 ReadingFile(std::path::PathBuf),
47 #[from] 47 WritingFile(std::path::PathBuf),
48 File(std::path::PathBuf), 48 RemovingFile(std::path::PathBuf),
49 RenamingFile {
50 from: std::path::PathBuf,
51 to: std::path::PathBuf,
52 },
49 /// `std::env::current_dir` 53 /// `std::env::current_dir`
50 CurrentDir, 54 CurrentDir,
51 /// `std::env::current_exe` 55 /// `std::env::current_exe`
52 CurrentExe, 56 CurrentExe,
53 } 57 }
107 111
108 // TODO: use `DisplayBytes` instead to show non-Unicode filenames losslessly? 112 // TODO: use `DisplayBytes` instead to show non-Unicode filenames losslessly?
109 impl fmt::Display for IoErrorContext { 113 impl fmt::Display for IoErrorContext {
110 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 114 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
111 match self { 115 match self {
112 IoErrorContext::File(path) => path.display().fmt(f), 116 IoErrorContext::ReadingFile(path) => {
113 IoErrorContext::CurrentDir => f.write_str("current directory"), 117 write!(f, "when reading {}", path.display())
114 IoErrorContext::CurrentExe => f.write_str("current executable"), 118 }
119 IoErrorContext::WritingFile(path) => {
120 write!(f, "when writing {}", path.display())
121 }
122 IoErrorContext::RemovingFile(path) => {
123 write!(f, "when removing {}", path.display())
124 }
125 IoErrorContext::RenamingFile { from, to } => write!(
126 f,
127 "when renaming {} to {}",
128 from.display(),
129 to.display()
130 ),
131 IoErrorContext::CurrentDir => write!(f, "current directory"),
132 IoErrorContext::CurrentExe => write!(f, "current executable"),
115 } 133 }
116 } 134 }
117 } 135 }
118 136
119 pub trait IoResultExt<T> { 137 pub trait IoResultExt<T> {
120 /// Annotate a possible I/O error as related to a file at the given path. 138 /// Annotate a possible I/O error as related to a reading a file at the
139 /// given path.
121 /// 140 ///
122 /// This allows printing something like “File not found: example.txt” 141 /// This allows printing something like “File not found when reading
123 /// instead of just “File not found”. 142 /// example.txt” instead of just “File not found”.
124 /// 143 ///
125 /// Converts a `Result` with `std::io::Error` into one with `HgError`. 144 /// Converts a `Result` with `std::io::Error` into one with `HgError`.
126 fn for_file(self, path: &std::path::Path) -> Result<T, HgError>; 145 fn when_reading_file(self, path: &std::path::Path) -> Result<T, HgError>;
146
147 fn with_context(
148 self,
149 context: impl FnOnce() -> IoErrorContext,
150 ) -> Result<T, HgError>;
127 } 151 }
128 152
129 impl<T> IoResultExt<T> for std::io::Result<T> { 153 impl<T> IoResultExt<T> for std::io::Result<T> {
130 fn for_file(self, path: &std::path::Path) -> Result<T, HgError> { 154 fn when_reading_file(self, path: &std::path::Path) -> Result<T, HgError> {
155 self.with_context(|| IoErrorContext::ReadingFile(path.to_owned()))
156 }
157
158 fn with_context(
159 self,
160 context: impl FnOnce() -> IoErrorContext,
161 ) -> Result<T, HgError> {
131 self.map_err(|error| HgError::IoError { 162 self.map_err(|error| HgError::IoError {
132 error, 163 error,
133 context: IoErrorContext::File(path.to_owned()), 164 context: context(),
134 }) 165 })
135 } 166 }
136 } 167 }
137 168
138 pub trait HgResultExt<T> { 169 pub trait HgResultExt<T> {