diff --git a/Cargo.lock b/Cargo.lock index d3a1b8c..a646b96 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -96,12 +96,40 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + [[package]] name = "heck" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + [[package]] name = "proc-macro2" version = "1.0.76" @@ -120,6 +148,45 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "ryu" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" + +[[package]] +name = "serde" +version = "1.0.195" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.195" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_yaml" +version = "0.9.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1bf28c79a99f70ee1f1d83d10c875d2e70618417fda01ad1785e027579d9d38" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "strsim" version = "0.10.0" @@ -142,6 +209,8 @@ name = "tester" version = "0.1.0" dependencies = [ "clap", + "serde", + "serde_yaml", ] [[package]] @@ -150,6 +219,12 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unsafe-libyaml" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" + [[package]] name = "utf8parse" version = "0.2.1" diff --git a/Cargo.toml b/Cargo.toml index 2a8cbec..b78d78d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,3 +7,5 @@ edition = "2021" [dependencies] clap = { version = "4.4.16", features = ["derive"] } +serde = { version = "1.0.195", features = ["derive"] } +serde_yaml = "0.9.30" diff --git a/README.md b/README.md new file mode 100644 index 0000000..680488e --- /dev/null +++ b/README.md @@ -0,0 +1,70 @@ +# Tester CMPUT 415 (rust version) + +This is a (mostly) drop-in replacement for the previous tester written for CMPUT 415. + +Most of the options are specified in the [config file](#configuration-file), so the cli is minimal. We do specify some options: +``` rust +Usage: tester [OPTIONS] --config-file + +Commands: + validate Validate test matching and config file correctness + run Run all tests + grade Grade with grading config + help Print this message or the help of the given subcommand(s) + +Options: + -v, --verbosity... Sets the verbosity of the tester + -c, --config-file Set the config file + -g, --grading-conf Set the grading config file + -h, --help Print help + -V, --version Print version + +``` + +the verbosity defines the level of logging, you can play around with it (specify `-v[v]+` for more verbose logging). + +## Configuration File + +The configuration file is specified in [YAML](https://yaml.org/spec/1.2.2/), so go check it out. Below is a fully featured config file, with more to come: + +``` yaml +input_path: "/path/to/dir" +output_path: "/path/to/out/dir" +in_stream_path: "/path/to/in/stream" + +tested_executables: + - name: "team1" + executable: "/path/to/exec" + - name: "team2" + executable: "/path/to/exec2" + +runtimes: + - name: "team1" + executable: "/path/to/exec" + - name: "team1" + executable: "/path/to/exec" + +toolchains: + - name: "toolchain1" + steps: + - name: "step1" + executable_path: "$EXE" + arguments: + - $INPUT + - $OUTPUT + output: "out.test" + - name: "step2" + executable_path: "/bin/bash" + arguments: + - echo "Hello World" + output: "-" + - name: "toolchain2" + steps: + - name: "step1" + executable_path: "/bin/bash" + arguments: + - echo "Hello toolchain 2!" + output: "-" +``` + +You can refer to the [original tester](https://github.com/cmput415/Tester) documentation to see some more options (#TODO will be pasting that here) diff --git a/src/grade.rs b/src/grade.rs index fd55e01..c8c7f39 100644 --- a/src/grade.rs +++ b/src/grade.rs @@ -1,5 +1,7 @@ -use std::path::{Path, PathBuf}; +use std::path::Path; -pub fn grade(verbosity: u8, config_file: PathBuf, grade_config: Option<&Path>) { +use crate::util; + +pub fn grade(verbosity: u8, config: util::config::Config, grade_config: Option<&Path>) { println!("Grading!"); } diff --git a/src/main.rs b/src/main.rs index ffe15dd..8ec0d7b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,7 @@ use clap::{Parser, Subcommand}; mod validate; mod run; mod grade; +pub mod util; fn main() { // get cli args @@ -12,11 +13,15 @@ fn main() { // parse the verbosity and eliminate the Option<> let verbosity = get_verbosity(cli.verbosity); + let config = util::config::parse_config(cli.config_file); + + //parse the config file + // let config = parse_config(cli.config_file); match &cli.command { - Command::Validate => validate::validate(verbosity, cli.config_file), - Command::Run => run::run(verbosity, cli.config_file), - Command::Grade => grade::grade(verbosity, cli.config_file, cli.grading_conf.as_deref()), + Command::Validate => validate::validate(verbosity, config), + Command::Run => run::run(verbosity, config), + Command::Grade => grade::grade(verbosity, config, cli.grading_conf.as_deref()), } } @@ -28,6 +33,8 @@ struct Cli { #[arg(short, long, action = clap::ArgAction::Count)] verbosity: Option, + //TODO implement a thread count variable for the runner + /// Set the config file #[arg(short, long, value_name = "CONFIG")] config_file: PathBuf, diff --git a/src/run.rs b/src/run.rs index 1dcb660..a2d7891 100644 --- a/src/run.rs +++ b/src/run.rs @@ -1,5 +1,10 @@ -use std::path::PathBuf; +use crate::util; -pub fn run(verbosity: u8, config_file: PathBuf) { +pub fn run(verbosity: u8, config: util::config::Config) { println!("Running!"); } + +#[cfg(test)] +mod tests { + +} diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000..ef68c36 --- /dev/null +++ b/src/util.rs @@ -0,0 +1 @@ +pub mod config; diff --git a/src/util/config.rs b/src/util/config.rs new file mode 100644 index 0000000..1aa5457 --- /dev/null +++ b/src/util/config.rs @@ -0,0 +1,84 @@ +use std::path::PathBuf; + +use serde::Deserialize; +use serde_yaml::{self}; + +#[derive(Debug, Deserialize)] +pub struct Config { + tested_executables: Vec, + + input_path: PathBuf, + output_path: PathBuf, + in_stream_path: PathBuf, + + runtimes: Option>, + + toolchains: Vec, +} + +#[derive(Debug, Deserialize)] +pub struct Team { + name: String, + executable: PathBuf, +} + +#[derive(Debug, Deserialize)] +pub struct Toolchain { + name: String, + steps: Vec,} + +#[derive(Debug, Deserialize)] +pub struct Step { + name: String, + + executable_path: Option, // if None then we use the current executable path + arguments: Vec, // special string $INPUT corresponds to previous step output + output: String, // the output file name + + uses_runtime: Option, + uses_in_stream: Option, + allow_error: Option +} + +pub fn parse_config(path: PathBuf) -> Config { + // load the yaml from the system path, if it fails, tell the user and exit + let yaml_load = std::fs::File::open(path); + let yaml_file = match yaml_load { + Ok(file) => file, + Err(error) => panic!("Failed to load configuration file 🤮, error thrown: {:?}", error), + }; + + let config: Config = match serde_yaml::from_reader(yaml_file) { + Ok(conf) => conf, + Err(error) => panic!("Failed to parse YAML file 😕, error: {}", error), + }; + + return config; +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[should_panic] + fn test_nonexistant_config() { + let path: PathBuf = PathBuf::from("src/util/test/parse_config/non_existant.yaml"); + parse_config(path); + } + + #[test] + fn test_load_config() { + let path: PathBuf = PathBuf::from("src/util/test/parse_config/config.yaml"); + let config = parse_config(path); + println!("{:?}", config); + } + + #[test] + #[should_panic] + fn test_load_bad_config() { + let path: PathBuf = PathBuf::from("src/util/test/parse_config/bad_config.yaml"); + let config = parse_config(path); + println!("{:?}", config); + } +} diff --git a/src/util/test/parse_config/bad_config.yaml b/src/util/test/parse_config/bad_config.yaml new file mode 100644 index 0000000..6436c18 --- /dev/null +++ b/src/util/test/parse_config/bad_config.yaml @@ -0,0 +1,37 @@ + +input_path: "/path/to/dir" +in_stream_path: "/path/to/in/stream" + +tested_executables: + - name: "team1" + executable: "/path/to/exec" + - name: "team2" + executable: "/path/to/exec2" + +runtimes: + - name: "team1" + executable: "/path/to/exec" + - name: "team1" + executable: "/path/to/exec" + +toolchains: + - name: "toolchain1" + steps: + - name: "step1" + executable_path: "$EXE" + arguments: + - $INPUT + - $OUTPUT + output: "out.test" + - name: "step2" + executable_path: "/bin/bash" + arguments: + - echo "Hello World" + output: "-" + - name: "toolchain2" + steps: + - name: "step1" + executable_path: "/bin/bash" + arguments: + - echo "Hello toolchain 2!" + output: "-" diff --git a/src/util/test/parse_config/config.yaml b/src/util/test/parse_config/config.yaml new file mode 100644 index 0000000..e166161 --- /dev/null +++ b/src/util/test/parse_config/config.yaml @@ -0,0 +1,37 @@ +input_path: "/path/to/dir" +output_path: "/path/to/out/dir" +in_stream_path: "/path/to/in/stream" + +tested_executables: + - name: "team1" + executable: "/path/to/exec" + - name: "team2" + executable: "/path/to/exec2" + +runtimes: + - name: "team1" + executable: "/path/to/exec" + - name: "team1" + executable: "/path/to/exec" + +toolchains: + - name: "toolchain1" + steps: + - name: "step1" + executable_path: "$EXE" + arguments: + - $INPUT + - $OUTPUT + output: "out.test" + - name: "step2" + executable_path: "/bin/bash" + arguments: + - echo "Hello World" + output: "-" + - name: "toolchain2" + steps: + - name: "step1" + executable_path: "/bin/bash" + arguments: + - echo "Hello toolchain 2!" + output: "-" diff --git a/src/util/test/parse_config/file1.txt b/src/util/test/parse_config/file1.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/util/test/parse_config/file10.txt b/src/util/test/parse_config/file10.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/util/test/parse_config/file2.txt b/src/util/test/parse_config/file2.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/util/test/parse_config/file3.txt b/src/util/test/parse_config/file3.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/util/test/parse_config/file4.txt b/src/util/test/parse_config/file4.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/util/test/parse_config/file5.txt b/src/util/test/parse_config/file5.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/util/test/parse_config/file6.txt b/src/util/test/parse_config/file6.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/util/test/parse_config/file7.txt b/src/util/test/parse_config/file7.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/util/test/parse_config/file8.txt b/src/util/test/parse_config/file8.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/util/test/parse_config/file9.txt b/src/util/test/parse_config/file9.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/validate.rs b/src/validate.rs index 2bb60d6..fb88886 100644 --- a/src/validate.rs +++ b/src/validate.rs @@ -1,5 +1,11 @@ -use std::path::PathBuf; +use crate::util; -pub fn validate(verbosity: u8, config_file: PathBuf) { +pub fn validate(verbosity: u8, config: util::config::Config) { println!("Validating"); } + + +#[cfg(test)] +mod tests { + +}