summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorsyn <isaqtm@gmail.com>2019-12-27 10:19:55 +0300
committersyn <isaqtm@gmail.com>2019-12-27 10:19:55 +0300
commit4b062197e6dd67311e7cfb2c05f28e20c6809daa (patch)
tree2961151b2b19b582e4d41b47fb832aa2838f5e6d /src
downloadevr-4b062197e6dd67311e7cfb2c05f28e20c6809daa.tar.gz
Something is done
Diffstat (limited to 'src')
-rw-r--r--src/backends/clang.rs21
-rw-r--r--src/backends/mod.rs20
-rw-r--r--src/backends/python.rs43
-rw-r--r--src/conf.rs110
-rw-r--r--src/main.rs67
5 files changed, 261 insertions, 0 deletions
diff --git a/src/backends/clang.rs b/src/backends/clang.rs
new file mode 100644
index 0000000..5a0c37f
--- /dev/null
+++ b/src/backends/clang.rs
@@ -0,0 +1,21 @@
+use serde_derive::{ Serialize, Deserialize };
+use crate::backends::Backend;
+use std::path::Path;
+
+#[derive(Debug, Serialize, Deserialize, Default)]
+pub struct ClangBackend {
+ template: Option<String>
+}
+
+impl Backend for ClangBackend {
+ fn get_template(&self) -> Option<&str> {
+ match self.template {
+ Some(ref t) => Some(t),
+ None => None
+ }
+ }
+
+ fn run(&self, _fname: &Path) -> std::io::Result<()> {
+ todo!();
+ }
+} \ No newline at end of file
diff --git a/src/backends/mod.rs b/src/backends/mod.rs
new file mode 100644
index 0000000..729daa5
--- /dev/null
+++ b/src/backends/mod.rs
@@ -0,0 +1,20 @@
+use std::path::{ Path, PathBuf };
+
+pub mod python;
+pub mod clang;
+
+pub use python::PythonBackend;
+pub use clang::ClangBackend;
+
+pub trait Backend {
+ fn get_template(&self) -> Option<&str>;
+ fn run(&self, fname: &Path) -> std::io::Result<()>;
+
+ fn try_guess_test(&self, fname: &Path) -> Option<PathBuf> {
+ let maybe_test = fname.with_extension("txt");
+ if maybe_test.exists() {
+ return Some(maybe_test);
+ }
+ None
+ }
+}
diff --git a/src/backends/python.rs b/src/backends/python.rs
new file mode 100644
index 0000000..2776eb2
--- /dev/null
+++ b/src/backends/python.rs
@@ -0,0 +1,43 @@
+use serde_derive::{ Serialize, Deserialize };
+use crate::backends::Backend;
+use std::process::{ Command, Stdio };
+use std::path::Path;
+use log::trace;
+use std::io::{ Error, ErrorKind };
+
+#[derive(Debug, Serialize, Deserialize, Default)]
+pub struct PythonBackend {
+ template: Option<String>,
+ version: Option<String>,
+}
+
+impl Backend for PythonBackend {
+ fn get_template(&self) -> Option<&str> {
+ match self.template {
+ Some(ref t) => Some(t),
+ None => None
+ }
+ }
+
+ fn run(&self, fname: &Path) -> std::io::Result<()> {
+ let interpreter = format!("python{}", self.version.as_ref().unwrap_or(&String::new()));
+ let stdio = match self.try_guess_test(fname) {
+ Some(test_file) => Stdio::from(std::fs::File::open(test_file)?),
+ None => Stdio::piped()
+ };
+ let timer = std::time::SystemTime::now();
+ let mut child = Command::new(interpreter)
+ .arg(fname.as_os_str())
+ .stdin(stdio)
+ .spawn()?;
+
+ let status = child.wait()?;
+ if !status.success() {
+ return Err(Error::new(ErrorKind::Other,
+ "Process exited with non-zero exit code"));
+ }
+ trace!("elapsed: {:#?}", timer.elapsed());
+
+ Ok(())
+ }
+} \ No newline at end of file
diff --git a/src/conf.rs b/src/conf.rs
new file mode 100644
index 0000000..eec5d86
--- /dev/null
+++ b/src/conf.rs
@@ -0,0 +1,110 @@
+use serde_derive::{Serialize, Deserialize};
+use std::path::{ PathBuf, Path };
+use toml::de;
+use log::{ error, trace };
+use std::io::prelude::*;
+
+type Error = std::io::Error;
+use std::io::ErrorKind;
+
+use crate::backends::{ Backend, PythonBackend, ClangBackend };
+
+
+#[derive(Debug, Serialize, Deserialize, Default)]
+pub struct Conf {
+ #[serde(skip)]
+ path: Option<PathBuf>,
+
+ #[serde(default)]
+ python: PythonBackend,
+
+ #[serde(default)]
+ clang: ClangBackend
+}
+
+
+impl Conf {
+ pub fn get_template(&self, fname: &Path) -> &str {
+ self.get_backend(fname)
+ .and_then(|backend| backend.get_template())
+ .unwrap_or("")
+ }
+
+ pub fn get_backend(&self, fname: &Path) -> Option<Box<&dyn Backend>> {
+ let ext = fname.extension()
+ .and_then(|ext| ext.to_str())
+ .unwrap_or("");
+
+ match ext {
+ "py" => Some(Box::new(&self.python)),
+ "cc" | "cpp" | "cxx" => Some(Box::new(&self.clang)),
+ _ => None
+ }
+ }
+
+ pub fn run(&self, fname: &Path) -> std::io::Result<()> {
+ self.get_backend(fname)
+ .and_then(|backend| Some(backend.run(fname)))
+ .unwrap_or(Err(Error::new(ErrorKind::InvalidData, "Backend not found")))
+ }
+
+ pub fn make(&self, fname: &Path) -> std::io::Result<()> {
+ trace!("Template: {:?}", self.get_template(&fname));
+
+ std::fs::File::create(fname)?
+ .write_all(self.get_template(fname).as_bytes())?;
+
+ trace!("Written some bytes to {}", fname.to_string_lossy());
+ Ok(())
+ }
+
+ #[allow(unused)]
+ pub fn get_compiler_args(&self) -> String {
+ "somedef".to_string()
+ }
+}
+
+
+
+pub fn get_conf() -> Conf {
+ match get_conf_maybe() {
+ Ok(c) => c,
+ Err(e) => {
+ match e.kind() {
+ ErrorKind::InvalidData => error!("parse: {}", e),
+ _ => error!("{}", e)
+ };
+ Default::default()
+ }
+ }
+}
+
+
+pub fn get_conf_maybe() -> Result<Conf, Error> {
+ let mut current = std::env::current_dir()?;
+ let path = loop {
+ let candidate = current.join(".evr");
+ if candidate.exists() {
+ break candidate;
+ }
+
+ if !current.pop() {
+ error!("Not a evr subtree.");
+ return Err(Error::new(ErrorKind::NotFound, "Not a evr subtree"));
+ }
+ };
+
+ let raw_buf = std::fs::read_to_string(path.as_path())?;
+
+ let buf_result: Result<Conf, de::Error> = de::from_str(&raw_buf);
+
+ match buf_result {
+ Ok(mut buf) => {
+ buf.path = Some(path.clone());
+ Ok(buf)
+ },
+ Err(err) => {
+ Err(Error::new(ErrorKind::InvalidData, err))
+ }
+ }
+}
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..af6a547
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,67 @@
+use clap::{AppSettings};
+use structopt::StructOpt;
+use env_logger;
+use log::{ trace, error };
+
+mod conf;
+mod backends;
+
+#[derive(StructOpt, Debug)]
+#[structopt(
+ name = "evr",
+ version = "0.1",
+ author = "by syn",
+ global_settings = &[
+ AppSettings::ColoredHelp,
+ AppSettings::UnifiedHelpMessage
+ ],
+)]
+struct EVROpts {
+ /// source filename
+ #[structopt(long, index = 1)]
+ src: String,
+
+ /// be quiet
+ #[structopt(short, long)]
+ quiet: bool,
+
+ /// optimize with this level
+ #[structopt(short, long)]
+ opt: Option<u8>,
+
+ /// show time (wall)
+ #[structopt(short, long)]
+ time: bool,
+
+ /// show mem usage (rss)
+ #[structopt(short, long)]
+ mem: bool
+}
+
+fn main() {
+ let opts = EVROpts::from_args();
+ if !opts.quiet {
+ env_logger::builder()
+ .format_timestamp(None)
+ .init();
+ }
+
+ trace!("{:#?}", opts);
+
+ let src_path: std::path::PathBuf = opts.src.into();
+ let config = conf::get_conf();
+
+ trace!("{:#?}", config);
+
+ let (action, result) =
+ if src_path.exists() {
+ ("run", config.run(&src_path))
+ } else {
+ ("make", config.make(&src_path))
+ };
+
+ match result {
+ Ok(_) => trace!("ok {}", action),
+ Err(err) => error!("{}", err)
+ }
+}