1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use std::{convert::TryInto, ops::DerefMut};
use bstr::BString;
use git_hash::ObjectId;
use git_odb::{Find, FindExt};
use git_ref::{
transaction::{LogChange, PreviousValue, RefLog},
FullName,
};
use crate::{
easy,
easy::{commit, object, ObjectRef, Oid},
ext::ObjectIdExt,
};
pub trait ObjectAccessExt: easy::Access + Sized {
fn find_object(&self, id: impl Into<ObjectId>) -> Result<ObjectRef<'_, Self>, object::find::existing::Error> {
let state = self.state();
let id = id.into();
let kind = {
let mut buf = self.state().try_borrow_mut_buf()?;
let obj = self
.repo()?
.odb
.find(&id, &mut buf, state.try_borrow_mut_pack_cache()?.deref_mut())?;
obj.kind
};
ObjectRef::from_current_buf(id, kind, self).map_err(Into::into)
}
fn try_find_object(&self, id: impl Into<ObjectId>) -> Result<Option<ObjectRef<'_, Self>>, object::find::Error> {
let state = self.state();
let id = id.into();
self.repo()?
.odb
.try_find(
&id,
state.try_borrow_mut_buf()?.deref_mut(),
state.try_borrow_mut_pack_cache()?.deref_mut(),
)?
.map(|obj| {
let kind = obj.kind;
drop(obj);
ObjectRef::from_current_buf(id, kind, self).map_err(Into::into)
})
.transpose()
}
fn write_object(&self, object: &git_object::Object) -> Result<Oid<'_, Self>, object::write::Error> {
use git_odb::Write;
let repo = self.repo()?;
repo.odb
.write(object, repo.hash_kind)
.map(|oid| oid.attach(self))
.map_err(Into::into)
}
fn commit<Name, E>(
&self,
reference: Name,
message: impl Into<BString>,
author: impl Into<git_actor::Signature>,
committer: impl Into<git_actor::Signature>,
tree: impl Into<ObjectId>,
parents: impl IntoIterator<Item = impl Into<ObjectId>>,
) -> Result<Oid<'_, Self>, commit::Error>
where
Name: TryInto<FullName, Error = E>,
commit::Error: From<E>,
{
use git_ref::{
transaction::{Change, RefEdit},
Target,
};
use crate::easy::ext::ReferenceAccessExt;
let reference = reference.try_into()?;
let commit: git_object::Object = git_object::Commit {
message: message.into(),
tree: tree.into(),
author: author.into(),
committer: committer.into(),
encoding: None,
parents: parents.into_iter().map(|id| id.into()).collect(),
extra_headers: Default::default(),
}
.into();
let commit_id = self.write_object(&commit)?;
let commit = commit.into_commit();
self.edit_reference(
RefEdit {
change: Change::Update {
log: LogChange {
mode: RefLog::AndReference,
force_create_reflog: false,
message: crate::reference::log::message("commit", &commit),
},
expected: match commit.parents.get(0).map(|p| Target::Peeled(*p)) {
Some(previous) => PreviousValue::ExistingMustMatch(previous),
None => PreviousValue::MustNotExist,
},
new: Target::Peeled(commit_id.inner),
},
name: reference,
deref: true,
},
git_lock::acquire::Fail::Immediately,
Some(&commit.committer),
)?;
Ok(commit_id)
}
}
impl<A> ObjectAccessExt for A where A: easy::Access + Sized {}