Skip to content

Commit

Permalink
feat: use custom error types in internal and external crates
Browse files Browse the repository at this point in the history
  • Loading branch information
ereslibre committed Jul 20, 2023
1 parent f4e13a4 commit 2a40dec
Show file tree
Hide file tree
Showing 34 changed files with 486 additions and 124 deletions.
7 changes: 0 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ path = "src/main.rs"

# Main binary (wws CLI dependencies)
[dependencies]
anyhow = { workspace = true }
actix-web = { workspace = true }
anyhow = "1.0.66"
env_logger = "0.10.0"
clap = { version = "4.0.10", features = ["derive"] }
prettytable-rs = "0.10.0"
Expand Down Expand Up @@ -73,7 +73,6 @@ exclude = [

[workspace.dependencies]
actix-web = "4"
anyhow = "1.0.66"
lazy_static = "1.4.0"
reqwest = "0.11"
serde = { version = "1.0", features = ["derive"] }
Expand Down
1 change: 0 additions & 1 deletion crates/config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ license = { workspace = true }
repository = { workspace = true }

[dependencies]
anyhow = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
toml = { workspace = true }
Expand Down
39 changes: 39 additions & 0 deletions crates/config/src/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2023 VMware, Inc.
// SPDX-License-Identifier: Apache-2.0

pub type Result<T> = std::result::Result<T, ConfigError>;

#[derive(Debug)]
pub enum ConfigError {
CouldNotLoadConfig(std::io::Error),
CouldNotParseConfig(toml::de::Error),
CouldNotSaveConfig,
}

impl std::fmt::Display for ConfigError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::CouldNotLoadConfig(err) => write!(f, "Could not load configuration: {}", err),
Self::CouldNotParseConfig(err) => write!(f, "Could not parse configuration: {}", err),
Self::CouldNotSaveConfig => write!(f, "Could not save configuration"),
}
}
}

impl From<std::io::Error> for ConfigError {
fn from(error: std::io::Error) -> Self {
ConfigError::CouldNotLoadConfig(error)
}
}

impl From<toml::de::Error> for ConfigError {
fn from(error: toml::de::Error) -> ConfigError {
ConfigError::CouldNotParseConfig(error)
}
}

impl From<toml::ser::Error> for ConfigError {
fn from(_: toml::ser::Error) -> ConfigError {
ConfigError::CouldNotSaveConfig
}
}
16 changes: 8 additions & 8 deletions crates/config/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// Copyright 2022 VMware, Inc.
// SPDX-License-Identifier: Apache-2.0

use anyhow::{anyhow, Result};
pub mod errors;
pub use errors::Result;

