Select Git revision
checkout.rs

nfontrod authored
checkout.rs 7.30 KiB
use crate::commit;
use std::{
path::PathBuf,
process::{exit, Command, Stdio},
};
/// Create a commit of the results folder named as the current git commit id
pub fn silent_commit(compression: String, mut commit_id: String, update: bool) {
let (borg_folder, results_folder) = commit::check_path();
let (has_ignore, borgignore) = commit::check_if_borgignore_exists(&borg_folder);
if commit_id == String::from("") {
commit_id = commit::get_current_commit();
}
if update {
commit::delete_commit(&commit_id, &borg_folder);
}
let mut margs: Vec<&str> = vec!["create", "--compression", &compression];
if has_ignore {
margs.push("--exclude-from");
margs.push(borgignore.to_str().unwrap());
}
let cmd_part = format!("{}::{}", borg_folder.to_str().unwrap(), commit_id);
margs.push(&cmd_part);
margs.push(results_folder.to_str().unwrap());
let output = Command::new("borg").args(margs).output().unwrap();
match output.status.code().unwrap() {
0 => (),
num => {
eprintln!("{}", String::from_utf8(output.stderr).unwrap());
exit(num);
}
}
}
/// Check if two commits are differents
pub fn is_diff(commit1: &str, commit2: &str, borg_folder: &PathBuf) -> bool {
let archive1 = format!("{}::{}", borg_folder.to_str().unwrap(), commit1);
let (has_ignore, borgignore) = commit::check_if_borgignore_exists(&borg_folder);
let cmd = match has_ignore {
false => format!("borg diff {} {}", archive1, commit2),
true => format!(
"borg diff --exclude-from {} {} {}",
borgignore.to_str().unwrap(),
archive1,
commit2
),
};
let output = Command::new("sh").arg("-c").arg(cmd).output().unwrap();
match output.status.code().unwrap() {
0 => (),
num => {
eprintln!("{}", String::from_utf8(output.stderr.clone()).unwrap());
exit(num);
}
}
let mut diff_files = String::from_utf8(output.stdout.clone()).unwrap();
if diff_files.ends_with('\n') {
diff_files.pop();
}
let res = diff_files
.split("\n")
.filter(|x| x.len() > 1)
.collect::<Vec<&str>>()
.len();
if res > 0 {
println!("{}\n", diff_files);
}
res > 0
}
/// Function that checks if the archive with the name of the current commit id
/// exits in borg repository
pub fn check_if_current_commit_exits(borg_path: &PathBuf, commit_id: &str) {
// Trying to create an archive with the current git commit id
let output = Command::new("borg")
.arg("list")
.arg(format!("{}::{}", borg_path.to_str().unwrap(), commit_id))
.output()
.unwrap();
match output.status.code().unwrap() {
0 => (),
num => {
let msg = format!("Archive {} does not exist", commit_id);
let mut output_msg = String::from_utf8(output.stderr).unwrap();
if output_msg.ends_with("\n") {
output_msg.pop();
}
if output_msg == msg {
eprintln!("{}\n{}\n{}",
"No archive with the current commit id found !",
"You should commit it first !",
"If you're using hooks and you want to force the chekout, run git conh [TARGET-BRANCH] && gblk checkout --mode hard"
);
exit(3);
} else {
eprintln!("{}", output_msg);
exit(num);
}
}
}
}
/// Function that prepare checkout. **This function should be used before a
/// git checkout !
///
/// # Description:
/// This function will check if the archive named as the current commit exits.
/// If it doesn't exists, it will create one. If it exists, it will create a
/// temporary archive of the current result respository and compare it with
/// the archive with the current git commit id.
/// If it is the same as the temporary achive then you can make a
/// checkout without losing data. If not, then you might.
pub fn prepare_checkout() {
let (borg_path, _) = commit::check_path();
let commit_id = commit::get_current_commit();
check_if_current_commit_exits(&borg_path, &commit_id);
// Create an archive with the content of the current commit
let tmp_name = format!("{}-tmp", commit_id);
silent_commit(String::from("none"), tmp_name.clone(), false);
let res = is_diff(&commit_id, &tmp_name, &borg_path);
commit::delete_commit(&tmp_name, &borg_path);
if res {
eprintln!(
"{}\n{}\n{}",
"Your results folder contains unsaved changes!",
"Please update your current commit with: gblk commit --update",
"Or revert it back to it's previous state with gblk commit --revert"
);
exit(4);
}
}
/// Remove content of the results folder that is not ignored
pub fn remove_results(borg_path: &PathBuf, results: &PathBuf) {
let (has_ignore, borgignore) = commit::check_if_borgignore_exists(&borg_path);
let cmd = if !has_ignore {
format!("rm -r {}/*", results.to_str().unwrap())
} else {
format!("find {} -name '*' -type f | egrep -v -f {} | xargs rm 2>> /dev/null; find results -name '*' -type d | xargs rm -d 2>> /dev/null", results.to_str().unwrap(), borgignore.to_str().unwrap())
};
let output = Command::new("sh").arg("-c").arg(cmd).output().unwrap();
println!("{}", String::from_utf8(output.stdout).unwrap());
match output.status.code().unwrap() {
0 => (),
123 => (),
1 => (),
num => {
eprintln!("{}", String::from_utf8(output.stderr).unwrap());
exit(num);
}
}
}
/// Function that perform a checkout on your results
pub fn checkout(mode: &str) {
let (borg_path, results) = commit::check_path();
let (has_ignore, borgignore) = commit::check_if_borgignore_exists(&borg_path);
if mode == "hard" {
remove_results(&borg_path, &results)
}
let commit_id = commit::get_current_commit();
let project_dir = borg_path
.canonicalize()
.unwrap()
.parent()
.unwrap()
.to_owned();
let temp = Command::new("pwd").output().unwrap();
match temp.status.code().unwrap() {
0 => (),
_ => {
eprintln!("{}", String::from_utf8(temp.stderr).unwrap());
exit(23);
}
};
let mut current_dir = String::from_utf8(temp.stdout.clone()).unwrap();
if current_dir.ends_with("\n") {
current_dir.pop();
}
if current_dir != project_dir.to_str().unwrap() {
eprintln!("Extraction can only happen if you are at the root of your project folder");
exit(47);
}
let progress_part = match has_ignore {
false => String::from("--progress"),
true => format!("--progress --exclude-from {}", borgignore.to_str().unwrap()),
};
let cmd = format!(
"borg extract {} {}::{}",
progress_part,
borg_path.to_str().unwrap(),
commit_id
);
let mut output = Command::new("sh")
.arg("-c")
.arg(cmd)
.stdout(Stdio::piped())
.spawn()
.unwrap();
let ecode = output.wait().expect("error");
match ecode.code().unwrap() {
0 => (),
num => {
//eprintln!("{}", ecode.to_string());
exit(num);
}
}
}