use chrono::Local; use git2::{Cred, Error, IndexAddOption, PushOptions, RemoteCallbacks, Repository, StatusOptions}; use keyring::Entry; use std::path::Path; pub fn current_change_count(repo_path: &Path) -> Result { // Open the repository at the provided path let repo = Repository::open(repo_path)?; // Gather the repository statuses, including untracked files let mut status_opts = StatusOptions::new(); status_opts.include_untracked(true); let statuses = repo.statuses(Some(&mut status_opts))?; Ok(statuses.len()) } pub fn backup_changes(repo_path: &Path) -> Result<(), Box> { // Open the repository at the provided path let repo = Repository::open(repo_path)?; // Gather the repository statuses, including untracked files let mut status_opts = StatusOptions::new(); status_opts.include_untracked(true); let statuses = repo.statuses(Some(&mut status_opts))?; // If no changes are detected, exit early if statuses.is_empty() { println!("No changes detected"); return Ok(()); } // Print out all changes println!("Detected changes: {:?}", statuses.len()); for entry in statuses.iter() { let path = entry.path().unwrap_or(""); let status = entry.status(); println!(" - {}: {:?}", path, status); } // Add all changes to the index let mut index = repo.index()?; index.add_all(["*"].iter(), IndexAddOption::DEFAULT, None)?; index.write()?; // Write the index to a tree let tree_id = index.write_tree()?; let tree = repo.find_tree(tree_id)?; // Use the repository signature for both author and committer let signature = repo.signature()?; // Determine the parent commit let parent_commit = repo.head()?.peel_to_commit()?; // Generate commit message with current timestamp let commit_message = format!("{} Autobackup", Local::now().format("%Y-%m-%d %H:%M:%S")); // Create commit repo.commit( Some("HEAD"), &signature, &signature, &commit_message, &tree, &[&parent_commit], )?; // // Set up remote push with credentials callback // let mut callbacks = RemoteCallbacks::new(); // callbacks.credentials(move |_url, username, _allowed_types| { // let user = username.unwrap_or("git"); // let token = get_git_token(); // Cred::userpass_plaintext(user, &token) // }); // // Push changes // let mut push_options = PushOptions::new(); // push_options.remote_callbacks(callbacks); // let mut remote = repo.find_remote("origin")?; // remote.push(&["refs/heads/main"], Some(&mut push_options))?; println!("Changes committed and pushed successfully."); Ok(()) } fn get_git_token() -> String { // Get token from Windows Credential Manager let service = "obsidian-git-backup"; // git.obsidian-git-backup in Credetial Manager let username = "git"; let entry = Entry::new(service, username).unwrap(); entry .get_password() .expect("Git access token could not be retrieved from Windows Credential Manager") }