diff --git a/src/commands/repo/list.rs b/src/commands/repo/list.rs index 58d5839..0ea3be9 100644 --- a/src/commands/repo/list.rs +++ b/src/commands/repo/list.rs @@ -1,54 +1,8 @@ -use crate::common::git; -use crate::config::CONFIG; -use crate::filesystem::{all_cheat_files, default_cheat_pathbuf}; +use crate::filesystem::local_cheatsheet_repositories; use crate::libs::terminal::hyperlink; -use crate::prelude::*; pub fn main() { - let mut cheats_repos: Vec = Vec::new(); - let cheats = CONFIG.path().unwrap_or_else(|| { - // if we don't have a path, use the default value - let mut _cheats = default_cheat_pathbuf().unwrap(); - _cheats.push("navi"); - _cheats.push("cheats"); - - _cheats.to_string() - }); - - // We're checking each given paths possible - for cheat_path in cheats.split(':') { - // If the path doesn't exist, continue to the next one - if !std::fs::exists(cheat_path).unwrap() { - continue; - } - - let curr_dir = std::fs::read_dir(cheat_path).unwrap(); - - // We're checking subfolders -> they should contain at least one .cheat files - for entry in curr_dir { - let entry = entry.unwrap(); - - if entry.file_type().unwrap().is_dir() { - // If the directory doesn't have at least one cheat file -> ignore it and continue - if all_cheat_files(&entry.path()).is_empty() { - continue; - }; - - // If the directory have at least one cheat file -> add it to the list - // Note: for the list, we are registering the git remote name and not the - // folder name since we modify it internally. - let git_path = format!("{}/{}", &entry.path().display(), ".git"); - - if std::fs::exists(&git_path).unwrap() { - let remote_uri = git::get_remote(&entry.path().to_string()).unwrap(); - - cheats_repos.push(remote_uri); - } else { - cheats_repos.push(entry.path().display().to_string()); - } - } - } - } + let (cheats_repos, _) = local_cheatsheet_repositories(); // Now that we have our list of cheatsheet repositories, we loop through them // Two behaviours: diff --git a/src/commands/repo/sync.rs b/src/commands/repo/sync.rs index 34cab04..1d3904a 100644 --- a/src/commands/repo/sync.rs +++ b/src/commands/repo/sync.rs @@ -1,7 +1,35 @@ use crate::common::git; -use crate::filesystem; +use crate::filesystem::local_cheatsheet_repositories; use crate::prelude::*; pub fn main(name: Option) -> Result<()> { + let (cheats_repo_uris, cheats_repo_paths) = local_cheatsheet_repositories(); + + if name.clone().is_some() { + let name = name.clone().unwrap(); + + // We have been given a repository uri to check + if cheats_repo_uris.contains(&name) { + let folder_index = cheats_repo_uris.iter().position(|r| r == &name).unwrap(); + let repo_path = cheats_repo_paths[folder_index].clone(); + + git::pull(&repo_path)?; + } else { + eprintln!("I don't find {} locally, are you sure you downloaded it?", &name); + } + + return Ok(()); + } + + // We haven't been given a name -> We synchronize every cheatsheet repository we've found + for cheat_repo in cheats_repo_paths { + eprintln!("Pulling the latest version of {}", cheat_repo); + + git::pull(&cheat_repo)?; + } + + // TODO: Sanitize the cheatsheet folder of any file that is not a cheat file + // Ref: https://github.com/denisidoro/navi/issues/733 + Ok(()) } diff --git a/src/common/git.rs b/src/common/git.rs index f8e3295..1a7ac29 100644 --- a/src/common/git.rs +++ b/src/common/git.rs @@ -27,6 +27,8 @@ pub fn meta(uri: &str) -> (String, String, String) { (actual_uri, user.to_string(), repo) } +/// Retrieves the remote URI of a git repository +/// Works best with a repository containing only one remote. pub fn get_remote(uri: &str) -> Result { // We consider the repository having only one remote // In case of multiple occurrences, we return the first one and discard the others @@ -63,6 +65,17 @@ pub fn get_remote(uri: &str) -> Result { Ok(remotes_uri[0].clone()) } +/// Pulls the latest version of a git repository +pub fn pull(uri: &str) -> Result<()> { + Command::new("git") + .current_dir(uri) + .args(["pull", "origin"]) + .spawn()? + .wait() + .expect("Unable to git pull"); + Ok(()) +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/config/env.rs b/src/config/env.rs index ba428fc..9ded965 100644 --- a/src/config/env.rs +++ b/src/config/env.rs @@ -26,3 +26,11 @@ impl EnvConfig { } } } + +/// A default implementation for EnvConfig +/// to satisfy cargo clippy. +impl Default for EnvConfig { + fn default() -> Self { + Self::new() + } +} diff --git a/src/filesystem.rs b/src/filesystem.rs index a4e67bd..d098873 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -10,6 +10,7 @@ use regex::Regex; use std::cell::RefCell; use std::path::MAIN_SEPARATOR; +use crate::common::git; use walkdir::WalkDir; /// Multiple paths are joint by a platform-specific separator. @@ -114,6 +115,16 @@ pub fn cheat_paths(path: Option) -> Result { } } +/// Returns the cheats path defined at run time +pub fn running_cheats_path() -> String { + CONFIG.path().unwrap_or_else(|| { + // if we don't have a path, use the default value + let _cheats = default_cheat_pathbuf().unwrap(); + + _cheats.to_string() + }) +} + //////////////////////////////////////////////////////////////////////////////////////////////////// // // Here are other functions, unrelated to CLI commands (or at least not directly related) @@ -150,6 +161,54 @@ fn get_config_dir_by_platform() -> Result { } } +/// Goes through the cheats path(s) defined within the configuration +/// and sends back any cheatsheet repository remote URI it finds. +pub fn local_cheatsheet_repositories() -> (Vec, Vec) { + let mut cheats_repos_uri: Vec = Vec::new(); + let mut cheats_repos_paths: Vec = Vec::new(); + let cheats = running_cheats_path(); + + // We're checking each given paths possible + for cheat_path in cheats.split(':') { + // If the path doesn't exist, continue to the next one + if !std::fs::exists(cheat_path).unwrap() { + continue; + } + + let curr_dir = std::fs::read_dir(cheat_path).unwrap(); + + // We're checking subfolders -> they should contain at least one .cheat files + for entry in curr_dir { + let entry = entry.unwrap(); + + if entry.file_type().unwrap().is_dir() { + // If the directory doesn't have at least one cheat file -> ignore it and continue + if all_cheat_files(&entry.path()).is_empty() { + continue; + }; + + // If the directory have at least one cheat file -> add it to the list + // Note: for the list, we are registering the git remote name and not the + // folder name since we modify it internally. + let git_path = format!("{}/{}", &entry.path().display(), ".git"); + let folder_path = entry.path().display().to_string(); + + if std::fs::exists(&git_path).unwrap() { + let remote_uri = git::get_remote(&entry.path().to_string()).unwrap(); + + cheats_repos_uri.push(remote_uri); + } else { + cheats_repos_uri.push(folder_path.clone()); + } + + cheats_repos_paths.push(folder_path); + } + } + } + + (cheats_repos_uri, cheats_repos_paths) +} + pub fn tmp_pathbuf() -> Result { let mut root = default_cheat_pathbuf()?; root.push("tmp");