use serde::{Deserialize, Serialize};
use std::{
fs,
Expand Down Expand Up @@ -42,9 +44,7 @@ impl Config {
let config_path = Self::config_path(project_root);

if config_path.exists() {
toml::from_str(&fs::read_to_string(config_path)?).map_err(|_| {
anyhow!("Error opening the .wws.toml file. The file format is not correct")
})
Ok(toml::from_str(&fs::read_to_string(config_path)?)?)
} else {
Ok(Self::default())
}
Expand Down Expand Up @@ -111,10 +111,10 @@ impl Config {
/// Write the current configuration into the `.wws.toml` file. It will
/// store it in the project root folder
pub fn save(&self, project_root: &Path) -> Result<()> {
let contents = toml::to_string_pretty(self)?;

fs::write(Self::config_path(project_root), contents)
.map_err(|_| anyhow!("Error saving the .wws.toml file"))
Ok(fs::write(
Self::config_path(project_root),
toml::to_string_pretty(self)?,
)?)
}

/// Retrieve the configuration path from the project root
Expand Down
1 change: 0 additions & 1 deletion crates/data-kv/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,5 @@ license = { workspace = true }
repository = { workspace = true }

[dependencies]
anyhow = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
1 change: 0 additions & 1 deletion crates/project/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ license = { workspace = true }
repository = { workspace = true }

[dependencies]
anyhow = { workspace = true }
reqwest = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
Expand Down
65 changes: 65 additions & 0 deletions crates/project/src/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright 2023 VMware, Inc.
// SPDX-License-Identifier: Apache-2.0

use wws_store::errors::StoreError;

pub type Result<T> = std::result::Result<T, FetchError>;

#[derive(Debug)]
pub enum FetchError {
DefaultBranchMissing,
GitError(git2::Error),
HttpError(reqwest::Error),
InvalidURL,
InvalidReusedRepository,
InvalidRepository,
InvalidChecksum,
MissingPathInFilesystem,
StoreError(StoreError),
}

impl std::fmt::Display for FetchError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::DefaultBranchMissing => write!(f, "Couldn't find the default main branch. Please, set the Git branch you want to use"),
Self::GitError(err) => write!(f, "Git error: {}", err),
Self::HttpError(err) => write!(f, "HTTP error: {}", err),
Self::InvalidURL => write!(f, "Invalid URL"),
Self::InvalidReusedRepository => write!(f, "Invalid local copy of repository"),
Self::InvalidRepository => write!(f, "Invalid repository"),
Self::InvalidChecksum => write!(f, "Invalid checksum"),
Self::MissingPathInFilesystem => write!(f, "Missing path in filesystem"),
Self::StoreError(err) => write!(f, "Store error: {}", err),
}
}
}

impl From<git2::Error> for FetchError {
fn from(error: git2::Error) -> Self {
FetchError::GitError(error)
}
}

impl From<url::ParseError> for FetchError {
fn from(_error: url::ParseError) -> Self {
FetchError::InvalidURL
}
}

impl From<reqwest::Error> for FetchError {
fn from(error: reqwest::Error) -> Self {
FetchError::HttpError(error)
}
}

impl From<StoreError> for FetchError {
fn from(error: StoreError) -> Self {
FetchError::StoreError(error)
}
}

impl From<std::string::FromUtf8Error> for FetchError {
fn from(_error: std::string::FromUtf8Error) -> Self {
FetchError::InvalidRepository
}
}
2 changes: 1 addition & 1 deletion crates/project/src/fetch.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Copyright 2022 VMware, Inc.
// SPDX-License-Identifier: Apache-2.0

use crate::errors::Result;
use crate::metadata::Checksum;
use anyhow::Result;
use reqwest::header::USER_AGENT;

/// The current wws version
Expand Down
11 changes: 6 additions & 5 deletions crates/project/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
// Copyright 2022-2023 VMware, Inc.
// SPDX-License-Identifier: Apache-2.0

pub mod errors;
mod fetch;
pub mod metadata;
pub mod options;
pub mod types;

