Skip to content

Commit

Permalink
feat: basic deltas extraction
Browse files Browse the repository at this point in the history
  • Loading branch information
wzslr321 committed Oct 9, 2024
1 parent 9e6ab20 commit b41f885
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 23 deletions.
26 changes: 18 additions & 8 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,17 +69,12 @@ struct Args {
tracing_level: u8,
}

// TODO add more credentials variants
pub enum Credentials<'a> {
UsernamePassword {
username: &'a str,
password: &'a str,
},
SshKey {
username: String,
public_key_path: String,
private_key_path: String,
passphrase: Option<String>,
},
}

pub fn run() -> Result<(), CliError> {
Expand Down Expand Up @@ -132,7 +127,22 @@ pub fn run() -> Result<(), CliError> {
},
};

let _ = extract_difference(&repository);
let credentials = Credentials::UsernamePassword {
username: "wzslr321",
password: "TEST",
};

crate::git::fetch_remote(&repository, "origin", &credentials).unwrap();

let diff = extract_difference(
&repository,
&crate::git::DiffOptions::Branches {
from: &args.from_branch.unwrap(),
to: &args.to_branch.unwrap_or_else(|| "main".to_string()),
},
);

println!("{:?}", diff);

Ok(())
}
Expand Down Expand Up @@ -199,7 +209,7 @@ fn try_retrieve_repo_from_url(

let credentials = Credentials::UsernamePassword {
username,
password: &access_token.unwrap_or_else(|| "OnlyForTesting".to_string()), // expect("access_token must be specified, as it is the only supported authentication method for now"),
password: &access_token.unwrap_or_else(|| "OnlyForTesting".to_string()), // ehttps://www.twitch.tv/directory/followingxpect("access_token must be specified, as it is the only supported authentication method for now"),
};
let cloned_repo = match clone_repo(&credentials, url, &clone_into_path) {
Ok(repo) => repo,
Expand Down
91 changes: 76 additions & 15 deletions src/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::path::Path;
use thiserror::Error;

use git2::{Cred, RemoteCallbacks, Repository};
use std::str;
use tracing::{error, info, trace};
use url::Url;

Expand All @@ -28,10 +29,81 @@ pub enum GitError {
// Unknown { err: Box<dyn std::error::Error> },
}

pub struct FileDiff {}
#[derive(Debug)]
pub struct Diff {
pub deltas: Vec<FileDelta>,
}

#[derive(Debug)]
pub struct FileDelta {
pub value: String,
}

impl FileDelta {
fn from(value: String) -> Self {
Self { value }
}
}

pub enum DiffOptions<'a> {
Branches { from: &'a str, to: &'a str },
}

pub fn extract_difference(repo: &Repository, options: &DiffOptions) -> anyhow::Result<Diff> {
match options {
DiffOptions::Branches { from, to } => extract_difference_branches(repo, from, to),
}
}

pub fn fetch_remote(repo: &Repository, remote_name: &str, credentials: &Credentials) -> anyhow::Result<()> {
// Find the remote
let mut remote = repo.find_remote(remote_name)?;

// Set up callbacks for authentication (if needed)
let mut cb = RemoteCallbacks::new();
cb.credentials(|_url, _username_from_url, _allowed_types| credentials.into());

// Configure fetch options with the callbacks
let mut fetch_options = git2::FetchOptions::new();
fetch_options.remote_callbacks(cb);

// Define the refspecs to fetch. Here, we fetch all branches.
let refspecs = ["+refs/heads/*:refs/remotes/origin/*"];

// Perform the fetch
remote.fetch(&refspecs, Some(&mut fetch_options), None)?;

Ok(())
}

pub fn extract_difference_branches(
repo: &Repository,
from_branch: &str,
to_branch: &str,
) -> anyhow::Result<Diff> {
let ref_from = repo.find_reference(&format!("refs/heads/{}", from_branch))?;
let ref_to = repo.find_reference(&format!("refs/remotes/origin/{}", to_branch))?;

let commit_a = ref_from.peel_to_commit()?;
let commit_b = ref_to.peel_to_commit()?;

let tree_a = commit_a.tree()?;
let tree_b = commit_b.tree()?;

let diff = repo.diff_tree_to_tree(Some(&tree_a), Some(&tree_b), None)?;
let mut diff_output = Vec::new();
diff.print(git2::DiffFormat::Patch, |_delta, _hunk, line| {
diff_output.extend_from_slice(line.content());
true
})?;

let diff_str = str::from_utf8(&diff_output)
.map_err(|e| git2::Error::from_str(&format!("UTF-8 conversion error: {}", e)))?
.to_string();

pub fn extract_difference(_repo: &Repository) -> Result<Vec<FileDiff>, GitError> {
todo!()
Ok(Diff {
deltas: vec![FileDelta::from(diff_str)],
})
}

pub fn open_repo(path: &Path) -> Result<Repository, GitError> {
Expand All @@ -58,17 +130,6 @@ impl Credentials<'_> {
Credentials::UsernamePassword { username, password } => {
Cred::userpass_plaintext(&username, &password)
}
Credentials::SshKey {
username,
public_key_path,
private_key_path,
passphrase,
} => Cred::ssh_key(
&username,
Some(Path::new(public_key_path)),
Path::new(private_key_path),
passphrase.as_deref(),
),
};

match credentials {
Expand Down Expand Up @@ -114,7 +175,7 @@ pub fn clone_repo(
let err = match e.code() {
git2::ErrorCode::Auth => GitError::NoAccess { err: e },
_ => GitError::CloneFailure {
url: url.to_string(),
url: url.to_string(),
path: String::from(clone_into.to_string_lossy()),
err: e,
},
Expand Down

0 comments on commit b41f885

Please sign in to comment.