96 lines
3.1 KiB
Rust
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")
|
|
}
|