use anyhow::{bail, Result};
use errors::Result;
use fetch::fetch_and_validate;
use metadata::{RemoteFile, Runtime};
use options::Options;
Expand Down Expand Up @@ -68,7 +69,7 @@ pub fn identify_type(location: &Path) -> Result<ProjectType> {
if path.exists() {
Ok(ProjectType::Local)
} else {
bail!("The given path does not exist in the local filesystem.")
Err(errors::FetchError::MissingPathInFilesystem)
}
}
}
Expand Down Expand Up @@ -138,19 +139,19 @@ pub fn check_runtime(project_root: &Path, repository: &str, runtime: &Runtime) -
/// and delete the folder.
pub fn uninstall_runtime(project_root: &Path, repository: &str, metadata: &Runtime) -> Result<()> {
// Delete the current folder
Store::new(
Ok(Store::new(
project_root,
&["runtimes", repository, &metadata.name, &metadata.version],
)
.delete_root_folder()
.delete_root_folder()?)
}

/// Downloads a remote file and saves into the given store. This
/// method also validates the file against the checksum provided
/// in the metadata.
async fn download_file(file: &RemoteFile, store: &Store) -> Result<()> {
let contents = fetch_and_validate(&file.url, &file.checksum).await?;
store.write(&[&file.filename], &contents)
Ok(store.write(&[&file.filename], &contents)?)
}

#[cfg(test)]
Expand Down
11 changes: 4 additions & 7 deletions crates/project/src/metadata.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Copyright 2022 VMware, Inc.
// SPDX-License-Identifier: Apache-2.0

use crate::errors::{self, Result};
use crate::fetch::fetch;
use anyhow::{anyhow, Result};
use serde::{Deserialize, Serialize};
use sha256::digest as sha256_digest;
use std::collections::HashMap;
Expand Down Expand Up @@ -61,15 +61,12 @@ impl Repository {
}

impl FromStr for Repository {
type Err = anyhow::Error;
type Err = errors::FetchError;

/// Reads and parses the metadata from a slice of bytes. It will return
/// a result as the deserialization may fail.
fn from_str(data: &str) -> Result<Self> {
toml::from_str::<Repository>(data).map_err(|err| {
println!("Err: {err}");
anyhow!("wws could not deserialize the repository metadata")
})
toml::from_str::<Repository>(data).map_err(|_| errors::FetchError::InvalidRepository)
}
}

Expand Down Expand Up @@ -169,7 +166,7 @@ impl Checksum {
pub fn validate(&self, bytes: &[u8]) -> Result<()> {
match self {
Checksum::Sha256 { value } if value == &sha256_digest(bytes) => Ok(()),
_ => Err(anyhow!("The checksums don't match")),
_ => Err(errors::FetchError::InvalidChecksum),
}
}
}
Expand Down
12 changes: 5 additions & 7 deletions crates/project/src/types/git.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Copyright 2023 VMware, Inc.
// SPDX-License-Identifier: Apache-2.0

use crate::errors::{self, Result};
use crate::options::{GitReference, Options};
use anyhow::{anyhow, bail, Result};
use git2::{build::CheckoutBuilder, FetchOptions, Oid, Repository};
use sha256::digest as sha256_digest;
use std::{
Expand All @@ -18,19 +18,17 @@ static DEFAULT_REMOTE: &str = "origin";
pub fn prepare_git_project(location: &Path, options: Options) -> Result<PathBuf> {
let project_url = location
.to_str()
.ok_or(anyhow!("The project URL cannot be retrieved"))?;
.ok_or(errors::FetchError::InvalidRepository)?;
let (folder, git_ref) = parse_options(options);
// By default, we use temporary dirs
let mut dir = temp_dir().join(sha256_digest(project_url));

let repo = if dir.exists() {
// Reuse the same repository.
Repository::open(&dir)
.map_err(|e| anyhow!("There was an error opening the repository: {e}"))?
Repository::open(&dir).map_err(|_| errors::FetchError::InvalidReusedRepository)?
} else {
// clone it
Repository::clone(project_url, &dir)
.map_err(|e| anyhow!("There was an error cloning the repository: {e}"))?
Repository::clone(project_url, &dir).map_err(|_| errors::FetchError::InvalidRepository)?
};

if let Some(git_ref) = git_ref.as_ref() {
Expand Down Expand Up @@ -106,7 +104,7 @@ fn detect_main_branch(repo: &Repository) -> Result<&str> {
} else if repo.find_branch("master", git2::BranchType::Local).is_ok() {
Ok("master")
} else {
bail!("Couldn't find the default main branch. Please, set the Git branch you want to use.")
Err(errors::FetchError::DefaultBranchMissing)
}
}

Expand Down
1 change: 0 additions & 1 deletion crates/runtimes/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ license = { workspace = true }
repository = { workspace = true }

[dependencies]
anyhow = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
wasmtime-wasi = { workspace = true }
Expand Down
Loading

0 comments on commit 2a40dec

Please sign in to comment.