1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#![feature(async_closure)]
#[macro_use]
extern crate diesel;
#[macro_use]
extern crate diesel_migrations;
mod commands;
pub mod database;
mod models;
mod modify_gitignore;
pub use commands::*;
use crate::models::{Icon, Repo};
use database::db;
use diesel::prelude::*;
use once_cell::sync::Lazy;
use std::{
error::Error,
fs::create_dir,
io::ErrorKind,
path::{Path, PathBuf},
process::Command,
};
use tokio::fs;
use url::Url;
static CACHE_DIR: Lazy<PathBuf> = Lazy::new(|| {
let path = Path::new(&home::home_dir().unwrap()).join("Library/Caches/com.samdenty.github-icons");
if !path.exists() {
create_dir(&path).unwrap()
}
path
});
pub async fn clear_cache() -> Result<(), Box<dyn Error>> {
if CACHE_DIR.exists() {
fs::remove_dir_all(&*CACHE_DIR).await?;
}
Ok(())
}
pub async fn list_icons(slug_or_path: &str) -> Result<Vec<String>, Box<dyn Error + Send + Sync>> {
let (user, repo_name, _) = get_slug(slug_or_path)?;
let icons = {
use database::schema::icons::dsl::*;
icons
.filter(owner.like(&user).and(repo.like(&repo_name)))
.load::<Icon>(db())?
};
Ok(
icons
.into_iter()
.map(|icon| CACHE_DIR.join(icon.path).to_string_lossy().to_string())
.collect(),
)
}
pub async fn list_repos() -> Result<Vec<Repo>, Box<dyn Error>> {
let mut repo_results = {
use database::schema::repos::dsl::*;
repos.load::<Repo>(db())?
};
for repo_result in &mut repo_results {
repo_result.icon_path = match &repo_result.icon_path {
Some(icon_path) => Some(CACHE_DIR.join(icon_path).to_string_lossy().to_string()),
None => None,
}
}
Ok(repo_results)
}
fn get_slug(repo: &str) -> Result<(String, String, Option<String>), Box<dyn Error + Send + Sync>> {
if repo.split("/").count() == 2 && !Path::new(&repo).exists() {
let mut slug = repo.split("/");
let user = slug.next().unwrap().to_string();
let repo = slug.next().unwrap().to_string();
Ok((user, repo, None))
} else {
let output = Command::new("git")
.args(["config", "--get", "remote.origin.url"])
.current_dir(Path::new(repo))
.output()?;
let url = Url::parse(&String::from_utf8(output.stdout)?)
.map_err(|_| std::io::Error::new(ErrorKind::Other, "No repository found for folder"))?;
let slug = url.path().strip_suffix(".git").unwrap_or(url.path());
let mut slug = slug.split("/");
slug.next();
let user = slug
.next()
.ok_or(std::io::Error::new(
ErrorKind::Other,
"No user in repo url found",
))?
.to_string();
let repo_name = slug
.next()
.ok_or(std::io::Error::new(
ErrorKind::Other,
"No repo in repo url found",
))?
.to_string();
Ok((user, repo_name, Some(repo.to_string())))
}
}