obsidian-git-backup/src/git.rs

96 lines
3.1 KiB
Rust

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<usize, Error> {
// 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<dyn std::error::Error>> {
// 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("<unknown>");
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")
}