dotfiles_actions/create/
action.rs1extern crate strict_yaml_rust;
26
27use derivative::Derivative;
28use dotfiles_core::error::DotfilesError;
29use dotfiles_core::path::convert_path_to_absolute;
30use dotfiles_core::path::process_home_dir_in_path;
31use dotfiles_core::settings::{initialize_settings_object, Setting, Settings};
32use dotfiles_core::yaml_util;
33use dotfiles_core::{action::SKIP_IN_CI_SETTING, Action};
34use filesystem::FakeFileSystem;
35use filesystem::FileSystem;
36use filesystem::OsFileSystem;
37
38use getset::Getters;
39use log::info;
40
41use std::io::ErrorKind;
42use std::path::Path;
43use std::path::PathBuf;
44use strict_yaml_rust::StrictYaml;
45
46pub const CREATE_PARENT_DIRS_SETTING: &str = "create_parent_dirs";
49pub const DIR_SETTING: &str = "dir";
52
53pub fn default_settings() -> Settings {
55 initialize_settings_object(&[
56 (
57 CREATE_PARENT_DIRS_SETTING.to_owned(),
58 Setting::Boolean(false),
59 ),
60 (SKIP_IN_CI_SETTING.to_owned(), Setting::Boolean(false)),
61 ])
62}
63
64#[derive(Derivative, Getters)]
66#[derivative(Debug, PartialEq)]
67pub struct CreateAction<F: FileSystem> {
68 skip_in_ci: bool,
70 #[derivative(Debug = "ignore", PartialEq = "ignore")]
75 fs: F,
76 #[get = "pub"]
78 directory: String,
79 #[get = "pub"]
85 create_parent_dirs: bool,
86 #[get = "pub"]
89 current_dir: PathBuf,
90}
91
92pub type NativeCreateAction = CreateAction<OsFileSystem>;
94pub type FakeCreateAction = CreateAction<FakeFileSystem>;
96
97impl<F: FileSystem> CreateAction<F> {
98 pub fn new(
100 fs: F,
101 skip_in_ci: bool,
102 directory: String,
103 create_parent_dirs: bool,
104 current_dir: PathBuf,
105 ) -> Result<Self, DotfilesError> {
106 let action = CreateAction {
107 skip_in_ci,
108 fs,
109 directory,
110 create_parent_dirs,
111 current_dir,
112 };
113 log::trace!("Creating new {:?}", action);
114 Ok(action)
115 }
116}
117
118impl<F: FileSystem> Action for CreateAction<F> {
119 fn execute(&self) -> Result<(), DotfilesError> {
127 fn create_dir<F: FileSystem>(
128 fs: &'_ F,
129 directory: &str,
130 create_parent_dirs: bool,
131 current_dir: &Path,
132 ) -> Result<(), DotfilesError> {
133 let path = PathBuf::from(directory.to_owned());
134 let path = process_home_dir_in_path(&path);
135 let path = convert_path_to_absolute(&path, Some(current_dir))?;
136 if create_parent_dirs {
137 fs.create_dir_all(path)
138 } else {
139 fs.create_dir(path)
140 }
141 .or_else(|io_error| {
142 if let ErrorKind::AlreadyExists = io_error.kind() {
143 Ok(())
144 } else {
145 Err(DotfilesError::from_io_error(io_error))
146 }
147 })
148 }
149 create_dir(
150 &self.fs,
151 &self.directory,
152 self.create_parent_dirs,
153 &self.current_dir,
154 )
155 .map(|_| {
156 info!("Created directory {}", self.directory);
157 })
158 }
159
160 fn skip_in_ci(&self) -> bool {
161 self.skip_in_ci
162 }
163}
164
165pub fn parse_action<F: FileSystem>(
167 fs: F,
168 settings: &Settings,
169 yaml: &StrictYaml,
170 current_dir: &Path,
171) -> Result<CreateAction<F>, DotfilesError> {
172 let defaults = default_settings();
173 CreateAction::new(
174 fs,
175 yaml_util::get_boolean_setting_from_yaml_or_context(
176 SKIP_IN_CI_SETTING,
177 yaml,
178 settings,
179 &defaults,
180 )?,
181 yaml_util::get_string_content_or_keyed_value(yaml, Some(DIR_SETTING))?,
182 yaml_util::get_boolean_setting_from_yaml_or_context(
183 CREATE_PARENT_DIRS_SETTING,
184 yaml,
185 settings,
186 &defaults,
187 )?,
188 current_dir.to_owned(),
189 )
190}