sass_rocket_fairing/
context.rs1use normpath::PathExt;
2
3use std::path::{Path, PathBuf};
4
5pub struct Context {
7 pub sass_dir: PathBuf,
8 pub css_dir: PathBuf,
9 pub rsass_format: rsass::output::Format,
10}
11
12impl Context {
13 pub fn initialize(sass_dir: &Path, css_dir: &Path, rsass_format: rsass::output::Format) -> Option<Self> {
15 let sass_dir_buf = match sass_dir.normalize() {
16 Ok(dir) => dir.into_path_buf(),
17 Err(e) => {
18 rocket::error!("Invalid sass directory '{}': {}.", sass_dir.display(), e);
19 return None;
20 }
21 };
22
23 let css_dir_buf = match css_dir.normalize() {
24 Ok(dir) => dir.into_path_buf(),
25 Err(e) => {
26 rocket::error_!("Invalid css directory '{}': {}.", css_dir.display(), e);
27 return None;
28 }
29 };
30
31 Some(Self { sass_dir: sass_dir_buf, css_dir: css_dir_buf, rsass_format: rsass_format })
32 }
33}
34
35pub use self::manager::ContextManager;
36
37#[cfg(not(debug_assertions))]
38mod manager {
39 use std::ops::Deref;
40 use crate::Context;
41
42 pub struct ContextManager(Context);
43
44 impl ContextManager {
45 pub fn new(ctx: Context) -> ContextManager {
46 ContextManager(ctx)
47 }
48
49 pub fn context<'a>(&'a self) -> impl Deref<Target=Context> + 'a {
50 &self.0
51 }
52
53 pub fn is_reloading(&self) -> bool {
54 false
55 }
56
57 pub fn compile_all_and_write(&self) {}
59 }
60}
61
62#[cfg(debug_assertions)]
63mod manager {
64 use std::sync::{RwLock, Mutex, mpsc};
65 use std::collections::HashMap;
66 use std::path::PathBuf;
67 use std::fs;
68
69 use std::io::Write;
70
71 use notify::{raw_watcher, RawEvent, RecommendedWatcher, RecursiveMode, Watcher};
72 use walkdir::WalkDir;
73
74 use super::Context;
75
76 pub struct ContextManager{
78 context: RwLock<Context>,
79 watcher: Option<(RecommendedWatcher, Mutex<mpsc::Receiver<RawEvent>>)>
80 }
81
82 impl ContextManager {
83 pub fn new(ctx: Context) -> Self {
84 let (tx, rx) = mpsc::channel();
85 let watcher = raw_watcher(tx).and_then(|mut watcher| {
86 watcher.watch(ctx.sass_dir.canonicalize()?, RecursiveMode::Recursive)?;
87
88 Ok(watcher)
89 });
90
91 let watcher = match watcher {
92 Ok(watcher) => Some((watcher, Mutex::new(rx))),
93 Err(e) => {
94 rocket::warn!("Failed to enable live sass compiling: {}", e);
95 rocket::debug_!("Reload error: {:?}", e);
96 rocket::warn_!("Live sass compiling is unawailable.");
97
98 None
99 }
100 };
101
102 Self { context: RwLock::new(ctx), watcher }
103 }
104
105 pub fn context(&self) -> impl std::ops::Deref<Target=Context> + '_ {
107 self.context.read().unwrap()
108 }
109
110 pub fn context_mut(&self) -> impl std::ops::DerefMut<Target=Context> + '_ {
112 self.context.write().unwrap()
113 }
114
115 pub fn compile_all(&self) -> Result<HashMap<String, String>, ()> {
117 let mut compiled: HashMap<String, String> = HashMap::new();
118 let sass_dir = &*self.context().sass_dir;
119 let rsass_format = *&self.context().rsass_format;
120
121 for entry in WalkDir::new(sass_dir).into_iter().filter_map(|e| e.ok()) {
122 if entry.metadata().unwrap().is_file() {
123 let file_name = entry.path().file_name().unwrap().to_str().unwrap().to_string();
124 let result = match crate::compile_file(entry.into_path(), rsass_format) {
125 Ok(result) => result,
126 Err(e) => {
127 rocket::error!("Failed to compile file '{}'", file_name);
128 rocket::error!("Sass error: {:?}", e);
129
130 break;
131 }
132 };
133
134 compiled.insert(file_name, result);
135 }
136 }
137
138 Ok(compiled)
139 }
140
141 pub fn write_compiled(&self, compiled_files: HashMap<String, String>) {
143 let css_dir = &*self.context().css_dir;
144
145 for (sass_file_name, compiled) in compiled_files {
146 let mut sass_file_name_path = PathBuf::new();
147
148 sass_file_name_path.push(sass_file_name);
149 sass_file_name_path.set_extension("css");
150
151 let css_file_path = css_dir.join(sass_file_name_path);
152
153 let mut file = fs::File::create(&css_file_path)
154 .expect(format!("Failed to create css file: '{:?}'", css_file_path).as_str());
155
156 file.write_all(compiled.as_bytes())
157 .expect(format!("Failed to write file: {:?}", css_file_path).as_str());
158 }
159 }
160
161 pub fn compile_all_and_write(&self) {
163 if let Ok(compiled_files) = self.compile_all() {
164 self.write_compiled(compiled_files);
165 }
166
167 }
168
169 pub fn is_reloading(&self) -> bool {
171 self.watcher.is_some()
172 }
173
174 pub fn reload_if_needed(&self) {
177 let sass_changes = self.watcher.as_ref()
178 .map(|(_, rx)| rx.lock().expect("Failed to lock receiver").try_iter().count() > 0 );
179
180 if let Some(true) = sass_changes {
181 rocket::info_!("Change detected: compiling sass files.");
182
183 self.compile_all_and_write();
184 }
185 }
186 }
187}