feat!: put links in categories

This required a lot of refatoring, and added a lot of codedepth that
have to be repaid soon by a large refactor.

Also, it is becoming painfully obvious that testing should be expanded
significantly.

This, after the refactor, nonetheless.

Signed-off-by: Christina Sørensen <christina@cafkafk.com>
This commit is contained in:
Christina Sørensen 2023-07-04 11:26:25 +02:00 committed by Christina Sørensen
parent c62a0a720f
commit d5b845508a
5 changed files with 109 additions and 43 deletions

View file

@ -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

View file

@ -62,8 +62,6 @@ pub struct Config {
///
/// Key should conceptually be seen as the name of the category.
pub categories: HashMap<String, Category>,
/// A vector containing links
pub links: Vec<Links>,
}
/// 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<Vec<RepoFlags>>, // 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<HashMap<String, GitRepo>>,
/// 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<HashMap<String, Link>>,
}
/// 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<F>(&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);
}
}

View file

@ -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<F>(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
}
}*/
}
}

View file

@ -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

View file

@ -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