summaryrefslogtreecommitdiffstats
path: root/ignore
diff options
context:
space:
mode:
authorAndrew Gallant <jamslam@gmail.com>2017-04-12 18:12:34 -0400
committerAndrew Gallant <jamslam@gmail.com>2017-04-12 18:14:23 -0400
commitc50b8b4125dc7f1181944dd92d0aca97c2450421 (patch)
tree6420424f7dcfdbd12867da5159c2a8dbf1ba1d82 /ignore
parent7ad23e5565e9dca308c52929571c0609c28291c6 (diff)
Add better error messages for invalid globs.
This threads the original glob given by end users through all of the glob parsing errors. This was slightly trickier than it might appear because the gitignore implementation actually modifies the glob before compiling it. So in order to get better glob error messages everywhere, we need to track the original glob both in the glob parser and in the higher-level abstractions in the `ignore` crate. Fixes #444
Diffstat (limited to 'ignore')
-rw-r--r--ignore/src/gitignore.rs14
-rw-r--r--ignore/src/lib.rs21
-rw-r--r--ignore/src/types.rs9
3 files changed, 36 insertions, 8 deletions
diff --git a/ignore/src/gitignore.rs b/ignore/src/gitignore.rs
index 4972dcd5..68655261 100644
--- a/ignore/src/gitignore.rs
+++ b/ignore/src/gitignore.rs
@@ -279,7 +279,12 @@ impl GitignoreBuilder {
let nignore = self.globs.iter().filter(|g| !g.is_whitelist()).count();
let nwhite = self.globs.iter().filter(|g| g.is_whitelist()).count();
let set = try!(
- self.builder.build().map_err(|err| Error::Glob(err.to_string())));
+ self.builder.build().map_err(|err| {
+ Error::Glob {
+ glob: None,
+ err: err.to_string(),
+ }
+ }));
Ok(Gitignore {
set: set,
root: self.root.clone(),
@@ -420,7 +425,12 @@ impl GitignoreBuilder {
GlobBuilder::new(&glob.actual)
.literal_separator(literal_separator)
.build()
- .map_err(|err| Error::Glob(err.to_string())));
+ .map_err(|err| {
+ Error::Glob {
+ glob: Some(glob.original.clone()),
+ err: err.kind().to_string(),
+ }
+ }));
self.builder.add(parsed);
self.globs.push(glob);
Ok(self)
diff --git a/ignore/src/lib.rs b/ignore/src/lib.rs
index c93a4de7..d053014c 100644
--- a/ignore/src/lib.rs
+++ b/ignore/src/lib.rs
@@ -112,7 +112,17 @@ pub enum Error {
/// An error that occurs when doing I/O, such as reading an ignore file.
Io(io::Error),
/// An error that occurs when trying to parse a glob.
- Glob(String),
+ Glob {
+ /// The original glob that caused this error. This glob, when
+ /// available, always corresponds to the glob provided by an end user.
+ /// e.g., It is the glob as writtein in a `.gitignore` file.
+ ///
+ /// (This glob may be distinct from the glob that is actually
+ /// compiled, after accounting for `gitignore` semantics.)
+ glob: Option<String>,
+ /// The underlying glob error as a string.
+ err: String,
+ },
/// A type selection for a file type that is not defined.
UnrecognizedFileType(String),
/// A user specified file type definition could not be parsed.
@@ -144,7 +154,7 @@ impl Error {
Error::WithDepth { ref err, .. } => err.is_io(),
Error::Loop { .. } => false,
Error::Io(_) => true,
- Error::Glob(_) => false,
+ Error::Glob { .. } => false,
Error::UnrecognizedFileType(_) => false,
Error::InvalidDefinition => false,
}
@@ -199,7 +209,7 @@ impl error::Error for Error {
Error::WithDepth { ref err, .. } => err.description(),
Error::Loop { .. } => "file system loop found",
Error::Io(ref err) => err.description(),
- Error::Glob(ref msg) => msg,
+ Error::Glob { ref err, .. } => err,
Error::UnrecognizedFileType(_) => "unrecognized file type",
Error::InvalidDefinition => "invalid definition",
}
@@ -227,7 +237,10 @@ impl fmt::Display for Error {
child.display(), ancestor.display())
}
Error::Io(ref err) => err.fmt(f),
- Error::Glob(ref msg) => write!(f, "{}", msg),
+ Error::Glob { glob: None, ref err } => write!(f, "{}", err),
+ Error::Glob { glob: Some(ref glob), ref err } => {
+ write!(f, "error parsing glob '{}': {}", glob, err)
+ }
Error::UnrecognizedFileType(ref ty) => {
write!(f, "unrecognized file type: {}", ty)
}
diff --git a/ignore/src/types.rs b/ignore/src/types.rs
index 407da309..2b8c1ddb 100644
--- a/ignore/src/types.rs
+++ b/ignore/src/types.rs
@@ -448,13 +448,18 @@ impl TypesBuilder {
GlobBuilder::new(glob)
.literal_separator(true)
.build()
- .map_err(|err| Error::Glob(err.to_string()))));
+ .map_err(|err| {
+ Error::Glob {
+ glob: Some(glob.to_string()),
+ err: err.kind().to_string(),
+ }
+ })));
glob_to_selection.push((isel, iglob));
}
selections.push(selection.clone().map(move |_| def));
}
let set = try!(build_set.build().map_err(|err| {
- Error::Glob(err.to_string())
+ Error::Glob { glob: None, err: err.to_string() }
}));
Ok(Types {
defs: defs,