Compare commits

..

No commits in common. "3f6e996c64d24574f71ae45ae1ba03e1bc0c7092" and "3941e77f6ad66248035758345021af5688a0a448" have entirely different histories.

6 changed files with 43 additions and 69 deletions

View file

@ -1,15 +1,15 @@
[package] [package]
name = "oink" name = "oink"
version = "0.1.1" version = "0.0.2"
edition = "2021" 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]
#copy_dir = "0.1.3"
pico-args = "0.5.0" pico-args = "0.5.0"
termion = "2.0.1" tera = "1.19.0"
toml = "0.7.6" toml = "0.7.6"
upon = "0.7.1"
[profile.release] [profile.release]
opt-level = "s" opt-level = "s"

View file

@ -41,6 +41,6 @@ path = "/home/test/.config/oink/oink.toml"
## Libraries ## Libraries
- [pico-args](https://crates.io/crates/pico-args) — argument parsing - [pico-args](https://crates.io/crates/pico-args) — argument parsing
- [termion](https://crates.io/crates/termion) — ANSI formatting - [tera](https://crates.io/crates/tera) — template engine
- [toml](https://crates.io/crates/toml) — configuration parsing - [toml](https://crates.io/crates/toml) — configuration parsing
- [upon](https://crates.io/crates/upon) — template engine

4
rust-toolchain.toml Normal file
View file

@ -0,0 +1,4 @@
[toolchain]
channel = "nightly"

View file

@ -1,7 +1,7 @@
//! configuration struct and implementations //! configuration struct and implementations
use std::{ use std::{
collections::{ BTreeMap, HashMap }, collections::HashMap,
env::var, env::var,
fs::{ create_dir, read_to_string, File }, fs::{ create_dir, read_to_string, File },
io::Error, io::Error,
@ -9,7 +9,7 @@ use std::{
process::exit process::exit
}; };
use upon::Value as ContextValue; use tera::Context;
use toml::{ use toml::{
map::Map, map::Map,
Value Value
@ -17,8 +17,6 @@ use toml::{
use crate::error; use crate::error;
pub type Context = BTreeMap<String, ContextValue>;
/// configuration struct /// configuration struct
pub struct Config { pub struct Config {
pub dir: String, pub dir: String,
@ -63,17 +61,17 @@ impl Config {
if vars.is_some() { if vars.is_some() {
let vars = vars.unwrap().as_table().unwrap(); let vars = vars.unwrap().as_table().unwrap();
for (key, value) in vars.iter() { for (key, value) in vars.iter() {
output.insert(key.to_owned(), value.as_str().into()); output.insert(key, value.as_str().unwrap());
} }
} }
let colors = self.inner.get("colors"); let colors = self.inner.get("colors");
if colors.is_some() { if colors.is_some() {
let colors = colors.unwrap().as_table().unwrap(); let colors = colors.unwrap().as_table().unwrap();
let mut map = Context::new(); let mut map = HashMap::<&str, &str>::new();
for (key, value) in colors.iter() { for (key, value) in colors.iter() {
map.insert(key.to_owned(), value.as_str().unwrap().into()); map.insert(key, value.as_str().unwrap());
} }
output.insert("colors".to_owned(), map.into()); output.insert("colors", &map);
} }
output output

View file

@ -1,11 +1,12 @@
#![feature(error_in_core)]
use std::process::exit; use std::process::exit;
use pico_args::Arguments; use pico_args::Arguments;
use tera::Tera;
mod config; mod config;
mod error; mod error;
mod operation; mod operation;
use crate::config::Config; use crate::config::Config;
fn main() { fn main() {
@ -19,8 +20,10 @@ fn main() {
// init configuration // init configuration
let config = Config::new(); let config = Config::new();
// build template dir // tera init
let template_dir = format!("{}/templates/", &(config.dir)); let context = config.context();
let template_dir = format!("{}/templates/*", &(config.dir));
let mut tera = Tera::new(&template_dir).unwrap();
let targets = config.targets(); let targets = config.targets();
if targets.len() == 0 { error::no_targets(); } if targets.len() == 0 { error::no_targets(); }
@ -32,11 +35,11 @@ fn main() {
}, },
Some("build") Some("build")
=> { => {
operation::build(&targets, template_dir, &config); operation::build(&targets, &mut tera, &context);
}, },
Some("full") Some("full")
=> { => {
operation::build(&targets, template_dir, &config); operation::build(&targets, &mut tera, &context);
operation::apply(&targets); operation::apply(&targets);
}, },
_ _

View file

@ -1,27 +1,14 @@
//! higher-level operation functions //! higher-level operation functions
use std::{ use std::{
env::var, env::var,
fs::{self, read_to_string, File }, fs::{ self, File },
io::Write, io::Write,
path::{ Path, PathBuf } path::Path
}; };
use core::error::Error;
use termion::{
color::{ self, Fg },
style::{
Bold as BOLD,
Italic as ITALIC,
Reset as RESET
}
};
use toml::{ map::Map, Value }; use toml::{ map::Map, Value };
use upon::Engine; use tera::{ Context, Tera };
use crate::config::Config;
static SUCCESS: Fg<color::Green> = Fg(color::Green);
static WARNING: Fg<color::Yellow> = Fg(color::Yellow);
static FAILURE: Fg<color::Red> = Fg(color::Red);
pub fn apply(targets: &Vec<Map<String, Value>>) { pub fn apply(targets: &Vec<Map<String, Value>>) {
let home = var("HOME").unwrap(); let home = var("HOME").unwrap();
@ -35,12 +22,12 @@ pub fn apply(targets: &Vec<Map<String, Value>>) {
if path.is_none() { if path.is_none() {
if i_name.is_some() { if i_name.is_some() {
let name = i_name.unwrap().as_str().unwrap(); let name = i_name.unwrap().as_str().unwrap();
println!(" {WARNING}\"{name}\" is missing its path property; skipping{RESET}"); println!(" \"{name}\" is missing its path property; skipping");
} else { println!(" {WARNING}skipping empty target{RESET}"); } } else { println!(" skipping empty target"); }
continue; continue;
} }
if i_name.is_none() { if i_name.is_none() {
println!(" {WARNING}target missing name; skipping{RESET}"); println!(" target missing name; skipping");
continue; continue;
} }
@ -55,28 +42,20 @@ pub fn apply(targets: &Vec<Map<String, Value>>) {
// copy and print // copy and print
let result = fs::copy(source, destination); let result = fs::copy(source, destination);
if result.is_err() { if result.is_err() { println!(" failed to copy!"); }
println!(" {BOLD}{FAILURE}failed to copy{RESET}"); else { println!(" completed successfully"); }
}
else {
println!(" {BOLD}{SUCCESS}completed{RESET}");
}
} }
} }
pub fn build(targets: &Vec<Map<String, Value>>, template_dir: String, config: &Config) { pub fn build(targets: &Vec<Map<String, Value>>, tera: &mut Tera, context: &Context) {
let home = var("HOME").unwrap(); let home = var("HOME").unwrap();
println!("running build:"); println!("running build:");
let engine = Engine::new();
let context = config.context();
for target in targets { for target in targets {
// get name property // get name property
let i_name = target.get("name"); let i_name = target.get("name");
// handle empty names gracefully // handle empty names gracefully
if i_name.is_none() { if i_name.is_none() {
println!(" {WARNING}target missing name; skipping{RESET}"); println!(" target missing name; skipping");
continue; continue;
} }
@ -84,24 +63,14 @@ pub fn build(targets: &Vec<Map<String, Value>>, template_dir: String, config: &C
let name = i_name.unwrap().as_str().unwrap(); let name = i_name.unwrap().as_str().unwrap();
println!(" building \"{name}\":"); println!(" building \"{name}\":");
// compile // render template
println!(" {ITALIC}compiling{RESET}"); let render = tera.render(name, context);
let mut path = PathBuf::from(&template_dir); // handle rendering errors gracefully
path.push(name);
let content = read_to_string(path).unwrap();
let template = engine.compile(&content);
if template.is_err() {
let error = template.err().unwrap();
println!(" {BOLD}{FAILURE}failed to compile template:{RESET}\n {FAILURE}{error}\n {BOLD}skipping{RESET}");
continue;
}
// render
println!(" {ITALIC}rendering{RESET}");
let render = template.unwrap().render(&context).to_string();
if render.is_err() { if render.is_err() {
let error = render.err().unwrap(); let error = render.err().unwrap();
println!(" {BOLD}{FAILURE}failed to render template:{RESET}\n {FAILURE}{error}\n {BOLD}skipping{RESET}"); let message = error.source().unwrap();
println!(" failed to render template:\n {message}");
continue; continue;
} }
@ -111,14 +80,14 @@ pub fn build(targets: &Vec<Map<String, Value>>, template_dir: String, config: &C
let path = Path::new(&destination); let path = Path::new(&destination);
let i_file = File::create(path); let i_file = File::create(path);
if i_file.is_err() { if i_file.is_err() {
println!(" {BOLD}{FAILURE}failed to create destination file at {path:?}{RESET}"); println!(" failed to create destination file at {path:?}");
continue; continue;
} }
let mut file = i_file.unwrap(); let mut file = i_file.unwrap();
// write to destination file // write to destination file
let written = write!(&mut file, "{output}"); let written = write!(&mut file, "{output}");
if written.is_err() { println!(" {FAILURE}failed to write to destination file at {path:?}{RESET}"); } if written.is_err() { println!(" failed to write to destination file at {path:?}"); }
else { println!(" {BOLD}{SUCCESS}completed{RESET}"); } else { println!(" completed successfully"); }
} }
} }