2727#include <string.h>
2828#include <git2.h>
2929#include <git2/sys/odb_backend.h>
30+ #include <git2/sys/refdb_backend.h>
31+ #include <git2/sys/refs.h>
3032#include <hiredis/hiredis.h>
3133
3234typedef struct {
@@ -37,6 +39,25 @@ typedef struct {
3739 redisContext * db ;
3840} hiredis_odb_backend ;
3941
42+ typedef struct {
43+ git_refdb_backend parent ;
44+
45+ const char * prefix ;
46+ const char * repo_path ;
47+ redisContext * db ;
48+ } hiredis_refdb_backend ;
49+
50+ typedef struct {
51+ git_reference_iterator parent ;
52+
53+ size_t current ;
54+ redisReply * keys ;
55+
56+ hiredis_refdb_backend * backend ;
57+ } hiredis_refdb_iterator ;
58+
59+ /* Odb methods */
60+
4061int hiredis_odb_backend__read_header (size_t * len_p , git_otype * type_p , git_odb_backend * _backend , const git_oid * oid )
4162{
4263 hiredis_odb_backend * backend ;
@@ -197,6 +218,274 @@ void hiredis_odb_backend__free(git_odb_backend *_backend)
197218 free (backend );
198219}
199220
221+ /* Refdb methods */
222+
223+ int hiredis_refdb_backend__exists (int * exists , git_refdb_backend * _backend , const char * ref_name )
224+ {
225+ hiredis_refdb_backend * backend ;
226+ int error = GIT_OK ;
227+ redisReply * reply ;
228+
229+ assert (ref_name && _backend );
230+
231+ backend = (hiredis_refdb_backend * ) _backend ;
232+
233+ reply = redisCommand (backend -> db , "EXISTS %s:%s:refdb:%s" , backend -> prefix , backend -> repo_path , ref_name );
234+ if (reply -> type == REDIS_REPLY_INTEGER ) {
235+ * exists = reply -> integer ;
236+ } else {
237+ giterr_set_str (GITERR_REFERENCE , "Redis refdb storage error" );
238+ error = GIT_ERROR ;
239+ }
240+
241+ freeReplyObject (reply );
242+ return error ;
243+ }
244+
245+ int hiredis_refdb_backend__lookup (git_reference * * out , git_refdb_backend * _backend , const char * ref_name )
246+ {
247+ hiredis_refdb_backend * backend ;
248+ int error = GIT_OK ;
249+ redisReply * reply ;
250+ git_oid oid ;
251+
252+ assert (ref_name && _backend );
253+
254+ backend = (hiredis_refdb_backend * ) _backend ;
255+
256+ reply = redisCommand (backend -> db , "HMGET %s:%s:refdb:%s type target" , backend -> prefix , backend -> repo_path , ref_name );
257+ if (reply -> type == REDIS_REPLY_ARRAY ) {
258+ if (reply -> element [0 ]-> type != REDIS_REPLY_NIL && reply -> element [1 ]-> type != REDIS_REPLY_NIL ) {
259+ git_ref_t type = (git_ref_t ) atoi (reply -> element [0 ]-> str );
260+
261+ if (type == GIT_REF_OID ) {
262+ git_oid_fromstr (& oid , reply -> element [1 ]-> str );
263+ * out = git_reference__alloc (ref_name , & oid , NULL );
264+ } else if (type == GIT_REF_SYMBOLIC ) {
265+ * out = git_reference__alloc_symbolic (ref_name , reply -> element [1 ]-> str );
266+ } else {
267+ giterr_set_str (GITERR_REFERENCE , "Redis refdb storage corrupted (unknown ref type returned)" );
268+ error = GIT_ERROR ;
269+ }
270+
271+ } else {
272+ giterr_set_str (GITERR_REFERENCE , "Redis refdb couldn't find ref" );
273+ error = GIT_ENOTFOUND ;
274+ }
275+ } else {
276+ giterr_set_str (GITERR_REFERENCE , "Redis refdb storage error" );
277+ error = GIT_ERROR ;
278+ }
279+
280+ freeReplyObject (reply );
281+ return error ;
282+ }
283+
284+ int hiredis_refdb_backend__iterator_next (git_reference * * ref , git_reference_iterator * _iter ) {
285+ hiredis_refdb_iterator * iter ;
286+ hiredis_refdb_backend * backend ;
287+ char * ref_name ;
288+ int error ;
289+
290+ assert (_iter );
291+ iter = (hiredis_refdb_iterator * ) _iter ;
292+
293+ if (iter -> current < iter -> keys -> elements ) {
294+ ref_name = strstr (iter -> keys -> element [iter -> current ++ ]-> str , ":refdb:" ) + 7 ;
295+ error = hiredis_refdb_backend__lookup (ref , (git_refdb_backend * ) iter -> backend , ref_name );
296+
297+ return error ;
298+ } else {
299+ return GIT_ITEROVER ;
300+ }
301+ }
302+
303+ int hiredis_refdb_backend__iterator_next_name (const char * * ref_name , git_reference_iterator * _iter ) {
304+ hiredis_refdb_iterator * iter ;
305+
306+ assert (_iter );
307+ iter = (hiredis_refdb_iterator * ) _iter ;
308+
309+ if (iter -> current < iter -> keys -> elements ) {
310+ * ref_name = strdup (strstr (iter -> keys -> element [iter -> current ++ ]-> str , ":refdb:" ) + 7 );
311+
312+ return GIT_OK ;
313+ } else {
314+ return GIT_ITEROVER ;
315+ }
316+ }
317+
318+ void hiredis_refdb_backend__iterator_free (git_reference_iterator * _iter ) {
319+ hiredis_refdb_iterator * iter ;
320+
321+ assert (_iter );
322+ iter = (hiredis_refdb_iterator * ) _iter ;
323+
324+ freeReplyObject (iter -> keys );
325+
326+ free (iter );
327+ }
328+
329+ int hiredis_refdb_backend__iterator (git_reference_iterator * * _iter , struct git_refdb_backend * _backend , const char * glob )
330+ {
331+ hiredis_refdb_backend * backend ;
332+ hiredis_refdb_iterator * iterator ;
333+ int error = GIT_OK ;
334+ redisReply * reply ;
335+
336+ assert (_backend );
337+
338+ backend = (hiredis_refdb_backend * ) _backend ;
339+
340+ reply = redisCommand (backend -> db , "KEYS %s:%s:refdb:%s" , backend -> prefix , backend -> repo_path , (glob != NULL ? glob : "*" ));
341+ if (reply -> type != REDIS_REPLY_ARRAY ) {
342+ freeReplyObject (reply );
343+ giterr_set_str (GITERR_REFERENCE , "Redis refdb storage error" );
344+ return GIT_ERROR ;
345+ }
346+
347+ iterator = calloc (1 , sizeof (hiredis_refdb_iterator ));
348+
349+ iterator -> backend = backend ;
350+ iterator -> keys = reply ;
351+
352+ iterator -> parent .next = & hiredis_refdb_backend__iterator_next ;
353+ iterator -> parent .next_name = & hiredis_refdb_backend__iterator_next_name ;
354+ iterator -> parent .free = & hiredis_refdb_backend__iterator_free ;
355+
356+ * _iter = (git_reference_iterator * ) iterator ;
357+
358+ return GIT_OK ;
359+ }
360+
361+ int hiredis_refdb_backend__write (git_refdb_backend * _backend , const git_reference * ref , int force , const git_signature * who ,
362+ const char * message ) // FIXME when rugged gets updated to the latest libgit2 update this to the latest backend API
363+ {
364+ hiredis_refdb_backend * backend ;
365+ int error = GIT_OK ;
366+ redisReply * reply ;
367+
368+ const char * name = git_reference_name (ref );
369+ const git_oid * target ;
370+ const char * symbolic_target ;
371+ char oid_str [GIT_OID_HEXSZ + 1 ];
372+
373+ assert (ref && _backend );
374+
375+ backend = (hiredis_refdb_backend * ) _backend ;
376+
377+ target = git_reference_target (ref );
378+ symbolic_target = git_reference_symbolic_target (ref );
379+
380+ /* FIXME handle force correctly */
381+
382+ if (target ) {
383+ git_oid_nfmt (oid_str , sizeof (oid_str ), target );
384+ reply = redisCommand (backend -> db , "HMSET %s:%s:refdb:%s type %d target %s" , backend -> prefix , backend -> repo_path , name , GIT_REF_OID , oid_str );
385+ } else {
386+ symbolic_target = git_reference_symbolic_target (ref );
387+ reply = redisCommand (backend -> db , "HMSET %s:%s:refdb:%s type %d target %s" , backend -> prefix , backend -> repo_path , name , GIT_REF_SYMBOLIC , symbolic_target );
388+ }
389+
390+ if (reply -> type == REDIS_REPLY_ERROR ) {
391+ giterr_set_str (GITERR_REFERENCE , "Redis refdb storage error" );
392+ error = GIT_ERROR ;
393+ }
394+
395+ freeReplyObject (reply );
396+ return error ;
397+ }
398+
399+ int hiredis_refdb_backend__rename (git_reference * * out , git_refdb_backend * _backend , const char * old_name ,
400+ const char * new_name , int force , const git_signature * who , const char * message )
401+ {
402+ hiredis_refdb_backend * backend ;
403+ int error = GIT_OK ;
404+ redisReply * reply ;
405+
406+ assert (old_name && new_name && _backend );
407+
408+ backend = (hiredis_refdb_backend * ) _backend ;
409+
410+ reply = redisCommand (backend -> db , "RENAME %s:%s:refdb:%s %s:%s:refdb:%s" ,
411+ backend -> prefix , backend -> repo_path , old_name , backend -> prefix , backend -> repo_path , new_name );
412+ if (reply -> type == REDIS_REPLY_ERROR ) {
413+ freeReplyObject (reply );
414+
415+ giterr_set_str (GITERR_REFERENCE , "Redis refdb storage error" );
416+ return GIT_ERROR ;
417+ }
418+
419+ freeReplyObject (reply );
420+ return hiredis_refdb_backend__lookup (out , _backend , new_name );
421+ }
422+
423+ int hiredis_refdb_backend__del (git_refdb_backend * _backend , const char * ref_name ) // FIXME when rugged gets updated to the latest libgit2 update this to the latest backend API
424+ {
425+ hiredis_refdb_backend * backend ;
426+ int error = GIT_OK ;
427+ redisReply * reply ;
428+
429+ assert (ref_name && _backend );
430+
431+ backend = (hiredis_refdb_backend * ) _backend ;
432+
433+ reply = redisCommand (backend -> db , "DEL %s:%s:refdb:%s" , backend -> prefix , backend -> repo_path , ref_name );
434+ if (reply -> type == REDIS_REPLY_ERROR ) {
435+ giterr_set_str (GITERR_REFERENCE , "Redis refdb storage error" );
436+ error = GIT_ERROR ;
437+ }
438+
439+ freeReplyObject (reply );
440+ return error ;
441+ }
442+
443+ void hiredis_refdb_backend__free (git_refdb_backend * _backend )
444+ {
445+ hiredis_refdb_backend * backend ;
446+
447+ assert (_backend );
448+ backend = (hiredis_refdb_backend * ) _backend ;
449+
450+ redisFree (backend -> db );
451+
452+ free (backend );
453+ }
454+
455+ /* reflog methods */
456+
457+ int hiredis_refdb_backend__has_log (git_refdb_backend * _backend , const char * refname )
458+ {
459+ return 0 ;
460+ }
461+
462+ int hiredis_refdb_backend__ensure_log (git_refdb_backend * _backend , const char * refname )
463+ {
464+ return GIT_ERROR ;
465+ }
466+
467+ int hiredis_refdb_backend__reflog_read (git_reflog * * out , git_refdb_backend * _backend , const char * name )
468+ {
469+ return GIT_ERROR ;
470+ }
471+
472+ int hiredis_refdb_backend__reflog_write (git_refdb_backend * _backend , git_reflog * reflog )
473+ {
474+ return GIT_ERROR ;
475+ }
476+
477+ int hiredis_refdb_backend__reflog_rename (git_refdb_backend * _backend , const char * old_name , const char * new_name )
478+ {
479+ return GIT_ERROR ;
480+ }
481+
482+ int hiredis_refdb_backend__reflog_delete (git_refdb_backend * _backend , const char * name )
483+ {
484+ return GIT_ERROR ;
485+ }
486+
487+ /* Constructors */
488+
200489int git_odb_backend_hiredis (git_odb_backend * * backend_out , const char * prefix , const char * path , const char * host , int port )
201490{
202491 hiredis_odb_backend * backend ;
@@ -231,3 +520,43 @@ int git_odb_backend_hiredis(git_odb_backend **backend_out, const char* prefix, c
231520
232521 return GIT_OK ;
233522}
523+
524+ int git_refdb_backend_hiredis (git_refdb_backend * * backend_out , const char * prefix , const char * path , const char * host , int port )
525+ {
526+ hiredis_refdb_backend * backend ;
527+
528+ backend = calloc (1 , sizeof (hiredis_refdb_backend ));
529+ if (backend == NULL )
530+ return GITERR_NOMEMORY ;
531+
532+ backend -> db = redisConnect (host , port );
533+ if (backend -> db -> err ) {
534+ free (backend );
535+ giterr_set_str (GITERR_REFERENCE , "Redis refdb storage couldn't connect to redis server" );
536+ return GIT_ERROR ;
537+ }
538+
539+ backend -> prefix = prefix ;
540+ backend -> repo_path = path ;
541+
542+ backend -> parent .exists = & hiredis_refdb_backend__exists ;
543+ backend -> parent .lookup = & hiredis_refdb_backend__lookup ;
544+ backend -> parent .iterator = & hiredis_refdb_backend__iterator ;
545+ backend -> parent .write = & hiredis_refdb_backend__write ;
546+ backend -> parent .del = & hiredis_refdb_backend__del ;
547+ backend -> parent .rename = & hiredis_refdb_backend__rename ;
548+ backend -> parent .compress = NULL ;
549+ backend -> parent .free = & hiredis_refdb_backend__free ;
550+
551+ backend -> parent .has_log = & hiredis_refdb_backend__has_log ;
552+ backend -> parent .ensure_log = & hiredis_refdb_backend__ensure_log ;
553+ backend -> parent .reflog_read = & hiredis_refdb_backend__reflog_read ;
554+ backend -> parent .reflog_write = & hiredis_refdb_backend__reflog_write ;
555+ backend -> parent .reflog_rename = & hiredis_refdb_backend__reflog_rename ;
556+ backend -> parent .reflog_delete = & hiredis_refdb_backend__reflog_delete ;
557+
558+ * backend_out = (git_refdb_backend * ) backend ;
559+
560+ return GIT_OK ;
561+ }
562+
0 commit comments