From a11529717cb6897f66961b889904318e828b574c Mon Sep 17 00:00:00 2001 From: Sandipsinh Rathod Date: Sun, 17 Nov 2024 20:06:31 -0500 Subject: [PATCH] add `run` command --- Cargo.lock | 27 ++++++++++++++++++ Cargo.toml | 2 ++ src/cpgen/commands.rs | 26 +++++++++++++++++ src/{runner => cpgen}/gen.rs | 28 +++++++++++++------ src/{runner => cpgen}/mod.rs | 2 +- src/{runner => cpgen}/run.rs | 14 ++++++++-- src/lang.rs | 8 +++++- src/lib.rs | 4 ++- src/main.rs | 2 +- src/runner.rs | 54 ++++++++++++++++++++++++++++++++++++ src/runner/commands.rs | 23 --------------- src/static.rs | 11 +++----- 12 files changed, 155 insertions(+), 46 deletions(-) create mode 100644 src/cpgen/commands.rs rename src/{runner => cpgen}/gen.rs (73%) rename src/{runner => cpgen}/mod.rs (100%) rename src/{runner => cpgen}/run.rs (50%) create mode 100644 src/runner.rs delete mode 100644 src/runner/commands.rs diff --git a/Cargo.lock b/Cargo.lock index de15d74..c666441 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -163,6 +163,8 @@ version = "0.1.0" dependencies = [ "anyhow", "clap", + "strum", + "strum_macros", "tokio", "tracing", "tracing-subscriber", @@ -340,6 +342,12 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustversion" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" + [[package]] name = "scopeguard" version = "1.2.0" @@ -386,6 +394,25 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + [[package]] name = "syn" version = "2.0.87" diff --git a/Cargo.toml b/Cargo.toml index 26f4217..1d0e781 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,3 +9,5 @@ anyhow = "1.0.93" tokio = { version = "1.10.0", features = ["full"] } tracing = "0.1.40" tracing-subscriber = "0.3.18" +strum = "0.26.3" +strum_macros = "0.26.4" diff --git a/src/cpgen/commands.rs b/src/cpgen/commands.rs new file mode 100644 index 0000000..338acca --- /dev/null +++ b/src/cpgen/commands.rs @@ -0,0 +1,26 @@ +use crate::lang::Language; +use clap::{Parser, Subcommand}; + +#[derive(Parser)] +pub struct Cli { + #[command(subcommand)] + pub command: Command, +} + +#[derive(Subcommand, Clone)] +pub enum Command { + Init { + #[arg(required = true)] + contest_urls: Vec, + }, + Gen { + #[arg(required = true)] + file_dirs: Vec, + + #[arg(short, long)] + language: Option, + }, + Run { + file: String, + }, +} diff --git a/src/runner/gen.rs b/src/cpgen/gen.rs similarity index 73% rename from src/runner/gen.rs rename to src/cpgen/gen.rs index 9ed3e0a..75060ad 100644 --- a/src/runner/gen.rs +++ b/src/cpgen/gen.rs @@ -1,6 +1,6 @@ +use crate::lang::Language; use std::io::Write; use std::path::PathBuf; -use crate::lang::Language; pub struct Generator { pub file_dirs: Vec, @@ -18,11 +18,11 @@ impl Generator { for file_dir in &self.file_dirs { tracing::info!("Generating files in {}", file_dir); - let path = PathBuf::try_from(file_dir); - match path { + #[allow(clippy::unnecessary_fallible_conversions)] + match PathBuf::try_from(file_dir) { Ok(file_dir) => { generate(file_dir.to_str().unwrap(), &self.language)?; - }, + } Err(_) => { return Err(anyhow::anyhow!("Invalid path: {}", file_dir)); } @@ -39,14 +39,21 @@ struct InnerGenerator { impl InnerGenerator { fn new, S: AsRef>(files: Vec<(T, S)>) -> Self { Self { - files: files.into_iter().map(|(t, s)| (t.as_ref().to_string(), s.as_ref().to_string())).collect(), + files: files + .into_iter() + .map(|(t, s)| (t.as_ref().to_string(), s.as_ref().to_string())) + .collect(), } } fn run(self, dir_path: &str) -> anyhow::Result<()> { for (file_name, content) in self.files { let file_path = PathBuf::from(format!("{}/{}", dir_path, file_name)); - std::fs::create_dir_all(file_path.parent().ok_or(anyhow::anyhow!("Invalid parent dir"))?)?; + std::fs::create_dir_all( + file_path + .parent() + .ok_or(anyhow::anyhow!("Invalid parent dir"))?, + )?; let mut file = std::fs::File::create(file_path)?; file.write_all(content.as_bytes())?; @@ -56,11 +63,14 @@ impl InnerGenerator { } } - fn generate(dir_path: &str, lang: &Language) -> anyhow::Result<()> { let inner_gen = match lang { Language::Cpp => { - let cpp_files = vec![crate::r#static::MAIN_CPP, crate::r#static::BITS, crate::r#static::DBG_H]; + let cpp_files = vec![ + crate::r#static::MAIN_CPP, + crate::r#static::BITS, + crate::r#static::DBG_H, + ]; InnerGenerator::new(cpp_files) } Language::Rust => { @@ -70,4 +80,4 @@ fn generate(dir_path: &str, lang: &Language) -> anyhow::Result<()> { }; inner_gen.run(dir_path) -} \ No newline at end of file +} diff --git a/src/runner/mod.rs b/src/cpgen/mod.rs similarity index 100% rename from src/runner/mod.rs rename to src/cpgen/mod.rs index 6a174d5..ff12c4e 100644 --- a/src/runner/mod.rs +++ b/src/cpgen/mod.rs @@ -1,5 +1,5 @@ -mod run; mod commands; mod gen; +mod run; pub use run::*; diff --git a/src/runner/run.rs b/src/cpgen/run.rs similarity index 50% rename from src/runner/run.rs rename to src/cpgen/run.rs index 6e1b195..aabd879 100644 --- a/src/runner/run.rs +++ b/src/cpgen/run.rs @@ -1,16 +1,24 @@ -use crate::runner::commands::{Cli, Command}; +use crate::cpgen::commands::{Cli, Command}; +use crate::cpgen::gen::Generator; +use crate::runner::Runner; use clap::Parser; -use crate::runner::gen::Generator; pub async fn run() -> anyhow::Result<()> { let cli: Cli = Cli::parse(); let command = cli.command; match command { Command::Init { .. } => todo!(), - Command::Gen { file_dirs, language } => { + Command::Gen { + file_dirs, + language, + } => { let generator = Generator::new(file_dirs, language); generator.generate()?; } + Command::Run { file } => { + let runner = Runner::new(file); + runner.run()?; + } } Ok(()) } diff --git a/src/lang.rs b/src/lang.rs index 31d6191..d7009d8 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -1,8 +1,14 @@ use clap::ValueEnum; -#[derive(ValueEnum, Default, Clone)] +#[derive(ValueEnum, Default, Clone, strum_macros::EnumIter, strum_macros::Display)] pub enum Language { #[default] Cpp, Rust, } + +impl Language { + pub fn extension(&self) -> String { + self.to_string().to_lowercase() + } +} diff --git a/src/lib.rs b/src/lib.rs index 8518a2d..1b0d6a5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ -pub mod runner; +pub mod cpgen; pub mod lang; pub mod r#static; + +pub mod runner; diff --git a/src/main.rs b/src/main.rs index 8df12fa..f8987ee 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,7 @@ fn init() -> anyhow::Result<()> { .enable_all() .build()?; - rt.block_on(cpgen::runner::run()) + rt.block_on(cpgen::cpgen::run()) } fn main() { diff --git a/src/runner.rs b/src/runner.rs new file mode 100644 index 0000000..718dcd8 --- /dev/null +++ b/src/runner.rs @@ -0,0 +1,54 @@ +use crate::lang::Language; +use std::process::Command; +use strum::IntoEnumIterator; + +pub struct Runner { + file_path: String, +} + +impl Runner { + pub fn new(file: String) -> Self { + Self { file_path: file } + } + + pub fn run(self) -> anyhow::Result<()> { + let ext = self + .file_path + .split(".") + .last() + .ok_or(anyhow::anyhow!("No file extension"))? + .to_string(); + let lang: Language = Language::iter() + .find(|lang| lang.extension() == ext) + .ok_or(anyhow::anyhow!("Unsupported file extension"))?; + + let file_name = self + .file_path + .split("/") + .last() + .ok_or(anyhow::anyhow!("No file name"))?; + + match lang { + Language::Cpp => { + Command::new("g++") + .arg(file_name) + .arg("-o") + .arg("main") + .arg("-DLOCAL") + .arg(&self.file_path) + .output()?; + } + Language::Rust => { + Command::new("rustc") + .arg(file_name) + .arg("--cfg") + .arg(r#"'feature="local"'"#) + .arg("-o") + .arg("main") + .output()?; + } + }; + + Ok(()) + } +} diff --git a/src/runner/commands.rs b/src/runner/commands.rs deleted file mode 100644 index a30cf11..0000000 --- a/src/runner/commands.rs +++ /dev/null @@ -1,23 +0,0 @@ - use clap::{Parser, Subcommand}; - use crate::lang::Language; - - #[derive(Parser)] - pub struct Cli { - #[command(subcommand)] - pub command: Command, - } - - #[derive(Subcommand, Clone)] - pub enum Command { - Init { - #[arg(required = true)] - contest_urls: Vec, - }, - Gen { - #[arg(required = true)] - file_dirs: Vec, - - #[arg(short, long)] - language: Option, - }, - } diff --git a/src/static.rs b/src/static.rs index 55a9512..e95ae39 100644 --- a/src/static.rs +++ b/src/static.rs @@ -1,10 +1,7 @@ /// CPP -pub const MAIN_CPP: (&'static str, &'static str) = ("main.cpp", include_str!("../cpp/main.cpp")); -pub const DBG_H: (&'static str, &'static str) = ("debug.h", include_str!("../cpp/dbg.h")); -pub const BITS: (&'static str, &'static str) = ("bits/stdc++.h", include_str!("../cpp/bits/stdc++.h")); -pub const CPP_CMD: &'static str = r#"g++ main.cpp -o main -DLOCAL"#; - +pub const MAIN_CPP: (&str, &str) = ("main.cpp", include_str!("../cpp/main.cpp")); +pub const DBG_H: (&str, &str) = ("debug.h", include_str!("../cpp/dbg.h")); +pub const BITS: (&str, &str) = ("bits/stdc++.h", include_str!("../cpp/bits/stdc++.h")); /// Rust -pub const MAIN_RS: (&'static str, &'static str) = ("main.rs", include_str!("../rust/main.rs")); -pub const RS_CMD: &'static str = r#"rustc main.rs --cfg 'feature="local"'"#; +pub const MAIN_RS: (&str, &str) = ("main.rs", include_str!("../rust/main.rs"));