dotfiles_actions/brew/
directive.rs1extern crate strict_yaml_rust;
24
25use crate::brew::action::BrewAction;
26#[cfg(target_os = "macos")]
27use crate::brew::action::MacAppStoreItem;
28use dotfiles_core::action::ActionParser;
29use dotfiles_core::action::SKIP_IN_CI_SETTING;
30use dotfiles_core::directive::DirectiveData;
31use dotfiles_core::error::add_directive_error_prefix;
32use dotfiles_core::error::DotfilesError;
33#[cfg(target_os = "macos")]
34use dotfiles_core::error::ErrorType;
35use dotfiles_core::settings::initialize_settings_object;
36use dotfiles_core::settings::Setting;
37use dotfiles_core::settings::Settings;
38use dotfiles_core::yaml_util::*;
39use dotfiles_core_macros::Directive;
40
41use std::marker::PhantomData;
42use std::path::Path;
43use strict_yaml_rust::StrictYaml;
44
45pub const DIRECTIVE_NAME: &str = "brew";
47pub const FORCE_CASKS_SETTING: &str = "force_casks";
49pub const ADOPT_CASKS_SETTING: &str = "adopt_casks";
51
52pub const TAP_SETTING: &str = "tap";
54pub const FORMULA_SETTING: &str = "formula";
56pub const CASK_SETTING: &str = "cask";
58
59pub fn init_directive_data() -> DirectiveData {
61 DirectiveData::from(
62 DIRECTIVE_NAME.into(),
63 initialize_settings_object(&[
64 (FORCE_CASKS_SETTING.to_owned(), Setting::Boolean(false)),
65 (ADOPT_CASKS_SETTING.to_owned(), Setting::Boolean(false)),
66 (SKIP_IN_CI_SETTING.to_owned(), Setting::Boolean(false)),
67 ]),
68 )
69}
70
71#[derive(Directive, Clone)]
73pub struct BrewDirective<'a> {
74 data: DirectiveData,
75 phantom_data: PhantomData<&'a DirectiveData>,
76}
77
78impl<'a> Default for BrewDirective<'a> {
79 fn default() -> BrewDirective<'a> {
80 BrewDirective::<'a> {
81 data: init_directive_data(),
82 phantom_data: PhantomData,
83 }
84 }
85}
86
87impl<'a> ActionParser<'a> for BrewDirective<'a> {
88 type ActionType = BrewAction<'a>;
89
90 fn parse_action(
91 &'a self,
92 context_settings: &Settings,
93 yaml: &StrictYaml,
94 _: &Path,
95 ) -> Result<BrewAction<'a>, DotfilesError> {
96 let force_casks = get_boolean_setting_from_yaml_or_context(
97 FORCE_CASKS_SETTING,
98 yaml,
99 context_settings,
100 self.data.defaults(),
101 )?;
102 let adopt_casks = get_boolean_setting_from_yaml_or_context(
103 ADOPT_CASKS_SETTING,
104 yaml,
105 context_settings,
106 self.data.defaults(),
107 )?;
108 let skip_in_ci = get_boolean_setting_from_yaml_or_context(
109 SKIP_IN_CI_SETTING,
110 yaml,
111 context_settings,
112 self.data.defaults(),
113 )?;
114 let taps = get_optional_string_array_from_yaml_hash(TAP_SETTING, yaml)?;
115 let formulae = get_optional_string_array_from_yaml_hash(FORMULA_SETTING, yaml)?;
116 let casks = get_optional_string_array_from_yaml_hash(CASK_SETTING, yaml)?;
117 #[cfg(target_os = "macos")]
118 let mas_apps = process_value_from_yaml_hash("mas", yaml, |mas_yaml| {
119 fold_hash_until_first_err(
120 mas_yaml,
121 Ok(Vec::<MacAppStoreItem>::new()),
122 |key, val| {
123 Ok((
124 val
125 .to_owned()
126 .into_string()
127 .ok_or(DotfilesError::from_wrong_yaml(
128 "Mac App Store app ID is not a string as expected".into(),
129 val.to_owned(),
130 StrictYaml::String("".into()),
131 ))
132 .and_then(|id| {
133 id.parse::<i64>().map_err(|_| {
134 DotfilesError::from(
135 format!("{id} is not a valid Mac App Store app id"),
136 ErrorType::InconsistentConfigurationError,
137 )
138 })
139 })?,
140 key,
141 ))
142 },
143 |mut list, item| {
144 list.push(MacAppStoreItem::from(item));
145 Ok(list)
146 },
147 )
148 })
149 .map_or_else(
150 |err| {
151 if err.is_missing_config("mas") {
152 Ok(Vec::new())
153 } else {
154 Err(err)
155 }
156 },
157 Ok,
158 )?;
159
160 Ok(BrewAction::new(
161 skip_in_ci,
162 force_casks,
163 adopt_casks,
164 taps,
165 formulae,
166 casks,
167 #[cfg(target_os = "macos")]
168 mas_apps,
169 ))
170 }
171
172 fn parse_action_list(
175 &'a self,
176 context_settings: &Settings,
177 yaml: &StrictYaml,
178 current_dir: &Path,
179 ) -> Result<Vec<BrewAction<'a>>, DotfilesError> {
180 Ok(vec![add_directive_error_prefix(
181 self,
182 self.parse_action(context_settings, yaml, current_dir),
183 )?])
184 }
185}