1use anyhow::Result;
2use regex::Regex;
3use std::{
4 env,
5 fs::{self, File},
6 io::{Read, Write},
7 path::{Path, PathBuf},
8 process::Command,
9};
10use toml::Value;
11use which::which;
12
13use crate::config;
14use crate::core::RswErr;
15
16pub fn check_env_cmd(program: &str) -> bool {
17 let result = which(program);
18 match result {
19 Err(e) => {
20 if is_program_in_path(program) {
21 true
22 } else {
23 eprint!("{}\n", e);
24 false
25 }
26 }
27 _ => true,
28 }
29}
30
31pub fn is_program_in_path(program: &str) -> bool {
32 if let Ok(path) = env::var("PATH") {
33 for p in path.split(":") {
34 let p_str = format!("{}/{}", p, program);
35 if fs::metadata(p_str).is_ok() {
36 return true;
37 }
38 }
39 }
40 false
41}
42
43pub fn get_crate_metadata(name: &str, root: PathBuf) -> Value {
45 let crate_root = root.join("Cargo.toml");
46 let content = fs::read_to_string(crate_root).unwrap_or_else(|e| {
47 print(RswErr::Crate(name.into(), e));
49 std::process::exit(1);
50 });
51 let value = content.parse::<Value>().unwrap();
52 value
53}
54
55pub fn path_exists(path: &Path) -> bool {
56 fs::metadata(path).is_ok()
57}
58
59pub fn get_pkg(name: &str) -> (String, String) {
61 let re = Regex::new(r"(?x)(@([\w\d_-]+)/)?((?P<pkg_name>[\w\d_-]+))").unwrap();
63 let caps = re.captures(name).unwrap();
64 let mut scope = "".into();
65 if caps.get(2) != None {
66 scope = caps.get(2).unwrap().as_str().into();
67 }
68
69 (caps["pkg_name"].to_owned(), scope)
70}
71
72pub fn load_file_contents<P: AsRef<Path>>(filename: P, dest: &mut Vec<u8>) -> Result<()> {
75 let filename = filename.as_ref();
76
77 let mut buffer = Vec::new();
78 File::open(filename)?.read_to_end(&mut buffer)?;
79
80 dest.clear();
83 dest.append(&mut buffer);
84
85 Ok(())
86}
87
88pub fn create_file(path: &Path) -> Result<File> {
93 debug!("Creating {}", path.display());
94
95 if let Some(p) = path.parent() {
97 trace!("Parent directory is: {:?}", p);
98 fs::create_dir_all(p)?;
99 }
100
101 File::create(path).map_err(Into::into)
102}
103
104pub fn write_file<P: AsRef<Path>>(build_dir: &Path, filename: P, content: &[u8]) -> Result<()> {
107 let path = build_dir.join(filename);
108 create_file(&path)?.write_all(content).map_err(Into::into)
109}
110
111pub fn copy_dirs<P: AsRef<Path>>(source: P, target: P) -> std::io::Result<()> {
113 fs::create_dir_all(&target)?;
114 for entry in fs::read_dir(source)? {
115 let entry = entry?;
116 let entry_target = target.as_ref().join(entry.file_name());
117 trace!(
118 "Copy {} to {}",
119 entry.path().display(),
120 entry_target.display()
121 );
122 if entry.file_type()?.is_dir() {
123 copy_dirs(entry.path(), entry_target)?;
124 } else {
125 fs::copy(entry.path(), entry_target)?;
126 }
127 }
128 Ok(())
129}
130
131pub fn init_logger() {
133 use colored::Colorize;
134 use env_logger::Builder;
135 use log::Level;
136 use log::LevelFilter;
137
138 let mut builder = Builder::new();
139
140 builder.format(|formatter, record| {
141 let level = record.level().as_str();
142 let log_level = match record.level() {
143 Level::Info => level.blue(),
144 Level::Debug => level.magenta(),
145 Level::Trace => level.green(),
146 Level::Error => level.red(),
147 Level::Warn => level.yellow(),
148 };
149
150 let log_target = match record.level() {
151 Level::Info | Level::Error => format!(""),
152 _ => format!(" {}", record.target().yellow()),
153 };
154
155 let rsw_log = format!("[rsw::{}]", log_level);
156 writeln!(
157 formatter,
158 "{}{} {}",
159 rsw_log.bold().on_black(),
160 log_target,
161 record.args()
162 )
163 });
164
165 if let Ok(var) = env::var("RUST_LOG") {
166 builder.parse_filters(&var);
167 } else {
168 builder.filter(None, LevelFilter::Info);
170 }
171
172 builder.init();
173}
174
175pub fn print<T: std::fmt::Display>(a: T) {
176 println!("{}", a)
177}
178
179pub fn get_root() -> PathBuf {
180 std::env::current_dir().unwrap()
181}
182
183pub fn dot_rsw_dir() -> PathBuf {
184 get_root().join(config::RSW_DIR)
185}
186
187pub fn init_rsw_crates(content: &[u8]) -> Result<()> {
188 let rsw_root = dot_rsw_dir();
189 if !path_exists(rsw_root.as_path()) {
190 std::fs::create_dir(&rsw_root)?;
191 }
192
193 let rsw_crates = rsw_root.join(config::RSW_CRATES);
194 if !path_exists(rsw_crates.as_path()) {
195 File::create(&rsw_crates)?;
196 }
197 fs::write(rsw_crates, content)?;
198
199 Ok(())
200}
201
202pub fn rsw_watch_file(info_content: &[u8], err_content: &[u8], file_type: String) -> Result<()> {
203 let rsw_root = dot_rsw_dir();
204 let rsw_info = rsw_root.join(config::RSW_INFO);
205 let rsw_err = rsw_root.join(config::RSW_ERR);
206 if !path_exists(rsw_info.as_path()) {
207 File::create(&rsw_info)?;
208 }
209 if !path_exists(rsw_err.as_path()) {
210 File::create(&rsw_err)?;
211 }
212 fs::write(&rsw_info, info_content)?;
213 if file_type == "info" {
214 fs::write(&rsw_err, "".as_bytes())?;
215 }
216 if file_type == "err" {
217 fs::write(rsw_err, err_content)?;
218 }
219
220 Ok(())
221}
222
223pub fn os_cli<P: AsRef<Path>>(cli: String, args: Vec<String>, path: P) {
224 if cfg!(target_os = "windows") {
225 Command::new("cmd")
226 .arg("/C")
227 .arg(cli)
228 .args(args)
229 .current_dir(path)
230 .status()
231 .unwrap();
232 } else {
233 Command::new(cli)
234 .args(args)
235 .current_dir(path)
236 .status()
237 .unwrap();
238 }
239}
240
241pub fn vec_of_str(v: &[&str]) -> Vec<String> {
243 v.iter().map(|&x| x.into()).collect()
244}
245
246#[cfg(test)]
247mod pkg_name_tests {
248 use super::*;
249
250 #[test]
251 fn pkg_word() {
252 assert_eq!(get_pkg("@rsw/test".into()), ("test".into(), "rsw".into()));
253 }
254
255 #[test]
256 fn pkg_word_num() {
257 assert_eq!(get_pkg("wasm123".into()), ("wasm123".into(), "".into()));
258 }
259
260 #[test]
261 fn pkg_word_num_line() {
262 assert_eq!(
263 get_pkg("@rsw-org/my_wasm".into()),
264 ("my_wasm".into(), "rsw-org".into())
265 );
266 }
267}