From 3b72d2e5f7922956f333e1d0d721d8a8a2d9e3a1 Mon Sep 17 00:00:00 2001 From: Jordon Brooks Date: Tue, 24 Jun 2025 16:32:26 +0100 Subject: [PATCH] Implement VCS trait and GitVcs struct with repository management functions; update Cargo.toml and Cargo.lock for new dependencies --- src-tauri/Cargo.lock | 93 +++++++++++++++++++++++++++++++++ src-tauri/Cargo.toml | 2 + src-tauri/src/lib.rs | 11 ++-- src-tauri/src/tauri_commands.rs | 19 +++++++ src-tauri/src/vcs/git.rs | 66 +++++++++++++++++++++++ src-tauri/src/vcs/mod.rs | 3 ++ src-tauri/src/vcs/vcs.rs | 18 +++++++ 7 files changed, 206 insertions(+), 6 deletions(-) create mode 100644 src-tauri/src/tauri_commands.rs create mode 100644 src-tauri/src/vcs/git.rs create mode 100644 src-tauri/src/vcs/mod.rs create mode 100644 src-tauri/src/vcs/vcs.rs diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 4ccf953..c2726e2 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -433,6 +433,8 @@ version = "1.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" dependencies = [ + "jobserver", + "libc", "shlex", ] @@ -1274,6 +1276,21 @@ dependencies = [ "winapi", ] +[[package]] +name = "git2" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110" +dependencies = [ + "bitflags 2.9.1", + "libc", + "libgit2-sys", + "log", + "openssl-probe", + "openssl-sys", + "url", +] + [[package]] name = "glib" version = "0.18.5" @@ -1793,6 +1810,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +[[package]] +name = "jobserver" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +dependencies = [ + "getrandom 0.3.3", + "libc", +] + [[package]] name = "js-sys" version = "0.3.77" @@ -1885,6 +1912,20 @@ version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +[[package]] +name = "libgit2-sys" +version = "0.18.2+1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c42fe03df2bd3c53a3a9c7317ad91d80c81cd1fb0caec8d7cc4cd2bfa10c222" +dependencies = [ + "cc", + "libc", + "libssh2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", +] + [[package]] name = "libloading" version = "0.7.4" @@ -1905,6 +1946,32 @@ dependencies = [ "libc", ] +[[package]] +name = "libssh2-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "220e4f05ad4a218192533b300327f5150e809b54c4ec83b5a1d91833601811b9" +dependencies = [ + "cc", + "libc", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "libz-sys" +version = "1.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linux-raw-sys" version = "0.9.4" @@ -2354,15 +2421,35 @@ dependencies = [ "pathdiff", ] +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "openvcs" version = "0.1.0" dependencies = [ + "git2", "serde", "serde_json", "tauri", "tauri-build", "tauri-plugin-opener", + "thiserror 2.0.12", ] [[package]] @@ -4195,6 +4282,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version-compare" version = "0.2.0" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index c6c35e1..b0b69fc 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -31,4 +31,6 @@ tauri = { version = "2", features = [] } tauri-plugin-opener = "2" serde = { version = "1", features = ["derive"] } serde_json = "1" +git2 = "0.20.2" +thiserror = "2.0.12" diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 4a277ef..bac60e7 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,14 +1,13 @@ -// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/ -#[tauri::command] -fn greet(name: &str) -> String { - format!("Hello, {}! You've been greeted from Rust!", name) -} +mod vcs; +mod tauri_commands; #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { + println!("Running OpenVCS..."); + tauri::Builder::default() .plugin(tauri_plugin_opener::init()) - .invoke_handler(tauri::generate_handler![greet]) + .invoke_handler(tauri::generate_handler![tauri_commands::greet]) .run(tauri::generate_context!()) .expect("error while running tauri application"); } diff --git a/src-tauri/src/tauri_commands.rs b/src-tauri/src/tauri_commands.rs new file mode 100644 index 0000000..e4d7890 --- /dev/null +++ b/src-tauri/src/tauri_commands.rs @@ -0,0 +1,19 @@ +use std::{path::{PathBuf}, sync::Arc}; +use crate::vcs::vcs::Vcs; + +#[tauri::command] +pub fn greet(name: &str) -> String { + format!("Hello, {}! You've been greeted from Rust!", name) +} + +#[tauri::command] +pub async fn init_repo(path: String, state: tauri::State<'_, Arc>) -> Result<(), String> { + let p = PathBuf::from(path); + state.init_repo(&p).map_err(|e| e.to_string()) +} + +#[tauri::command] +pub async fn list_branches(path: String, state: tauri::State<'_, Arc>) -> Result, String> { + let p = PathBuf::from(path); + state.list_branches(&p).map_err(|e| e.to_string()) +} diff --git a/src-tauri/src/vcs/git.rs b/src-tauri/src/vcs/git.rs new file mode 100644 index 0000000..38b27f0 --- /dev/null +++ b/src-tauri/src/vcs/git.rs @@ -0,0 +1,66 @@ +use std::path::Path; +use git2::{Repository, BranchType}; +use crate::vcs::vcs::{Vcs, VcsError}; + +pub struct GitVcs; + +impl GitVcs { + #[allow(dead_code)] + pub fn new() -> Self { + GitVcs + } +} + +impl Vcs for GitVcs { + fn init_repo(&self, path: &Path) -> Result<(), VcsError> { + Repository::init(path)?; + Ok(()) + } + + fn clone_repo(&self, url: &str, path: &Path) -> Result<(), VcsError> { + Repository::clone(url, path)?; + Ok(()) + } + + fn list_branches(&self, path: &Path) -> Result, VcsError> { + let repo = Repository::open(path)?; + let mut names = Vec::new(); + for branch in repo.branches(Some(BranchType::Local))? { + let (branch, _) = branch?; + if let Some(name) = branch.name()? { + names.push(name.to_string()); + } + } + Ok(names) + } + + fn commit_all(&self, path: &Path, message: &str) -> Result<(), VcsError> { + let repo = Repository::open(path)?; + let mut index = repo.index()?; + index.add_all(["*"].iter(), git2::IndexAddOption::DEFAULT, None)?; + let tree_id = index.write_tree()?; + let tree = repo.find_tree(tree_id)?; + let sig = repo.signature()?; + let parent_commit = repo.head() + .and_then(|h| h.peel_to_commit()) + .ok(); + let parents = parent_commit.iter().collect::>(); + repo.commit( + Some("HEAD"), + &sig, + &sig, + message, + &tree, + &parents + )?; + Ok(()) + } + + fn push(&self, path: &Path, remote: &str, branch: &str) -> Result<(), VcsError> { + let repo = Repository::open(path)?; + let mut r = repo.find_remote(remote)?; + let refspec = format!("refs/heads/{}:refs/heads/{}", branch, branch); + r.push(&[&refspec], None)?; + Ok(()) + } +} diff --git a/src-tauri/src/vcs/mod.rs b/src-tauri/src/vcs/mod.rs new file mode 100644 index 0000000..a40457f --- /dev/null +++ b/src-tauri/src/vcs/mod.rs @@ -0,0 +1,3 @@ + +pub mod git; +pub mod vcs; diff --git a/src-tauri/src/vcs/vcs.rs b/src-tauri/src/vcs/vcs.rs new file mode 100644 index 0000000..c218d38 --- /dev/null +++ b/src-tauri/src/vcs/vcs.rs @@ -0,0 +1,18 @@ +use std::path::Path; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum VcsError { + #[error("IO error: {0}")] + Io(#[from] std::io::Error), + #[error("Git error: {0}")] + Git(#[from] git2::Error), +} + +pub trait Vcs: Send + Sync + 'static { + fn init_repo(&self, path: &Path) -> Result<(), VcsError>; + fn clone_repo(&self, url: &str, path: &Path) -> Result<(), VcsError>; + fn list_branches(&self, path: &Path) -> Result, VcsError>; + fn commit_all(&self, path: &Path, message: &str) -> Result<(), VcsError>; + fn push(&self, path: &Path, remote: &str, branch: &str) -> Result<(), VcsError>; +}