Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48e5d8048a | ||
|
|
a429f9a496 | ||
|
|
8d149e201c |
18
Cargo.lock
generated
18
Cargo.lock
generated
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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"] }
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
82
src/git.rs
82
src/git.rs
|
|
@ -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")
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user