Skip to content

Commit

Permalink
Adds error handling routines and messages (#47)
Browse files Browse the repository at this point in the history
* Adds error handling routines and messages
* Error messages for review
  • Loading branch information
colincasey authored Oct 9, 2024
1 parent 2534391 commit 28498e8
Show file tree
Hide file tree
Showing 13 changed files with 2,994 additions and 340 deletions.
44 changes: 44 additions & 0 deletions Cargo.lock

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

7 changes: 5 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@ anyhow = "1"
apt-parser = "1"
ar = "0.9"
async-compression = { version = "0.4", default-features = false, features = ["tokio", "gzip", "zstd", "xz"] }
bon = "2"
bullet_stream = "0.2"
debversion = "0.4"
futures = { version = "0.3", default-features = false, features = ["io-compat"] }
indexmap = "2"
libcnb = { version = "=0.23.0", features = ["trace"] }
indoc = "2"
rayon = "1"
reqwest = { version = "0.12", default-features = false, features = ["stream", "rustls-tls"] }
reqwest-middleware = "0.3"
Expand All @@ -29,10 +32,10 @@ toml_edit = "0.22"
walkdir = "2"

[dev-dependencies]
bon = "2"
tempfile = "3"
libcnb-test = "=0.23.0"
regex = "1"
strip-ansi-escapes = "0.2"
tempfile = "3"

[lints.rust]
unreachable_pub = "warn"
Expand Down
68 changes: 48 additions & 20 deletions src/config/buildpack_config.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,44 @@
use indexmap::IndexSet;
use std::fs;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use std::str::FromStr;

use indexmap::IndexSet;
use toml_edit::{DocumentMut, TableLike};

use crate::config::ConfigError::{InvalidToml, ParseRequestedPackage, WrongConfigType};
use crate::config::{ParseRequestedPackageError, RequestedPackage};
use crate::debian::ParsePackageNameError;
use crate::{BuildpackResult, DebianPackagesBuildpackError};

#[derive(Debug, Default, Eq, PartialEq)]
pub(crate) struct BuildpackConfig {
pub(crate) install: IndexSet<RequestedPackage>,
}

impl BuildpackConfig {
pub(crate) fn exists(config_file: impl AsRef<Path>) -> BuildpackResult<bool> {
Ok(config_file
.as_ref()
.try_exists()
.map_err(|e| ConfigError::CheckExists(config_file.as_ref().to_path_buf(), e))?)
}
}

impl TryFrom<PathBuf> for BuildpackConfig {
type Error = ConfigError;

fn try_from(value: PathBuf) -> Result<Self, Self::Error> {
fs::read_to_string(value)
.map_err(ConfigError::ReadConfig)
.and_then(|contents| BuildpackConfig::from_str(&contents))
fs::read_to_string(&value)
.map_err(|e| ConfigError::ReadConfig(value.clone(), e))
.and_then(|contents| {
BuildpackConfig::from_str(&contents).map_err(|e| ConfigError::ParseConfig(value, e))
})
}
}

impl FromStr for BuildpackConfig {
type Err = ConfigError;
type Err = ParseConfigError;

fn from_str(contents: &str) -> Result<Self, Self::Err> {
let doc = DocumentMut::from_str(contents).map_err(InvalidToml)?;
let doc = DocumentMut::from_str(contents).map_err(Self::Err::InvalidToml)?;

// the root config is the table named `[com.heroku.buildpacks.debian-packages]` in project.toml
let root_config_item = doc
Expand All @@ -44,22 +54,23 @@ impl FromStr for BuildpackConfig {
None => Ok(BuildpackConfig::default()),
Some(item) => item
.as_table_like()
.ok_or(WrongConfigType)
.ok_or(Self::Err::WrongConfigType)
.map(BuildpackConfig::try_from)?,
}
}
}

impl TryFrom<&dyn TableLike> for BuildpackConfig {
type Error = ConfigError;
type Error = ParseConfigError;

fn try_from(config_item: &dyn TableLike) -> Result<Self, Self::Error> {
let mut install = IndexSet::new();

if let Some(install_values) = config_item.get("install").and_then(|item| item.as_array()) {
for install_value in install_values {
install.insert(
RequestedPackage::try_from(install_value).map_err(ParseRequestedPackage)?,
RequestedPackage::try_from(install_value)
.map_err(Self::Error::ParseRequestedPackage)?,
);
}
}
Expand All @@ -69,20 +80,37 @@ impl TryFrom<&dyn TableLike> for BuildpackConfig {
}

#[derive(Debug)]
#[allow(dead_code)]
pub(crate) enum ConfigError {
ReadConfig(std::io::Error),
CheckExists(PathBuf, std::io::Error),
ReadConfig(PathBuf, std::io::Error),
ParseConfig(PathBuf, ParseConfigError),
}

#[derive(Debug)]
pub(crate) enum ParseConfigError {
InvalidToml(toml_edit::TomlError),
PackageNameError(ParsePackageNameError),
WrongConfigType,
ParseRequestedPackage(ParseRequestedPackageError),
}

impl From<ConfigError> for DebianPackagesBuildpackError {
fn from(value: ConfigError) -> Self {
DebianPackagesBuildpackError::Config(value)
}
}

impl From<ConfigError> for libcnb::Error<DebianPackagesBuildpackError> {
fn from(value: ConfigError) -> Self {
Self::BuildpackError(value.into())
}
}

#[cfg(test)]
mod test {
use super::*;
use crate::debian::PackageName;

use super::*;

#[test]
fn test_deserialize() {
let toml = r#"
Expand Down Expand Up @@ -157,7 +185,7 @@ install = [
"#
.trim();
match BuildpackConfig::from_str(toml).unwrap_err() {
ParseRequestedPackage(_) => {}
ParseConfigError::ParseRequestedPackage(_) => {}
e => panic!("Not the expected error - {e:?}"),
}
}
Expand All @@ -175,7 +203,7 @@ install = [
"#
.trim();
match BuildpackConfig::from_str(toml).unwrap_err() {
ParseRequestedPackage(_) => {}
ParseConfigError::ParseRequestedPackage(_) => {}
e => panic!("Not the expected error - {e:?}"),
}
}
Expand All @@ -192,7 +220,7 @@ debian-packages = ["wrong"]
"#
.trim();
match BuildpackConfig::from_str(toml).unwrap_err() {
WrongConfigType => {}
ParseConfigError::WrongConfigType => {}
e => panic!("Not the expected error - {e:?}"),
}
}
Expand All @@ -204,7 +232,7 @@ debian-packages = ["wrong"]
"
.trim();
match BuildpackConfig::from_str(toml).unwrap_err() {
InvalidToml(_) => {}
ParseConfigError::InvalidToml(_) => {}
e => panic!("Not the expected error - {e:?}"),
}
}
Expand Down
15 changes: 9 additions & 6 deletions src/config/requested_package.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use crate::config::ParseRequestedPackageError::{InvalidPackageName, UnexpectedTomlValue};
use crate::debian::{PackageName, ParsePackageNameError};
use std::str::FromStr;

use toml_edit::{Formatted, InlineTable, Value};

use crate::debian::{PackageName, ParsePackageNameError};

#[derive(Debug, Eq, PartialEq, Hash)]
pub(crate) struct RequestedPackage {
pub(crate) name: PackageName,
Expand All @@ -14,7 +15,8 @@ impl FromStr for RequestedPackage {

fn from_str(package_name: &str) -> Result<Self, Self::Err> {
Ok(RequestedPackage {
name: PackageName::from_str(package_name).map_err(InvalidPackageName)?,
name: PackageName::from_str(package_name)
.map_err(ParseRequestedPackageError::InvalidPackageName)?,
skip_dependencies: false,
})
}
Expand All @@ -27,7 +29,9 @@ impl TryFrom<&Value> for RequestedPackage {
match value {
Value::String(formatted_string) => RequestedPackage::try_from(formatted_string),
Value::InlineTable(inline_table) => RequestedPackage::try_from(inline_table),
_ => Err(UnexpectedTomlValue(value.clone())),
_ => Err(ParseRequestedPackageError::UnexpectedTomlValue(
value.clone(),
)),
}
}
}
Expand All @@ -51,7 +55,7 @@ impl TryFrom<&InlineTable> for RequestedPackage {
.and_then(Value::as_str)
.unwrap_or_default(),
)
.map_err(InvalidPackageName)?,
.map_err(ParseRequestedPackageError::InvalidPackageName)?,

skip_dependencies: table
.get("skip_dependencies")
Expand All @@ -62,7 +66,6 @@ impl TryFrom<&InlineTable> for RequestedPackage {
}

#[derive(Debug)]
#[allow(dead_code)]
pub(crate) enum ParseRequestedPackageError {
InvalidPackageName(ParsePackageNameError),
UnexpectedTomlValue(Value),
Expand Down
Loading

0 comments on commit 28498e8

Please sign in to comment.