1
0
mirror of https://github.com/timvisee/ffsend.git synced 2025-01-31 19:51:35 +01:00

Nicely print CLI errors with their causes

This commit is contained in:
timvisee 2018-03-27 23:31:25 +02:00
parent a4b7736019
commit 8ae79c3e4f
No known key found for this signature in database
GPG Key ID: 109CBA0BF74036C2
6 changed files with 82 additions and 50 deletions

46
Cargo.lock generated
View File

@ -173,6 +173,14 @@ dependencies = [
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "colored"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "constant_time_eq"
version = "0.1.3"
@ -331,6 +339,7 @@ version = "0.1.0"
dependencies = [
"clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)",
"clipboard 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ffsend-api 0.1.0",
"open 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -366,7 +375,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "futures"
version = "0.1.19"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -374,7 +383,7 @@ name = "futures-cpupool"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -417,7 +426,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"base64 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -439,7 +448,7 @@ name = "hyper-tls"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)",
"native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
@ -881,7 +890,7 @@ name = "relay"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -899,7 +908,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"encoding_rs 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper-tls 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libflate 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1141,7 +1150,7 @@ name = "tokio"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-executor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1157,7 +1166,7 @@ version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1174,7 +1183,7 @@ name = "tokio-executor"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1183,7 +1192,7 @@ version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1192,7 +1201,7 @@ name = "tokio-proto"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1209,7 +1218,7 @@ name = "tokio-reactor"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1222,7 +1231,7 @@ name = "tokio-service"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1231,7 +1240,7 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1244,7 +1253,7 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-deque 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1256,7 +1265,7 @@ name = "tokio-tls"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
"native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1268,7 +1277,7 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1460,6 +1469,7 @@ dependencies = [
"checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536"
"checksum clipboard 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b9b4623b47d8637fc9d47564583d4cc01eb8c8e34e26b2bf348bf4b036acb657"
"checksum clipboard-win 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "14cc3e6c075926b96490d5f90d4a5af7be8012a4d8a8698e619655085a7641a3"
"checksum colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0aa3473e85a3161b59845d6096b289bb577874cafeaf75ea1b1beaa6572c7fc"
"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
"checksum core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25bfd746d203017f7d5cbd31ee5d8e17f94b6521c7af77ece6c9e4b2d4b16c67"
"checksum core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "065a5d7ffdcbc8fa145d6f0746f3555025b9097a9e9cda59f7467abae670c78d"
@ -1480,7 +1490,7 @@ dependencies = [
"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
"checksum futures 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f32b9e9aaa890fe8b9453b27ebbf3d11136a5ce59032500effd0e707bbcd80"
"checksum futures 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5a3176836efa0b37f0e321b86672dfada1564aeb516fbed67b7c24050a0263"
"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4"
"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d"
"checksum hkdf 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "706d158974721895e9234c91af77ee28bbbf561fa276b014f32d685d27fbdc30"

View File

@ -343,25 +343,25 @@ pub enum Error {
/// A general error occurred while requesting the file data.
/// This may be because authentication failed, because decrypting the
/// file metadata didn't succeed, or due to some other reason.
#[fail(display = "failed to request file data")]
#[fail(display = "Failed to request file data")]
Request(#[cause] RequestError),
/// The given Send file has expired, or did never exist in the first place.
/// Therefore the file could not be downloaded.
#[fail(display = "the file has expired or did never exist")]
#[fail(display = "The file has expired or did never exist")]
Expired,
/// An error occurred while downloading the file.
#[fail(display = "failed to download the file")]
#[fail(display = "Failed to download the file")]
Download(#[cause] DownloadError),
/// An error occurred while decrypting the downloaded file.
#[fail(display = "failed to decrypt the downloaded file")]
#[fail(display = "Failed to decrypt the downloaded file")]
Decrypt,
/// An error occurred while opening or writing to the target file.
// TODO: show what file this is about
#[fail(display = "could not open the file for writing")]
#[fail(display = "Couldn't use the target file")]
File(#[cause] FileError),
}
@ -374,11 +374,11 @@ impl From<AuthError> for Error {
#[derive(Fail, Debug)]
pub enum RequestError {
/// Failed authenticating, in order to fetch the file data.
#[fail(display = "failed to authenticate")]
#[fail(display = "Failed to authenticate")]
Auth(#[cause] AuthError),
/// Failed to retrieve the file metadata.
#[fail(display = "failed to retrieve file metadata")]
#[fail(display = "Failed to retrieve file metadata")]
Meta(#[cause] MetaError),
}
@ -386,24 +386,24 @@ pub enum RequestError {
pub enum AuthError {
/// Sending the request to gather the authentication encryption nonce
/// failed.
#[fail(display = "failed to request authentication nonce")]
#[fail(display = "Failed to request authentication nonce")]
NonceReq,
/// The response for fetching the authentication encryption nonce
/// indicated an error and wasn't successful.
#[fail(display = "bad HTTP response '{}' while requesting authentication nonce", _1)]
#[fail(display = "Bad HTTP response '{}' while requesting authentication nonce", _1)]
NonceReqStatus(StatusCode, String),
/// No authentication encryption nonce was included in the response
/// from the server, it was missing.
#[fail(display = "missing authentication nonce in server response")]
#[fail(display = "Missing authentication nonce in server response")]
NoNonceHeader,
/// The authentication encryption nonce from the response malformed or
/// empty.
/// Maybe the server responded with a new format that isn't supported yet
/// by this client.
#[fail(display = "received malformed authentication nonce")]
#[fail(display = "Received malformed authentication nonce")]
MalformedNonce,
}
@ -411,36 +411,36 @@ pub enum AuthError {
pub enum MetaError {
/// An error occurred while computing the cryptographic signature used for
/// decryption.
#[fail(display = "failed to compute cryptographic signature")]
#[fail(display = "Failed to compute cryptographic signature")]
ComputeSignature,
/// Sending the request to gather the metadata encryption nonce failed.
#[fail(display = "failed to request metadata nonce")]
#[fail(display = "Failed to request metadata nonce")]
NonceReq,
/// The response for fetching the metadata encryption nonce indicated an
/// error and wasn't successful.
#[fail(display = "bad HTTP response '{}' while requesting metadata nonce", _1)]
#[fail(display = "Bad HTTP response '{}' while requesting metadata nonce", _1)]
NonceReqStatus(StatusCode, String),
/// No metadata encryption nonce was included in the response from the
/// server, it was missing.
#[fail(display = "missing metadata nonce in server response")]
#[fail(display = "Missing metadata nonce in server response")]
NoNonceHeader,
/// The metadata encryption nonce from the response malformed or empty.
/// Maybe the server responded with a new format that isn't supported yet
/// by this client.
#[fail(display = "received malformed metadata nonce")]
#[fail(display = "Received malformed metadata nonce")]
MalformedNonce,
/// The received metadata is malformed, and couldn't be decoded or
/// interpreted.
#[fail(display = "received malformed metadata")]
#[fail(display = "Received malformed metadata")]
Malformed,
/// Failed to decrypt the received metadata.
#[fail(display = "failed to decrypt received metadata")]
#[fail(display = "Failed to decrypt received metadata")]
Decrypt,
}
@ -448,47 +448,47 @@ pub enum MetaError {
pub enum DownloadError {
/// An error occurred while computing the cryptographic signature used for
/// downloading the file.
#[fail(display = "failed to compute cryptographic signature")]
#[fail(display = "Failed to compute cryptographic signature")]
ComputeSignature,
/// Sending the request to gather the metadata encryption nonce failed.
#[fail(display = "failed to request file download")]
#[fail(display = "Failed to request file download")]
Request,
/// The response for downloading the indicated an error and wasn't successful.
#[fail(display = "bad HTTP response '{}' while requesting file download", _1)]
#[fail(display = "Bad HTTP response '{}' while requesting file download", _1)]
RequestStatus(StatusCode, String),
/// The length of the file is missing, thus the length of the file to download
/// couldn't be determined.
#[fail(display = "couldn't determine file download length, missing property")]
#[fail(display = "Couldn't determine file download length, missing property")]
NoLength,
/// Failed to start or update the downloading progress, because of this the
/// download can't continue.
#[fail(display = "failed to update download progress")]
#[fail(display = "Failed to update download progress")]
Progress,
/// The actual download and decryption process the server.
/// This covers reading the file from the server, decrypting the file,
/// and writing it to the file system.
#[fail(display = "failed to download the file")]
#[fail(display = "Failed to download the file")]
Download,
/// Verifiying the downloaded file failed.
#[fail(display = "file verification failed")]
#[fail(display = "File verification failed")]
Verify,
}
#[derive(Fail, Debug)]
pub enum FileError {
/// An error occurred while creating or opening the file to write to.
#[fail(display = "failed to create or open file")]
#[fail(display = "Failed to create or replace the file")]
Create(#[cause] IoError),
/// Failed to create an encrypted writer for the file, which is used to
/// decrypt the downloaded file.
#[fail(display = "failed to create file decryptor")]
#[fail(display = "Failed to create file decryptor")]
EncryptedWriter,
}

View File

@ -14,6 +14,7 @@ default = ["clipboard"]
[dependencies]
clap = "2.31"
clipboard = { version = "0.4", optional = true }
colored = "1.6"
failure = "0.1"
ffsend-api = { version = "*", path = "../api" }
open = "1"

View File

@ -1,5 +1,6 @@
use std::sync::{Arc, Mutex};
use failure::Fail;
use ffsend_api::action::download::Download as ApiDownload;
use ffsend_api::file::file::DownloadFile;
use ffsend_api::reqwest::Client;
@ -40,7 +41,7 @@ impl<'a> Download<'a> {
// Execute an download action
// TODO: do not unwrap, but return an error
if let Err(err) = ApiDownload::new(&file).invoke(&client, bar) {
quit_error(err);
quit_error(err.context("Failed to download the requested file"));
}
// TODO: open the file, or it's location

View File

@ -1,3 +1,4 @@
extern crate failure;
extern crate ffsend_api;
mod action;

View File

@ -1,6 +1,6 @@
#[cfg(feature = "clipboard")]
extern crate clipboard;
extern crate failure;
extern crate colored;
extern crate open;
#[cfg(feature = "clipboard")]
@ -11,14 +11,33 @@ use std::process::{exit, ExitStatus};
#[cfg(feature = "clipboard")]
use self::clipboard::{ClipboardContext, ClipboardProvider};
use self::failure::{Fail};
use self::colored::*;
use failure::{self, Fail};
use ffsend_api::url::Url;
/// Print the given error in a proper format for the user,
/// with it's causes.
pub fn print_error<E: Fail>(err: E) {
// Print the main error
eprintln!("{} {}", "error:".red().bold(), err);
// Print the causes
let mut cause = err.cause();
while let Some(err) = cause {
eprintln!("{} {}", "caused by:".red().bold(), err);
cause = err.cause();
}
}
/// Quit the application with an error code,
/// and print the given error.
pub fn quit_error<E: Fail>(err: E) -> ! {
// Print the error message
eprintln!("error: {}", err);
// Print the error
print_error(err);
// Print some additional information
eprintln!("\nFor detailed errors try '{}'", "--verbose".yellow());
eprintln!("For more information try '{}'", "--help".yellow());
// Quit
exit(1);