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

Skip to content

Commit c68044a

Browse files
author
Vicent Marti
committed
Merge pull request libgit2#3656 from ethomson/exists_prefixes
Introduce `git_odb_expand_ids`
2 parents b7809b8 + 62484f5 commit c68044a

File tree

8 files changed

+297
-37
lines changed

8 files changed

+297
-37
lines changed

include/git2/odb.h

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "common.h"
1111
#include "types.h"
1212
#include "oid.h"
13+
#include "oidarray.h"
1314

1415
/**
1516
* @file git2/odb.h
@@ -159,7 +160,8 @@ GIT_EXTERN(int) git_odb_read_header(size_t *len_out, git_otype *type_out, git_od
159160
GIT_EXTERN(int) git_odb_exists(git_odb *db, const git_oid *id);
160161

161162
/**
162-
* Determine if objects can be found in the object database from a short OID.
163+
* Determine if an object can be found in the object database by an
164+
* abbreviated object ID.
163165
*
164166
* @param out The full OID of the found object if just one is found.
165167
* @param db The database to be searched for the given object.
@@ -171,6 +173,50 @@ GIT_EXTERN(int) git_odb_exists(git_odb *db, const git_oid *id);
171173
GIT_EXTERN(int) git_odb_exists_prefix(
172174
git_oid *out, git_odb *db, const git_oid *short_id, size_t len);
173175

176+
/**
177+
* The information about object IDs to query in `git_odb_expand_ids`,
178+
* which will be populated upon return.
179+
*/
180+
typedef struct git_odb_expand_id {
181+
/** The object ID to expand */
182+
git_oid id;
183+
184+
/**
185+
* The length of the object ID (in nibbles, or packets of 4 bits; the
186+
* number of hex characters)
187+
* */
188+
unsigned short length;
189+
190+
/**
191+
* The (optional) type of the object to search for; leave as `0` or set
192+
* to `GIT_OBJ_ANY` to query for any object matching the ID.
193+
*/
194+
git_otype type;
195+
} git_odb_expand_id;
196+
197+
/**
198+
* Determine if one or more objects can be found in the object database
199+
* by their abbreviated object ID and type. The given array will be
200+
* updated in place: for each abbreviated ID that is unique in the
201+
* database, and of the given type (if specified), the full object ID,
202+
* object ID length (`GIT_OID_HEXSZ`) and type will be written back to
203+
* the array. For IDs that are not found (or are ambiguous), the
204+
* array entry will be zeroed.
205+
*
206+
* Note that since this function operates on multiple objects, the
207+
* underlying database will not be asked to be reloaded if an object is
208+
* not found (which is unlike other object database operations.)
209+
*
210+
* @param db The database to be searched for the given objects.
211+
* @param ids An array of short object IDs to search for
212+
* @param count The length of the `ids` array
213+
* @return 0 on success or an error code on failure
214+
*/
215+
GIT_EXTERN(int) git_odb_expand_ids(
216+
git_odb *db,
217+
git_odb_expand_id *ids,
218+
size_t count);
219+
174220
/**
175221
* Refresh the object database to load newly added files.
176222
*

src/odb.c

Lines changed: 71 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include "git2/odb_backend.h"
2020
#include "git2/oid.h"
21+
#include "git2/oidarray.h"
2122

2223
#define GIT_ALTERNATES_FILE "info/alternates"
2324

@@ -651,7 +652,7 @@ int git_odb_exists(git_odb *db, const git_oid *id)
651652

652653
if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) {
653654
git_odb_object_free(object);
654-
return (int)true;
655+
return 1;
655656
}
656657

657658
if (odb_exists_1(db, id, false))
@@ -716,31 +717,83 @@ int git_odb_exists_prefix(
716717

717718
if (len < GIT_OID_MINPREFIXLEN)
718719
return git_odb__error_ambiguous("prefix length too short");
719-
if (len > GIT_OID_HEXSZ)
720-
len = GIT_OID_HEXSZ;
721720

722-
if (len == GIT_OID_HEXSZ) {
721+
if (len >= GIT_OID_HEXSZ) {
723722
if (git_odb_exists(db, short_id)) {
724723
if (out)
725724
git_oid_cpy(out, short_id);
726725
return 0;
727726
} else {
728-
return git_odb__error_notfound("no match for id prefix", short_id);
727+
return git_odb__error_notfound(
728+
"no match for id prefix", short_id, len);
729729
}
730730
}
731731

732-
/* just copy valid part of short_id */
733-
memcpy(&key.id, short_id->id, (len + 1) / 2);
734-
if (len & 1)
735-
key.id[len / 2] &= 0xF0;
732+
git_oid__cpy_prefix(&key, short_id, len);
736733

