|
|
|
@ -1,23 +1,53 @@ |
|
|
|
|
use lazy_static::lazy_static; |
|
|
|
|
use sha1::{Digest, Sha1}; |
|
|
|
|
use std::fs; |
|
|
|
|
use std::path::Path; |
|
|
|
|
use std::str; |
|
|
|
|
use std::sync::Mutex; |
|
|
|
|
use walkdir::WalkDir; |
|
|
|
|
|
|
|
|
|
static RGIT_DIR: &'static str = ".rgit"; |
|
|
|
|
static BASE_RGIT_DIR: &'static str = ".rgit"; |
|
|
|
|
|
|
|
|
|
lazy_static! { |
|
|
|
|
static ref RGIT_DIR: Mutex<String> = Mutex::new(BASE_RGIT_DIR.to_owned()); |
|
|
|
|
static ref OLD_DIR: Mutex<String> = Mutex::new("".to_owned()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub struct RefValue { |
|
|
|
|
pub value: String, |
|
|
|
|
pub symbolic: bool, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// The below two methods are not the same thing as a "context manager"
|
|
|
|
|
// I might need to replace it later with a better alternative.
|
|
|
|
|
pub fn set_rgit_dir(path: &str) { |
|
|
|
|
let mut dir = RGIT_DIR.lock().unwrap(); |
|
|
|
|
let mut old_dir = OLD_DIR.lock().unwrap(); |
|
|
|
|
|
|
|
|
|
*old_dir = dir.to_string(); |
|
|
|
|
*dir = format!("{}/.rgit", path); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn reset_rgit_dir() { |
|
|
|
|
let mut dir = RGIT_DIR.lock().unwrap(); |
|
|
|
|
let mut old_dir = OLD_DIR.lock().unwrap(); |
|
|
|
|
if old_dir.to_string() == "" { |
|
|
|
|
*dir = BASE_RGIT_DIR.to_string().clone(); |
|
|
|
|
} else { |
|
|
|
|
*dir = old_dir.to_string(); |
|
|
|
|
*old_dir = "".to_string(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn init() -> std::io::Result<()> { |
|
|
|
|
fs::create_dir(RGIT_DIR)?; |
|
|
|
|
fs::create_dir(format!("{}/{}", RGIT_DIR, "objects"))?; |
|
|
|
|
let dir = RGIT_DIR.lock().unwrap().to_owned(); |
|
|
|
|
fs::create_dir(dir.clone())?; |
|
|
|
|
fs::create_dir(format!("{}/{}", dir, "objects"))?; |
|
|
|
|
Ok(()) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn hash_object(content: &Vec<u8>, _type: String) -> String { |
|
|
|
|
let dir = RGIT_DIR.lock().unwrap().to_owned(); |
|
|
|
|
let mut raw = format!("{}\u{0}", _type).into_bytes(); |
|
|
|
|
let mut data = content.clone(); |
|
|
|
|
raw.append(&mut data); |
|
|
|
@ -27,14 +57,15 @@ pub fn hash_object(content: &Vec<u8>, _type: String) -> String { |
|
|
|
|
let digest = &hasher.finalize(); |
|
|
|
|
let s = format!("{:x}", digest); |
|
|
|
|
|
|
|
|
|
fs::write(format!("{}/{}/{}", RGIT_DIR, "objects", s), raw.as_slice()) |
|
|
|
|
fs::write(format!("{}/{}/{}", dir, "objects", s), raw.as_slice()) |
|
|
|
|
.expect("Failed to write object"); |
|
|
|
|
|
|
|
|
|
return s; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn get_object(hash: String, expected: String) -> String { |
|
|
|
|
let mut content = fs::read_to_string(format!("{}/{}/{}", RGIT_DIR, "objects", hash)) |
|
|
|
|
let dir = RGIT_DIR.lock().unwrap().to_owned(); |
|
|
|
|
let mut content = fs::read_to_string(format!("{}/{}/{}", dir, "objects", hash)) |
|
|
|
|
.expect("Could not find a matching object"); |
|
|
|
|
|
|
|
|
|
let index = content.find(char::from(0)).expect("object type missing"); |
|
|
|
@ -50,6 +81,7 @@ pub fn get_object(hash: String, expected: String) -> String { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn update_ref(mut reference: String, value: RefValue, deref: bool) { |
|
|
|
|
let dir = RGIT_DIR.lock().unwrap().to_owned(); |
|
|
|
|
reference = get_ref_internal(reference, deref).0; |
|
|
|
|
let content: String; |
|
|
|
|
|
|
|
|
@ -60,7 +92,7 @@ pub fn update_ref(mut reference: String, value: RefValue, deref: bool) { |
|
|
|
|
content = value.value; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let path = format!("{}/{}", RGIT_DIR, reference); |
|
|
|
|
let path = format!("{}/{}", dir, reference); |
|
|
|
|
let mut parents = Path::new(&path).ancestors(); |
|
|
|
|
parents.next(); |
|
|
|
|
|
|
|
|
@ -74,11 +106,13 @@ pub fn get_ref(reference: String, deref: bool) -> RefValue { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn delete_ref(reference: String, deref: bool) { |
|
|
|
|
let dir = RGIT_DIR.lock().unwrap().to_owned(); |
|
|
|
|
let ref_to_del = get_ref_internal(reference, deref).0; |
|
|
|
|
fs::remove_file(format!("{}/{}", RGIT_DIR, ref_to_del)).unwrap(); |
|
|
|
|
fs::remove_file(format!("{}/{}", dir, ref_to_del)).unwrap(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn iter_refs(prefix: &str, deref: bool) -> Vec<(String, RefValue)> { |
|
|
|
|
let dir = RGIT_DIR.lock().unwrap().to_owned(); |
|
|
|
|
let mut refs: Vec<(String, RefValue)> = vec![]; |
|
|
|
|
|
|
|
|
|
refs.push(("HEAD".to_owned(), get_ref("HEAD".to_owned(), deref))); |
|
|
|
@ -87,12 +121,12 @@ pub fn iter_refs(prefix: &str, deref: bool) -> Vec<(String, RefValue)> { |
|
|
|
|
get_ref("MERGE_HEAD".to_owned(), deref), |
|
|
|
|
)); |
|
|
|
|
|
|
|
|
|
for entry in WalkDir::new(format!("{}/refs/", RGIT_DIR)) { |
|
|
|
|
for entry in WalkDir::new(format!("{}/refs/", dir.clone())) { |
|
|
|
|
let item = entry.unwrap(); |
|
|
|
|
let metadata = item.metadata().unwrap(); |
|
|
|
|
|
|
|
|
|
if metadata.is_file() { |
|
|
|
|
let relative_path = item.path().strip_prefix(RGIT_DIR).unwrap(); |
|
|
|
|
let relative_path = item.path().strip_prefix(dir.clone()).unwrap(); |
|
|
|
|
refs.push(( |
|
|
|
|
relative_path.to_str().unwrap().to_owned(), |
|
|
|
|
get_ref(relative_path.to_str().unwrap().to_owned(), deref), |
|
|
|
@ -110,7 +144,8 @@ pub fn iter_refs(prefix: &str, deref: bool) -> Vec<(String, RefValue)> { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn get_ref_internal(reference: String, deref: bool) -> (String, RefValue) { |
|
|
|
|
let ref_path = format!("{}/{}", RGIT_DIR, reference); |
|
|
|
|
let dir = RGIT_DIR.lock().unwrap().to_owned(); |
|
|
|
|
let ref_path = format!("{}/{}", dir, reference); |
|
|
|
|
let mut value = fs::read_to_string(ref_path).unwrap_or("".to_owned()); |
|
|
|
|
let symbolic = !value.is_empty() && value.starts_with("ref:"); |
|
|
|
|
|
|
|
|
|