Skip to content
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

Merged
merged 5 commits into from
Feb 21, 2018
Merged

Switch from clap to quicli #2

merged 5 commits into from
Feb 21, 2018

Conversation

mistydemeo
Copy link
Collaborator

Clap is great, but it's a bit verbose. I'm liking the combo of StructOpt with quicli's main! macro.

Copy link

@killercup killercup left a 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 {

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())));
}
Copy link

@killercup killercup Feb 19, 2018

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());

Copy link
Collaborator Author

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.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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))),
}

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))

Copy link
Collaborator Author

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>>`

Copy link
Collaborator Author

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.

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)));

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);

Copy link
Collaborator Author

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?

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.

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.

Copy link
Collaborator Author

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.

Copy link
Collaborator Author

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.

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);

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)

@mistydemeo
Copy link
Collaborator Author

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!

@mistydemeo mistydemeo merged commit a7dbad3 into master Feb 21, 2018
@mistydemeo mistydemeo deleted the switch_to_quicli branch February 21, 2018 04:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants