Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit afedd7f

Browse files
committed
Merge branch 'example-write-blob'
2 parents 86fe22c + 4f87a06 commit afedd7f

4 files changed

Lines changed: 126 additions & 22 deletions

File tree

git-repository/examples/init-repo-and-commit.rs

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,60 @@
22
// adds initial commit with empty tree
33

44
use anyhow::Context;
5+
use git::objs::tree;
56
use git_repository as git;
67

78
fn main() -> anyhow::Result<()> {
89
// Note use of args_os:
910
// paths may not be UTF-8 encoded and thus can't be forced into a String.
1011
// gitoxide does not assume encodings that aren't there
1112
// to match the way git does it as a bare minimum and be just as flexible.
12-
let work_dir = std::env::args_os()
13+
let git_dir = std::env::args_os()
1314
.nth(1)
1415
.context("First argument needs to be the directory to initialize the repository in")?;
15-
let repo = git::init(work_dir)?;
16+
let repo = git::init_bare(git_dir)?;
1617

17-
println!(
18-
"Repo: {:?}",
19-
repo.work_dir().expect("non-bare repositories have a work-dir")
20-
);
18+
println!("Repo (bare): {:?}", repo.git_dir());
19+
20+
let mut tree = git::objs::Tree::empty();
21+
let empty_tree_id = repo.write_object(&tree)?;
2122

22-
let empty_tree_id = repo.write_object(git::objs::Tree::empty())?;
2323
let author = git::actor::SignatureRef {
2424
name: "Maria Sanchez".into(),
2525
email: "[email protected]".into(),
2626
time: git_date::Time::now_local_or_utc(),
2727
};
28-
let id = repo.commit(
28+
let initial_commit_id = repo.commit(
2929
"HEAD",
3030
author,
3131
author,
3232
"initial commit",
3333
empty_tree_id,
3434
git::commit::NO_PARENT_IDS,
3535
)?;
36-
println!("new commit id with empty tree: {:?}", id);
36+
37+
println!("initial commit id with empty tree: {:?}", initial_commit_id);
38+
39+
let blob_id = repo.write_blob("hello world")?.into();
40+
let entry = tree::Entry {
41+
mode: tree::EntryMode::Blob,
42+
oid: blob_id,
43+
filename: "hello.txt".into(),
44+
};
45+
46+
tree.entries.push(entry);
47+
let hello_tree_id = repo.write_object(&tree)?;
48+
49+
let blob_commit_id = repo.commit(
50+
"HEAD",
51+
author,
52+
author,
53+
"hello commit",
54+
hello_tree_id,
55+
[initial_commit_id],
56+
)?;
57+
58+
println!("commit id for 'hello world' blob: {:?}", blob_commit_id);
59+
3760
Ok(())
3861
}

git-repository/src/lib.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -303,10 +303,20 @@ pub mod init {
303303
/// won't mind if the `directory` otherwise is non-empty.
304304
pub fn init(directory: impl AsRef<Path>, options: crate::create::Options) -> Result<Self, Error> {
305305
use git_sec::trust::DefaultForLevel;
306-
let path = crate::create::into(directory.as_ref(), options)?;
306+
let open_options = crate::open::Options::default_for_level(git_sec::Trust::Full);
307+
Self::init_opts(directory, options, open_options)
308+
}
309+
310+
/// Similar to [`init`][Self::init()], but allows to determine how exactly to open the newly created repository.
311+
pub fn init_opts(
312+
directory: impl AsRef<Path>,
313+
create_options: crate::create::Options,
314+
mut open_options: crate::open::Options,
315+
) -> Result<Self, Error> {
316+
let path = crate::create::into(directory.as_ref(), create_options)?;
307317
let (git_dir, worktree_dir) = path.into_repository_and_work_tree_directories();
308-
let options = crate::open::Options::default_for_level(git_sec::Trust::Full);
309-
ThreadSafeRepository::open_from_paths(git_dir, worktree_dir, options).map_err(Into::into)
318+
open_options.git_dir_trust = Some(git_sec::Trust::Full);
319+
ThreadSafeRepository::open_from_paths(git_dir, worktree_dir, open_options).map_err(Into::into)
310320
}
311321
}
312322
}

git-repository/src/repository/object.rs

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::convert::TryInto;
22

33
use git_hash::{oid, ObjectId};
4-
use git_odb::{Find, FindExt};
4+
use git_odb::{Find, FindExt, Write};
55
use git_ref::{
66
transaction::{LogChange, PreviousValue, RefLog},
77
FullName,
@@ -41,10 +41,9 @@ impl crate::Repository {
4141
/// `try_find_object()` operations from succeeding while alive.
4242
/// To bypass this limit, clone this `sync::Handle` instance.
4343
pub fn try_find_object(&self, id: impl Into<ObjectId>) -> Result<Option<Object<'_>>, object::find::OdbError> {
44-
let state = self;
4544
let id = id.into();
4645

47-
let mut buf = state.free_buf();
46+
let mut buf = self.free_buf();
4847
match self.objects.try_find(&id, &mut buf)? {
4948
Some(obj) => {
5049
let kind = obj.kind;
@@ -56,16 +55,33 @@ impl crate::Repository {
5655

5756
/// Write the given object into the object database and return its object id.
5857
pub fn write_object(&self, object: impl git_object::WriteTo) -> Result<Id<'_>, object::write::Error> {
59-
use git_odb::Write;
60-
61-
let state = self;
62-
state
63-
.objects
58+
self.objects
6459
.write(object)
6560
.map(|oid| oid.attach(self))
6661
.map_err(Into::into)
6762
}
6863

64+
/// Write a blob from the given `bytes`.
65+
pub fn write_blob(&self, bytes: impl AsRef<[u8]>) -> Result<Id<'_>, object::write::Error> {
66+
self.objects
67+
.write_buf(git_object::Kind::Blob, bytes.as_ref())
68+
.map(|oid| oid.attach(self))
69+
}
70+
71+
/// Write a blob from the given `Read` implementation.
72+
pub fn write_blob_stream(
73+
&self,
74+
mut bytes: impl std::io::Read + std::io::Seek,
75+
) -> Result<Id<'_>, object::write::Error> {
76+
let current = bytes.stream_position()?;
77+
let len = bytes.seek(std::io::SeekFrom::End(0))? - current;
78+
bytes.seek(std::io::SeekFrom::Start(current))?;
79+
80+
self.objects
81+
.write_stream(git_object::Kind::Blob, len, bytes)
82+
.map(|oid| oid.attach(self))
83+
}
84+
6985
/// Create a tag reference named `name` (without `refs/tags/` prefix) pointing to a newly created tag object
7086
/// which in turn points to `target` and return the newly created reference.
7187
///

git-repository/tests/repository/object.rs

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
use git_repository as git;
2+
13
mod write_object {
4+
use crate::repository::object::empty_bare_repo;
5+
26
#[test]
37
fn empty_tree() -> crate::Result {
4-
let tmp = tempfile::tempdir()?;
5-
let repo = git_repository::init_bare(&tmp)?;
8+
let (_tmp, repo) = empty_bare_repo()?;
69
let oid = repo.write_object(&git_repository::objs::TreeRef::empty())?;
710
assert_eq!(
811
oid,
@@ -13,6 +16,44 @@ mod write_object {
1316
}
1417
}
1518

19+
mod write_blob {
20+
use crate::repository::object::empty_bare_repo;
21+
use git_testtools::hex_to_id;
22+
use std::io::{Seek, SeekFrom};
23+
24+
#[test]
25+
fn from_slice() -> crate::Result {
26+
let (_tmp, repo) = empty_bare_repo()?;
27+
let oid = repo.write_blob(b"hello world")?;
28+
assert_eq!(oid, hex_to_id("95d09f2b10159347eece71399a7e2e907ea3df4f"));
29+
Ok(())
30+
}
31+
32+
#[test]
33+
fn from_stream() -> crate::Result {
34+
let (_tmp, repo) = empty_bare_repo()?;
35+
let mut cursor = std::io::Cursor::new(b"hello world");
36+
let mut seek_cursor = cursor.clone();
37+
let oid = repo.write_blob_stream(&mut cursor)?;
38+
assert_eq!(oid, hex_to_id("95d09f2b10159347eece71399a7e2e907ea3df4f"));
39+
40+
seek_cursor.seek(SeekFrom::Start(6))?;
41+
let oid = repo.write_blob_stream(&mut seek_cursor)?;
42+
assert_eq!(
43+
oid,
44+
hex_to_id("04fea06420ca60892f73becee3614f6d023a4b7f"),
45+
"it computes the object size correctly"
46+
);
47+
48+
assert_eq!(
49+
oid.object()?.data,
50+
&b"world"[..],
51+
"the seek position is taken into account, so only part of the input data is written"
52+
);
53+
Ok(())
54+
}
55+
}
56+
1657
mod find {
1758

1859
#[test]
@@ -215,3 +256,17 @@ mod commit {
215256
Ok(())
216257
}
217258
}
259+
260+
fn empty_bare_repo() -> crate::Result<(tempfile::TempDir, git::Repository)> {
261+
let tmp = tempfile::tempdir()?;
262+
let repo = git::ThreadSafeRepository::init_opts(
263+
tmp.path(),
264+
git::create::Options {
265+
bare: true,
266+
fs_capabilities: None,
267+
},
268+
git::open::Options::isolated(),
269+
)?
270+
.into();
271+
Ok((tmp, repo))
272+
}

0 commit comments

Comments
 (0)