continued API change
This commit is contained in:
parent
044a7ef2df
commit
11598f7f50
6 changed files with 118 additions and 118 deletions
119
src/check.rs
119
src/check.rs
|
@ -2,74 +2,89 @@ use std::fs;
|
||||||
|
|
||||||
use termion::color;
|
use termion::color;
|
||||||
|
|
||||||
use crate::{tasks::FormatTask, utils::log_failure};
|
use crate::{
|
||||||
|
tasks::FormatTask,
|
||||||
|
utils::{log_failure, log_process},
|
||||||
|
};
|
||||||
|
|
||||||
const FORMAT_CONFIG: &str = r#"{BasedOnStyle: llvm}"#;
|
const FORMAT_CONFIG: &str = r#"{BasedOnStyle: llvm}"#;
|
||||||
|
|
||||||
mod testables;
|
mod testables;
|
||||||
|
|
||||||
|
pub fn main(files: Vec<String>) {
|
||||||
|
for file in files {
|
||||||
|
log_process(&format!("checking '{file}'"));
|
||||||
|
check_formatting(file.to_string());
|
||||||
|
let content = fs::read_to_string(&file).unwrap();
|
||||||
|
for test in testables::tests() {
|
||||||
|
if let Err(reason) = test.test(content.clone()) {
|
||||||
|
let name = test.name();
|
||||||
|
log_failure(&format!("'{file}': rule '{name}' fails:"));
|
||||||
|
println!("{reason}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub enum Diff {
|
pub enum Diff {
|
||||||
ToRemove { index: usize, content: String },
|
ToRemove { index: usize, content: String },
|
||||||
ToAdd { index: usize, content: String },
|
ToAdd { index: usize, content: String },
|
||||||
Keep { index: usize, content: String },
|
Keep { index: usize, content: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main(files: Vec<String>) {
|
fn check_formatting(file: String) {
|
||||||
for file in files {
|
let content = fs::read_to_string(&file).unwrap();
|
||||||
let content = fs::read_to_string(&file).unwrap();
|
let formatted = FormatTask::new(file.clone(), FORMAT_CONFIG.into()).run();
|
||||||
let formatted = FormatTask::new(file, FORMAT_CONFIG.into()).run();
|
let mut line_number = 0usize;
|
||||||
let mut line_number = 0usize;
|
let mut invalid = false;
|
||||||
let mut invalid = false;
|
let differences = diff::lines(&content, &formatted)
|
||||||
let differences = diff::lines(&content, &formatted)
|
.into_iter()
|
||||||
.into_iter()
|
.map(|change| {
|
||||||
.map(|change| {
|
match change {
|
||||||
match change {
|
diff::Result::Left(_) | diff::Result::Both(_, _) => {
|
||||||
diff::Result::Left(_) | diff::Result::Both(_, _) => {
|
line_number += 1;
|
||||||
line_number += 1;
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
(line_number, change)
|
_ => (),
|
||||||
})
|
}
|
||||||
.map(|(index, d)| match d {
|
(line_number, change)
|
||||||
diff::Result::Left(content) => {
|
})
|
||||||
invalid = true;
|
.map(|(index, d)| match d {
|
||||||
Diff::ToRemove {
|
diff::Result::Left(content) => {
|
||||||
index,
|
invalid = true;
|
||||||
content: content.into(),
|
Diff::ToRemove {
|
||||||
}
|
|
||||||
}
|
|
||||||
diff::Result::Both(content, _) => Diff::Keep {
|
|
||||||
index,
|
index,
|
||||||
content: content.into(),
|
content: content.into(),
|
||||||
},
|
|
||||||
diff::Result::Right(content) => {
|
|
||||||
invalid = true;
|
|
||||||
Diff::ToAdd {
|
|
||||||
index,
|
|
||||||
content: content.into(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
.collect::<Vec<_>>();
|
diff::Result::Both(content, _) => Diff::Keep {
|
||||||
|
index,
|
||||||
|
content: content.into(),
|
||||||
|
},
|
||||||
|
diff::Result::Right(content) => {
|
||||||
|
invalid = true;
|
||||||
|
Diff::ToAdd {
|
||||||
|
index,
|
||||||
|
content: content.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
if invalid {
|
||||||
|
log_failure(&format!("'{file}': invalid formatting:"));
|
||||||
|
let red = color::Fg(color::Red);
|
||||||
|
let green = color::Fg(color::Green);
|
||||||
|
let reset = color::Fg(color::Reset);
|
||||||
|
|
||||||
if invalid {
|
for difference in differences {
|
||||||
log_failure("invalid formatting:");
|
match difference {
|
||||||
let red = color::Fg(color::Red);
|
Diff::ToRemove { index, content } => {
|
||||||
let green = color::Fg(color::Green);
|
println!("{red}{index:>3} -|{content}{reset}")
|
||||||
let reset = color::Fg(color::Reset);
|
}
|
||||||
|
Diff::ToAdd { index, content } => {
|
||||||
for difference in differences {
|
println!("{green}{index:>3} +|{content}{reset}")
|
||||||
match difference {
|
}
|
||||||
Diff::ToRemove { index, content } => {
|
Diff::Keep { index, content } => {
|
||||||
println!("{red} {index} - | {content}{reset}")
|
println!("{index:>3} |{content}")
|
||||||
}
|
|
||||||
Diff::ToAdd { index, content } => {
|
|
||||||
println!("{green} {index} + | {content}{reset}")
|
|
||||||
}
|
|
||||||
Diff::Keep { index, content } => {
|
|
||||||
println!(" {index} | {content}")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
use crate::utils::log_failure;
|
||||||
|
|
||||||
fn ends_with_newline(source: String) -> Result<(), String> {
|
fn ends_with_newline(source: String) -> Result<(), String> {
|
||||||
if !source.ends_with("\n") {
|
if !source.ends_with('\n') {
|
||||||
Err("source does not end with newline".into())
|
Err("source does not end with newline".into())
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
62
src/main.rs
62
src/main.rs
|
@ -30,7 +30,7 @@ pub enum Commands {
|
||||||
files: Vec<String>,
|
files: Vec<String>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Runs tests contained within a particular test file or
|
/// Runs tests contained within a particular test file or the default test file
|
||||||
test {
|
test {
|
||||||
/// Wether to capture standard output or not.
|
/// Wether to capture standard output or not.
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
|
@ -44,40 +44,18 @@ pub enum Commands {
|
||||||
tests: Vec<String>,
|
tests: Vec<String>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Watches changes to source files and re run them
|
/// Watches changes to the project included files and runs a command on changes
|
||||||
watch {
|
watch {
|
||||||
#[clap(subcommand)]
|
#[clap(short)]
|
||||||
command: WatchSubcommand,
|
files: Option<Vec<String>>,
|
||||||
|
/// command to run on changes (ex: "pi test")
|
||||||
|
command: String,
|
||||||
},
|
},
|
||||||
|
|
||||||
///
|
///
|
||||||
init { path: String },
|
init { path: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[derive(Subcommand)]
|
|
||||||
pub enum WatchSubcommand {
|
|
||||||
/// Runs a set of files or the default target.
|
|
||||||
run {
|
|
||||||
/// Files to run.
|
|
||||||
files: Vec<String>,
|
|
||||||
},
|
|
||||||
|
|
||||||
/// 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<String>,
|
|
||||||
|
|
||||||
/// Specific tests to run.
|
|
||||||
#[clap(short, long)]
|
|
||||||
tests: Vec<String>,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
fn append_includes(list: &mut Vec<String>) {
|
fn append_includes(list: &mut Vec<String>) {
|
||||||
list.extend(
|
list.extend(
|
||||||
Config::get_current()
|
Config::get_current()
|
||||||
|
@ -117,34 +95,18 @@ fn main() {
|
||||||
mut files,
|
mut files,
|
||||||
tests,
|
tests,
|
||||||
} => {
|
} => {
|
||||||
|
if files.is_empty() {
|
||||||
|
files.push(Config::get_current().test_file().to_string());
|
||||||
|
}
|
||||||
append_includes(&mut files);
|
append_includes(&mut files);
|
||||||
let args = compilation_args();
|
let args = compilation_args();
|
||||||
let tests = (!tests.is_empty()).then_some(tests);
|
let tests = (!tests.is_empty()).then_some(tests);
|
||||||
test::main(capture, files, args, tests)
|
test::main(capture, files, args, tests)
|
||||||
}
|
}
|
||||||
Commands::watch {
|
Commands::watch { command, files } => {
|
||||||
command: WatchSubcommand::run { mut files },
|
let mut files = files.unwrap_or_default();
|
||||||
} => {
|
|
||||||
append_includes(&mut files);
|
append_includes(&mut files);
|
||||||
let args = compilation_args();
|
watch::main(files, command);
|
||||||
watch::main(files.clone(), move || {
|
|
||||||
run::main(files.clone(), args.clone());
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
Commands::watch {
|
|
||||||
command: WatchSubcommand::test {
|
|
||||||
mut files,
|
|
||||||
tests,
|
|
||||||
capture,
|
|
||||||
},
|
|
||||||
} => {
|
|
||||||
append_includes(&mut files);
|
|
||||||
let args = compilation_args();
|
|
||||||
let tests = (!tests.is_empty()).then_some(tests);
|
|
||||||
watch::main(files.clone(), move || {
|
|
||||||
test::main(capture, files.clone(), args.clone(), tests.clone());
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Commands::init { path } => config::create(path),
|
Commands::init { path } => config::create(path),
|
||||||
|
|
24
src/tasks.rs
24
src/tasks.rs
|
@ -143,11 +143,31 @@ impl FormatTask {
|
||||||
command
|
command
|
||||||
.arg(self.file)
|
.arg(self.file)
|
||||||
.arg(format!("-style={config}"))
|
.arg(format!("-style={config}"))
|
||||||
.stdout(Stdio::null())
|
.stdout(Stdio::piped())
|
||||||
.stderr(Stdio::null());
|
.stderr(Stdio::piped());
|
||||||
command.status().unwrap();
|
command.status().unwrap();
|
||||||
|
|
||||||
let result = command.output().unwrap().stdout;
|
let result = command.output().unwrap().stdout;
|
||||||
String::from_utf8(result).unwrap()
|
String::from_utf8(result).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct CmdTask {
|
||||||
|
command: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CmdTask {
|
||||||
|
pub fn new(command: String) -> Self {
|
||||||
|
Self { command }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(self) -> Result<(), ()> {
|
||||||
|
Command::new("sh")
|
||||||
|
.arg("-c")
|
||||||
|
.arg(self.command)
|
||||||
|
.stdout(Stdio::inherit())
|
||||||
|
.output()
|
||||||
|
.map(|_| ())
|
||||||
|
.map_err(|_| ())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
17
src/test.rs
17
src/test.rs
|
@ -2,16 +2,11 @@ use std::{fs, thread, time::Duration};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
tasks::{CompileTask, GenTask, RunTask},
|
tasks::{CompileTask, GenTask, RunTask},
|
||||||
utils::{log_failure, log_process},
|
utils::{log_failure, log_process, log_success},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn main(_capture: bool, files: Vec<String>, args: Vec<String>, _test: Option<Vec<String>>) {
|
pub fn main(_capture: bool, files: Vec<String>, args: Vec<String>, _test: Option<Vec<String>>) {
|
||||||
// let includes = files
|
log_process("running tests");
|
||||||
// .iter()
|
|
||||||
// .cloned()
|
|
||||||
// .map(|p| PathBuf::from_str(&p).unwrap())
|
|
||||||
// .collect::<Vec<_>>();
|
|
||||||
|
|
||||||
for path in files {
|
for path in files {
|
||||||
let content = fs::read_to_string(&path).unwrap();
|
let content = fs::read_to_string(&path).unwrap();
|
||||||
let tests = find_tests(content);
|
let tests = find_tests(content);
|
||||||
|
@ -35,6 +30,7 @@ pub fn main(_capture: bool, files: Vec<String>, args: Vec<String>, _test: Option
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
log_success("finished");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_tests(source: String) -> Vec<String> {
|
pub fn find_tests(source: String) -> Vec<String> {
|
||||||
|
@ -50,8 +46,11 @@ pub fn gen_test_main(path: &str, test: &str) -> String {
|
||||||
"
|
"
|
||||||
void __pi_test();
|
void __pi_test();
|
||||||
|
|
||||||
int main(int _argc, char** _argv) {{
|
int main(int argc, char** argv) {{
|
||||||
__pi_test();
|
(void)argc;
|
||||||
|
(void)argv;
|
||||||
|
|
||||||
|
__pi_test();
|
||||||
return 0;
|
return 0;
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
|
10
src/watch.rs
10
src/watch.rs
|
@ -2,7 +2,7 @@ use std::{path::Path, sync::mpsc, time::Duration};
|
||||||
|
|
||||||
use notify_debouncer_mini::new_debouncer;
|
use notify_debouncer_mini::new_debouncer;
|
||||||
|
|
||||||
use crate::utils::log_process;
|
use crate::{tasks::CmdTask, utils::log_process};
|
||||||
|
|
||||||
pub struct Repeater {
|
pub struct Repeater {
|
||||||
op: Box<dyn Fn()>,
|
op: Box<dyn Fn()>,
|
||||||
|
@ -21,13 +21,15 @@ impl Repeater {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main(files: Vec<String>, op: impl Fn() + 'static) {
|
pub fn main(files: Vec<String>, command: String) {
|
||||||
log_process(&format!("watching files '{files:?}'"));
|
log_process(&format!("watching files '{files:?}'"));
|
||||||
let repeater = Repeater::new(op);
|
let repeater = Repeater::new(move || {
|
||||||
|
CmdTask::new(command.clone()).run().unwrap();
|
||||||
|
});
|
||||||
repeater.repeat();
|
repeater.repeat();
|
||||||
|
|
||||||
let (send, rec) = mpsc::channel();
|
let (send, rec) = mpsc::channel();
|
||||||
let mut debouncer = new_debouncer(Duration::from_millis(100), None, send).unwrap();
|
let mut debouncer = new_debouncer(Duration::from_millis(300), None, send).unwrap();
|
||||||
|
|
||||||
for file in files {
|
for file in files {
|
||||||
debouncer
|
debouncer
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue