1use auth_git2::GitAuthenticator;
2use dirs::config_dir;
3use git2::{Error, Repository};
4use regex::Regex;
5use serde::{Deserialize, Serialize};
6use std::fs;
7use std::path::{Path, PathBuf};
8
9pub mod projectmanager;
10use crate::projectmanager::{nvim, vscode};
11
12const DEFAULT_REGEX: &str = r"(?m)^(?:https?://|git@)?([^/:]+)[/:]([^/]+)/([^\.]+)(?:\.git)?/?$";
13
14#[derive(Serialize, Deserialize, Debug)]
15#[serde(default)]
16pub struct AppConfig {
17 #[serde(skip_serializing_if = "Option::is_none")]
18 pub vscode_path_prefix: Option<String>,
19 pub workspaces_dir: PathBuf,
20 pub nvim_projectmanager_path: PathBuf,
21 pub vscode_projectmanager_path: PathBuf,
22 pub regex: String,
23}
24
25impl AppConfig {
26 pub fn load() -> Self {
27 let config_path = Self::config_path();
28 if config_path.exists() {
29 let config_data = fs::read_to_string(config_path).expect("Unable to read config file");
30 toml::from_str(&config_data).expect("Invalid config file")
31 } else {
32 Self::default()
34 }
35 }
36
37 pub fn save(&self) {
38 let config_path = Self::config_path();
39 println!("Saving configfile to: {:?}", config_path);
40 let config_data = toml::to_string(self).expect("Unable to serialize config");
41 fs::create_dir_all(config_path.parent().unwrap())
42 .expect("Failed to create config directory");
43 fs::write(config_path, config_data).expect("Unable to write config file");
44 }
45
46 fn config_path() -> PathBuf {
47 config_dir().unwrap().join("clone").join("config.toml")
48 }
49}
50
51impl Default for AppConfig {
52 fn default() -> Self {
53 match detect_current_os() {
54 "wsl" => {
55 if let Some(username) = get_wsl_user_name() {
56 let win_user_home_path = format!("/mnt/c/Users/{}", username);
57 let wsl_user_home_path =
58 std::env::var("HOME").expect("'HOME' environment variable must be set.");
59 let wsl_distro_name = std::env::var("WSL_DISTRO_NAME").expect(
60 "'WSL_DISTRO_NAME' environment variable must be set in WSL environment.",
61 );
62
63 AppConfig {
64 vscode_path_prefix: Some(format!("vscode-remote://wsl+{}", wsl_distro_name)),
65 workspaces_dir: format!("{}/workspaces", wsl_user_home_path).into(),
66 nvim_projectmanager_path: format!("{}/.local/share/nvim/lazy/projectmgr.nvim/projects.json", wsl_user_home_path).into(),
67 vscode_projectmanager_path: format!("{}/AppData/Roaming/Code/User/globalStorage/alefragnani.project-manager/projects.json", win_user_home_path).into(),
68 regex: DEFAULT_REGEX.to_string()
69 }
70 } else {
71 panic!("Cannot get WSL username in a WSL environment, that must never happen, that mean powershell.exe didn't exist or didn't provide the environment variable $env:USERNAME.");
72 }
73 }
74 "macos" => {
75 let user_home_path =
76 std::env::var("HOME").expect("'HOME' environment variable must be set.");
77 AppConfig {
78 vscode_path_prefix: None,
79 workspaces_dir: format!("{}/workspaces", user_home_path).into(),
80 nvim_projectmanager_path: format!("{}/.local/share/nvim/lazy/projectmgr.nvim/projects.json", user_home_path).into(),
81 vscode_projectmanager_path: format!("{}/Library/Application Support/Code/User/globalStorage/alefragnani.project-manager/projects.json", user_home_path).into(),
82 regex: DEFAULT_REGEX.to_string()
83 }
84 }
85 "windows" => {
86 let user_home_path = std::env::var("USERPROFILE")
87 .expect("'USERPROFILE' environment variable must be set.");
88 AppConfig {
89 vscode_path_prefix: None,
90 workspaces_dir: format!("{}\\workspaces", user_home_path).into(),
91 nvim_projectmanager_path: format!("{}\\AppData\\Roaming\\nvim\\", user_home_path).into(),
92 vscode_projectmanager_path: format!("{}\\AppData\\Roaming\\Code\\User\\globalStorage\\alefragnani.project-manager\\projects.json", user_home_path).into(),
93 regex: DEFAULT_REGEX.to_string()
94 }
95 }
96 _linux => {
97 let user_home_path =
98 std::env::var("HOME").expect("'HOME' environment variable must be set.");
99 AppConfig {
100 vscode_path_prefix: None,
101 workspaces_dir: format!("{}/workspaces", user_home_path).into(),
102 nvim_projectmanager_path: format!("{}/.local/share/nvim/lazy/projectmgr.nvim/projects.json", user_home_path).into(),
103 vscode_projectmanager_path:format!("{}/.config/Code/User/globalStorage/alefragnani.project-manager/projects.json", user_home_path).into(),
104 regex: DEFAULT_REGEX.to_string()
105 }
106 }
107 }
108 }
109}
110
111pub fn parse_repo_url(url: &str, regex: &str) -> Result<(String, String, String), ()> {
112 let parser = Regex::new(regex).unwrap();
113 if let Some(result) = parser.captures(url) {
114 let host = &result[1];
115 let group = &result[2];
116 let name = &result[3];
117 Ok((host.to_string(), group.to_string(), name.to_string()))
118 } else {
119 Err(())
120 }
121}
122
123pub fn clone_repo(url: &str, repo_path: &Path) -> Result<Repository, Error> {
124 if repo_path.exists() {
125 Err(Error::new(
126 git2::ErrorCode::Exists,
127 git2::ErrorClass::Filesystem,
128 format!("repository already exist at {:?}", repo_path),
129 ))
130 } else {
131 let auth = GitAuthenticator::default();
133 match auth.clone_repo(url, &repo_path) {
134 Ok(repo) => {
135 println!("Cloned into {:?}", repo_path);
136 Ok(repo)
137 }
138 Err(e) => Err(e),
139 }
140 }
141}
142
143pub fn detect_current_os() -> &'static str {
144 match std::env::consts::OS {
145 "linux" => match detect_wsl_with_envs() {
146 true => "wsl",
147 false => "linux",
148 },
149 os => os,
150 }
151}
152
153fn _detect_wsl_with_powershell() -> bool {
154 if let Some(_output) = get_wsl_user_name() {
155 true
156 } else {
157 false
158 }
159}
160
161fn get_wsl_user_name() -> Option<String> {
162 if let Ok(output_utf8) = std::process::Command::new("powershell.exe")
163 .arg("-c")
164 .arg("echo $env:USERNAME")
165 .output()
166 {
167 if let Ok(output) = String::from_utf8(output_utf8.stdout) {
168 Some(output.trim().to_string())
169 } else {
170 None
171 }
172 } else {
173 None
174 }
175}
176
177fn detect_wsl_with_envs() -> bool {
178 std::env::var("WSL_DISTRO_NAME").is_ok()
179}
180
181pub fn add_project_to_nvim(
182 target_path: PathBuf,
183 workspace: PathBuf,
184 host: String,
185 group: String,
186 name: String,
187 debug: bool,
188) {
189 nvim::add_project(target_path, workspace, host, group, name, debug)
190}
191pub fn add_project_to_vscode(
192 target_path: PathBuf,
193 workspace: PathBuf,
194 host: String,
195 group: String,
196 name: String,
197 debug: bool,
198) {
199 vscode::add_project(target_path, workspace, host, group, name, debug)
200}