1
0
Fork 0
tplp-planning-benchmark/benchmark-new/benchmark_repository/src/lib.rs

296 lines
8.4 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

extern crate git2;
extern crate pretty_env_logger;
#[macro_use]
extern crate log;
extern crate indicatif;
use git2::{Cred, Error, FetchOptions, Progress, PushOptions, RemoteCallbacks, ResetType, Repository, Signature, TreeBuilder};
use git2::build::{CheckoutBuilder, RepoBuilder};
use std::fs::read;
use std::path::Path;
use std::string::String;
use std::str;
use indicatif::{ProgressBar, ProgressStyle};
pub struct BenchmarkRepository
{
repository: Repository,
ssh_user: String,
user_name: String,
user_email: String,
}
impl BenchmarkRepository
{
fn progress_bar_style() -> ProgressStyle
{
ProgressStyle::default_bar()
.template("{bar:74.on_black} {percent:>3} %")
.progress_chars("█▉▊▋▌▍▎▏ ")
}
fn transfer_progress_callback(progress: Progress, progress_bar: &mut ProgressBar) -> bool
{
progress_bar.set_length(progress.total_objects() as u64);
progress_bar.set_position(progress.received_objects() as u64);
// continue the transfer
true
}
fn push_update_reference_callback(reference: &str, status: Option<&str>) -> Result<(), Error>
{
match status
{
None => trace!("Reference “{}” pushed successfully to remote “origin”", reference),
Some(error) => panic!("Couldnt push reference “{}” to remote “origin”: {}", reference, error),
};
Ok(())
}
fn checkout_progress_callback(path: Option<&Path>, current: usize, total: usize, progress_bar: &mut ProgressBar)
{
progress_bar.set_length(total as u64);
progress_bar.set_position(current as u64);
}
fn reset_origin(&self, remote_url: &str) -> &Self
{
let remote = match self.repository.find_remote("origin")
{
Ok(remote) => remote,
Err(_) =>
match self.repository.remote("origin", remote_url)
{
Ok(remote) => remote,
Err(error) => panic!("Could not reset remote “origin”: {}", error),
},
};
info!("Reset origin to “{}”", remote_url);
self
}
fn fetch_branch(&self, branch_name: &str) -> &Self
{
let mut progress_bar = ProgressBar::new(0);
progress_bar.set_style(BenchmarkRepository::progress_bar_style());
{
let mut remote_callbacks = RemoteCallbacks::new();
remote_callbacks.credentials(
|_, _, _|
{
match Cred::ssh_key_from_agent(&self.ssh_user)
{
Ok(credentials) => Ok(credentials),
Err(error) => panic!("could not retrieve key pair for SSH authentication as user “{}”: {}", self.ssh_user, error),
}
});
remote_callbacks.transfer_progress(
|progress| BenchmarkRepository::transfer_progress_callback(progress, &mut progress_bar));
let mut fetch_options = FetchOptions::new();
fetch_options.remote_callbacks(remote_callbacks);
let mut origin = self.repository.find_remote("origin").expect("could not find remote “origin”");
info!("Updating branch “{}”", branch_name);
if let Err(error) = origin.fetch(&[branch_name], Some(&mut fetch_options), None)
{
panic!("failed to fetch branch “{}” from remote “origin”: {}", branch_name, error);
}
}
progress_bar.finish_and_clear();
trace!("Branch “{}” is up-to-date", branch_name);
self
}
fn update_branch_storage(&self, branch_name: &str) -> &Self
{
self.fetch_branch(branch_name);
let mut progress_bar = ProgressBar::new(0);
progress_bar.set_style(BenchmarkRepository::progress_bar_style());
{
let mut checkout_builder = CheckoutBuilder::new();
let workdir = self.repository.path().parent().expect("invalid repository storage path");
let branch_storage_path = workdir.join(branch_name);
checkout_builder.force();
checkout_builder.target_dir(&branch_storage_path);
checkout_builder.progress(
|path, current, total| BenchmarkRepository::checkout_progress_callback(path, current, total, &mut progress_bar));
let object_id = match self.repository.refname_to_id(&format!("refs/remotes/origin/{}", branch_name))
{
Ok(object_id) => object_id,
Err(error) => panic!("could not look up branch “{}” from remote “origin”: {}", branch_name, error),
};
let object = match self.repository.find_object(object_id, None)
{
Ok(object) => object,
Err(error) => panic!("could not retrieve branch “{}” from remote “origin”: {}", branch_name, error),
};
info!("Updating branch storage “{}”", branch_name);
if let Err(error) = self.repository.checkout_tree(&object, Some(&mut checkout_builder))
{
panic!("failed to update branch storage for “{}”: {}", branch_name, error);
}
}
progress_bar.finish_and_clear();
trace!("Branch storage “{}” is up-to-date", branch_name);
self
}
fn init(base_path: &Path) -> Repository
{
let repository = match Repository::init_bare(base_path)
{
Ok(repository) => repository,
Err(error) => panic!("failed to initialize Git repository in “{}”: {}", base_path.display(), error),
};
info!("Initialized Git repository in “{}”", base_path.display());
repository
}
pub fn new(remote_url: &str, base_path: &Path, ssh_user: &str, user_name: &str, user_email: &str) -> BenchmarkRepository
{
let repository = match Repository::open(base_path)
{
Ok(repository) =>
{
info!("Using existing Git repository");
repository
},
Err(_) => BenchmarkRepository::init(base_path),
};
let benchmark_repository =
BenchmarkRepository
{
repository: repository,
ssh_user: ssh_user.to_string(),
user_name: user_name.to_string(),
user_email: user_email.to_string(),
};
benchmark_repository
.reset_origin(remote_url)
.fetch_branch("test-config")
.fetch_branch("test-results")
.fetch_branch("test-status");
benchmark_repository
}
pub fn commit_file(&self, file_path: &Path, result_file_path: &Path, branch_name: &str)
{
let reference_name = format!("refs/remotes/origin/{}", branch_name);
let reference = match self.repository.find_reference(&reference_name)
{
Ok(value) => value,
Err(error) => panic!("Could not find reference “{}”: {}", reference_name, error),
};
// create a new blob with the file contents
let object_id = match self.repository.blob_path(file_path)
{
Ok(object_id) => object_id,
Err(error) => panic!("Could not write blob for “{}”: {}", file_path.display(), error),
};
info!("Created object “{}” from “{}”", object_id, file_path.display());
let parent_tree = match reference.peel_to_tree()
{
Ok(value) => value,
Err(error) => panic!("Could not peel reference to tree: {}", error),
};
let mut tree_builder = match self.repository.treebuilder(Some(&parent_tree))
{
Ok(tree_builder) => tree_builder,
Err(error) => panic!("Could not obtain tree builder: {}", error),
};
tree_builder.insert("foobartest/test2/foobar", object_id, 0o100644);
let tree_object_id = match tree_builder.write()
{
Ok(value) => value,
Err(error) => panic!("Could not write tree: {}", error),
};
let tree = match self.repository.find_tree(tree_object_id)
{
Ok(value) => value,
Err(error) => panic!("Could obtain tree: {}", error),
};
info!("Created tree object “{}”", tree_object_id);
let signature = Signature::now(&self.user_name, &self.user_email).expect("Could not create signature");
let message = format!("Add file “{}", result_file_path.display());
let parent = match reference.peel_to_commit()
{
Ok(value) => value,
Err(error) => panic!("Could not peel reference: {}", error),
};
let commit_id = match self.repository.commit(Some(&reference_name), &signature, &signature, &message, &tree, &[&parent])
{
Ok(value) => value,
Err(error) => panic!("Could not write commit: {}", error),
};
let push_refspec = format!("refs/remotes/origin/{}:refs/heads/{}", branch_name, branch_name);
trace!("Created commit “{}”, using refspec “{}”", commit_id, push_refspec);
let mut remote_callbacks = RemoteCallbacks::new();
remote_callbacks.credentials(
|_, _, _|
{
match Cred::ssh_key_from_agent(&self.ssh_user)
{
Ok(credentials) => Ok(credentials),
Err(error) => panic!("could not retrieve key pair for SSH authentication as user “{}”: {}", self.ssh_user, error),
}
});
remote_callbacks.push_update_reference(
|reference, status| BenchmarkRepository::push_update_reference_callback(reference, status));
let mut push_options = PushOptions::new();
push_options.remote_callbacks(remote_callbacks);
let mut remote = self.repository.find_remote("origin").expect("");
remote.push(&[&push_refspec], Some(&mut push_options)).expect("couldnt push");
}
}
#[cfg(test)]
mod tests
{
}