refactor(tauri) update error handling crate to anyhow+thiserror, close #613 (#621)

* Replace error-chain with thiserror in util crate

* Replace errorchain with anyhow/thiserror in api

* Replace with anyhow/thiserror in updater

* Replace with anyhow/thiserror in tauri

* Fix error handling on windows
This commit is contained in:
Wu Yu Wei 2020-05-30 07:22:04 +08:00 committed by GitHub
parent 974cd3d8ed
commit c23675b5e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 256 additions and 321 deletions

View File

@ -22,7 +22,8 @@ tempfile = "3"
either = "1.5.3"
tar = "0.4"
flate2 = "1"
error-chain = "0.12"
anyhow = "1.0.31"
thiserror = "1.0.19"
rand = "0.7"
nfd = "0.0.4"
attohttpc = {version = "0.13.0", features=["json", "form" ]}

View File

@ -10,35 +10,28 @@ use tauri_utils::platform;
#[cfg(not(windows))]
pub fn get_output(cmd: String, args: Vec<String>, stdout: Stdio) -> crate::Result<String> {
Command::new(cmd)
.args(args)
.stdout(stdout)
.output()
.map_err(|err| crate::Error::with_chain(err, "Command: get output failed"))
.and_then(|output| {
if output.status.success() {
Ok(String::from_utf8_lossy(&output.stdout).to_string())
} else {
Err(crate::ErrorKind::Command(String::from_utf8_lossy(&output.stderr).to_string()).into())
}
})
let output = Command::new(cmd).args(args).stdout(stdout).output()?;
if output.status.success() {
Ok(String::from_utf8_lossy(&output.stdout).to_string())
} else {
Err(crate::Error::Command(String::from_utf8_lossy(&output.stderr).to_string()).into())
}
}
#[cfg(windows)]
pub fn get_output(cmd: String, args: Vec<String>, stdout: Stdio) -> crate::Result<String> {
Command::new(cmd)
let output = Command::new(cmd)
.args(args)
.stdout(stdout)
.creation_flags(CREATE_NO_WINDOW)
.output()
.map_err(|err| crate::Error::with_chain(err, "Command: get output failed"))
.and_then(|output| {
if output.status.success() {
Ok(String::from_utf8_lossy(&output.stdout).to_string())
} else {
Err(crate::ErrorKind::Command(String::from_utf8_lossy(&output.stderr).to_string()).into())
}
})
.output()?;
if output.status.success() {
Ok(String::from_utf8_lossy(&output.stdout).to_string())
} else {
Err(crate::Error::Command(String::from_utf8_lossy(&output.stderr).to_string()).into())
}
}
pub fn format_command(path: String, command: String) -> String {
@ -52,7 +45,7 @@ pub fn format_command(path: String, command: String) -> String {
pub fn relative_command(command: String) -> crate::Result<String> {
match std::env::current_exe()?.parent() {
Some(exe_dir) => Ok(format_command(exe_dir.display().to_string(), command)),
None => Err(crate::ErrorKind::Command("Could not evaluate executable dir".to_string()).into()),
None => Err(crate::Error::Command("Could not evaluate executable dir".to_string()).into()),
}
}
@ -60,7 +53,7 @@ pub fn relative_command(command: String) -> crate::Result<String> {
pub fn command_path(command: String) -> crate::Result<String> {
match std::env::current_exe()?.parent() {
Some(exe_dir) => Ok(format!("{}/{}", exe_dir.display().to_string(), command)),
None => Err(crate::ErrorKind::Command("Could not evaluate executable dir".to_string()).into()),
None => Err(crate::Error::Command("Could not evaluate executable dir".to_string()).into()),
}
}
@ -68,7 +61,7 @@ pub fn command_path(command: String) -> crate::Result<String> {
pub fn command_path(command: String) -> crate::Result<String> {
match std::env::current_exe()?.parent() {
Some(exe_dir) => Ok(format!("{}/{}.exe", exe_dir.display().to_string(), command)),
None => Err(crate::ErrorKind::Command("Could not evaluate executable dir".to_string()).into()),
None => Err(crate::Error::Command("Could not evaluate executable dir".to_string()).into()),
}
}
@ -106,7 +99,8 @@ pub fn binary_command(binary_name: String) -> crate::Result<String> {
#[cfg(test)]
mod test {
use super::*;
use crate::{Error, ErrorKind};
use crate::Error;
use std::io;
use totems::{assert_err, assert_ok};
#[test]
@ -141,7 +135,7 @@ mod test {
assert_err!(&res);
// destruct the Error to check the ErrorKind and test that it is a Command type.
if let Err(Error(ErrorKind::Command(e), _)) = &res {
if let Some(Error::Command(e)) = res.unwrap_err().downcast_ref::<Error>() {
// assert that the message in the error matches this string.
assert_eq!(*e, "cat: test/: Is a directory\n".to_string());
}
@ -200,7 +194,7 @@ mod test {
assert_err!(&res);
// after asserting that the result is an error, check that the error kind is ErrorKind::Io
if let Err(Error(ErrorKind::Io(s), _)) = &res {
if let Some(s) = res.unwrap_err().downcast_ref::<io::Error>() {
// assert that the ErrorKind inside of the ErrorKind Io is ErrorKind::NotFound
assert_eq!(s.kind(), std::io::ErrorKind::NotFound);
}

View File

@ -1,33 +1,43 @@
use nfd::{DialogType, open_dialog};
pub use nfd::Response;
use nfd::{open_dialog, DialogType};
fn open_dialog_internal(dialog_type: DialogType, filter: Option<String>, default_path: Option<String>) -> crate::Result<Response> {
open_dialog(filter.as_deref(), default_path.as_deref(), dialog_type)
.map_err(|err| crate::Error::with_chain(err, "open dialog failed"))
.and_then(|response| {
match response {
Response::Cancel => Err(crate::Error::from("user cancelled")),
_ => Ok(response)
}
})
fn open_dialog_internal(
dialog_type: DialogType,
filter: Option<String>,
default_path: Option<String>,
) -> crate::Result<Response> {
let response = open_dialog(filter.as_deref(), default_path.as_deref(), dialog_type)?;
match response {
Response::Cancel => Err(crate::Error::Dialog("user cancelled".into()).into()),
_ => Ok(response),
}
}
/// Open single select file dialog
pub fn select(filter_list: Option<String>, default_path: Option<String>) -> crate::Result<Response> {
open_dialog_internal(DialogType::SingleFile, filter_list, default_path)
pub fn select(
filter_list: Option<String>,
default_path: Option<String>,
) -> crate::Result<Response> {
open_dialog_internal(DialogType::SingleFile, filter_list, default_path)
}
/// Open mulitple select file dialog
pub fn select_multiple(filter_list: Option<String>, default_path: Option<String>) -> crate::Result<Response> {
open_dialog_internal(DialogType::MultipleFiles, filter_list, default_path)
pub fn select_multiple(
filter_list: Option<String>,
default_path: Option<String>,
) -> crate::Result<Response> {
open_dialog_internal(DialogType::MultipleFiles, filter_list, default_path)
}
/// Open save dialog
pub fn save_file(filter_list: Option<String>, default_path: Option<String>) -> crate::Result<Response> {
open_dialog_internal(DialogType::SaveFile, filter_list, default_path)
pub fn save_file(
filter_list: Option<String>,
default_path: Option<String>,
) -> crate::Result<Response> {
open_dialog_internal(DialogType::SaveFile, filter_list, default_path)
}
/// Open pick folder dialog
pub fn pick_folder(default_path: Option<String>) -> crate::Result<Response> {
open_dialog_internal(DialogType::PickFolder, None, default_path)
open_dialog_internal(DialogType::PickFolder, None, default_path)
}

View File

@ -18,7 +18,7 @@ pub struct DiskEntry {
fn is_dir(file_name: String) -> crate::Result<bool> {
match metadata(file_name) {
Ok(md) => Result::Ok(md.is_dir()),
Err(err) => Result::Err(err.to_string().into()),
Err(err) => Result::Err(err.into()),
}
}
@ -43,21 +43,18 @@ pub fn walk_dir(path_copy: String) -> crate::Result<Vec<DiskEntry>> {
}
pub fn list_dir_contents(dir_path: String) -> crate::Result<Vec<DiskEntry>> {
fs::read_dir(dir_path)
.map_err(|err| crate::Error::with_chain(err, "read dir failed"))
.and_then(|paths| {
let mut dirs: Vec<DiskEntry> = vec![];
for path in paths {
let dir_path = path.expect("dirpath error").path();
let _dir_name = dir_path.display();
dirs.push(DiskEntry {
path: format!("{}", _dir_name),
is_dir: true,
name: get_dir_name_from_path(_dir_name.to_string()),
});
}
Ok(dirs)
})
let paths = fs::read_dir(dir_path)?;
let mut dirs: Vec<DiskEntry> = vec![];
for path in paths {
let dir_path = path.expect("dirpath error").path();
let _dir_name = dir_path.display();
dirs.push(DiskEntry {
path: format!("{}", _dir_name),
is_dir: true,
name: get_dir_name_from_path(_dir_name.to_string()),
});
}
Ok(dirs)
}
pub fn with_temp_dir<F: FnOnce(&tempfile::TempDir) -> ()>(callback: F) -> crate::Result<()> {

View File

@ -3,27 +3,27 @@ mod file_move;
use std::fs;
use crate::{Error, ErrorKind};
use crate::Error;
pub use extract::*;
pub use file_move::*;
pub fn read_string(file: String) -> crate::Result<String> {
fs::read_to_string(file)
.map_err(|err| Error::from(ErrorKind::File(format!("Read_string failed: {}", err))))
.map_err(|err| Error::File(format!("Read_string failed: {}", err)).into())
.map(|c| c)
}
pub fn read_binary(file: String) -> crate::Result<Vec<u8>> {
fs::read(file)
.map_err(|err| Error::from(ErrorKind::File(format!("Read_binary failed: {}", err))))
.map_err(|err| Error::File(format!("Read_binary failed: {}", err)).into())
.map(|b| b)
}
#[cfg(test)]
mod test {
use super::*;
use crate::{Error, ErrorKind};
use crate::Error;
use totems::{assert_err, assert_ok};
#[test]
@ -47,15 +47,15 @@ mod test {
assert_err!(res);
if let Err(Error(ErrorKind::File(e), _)) = res {
if let Some(Error::File(e)) = res.unwrap_err().downcast_ref::<Error>() {
#[cfg(windows)]
assert_eq!(
e,
*e,
"Read_string failed: Access is denied. (os error 5)".to_string()
);
#[cfg(not(windows))]
assert_eq!(
e,
*e,
"Read_string failed: Is a directory (os error 21)".to_string()
);
}
@ -93,15 +93,15 @@ mod test {
assert_err!(res);
if let Err(Error(ErrorKind::File(e), _)) = res {
if let Some(Error::File(e)) = res.unwrap_err().downcast_ref::<Error>() {
#[cfg(windows)]
assert_eq!(
e,
*e,
"Read_binary failed: Access is denied. (os error 5)".to_string()
);
#[cfg(not(windows))]
assert_eq!(
e,
*e,
"Read_binary failed: Is a directory (os error 21)".to_string()
);
}

View File

@ -92,9 +92,10 @@ impl<'a> Extract<'a> {
}
}
}
let file_name = self.source.file_name().ok_or_else(|| {
crate::ErrorKind::Extract("Extractor source has no file-name".into())
})?;
let file_name = self
.source
.file_name()
.ok_or_else(|| crate::Error::Extract("Extractor source has no file-name".into()))?;
let mut out_path = into_dir.join(file_name);
out_path.set_extension("");
let mut out_file = fs::File::create(&out_path)?;
@ -148,9 +149,9 @@ impl<'a> Extract<'a> {
}
}
}
let file_name = file_to_extract.file_name().ok_or_else(|| {
crate::ErrorKind::Extract("Extractor source has no file-name".into())
})?;
let file_name = file_to_extract
.file_name()
.ok_or_else(|| crate::Error::Extract("Extractor source has no file-name".into()))?;
let out_path = into_dir.join(file_name);
let mut out_file = fs::File::create(&out_path)?;
io::copy(&mut reader, &mut out_file)?;
@ -162,7 +163,7 @@ impl<'a> Extract<'a> {
.filter_map(|e| e.ok())
.find(|e| e.path().ok().filter(|p| p == file_to_extract).is_some())
.ok_or_else(|| {
crate::ErrorKind::Extract(format!(
crate::Error::Extract(format!(
"Could not find the required path in the archive: {:?}",
file_to_extract
))

View File

@ -48,7 +48,7 @@ impl<'a> Move<'a> {
fs::rename(dest, temp)?;
if let Err(e) = fs::rename(self.source, dest) {
fs::rename(temp, dest)?;
return Err(crate::Error::from(e));
return Err(e.into());
}
} else {
fs::rename(self.source, dest)?;

View File

@ -1,11 +1,11 @@
use std::time::Duration;
use std::fs::File;
use std::collections::HashMap;
use attohttpc::{RequestBuilder, Method};
use attohttpc::{Method, RequestBuilder};
use http::header::HeaderName;
use serde_json::Value;
use serde::Deserialize;
use serde_repr::{Serialize_repr, Deserialize_repr};
use serde_json::Value;
use serde_repr::{Deserialize_repr, Serialize_repr};
use std::collections::HashMap;
use std::fs::File;
use std::time::Duration;
#[derive(Serialize_repr, Deserialize_repr, Clone, Debug)]
#[repr(u16)]
@ -19,7 +19,7 @@ pub enum BodyType {
/// - if the body is a byte array, send is as bytes (application/octet-stream)
/// - if the body is an object or array, send it as JSON (application/json with UTF-8 charset)
/// - if the body is a string, send it as text (text/plain with UTF-8 charset)
Auto
Auto,
}
#[derive(Serialize_repr, Deserialize_repr, Clone, Debug)]
@ -31,7 +31,7 @@ pub enum ResponseType {
/// Read the response as text
Text,
/// Read the response as binary
Binary
Binary,
}
#[derive(Deserialize)]
@ -81,7 +81,10 @@ pub fn make_request(options: HttpRequestOptions) -> crate::Result<String> {
if let Some(headers) = options.headers {
for (header, header_value) in headers.iter() {
builder = builder.header(HeaderName::from_bytes(header.as_bytes())?, format!("{}", header_value));
builder = builder.header(
HeaderName::from_bytes(header.as_bytes())?,
format!("{}", header_value),
);
}
}
@ -103,7 +106,9 @@ pub fn make_request(options: HttpRequestOptions) -> crate::Result<String> {
if let Some(allow_compression) = options.allow_compression {
builder = builder.allow_compression(allow_compression);
}
builder = builder.danger_accept_invalid_certs(true).danger_accept_invalid_hostnames(true);
builder = builder
.danger_accept_invalid_certs(true)
.danger_accept_invalid_hostnames(true);
let response = if let Some(body) = options.body {
match options.body_type.unwrap_or(BodyType::Auto) {
@ -112,9 +117,9 @@ pub fn make_request(options: HttpRequestOptions) -> crate::Result<String> {
if let Some(path) = body.as_str() {
builder.file(File::open(path)?).send()
} else {
return Err(crate::Error::from("Body must be the path to the file"));
return Err(crate::Error::Path("Body must be the path to the file".into()).into());
}
},
}
BodyType::Auto => {
if body.is_object() {
builder.json(&body)?.send()
@ -124,24 +129,26 @@ pub fn make_request(options: HttpRequestOptions) -> crate::Result<String> {
let u: Result<Vec<u8>, _> = serde_json::from_value(body.clone());
match u {
Ok(vec) => builder.bytes(&vec).send(),
Err(_) => builder.json(&body)?.send()
Err(_) => builder.json(&body)?.send(),
}
} else {
builder.send()
}
}
}
} else { builder.send() };
} else {
builder.send()
};
let response = response?;
if response.is_success() {
let response_data = match options.response_type.unwrap_or(ResponseType::Json) {
ResponseType::Json => response.json()?,
ResponseType::Text => response.text()?,
ResponseType::Binary => serde_json::to_string(&response.bytes()?)?
ResponseType::Binary => serde_json::to_string(&response.bytes()?)?,
};
Ok(response_data)
} else {
Err(crate::Error::from(response.status().as_str()))
Err(crate::Error::Network(response.status()).into())
}
}
}

View File

@ -4,46 +4,32 @@
)]
pub mod command;
pub mod dialog;
pub mod dir;
pub mod file;
pub mod rpc;
pub mod version;
pub mod tcp;
pub mod dialog;
pub mod path;
pub mod http;
pub mod path;
pub mod rpc;
pub mod tcp;
pub mod version;
pub use tauri_utils::*;
use error_chain::error_chain;
pub use anyhow::Result;
use thiserror::Error;
error_chain! {
foreign_links {
Io(::std::io::Error);
ZipError(::zip::result::ZipError);
SemVer(::semver::SemVerError);
Platform(::tauri_utils::Error);
Json(::serde_json::Error);
Http(::attohttpc::Error);
HttpMethod(::http::method::InvalidMethod);
HttpHeaderName(::http::header::InvalidHeaderName);
}
errors {
Extract(t: String) {
description("Extract Error")
display("Extract Error: '{}'", t)
}
Command(t: String) {
description("Command Execution Error")
display("Command Error: '{}'", t)
}
File(t: String) {
description("File function Error")
display("File Error: {}", t)
}
Path(t: String) {
description("Path function Error")
display("Path Error: {}", t)
}
}
#[derive(Error, Debug)]
pub enum Error {
#[error("Extract Error:{0}")]
Extract(String),
#[error("Command Error:{0}")]
Command(String),
#[error("File Error:{0}")]
File(String),
#[error("Path Error:{0}")]
Path(String),
#[error("Dialog Error:{0}")]
Dialog(String),
#[error("Network Error:{0}")]
Network(attohttpc::StatusCode),
}

View File

@ -1,5 +1,6 @@
use std::path::PathBuf;
use serde_repr::{Serialize_repr, Deserialize_repr};
use serde_repr::{Deserialize_repr, Serialize_repr};
#[derive(Serialize_repr, Deserialize_repr, Clone, Debug)]
#[repr(u16)]
@ -50,7 +51,7 @@ pub fn resolve_path(path: String, dir: Option<BaseDirectory>) -> crate::Result<S
base_dir_path_value.push(path);
Ok(base_dir_path_value.to_string_lossy().to_string())
} else {
Err(crate::Error::from(crate::ErrorKind::Path("unable to determine base dir path".to_string())))
Err(crate::Error::Path("unable to determine base dir path".to_string()).into())
}
} else {
Ok(path)
@ -144,20 +145,20 @@ pub fn resource_dir() -> Option<PathBuf> {
fn app_name() -> crate::Result<String> {
let exe = std::env::current_exe()?;
let app_name = exe
.file_name().expect("failed to get exe filename")
.file_name()
.expect("failed to get exe filename")
.to_string_lossy();
Ok(app_name.to_string())
}
pub fn app_dir() -> Option<PathBuf> {
dirs::config_dir()
.and_then(|mut dir| {
if let Ok(app_name) = app_name() {
dir.push(app_name);
Some(dir)
} else {
None
}
})
dirs::config_dir().and_then(|mut dir| {
if let Ok(app_name) = app_name() {
dir.push(app_name);
Some(dir)
} else {
None
}
})
}

View File

@ -8,7 +8,7 @@ pub fn compare(first: &str, second: &str) -> crate::Result<i32> {
match v1.cmp(&v2) {
Ordering::Greater => Ok(-1),
Ordering::Less => Ok(1),
Ordering::Equal => Ok(0)
Ordering::Equal => Ok(0),
}
}

View File

@ -16,6 +16,7 @@ serde_json = "1.0"
serde = "1.0"
zip = "0.5.3"
tempdir = "0.3"
error-chain = "0.12.1"
tauri-api = { version = "0.5", path = "../tauri-api" }
tauri-utils = { version = "0.5", path = "../tauri-utils" }
anyhow = "1.0.31"
thiserror = "1.0.19"

View File

@ -23,11 +23,7 @@ pub fn download<T: Write>(url: String, dest: T, _display_progress: bool) -> crat
let resp = get(url)?;
if !resp.status().is_success() {
bail!(
crate::ErrorKind::Download,
"Download request failed with status: {:?}",
resp.status()
)
return Err(crate::Error::Download(resp.status()).into());
}
let file = BufWriter::new(dest);

View File

@ -3,36 +3,17 @@ pub mod macros;
pub mod http;
pub mod updater;
use error_chain::error_chain;
pub use anyhow::Result;
use thiserror::Error;
error_chain! {
foreign_links{
Io(::std::io::Error);
Json(::serde_json::Error);
Zip(::zip::result::ZipError);
API(::tauri_api::Error);
HTTP(::attohttpc::Error);
}
errors{
Download(t: String) {
description("Download Error")
display("Download Error: '{}'", t)
}
Updater(t: String) {
description("Updater Error")
display("Updater Error: '{}'", t)
}
Release(t: String) {
description("Release Error")
display("Release Error: '{}'", t)
}
Network(t: String) {
description("Network Error")
display("Network Error: '{}'", t)
}
Config(t: String) {
description("Config Error")
display("Config Error: '{}'", t)
}
}
#[derive(Error, Debug)]
pub enum Error {
#[error("Download request failed with status:{0}")]
Download(attohttpc::StatusCode),
#[error("Failed to determine parent dir")]
Updater,
#[error("Network Error:{0}")]
Network(String),
#[error("Config Error:{0} required")]
Config(String),
}

View File

@ -1,22 +1,3 @@
macro_rules! format_err {
($e_type:expr, $literal:expr) => {
$e_type(format!($literal))
};
($e_type:expr, $literal:expr, $($arg:expr),*) => {
$e_type(format!($literal, $($arg),*))
};
}
/// Helper for formatting `errors::Error`s and returning early
macro_rules! bail {
($e_type:expr, $literal:expr) => {
return Err(format_err!($e_type, $literal).into())
};
($e_type:expr, $literal:expr, $($arg:expr),*) => {
return Err(format_err!($e_type, $literal, $($arg),*).into())
};
}
/// Helper to `print!` and immediately `flush` `stdout`
macro_rules! print_flush {
($literal:expr) => {

View File

@ -160,27 +160,27 @@ impl UpdateBuilder {
release: if let Some(ref release) = self.release {
release.to_owned()
} else {
bail!(crate::ErrorKind::Config, "`release` required")
return Err(crate::Error::Config("`release`".into()).into());
},
bin_name: if let Some(ref name) = self.bin_name {
name.to_owned()
} else {
bail!(crate::ErrorKind::Config, "`bin_name` required")
return Err(crate::Error::Config("`bin_name`".into()).into());
},
bin_install_path: if let Some(ref path) = self.bin_install_path {
path.to_owned()
} else {
bail!(crate::ErrorKind::Config, "`bin_install_path` required")
return Err(crate::Error::Config("`bin_install_path`".into()).into());
},
bin_path_in_archive: if let Some(ref path) = self.bin_path_in_archive {
path.to_owned()
} else {
bail!(crate::ErrorKind::Config, "`bin_path_in_archive` required")
return Err(crate::Error::Config("`bin_path_in_archive`".into()).into());
},
current_version: if let Some(ref ver) = self.current_version {
ver.to_owned()
} else {
bail!(crate::ErrorKind::Config, "`current_version` required")
return Err(crate::Error::Config("`current_version`".into()).into());
},
show_download_progress: self.show_download_progress,
show_output: self.show_output,
@ -236,7 +236,7 @@ impl Update {
let tmp_dir_parent = self
.bin_install_path
.parent()
.ok_or_else(|| crate::ErrorKind::Updater("Failed to determine parent dir".into()))?;
.ok_or_else(|| crate::Error::Updater)?;
let tmp_dir =
tempdir::TempDir::new_in(&tmp_dir_parent, &format!("{}_download", self.bin_name))?;
let tmp_archive_path = tmp_dir.path().join(&self.release.asset_name);

View File

@ -12,12 +12,14 @@ pub fn get_latest_release(repo_owner: &str, repo_name: &str) -> crate::Result<Re
);
let resp = http::get(api_url.clone())?;
if !resp.status().is_success() {
bail!(
crate::ErrorKind::Network,
"api request failed with status: {:?} - for: {:?}",
resp.status(),
api_url
)
return Err(
crate::Error::Network(format!(
"api request failed with status: {:?} - for: {:?}",
resp.status(),
api_url
))
.into(),
);
}
let json = resp.json::<serde_json::Value>()?;
Ok(Release::parse(&json)?)
@ -31,12 +33,14 @@ pub fn get_release_version(repo_owner: &str, repo_name: &str, ver: &str) -> crat
);
let resp = http::get(api_url.clone())?;
if !resp.status().is_success() {
bail!(
crate::ErrorKind::Network,
"api request failed with status: {:?} - for: {:?}",
resp.status(),
api_url
)
return Err(
crate::Error::Network(format!(
"api request failed with status: {:?} - for: {:?}",
resp.status(),
api_url
))
.into(),
);
}
let json = resp.json::<serde_json::Value>()?;
Ok(Release::parse(&json)?)

View File

@ -14,15 +14,12 @@ impl ReleaseAsset {
/// Errors:
/// * Missing required name & browser_download_url keys
fn from_asset(asset: &serde_json::Value) -> crate::Result<ReleaseAsset> {
let download_url = asset["browser_download_url"].as_str().ok_or_else(|| {
format_err!(
crate::ErrorKind::Network,
"Asset missing `browser_download_url`"
)
})?;
let download_url = asset["browser_download_url"]
.as_str()
.ok_or_else(|| crate::Error::Network("Asset missing `browser_download_url`".into()))?;
let name = asset["name"]
.as_str()
.ok_or_else(|| format_err!(crate::ErrorKind::Network, "Asset missing `name`"))?;
.ok_or_else(|| crate::Error::Network("Asset missing `name`".into()))?;
Ok(ReleaseAsset {
download_url: download_url.to_owned(),
name: name.to_owned(),
@ -42,15 +39,15 @@ impl Release {
pub fn parse(release: &serde_json::Value) -> crate::Result<Release> {
let tag = release["tag_name"]
.as_str()
.ok_or_else(|| format_err!(crate::ErrorKind::Network, "Release missing `tag_name`"))?;
.ok_or_else(|| crate::Error::Network("Release missing `tag_name`".into()))?;
let date_created = release["created_at"]
.as_str()
.ok_or_else(|| format_err!(crate::ErrorKind::Network, "Release missing `created_at`"))?;
.ok_or_else(|| crate::Error::Network("Release missing `created_at`".into()))?;
let name = release["name"].as_str().unwrap_or(tag);
let body = release["body"].as_str().unwrap_or("");
let assets = release["assets"]
.as_array()
.ok_or_else(|| format_err!(crate::ErrorKind::Network, "No assets found"))?;
.ok_or_else(|| crate::Error::Network("No assets found".into()))?;
let assets = assets
.iter()
.map(ReleaseAsset::from_asset)
@ -117,12 +114,12 @@ impl ReleaseListBuilder {
repo_owner: if let Some(ref owner) = self.repo_owner {
owner.to_owned()
} else {
bail!(crate::ErrorKind::Config, "`repo_owner` required")
return Err(crate::Error::Config("`repo_owner`".into()).into());
},
repo_name: if let Some(ref name) = self.repo_name {
name.to_owned()
} else {
bail!(crate::ErrorKind::Config, "`repo_name` required")
return Err(crate::Error::Config("`repo_name`".into()).into());
},
target: self.target.clone(),
})
@ -170,18 +167,19 @@ impl ReleaseList {
let (status, headers, reader) = attohttpc::get(url).send()?.split();
if !status.is_success() {
bail!(
crate::ErrorKind::Network,
"api request failed with status: {:?} - for: {:?}",
status,
url
)
return Err(
crate::Error::Network(format!(
"api request failed with status: {:?} - for: {:?}",
status, url
))
.into(),
);
}
let releases = reader.json::<serde_json::Value>()?;
let releases = releases
.as_array()
.ok_or_else(|| format_err!(crate::ErrorKind::Network, "No releases found"))?;
.ok_or_else(|| crate::Error::Network("No releases found".into()))?;
let mut releases = releases
.iter()
.map(Release::parse)

View File

@ -11,4 +11,5 @@ edition = "2018"
[dependencies]
sysinfo = "0.10"
error-chain = "0.12.1"
anyhow = "1.0.31"
thiserror = "1.0.19"

View File

@ -1,11 +1,23 @@
pub mod platform;
pub mod process;
use error_chain::error_chain;
pub use anyhow::Result;
use thiserror::Error;
error_chain! {
foreign_links {
Io(::std::io::Error);
}
errors {}
}
#[derive(Error, Debug)]
pub enum Error {
#[error("Unable to determine target-architecture")]
Architecture,
#[error("Unable to determine target-os")]
OS,
#[error("Unable to determine target-environment")]
Environment,
#[error("Unknown target_os")]
Unknown,
#[error("Could not get parent process")]
ParentProcess,
#[error("Could not get parent PID")]
ParentPID,
#[error("Could not get child process")]
ChildProcess,
}

View File

@ -1,5 +1,7 @@
use std::path::{PathBuf, MAIN_SEPARATOR};
use anyhow::Result;
/// Try to determine the current target triple.
///
/// Returns a target triple (e.g. `x86_64-unknown-linux-gnu` or `i686-pc-windows-msvc`) or an
@ -9,7 +11,7 @@ use std::path::{PathBuf, MAIN_SEPARATOR};
///
/// * Errors:
/// * Unexpected system config
pub fn target_triple() -> Result<String, crate::Error> {
pub fn target_triple() -> Result<String> {
let arch = if cfg!(target_arch = "x86") {
"i686"
} else if cfg!(target_arch = "x86_64") {
@ -17,9 +19,7 @@ pub fn target_triple() -> Result<String, crate::Error> {
} else if cfg!(target_arch = "arm") {
"armv7"
} else {
return Err(crate::Error::from(
"Unable to determine target-architecture",
));
return Err(crate::Error::Architecture.into());
};
let os = if cfg!(target_os = "linux") {
@ -31,7 +31,7 @@ pub fn target_triple() -> Result<String, crate::Error> {
} else if cfg!(target_os = "freebsd") {
"unknown-freebsd"
} else {
return Err(crate::Error::from("Unable to determine target-os"));
return Err(crate::Error::OS.into());
};
let os = if cfg!(target_os = "macos") || cfg!(target_os = "freebsd") {
@ -44,7 +44,7 @@ pub fn target_triple() -> Result<String, crate::Error> {
} else if cfg!(target_env = "msvc") {
"msvc"
} else {
return Err(crate::Error::from("Unable to determine target-environment"));
return Err(crate::Error::Environment.into());
};
format!("{}-{}", os, env)
@ -53,7 +53,7 @@ pub fn target_triple() -> Result<String, crate::Error> {
Ok(format!("{}-{}", arch, os))
}
pub fn resource_dir() -> crate::Result<PathBuf> {
pub fn resource_dir() -> Result<PathBuf> {
let exe = std::env::current_exe()?;
let exe_dir = exe.parent().expect("failed to get exe directory");
let app_name = exe
@ -81,6 +81,6 @@ pub fn resource_dir() -> crate::Result<PathBuf> {
} else if cfg!(target_os = "macos") {
Ok(exe_dir.join("../Resources"))
} else {
Err(crate::Error::from("Unknown target_os"))
Err(crate::Error::Unknown.into())
}
}

View File

@ -1,17 +1,19 @@
use crate::Error;
use sysinfo;
pub use sysinfo::{Process, ProcessExt, Signal, System, SystemExt};
pub fn get_parent_process(system: &mut sysinfo::System) -> crate::Result<&Process> {
pub fn get_parent_process(system: &mut sysinfo::System) -> Result<&Process, Error> {
let pid = sysinfo::get_current_pid().unwrap();
system.refresh_process(pid);
let current_process = system
.get_process(pid)
.ok_or("Could not get current process")?;
let parent_pid = current_process.parent().ok_or("Could not get parent PID")?;
.ok_or(Error::ParentProcess)?;
let parent_pid = current_process.parent().ok_or(Error::ParentPID)?;
let parent_process = system
.get_process(parent_pid)
.ok_or("Could not get parent process")?;
.ok_or(Error::ParentProcess)?;
println!("{}", pid);
Ok(parent_process)

View File

@ -22,7 +22,8 @@ lazy_static = "1.4.0"
tiny_http = { version = "0.7", optional = true }
threadpool = "1.8"
uuid = { version = "0.8.1", features = ["v4"] }
error-chain = "0.12.2"
anyhow = "1.0.31"
thiserror = "1.0.19"
tauri-api = { version = "0.5", path = "../tauri-api" }

View File

@ -12,7 +12,7 @@ use web_view::WebView;
pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> crate::Result<()> {
use cmd::Cmd::*;
match serde_json::from_str(arg) {
Err(e) => Err(crate::Error::from(e.to_string())),
Err(e) => Err(e.into()),
Ok(command) => {
match command {
Init {} => {
@ -297,7 +297,7 @@ fn load_asset<T: 'static>(
));
}
None => {
return Err(format!("Asset '{}' not found", asset).into());
return Err(anyhow::anyhow!("Asset '{}' not found", asset));
}
}
} else {
@ -330,7 +330,7 @@ fn load_asset<T: 'static>(
_webview.eval(asset_str)
}
})
.map_err(|err| crate::ErrorKind::Promise(format!(r#""{}""#, err)).into())
.map_err(|err| err.into())
.map(|_| r#""Asset loaded successfully""#.to_string())
}
},

View File

@ -26,9 +26,7 @@ pub fn open<T: 'static>(
} else {
select(options.filter, options.default_path)
};
response
.map(map_response)
.map_err(|e| crate::ErrorKind::Dialog(e.to_string()).into())
response.map(map_response).map_err(|e| e.into())
},
callback,
error,
@ -46,7 +44,7 @@ pub fn save<T: 'static>(
move || {
save_file(options.filter, options.default_path)
.map(map_response)
.map_err(|e| crate::ErrorKind::Dialog(e.to_string()).into())
.map_err(|e| e.into())
},
callback,
error,

View File

@ -27,11 +27,11 @@ pub fn read_dir<T: 'static>(
};
if recursive {
dir::walk_dir(resolve_path(path, dir)?)
.map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
.map_err(|e| e.into())
.and_then(|f| serde_json::to_string(&f).map_err(|err| err.into()))
} else {
dir::list_dir_contents(resolve_path(path, dir)?)
.map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
.map_err(|e| e.into())
.and_then(|f| serde_json::to_string(&f).map_err(|err| err.into()))
}
},
@ -59,7 +59,7 @@ pub fn copy_file<T: 'static>(
None => (source, destination),
};
fs::copy(src, dest)
.map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
.map_err(|e| e.into())
.map(|_| "".to_string())
},
callback,
@ -89,9 +89,7 @@ pub fn create_dir<T: 'static>(
fs::create_dir(resolved_path)
};
response
.map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
.map(|_| "".to_string())
response.map_err(|e| e.into()).map(|_| "".to_string())
},
callback,
error,
@ -120,9 +118,7 @@ pub fn remove_dir<T: 'static>(
fs::remove_dir(resolved_path)
};
response
.map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
.map(|_| "".to_string())
response.map_err(|e| e.into()).map(|_| "".to_string())
},
callback,
error,
@ -141,7 +137,7 @@ pub fn remove_file<T: 'static>(
move || {
let resolved_path = resolve_path(path, options.and_then(|o| o.dir))?;
fs::remove_file(resolved_path)
.map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
.map_err(|e| e.into())
.map(|_| "".to_string())
},
callback,
@ -168,7 +164,7 @@ pub fn rename_file<T: 'static>(
None => (old_path, new_path),
};
fs::rename(old, new)
.map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
.map_err(|e| e.into())
.map(|_| "".to_string())
},
callback,
@ -188,7 +184,7 @@ pub fn write_file<T: 'static>(
webview,
move || {
File::create(resolve_path(file, options.and_then(|o| o.dir))?)
.map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
.map_err(|e| e.into())
.and_then(|mut f| {
f.write_all(contents.as_bytes())
.map_err(|err| err.into())
@ -211,7 +207,7 @@ pub fn read_text_file<T: 'static>(
webview,
move || {
file::read_string(resolve_path(path, options.and_then(|o| o.dir))?)
.map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
.map_err(|e| e.into())
.and_then(|f| serde_json::to_string(&f).map_err(|err| err.into()))
},
callback,
@ -230,7 +226,7 @@ pub fn read_binary_file<T: 'static>(
webview,
move || {
file::read_binary(resolve_path(path, options.and_then(|o| o.dir))?)
.map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
.map_err(|e| e.into())
.and_then(|f| serde_json::to_string(&f).map_err(|err| err.into()))
},
callback,

View File

@ -12,14 +12,12 @@ pub fn make_request<T: 'static>(
webview,
move || {
let response_type = options.response_type.clone();
request(options)
.map_err(|e| crate::ErrorKind::Http(e.to_string()).into())
.map(|response| {
match response_type.unwrap_or(ResponseType::Json) {
ResponseType::Text => format!(r#""{}""#, response),
_ => response
}
})
request(options).map_err(|e| e.into()).map(|response| {
match response_type.unwrap_or(ResponseType::Json) {
ResponseType::Text => format!(r#""{}""#, response),
_ => response,
}
})
},
callback,
error,

View File

@ -17,7 +17,7 @@ mod salt;
use std::process::Stdio;
use error_chain::error_chain;
pub use anyhow::Result;
use threadpool::ThreadPool;
pub use web_view::Handle;
@ -26,37 +26,6 @@ use web_view::WebView;
pub use app::*;
pub use tauri_api as api;
error_chain! {
foreign_links{
Api(::tauri_api::Error);
Json(::serde_json::Error);
Webview(::web_view::Error);
Io(::std::io::Error);
}
errors{
Promise(t: String) {
description("Promise Error")
display("Promise Error: '{}'", t)
}
Command(t: String) {
description("Command Error")
display("Command Error: '{}'", t)
}
Dialog(t: String) {
description("Dialog Error")
display("Dialog Error: '{}'", t)
}
FileSystem(t: String) {
description("FileSystem Error")
display("FileSystem Error: '{}'", t)
}
Http(t: String) {
description("Http Error")
display("Http Error: '{}'", t)
}
}
}
thread_local!(static POOL: ThreadPool = ThreadPool::new(4));
pub fn spawn<F: FnOnce() -> () + Send + 'static>(task: F) {
@ -110,7 +79,7 @@ pub fn call<T: 'static>(
webview,
|| {
api::command::get_output(command, args, Stdio::piped())
.map_err(|err| crate::ErrorKind::Promise(err.to_string()).into())
.map_err(|err| err)
.map(|output| format!(r#""{}""#, output))
},
callback,