✨ file literal.
parent
586676b519
commit
8420c7cce5
|
@ -2,6 +2,53 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "1.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "alchimake"
|
name = "alchimake"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"regex",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.10.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-automata",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||||
|
|
|
@ -6,3 +6,4 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
regex = "1.10.3"
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use crate::cli::parse;
|
||||||
|
use crate::core::conf::Conf;
|
||||||
|
|
||||||
|
pub struct App {
|
||||||
|
conf: Conf
|
||||||
|
}
|
||||||
|
|
||||||
|
impl App {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
conf: Conf::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(&mut self) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let mut args = parse::Args::new();
|
||||||
|
let sys_args: Vec<String> = std::env::args().collect();
|
||||||
|
|
||||||
|
args.register(&vec!["-h", "--help"])
|
||||||
|
.description("show this help")
|
||||||
|
.callback(Box::new(|_, ctx| {
|
||||||
|
println!("{}", ctx.help);
|
||||||
|
std::process::exit(0);
|
||||||
|
}));
|
||||||
|
|
||||||
|
args.register(&vec!["-v", "--version"])
|
||||||
|
.description("show alchimake version")
|
||||||
|
.callback(Box::new(|_, _| {
|
||||||
|
println!("Alchimake v0.0.0");
|
||||||
|
println!("Copyright (C) 2024 bog");
|
||||||
|
println!("Licensed under the GPLv3+ (see LICENSE)");
|
||||||
|
std::process::exit(0);
|
||||||
|
}));
|
||||||
|
|
||||||
|
args.register(&vec!["-s", "--source"])
|
||||||
|
.description("set the source directory")
|
||||||
|
.callback(Box::new(|value, _| {
|
||||||
|
if let Some(val) = value {
|
||||||
|
self.conf.src_dir = PathBuf::from(val);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
args.register(&vec!["-b", "--build"])
|
||||||
|
.description("set the build directory")
|
||||||
|
.callback(Box::new(|value, _| {
|
||||||
|
if let Some(val) = value {
|
||||||
|
self.conf.build_dir = PathBuf::from(val);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
args.parse(&sys_args.iter().map(|v| v.as_str()).collect())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start(&mut self) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,19 +23,19 @@ pub struct Context {
|
||||||
pub help: String
|
pub help: String
|
||||||
}
|
}
|
||||||
|
|
||||||
type Callback = Box<dyn Fn(Option<String>, Context)>;
|
type Callback<'a> = Box<dyn FnMut(Option<String>, Context) + 'a>;
|
||||||
|
|
||||||
pub struct Arg {
|
pub struct Arg<'a> {
|
||||||
pub flags: Vec<String>,
|
pub flags: Vec<String>,
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
pub callback: Option<Callback>
|
pub callback: Option<Callback<'a>>
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Args {
|
pub struct Args<'a> {
|
||||||
args: Vec<Arg>,
|
args: Vec<Arg<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Args {
|
impl<'a> Args<'a> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
args: vec![]
|
args: vec![]
|
||||||
|
@ -45,6 +45,7 @@ impl Args {
|
||||||
pub fn help(&self) -> String {
|
pub fn help(&self) -> String {
|
||||||
let mut res = String::from("Usage: alchimake [OPTION]...\n");
|
let mut res = String::from("Usage: alchimake [OPTION]...\n");
|
||||||
res += "OPTIONS:\n";
|
res += "OPTIONS:\n";
|
||||||
|
|
||||||
for arg in self.args.iter() {
|
for arg in self.args.iter() {
|
||||||
if let Some(description) = &arg.description {
|
if let Some(description) = &arg.description {
|
||||||
res += format!(
|
res += format!(
|
||||||
|
@ -67,7 +68,7 @@ impl Args {
|
||||||
for arg in self.args.iter_mut() {
|
for arg in self.args.iter_mut() {
|
||||||
for flag in arg.flags.iter() {
|
for flag in arg.flags.iter() {
|
||||||
if &flag == cli_arg {
|
if &flag == cli_arg {
|
||||||
if let Some(ref callback) = arg.callback {
|
if let Some(ref mut callback) = arg.callback {
|
||||||
let value = getval(&args, &flag)?;
|
let value = getval(&args, &flag)?;
|
||||||
callback(value.clone(), Context {
|
callback(value.clone(), Context {
|
||||||
help: help.clone()
|
help: help.clone()
|
||||||
|
@ -99,9 +100,16 @@ impl Args {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn callback(&mut self,
|
pub fn callback(&mut self,
|
||||||
callback: Callback) -> &mut Self{
|
callback: Callback<'a>) -> &mut Self{
|
||||||
let idx = self.args.len() - 1;
|
let idx = self.args.len() - 1;
|
||||||
self.args[idx].callback = Some(Box::new(callback));
|
self.args[idx].callback = Some(Box::new(callback));
|
||||||
|
self.args.sort_by_cached_key(|a| {
|
||||||
|
if let Some(val) = a.flags.get(0) {
|
||||||
|
val.clone()
|
||||||
|
} else {
|
||||||
|
String::from("")
|
||||||
|
}
|
||||||
|
});
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Conf {
|
||||||
|
pub src_dir: PathBuf,
|
||||||
|
pub build_dir: PathBuf
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Conf {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
src_dir: PathBuf::from("."),
|
||||||
|
build_dir: PathBuf::from(".")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,27 +1,54 @@
|
||||||
|
use regex::Regex;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use crate::core::{
|
use crate::core::{
|
||||||
value::Value,
|
value::Value,
|
||||||
expr::Expr,
|
expr::Expr,
|
||||||
sym::Sym,
|
sym::Sym,
|
||||||
cmd::Command
|
cmd::Command,
|
||||||
|
conf::Conf
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Evaluator {
|
pub struct Evaluator {
|
||||||
sym: Sym,
|
sym: Sym,
|
||||||
commands: HashMap<String, Box<dyn Command>>
|
commands: HashMap<String, Box<dyn Command>>,
|
||||||
|
conf: Conf
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluator {
|
impl Evaluator {
|
||||||
pub fn new(sym: Sym) -> Self {
|
pub fn new(sym: Sym, conf: Conf) -> Self {
|
||||||
Self {
|
Self {
|
||||||
sym,
|
sym,
|
||||||
commands: HashMap::new()
|
commands: HashMap::new(),
|
||||||
|
conf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&mut self, expr: &Expr) -> Result<Value, Box<dyn Error>> {
|
pub fn run(&mut self, expr: &Expr) -> Result<Value, Box<dyn Error>> {
|
||||||
match expr {
|
match expr {
|
||||||
|
Expr::File(rel_path) => {
|
||||||
|
fn replace_path(dir: &std::path::Path, prefix: &str, rel_path: &str)
|
||||||
|
-> Result<Value, Box<dyn Error>> {
|
||||||
|
let re = Regex::new(&format!("{}://([^)]*)", prefix)).unwrap();
|
||||||
|
if let Some(path) = re.captures(rel_path) {
|
||||||
|
Ok(Value::String(
|
||||||
|
dir.join(
|
||||||
|
path[1].to_string()
|
||||||
|
).to_str().unwrap().to_string(),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Err(String::from("wrong path").into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok(res) = replace_path(&self.conf.src_dir, "src", rel_path) {
|
||||||
|
Ok(res)
|
||||||
|
} else if let Ok(res) = replace_path(&self.conf.build_dir, "build", rel_path) {
|
||||||
|
Ok(res)
|
||||||
|
} else {
|
||||||
|
Err(format!("wrong path {}", rel_path).into())
|
||||||
|
}
|
||||||
|
},
|
||||||
Expr::BuiltIn(value) => Ok(value.clone()),
|
Expr::BuiltIn(value) => Ok(value.clone()),
|
||||||
Expr::Ident(value) => {
|
Expr::Ident(value) => {
|
||||||
if let Some(val) = self.sym.get(value) {
|
if let Some(val) = self.sym.get(value) {
|
||||||
|
@ -89,14 +116,9 @@ impl Evaluator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub struct Evaluator {
|
|
||||||
// sym: Sym,
|
|
||||||
// commands: HashMap<String, Box<dyn Command>>
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
impl Clone for Evaluator {
|
impl Clone for Evaluator {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
let mut c = Evaluator::new(self.sym.clone());
|
let mut c = Evaluator::new(self.sym.clone(), self.conf.clone());
|
||||||
for cmd in self.commands.iter() {
|
for cmd in self.commands.iter() {
|
||||||
c.commands.insert(cmd.0.to_string(), cmd.1.clone_box());
|
c.commands.insert(cmd.0.to_string(), cmd.1.clone_box());
|
||||||
}
|
}
|
||||||
|
@ -112,7 +134,11 @@ mod test {
|
||||||
-> TestResult
|
-> TestResult
|
||||||
where U: Fn(&mut Evaluator) {
|
where U: Fn(&mut Evaluator) {
|
||||||
let sym = Sym::new();
|
let sym = Sym::new();
|
||||||
let mut eval = Evaluator::new(sym);
|
let mut conf = Conf::new();
|
||||||
|
conf.src_dir = std::path::PathBuf::from("/root/source");
|
||||||
|
conf.build_dir = std::path::PathBuf::from("/root/build");
|
||||||
|
|
||||||
|
let mut eval = Evaluator::new(sym, conf);
|
||||||
init(&mut eval);
|
init(&mut eval);
|
||||||
let res = eval.run(&expr)?;
|
let res = eval.run(&expr)?;
|
||||||
|
|
||||||
|
@ -204,4 +230,39 @@ where U: Fn(&mut Evaluator) {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn files() -> TestResult {
|
||||||
|
test_eval(
|
||||||
|
Expr::File(String::from("build://")),
|
||||||
|
Value::String(String::from("/root/build/"))
|
||||||
|
)?;
|
||||||
|
|
||||||
|
test_eval(
|
||||||
|
Expr::File(String::from("build://hello/world.txt")),
|
||||||
|
Value::String(String::from("/root/build/hello/world.txt"))
|
||||||
|
)?;
|
||||||
|
|
||||||
|
test_eval(
|
||||||
|
Expr::File(String::from("build://../parent")),
|
||||||
|
Value::String(String::from("/root/build/../parent"))
|
||||||
|
)?;
|
||||||
|
|
||||||
|
test_eval(
|
||||||
|
Expr::File(String::from("src://")),
|
||||||
|
Value::String(String::from("/root/source/"))
|
||||||
|
)?;
|
||||||
|
|
||||||
|
test_eval(
|
||||||
|
Expr::File(String::from("src://hello/world.txt")),
|
||||||
|
Value::String(String::from("/root/source/hello/world.txt"))
|
||||||
|
)?;
|
||||||
|
|
||||||
|
test_eval(
|
||||||
|
Expr::File(String::from("src://../parent")),
|
||||||
|
Value::String(String::from("/root/source/../parent"))
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,8 @@ use crate::core::{
|
||||||
value::Value,
|
value::Value,
|
||||||
eval::Evaluator,
|
eval::Evaluator,
|
||||||
sym::Sym,
|
sym::Sym,
|
||||||
cmd::Command
|
cmd::Command,
|
||||||
|
conf::Conf
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -186,7 +187,7 @@ mod test {
|
||||||
-> TestResult
|
-> TestResult
|
||||||
where T: Fn(&mut Executor) {
|
where T: Fn(&mut Executor) {
|
||||||
let sym = Sym::new();
|
let sym = Sym::new();
|
||||||
let eval = Evaluator::new(sym);
|
let eval = Evaluator::new(sym, Conf::new());
|
||||||
let mut exec = Executor::new(eval);
|
let mut exec = Executor::new(eval);
|
||||||
|
|
||||||
init(&mut exec);
|
init(&mut exec);
|
||||||
|
|
|
@ -6,5 +6,6 @@ use crate::core::value::Value;
|
||||||
pub enum Expr {
|
pub enum Expr {
|
||||||
BuiltIn(Value),
|
BuiltIn(Value),
|
||||||
Ident(String),
|
Ident(String),
|
||||||
Call(String, Vec<Expr>)
|
Call(String, Vec<Expr>),
|
||||||
|
File(String)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,3 +5,4 @@ pub mod eval;
|
||||||
pub mod sym;
|
pub mod sym;
|
||||||
pub mod cmd;
|
pub mod cmd;
|
||||||
pub mod exec;
|
pub mod exec;
|
||||||
|
pub mod conf;
|
||||||
|
|
27
src/main.rs
27
src/main.rs
|
@ -1,29 +1,12 @@
|
||||||
mod cli;
|
mod cli;
|
||||||
mod core;
|
mod core;
|
||||||
|
mod app;
|
||||||
|
|
||||||
use crate::cli::parse;
|
use crate::cli::parse;
|
||||||
|
use crate::app::App;
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut args = parse::Args::new();
|
let mut app = App::new();
|
||||||
let sys_args: Vec<String> = std::env::args().collect();
|
app.init()?;
|
||||||
|
app.start()
|
||||||
args.register(&vec!["-h", "--help"])
|
|
||||||
.description("show this help")
|
|
||||||
.callback(Box::new(|_, ctx| {
|
|
||||||
println!("{}", ctx.help);
|
|
||||||
std::process::exit(0);
|
|
||||||
}));
|
|
||||||
|
|
||||||
args.register(&vec!["-v", "--version"])
|
|
||||||
.description("show alchimake version")
|
|
||||||
.callback(Box::new(|_, _| {
|
|
||||||
println!("Alchimake v0.0.0");
|
|
||||||
println!("Copyright (C) 2024 bog");
|
|
||||||
println!("Licensed under the GPLv3+ (see LICENSE)");
|
|
||||||
std::process::exit(0);
|
|
||||||
}));
|
|
||||||
|
|
||||||
args.parse(&sys_args.iter().map(|v| v.as_str()).collect())?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue