Skip to content

Commit

Permalink
Better error handling (#40)
Browse files Browse the repository at this point in the history
  • Loading branch information
oltrep authored Jan 27, 2022
1 parent 9e2384d commit c0eece4
Show file tree
Hide file tree
Showing 17 changed files with 777 additions and 432 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Unreleased Changes

- Improve error handling to reduces crashes and add more useful error messages ([#40](https://github.com/Roblox/foreman/pull/40))
- Add environment variable to override Foreman home directory ([#39](https://github.com/Roblox/foreman/pull/39))
- Support tools hosted on GitLab ([#31](https://github.com/Roblox/foreman/pull/31))
- Updated config format to support both GitHub and GitLab tools
Expand Down
13 changes: 9 additions & 4 deletions src/aliaser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,17 @@ use std::{
path::Path,
};

use crate::fs;
use crate::{
error::{ForemanError, ForemanResult},
fs,
};

pub fn add_self_alias(name: &str, bin_path: &Path) {
let foreman_path = env::current_exe().unwrap();
pub fn add_self_alias(name: &str, bin_path: &Path) -> ForemanResult<()> {
let foreman_path = env::current_exe().map_err(|err| {
ForemanError::io_error_with_context(err, "unable to obtain foreman executable location")
})?;
let mut alias_path = bin_path.to_owned();
alias_path.push(format!("{}{}", name, EXE_SUFFIX));

fs::copy(foreman_path, alias_path).unwrap();
fs::copy(foreman_path, alias_path).map(|_| ())
}
77 changes: 34 additions & 43 deletions src/auth_store.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use std::{io, path::Path};
use std::path::Path;

use serde::{Deserialize, Serialize};
use toml_edit::{value, Document};
use toml_edit::{value, Document, TomlError};

use crate::fs;
use crate::{
error::{ForemanError, ForemanResult},
fs,
};

pub static DEFAULT_AUTH_CONFIG: &str = include_str!("../resources/default-auth.toml");

Expand All @@ -15,59 +18,47 @@ pub struct AuthStore {
}

impl AuthStore {
pub fn load(path: &Path) -> io::Result<Self> {
log::debug!("Loading auth store...");
pub fn load(path: &Path) -> ForemanResult<Self> {
if let Some(contents) = fs::try_read(path)? {
log::debug!("Loading auth store");
let store: AuthStore = toml::from_slice(&contents)
.map_err(|error| ForemanError::auth_parsing(path, error.to_string()))?;

match fs::read(path) {
Ok(contents) => {
let store: AuthStore = toml::from_slice(&contents).unwrap();

let mut found_credentials = false;
if store.github.is_some() {
log::debug!("Found GitHub credentials");
found_credentials = true;
}
if store.gitlab.is_some() {
log::debug!("Found GitLab credentials");
found_credentials = true;
}
if !found_credentials {
log::debug!("Found no credentials");
}

Ok(store)
let mut found_credentials = false;
if store.github.is_some() {
log::debug!("Found GitHub credentials");
found_credentials = true;
}
if store.gitlab.is_some() {
log::debug!("Found GitLab credentials");
found_credentials = true;
}
Err(err) => {
if err.kind() == io::ErrorKind::NotFound {
Ok(AuthStore::default())
} else {
Err(err)
}
if !found_credentials {
log::debug!("Found no credentials");
}

Ok(store)
} else {
log::debug!("Auth store not found");
Ok(AuthStore::default())
}
}

pub fn set_github_token(auth_file: &Path, token: &str) -> io::Result<()> {
pub fn set_github_token(auth_file: &Path, token: &str) -> ForemanResult<()> {
Self::set_token(auth_file, "github", token)
}

pub fn set_gitlab_token(auth_file: &Path, token: &str) -> io::Result<()> {
pub fn set_gitlab_token(auth_file: &Path, token: &str) -> ForemanResult<()> {
Self::set_token(auth_file, "gitlab", token)
}

fn set_token(auth_file: &Path, key: &str, token: &str) -> io::Result<()> {
let contents = match fs::read_to_string(auth_file) {
Ok(contents) => contents,
Err(err) => {
if err.kind() == io::ErrorKind::NotFound {
DEFAULT_AUTH_CONFIG.to_owned()
} else {
return Err(err);
}
}
};
fn set_token(auth_file: &Path, key: &str, token: &str) -> ForemanResult<()> {
let contents =
fs::try_read_to_string(auth_file)?.unwrap_or_else(|| DEFAULT_AUTH_CONFIG.to_owned());

let mut store: Document = contents.parse().unwrap();
let mut store: Document = contents
.parse()
.map_err(|err: TomlError| ForemanError::auth_parsing(auth_file, err.to_string()))?;
store[key] = value(token);

let serialized = store.to_string();
Expand Down
61 changes: 28 additions & 33 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use std::{collections::HashMap, env, fmt, io};
use std::{collections::HashMap, env, fmt};

use semver::VersionReq;
use serde::{Deserialize, Serialize};

use crate::{ci_string::CiString, fs, paths::ForemanPaths, tool_provider::Provider};
use crate::{
ci_string::CiString, error::ForemanError, fs, paths::ForemanPaths, tool_provider::Provider,
};

#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ToolSpec {
Github {
Expand Down Expand Up @@ -83,29 +85,28 @@ impl ConfigFile {
}
}

pub fn aggregate(paths: &ForemanPaths) -> io::Result<ConfigFile> {
pub fn aggregate(paths: &ForemanPaths) -> Result<ConfigFile, ForemanError> {
let mut config = ConfigFile::new();

let base_dir = env::current_dir()?;
let base_dir = env::current_dir().map_err(|err| {
ForemanError::io_error_with_context(
err,
"unable to obtain the current working directory",
)
})?;
let mut current_dir = base_dir.as_path();

loop {
let config_path = current_dir.join("foreman.toml");

match fs::read(&config_path) {
Ok(contents) => {
let config_source = toml::from_slice(&contents).unwrap();
log::debug!(
"aggregating content from config file at {}",
config_path.display()
);
config.fill_from(config_source);
}
Err(err) => {
if err.kind() != io::ErrorKind::NotFound {
return Err(err);
}
}
if let Some(contents) = fs::try_read(&config_path)? {
let config_source = toml::from_slice(&contents)
.map_err(|err| ForemanError::config_parsing(&config_path, err.to_string()))?;
log::debug!(
"aggregating content from config file at {}",
config_path.display()
);
config.fill_from(config_source);
}

if let Some(parent) = current_dir.parent() {
Expand All @@ -116,20 +117,14 @@ impl ConfigFile {
}

let home_config_path = paths.user_config();
match fs::read(&home_config_path) {
Ok(contents) => {
let config_source = toml::from_slice(&contents).unwrap();
log::debug!(
"aggregating content from config file at {}",
home_config_path.display()
);
config.fill_from(config_source);
}
Err(err) => {
if err.kind() != io::ErrorKind::NotFound {
return Err(err);
}
}
if let Some(contents) = fs::try_read(&home_config_path)? {
let config_source = toml::from_slice(&contents)
.map_err(|err| ForemanError::config_parsing(&home_config_path, err.to_string()))?;
log::debug!(
"aggregating content from config file at {}",
home_config_path.display()
);
config.fill_from(config_source);
}

Ok(config)
Expand Down
Loading

0 comments on commit c0eece4

Please sign in to comment.