Skip to content

Commit 4447e3d

Browse files
jackieismpcgenednaCopilot
authored
update some tests and docs (#57)
* add 2 docs Signed-off-by: jackieismpc <jackieismpc@gmail.com> * update readme Signed-off-by: jackieismpc <jackieismpc@gmail.com> * Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Quanyi Ma <eli@patch.sh> * Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Quanyi Ma <eli@patch.sh> * Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Quanyi Ma <eli@patch.sh> * Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Quanyi Ma <eli@patch.sh> * update src/delta Signed-off-by: jackieismpc <jackieismpc@gmail.com> * modify some docs Signed-off-by: jackieismpc <jackieismpc@gmail.com> * update protocol doc and tests Signed-off-by: jackieismpc <jackieismpc@gmail.com> * update docs and tests Signed-off-by: jackieismpc <jackieismpc@gmail.com> * fix a bug Signed-off-by: jackieismpc <jackieismpc@gmail.com> * update object Signed-off-by: jackieismpc <jackieismpc@gmail.com> * update pack Signed-off-by: jackieismpc <jackieismpc@gmail.com> * add examples and Analyze the coverage of test cases. Signed-off-by: jackieismpc <jackieismpc@gmail.com> * Update Examples/create_tree.rs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Jackie <jackieismpc@gmail.com> * Update docs/GIT_OBJECTS.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Jackie <jackieismpc@gmail.com> Signed-off-by: jackieismpc <jackieismpc@gmail.com> --------- Signed-off-by: jackieismpc <jackieismpc@gmail.com> Signed-off-by: Quanyi Ma <eli@patch.sh> Signed-off-by: Jackie <jackieismpc@gmail.com> Co-authored-by: Quanyi Ma <eli@patch.sh> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 23f7fbb commit 4447e3d

35 files changed

+1616
-967
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ buck-out/
99

1010
src/.DS_Store
1111
.DS_Store
12+
examples/output_packs

Examples/create_tree.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//! An example demonstrating how to create a Git Tree object from Blob hashes and display its contents.
2+
//! This example assumes you have Blob hashes available.
3+
//! In a real scenario, you would obtain these hashes by creating Blob objects first.
4+
5+
use git_internal::hash::ObjectHash;
6+
use git_internal::internal::object::tree::{Tree, TreeItem, TreeItemMode};
7+
use std::str::FromStr;
8+
9+
fn main() {
10+
// mock Blob hashes (replace with actual Blob hashes as needed)
11+
let blob_hash_1 = ObjectHash::from_str("8ab686eafeb1f44702738c8b0f24f2567c36da6d").unwrap();
12+
let blob_hash_2 =
13+
ObjectHash::from_str("2cf8d83d9ee29543b34a87727421fdecb7e3f3a183d337639025de576db9ebb4")
14+
.unwrap();
15+
16+
println!("Building a Tree object...");
17+
18+
// create TreeItems for each Blob
19+
let item1 = TreeItem::new(
20+
TreeItemMode::Blob, // file mode (100644)
21+
blob_hash_1,
22+
"README.md".to_string(),
23+
);
24+
25+
let item2 = TreeItem::new(TreeItemMode::Blob, blob_hash_2, "main.rs".to_string());
26+
27+
// build Tree object from the list of TreeItems
28+
let tree_items = vec![item1, item2];
29+
let tree = Tree::from_tree_items(tree_items).expect("Failed to create tree");
30+
31+
// output results
32+
println!("Created Tree Object successfully.");
33+
println!("Tree Hash ID: {}", tree.id);
34+
println!("Tree Contents:");
35+
for item in tree.tree_items {
36+
// Output format: <mode> <hash> <filename>
37+
println!(" - {} {} {}", item.mode, item.id, item.name);
38+
}
39+
}

Examples/decode_pack.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//! An example demonstrating how to decode a Git pack file using git-internal crate.
2+
//! This example reads a pack file from disk, decodes it, and prints out the
3+
//! decoded objects' information.
4+
//! Make sure to replace the `pack_path` variable with the path to your own pack file.
5+
//! The example assumes the pack file uses SHA-1 hashing.
6+
use git_internal::hash::ObjectHash;
7+
use git_internal::internal::pack::Pack;
8+
use std::fs::File;
9+
use std::io::BufReader;
10+
use std::path::Path;
11+
12+
fn main() {
13+
// replace with the path to your pack file
14+
let pack_path = "tests/data/packs/small-sha1.pack";
15+
if !Path::new(pack_path).exists() {
16+
println!("Pack file not found: {}, skipping example.", pack_path);
17+
return;
18+
}
19+
20+
let f = File::open(pack_path).expect("Failed to open pack file");
21+
// Pack decode requires a reader that implements BufRead + Send
22+
let mut reader = BufReader::new(f);
23+
24+
// Initialize Pack
25+
// Parameters:
26+
// 1. thread_num: None (automatically use the number of CPU cores)
27+
// 2. mem_limit: None (no memory limit)
28+
// 3. temp_path: None (use default temporary directory ./.cache_temp)
29+
// 4. clean_tmp: true (automatically clean temporary files on Drop)
30+
let mut pack = Pack::new(None, None, None, true);
31+
32+
println!("Starting to decode pack file...");
33+
34+
// Start decoding
35+
pack.decode(
36+
&mut reader,
37+
|entry| {
38+
// Callback function: process each decoded object (Entry)
39+
// entry.inner contains the actual data, entry.meta contains metadata
40+
println!(
41+
"Decoded object: {} | Type: {:?}",
42+
entry.inner.hash, entry.inner.obj_type
43+
);
44+
},
45+
None::<fn(ObjectHash)>, // Optional: callback for the overall Pack file Hash
46+
)
47+
.expect("Failed to decode pack");
48+
49+
println!("Decode finished. Total objects processed: {}", pack.number);
50+
}

Examples/encode_pack.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//! An example demonstrating how to encode Git objects into a pack file using git-internal crate.
2+
//! This example creates several Blob objects from string data, encodes them into a pack file,
3+
//! and writes the resulting pack file to disk.
4+
//!
5+
//! Make sure to check the output directory for the generated pack file after running this example.
6+
//! The example assumes SHA-1 hashing for simplicity.
7+
8+
use git_internal::internal::metadata::{EntryMeta, MetaAttached};
9+
use git_internal::internal::object::blob::Blob;
10+
use git_internal::internal::pack::encode::encode_and_output_to_files;
11+
use git_internal::internal::pack::entry::Entry;
12+
use std::fs;
13+
use std::path::PathBuf;
14+
use tokio::sync::mpsc;
15+
16+
#[tokio::main]
17+
async fn main() {
18+
// 1. prepare data to encode
19+
let contents = vec!["Hello World", "Rust is awesome", "Git internals are fun"];
20+
21+
let object_number = contents.len();
22+
let window_size = 10; // Delta compression window size, 0 means no Delta compression
23+
let output_dir = PathBuf::from("examples/output_packs");
24+
25+
if !output_dir.exists() {
26+
fs::create_dir(&output_dir).expect("Failed to create output directory");
27+
}
28+
29+
println!("Preparing to encode {} objects...", object_number);
30+
31+
// 2. Create a channel to send Entry
32+
// Buffer size can be adjusted based on memory conditions
33+
let (entry_tx, entry_rx) = mpsc::channel(100);
34+
35+
// 3. Start encoding task
36+
// encode_and_output_to_files will process received Entry in the background and write to files
37+
let encode_handle = tokio::spawn(async move {
38+
encode_and_output_to_files(entry_rx, object_number, output_dir, window_size).await
39+
});
40+
41+
// 4. Send data
42+
for content in contents {
43+
// Convert string to Blob, then to Entry
44+
let blob = Blob::from_content(content);
45+
let entry: Entry = blob.into();
46+
47+
// Wrap metadata
48+
let meta_entry = MetaAttached {
49+
inner: entry,
50+
meta: EntryMeta::new(),
51+
};
52+
53+
entry_tx
54+
.send(meta_entry)
55+
.await
56+
.expect("Failed to send entry");
57+
}
58+
59+
// 5. Close the sender to notify the encoder that data sending is complete
60+
drop(entry_tx);
61+
62+
// 6. wait for encoding to complete
63+
match encode_handle.await.unwrap() {
64+
Ok(_) => println!("Pack encoding successful! Check 'output_packs' directory."),
65+
Err(e) => eprintln!("Pack encoding failed: {}", e),
66+
}
67+
}

Examples/hashing.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//! An example demonstrating how to use the hashing functionality in git-internal,
2+
//! including how to switch between SHA-1 and SHA-256.
3+
4+
use git_internal::hash::{HashKind, ObjectHash, set_hash_kind};
5+
use git_internal::internal::object::types::ObjectType;
6+
7+
fn main() {
8+
let data = b"This is some data to be hashed.";
9+
println!("Original data: \"{}\"", String::from_utf8_lossy(data));
10+
println!();
11+
12+
// --- SHA-1 Hashing ---
13+
{
14+
// Set the hash kind for the current thread to SHA-1.
15+
// The guard ensures the hash kind is restored when it goes out of scope.
16+
let _guard = set_hash_kind(HashKind::Sha1);
17+
println!("Using HashKind: {:?}", HashKind::Sha1);
18+
19+
// Create a hash for a blob object. The library automatically prepends
20+
// the "blob <size>\0" header before hashing.
21+
let blob_hash = ObjectHash::from_type_and_data(ObjectType::Blob, data);
22+
println!("Blob hash (SHA-1): {}", blob_hash);
23+
24+
// Manually verify with the `sha1` crate for correctness
25+
use sha1::{Digest, Sha1};
26+
let mut hasher = Sha1::new();
27+
hasher.update(format!("blob {}\0", data.len()).as_bytes());
28+
hasher.update(data);
29+
let expected_sha1_bytes: [u8; 20] = hasher.finalize().into();
30+
assert_eq!(
31+
blob_hash,
32+
ObjectHash::from_bytes(&expected_sha1_bytes).unwrap()
33+
);
34+
println!("Verified correctly against manual SHA-1 calculation.");
35+
}
36+
37+
println!("\n----------------------------------------\n");
38+
39+
// --- SHA-256 Hashing ---
40+
{
41+
// Set the hash kind for the current thread to SHA-256.
42+
let _guard = set_hash_kind(HashKind::Sha256);
43+
println!("Using HashKind: {:?}", HashKind::Sha256);
44+
45+
let blob_hash = ObjectHash::from_type_and_data(ObjectType::Blob, data);
46+
println!("Blob hash (SHA-256): {}", blob_hash);
47+
48+
// Manually verify with the `sha2` crate
49+
use sha2::{Digest as Sha2Digest, Sha256};
50+
let mut hasher = Sha256::new();
51+
hasher.update(format!("blob {}\0", data.len()).as_bytes());
52+
hasher.update(data);
53+
let expected_sha256_bytes: [u8; 32] = hasher.finalize().into();
54+
assert_eq!(
55+
blob_hash,
56+
ObjectHash::from_bytes(&expected_sha256_bytes).unwrap()
57+
);
58+
println!("Verified correctly against manual SHA-256 calculation.");
59+
}
60+
}

docs/ARCHITECTURE.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,5 +115,3 @@ Client ─pkt-line─▶ SmartProtocol
115115
- docs/GIT_PROTOCOL_GUIDE.md: protocol details and layering.
116116
- docs/GIT_OBJECTS.md: Git objects overview.
117117
- tests/data/: real pack/index fixtures for decode/idx roundtrip testing.
118-
119-
This view lets you trace from protocol entry to object parsing and pack encode/decode, and adapt it to custom storage/transport scenarios.

0 commit comments

Comments
 (0)