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}