From 5f4abc7c7312d08dcd981a554a9ba6dac3deeb60 Mon Sep 17 00:00:00 2001 From: alexis-opolka Date: Thu, 12 Mar 2026 13:48:27 +0100 Subject: [PATCH] feat: Fixes small issues and added the sync command Signed-off-by: alexis-opolka --- src/commands/repo/add.rs | 3 +-- src/commands/repo/sync.rs | 57 +++++++++++++++++++++++++-------------- src/common/git.rs | 43 +++++++++++++++++++++-------- 3 files changed, 70 insertions(+), 33 deletions(-) diff --git a/src/commands/repo/add.rs b/src/commands/repo/add.rs index a94e97e..b158517 100644 --- a/src/commands/repo/add.rs +++ b/src/commands/repo/add.rs @@ -162,8 +162,7 @@ pub fn main(uri: String, yes_flag: bool, branch: &Option) -> Result<()> })?; } - println!("Temp cheats folder: {:?}", &tmp_repository_path_str); - println!("Final cheats folder: {:?}", cheat_pathbuf.to_string()); + fs::remove_dir_all(&tmp_repository_pathbuf).with_context(|| format!("Unable to delete {}", &tmp_repository_path_str))?; Ok(()) } diff --git a/src/commands/repo/sync.rs b/src/commands/repo/sync.rs index 84d8897..cc80c5b 100644 --- a/src/commands/repo/sync.rs +++ b/src/commands/repo/sync.rs @@ -1,10 +1,10 @@ -use crate::common::git; +use std::fs; +use std::path::MAIN_SEPARATOR; use crate::filesystem::{all_cheat_files, all_git_files, local_cheatsheet_repositories}; use crate::prelude::*; use git2::Repository; -use std::{fs, path}; -use walkdir::WalkDir; +use crate::common::git::reset_to_remote_state; use crate::commands::repo::{HELP_NO_GIVEN_REPOSITORIES_FOUND, HELP_NO_REPOSITORIES_FOUND}; pub fn main(uri: Option) -> Result<()> { @@ -21,19 +21,13 @@ pub fn main(uri: Option) -> Result<()> { if uri.is_some() { let given_uri = uri.as_ref().unwrap(); - // let repository = cheat_repos.iter() - // .filter(|repository| repository == &given_uri) - // .next(); + let repository = cheat_repos.iter() + .filter(|repository| repository.uri().eq(given_uri)) + .next().unwrap(); - println!("Repo: {given_uri:#}"); + let repository_object = Repository::open(repository.path())?; - // repository.map(|_| { - // let cheat_repo_index = cheats_repo_uris.iter().position(|repository| repository == given_uri); - // let given_repository = Repository::open(Path::new(cheats_repo_paths.get(cheat_repo_index.unwrap()).unwrap())); - // let repo_object = given_repository.as_ref().unwrap(); - // - // synchronize(repo_object).expect("Unable to sync repository"); - // }).expect(format!("{}", HELP_NO_GIVEN_REPOSITORIES_FOUND).as_str()); + synchronize(&repository_object).expect("Unable to sync repository"); return Ok(()); } @@ -50,13 +44,36 @@ pub fn main(uri: Option) -> Result<()> { } fn synchronize(cheat_repo: &Repository) -> Result<()> { - let cheat_path = cheat_repo.path(); - eprintln!("Checking repo {:?}", &cheat_path); + let repo_path = cheat_repo.path().parent().unwrap(); - // We retrieve all existing cheat files - let cheat_files = all_cheat_files(&cheat_path); - let git_files = all_git_files(cheat_path); - let mut cheat_dirs: Vec = Vec::new(); + // 1 - Before doing an actual reset, we remove the current cheatsheets + let mut cheat_files = all_cheat_files(repo_path); + + for cheat_file in cheat_files { + + fs::remove_file(Path::new(cheat_file.as_str())) + .with_context(|| format!("Unable to remove {}", cheat_file))?; + } + + // 2 - We reset the repository to its remote equivalent + reset_to_remote_state(cheat_repo)?; + + // 3 - We reshuffle the files + cheat_files = all_cheat_files(repo_path); + + for cheat_file in cheat_files { + let source = Path::new(cheat_file.as_str()); + + let filename = cheat_file.replace(&format!("{}", &repo_path.to_str().unwrap()), "") + .replace(MAIN_SEPARATOR, "__"); + + let destination = repo_path.join(filename); + println!("[Repo::sync](DEBUG) - {} => {:?}", cheat_file, destination); + + fs::copy(source, &destination).with_context(|| format!("Unable to copy {} to {}", cheat_file, destination.display()))?; + + fs::remove_file(source).with_context(|| format!("Unable to remove {}", cheat_file))?; + } Ok(()) } diff --git a/src/common/git.rs b/src/common/git.rs index 4fafca4..1315a3f 100644 --- a/src/common/git.rs +++ b/src/common/git.rs @@ -1,8 +1,8 @@ use crate::common::shell::ShellSpawnError; use crate::filesystem::remove_dir; use crate::prelude::*; -use git2::Repository; -use std::fmt::Error; +use git2::{BranchType, Repository, ResetType}; +use std::fmt::{Display, Error, Formatter}; use std::process::Command; pub struct CheatRepositoryRecord { @@ -33,6 +33,12 @@ impl CheatRepositoryRecord { } } +impl Display for CheatRepositoryRecord { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{} -> {}", self.uri, self.path) + } +} + pub fn shallow_clone(remote_uri: &str, target: &str, branch: &Option, overwrite: bool) -> Result<()> { let target_path = PathBuf::from(target); @@ -54,18 +60,15 @@ pub fn shallow_clone(remote_uri: &str, target: &str, branch: &Option, ov ); } - println!("Cloning {} to {}", remote_uri, target); - let repository = - Repository::clone(remote_uri, target).expect(format!("Failed to clone {}", remote_uri).as_str()); - + // Prepare fetch options. + let mut builder = git2::build::RepoBuilder::new(); if branch.is_some() { - let branch = branch.as_ref().unwrap(); - repository - .set_head(branch) - .context("Failed to set the HEAD to the given branch") - .expect("Failed to set the HEAD to the given branch"); + builder.branch(branch.as_ref().unwrap()); } + println!("Cloning {} to {}", remote_uri, target); + builder.clone(remote_uri, target.as_ref()).expect(format!("Failed to clone {}", remote_uri).as_str()); + Ok(()) } @@ -111,6 +114,24 @@ pub fn get_remote_uri(repository: Repository) -> String { returned_remotes.get(0).unwrap().to_string() } +/// Takes a repository instance and updates it to its remote equivalent with a hard reset. +/// +/// 3 steps function: +/// - Fetch latest tree state +/// - Grabs the latest commit ID +/// - hard reset to the latest commit +pub fn reset_to_remote_state(repository: &Repository) -> Result<()> { + repository.find_remote("origin")?.fetch(&["main"], None, None)?; + + // Get the latest commit ID from the remote branch (origin/main) + let latest_commit_id = repository.find_branch("origin/main", BranchType::Remote)?.into_reference().peel_to_commit()?; + + // Hard reset onto this commit + repository.reset(latest_commit_id.as_object(), ResetType::Hard, None)?; + + Ok(()) +} + #[cfg(test)] mod tests { use super::*;