~skye/git/src/lib.rs
view raw
use clap::Parser;
use lazy_static::lazy_static;
use toml::Table;
use std::fs;
pub mod act;
pub mod com;
pub mod db;
/** rexport for all the macros */
pub mod macros {
pub use crate::{
dbg_elog, dbg_log, dbg_log_fmt, elog, encode_fmt, eputs, err_fmt,
err_fmt_html, err_fmt_into, fatal, fmt, log, log_efmt, log_fmt,
log_fmt_, mkrepopath, ok_fmt, page_fmt, safe_assert_eq, str_fmt,
str_from,
};
}
#[derive(Parser, Debug, Clone)]
#[command(version, about, long_about = None)]
pub struct Args {
/* config file path */
#[arg(short, long)]
pub cfg: String,
}
/** assert_eq but just print the message, don't actually panic */
#[macro_export]
macro_rules! safe_assert_eq {
($x:expr, $y:expr) => {{
if $x == $y {
()
} else {
elog!(
"{}: left: {:?}, right: {:?}",
"assert eq failed".red(),
$x,
$y
);
}
}};
}
/** format! is too long for my k brain rot */
#[macro_export]
macro_rules! fmt {
($($t:tt)*) => {{
format!($($t)*)
}};
}
/** format a page */
#[macro_export]
macro_rules! page_fmt {
{ ($($t:tt)*), ($($b:tt)*) } => {{
Html(format!(
r#"
<!DOCTYPE html>
<html>
<head>
<title>{title} :: {t}</title>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="/style.css">
</head>
<body>
<div id="head">
<b><a href="/">{title}</a></b>
</div>
<div id="page">
{b}
</div>
<div id="foot">
{version}
</div>
</body>
</html>
"#,
title = match CFG["title"].as_str() {
Some(x) => x,
None => "badboy git",
},
version = crate::com::cfg::VERSION,
t = format!($($t)*),
b = format!($($b)*)
))
}};
}
/** shorhand for Err(format!) */
#[macro_export]
macro_rules! err_fmt {
($($t:tt)*) => {{
Err(format!($($t)*))
}};
}
/** shorthand for Err(format!.into()) */
#[macro_export]
macro_rules! err_fmt_into {
($($t:tt)*) => {{
Err(format!($($t)*).into())
}};
}
/** shorthand for Err(page_fmt!) */
#[macro_export]
macro_rules! err_fmt_html {
[$g:expr, $($t:tt)*] => {{
Err(page_fmt! {
($($t)*),
(
r#"
<h1>error</h1>
<p>{}</p>
<p><a href="{}">go back<a></p>
"#,
format!($($t)*),
$g
)
})
}};
($($t:tt)*) => {{
Err(page_fmt! {
($($t)*),
(
"<h1>error</h1>
<p>{}</p>",
format!($($t)*)
)
})
}};
}
/** shorthand for Ok(format!()) */
#[macro_export]
macro_rules! ok_fmt {
($($t:tt)*) => {{
Ok(format!($($t)*))
}};
}
/** macro to format a fatal error.
* basically a shorthand for panic(format!()) */
#[macro_export]
macro_rules! fatal {
($($t:tt)*) => {{
use colored::Colorize;
eputs!("{}: ", "fatal".red());
elog!($($t)*);
std::process::exit(-1);
}};
}
/** $p: prefix */
#[macro_export]
macro_rules! log_fmt_ {
($p:expr, $($t:tt)*) => {{
use colored::Colorize;
format!(
"{}: {}: {}",
$p,
format!("{}", now()).purple(),
format!($($t)*)
)
}};
}
/** format a string for logging */
#[macro_export]
macro_rules! log_fmt {
($($t:tt)*) => {{
log_fmt_!("log".blue(), $($t)*)
}};
}
/** format a string for logging errors */
#[macro_export]
macro_rules! log_efmt {
($($t:tt)*) => {{
log_fmt_!("err".red(), $($t)*)
}};
}
/** log a string with a timestamp */
#[macro_export]
macro_rules! log {
($($t:tt)*) => {{
println!("{}", log_fmt!($($t)*));
}};
}
/** log but stderr */
#[macro_export]
macro_rules! elog {
($($t:tt)*) => {{
eprintln!("{}", log_efmt!($($t)*));
}};
}
/** formatter for the debug logger */
//#[macro_export]
//#[cfg(not(debug_assertions))]
//macro_rules! dbg_log_fmt {
// ($x:expr, $($t:tt)*) => {{
// String::new()
// }};
//}
//#[cfg(debug_assertions)]
#[macro_export]
macro_rules! dbg_log_fmt {
($($t:tt)*) => {{
log_fmt!("{}: {}", "dbg".purple(), format!($($t)*))
}};
}
/** log but only in debug mode */
#[macro_export]
macro_rules! dbg_log {
($($t:tt)*) => {{
println!("{}", dbg_log_fmt!("{}", format!($($t)*)));
}};
}
/** log an error in debug mode */
#[macro_export]
macro_rules! dbg_elog {
($($t:tt)*) => {{
eprintln!("{}", dbg_log_fmt!("dbg err: {}", format!($($t)*)));
}};
}
/*
/** put a string without a newline */
#[macro_export]
macro_rules! puts {
($($t:tt)*) => {{
use std::io::{self, Write};
print!($($t)*);
match io::stdout().flush() {
Ok(_) => (),
Err(e) => fatal!("failed to flush stdout: {e}")
}
}};
}
*/
/** puts but stderr */
#[macro_export]
macro_rules! eputs {
($($t:tt)*) => {{
use std::io::{self, Write};
eprint!($($t)*);
match io::stderr().flush() {
Ok(_) => (),
Err(e) => {
/* TODO: can't reuse fatal bc it leads to infinite recursion
* is there a better way? maybe an internal fn? */
eprintln!(
"{}: failed to flush stderr: {}",
"fatal".red(),
e
);
}
}
}};
}
/** format! but it makes a &str */
#[macro_export]
macro_rules! str_fmt {
($($t:tt)*) => {
format!($($t)*).as_str()
}
}
/** encode a formatted string */
#[macro_export]
macro_rules! encode_fmt {
($($t:tt)*) => {{
use html_escape::encode_text;
format!("{}", encode_text(str_fmt!($($t)*)))
}};
}
/** make a &str from x where x is a String: From<T> */
#[macro_export]
macro_rules! str_from {
($x:expr) => {{
String::from($x).as_str()
}};
}
/** get the current time and format it */
pub fn now() -> String {
chrono::Local::now().format("%Y-%m-%d %H:%M:%S").to_string()
}
/*
#[derive(Clone, Debug)]
pub struct Cfg {
pub title: String,
pub git_addr: String,
pub git_port: String,
}
*/
/*
* i love global variables :)
*/
lazy_static! {
/** args are global so they can be used by all the actions */
pub static ref ARGS: Args = Args::parse();
/** the configuration file structure */
pub static ref CFG: Table = {
/* file to read */
let f = &ARGS.cfg;
/* content of that file */
let c = match fs::read_to_string(f) {
Ok(x) => x,
Err(e) => fatal!("failed to read config file: {e}"),
};
/* the resulting table */
let t = match c.parse::<Table>() {
Ok(x) => x,
Err(e) => fatal!("failed to get config: {e}"),
};
/* err out if we don't have the required settings */
{
if !t.contains_key("title") {
fatal!("configuration does not contain a title!!");
}
if !t.contains_key("git_addr") {
fatal!("configuration does not contain a git addr!");
}
if !t.contains_key("git_port") {
fatal!("configuration does not gontain a git port!");
}
}
t
};
}