Skip to content
Snippets Groups Projects
Select Git revision
  • 455ada3172ab850b9196c17c3baafa360d447b83
  • master default protected
  • doc
  • dev_doc
  • dev_push
  • dev
6 results

checkout.rs

Blame
  • 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);
            }
        }
    }