extern crate strict_yaml_rust;
use crate::brew::action::BrewAction;
#[cfg(target_os = "macos")]
use crate::brew::action::MacAppStoreItem;
use dotfiles_core::action::ActionParser;
use dotfiles_core::action::SKIP_IN_CI_SETTING;
use dotfiles_core::directive::DirectiveData;
use dotfiles_core::error::add_directive_error_prefix;
use dotfiles_core::error::DotfilesError;
#[cfg(target_os = "macos")]
use dotfiles_core::error::ErrorType;
use dotfiles_core::settings::initialize_settings_object;
use dotfiles_core::settings::Setting;
use dotfiles_core::settings::Settings;
use dotfiles_core::yaml_util::*;
use dotfiles_core_macros::Directive;
use std::marker::PhantomData;
use std::path::Path;
use strict_yaml_rust::StrictYaml;
pub const DIRECTIVE_NAME: &str = "brew";
pub const FORCE_CASKS_SETTING: &str = "force_casks";
pub const ADOPT_CASKS_SETTING: &str = "adopt_casks";
pub const TAP_SETTING: &str = "tap";
pub const FORMULA_SETTING: &str = "formula";
pub const CASK_SETTING: &str = "cask";
pub fn init_directive_data() -> DirectiveData {
DirectiveData::from(
DIRECTIVE_NAME.into(),
initialize_settings_object(&[
(FORCE_CASKS_SETTING.to_owned(), Setting::Boolean(false)),
(ADOPT_CASKS_SETTING.to_owned(), Setting::Boolean(false)),
(SKIP_IN_CI_SETTING.to_owned(), Setting::Boolean(false)),
]),
)
}
#[derive(Directive, Clone)]
pub struct BrewDirective<'a> {
data: DirectiveData,
phantom_data: PhantomData<&'a DirectiveData>,
}
impl<'a> Default for BrewDirective<'a> {
fn default() -> BrewDirective<'a> {
BrewDirective::<'a> {
data: init_directive_data(),
phantom_data: PhantomData,
}
}
}
impl<'a> ActionParser<'a> for BrewDirective<'a> {
type ActionType = BrewAction<'a>;
fn parse_action(
&'a self,
context_settings: &Settings,
yaml: &StrictYaml,
_: &Path,
) -> Result<BrewAction<'a>, DotfilesError> {
let force_casks = get_boolean_setting_from_yaml_or_context(
FORCE_CASKS_SETTING,
yaml,
context_settings,
self.data.defaults(),
)?;
let adopt_casks = get_boolean_setting_from_yaml_or_context(
ADOPT_CASKS_SETTING,
yaml,
context_settings,
self.data.defaults(),
)?;
let skip_in_ci = get_boolean_setting_from_yaml_or_context(
SKIP_IN_CI_SETTING,
yaml,
context_settings,
self.data.defaults(),
)?;
let taps = get_optional_string_array_from_yaml_hash(TAP_SETTING, yaml)?;
let formulae = get_optional_string_array_from_yaml_hash(FORMULA_SETTING, yaml)?;
let casks = get_optional_string_array_from_yaml_hash(CASK_SETTING, yaml)?;
#[cfg(target_os = "macos")]
let mas_apps = process_value_from_yaml_hash("mas", yaml, |mas_yaml| {
fold_hash_until_first_err(
mas_yaml,
Ok(Vec::<MacAppStoreItem>::new()),
|key, val| {
Ok((
val
.to_owned()
.into_string()
.ok_or(DotfilesError::from_wrong_yaml(
"Mac App Store app ID is not a string as expected".into(),
val.to_owned(),
StrictYaml::String("".into()),
))
.and_then(|id| {
id.parse::<i64>().map_err(|_| {
DotfilesError::from(
format!("{id} is not a valid Mac App Store app id"),
ErrorType::InconsistentConfigurationError,
)
})
})?,
key,
))
},
|mut list, item| {
list.push(MacAppStoreItem::from(item));
Ok(list)
},
)
})
.map_or_else(
|err| {
if err.is_missing_config("mas") {
Ok(Vec::new())
} else {
Err(err)
}
},
Ok,
)?;
Ok(BrewAction::new(
skip_in_ci,
force_casks,
adopt_casks,
taps,
formulae,
casks,
#[cfg(target_os = "macos")]
mas_apps,
))
}
fn parse_action_list(
&'a self,
context_settings: &Settings,
yaml: &StrictYaml,
current_dir: &Path,
) -> Result<Vec<BrewAction<'a>>, DotfilesError> {
Ok(vec![add_directive_error_prefix(
self,
self.parse_action(context_settings, yaml, current_dir),
)?])
}
}