From b2461d0cc8e78148ff7c0ccd7846268227856477 Mon Sep 17 00:00:00 2001 From: Luca Bilke Date: Tue, 4 Jun 2024 13:17:09 +0200 Subject: [PATCH] refactor, new functions --- Cargo.lock | 39 +++++++++++++++ Cargo.toml | 11 ++--- TODO.md | 2 +- src/config.rs | 34 ------------- src/lib.rs | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 6 +-- src/remote.rs | 35 ------------- 7 files changed, 181 insertions(+), 80 deletions(-) delete mode 100644 src/config.rs create mode 100644 src/lib.rs delete mode 100644 src/remote.rs diff --git a/Cargo.lock b/Cargo.lock index bb5ba8b..d48d442 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -466,6 +475,7 @@ version = "0.1.0" dependencies = [ "confy", "git2", + "regex", "reqwest", "serde", "serde_json", @@ -736,6 +746,35 @@ dependencies = [ "thiserror", ] +[[package]] +name = "regex" +version = "1.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" + [[package]] name = "reqwest" version = "0.12.4" diff --git a/Cargo.toml b/Cargo.toml index 735f3d1..d57ef0a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,16 +3,15 @@ name = "klados" version = "0.1.0" edition = "2021" +[dependencies] +git2 = "0.18.3" +regex = "1.10.4" +serde_json = "1.0.117" + [dependencies.reqwest] version = "0.12.4" features = ["json", "blocking"] -[dependencies.git2] -version = "0.18.3" - -[dependencies.serde_json] -version = "1.0.117" - [dependencies.serde] version = "1.0.203" features = ["derive"] diff --git a/TODO.md b/TODO.md index ced633c..1319e98 100644 --- a/TODO.md +++ b/TODO.md @@ -2,8 +2,8 @@ - [X] Define config schema - [X] Parse config -- [ ] Discover local repositories in $KLADOS_DIR - [X] Discover remote repositories +- [X] Discover local repositories - [ ] Clone remote repositories - [ ] List unclean local repositories - [ ] Pull clean local repositories diff --git a/src/config.rs b/src/config.rs deleted file mode 100644 index 71de2be..0000000 --- a/src/config.rs +++ /dev/null @@ -1,34 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Default, Deserialize, Serialize)] -pub struct Config { - blacklist: Option>, - lookups: Option>, - map: Option>, -} - -#[derive(Debug, Deserialize, Serialize)] -pub struct Lookup { - name: String, - url: String, - field: String, - interpolate: Option>, - token_cmd: Option, - block_unmatched: Option, - auth_header: Option, -} - -#[derive(Debug, Deserialize, Serialize)] -pub struct Map { - patterns: Option>, - url: Option, - directory: Option, - rename: Option>, - ignore: Option, -} - -#[derive(Debug, Deserialize, Serialize)] -pub struct Rename { - replace: String, - with: String, -} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..aeaae10 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,134 @@ +use git2::Repository; +use regex::Regex; +use reqwest::header::{HeaderMap, HeaderValue, CONTENT_TYPE}; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use std::{env, fs, path::PathBuf}; + +#[derive(Debug, Default, Deserialize, Serialize)] +pub struct Config { + pub root_dir: String, + blacklist: Option>, + lookups: Option>, + map: Vec, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct Lookup { + name: String, + url: String, + field: String, + interpolate: Option>, + token_cmd: Option, + block_unmatched: Option, + auth_header: Option, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct Map { + patterns: Option>, + url: Option, + directory: Option, + rename: Option>, + ignore: Option, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct Rename { + replace: String, + with: String, +} + +impl Config { + pub fn setup(self: &mut Config) { + self.root_dir = expand_env_vars(&self.root_dir); + } + + pub fn list_target_dirs(self: &Config) -> Vec { + self.map + .iter() + .filter_map(|map| { + map.directory + .as_ref() + .map(|path| PathBuf::from(self.root_dir.clone()).join(path)) + }) + .collect() + } + + pub fn get_target_dir(self: &Config, repo_url: &str) -> Option<&PathBuf> { + for map in &self.map { + if let Some(patterns) = &map.patterns { + for pattern in patterns { + if repo_url.contains(pattern) { + return map.directory.as_ref(); + } + } + } + } + None + } +} + +pub fn get_remote_urls( + endpoint: &str, + auth_header: &str, + field: &str, +) -> Result, Box> { + let handle = reqwest::blocking::Client::new(); + let mut headers = HeaderMap::new(); + + headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json")); + headers.insert( + "Authorization", + HeaderValue::from_str(auth_header).expect("Malformed auth header"), + ); + + let res = handle + .get(endpoint) + .headers(headers) + .send() + .expect("Request to API Failed") + .json::() + .expect("Malformed JSON Response from API"); + + let urls = res + .as_array() + .unwrap_or(&Vec::new()) + .iter() + .filter_map(|obj| obj[field].as_str()) + .map(|url| url.to_string()) + .collect(); + + Ok(urls) +} + +pub fn get_existing_repos(directories: &Vec) -> Option> { + let mut repos: Vec = Vec::new(); + + for dir in directories { + let entries = match fs::read_dir(dir) { + Ok(entries) => entries + .filter_map(|entry| entry.ok()) + .map(|entry| entry.path()) + .filter_map(|path| Repository::open(path).ok()) + .collect::>(), + Err(_) => continue, + }; + repos.extend(entries) + } + Some(repos) +} + +fn expand_env_vars(input: &str) -> String { + let re = Regex::new(r"\$\{?[a-zA-Z_][a-zA-Z0-9_]*(\}|\b)").unwrap(); + re.replace_all(input, |captures: ®ex::Captures| { + let var = captures + .get(0) + .unwrap() + .as_str() + .trim_start_matches('$') + .trim_matches(|c| c == '{' || c == '}'); + env::var(var).unwrap() + }) + .to_string() +} diff --git a/src/main.rs b/src/main.rs index 71149c4..ec52b33 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,4 @@ -pub mod config; -pub mod remote; - fn main() { - let cfg: config::Config = confy::load("klados", "config").unwrap(); + let mut cfg: klados::Config = confy::load("klados", "config").unwrap(); + cfg.setup(); } diff --git a/src/remote.rs b/src/remote.rs deleted file mode 100644 index 00d0cc7..0000000 --- a/src/remote.rs +++ /dev/null @@ -1,35 +0,0 @@ -use reqwest::header::{HeaderMap, HeaderValue, CONTENT_TYPE}; -use serde_json::Value; - -pub fn get_remote_urls( - endpoint: &str, - auth_header: &str, - field: &str, -) -> Result, Box> { - let handle = reqwest::blocking::Client::new(); - let mut headers = HeaderMap::new(); - - headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json")); - headers.insert( - "Authorization", - HeaderValue::from_str(auth_header).expect("Malformed auth header"), - ); - - let res = handle - .get(endpoint) - .headers(headers) - .send() - .expect("Request to API Failed") - .json::() - .expect("Malformed JSON Response from API"); - - let urls = res - .as_array() - .unwrap_or(&Vec::new()) - .iter() - .filter_map(|obj| obj[field].as_str()) - .map(|url| url.to_string()) - .collect(); - - Ok(urls) -}