-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Switch from clap to quicli #2
Conversation
8f2b790
to
e3b334c
Compare
e3b334c
to
19cceb9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool!
Coming here from killercup/quicli#66 I just wanted to leave some comments on the error handling :)
This assumes you use quicli's Result
alias or a Result<_, ::failure::Error>
(Error
is also re-exported by quicli IIRC) in the functions where you return FontCreationError
right now.
use std::error::Error; | ||
|
||
#[derive(Debug)] | ||
pub struct FontCreationError { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You might want to use the failure crate and derive Fail
:)
src/main.rs
Outdated
if !input_dir.exists() { | ||
return Err(format!("Directory does not exist: {}", input_dir.to_string_lossy())); | ||
return Err(FontCreationError::new(format!("Directory does not exist: {}", input_dir.to_string_lossy()))); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be rewritten as
ensure!(input_dir.exists(), "Directory does not exist: {}", input_dir.to_string_lossy());
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where are the ensure!
and bail!
macros defined? I wasn't able to find their documentation when I was looking for them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Failure exports them: https://docs.rs/failure/0.1.1/failure/index.html#macros
src/main.rs
Outdated
} | ||
match glob(&input_dir.join("*.png").to_string_lossy()) { | ||
Ok(glob) => return Ok(glob), | ||
Err(e) => return Err(format!("Error listing files: {}", e)), | ||
Err(e) => return Err(FontCreationError::new(format!("Error listing files: {}", e))), | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rewrite that like
glob(&input_dir.join("*.png").to_string_lossy())
.with_context(|e| format!("Error listing files: {}", e))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this also require using failure
types? Attempting to use this nets the following error:
--> src/main.rs:52:5
|
48 | fn list_tiles(input_dir : &PathBuf) -> Result<Paths, FontCreationError> {
| -------------------------------- expected `std::result::Result<glob::Paths, sss_fontbuild::errors::FontCreationError>` because of return type
...
52 | / glob(&input_dir.join("*.png").to_string_lossy())
53 | | .with_context(|e| format!("Error listing files: {}", e))
| |________________________________________________________________^ expected struct `sss_fontbuild::errors::FontCreationError`, found struct `quicli::prelude::Context`
|
= note: expected type `std::result::Result<_, sss_fontbuild::errors::FontCreationError>`
found type `std::result::Result<_, quicli::prelude::Context<std::string::String>>`
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, it looks like I'm still seeing a variant on this even when I'm using an error type that implements Fail
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The concrete error type here is quicli::prelude::Context<std::string::String>
(feel free to read quicli::prelude::
as failure::
), so you need a return error type that has a From<Context<String>>
implementation. failure::Error
is a trait object which fulfills that. For you own type, you'd need to add that implementation specifically. Or, you know, just use failure::Error
:)
src/main.rs
Outdated
@@ -56,7 +76,7 @@ fn collapse_bits(bytes : &[u8]) -> Result<u8, String> { | |||
0 => result |= mask, | |||
1 => result &= !mask, | |||
_ => { | |||
return Err(format!("Bits must be either 0 or 1 (value was {})", *byte)); | |||
return Err(FontCreationError::new(format!("Bits must be either 0 or 1 (value was {})", *byte))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bail!("Bits must be either 0 or 1 (value was {})", *byte);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like both this and ensure!
are unhappy about the error type:
--> src/main.rs:79:17
|
79 | bail!("Bits must be either 0 or 1 (value was {})", *byte);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `sss_fontbuild::errors::FontCreationError`, found struct `quicli::prelude::Error`
|
= note: expected type `sss_fontbuild::errors::FontCreationError`
found type `quicli::prelude::Error`
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
Is the failure
create's Fail
trait necessary for this to work?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, the macro can't know how to construct your error with a string otherwise. (It calls failure's err_msg
internally which returns a failure::Error
.)
If you wanted, you could probably copypaste these macros into your code quite easily, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, I haven't tested if this works with quicli's re-export! You might need to include failure directly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, I haven't tested if this works with quicli's re-export!
With some quick testing, it looks like that's the case. quicli's re-export doesn't appear to make Fail
available. For example, trying to use it nets this error:
error[E0433]: failed to resolve. Maybe a missing `extern crate failure;`?
--> src/errors.rs:6:17
|
6 | #[derive(Debug, Fail)]
| ^^^^ Maybe a missing `extern crate failure;`?
So it does in fact look like the reexport isn't going to be available without independently using failure
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please ignore my earlier edit about the conflict - I misread an error message. However, it is the case that it doesn't seem to be possible to use Fail
without independently importing both failure
and failure_derive
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code failure_derive 0.1.1 produces seems to insert extern crate failure;
but I can't find the code as the crate seems to be undergoing quite a large refactoring. As probably all the comments here already tell you: We need to have a better story integrating failure :)
Ok(f) => target_file = f, | ||
Err(e) => { | ||
println!("Unable to open target file {}!\n{}", target, e); | ||
println!("Unable to open target file {}!\n{}", args.target.to_string_lossy(), e); | ||
exit(1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bail!("Unable to open target file {}!\n{}", args.target.to_string_lossy(), e);
(Returning the error exits main!
with a non-zero exit code)
After experimenting briefly with the failure types, and its macros, I didn't feel like the convenience it brought is worth the reduced readability/googleability for people who aren't familiar with them. Going to go with this version. Thanks! |
Clap is great, but it's a bit verbose. I'm liking the combo of StructOpt with quicli's
main!
macro.