From 55f0a5af4c160d0b7ac62cc155b46b9d85aa3f04 Mon Sep 17 00:00:00 2001 From: Matt Ferraro Date: Thu, 11 Apr 2024 22:55:31 -0400 Subject: [PATCH] implement git_log like printing --- packages/cadmium/src/main.rs | 46 +++++++++- packages/cadmium/src/oplog/mod.rs | 147 ++++++++++++++++++++++++++++-- 2 files changed, 184 insertions(+), 9 deletions(-) diff --git a/packages/cadmium/src/main.rs b/packages/cadmium/src/main.rs index a2c0f742..f6da1622 100644 --- a/packages/cadmium/src/main.rs +++ b/packages/cadmium/src/main.rs @@ -21,6 +21,48 @@ use truck_topology::{Shell, Solid}; fn main() { let mut el = EvolutionLog::new(); + // Create the Top Plane + let top_plane_id = el.append(Operation::CreatePlane { + nonce: "a".to_string(), + }); + el.append(Operation::SetPlaneName { + plane_id: top_plane_id.clone(), + name: "Top".to_string(), + }); + let set_plane = el.append(Operation::SetPlane { + plane_id: top_plane_id.clone(), + plane: Plane::top(), + }); + let set_name = el.append(Operation::SetPlaneName { + plane_id: top_plane_id.clone(), + name: "Top2".to_string(), + }); + let new_extrusion = el.append(Operation::CreateExtrusion { + nonce: "b".to_string(), + }); + let set_ext_name = el.append(Operation::SetExtrusionName { + extrusion_id: new_extrusion.clone(), + name: "Extrusion1".to_string(), + }); + el.checkout(top_plane_id.clone()); + el.append(Operation::SetPlaneName { + plane_id: top_plane_id.clone(), + name: "Bottom".to_string(), + }); + el.cherry_pick(set_plane); + el.cherry_pick(set_name); + el.cherry_pick(new_extrusion); + el.cherry_pick(set_ext_name); + // let new_extrusion = el.append(Operation::CreateExtrusion { + // nonce: "c".to_string(), + // }); + + el.git_log() +} + +fn main_2() { + let mut el = EvolutionLog::new(); + // Create the Top Plane let top_plane_id = el.append(Operation::CreatePlane { nonce: "a".to_string(), @@ -118,7 +160,9 @@ fn main() { let finished_circle_commit = el.cherry_pick(finished_rectangle_commit).unwrap(); let rotated_circle_commit = el.cherry_pick(rotated_rectangle_commit).unwrap(); - el.pretty_print(); + // el.pretty_print(); + + el.git_log(); } fn main_old() { diff --git a/packages/cadmium/src/oplog/mod.rs b/packages/cadmium/src/oplog/mod.rs index bdf10506..55d2e529 100644 --- a/packages/cadmium/src/oplog/mod.rs +++ b/packages/cadmium/src/oplog/mod.rs @@ -1,10 +1,13 @@ use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; +use std::collections::HashMap; use std::hash::{Hash, Hasher}; use std::process::id; use crate::project::Plane; +pub type Sha = String; + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct OpLog { commits: Vec, @@ -24,7 +27,7 @@ impl OpLog { let op_hash = operation.hash(); let parent = parent.clone(); let new_commit = Commit { - id: id_from_op_and_parent(&operation, &parent), + id: id_from_op_and_parent(&operation, &parent, self.commits.len()), operation, content_hash: op_hash, parent, @@ -45,10 +48,10 @@ impl OpLog { } } -fn id_from_op_and_parent(operation: &Operation, parent: &Sha) -> Sha { +fn id_from_op_and_parent(operation: &Operation, parent: &Sha, nonce: usize) -> Sha { let h = operation.hash(); let mut hasher = Sha256::new(); - hasher.update(format!("{h}-{parent}").as_bytes()); + hasher.update(format!("{h}-{parent}-{nonce}").as_bytes()); format!("{:x}", hasher.finalize()) } @@ -79,6 +82,112 @@ impl EvolutionLog { } } + pub fn to_tree(&self) -> CommitNode { + // Build a tree of commits using CommitNode + let mut commit_node_table: HashMap = HashMap::new(); + for commit in &self.oplog.commits { + commit_node_table.insert( + commit.id.clone(), + CommitNode { + commit: commit.id.clone(), + children: vec![], + }, + ); + } + for commit in &self.oplog.commits { + let parent = commit.parent.clone(); + if parent == "" { + // special treatment for the root node + continue; + } + let mut parent_commit_node = commit_node_table.get_mut(&parent).unwrap(); + parent_commit_node.children.push(commit.id.clone()); + } + + let root_node = commit_node_table.get(&self.oplog.commits[0].id).unwrap(); + root_node.clone() + } + + pub fn git_log(&self) { + // Build a tree of commits using CommitNode + let mut commit_node_table: HashMap = HashMap::new(); + for commit in &self.oplog.commits { + commit_node_table.insert( + commit.id.clone(), + CommitNode { + commit: commit.id.clone(), + children: vec![], + }, + ); + } + for commit in &self.oplog.commits { + let parent = commit.parent.clone(); + if parent == "" { + // special treatment for the root node + continue; + } + let mut parent_commit_node = commit_node_table.get_mut(&parent).unwrap(); + parent_commit_node.children.push(commit.id.clone()); + // println!( + // "Parent now has: {} children", + // parent_commit_node.children.len() + // ) + } + + let root_node = commit_node_table.get(&self.oplog.commits[0].id).unwrap(); + + let commit_table = self + .oplog + .commits + .iter() + .map(|commit| (commit.id.clone(), commit)) + .collect::>(); + + // const OTHER_CHILD: &str = "│ "; // prefix: pipe + // const OTHER_ENTRY: &str = "├── "; // connector: tee + // const FINAL_CHILD: &str = " "; // prefix: no more siblings + // const FINAL_ENTRY: &str = "└── "; // connector: elbow + + println!("Root:"); + visit(&root_node.commit, "", &commit_table, &commit_node_table); + + fn visit( + sha: &Sha, + prefix: &str, + commit_table: &HashMap, + commit_node_table: &HashMap, + ) { + let commit = commit_table.get(sha).unwrap(); + let commit_node = commit_node_table.get(sha).unwrap(); + println!("{}* {}", prefix, commit); + + if commit_node.children.len() == 0 { + return; + } else if commit_node.children.len() == 1 { + visit( + &commit_node.children[0], + &prefix, + commit_table, + commit_node_table, + ); + } else if commit_node.children.len() == 2 { + println!("{}|\\", prefix); + visit( + &commit_node.children[0], + &format!("| {}", prefix), + commit_table, + commit_node_table, + ); + visit( + &commit_node.children[1], + &prefix, + commit_table, + commit_node_table, + ); + } + } + } + pub fn checkout(&mut self, sha: Sha) -> Result { // check that the sha exists in the oplog before doing this for commit in &self.oplog.commits { @@ -95,7 +204,7 @@ impl EvolutionLog { for commit in &self.oplog.commits { if commit.id == sha { let new_operation = commit.operation.clone(); - let mut new_commit_id = self.append(commit.operation.clone()); + let mut new_commit_id = self.append(new_operation.clone()); // If the original commit created an entity, we'll need to create an alias commit if new_operation.is_create() { @@ -127,7 +236,7 @@ impl Commit { }; let parent_sha = "".to_owned(); Self { - id: id_from_op_and_parent(&init_op, &parent_sha), + id: id_from_op_and_parent(&init_op, &parent_sha, 0), content_hash: init_op.hash(), operation: init_op, parent: parent_sha, @@ -140,7 +249,23 @@ impl Commit { } } -pub type Sha = String; +impl std::fmt::Display for Commit { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}: {}", &self.id[..8], self.operation) + } +} + +#[derive(Debug, Clone)] +pub struct CommitNode { + pub commit: Sha, + pub children: Vec, +} + +impl std::fmt::Display for CommitNode { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", self.commit) + } +} #[derive(Debug, Clone, Serialize, Deserialize)] pub enum Operation { @@ -320,9 +445,9 @@ impl Operation { } Operation::SetPlane { plane_id, plane } => { format!( - "SetPlane: {} {:?}", + "SetPlane: {}", plane_id.to_owned()[..10].to_string(), - plane + // plane ) } Operation::CreateSketch { nonce } => format!("CreateSketch: {}", nonce), @@ -414,3 +539,9 @@ impl Operation { } } } + +impl std::fmt::Display for Operation { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", &self.pretty_print()) + } +}