|
13 | 13 | #include "reflog.h" |
14 | 14 | #include "refdb.h" |
15 | 15 | #include "refdb_fs.h" |
| 16 | +#include "iterator.h" |
16 | 17 |
|
17 | 18 | #include <git2/tag.h> |
18 | 19 | #include <git2/object.h> |
@@ -652,6 +653,128 @@ static int refdb_fs_backend__foreach( |
652 | 653 | return data.callback_error ? GIT_EUSER : result; |
653 | 654 | } |
654 | 655 |
|
| 656 | +typedef struct { |
| 657 | + git_reference_iterator parent; |
| 658 | + unsigned int loose; |
| 659 | + /* packed */ |
| 660 | + git_strmap *h; |
| 661 | + khiter_t k; |
| 662 | + /* loose */ |
| 663 | + git_iterator *fsiter; |
| 664 | + git_buf buf; |
| 665 | +} refdb_fs_iter; |
| 666 | + |
| 667 | +static int refdb_fs_backend__iterator(git_reference_iterator **out, git_refdb_backend *_backend) |
| 668 | +{ |
| 669 | + refdb_fs_iter *iter; |
| 670 | + refdb_fs_backend *backend; |
| 671 | + |
| 672 | + assert(_backend); |
| 673 | + backend = (refdb_fs_backend *)_backend; |
| 674 | + |
| 675 | + if (packed_load(backend) < 0) |
| 676 | + return -1; |
| 677 | + |
| 678 | + iter = git__calloc(1, sizeof(refdb_fs_iter)); |
| 679 | + GITERR_CHECK_ALLOC(iter); |
| 680 | + |
| 681 | + iter->parent.backend = _backend; |
| 682 | + iter->h = backend->refcache.packfile; |
| 683 | + iter->k = kh_begin(backend->refcache.packfile); |
| 684 | + |
| 685 | + *out = (git_reference_iterator *)iter; |
| 686 | + |
| 687 | + return 0; |
| 688 | +} |
| 689 | + |
| 690 | +static void refdb_fs_backend__iterator_free(git_reference_iterator *_iter) |
| 691 | +{ |
| 692 | + refdb_fs_iter *iter = (refdb_fs_iter *) _iter; |
| 693 | + |
| 694 | + git_buf_free(&iter->buf); |
| 695 | + git_iterator_free(iter->fsiter); |
| 696 | + git__free(iter); |
| 697 | +} |
| 698 | + |
| 699 | +static int iter_packed(const char **out, refdb_fs_iter *iter) |
| 700 | +{ |
| 701 | + /* Move forward to the next entry */ |
| 702 | + while (!kh_exist(iter->h, iter->k)) { |
| 703 | + iter->k++; |
| 704 | + if (iter->k == kh_end(iter->h)) |
| 705 | + return GIT_ITEROVER; |
| 706 | + } |
| 707 | + |
| 708 | + *out = kh_key(iter->h, iter->k); |
| 709 | + iter->k++; |
| 710 | + |
| 711 | + return 0; |
| 712 | +} |
| 713 | + |
| 714 | +static int iter_loose(const char **out, refdb_fs_iter *iter) |
| 715 | +{ |
| 716 | + const git_index_entry *entry; |
| 717 | + int retry; |
| 718 | + git_strmap *packfile_refs; |
| 719 | + refdb_fs_backend *backend = (refdb_fs_backend *) iter->parent.backend; |
| 720 | + |
| 721 | + packfile_refs = backend->refcache.packfile; |
| 722 | + |
| 723 | + do { |
| 724 | + khiter_t pos; |
| 725 | + if (git_iterator_current(&entry, iter->fsiter) < 0) |
| 726 | + return -1; |
| 727 | + |
| 728 | + git_buf_clear(&iter->buf); |
| 729 | + if (!entry) |
| 730 | + return GIT_ITEROVER; |
| 731 | + |
| 732 | + if (git_buf_printf(&iter->buf, "refs/%s", entry->path) < 0) |
| 733 | + return -1; |
| 734 | + |
| 735 | + git_iterator_advance(NULL, iter->fsiter); |
| 736 | + |
| 737 | + /* Skip this one if we already listed it in packed */ |
| 738 | + pos = git_strmap_lookup_index(packfile_refs, git_buf_cstr(&iter->buf)); |
| 739 | + retry = 0; |
| 740 | + if (git_strmap_valid_index(packfile_refs, pos) || |
| 741 | + !git_reference_is_valid_name(git_buf_cstr(&iter->buf))) |
| 742 | + retry = 1; |
| 743 | + |
| 744 | + *out = git_buf_cstr(&iter->buf); |
| 745 | + } while (retry); |
| 746 | + |
| 747 | + return 0; |
| 748 | +} |
| 749 | + |
| 750 | +static int iter_loose_setup(refdb_fs_iter *iter) |
| 751 | +{ |
| 752 | + refdb_fs_backend *backend = (refdb_fs_backend *) iter->parent.backend; |
| 753 | + |
| 754 | + git_buf_clear(&iter->buf); |
| 755 | + if (git_buf_printf(&iter->buf, "%s/refs", backend->path) < 0) |
| 756 | + return -1; |
| 757 | + |
| 758 | + return git_iterator_for_filesystem(&iter->fsiter, git_buf_cstr(&iter->buf), 0, NULL, NULL); |
| 759 | +} |
| 760 | + |
| 761 | +static int refdb_fs_backend__next(const char **out, git_reference_iterator *_iter) |
| 762 | +{ |
| 763 | + refdb_fs_iter *iter = (refdb_fs_iter *)_iter; |
| 764 | + |
| 765 | + /* First round of checks to make sure where we are */ |
| 766 | + if (!iter->loose && iter->k == kh_end(iter->h)) { |
| 767 | + if (iter_loose_setup(iter) < 0) |
| 768 | + return -1; |
| 769 | + iter->loose = 1; |
| 770 | + } |
| 771 | + |
| 772 | + if (!iter->loose) |
| 773 | + return iter_packed(out, iter); |
| 774 | + else |
| 775 | + return iter_loose(out, iter); |
| 776 | +} |
| 777 | + |
655 | 778 | static int loose_write(refdb_fs_backend *backend, const git_reference *ref) |
656 | 779 | { |
657 | 780 | git_filebuf file = GIT_FILEBUF_INIT; |
@@ -1082,6 +1205,9 @@ int git_refdb_backend_fs( |
1082 | 1205 | backend->parent.exists = &refdb_fs_backend__exists; |
1083 | 1206 | backend->parent.lookup = &refdb_fs_backend__lookup; |
1084 | 1207 | backend->parent.foreach = &refdb_fs_backend__foreach; |
| 1208 | + backend->parent.iterator = &refdb_fs_backend__iterator; |
| 1209 | + backend->parent.next = &refdb_fs_backend__next; |
| 1210 | + backend->parent.iterator_free = &refdb_fs_backend__iterator_free; |
1085 | 1211 | backend->parent.write = &refdb_fs_backend__write; |
1086 | 1212 | backend->parent.delete = &refdb_fs_backend__delete; |
1087 | 1213 | backend->parent.compress = &refdb_fs_backend__compress; |
|
0 commit comments