diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..1f53a44 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1 @@ +"hard_tabs" = true diff --git a/src/check.rs b/src/check.rs index 9e6044a..0d57e31 100644 --- a/src/check.rs +++ b/src/check.rs @@ -1,3 +1,3 @@ pub fn main(_files: Vec) { - todo!() + todo!() } diff --git a/src/config.rs b/src/config.rs index deb7177..9f2140e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,6 +1,6 @@ use std::{ - env, fs, - path::{Path, PathBuf}, + env, fs, + path::{Path, PathBuf}, }; use ron::ser::PrettyConfig; @@ -10,71 +10,71 @@ use crate::utils::Apply; #[derive(Debug, Serialize, Deserialize)] pub struct Config { - name: String, - main_file: String, - test_file: String, - includes: Vec, + name: String, + main_file: String, + test_file: String, + includes: Vec, } impl Config { - const CONFIG_FILE_NAME: &'static str = "pi.ron"; - pub fn new(name: String) -> Self { - Self { - name, - main_file: "main.c".into(), - test_file: "test.c".into(), - includes: vec![], - } - } + const CONFIG_FILE_NAME: &'static str = "pi.ron"; + pub fn new(name: String) -> Self { + Self { + name, + main_file: "main.c".into(), + test_file: "test.c".into(), + includes: vec![], + } + } - pub fn write(&self, mut path: PathBuf) { - path.extend([Self::CONFIG_FILE_NAME]); - let content = - ron::ser::to_string_pretty(self, PrettyConfig::default().struct_names(true)).unwrap(); - fs::write(path, content).unwrap(); - } + pub fn write(&self, mut path: PathBuf) { + path.extend([Self::CONFIG_FILE_NAME]); + let content = + ron::ser::to_string_pretty(self, PrettyConfig::default().struct_names(true)).unwrap(); + fs::write(path, content).unwrap(); + } - pub fn get_current() -> Self { - let path = env::current_dir().unwrap(); - Self::get(&path) - .unwrap_or_else(|| Self::new(path.file_name().unwrap().to_str().unwrap().to_string())) - } + pub fn get_current() -> Self { + let path = env::current_dir().unwrap(); + Self::get(&path) + .unwrap_or_else(|| Self::new(path.file_name().unwrap().to_str().unwrap().to_string())) + } - pub fn get(path: &Path) -> Option { - let path = path.to_path_buf().canonicalize().unwrap(); - Self::try_get(&path).or_else(|| path.parent().and_then(Self::get)) - } + pub fn get(path: &Path) -> Option { + let path = path.to_path_buf().canonicalize().unwrap(); + Self::try_get(&path).or_else(|| path.parent().and_then(Self::get)) + } - pub fn name(&self) -> &str { - &self.name - } + pub fn name(&self) -> &str { + &self.name + } - pub fn main_file(&self) -> &str { - &self.main_file - } + pub fn main_file(&self) -> &str { + &self.main_file + } - pub fn test_file(&self) -> &str { - &self.test_file - } + pub fn test_file(&self) -> &str { + &self.test_file + } - pub fn includes(&self) -> &Vec { - &self.includes - } + pub fn includes(&self) -> &Vec { + &self.includes + } - fn try_get(path: &Path) -> Option { - let path = path.to_path_buf().apply(|p| p.push(Self::CONFIG_FILE_NAME)); - fs::read_to_string(path) - .ok() - .and_then(|content| ron::from_str(&content).ok()) - } + fn try_get(path: &Path) -> Option { + let path = path.to_path_buf().apply(|p| p.push(Self::CONFIG_FILE_NAME)); + fs::read_to_string(path) + .ok() + .and_then(|content| ron::from_str(&content).ok()) + } } pub fn create(path: String) { - let absolute = fs::canonicalize(&path).unwrap(); - if !absolute.is_dir() { - panic!("not a directory"); - } - let name = absolute.file_name().unwrap(); - let config = Config::new(name.to_str().unwrap().to_string()); - config.write(absolute); + let absolute = fs::canonicalize(&path).unwrap(); + if !absolute.is_dir() { + panic!("not a directory"); + } + let name = absolute.file_name().unwrap(); + let config = Config::new(name.to_str().unwrap().to_string()); + config.write(absolute); } diff --git a/src/main.rs b/src/main.rs index 74406a6..2592f49 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,80 +11,80 @@ pub mod watch; #[derive(Parser)] pub struct Arguments { - #[clap(subcommand)] - command: Commands, + #[clap(subcommand)] + command: Commands, } #[allow(non_camel_case_types)] #[derive(Subcommand)] pub enum Commands { - /// Checks a source file for conformance with piscine limitations. - check { - /// File to check. - files: Vec, - }, + /// Checks a source file for conformance with piscine limitations. + check { + /// File to check. + files: Vec, + }, - /// Runs a set of files or the default target. - run { - /// Files to run. - files: Vec, - }, + /// Runs a set of files or the default target. + run { + /// Files to run. + files: Vec, + }, - /// Runs tests contained within a particular test file or - test { - /// Wether to capture standard output or not. - #[clap(short, long)] - capture: bool, + /// Runs tests contained within a particular test file or + test { + /// Wether to capture standard output or not. + #[clap(short, long)] + capture: bool, - /// Files to run tests from. - files: Vec, + /// Files to run tests from. + files: Vec, - /// Specific tests to run. - #[clap(short, long)] - tests: Vec, - }, + /// Specific tests to run. + #[clap(short, long)] + tests: Vec, + }, - /// Watches changes to source files and re run them - watch { - /// Files to run. - files: Vec, - }, + /// Watches changes to source files and re run them + watch { + /// Files to run. + files: Vec, + }, - /// - init { path: String }, + /// + init { path: String }, } fn append_includes(list: &mut Vec) { - list.extend( - Config::get_current() - .includes() - .iter() - .map(|f| f.to_string()), - ); + list.extend( + Config::get_current() + .includes() + .iter() + .map(|f| f.to_string()), + ); } fn main() { - let args: Arguments = Parser::parse(); + let args: Arguments = Parser::parse(); - match args.command { - Commands::check { files } => check::main(files), - Commands::run { mut files } => { - append_includes(&mut files); - run::main(files); - } - Commands::test { - capture, - mut files, - tests, - } => { - append_includes(&mut files); - let tests = (!tests.is_empty()).then_some(tests); - test::main(capture, files, tests) - } - Commands::watch { mut files } => { - append_includes(&mut files); - watch::main(files) - } - Commands::init { path } => config::create(path), - } + match args.command { + Commands::check { files } => check::main(files), + Commands::run { mut files } => { + append_includes(&mut files); + run::main(files); + } + Commands::test { + capture, + mut files, + tests, + } => { + append_includes(&mut files); + let tests = (!tests.is_empty()).then_some(tests); + test::main(capture, files, tests) + } + Commands::watch { mut files } => { + append_includes(&mut files); + watch::main(files) + } + Commands::init { path } => config::create(path), + } } diff --git a/src/run.rs b/src/run.rs index 647a11a..af662f6 100644 --- a/src/run.rs +++ b/src/run.rs @@ -1,28 +1,28 @@ use crate::{ - tasks::{CompileTask, RunTask}, - utils::{log_failure, log_success}, + tasks::{CompileTask, RunTask}, + utils::{log_failure, log_success}, }; pub fn main(files: Vec) -> Option<()> { - let source_file = files.into_iter().map(|f| f.into()).collect(); - let compiled = CompileTask::new(source_file) - .with_flag("-Wall") - .with_flag("-Wextra") - .with_flag("-std=c99") - .run() - .map(Option::from) - .unwrap_or_else(|_| { - log_failure("compilation failed"); - None - })?; - log_success("compilation successful"); - RunTask::new(compiled) - .run() - .map(Option::from) - .unwrap_or_else(|_| { - log_failure("process failure"); - None - })?; - log_success("process exited successfully"); - Some(()) + let source_file = files.into_iter().map(|f| f.into()).collect(); + let compiled = CompileTask::new(source_file) + .with_flag("-Wall") + .with_flag("-Wextra") + .with_flag("-std=c99") + .run() + .map(Option::from) + .unwrap_or_else(|_| { + log_failure("compilation failed"); + None + })?; + log_success("compilation successful"); + RunTask::new(compiled) + .run() + .map(Option::from) + .unwrap_or_else(|_| { + log_failure("process failure"); + None + })?; + log_success("process exited successfully"); + Some(()) } diff --git a/src/tasks.rs b/src/tasks.rs index f0ea485..e3592ba 100644 --- a/src/tasks.rs +++ b/src/tasks.rs @@ -1,109 +1,109 @@ use std::{ - fs, - path::PathBuf, - process::{Command, ExitStatus}, - thread, - time::Duration, + fs, + path::PathBuf, + process::{Command, ExitStatus}, + thread, + time::Duration, }; use crate::utils::{ - log_command_run, log_separator_bottom, log_separator_top, tmp_file_path, Apply, + log_command_run, log_separator_bottom, log_separator_top, tmp_file_path, Apply, }; pub struct CompileTask { - files: Vec, - addition: Vec, - flags: Vec, + files: Vec, + addition: Vec, + flags: Vec, } // TODO: split compile & compile raw impl CompileTask { - pub fn new(files: Vec) -> Self { - Self { - files, - addition: vec![], - flags: vec![], - } - } + pub fn new(files: Vec) -> Self { + Self { + files, + addition: vec![], + flags: vec![], + } + } - pub fn with_addition(mut self, code: impl ToString) -> Self { - self.addition.push(code.to_string()); - self - } + pub fn with_addition(mut self, code: impl ToString) -> Self { + self.addition.push(code.to_string()); + self + } - pub fn with_flag(mut self, flag: impl ToString) -> Self { - self.flags.push(flag.to_string()); - self - } + pub fn with_flag(mut self, flag: impl ToString) -> Self { + self.flags.push(flag.to_string()); + self + } - pub fn run(self) -> Result { - let proc_source = self.gen_source(); - let mut sources = self.files.clone(); - sources.push(proc_source); - self.compile(sources) - } + pub fn run(self) -> Result { + let proc_source = self.gen_source(); + let mut sources = self.files.clone(); + sources.push(proc_source); + self.compile(sources) + } - pub fn gen_source(&self) -> PathBuf { - let mut output_path = tmp_file_path(); - // TODO: make use of supplement - output_path.set_extension("c"); - fs::write(&output_path, "").unwrap(); - output_path - } + pub fn gen_source(&self) -> PathBuf { + let mut output_path = tmp_file_path(); + // TODO: make use of supplement + output_path.set_extension("c"); + fs::write(&output_path, "").unwrap(); + output_path + } - pub fn compile(&self, sources: Vec) -> Result { - let output_path = tmp_file_path().apply(|o| o.set_extension("b")); - let output_path_ref = output_path.to_str().unwrap(); - let mut command = Command::new("gcc"); - command - .args(["-o", output_path_ref]) - .args(self.flags.clone()) - .args(sources.iter().map(|s| s.to_str().unwrap())); - log_command_run(&command); - log_separator_top(); - let status = command.status().unwrap(); - log_separator_bottom(); - thread::sleep(Duration::from_millis(100)); - status.success().then_some(output_path).ok_or(status) - } + pub fn compile(&self, sources: Vec) -> Result { + let output_path = tmp_file_path().apply(|o| o.set_extension("b")); + let output_path_ref = output_path.to_str().unwrap(); + let mut command = Command::new("gcc"); + command + .args(["-o", output_path_ref]) + .args(self.flags.clone()) + .args(sources.iter().map(|s| s.to_str().unwrap())); + log_command_run(&command); + log_separator_top(); + let status = command.status().unwrap(); + log_separator_bottom(); + thread::sleep(Duration::from_millis(100)); + status.success().then_some(output_path).ok_or(status) + } } pub struct RunTask { - file: PathBuf, + file: PathBuf, } impl RunTask { - pub fn new(file: PathBuf) -> Self { - Self { file } - } + pub fn new(file: PathBuf) -> Self { + Self { file } + } - pub fn run(self) -> Result<(), ExitStatus> { - let mut command = Command::new(self.file); - log_command_run(&command); - log_separator_top(); - let status = command.status().unwrap(); - log_separator_bottom(); - if status.success() { - Ok(()) - } else { - Err(status) - } - } + pub fn run(self) -> Result<(), ExitStatus> { + let mut command = Command::new(self.file); + log_command_run(&command); + log_separator_top(); + let status = command.status().unwrap(); + log_separator_bottom(); + if status.success() { + Ok(()) + } else { + Err(status) + } + } } pub struct GenTask { - content: String, + content: String, } impl GenTask { - pub fn new(content: String) -> Self { - Self { content } - } - pub fn run(self) -> PathBuf { - let output_path = tmp_file_path().apply(|o| o.set_extension("c")); - fs::write(&output_path, &self.content).unwrap(); - dbg!(fs::read_to_string(&output_path).unwrap()); - output_path - } + pub fn new(content: String) -> Self { + Self { content } + } + pub fn run(self) -> PathBuf { + let output_path = tmp_file_path().apply(|o| o.set_extension("c")); + fs::write(&output_path, &self.content).unwrap(); + dbg!(fs::read_to_string(&output_path).unwrap()); + output_path + } } diff --git a/src/test.rs b/src/test.rs index 60c241b..a1007c7 100644 --- a/src/test.rs +++ b/src/test.rs @@ -3,39 +3,39 @@ use std::fs; use crate::tasks::{CompileTask, GenTask, RunTask}; pub fn main(_capture: bool, files: Vec, _test: Option>) { - // let includes = files - // .iter() - // .cloned() - // .map(|p| PathBuf::from_str(&p).unwrap()) - // .collect::>(); + // let includes = files + // .iter() + // .cloned() + // .map(|p| PathBuf::from_str(&p).unwrap()) + // .collect::>(); - for path in files { - let content = fs::read_to_string(&path).unwrap(); - let tests = find_tests(content); - for test in tests { - let content = gen_test_main(fs::canonicalize(&path).unwrap().to_str().unwrap(), &test); - let generated_code = GenTask::new(content).run(); + for path in files { + let content = fs::read_to_string(&path).unwrap(); + let tests = find_tests(content); + for test in tests { + let content = gen_test_main(fs::canonicalize(&path).unwrap().to_str().unwrap(), &test); + let generated_code = GenTask::new(content).run(); - // compile with all files - //let files = includes.clone().apply(|v| v.insert(0, generated_code)); - let generated_bin = CompileTask::new(vec![generated_code]).run().unwrap(); - // run - RunTask::new(generated_bin).run().unwrap(); - } - } + // compile with all files + //let files = includes.clone().apply(|v| v.insert(0, generated_code)); + let generated_bin = CompileTask::new(vec![generated_code]).run().unwrap(); + // run + RunTask::new(generated_bin).run().unwrap(); + } + } } pub fn find_tests(source: String) -> Vec { - source - .split([' ', '(', ')', ';']) - .filter(|name| name.starts_with("test_")) - .map(String::from) - .collect() + source + .split([' ', '(', ')', ';']) + .filter(|name| name.starts_with("test_")) + .map(String::from) + .collect() } pub fn gen_test_main(path: &str, test: &str) -> String { - format!( - " + format!( + " void ____test(); int main() {{ @@ -49,5 +49,5 @@ void ____test() {{ {test}(); }} " - ) + ) } diff --git a/src/utils.rs b/src/utils.rs index ecea085..e93f060 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -4,90 +4,90 @@ use chrono::Utc; use termion::color; pub fn tmp_file_path() -> PathBuf { - let ms = Utc::now().timestamp_millis().to_string(); - let mut path: PathBuf = ["/", "tmp", "epitls-pi"].iter().collect(); - fs::create_dir_all(&path).unwrap(); - path.push(ms); - path + let ms = Utc::now().timestamp_millis().to_string(); + let mut path: PathBuf = ["/", "tmp", "epitls-pi"].iter().collect(); + fs::create_dir_all(&path).unwrap(); + path.push(ms); + path } pub trait Apply: Sized { - fn apply(mut self, f: F) -> Self - where - F: FnOnce(&mut Self) -> O, - { - f(&mut self); - self - } + fn apply(mut self, f: F) -> Self + where + F: FnOnce(&mut Self) -> O, + { + f(&mut self); + self + } } impl Apply for T {} fn log_pi_prefix() { - print!( - "{}[pi] {}", - color::Fg(color::LightBlue), - color::Fg(color::Reset) - ) + print!( + "{}[pi] {}", + color::Fg(color::LightBlue), + color::Fg(color::Reset) + ) } pub fn log_command_run(command: &Command) { - log_pi_prefix(); - let prefix = format_process("running "); - let value = format_variable(&format!("{command:?}")); - let suffix = format_process(" ..."); - println!("{prefix}{value}{suffix}"); + log_pi_prefix(); + let prefix = format_process("running "); + let value = format_variable(&format!("{command:?}")); + let suffix = format_process(" ..."); + println!("{prefix}{value}{suffix}"); } pub fn log_separator() { - println!("────────────────") + println!("────────────────") } pub fn log_separator_top() { - println!("───────────────┐") + println!("───────────────┐") } pub fn log_separator_bottom() { - println!("───────────────┘") + println!("───────────────┘") } pub fn log_failure(text: &str) { - log_pi_prefix(); - let text = format!("{}{text}{}", color::Fg(color::Red), color::Fg(color::Reset)); - println!("{text}"); + log_pi_prefix(); + let text = format!("{}{text}{}", color::Fg(color::Red), color::Fg(color::Reset)); + println!("{text}"); } pub fn log_success(text: &str) { - log_pi_prefix(); - let text = format_success(text); - println!("{text}"); + log_pi_prefix(); + let text = format_success(text); + println!("{text}"); } pub fn log_process(text: &str) { - log_pi_prefix(); - let text = format_process(text); - println!("{text}"); + log_pi_prefix(); + let text = format_process(text); + println!("{text}"); } fn format_process(input: &str) -> String { - format!( - "{}{input}{}", - color::Fg(color::Blue), - color::Fg(color::Reset) - ) + format!( + "{}{input}{}", + color::Fg(color::Blue), + color::Fg(color::Reset) + ) } fn format_success(input: &str) -> String { - format!( - "{}{input}{}", - color::Fg(color::Green), - color::Fg(color::Reset) - ) + format!( + "{}{input}{}", + color::Fg(color::Green), + color::Fg(color::Reset) + ) } fn format_variable(input: &str) -> String { - format!( - "{}{input}{}", - color::Fg(color::White), - color::Fg(color::Reset), - ) + format!( + "{}{input}{}", + color::Fg(color::White), + color::Fg(color::Reset), + ) } diff --git a/src/watch.rs b/src/watch.rs index cf1ad14..cbac4d7 100644 --- a/src/watch.rs +++ b/src/watch.rs @@ -3,61 +3,61 @@ use std::{path::Path, sync::mpsc, time::Duration}; use notify_debouncer_mini::new_debouncer; use crate::{ - tasks::{CompileTask, RunTask}, - utils::{log_failure, log_process, log_success}, + tasks::{CompileTask, RunTask}, + utils::{log_failure, log_process, log_success}, }; pub struct Repeater { - files: Vec, + files: Vec, } impl Repeater { - pub fn new(files: Vec) -> Self { - Self { files } - } + pub fn new(files: Vec) -> Self { + Self { files } + } - pub fn repeat(&self) -> Option<()> { - let binary = CompileTask::new(self.files.clone().into_iter().map(|f| f.into()).collect()) - .run() - .map(Option::from) - .unwrap_or_else(|_| { - log_failure("failed compilation"); - None - })?; + pub fn repeat(&self) -> Option<()> { + let binary = CompileTask::new(self.files.clone().into_iter().map(|f| f.into()).collect()) + .run() + .map(Option::from) + .unwrap_or_else(|_| { + log_failure("failed compilation"); + None + })?; - log_success("compilation successful"); - RunTask::new(binary) - .run() - .map(Option::from) - .unwrap_or_else(|_| { - log_failure("task failure"); - None - })?; + log_success("compilation successful"); + RunTask::new(binary) + .run() + .map(Option::from) + .unwrap_or_else(|_| { + log_failure("task failure"); + None + })?; - log_success("task successful"); - log_process("waiting for changes before re run"); - Some(()) - } + log_success("task successful"); + log_process("waiting for changes before re run"); + Some(()) + } } pub fn main(files: Vec) { - log_process(&format!("watching files '{files:?}'")); - let repeater = Repeater::new(files.clone()); - repeater.repeat(); + log_process(&format!("watching files '{files:?}'")); + let repeater = Repeater::new(files.clone()); + repeater.repeat(); - let (send, rec) = mpsc::channel(); - let mut debouncer = new_debouncer(Duration::from_millis(100), None, send).unwrap(); + let (send, rec) = mpsc::channel(); + let mut debouncer = new_debouncer(Duration::from_millis(100), None, send).unwrap(); - for file in files { - debouncer - .watcher() - .watch(Path::new(&file), notify::RecursiveMode::Recursive) - .unwrap(); - } + for file in files { + debouncer + .watcher() + .watch(Path::new(&file), notify::RecursiveMode::Recursive) + .unwrap(); + } - for events in rec { - for _ in events.unwrap() { - repeater.repeat(); - } - } + for events in rec { + for _ in events.unwrap() { + repeater.repeat(); + } + } }