diff --git a/doc/roadmap.org b/doc/roadmap.org index 194466f..5d3c3cb 100644 --- a/doc/roadmap.org +++ b/doc/roadmap.org @@ -1,7 +1,9 @@ #+title: Roadmap * 0.2.0 (maybe) -- [ ] Links in categories? +- [-] Links in categories? +- [ ] Fix category with no links +- [ ] Refactor * 0.1.2 - [X] Implement Quiet flag * 0.1.1 diff --git a/src/git.rs b/src/git.rs index 8734bc3..ec9aed8 100644 --- a/src/git.rs +++ b/src/git.rs @@ -62,8 +62,6 @@ pub struct Config { /// /// Key should conceptually be seen as the name of the category. pub categories: HashMap, - /// A vector containing links - pub links: Vec, } /// Represents a category of repositories @@ -73,16 +71,22 @@ pub struct Config { pub struct Category { #[serde(skip_serializing_if = "Option::is_none")] pub flags: Option>, // FIXME: not implemented - /// map of all categories + /// map of all repos in category /// /// Key should conceptually be seen as the name of the category. #[serde(skip_serializing_if = "Option::is_none")] pub repos: Option>, + + /// map of all links in category + /// + /// Key should conceptually be seen as the name of the category. + #[serde(skip_serializing_if = "Option::is_none")] + pub links: Option>, } /// Contain fields for a single link. #[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] -pub struct Links { +pub struct Link { /// The name of the link pub name: String, pub rx: String, @@ -115,7 +119,7 @@ pub struct SeriesItem<'series> { //////////////////////////////////// //////////////////////////////////// -fn handle_file_exists(selff: &Links, tx_path: &Path, rx_path: &Path) { +fn handle_file_exists(selff: &Link, tx_path: &Path, rx_path: &Path) -> bool { match rx_path.read_link() { Ok(file) if file.canonicalize().expect("failed to canonicalize file") @@ -125,22 +129,25 @@ fn handle_file_exists(selff: &Links, tx_path: &Path, rx_path: &Path) { "Linking {} -> {} failed: file already linked", &selff.tx, &selff.rx ); + false } Ok(file) => { error!( "Linking {} -> {} failed: link to different file exists", &selff.tx, &selff.rx ); + false } Err(error) => { error!("Linking {} -> {} failed: file exists", &selff.tx, &selff.rx); + false } } } -impl Links { +impl Link { /// Creates the link from the link struct - pub fn link(&self) { + pub fn link(&self) -> bool { let tx_path: &Path = std::path::Path::new(&self.tx); let rx_path: &Path = std::path::Path::new(&self.rx); match rx_path.try_exists() { @@ -150,14 +157,17 @@ impl Links { "Linking {} -> {} failed: broken symlink", &self.tx, &self.rx ); + false } Ok(false) => { symlink(&self.tx, &self.rx).expect("failed to create link"); + true } Err(error) => { error!("Linking {} -> {} failed: {}", &self.tx, &self.rx, error); + false } - }; + } } } @@ -363,6 +373,38 @@ impl Config { } } } + /// Runs associated function on all links in config + fn on_all_links_spinner(&self, op: &str, f: F) + where + F: Fn(&Link) -> bool, + { + for category in self.categories.values() { + match category.links.as_ref() { + Some(links) => { + for (_, link) in links.iter() { + if !settings::QUIET.load(std::sync::atomic::Ordering::Relaxed) { + let mut sp = + Spinner::new(Spinners::Dots10, format!("{}: {}", link.name, op)); + if f(link) { + sp.stop_and_persist( + success_str(), + format!("{}: {}", link.name, op), + ); + } else { + sp.stop_and_persist( + failure_str(), + format!("{}: {}", link.name, op), + ); + } + } else { + f(link); + } + } + } + None => continue, + }; + } + } /// Runs associated function on all repos in config /// /// TODO: need to be made over a generic repo type @@ -558,8 +600,6 @@ impl Config { /// Tries to link all repositories, skips if fail. pub fn link_all(&self) { debug!("exectuting link_all"); - for link in &self.links { - link.link(); - } + self.on_all_links_spinner("link", Link::link); } } diff --git a/src/main.rs b/src/main.rs index 1503283..ce0d49f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -116,7 +116,7 @@ fn main() { mod config { use crate::*; use git::RepoFlags::{Clone, Push}; - use git::{Category, GitRepo}; + use git::{Category, GitRepo, Link}; use relative_path::RelativePath; use std::collections::HashMap; use std::env::current_dir; @@ -126,7 +126,6 @@ mod config { fn init_config() { let _config = Config { categories: HashMap::new(), - links: vec![], }; } #[test] @@ -134,10 +133,10 @@ mod config { let default_category = Category { flags: Some(vec![]), repos: Some(HashMap::new()), + links: Some(HashMap::new()), }; let mut config = Config { categories: HashMap::new(), - links: vec![], }; config .categories @@ -192,6 +191,7 @@ mod config { let test_config = Config::new(&RelativePath::new("./src/test/test.yaml").to_string()); assert_eq!(config, test_config); } + #[allow(dead_code)] fn get_category<'cat>(config: &'cat Config, name: &'cat str) -> &'cat Category { config.categories.get(name).expect("failed to get category") } @@ -209,6 +209,20 @@ mod config { .get(repo_name) .expect("failed to get category")) } + fn get_link(config: &Config, cat_name: &str, link_name: &str, f: F) + where + F: FnOnce(&Link), + { + f(config + .categories + .get(cat_name) + .expect("failed to get category") + .links + .as_ref() + .expect("failed to get repo") + .get(link_name) + .expect("failed to get category")) + } #[test] fn is_config_readable() { let root = current_dir().expect("failed to get current dir"); @@ -220,7 +234,7 @@ mod config { .expect("failed to turnn config into string"), ); - let flags = vec![Clone, Push]; + let _flags = vec![Clone, Push]; // FIXME not very extensive #[allow(clippy::bool_assert_comparison)] { @@ -228,8 +242,14 @@ mod config { assert_eq!(repo.name, "qmk_firmware"); assert_eq!(repo.path, "/home/ces/org/src/git/"); assert_eq!(repo.url, "git@github.com:cafkafk/qmk_firmware.git"); - }) + }); + get_link(&config, "stuff", "gg", |link| { + assert_eq!(link.name, "gg"); + assert_eq!(link.tx, "/home/ces/.dots/gg"); + assert_eq!(link.rx, "/home/ces/.config/gg"); + }); } + /* { assert_eq!(config.links[0].name, "gg"); assert_eq!(config.links[0].rx, "/home/ces/.config/gg"); @@ -238,7 +258,7 @@ mod config { assert_eq!(config.links[1].rx, "/home/ces/.config/starship.toml"); assert_eq!(config.links[1].tx, "/home/ces/.dots/starship.toml"); // FIXME doesn't check repoflags - } + }*/ } } diff --git a/src/test/config.yaml b/src/test/config.yaml index 54dcaac..dc8ec78 100644 --- a/src/test/config.yaml +++ b/src/test/config.yaml @@ -36,10 +36,12 @@ categories: name: li path: /home/ces/org/src/git/ url: git@github.com:cafkafk/li.git -links: - - name: gg - rx: /home/ces/.config/gg - tx: /home/ces/.dots/gg - - name: starship - rx: /home/ces/.config/starship.toml - tx: /home/ces/.dots/starship.toml + links: + gg: + name: gg + rx: /home/ces/.config/gg + tx: /home/ces/.dots/gg + starship: + name: starship + rx: /home/ces/.config/starship.toml + tx: /home/ces/.dots/starship.toml diff --git a/src/test/test.yaml b/src/test/test.yaml index 56c844b..3b777f2 100644 --- a/src/test/test.yaml +++ b/src/test/test.yaml @@ -2,13 +2,6 @@ categories: config: flags: [] repos: - starship: - name: starship - path: /home/ces/org/src/git/ - url: https://github.com/starship/starship.git - flags: - - Clone - - Push qmk_firmware: name: qmk_firmware path: /home/ces/org/src/git/ @@ -16,17 +9,33 @@ categories: flags: - Clone - Push + starship: + name: starship + path: /home/ces/org/src/git/ + url: https://github.com/starship/starship.git + flags: + - Clone + - Push stuff: flags: [] repos: - li: - name: li - path: /home/ces/org/src/git/ - url: git@github.com:cafkafk/li.git gg: name: gg path: /home/ces/.dots/ url: git@github.com:cafkafk/gg.git + li: + name: li + path: /home/ces/org/src/git/ + url: git@github.com:cafkafk/li.git + links: + gg: + name: gg + rx: /home/ces/.config/gg + tx: /home/ces/.dots/gg + starship: + name: starship + rx: /home/ces/.config/starship.toml + tx: /home/ces/.dots/starship.toml utils: repos: gg: @@ -44,10 +53,3 @@ categories: - Clone - Push empty: {} -links: -- name: gg - rx: /home/ces/.config/gg - tx: /home/ces/.dots/gg -- name: starship - rx: /home/ces/.config/starship.toml - tx: /home/ces/.dots/starship.toml