chore: add app_tools
This commit is contained in:
parent
6bcb904c42
commit
c4723576b7
10
app_tools/.gitignore
vendored
Normal file
10
app_tools/.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
/target
|
||||
target
|
||||
Cargo.lock
|
||||
.cache
|
||||
.temp
|
||||
.env
|
||||
*.log
|
||||
.DS_Store
|
||||
logs
|
||||
tmp
|
29
app_tools/Cargo.toml
Normal file
29
app_tools/Cargo.toml
Normal file
@ -0,0 +1,29 @@
|
||||
[package]
|
||||
name = "app_tools"
|
||||
version = "0.1.0"
|
||||
authors = ["JesusPerez <jpl@jesusperez.pro>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.40"
|
||||
base64 = "0.13.0"
|
||||
envmnt = "0.9.0"
|
||||
rand = "0.8.3"
|
||||
regex = "1.4.3"
|
||||
reqwest = "0.11.3"
|
||||
json = "0.12.4"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_derive = "1.0.125"
|
||||
serde_json = "1.0.64"
|
||||
serde_yaml = "0.8.17"
|
||||
slab = "0.4.3"
|
||||
sthash = "0.2.9"
|
||||
tempfile = "3.2.0"
|
||||
tera = "1.8.0"
|
||||
thiserror = "1.0.24"
|
||||
toml = "0.5.8"
|
||||
yaml-rust = "0.4"
|
||||
uuid = { version = "0.8", features = ["serde", "v4"] }
|
||||
|
52
app_tools/README.md
Normal file
52
app_tools/README.md
Normal file
@ -0,0 +1,52 @@
|
||||
# App Tools Utils library
|
||||
|
||||
Several functions to help in applications
|
||||
|
||||
Utility functions for variety of tasks
|
||||
|
||||
```rust
|
||||
fn run_command(cmd: &str, arg1: &str, arg2: &str) -> anyhow::Result<()>
|
||||
```
|
||||
|
||||
```rust
|
||||
fn from_base64(source: &str) -> String
|
||||
```
|
||||
|
||||
FromStr for RGB
|
||||
|
||||
Trim newline
|
||||
this function is critical for base64 content as usually adds a newline at the end, causing decode not work properly with code.
|
||||
**trim_newline** should be called to clean content before to be decoded.
|
||||
|
||||
```rust
|
||||
fn trim_newline(s: &mut String)
|
||||
```
|
||||
|
||||
```rust
|
||||
fn hash_from_data(path: &str, ctx: &mut tera::Context, data_hash: &mut HashMap<String, String>, load_extend: bool) -> anyhow::Result<()>
|
||||
```
|
||||
|
||||
**get_json_val** is a simple match Option to remove quotes in json values and returned as a String
|
||||
|
||||
```rust
|
||||
get_json_val(json_value: &serde_json::Value, dflt_val: String) -> String
|
||||
```
|
||||
|
||||
**get_toml_val** is a simple match Option to remove quotes in json values and returned as a String
|
||||
|
||||
```rust
|
||||
get_toml_val(toml_value: &toml::Value, dflt_val: String) -> String
|
||||
```
|
||||
|
||||
**get_toml_val** is a simple match Option to remove quotes in json values and returned as a String
|
||||
|
||||
```rust
|
||||
get_yaml_val(yaml_value: &serde_yaml::Value, dflt_val: String) -> String
|
||||
```
|
||||
|
||||
Read a **file_name** from a path (root / file_name) ( "" file_name_full_path )
|
||||
format of reading can be matched with `file_type`
|
||||
|
||||
```rust
|
||||
read_path_file(path: &str, file_name: &str, file_type: &str) -> anyhow::Result<String>
|
||||
````
|
9
app_tools/TODO.md
Normal file
9
app_tools/TODO.md
Normal file
@ -0,0 +1,9 @@
|
||||
### App Env library
|
||||
|
||||
- [ ] Implement tests for **config**
|
||||
|
||||
- [ ] Extend **config** to support other **data stores**
|
||||
|
||||
- [ ] Add encryption to **config**
|
||||
|
||||
- [ ] Complete implementation for this types by moving some code here.
|
273
app_tools/src/lib.rs
Normal file
273
app_tools/src/lib.rs
Normal file
@ -0,0 +1,273 @@
|
||||
/*! Utility functions for variety of tasks */
|
||||
//
|
||||
/*! Zterton */
|
||||
//
|
||||
// Copyright 2020, Jesús Pérez Lorenzo
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
use std::fs;
|
||||
use anyhow::anyhow;
|
||||
use regex::Regex;
|
||||
use std::process::Command;
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(PartialEq, Default, Clone, Debug)]
|
||||
struct Commit {
|
||||
hash: String,
|
||||
message: String,
|
||||
}
|
||||
/// A very simple Operating System Command runner capturing output
|
||||
/// Allows two arguments, they can be empty
|
||||
///```rust
|
||||
/// let res =
|
||||
/// match run_command("pwd", "", "") {
|
||||
/// Ok(_) => format!("{} {}", "pwd","Done"),
|
||||
/// Err(e) => format!("{}",e),
|
||||
/// };
|
||||
/// println!("Result: {}",res);
|
||||
/// ```
|
||||
#[allow(dead_code)]
|
||||
#[allow(clippy::missing_errors_doc, clippy::filter_map)]
|
||||
pub fn run_command(cmd: &str, arg1: &str, arg2: &str) -> anyhow::Result<()> {
|
||||
let output = match arg2 {
|
||||
"" => match arg1 {
|
||||
"" => Command::new(cmd).output()?,
|
||||
_ => Command::new(cmd).arg(arg1).output()?,
|
||||
},
|
||||
_ => Command::new(cmd).arg(arg1).arg(arg2).output()?,
|
||||
};
|
||||
|
||||
if !output.status.success() {
|
||||
//dbg!(&output);
|
||||
let code = output.status.code().unwrap_or(-1);
|
||||
// let code = match output.status.code() {
|
||||
// Some(val) => val,
|
||||
// None => -1,
|
||||
// };
|
||||
let stderr = String::from_utf8(output.stderr)?;
|
||||
let msg = format!(
|
||||
"Command {} executed with failing errors({}): {}",
|
||||
&cmd, &code, &stderr
|
||||
);
|
||||
println!("{}", &msg);
|
||||
return Err(anyhow!(msg));
|
||||
// error_chain::bail!("Command {} executed with failing error code", &cmd);
|
||||
}
|
||||
let pattern = Regex::new(
|
||||
r"(?x)
|
||||
([0-9a-fA-F]+) # commit hash
|
||||
(.*) # The commit message",
|
||||
)?;
|
||||
String::from_utf8(output.stdout)?
|
||||
.lines()
|
||||
.filter_map(|line| pattern.captures(line))
|
||||
.map(|cap| Commit {
|
||||
hash: cap[1].to_string(),
|
||||
message: cap[2].trim().to_string(),
|
||||
})
|
||||
.take(5)
|
||||
.for_each(|x| println!("{:?}", x));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn from_base64(source: &str) -> String {
|
||||
match base64::decode(source) {
|
||||
Ok(res_deco) =>
|
||||
String::from_utf8(res_deco).unwrap_or_else(
|
||||
|e|{ println!("Error utf8 decode: {}", e); "".to_string() }
|
||||
),
|
||||
Err(e) => {
|
||||
println!("Error 64 decode: {}", e);
|
||||
source.to_owned()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
|
||||
pub struct RGB {
|
||||
pub r: u8,
|
||||
pub g: u8,
|
||||
pub b: u8,
|
||||
}
|
||||
|
||||
impl FromStr for RGB {
|
||||
type Err = std::num::ParseIntError;
|
||||
|
||||
// Parses a color hex code of the form '#rRgGbB..' into an
|
||||
// instance of 'RGB'
|
||||
fn from_str(hex_code: &str) -> Result<Self, Self::Err> {
|
||||
// u8::from_str_radix(src: &str, radix: u32) converts a string
|
||||
// slice in a given base to u8
|
||||
let r: u8 = u8::from_str_radix(&hex_code[1..3], 16)?;
|
||||
let g: u8 = u8::from_str_radix(&hex_code[3..5], 16)?;
|
||||
let b: u8 = u8::from_str_radix(&hex_code[5..7], 16)?;
|
||||
|
||||
Ok(RGB { r, g, b })
|
||||
}
|
||||
}
|
||||
|
||||
impl RGB {
|
||||
#[must_use]
|
||||
pub fn as_u8(&self) -> [u8; 3] {
|
||||
[self.r,self.g,self.b]
|
||||
}
|
||||
}
|
||||
/// Trim newline
|
||||
/// this function is critical for base64 content as usually adds a newline at the end, causing decode not work properly with code.
|
||||
/// `trim_newline` should be called to clean content before to be decoded.
|
||||
pub fn trim_newline(s: &mut String) {
|
||||
if s.ends_with('\n') {
|
||||
s.pop();
|
||||
if s.ends_with('\r') {
|
||||
s.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
#[allow(clippy::missing_errors_doc,clippy::implicit_hasher)]
|
||||
pub fn hash_from_data(path: &str, ctx: &mut tera::Context, data_hash: &mut HashMap<String, String>, load_extend: bool) -> anyhow::Result<()> {
|
||||
// {HashMap<String, String>> {
|
||||
let mut check_value = | key: String, v: String | {
|
||||
if let Some(first_char) = v.chars().next() {
|
||||
if first_char == '@' {
|
||||
let field_file = &v[1..];
|
||||
let _ = hash_from_data(field_file, ctx, data_hash, load_extend);
|
||||
// dbg!("{}",&data_hash);
|
||||
return;
|
||||
}
|
||||
}
|
||||
data_hash.insert(key, v);
|
||||
};
|
||||
let vars_content = fs::read_to_string(&path)?;
|
||||
//let mut data_hash: HashMap<String, String> = HashMap::new();
|
||||
if let Some(extension) = path.split('.').last() {
|
||||
//println!("File {} extension {}", &path, &extension);
|
||||
match extension {
|
||||
"json" => {
|
||||
let data: HashMap<String, serde_json::Value> = serde_json::from_str(&vars_content)?;
|
||||
if load_extend {
|
||||
match tera::Context::from_serialize(data) {
|
||||
Ok(res) => {
|
||||
ctx.extend(res);
|
||||
},
|
||||
Err(e) => {
|
||||
println!("Error loading {}: {}",&path, e);
|
||||
},
|
||||
}
|
||||
} else {
|
||||
for (key, value) in data {
|
||||
let val = get_json_val(&value, "".into());
|
||||
check_value(key,val);
|
||||
}
|
||||
}
|
||||
}
|
||||
"toml" => {
|
||||
// As a table content
|
||||
let data: toml::Value = toml::from_str(&vars_content)?;
|
||||
// let data = &vars_content.parse::<toml::Value>()?;
|
||||
if load_extend {
|
||||
match tera::Context::from_serialize(data) {
|
||||
Ok(res) => {
|
||||
ctx.extend(res);
|
||||
},
|
||||
Err(e) => {
|
||||
println!("Error loading {}: {}",&path, e);
|
||||
},
|
||||
}
|
||||
} else if let Some(table_data) = data.as_table() {
|
||||
for (key, value) in table_data {
|
||||
println!("-{}-{}",&key,&value);
|
||||
let val = get_toml_val(&value, "".into());
|
||||
check_value(key.into(),val);
|
||||
}
|
||||
}
|
||||
}
|
||||
"yaml" => {
|
||||
let data: HashMap<String, serde_yaml::Value> = serde_yaml::from_str(&vars_content)?;
|
||||
if load_extend {
|
||||
match tera::Context::from_serialize(data) {
|
||||
Ok(res) => {
|
||||
ctx.extend(res);
|
||||
},
|
||||
Err(e) => {
|
||||
println!("Error loading {}: {}",&path, e);
|
||||
},
|
||||
}
|
||||
} else {
|
||||
for (key, value) in data {
|
||||
let val = get_yaml_val(&value, "".into());
|
||||
check_value(key,val);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
println!(
|
||||
"File {} format extension {} not defined ",
|
||||
&path, &extension
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
println!("File {} unknown extension", &path);
|
||||
}
|
||||
// dbg!(&data_hash);
|
||||
Ok(()) // data_hash)
|
||||
}
|
||||
/// `get_json_val` is a simple match Option to remove quotes in json values and returned as a String
|
||||
#[must_use]
|
||||
pub fn get_json_val(json_value: &serde_json::Value, dflt_val: String) -> String {
|
||||
match json_value.as_str() {
|
||||
Some(val) => val.to_string(),
|
||||
None => dflt_val,
|
||||
}
|
||||
}
|
||||
/// `get_toml_val` is a simple match Option to remove quotes in json values and returned as a String
|
||||
#[must_use]
|
||||
pub fn get_toml_val(toml_value: &toml::Value, dflt_val: String) -> String {
|
||||
match toml_value.as_str() {
|
||||
Some(val) => val.to_string(),
|
||||
None => dflt_val,
|
||||
}
|
||||
}
|
||||
/// `get_toml_val` is a simple match Option to remove quotes in json values and returned as a String
|
||||
#[must_use]
|
||||
pub fn get_yaml_val(yaml_value: &serde_yaml::Value, dflt_val: String) -> String {
|
||||
match yaml_value.as_str() {
|
||||
Some(val) => val.to_string(),
|
||||
None => dflt_val,
|
||||
}
|
||||
}
|
||||
/// Read a `file_name` from a path (root / `file_name`) ( "" `file_name_full_path` )
|
||||
/// format of reading can be matched with `file_type`
|
||||
/// TODO implement other types to read
|
||||
#[allow(clippy::missing_errors_doc)]
|
||||
pub fn read_path_file(path: &str, file_name: &str, file_type: &str) -> anyhow::Result<String> {
|
||||
let mut result = String::from("");
|
||||
let mut root_path = format!("{}/", path);
|
||||
if root_path.as_str() == "/" {
|
||||
root_path = String::from("");
|
||||
}
|
||||
//println!("{}",format!("{}{}", &root_path.as_str(), &file_name));
|
||||
match file_type {
|
||||
"content" => {
|
||||
result = fs::read_to_string(format!("{}{}", &root_path.as_str(), &file_name).as_str())?
|
||||
}
|
||||
_ => println!(
|
||||
"File {}{} type {} not defined ",
|
||||
&root_path, &file_name, &file_type
|
||||
),
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert_eq!(2 + 2, 4);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user