add run command

This commit is contained in:
Sandipsinh Rathod 2024-11-17 20:06:31 -05:00
parent af46e2a811
commit a11529717c
12 changed files with 155 additions and 46 deletions

27
Cargo.lock generated

@ -163,6 +163,8 @@ version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"clap", "clap",
"strum",
"strum_macros",
"tokio", "tokio",
"tracing", "tracing",
"tracing-subscriber", "tracing-subscriber",
@ -340,6 +342,12 @@ version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
[[package]]
name = "rustversion"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248"
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
version = "1.2.0" version = "1.2.0"
@ -386,6 +394,25 @@ version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 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]] [[package]]
name = "syn" name = "syn"
version = "2.0.87" version = "2.0.87"

@ -9,3 +9,5 @@ anyhow = "1.0.93"
tokio = { version = "1.10.0", features = ["full"] } tokio = { version = "1.10.0", features = ["full"] }
tracing = "0.1.40" tracing = "0.1.40"
tracing-subscriber = "0.3.18" tracing-subscriber = "0.3.18"
strum = "0.26.3"
strum_macros = "0.26.4"

26
src/cpgen/commands.rs Normal file

@ -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<String>,
},
Gen {
#[arg(required = true)]
file_dirs: Vec<String>,
#[arg(short, long)]
language: Option<Language>,
},
Run {
file: String,
},
}

@ -1,6 +1,6 @@
use crate::lang::Language;
use std::io::Write; use std::io::Write;
use std::path::PathBuf; use std::path::PathBuf;
use crate::lang::Language;
pub struct Generator { pub struct Generator {
pub file_dirs: Vec<String>, pub file_dirs: Vec<String>,
@ -18,11 +18,11 @@ impl Generator {
for file_dir in &self.file_dirs { for file_dir in &self.file_dirs {
tracing::info!("Generating files in {}", file_dir); tracing::info!("Generating files in {}", file_dir);
let path = PathBuf::try_from(file_dir); #[allow(clippy::unnecessary_fallible_conversions)]
match path { match PathBuf::try_from(file_dir) {
Ok(file_dir) => { Ok(file_dir) => {
generate(file_dir.to_str().unwrap(), &self.language)?; generate(file_dir.to_str().unwrap(), &self.language)?;
}, }
Err(_) => { Err(_) => {
return Err(anyhow::anyhow!("Invalid path: {}", file_dir)); return Err(anyhow::anyhow!("Invalid path: {}", file_dir));
} }
@ -39,14 +39,21 @@ struct InnerGenerator {
impl InnerGenerator { impl InnerGenerator {
fn new<T: AsRef<str>, S: AsRef<str>>(files: Vec<(T, S)>) -> Self { fn new<T: AsRef<str>, S: AsRef<str>>(files: Vec<(T, S)>) -> Self {
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<()> { fn run(self, dir_path: &str) -> anyhow::Result<()> {
for (file_name, content) in self.files { for (file_name, content) in self.files {
let file_path = PathBuf::from(format!("{}/{}", dir_path, file_name)); 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)?; let mut file = std::fs::File::create(file_path)?;
file.write_all(content.as_bytes())?; file.write_all(content.as_bytes())?;
@ -56,11 +63,14 @@ impl InnerGenerator {
} }
} }
fn generate(dir_path: &str, lang: &Language) -> anyhow::Result<()> { fn generate(dir_path: &str, lang: &Language) -> anyhow::Result<()> {
let inner_gen = match lang { let inner_gen = match lang {
Language::Cpp => { 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) InnerGenerator::new(cpp_files)
} }
Language::Rust => { Language::Rust => {
@ -70,4 +80,4 @@ fn generate(dir_path: &str, lang: &Language) -> anyhow::Result<()> {
}; };
inner_gen.run(dir_path) inner_gen.run(dir_path)
} }

@ -1,5 +1,5 @@
mod run;
mod commands; mod commands;
mod gen; mod gen;
mod run;
pub use run::*; pub use run::*;

@ -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 clap::Parser;
use crate::runner::gen::Generator;
pub async fn run() -> anyhow::Result<()> { pub async fn run() -> anyhow::Result<()> {
let cli: Cli = Cli::parse(); let cli: Cli = Cli::parse();
let command = cli.command; let command = cli.command;
match command { match command {
Command::Init { .. } => todo!(), Command::Init { .. } => todo!(),
Command::Gen { file_dirs, language } => { Command::Gen {
file_dirs,
language,
} => {
let generator = Generator::new(file_dirs, language); let generator = Generator::new(file_dirs, language);
generator.generate()?; generator.generate()?;
} }
Command::Run { file } => {
let runner = Runner::new(file);
runner.run()?;
}
} }
Ok(()) Ok(())
} }

@ -1,8 +1,14 @@
use clap::ValueEnum; use clap::ValueEnum;
#[derive(ValueEnum, Default, Clone)] #[derive(ValueEnum, Default, Clone, strum_macros::EnumIter, strum_macros::Display)]
pub enum Language { pub enum Language {
#[default] #[default]
Cpp, Cpp,
Rust, Rust,
} }
impl Language {
pub fn extension(&self) -> String {
self.to_string().to_lowercase()
}
}

@ -1,3 +1,5 @@
pub mod runner; pub mod cpgen;
pub mod lang; pub mod lang;
pub mod r#static; pub mod r#static;
pub mod runner;

@ -11,7 +11,7 @@ fn init() -> anyhow::Result<()> {
.enable_all() .enable_all()
.build()?; .build()?;
rt.block_on(cpgen::runner::run()) rt.block_on(cpgen::cpgen::run())
} }
fn main() { fn main() {

54
src/runner.rs Normal file

@ -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(())
}
}

@ -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<String>,
},
Gen {
#[arg(required = true)]
file_dirs: Vec<String>,
#[arg(short, long)]
language: Option<Language>,
},
}

@ -1,10 +1,7 @@
/// CPP /// CPP
pub const MAIN_CPP: (&'static str, &'static str) = ("main.cpp", include_str!("../cpp/main.cpp")); pub const MAIN_CPP: (&str, &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 DBG_H: (&str, &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 BITS: (&str, &str) = ("bits/stdc++.h", include_str!("../cpp/bits/stdc++.h"));
pub const CPP_CMD: &'static str = r#"g++ main.cpp -o main -DLOCAL"#;
/// Rust /// Rust
pub const MAIN_RS: (&'static str, &'static str) = ("main.rs", include_str!("../rust/main.rs")); pub const MAIN_RS: (&str, &str) = ("main.rs", include_str!("../rust/main.rs"));
pub const RS_CMD: &'static str = r#"rustc main.rs --cfg 'feature="local"'"#;