History

feat: Add `Repository::has_object()` as a high-level alternative.

Previously, one would have to call `repo.objects.contains()`, which is fine, but this method is necessary for symmetry of the API and one shouldn't have to drop down a level to do this. This method also knows empty trees as special case.

Sebastian Thiel committed 3 years ago

Commit 787a9aa1 parent 3cec9352 files · +28 −7Browse files

Unified · Split

2 files
  1. gix/src/repository/object.rs +26 −7
  2. gix/tests/repository/object.rs +2 −0
gix/src/repository/object.rs+26−7
@@ -26,7 +26,7 @@ impl crate::Repository { · 25 unmodified lines
2626 #[momo]
2727 pub fn find_object(&self, id: impl Into<ObjectId>) -> Result<Object<'_>, object::find::existing::Error> {
2828 let id = id.into();
29− if id == gix_hash::ObjectId::empty_tree(self.object_hash()) {
29+ if id == ObjectId::empty_tree(self.object_hash()) {
3030 return Ok(Object {
3131 id,
3232 kind: gix_object::Kind::Tree,
@@ -46,7 +46,7 @@ impl crate::Repository { · 13 unmodified lines
4646 #[momo]
4747 pub fn find_header(&self, id: impl Into<ObjectId>) -> Result<gix_odb::find::Header, object::find::existing::Error> {
4848 let id = id.into();
49− if id == gix_hash::ObjectId::empty_tree(self.object_hash()) {
49+ if id == ObjectId::empty_tree(self.object_hash()) {
5050 return Ok(gix_odb::find::Header::Loose {
5151 kind: gix_object::Kind::Tree,
5252 size: 0,
@@ -55,6 +55,25 @@ impl crate::Repository { · 2 unmodified lines
5555 self.objects.header(id)
5656 }
5757
58+ /// Return `true` if `id` exists in the object database.
59+ ///
60+ /// # Performance
61+ ///
62+ /// This method can be slow if the underlying [object database](crate::Repository::objects) has
63+ /// an unsuitable [RefreshMode](gix_odb::store::RefreshMode) and `id` is not likely to exist.
64+ /// Use [`repo.objects.refresh_never()`](gix_odb::store::Handle::refresh_never) to avoid expensive
65+ /// IO-bound refreshes if an object wasn't found.
66+ #[doc(alias = "exists", alias = "git2")]
67+ #[momo]
68+ pub fn has_object(&self, id: impl AsRef<gix_hash::oid>) -> bool {
69+ let id = id.as_ref();
70+ if id == ObjectId::empty_tree(self.object_hash()) {
71+ true
72+ } else {
73+ self.objects.contains(id)
74+ }
75+ }
76+
5877 /// Obtain information about an object without fully decoding it, or `None` if the object doesn't exist.
5978 ///
6079 /// Note that despite being cheaper than [`Self::try_find_object()`], there is still some effort traversing delta-chains.
@@ -64,7 +83,7 @@ impl crate::Repository { · 3 unmodified lines
6483 id: impl Into<ObjectId>,
6584 ) -> Result<Option<gix_odb::find::Header>, object::find::Error> {
6685 let id = id.into();
67− if id == gix_hash::ObjectId::empty_tree(self.object_hash()) {
86+ if id == ObjectId::empty_tree(self.object_hash()) {
6887 return Ok(Some(gix_odb::find::Header::Loose {
6988 kind: gix_object::Kind::Tree,
7089 size: 0,
@@ -77,7 +96,7 @@ impl crate::Repository { · 6 unmodified lines
7796 #[momo]
7897 pub fn try_find_object(&self, id: impl Into<ObjectId>) -> Result<Option<Object<'_>>, object::find::Error> {
7998 let id = id.into();
80− if id == gix_hash::ObjectId::empty_tree(self.object_hash()) {
99+ if id == ObjectId::empty_tree(self.object_hash()) {
81100 return Ok(Some(Object {
82101 id,
83102 kind: gix_object::Kind::Tree,
@@ -236,7 +255,7 @@ impl crate::Repository { · 152 unmodified lines
236255 reference: FullName,
237256 message: &str,
238257 tree: ObjectId,
239− parents: SmallVec<[gix_hash::ObjectId; 1]>,
258+ parents: SmallVec<[ObjectId; 1]>,
240259 ) -> Result<Id<'_>, commit::Error> {
241260 use gix_ref::{
242261 transaction::{Change, RefEdit},
@@ -310,12 +329,12 @@ impl crate::Repository { · 67 unmodified lines
310329 self.commit_as(committer, author, reference, message, tree, parents)
311330 }
312331
313− /// Return an empty tree object, suitable for [getting changes](crate::Tree::changes()).
332+ /// Return an empty tree object, suitable for [getting changes](Tree::changes()).
314333 ///
315334 /// Note that the returned object is special and doesn't necessarily physically exist in the object database.
316335 /// This means that this object can be used in an uninitialized, empty repository which would report to have no objects at all.
317336 pub fn empty_tree(&self) -> Tree<'_> {
318− self.find_object(gix_hash::ObjectId::empty_tree(self.object_hash()))
337+ self.find_object(ObjectId::empty_tree(self.object_hash()))
319338 .expect("always present")
320339 .into_tree()
321340 }
gix/tests/repository/object.rs+2−0
@@ -68,6 +68,7 @@ fn writes_avoid_io_using_duplicate_check() -> crate::Result { · 67 unmodified lines
6868
6969 for id in repo.objects.iter()? {
7070 let id = id?;
71+ assert!(repo.has_object(id));
7172 let obj = repo.find_object(id)?;
7273 let header = repo.find_header(id)?;
7374 assert_eq!(obj.kind, header.kind(), "header and object agree");
@@ -156,6 +157,7 @@ mod find { · 82 unmodified lines
156157 let repo = basic_repo()?;
157158 let empty_tree = gix::hash::ObjectId::empty_tree(repo.object_hash());
158159 assert_eq!(repo.find_object(empty_tree)?.into_tree().iter().count(), 0);
160+ assert!(repo.has_object(empty_tree));
159161 assert_eq!(
160162 repo.find_header(empty_tree)?,
161163 gix_odb::find::Header::Loose {