Compare commits

...

3 Commits

Author SHA1 Message Date
Robin Gottschalk
48e5d8048a Silence git command output to prevent cmd window to spawn 2025-03-22 12:43:22 +01:00
Robin Gottschalk
a429f9a496 Remove console window from release builds 2025-03-14 09:33:55 +01:00
Robin Gottschalk
8d149e201c Replaced git2 crate add to index, commit and push with calls to git cli and changed delay to 30 min 2025-03-14 09:05:20 +01:00
5 changed files with 39 additions and 68 deletions

18
Cargo.lock generated
View File

@ -168,12 +168,6 @@ version = "1.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]] [[package]]
name = "bytes" name = "bytes"
version = "1.9.0" version = "1.9.0"
@ -1135,17 +1129,6 @@ dependencies = [
"unicode-segmentation", "unicode-segmentation",
] ]
[[package]]
name = "keyring"
version = "3.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f8fe839464d4e4b37d756d7e910063696af79a7e877282cb1825e4ec5f10833"
dependencies = [
"byteorder",
"log",
"windows-sys 0.59.0",
]
[[package]] [[package]]
name = "kqueue" name = "kqueue"
version = "1.0.8" version = "1.0.8"
@ -1664,7 +1647,6 @@ version = "0.1.0"
dependencies = [ dependencies = [
"chrono", "chrono",
"git2", "git2",
"keyring",
"notify", "notify",
"tray-icon", "tray-icon",
"winit", "winit",

View File

@ -9,4 +9,3 @@ notify = "8.0.0"
tray-icon = "0.19.2" tray-icon = "0.19.2"
git2 = "0.20.0" git2 = "0.20.0"
chrono = "0.4.39" chrono = "0.4.39"
keyring = { version = "3.6.1", features = ["windows-native"] }

View File

@ -7,6 +7,7 @@ This script automates the process of backing up your Obsidian vault to a Git rep
- [x] Trigger backup after file changes with delay - [x] Trigger backup after file changes with delay
- [x] Maintain git repo in a seperate folder to not have the repo synced by syncthing (copy changed files over) - [x] Maintain git repo in a seperate folder to not have the repo synced by syncthing (copy changed files over)
- [x] Push changes to remote repository - [x] Push changes to remote repository
- [x] Make adding and pushing LFS objects work with git
- [x] Tray Menu - [x] Tray Menu
- [x] Exit - [x] Exit
- [x] Backup now - [x] Backup now
@ -30,3 +31,4 @@ This script automates the process of backing up your Obsidian vault to a Git rep
*.svg filter=lfs diff=lfs merge=lfs -text *.svg filter=lfs diff=lfs merge=lfs -text
``` ```
- Link repository to origin as remote - Link repository to origin as remote
- Make sure the underlying system has the git user set up with the corresponding access token

View File

@ -1,7 +1,7 @@
use chrono::Local; use chrono::Local;
use git2::{Cred, Error, IndexAddOption, PushOptions, RemoteCallbacks, Repository, StatusOptions}; use git2::{Error, Repository, StatusOptions};
use keyring::Entry;
use std::path::Path; use std::path::Path;
use std::process::{Command, Stdio};
pub fn current_change_count(repo_path: &Path) -> Result<usize, Error> { pub fn current_change_count(repo_path: &Path) -> Result<usize, Error> {
// Open the repository at the provided path // Open the repository at the provided path
@ -38,58 +38,44 @@ pub fn backup_changes(repo_path: &Path) -> Result<(), Box<dyn std::error::Error>
println!(" - {}: {:?}", path, status); println!(" - {}: {:?}", path, status);
} }
// Add all changes to the index // Stage all changes using the Git CLI
let mut index = repo.index()?; let status = Command::new("git")
index.add_all(["*"].iter(), IndexAddOption::DEFAULT, None)?; .arg("add")
index.write()?; .arg("-A")
.current_dir(repo_path)
// Write the index to a tree .stdout(Stdio::null())
let tree_id = index.write_tree()?; .status()?;
let tree = repo.find_tree(tree_id)?; if !status.success() {
return Err("git add failed".into());
// 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 // Generate commit message with current timestamp
let commit_message = format!("{} Autobackup", Local::now().format("%Y-%m-%d %H:%M:%S")); let commit_message = format!("{} Autobackup", Local::now().format("%Y-%m-%d %H:%M:%S"));
// Create commit // Create a commit with a timestamped message
repo.commit( let status = Command::new("git")
Some("HEAD"), .arg("commit")
&signature, .arg("-m")
&signature, .arg(&commit_message)
&commit_message, .current_dir(repo_path)
&tree, .stdout(Stdio::null())
&[&parent_commit], .status()?;
)?; if !status.success() {
return Err("git commit failed".into());
}
// Set up remote push with credentials callback // Push changes with Git CLI
let mut callbacks = RemoteCallbacks::new(); let status = Command::new("git")
callbacks.credentials(move |_url, username, _allowed_types| { .arg("push")
let user = username.unwrap_or("git"); .arg("origin")
let token = get_git_token(); .arg("main")
Cred::userpass_plaintext(user, &token) .current_dir(repo_path)
}); .stdout(Stdio::null())
.status()?;
// Push changes if !status.success() {
let mut push_options = PushOptions::new(); return Err("git push failed".into());
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."); println!("Changes committed and pushed successfully.");
Ok(()) 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")
}

View File

@ -1,3 +1,5 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
use notify::{Event, RecursiveMode, Watcher}; use notify::{Event, RecursiveMode, Watcher};
use std::path::Path; use std::path::Path;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
@ -19,7 +21,7 @@ const PROTECT_PREFIX: &str = ".git"; // only at first directory level
const SOURCE_VAULT: &str = "D:\\Cloud\\Syncthing\\obsidian-vault"; // syncthing vault folder const SOURCE_VAULT: &str = "D:\\Cloud\\Syncthing\\obsidian-vault"; // syncthing vault folder
const REPO_VAULT: &str = const REPO_VAULT: &str =
"C:\\Users\\robin\\AppData\\Roaming\\obsidian-git-backup\\obsidian-vault-clone"; // git repo folder "C:\\Users\\robin\\AppData\\Roaming\\obsidian-git-backup\\obsidian-vault-clone"; // git repo folder
const GIT_COMMIT_DELAY_AFTER_FILE_CHANGE: Duration = Duration::from_secs(5 * 60); // 5 min const GIT_COMMIT_DELAY_AFTER_FILE_CHANGE: Duration = Duration::from_secs(30 * 60); // 30 min
#[derive(Debug)] #[derive(Debug)]
enum UserEvent { enum UserEvent {