use std::path::Path;
use git_url_parse::GitUrlParseError;
use thiserror::Error;
mod domain;
mod repository;
mod url;
pub use domain::{actor::Actor, commit::Commit, mfile::ModifiedFile};
pub use repository::{Local, Remote, Repository};
pub use url::GitUrl;
pub fn open_repository<P: AsRef<Path>>(p: P) -> Result<Repository<Local>, Error> {
Repository::<Local>::new(p)
}
pub fn clone_repository<P: AsRef<Path>>(
url: &str,
dest: Option<P>,
) -> Result<Repository<Local>, Error> {
Repository::<Remote>::new(url, dest)
}
#[derive(Debug, Error)]
pub enum Error {
#[error(transparent)]
Git(#[from] git2::Error),
#[error(transparent)]
Regex(#[from] regex::Error),
#[error(transparent)]
GitUrlError(#[from] GitUrlParseError),
#[error("URL scheme was {0}, cannot clone URL.")]
UrlScheme(String),
#[error("{0}")]
PathError(String),
}
#[cfg(test)]
mod common {
use once_cell::sync::Lazy;
use std::{fs, path::Path};
use tempfile::TempDir;
pub const EXPECTED_MSG: &str = "commit msg\n\nCo-authored-by: John Doe <john@example.com>\nCo-authored-by: John Doe <john@example.com>\nCo-authored-by: Dave <dave@example.com>";
pub const EXPECTED_ACTOR_NAME: &str = "test";
pub const EXPECTED_ACTOR_EMAIL: &str = "test@example.com";
fn write_fp(root: &TempDir, path: &str, content: &str) {
let fp = root.path().join(path);
fs::write(&fp, content).expect("Failed to write to file");
}
fn write_to_index(index: &mut git2::Index, file: &str) {
index
.add_path(Path::new(file))
.expect("Failed to add file to index");
index.write().expect("Failed to write index");
}
fn write_tree<'a>(
repo: &'a git2::Repository,
index: &mut git2::Index,
file: &str,
) -> git2::Tree<'a> {
write_to_index(index, file);
let tree_id = index.write_tree().expect("Failed to write tree");
repo.find_tree(tree_id).expect("Failed to find tree")
}
fn commit_file(
repo: &git2::Repository,
sig: &git2::Signature,
file: &str,
parent: Option<&git2::Commit<'_>>,
) -> git2::Oid {
let mut index = repo.index().expect("Failed to get index");
let tree = write_tree(repo, &mut index, file);
let parents = match parent {
Some(v) => vec![v],
None => vec![],
};
repo.commit(Some("HEAD"), sig, sig, EXPECTED_MSG, &tree, &parents)
.expect("Failed to create commit")
}
fn make_repo(tmpdir: &TempDir) {
let repo = git2::Repository::init(tmpdir.path()).expect("Failed to init repo");
let sig = git2::Signature::now(EXPECTED_ACTOR_NAME, EXPECTED_ACTOR_EMAIL)
.expect("Failed to create actor signature");
let file = "file.txt";
write_fp(tmpdir, file, "Hello World\n");
let first_commit_id = commit_file(&repo, &sig, file, None);
write_fp(tmpdir, file, "Hello World\nFile Update\n");
let parent = repo
.find_commit(first_commit_id)
.expect("Failed to find first commit");
commit_file(&repo, &sig, file, Some(&parent));
}
static TEST_DATA_DIR: Lazy<TempDir> = Lazy::new(|| {
let dir = TempDir::new().expect("Create temp dir");
make_repo(&dir);
dir
});
fn test_data_dir() -> &'static Path {
TEST_DATA_DIR.path()
}
pub fn init_repo() -> git2::Repository {
git2::Repository::open(test_data_dir()).expect("Failed to open temp repo")
}
}