Parcourir la source

Nicely print CLI errors with their causes

timvisee il y a 7 ans
Parent
commit
8ae79c3e4f
6 fichiers modifiés avec 82 ajouts et 50 suppressions
  1. 28 18
      Cargo.lock
  2. 27 27
      api/src/action/download.rs
  3. 1 0
      cli/Cargo.toml
  4. 2 1
      cli/src/action/download.rs
  5. 1 0
      cli/src/main.rs
  6. 23 4
      cli/src/util.rs

+ 28 - 18
Cargo.lock

@@ -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"

+ 27 - 27
api/src/action/download.rs

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

+ 1 - 0
cli/Cargo.toml

@@ -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"

+ 2 - 1
cli/src/action/download.rs

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

+ 1 - 0
cli/src/main.rs

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

+ 23 - 4
cli/src/util.rs

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