737734
error = odb_exists_prefix_1(out, db, &key, len, false);
738735

739736
if (error == GIT_ENOTFOUND && !git_odb_refresh(db))
740737
error = odb_exists_prefix_1(out, db, &key, len, true);
741738

742739
if (error == GIT_ENOTFOUND)
743-
return git_odb__error_notfound("no match for id prefix", &key);
740+
return git_odb__error_notfound("no match for id prefix", &key, len);
741+
742+
return error;
743+
}
744+
745+
int git_odb_expand_ids(
746+
git_odb *db,
747+
git_odb_expand_id *ids,
748+
size_t count)
749+
{
750+
size_t len, i;
751+
int error;
752+
753+
assert(db && ids);
754+
755+
for (i = 0; i < count; i++) {
756+
git_odb_expand_id *query = &ids[i];
757+
git_oid *actual_id = NULL, tmp;
758+
git_otype query_type = (query->type == GIT_OBJ_ANY) ? 0 : query->type;
759+
git_otype actual_type = 0;
760+
761+
/* if we were given a full object ID, simply look it up */
762+
if (query->length >= GIT_OID_HEXSZ) {
763+
error = git_odb_read_header(&len, &actual_type, db, &query->id);
764+
}
765+
766+
/* otherwise, resolve the short id to full, then (optionally)
767+
* read the header.
768+
*/
769+
else if (query->length >= GIT_OID_MINPREFIXLEN) {
770+
error = odb_exists_prefix_1(&tmp,
771+
db, &query->id, query->length, false);
772+
773+
if (!error) {
774+
actual_id = &tmp;
775+
error = git_odb_read_header(&len, &actual_type, db, &tmp);
776+
}
777+
}
778+
779+
if (error < 0 && error != GIT_ENOTFOUND && error != GIT_EAMBIGUOUS)
780+
break;
781+
782+
if (error == 0 && (query_type == actual_type || !query_type)) {
783+
if (actual_id)
784+
git_oid_cpy(&query->id, actual_id);
785+
786+
query->length = GIT_OID_HEXSZ;
787+
query->type = actual_type;
788+
} else {
789+
memset(&query->id, 0, sizeof(git_oid));
790+
query->length = 0;
791+
query->type = 0;
792+
}
793+
}
794+
795+
if (!error)
796+
giterr_clear();
744797

745798
return error;
746799
}
@@ -881,7 +934,7 @@ int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id)
881934
error = odb_read_1(out, db, id, true);
882935

883936
if (error == GIT_ENOTFOUND)
884-
return git_odb__error_notfound("no match for id", id);
937+
return git_odb__error_notfound("no match for id", id, GIT_OID_HEXSZ);
885938

886939
return error;
887940
}
@@ -956,18 +1009,15 @@ int git_odb_read_prefix(
9561009
return 0;
9571010
}
9581011

959-
/* just copy valid part of short_id */
960-
memcpy(&key.id, short_id->id, (len + 1) / 2);
961-
if (len & 1)
962-
key.id[len / 2] &= 0xF0;
1012+
git_oid__cpy_prefix(&key, short_id, len);
9631013

9641014
error = read_prefix_1(out, db, &key, len, false);
9651015

9661016
if (error == GIT_ENOTFOUND && !git_odb_refresh(db))
9671017
error = read_prefix_1(out, db, &key, len, true);
9681018

9691019
if (error == GIT_ENOTFOUND)
970-
return git_odb__error_notfound("no match for prefix", &key);
1020+
return git_odb__error_notfound("no match for prefix", &key, len);
9711021

