step twelve: extract tree from object

This commit is contained in:
Gonçalo Valério 2020-10-25 18:35:47 +00:00
parent c93915acf7
commit 3436deb267
4 changed files with 64 additions and 0 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
/target
/test
.rgit

View File

@ -1,4 +1,7 @@
use std::collections::HashMap;
use std::fs;
use std::io;
use std::path::Path;
#[path = "data.rs"]
mod data;
@ -45,6 +48,19 @@ pub fn write_tree(directory: String) -> String {
return data::hash_object(&tree.into_bytes(), "tree".to_owned());
}
pub fn read_tree(oid: String) {
for (path, object_id) in get_tree(oid, "./".to_owned()).iter() {
let mut dirs = Path::new(path).ancestors();
dirs.next();
let dir = dirs.next().unwrap().to_str().unwrap();
fs::create_dir_all(dir).expect("Cannot create required dirs");
fs::write(path, data::get_object(object_id.clone(), "".to_owned()))
.expect("Cannot write required object");
}
}
fn is_ignored(path: &String) -> bool {
if path.contains(".rgit") {
true
@ -52,3 +68,36 @@ fn is_ignored(path: &String) -> bool {
false
}
}
fn tree_entries(oid: String) -> Vec<(String, String, String)> {
let mut entries: Vec<(String, String, String)> = vec![];
let tree_data = data::get_object(oid, "tree".to_owned());
for line in tree_data.split_terminator("\n") {
let items: Vec<&str> = line.splitn(3, " ").collect();
entries.push((
items[0].to_owned(), // _type
items[1].to_owned(), // oid
items[2].to_owned(), // name
));
}
return entries;
}
fn get_tree(oid: String, base_path: String) -> HashMap<String, String> {
let mut result = HashMap::new();
for entry in tree_entries(oid) {
// _type, oid, name
assert!(entry.2.find("/").is_none());
assert!(entry.2 != "..");
assert!(entry.2 != ".");
let path = base_path.clone() + entry.2.as_str();
if entry.0 == "blob".to_owned() {
result.insert(path.clone(), entry.1.clone());
} else if entry.0 == "tree".to_owned() {
result.extend(get_tree(entry.1, format!("{}/", path)));
} else {
panic!("Unknown tree entry: {}", entry.0);
}
}
result
}

View File

@ -35,6 +35,7 @@ pub fn get_object(hash: String, expected: String) -> String {
if expected != "".to_owned() {
// Compare the type
content.pop();
assert_eq!(expected, content);
}

View File

@ -23,6 +23,11 @@ fn main() {
SubCommand::with_name("write-tree")
.about("write the current working directory to the database"),
)
.subcommand(
SubCommand::with_name("read-tree")
.about("writes a given tree to the working directory")
.arg(Arg::with_name("oid").index(1).required(true)),
)
.get_matches();
match matches.subcommand_name() {
@ -30,6 +35,7 @@ fn main() {
Some("hash-object") => hash_object(matches),
Some("cat-file") => cat_file(matches),
Some("write-tree") => write_tree(),
Some("read-tree") => read_tree(matches),
_ => println!("unknown sub command"),
}
}
@ -63,3 +69,10 @@ fn cat_file(matches: ArgMatches) {
fn write_tree() {
println!("{}", base::write_tree(".".to_owned()));
}
fn read_tree(matches: ArgMatches) {
if let Some(cmd_matches) = matches.subcommand_matches("read-tree") {
let oid = cmd_matches.value_of("oid").unwrap();
base::read_tree(oid.to_owned());
}
}