dotsy/
lib.rs

1pub mod cli;
2pub mod commands;
3pub mod configs;
4pub mod defaults;
5pub mod error;
6pub mod handlers;
7pub mod macros;
8
9use ansi_term::Colour::Green;
10use std::path::PathBuf;
11
12use std::fs;
13
14use configs::{ConfigFile, DotsyConfig, Link};
15use error::DotsyError;
16extern crate shellexpand;
17
18pub type DotsyResult<T, E = DotsyError> = ::std::result::Result<T, E>;
19
20// FIXME: This stuff should be handled better (there is a lot of duplicate logic)
21
22fn get_absolute_link(link: Link, global_config: &DotsyConfig) -> Link {
23    let from = absolute(
24        global_config
25            .dotfiles
26            .join(&global_config.configs_dir)
27            .join(link.from),
28    );
29    let to = absolute(link.to);
30
31    Link {
32        from,
33        to,
34        glob: link.glob,
35    }
36}
37
38fn link_exists(path: &PathBuf) -> bool {
39    let metadata = fs::symlink_metadata(path);
40    if metadata.is_err() {
41        return false;
42    }
43    true
44}
45
46fn is_symlink(path: &PathBuf) -> bool {
47    let metadata = fs::symlink_metadata(path);
48    if metadata.is_err() {
49        return false;
50    }
51    metadata.unwrap().file_type().is_symlink()
52}
53
54fn absolute(base: PathBuf) -> PathBuf {
55    match shellexpand::tilde(&base.into_os_string().to_str().unwrap()) {
56        std::borrow::Cow::Borrowed(s) => PathBuf::from(s),
57        std::borrow::Cow::Owned(s) => PathBuf::from(s),
58    }
59}
60
61pub fn install_configs(configs: Vec<String>, global_config: &DotsyConfig) {
62    for config in configs {
63        install_config(config, global_config)
64    }
65}
66
67pub fn uninstall_configs(configs: Vec<String>, global_config: &DotsyConfig) {
68    for config in configs {
69        uninstall_config(config, global_config);
70    }
71}
72
73fn uninstall_config(config: String, global_config: &DotsyConfig) {
74    println!(
75        "{message}: {arg}",
76        message = Green.paint("Attempting to uninstall config"),
77        arg = config
78    );
79
80    let config = {
81        let this = configs::ConfigConfig::load_by_name(&config, global_config);
82        match this {
83            Ok(t) => t,
84            Err(e) => return dotsy_log_error!("{}", e),
85        }
86    };
87
88    // Unlink files
89    for link in config.links.unwrap_or_default() {
90        handlers::link::unlink_file(link, global_config)
91            .unwrap_or_else(|e| dotsy_log_error!("{}", e));
92    }
93
94    // Run cleanup scripts
95    for script in config.revert_shell.unwrap_or_default() {
96        handlers::script::run_script(&script).unwrap_or_else(|e| dotsy_log_error!("{}", e));
97    }
98}
99
100fn install_config(config: String, global_config: &DotsyConfig) {
101    println!(
102        "{message}: {arg}",
103        message = Green.paint("Attempting to install config"),
104        arg = config
105    );
106
107    let config = {
108        let this = configs::ConfigConfig::load_by_name(&config, global_config);
109        match this {
110            Ok(t) => t,
111            Err(e) => return dotsy_log_error!("{}", e),
112        }
113    };
114
115    // TODO: Extract this logic
116    // Link files
117    // TODO: I need to work more on paths logic
118    for link in config.links.unwrap_or_default() {
119        handlers::link::link_file(link, global_config)
120            .unwrap_or_else(|e| dotsy_log_error!("{}", e));
121    }
122
123    // Run scripts
124    for script in config.shell.unwrap_or_default() {
125        handlers::script::run_script(&script).unwrap_or_else(|e| dotsy_log_error!("{}", e));
126    }
127
128    // Make directories
129    for dir in config.directories.unwrap_or_default() {
130        handlers::files::create_dir(absolute(dir)).unwrap_or_else(|e| dotsy_log_error!("{}", e));
131    }
132}
133
134fn uninstall_profile(_profile: String, global_config: &DotsyConfig) {
135    println!(
136        "{message}: {arg}",
137        message = Green.paint("Attempting to uninstall profile"),
138        arg = _profile
139    );
140    let profile = configs::ProfileConfig::load_by_name(&_profile, global_config).unwrap();
141
142    // Unlink files
143    for link in profile.links.unwrap_or_default() {
144        handlers::link::unlink_file(link, global_config)
145            .unwrap_or_else(|e| dotsy_log_error!("{}", e));
146    }
147
148    // Run cleanup scripts
149    for script in profile.revert_shell.unwrap_or_default() {
150        handlers::script::run_script(&script).unwrap_or_else(|e| dotsy_log_error!("{}", e));
151    }
152
153    // Uninstall configs
154    for config in profile.configs.unwrap_or_default() {
155        uninstall_config(config, global_config);
156    }
157    println!(
158        "{message}: {arg}",
159        message = Green.paint("Finished uninstalling profile"),
160        arg = _profile
161    );
162}
163
164fn install_profile(_profile: String, global_config: &DotsyConfig) {
165    println!(
166        "{message}: {arg}",
167        message = Green.paint("Attempting to install profile"),
168        arg = _profile
169    );
170    let profile = configs::ProfileConfig::load_by_name(&_profile, global_config).unwrap();
171
172    // TODO: Extract this logic
173    // Link files
174    for link in profile.links.unwrap_or_default() {
175        handlers::link::link_file(link, global_config)
176            .unwrap_or_else(|e| dotsy_log_error!("{}", e));
177    }
178
179    // Make directories
180    for dir in profile.directories.unwrap_or_default() {
181        handlers::files::create_dir(absolute(dir)).unwrap_or_else(|e| dotsy_log_error!("{}", e));
182    }
183
184    // Run scripts
185    for script in profile.shell.unwrap_or_default() {
186        handlers::script::run_script(&script).unwrap_or_else(|e| dotsy_log_error!("{}", e));
187    }
188
189    // Install configs
190    install_configs(profile.configs.unwrap_or_default(), global_config);
191
192    println!(
193        "{message}: {arg}",
194        message = Green.paint("Finished installing profile"),
195        arg = _profile
196    );
197}
198
199pub fn load_rcfile() -> DotsyResult<DotsyConfig> {
200    let rcfile_path = defaults::fallback_path().unwrap();
201
202    let mut config = configs::DotsyConfig::load(rcfile_path).unwrap();
203    config.dotfiles = absolute(config.dotfiles);
204
205    Ok(config)
206}