9721022
return error;
9731023
}
@@ -1223,12 +1273,14 @@ int git_odb_refresh(struct git_odb *db)
12231273
return 0;
12241274
}
12251275

1226-
int git_odb__error_notfound(const char *message, const git_oid *oid)
1276+
int git_odb__error_notfound(
1277+
const char *message, const git_oid *oid, size_t oid_len)
12271278
{
12281279
if (oid != NULL) {
12291280
char oid_str[GIT_OID_HEXSZ + 1];
1230-
git_oid_tostr(oid_str, sizeof(oid_str), oid);
1231-
giterr_set(GITERR_ODB, "Object not found - %s (%s)", message, oid_str);
1281+
git_oid_tostr(oid_str, oid_len, oid);
1282+
giterr_set(GITERR_ODB, "Object not found - %s (%.*s)",
1283+
message, oid_len, oid_str);
12321284
} else
12331285
giterr_set(GITERR_ODB, "Object not found - %s", message);
12341286

src/odb.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ int git_odb__hashlink(git_oid *out, const char *path);
8282
/*
8383
* Generate a GIT_ENOTFOUND error for the ODB.
8484
*/
85-
int git_odb__error_notfound(const char *message, const git_oid *oid);
85+
int git_odb__error_notfound(
86+
const char *message, const git_oid *oid, size_t oid_len);
8687

8788
/*
8889
* Generate a GIT_EAMBIGUOUS error for the ODB.

src/odb_loose.c

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,8 @@ static int locate_object_short_oid(
547547

548548
/* Check that directory exists */
549549
if (git_path_isdir(object_location->ptr) == false)
550-
return git_odb__error_notfound("no matching loose object for prefix", short_oid);
550+
return git_odb__error_notfound("no matching loose object for prefix",
551+
short_oid, len);
551552

552553
state.dir_len = git_buf_len(object_location);
553554
state.short_oid_len = len;
@@ -560,7 +561,8 @@ static int locate_object_short_oid(
560561
return error;
561562

562563
if (!state.found)
563-
return git_odb__error_notfound("no matching loose object for prefix", short_oid);
564+
return git_odb__error_notfound("no matching loose object for prefix",
565+
short_oid, len);
564566

565567
if (state.found > 1)
566568
return git_odb__error_ambiguous("multiple matches in loose objects");
@@ -613,9 +615,10 @@ static int loose_backend__read_header(size_t *len_p, git_otype *type_p, git_odb_
613615
raw.len = 0;
614616
raw.type = GIT_OBJ_BAD;
615617

616-
if (locate_object(&object_path, (loose_backend *)backend, oid) < 0)
617-
error = git_odb__error_notfound("no matching loose object", oid);
618-
else if ((error = read_header_loose(&raw, &object_path)) == 0) {
618+
if (locate_object(&object_path, (loose_backend *)backend, oid) < 0) {
619+
error = git_odb__error_notfound("no matching loose object",
620+
oid, GIT_OID_HEXSZ);
621+
} else if ((error = read_header_loose(&raw, &object_path)) == 0) {
619622
*len_p = raw.len;
620623
*type_p = raw.type;
621624
}
@@ -633,9 +636,10 @@ static int loose_backend__read(void **buffer_p, size_t *len_p, git_otype *type_p
633636

634637
assert(backend && oid);
635638

636-
if (locate_object(&object_path, (loose_backend *)backend, oid) < 0)
637-
error = git_odb__error_notfound("no matching loose object", oid);
638-
else if ((error = read_loose(&raw, &object_path)) == 0) {
639+
if (locate_object(&object_path, (loose_backend *)backend, oid) < 0) {
640+
error = git_odb__error_notfound("no matching loose object",
641+
oid, GIT_OID_HEXSZ);
642+
} else if ((error = read_loose(&raw, &object_path)) == 0) {
639643
*buffer_p = raw.data;
640644
*len_p = raw.len;
641645
*type_p = raw.type;

src/odb_pack.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,8 @@ static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backen
264264
if (!pack_entry_find_inner(e, backend, oid, last_found))
265265
return 0;
266266

267-
return git_odb__error_notfound("failed to find pack entry", oid);
267+
return git_odb__error_notfound(
268+
"failed to find pack entry", oid, GIT_OID_HEXSZ);
268269
}
269270

270271
static int pack_entry_find_prefix(
@@ -309,7 +310,8 @@ static int pack_entry_find_prefix(
309310
}
310311

311312
if (!found)
312-
return git_odb__error_notfound("no matching pack entry for prefix", short_oid);
313+
return git_odb__error_notfound("no matching pack entry for prefix",
314+
short_oid, len);
313315
else
314316
return 0;
315317
}
@@ -333,7 +335,7 @@ static int pack_backend__refresh(git_odb_backend *backend_)
333335
return 0;
334336

335337
if (p_stat(backend->pack_folder, &st) < 0 || !S_ISDIR(st.st_mode))
336-
return git_odb__error_notfound("failed to refresh packfiles", NULL);
338+
return git_odb__error_notfound("failed to refresh packfiles", NULL, 0);
337339

338340
git_buf_sets(&path, backend->pack_folder);
339341

src/oid.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,13 @@ GIT_INLINE(int) git_oid__cmp(const git_oid *a, const git_oid *b)
4444
return git_oid__hashcmp(a->id, b->id);
4545
}
4646

47+
GIT_INLINE(void) git_oid__cpy_prefix(
48+
git_oid *out, const git_oid *id, size_t len)
49+
{
50+
memcpy(&out->id, id->id, (len + 1) / 2);
51+
52+
if (len & 1)
53+
out->id[len / 2] &= 0xF0;
54+
}
55+
4756
#endif

src/pack.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,7 +1018,7 @@ static int packfile_open(struct git_pack_file *p)
10181018
unsigned char *idx_sha1;
10191019

10201020
if (p->index_version == -1 && pack_index_open(p) < 0)
1021-
return git_odb__error_notfound("failed to open packfile", NULL);
1021+
return git_odb__error_notfound("failed to open packfile", NULL, 0);
10221022

10231023
/* if mwf opened by another thread, return now */
10241024
if (git_mutex_lock(&p->lock) < 0)
@@ -1099,7 +1099,7 @@ int git_packfile__name(char **out, const char *path)
10991099
path_len = strlen(path);
11001100

11011101
if (path_len < strlen(".idx"))
1102-
return git_odb__error_notfound("invalid packfile path", NULL);
1102+
return git_odb__error_notfound("invalid packfile path", NULL, 0);
11031103

11041104
if (git_buf_printf(&buf, "%.*s.pack", (int)(path_len - strlen(".idx")), path) < 0)
11051105
return -1;
@@ -1117,7 +1117,7 @@ int git_packfile_alloc(struct git_pack_file **pack_out, const char *path)
11171117
*pack_out = NULL;
11181118

11191119
if (path_len < strlen(".idx"))
1120-
return git_odb__error_notfound("invalid packfile path", NULL);
1120+
return git_odb__error_notfound("invalid packfile path", NULL, 0);
11211121

11221122
GITERR_CHECK_ALLOC_ADD(&alloc_len, sizeof(*p), path_len);
11231123
GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 2);
@@ -1143,7 +1143,7 @@ int git_packfile_alloc(struct git_pack_file **pack_out, const char *path)
11431143

11441144
if (p_stat(p->pack_name, &st) < 0 || !S_ISREG(st.st_mode)) {
11451145
git__free(p);
1146-
return git_odb__error_notfound("packfile not found", NULL);
1146+
return git_odb__error_notfound("packfile not found", NULL, 0);
11471147
}
11481148

11491149
/* ok, it looks sane as far as we can check without
@@ -1344,7 +1344,7 @@ static int pack_entry_find_offset(
13441344
}
13451345

13461346
if (!found)
1347-
return git_odb__error_notfound("failed to find offset for pack entry", short_oid);
1347+
return git_odb__error_notfound("failed to find offset for pack entry", short_oid, len);
13481348
if (found > 1)
13491349
return git_odb__error_ambiguous("found multiple offsets for pack entry");
13501350

0 commit comments

Comments
 (0)