ls-refs.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. #include "cache.h"
  2. #include "repository.h"
  3. #include "refs.h"
  4. #include "remote.h"
  5. #include "strvec.h"
  6. #include "ls-refs.h"
  7. #include "pkt-line.h"
  8. #include "config.h"
  9. /*
  10. * Check if one of the prefixes is a prefix of the ref.
  11. * If no prefixes were provided, all refs match.
  12. */
  13. static int ref_match(const struct strvec *prefixes, const char *refname)
  14. {
  15. int i;
  16. if (!prefixes->nr)
  17. return 1; /* no restriction */
  18. for (i = 0; i < prefixes->nr; i++) {
  19. const char *prefix = prefixes->v[i];
  20. if (starts_with(refname, prefix))
  21. return 1;
  22. }
  23. return 0;
  24. }
  25. struct ls_refs_data {
  26. unsigned peel;
  27. unsigned symrefs;
  28. struct strvec prefixes;
  29. };
  30. static int send_ref(const char *refname, const struct object_id *oid,
  31. int flag, void *cb_data)
  32. {
  33. struct ls_refs_data *data = cb_data;
  34. const char *refname_nons = strip_namespace(refname);
  35. struct strbuf refline = STRBUF_INIT;
  36. if (ref_is_hidden(refname_nons, refname))
  37. return 0;
  38. if (!ref_match(&data->prefixes, refname_nons))
  39. return 0;
  40. strbuf_addf(&refline, "%s %s", oid_to_hex(oid), refname_nons);
  41. if (data->symrefs && flag & REF_ISSYMREF) {
  42. struct object_id unused;
  43. const char *symref_target = resolve_ref_unsafe(refname, 0,
  44. &unused,
  45. &flag);
  46. if (!symref_target)
  47. die("'%s' is a symref but it is not?", refname);
  48. strbuf_addf(&refline, " symref-target:%s",
  49. strip_namespace(symref_target));
  50. }
  51. if (data->peel) {
  52. struct object_id peeled;
  53. if (!peel_ref(refname, &peeled))
  54. strbuf_addf(&refline, " peeled:%s", oid_to_hex(&peeled));
  55. }
  56. strbuf_addch(&refline, '\n');
  57. packet_write(1, refline.buf, refline.len);
  58. strbuf_release(&refline);
  59. return 0;
  60. }
  61. static int ls_refs_config(const char *var, const char *value, void *data)
  62. {
  63. /*
  64. * We only serve fetches over v2 for now, so respect only "uploadpack"
  65. * config. This may need to eventually be expanded to "receive", but we
  66. * don't yet know how that information will be passed to ls-refs.
  67. */
  68. return parse_hide_refs_config(var, value, "uploadpack");
  69. }
  70. int ls_refs(struct repository *r, struct strvec *keys,
  71. struct packet_reader *request)
  72. {
  73. struct ls_refs_data data;
  74. memset(&data, 0, sizeof(data));
  75. git_config(ls_refs_config, NULL);
  76. while (packet_reader_read(request) == PACKET_READ_NORMAL) {
  77. const char *arg = request->line;
  78. const char *out;
  79. if (!strcmp("peel", arg))
  80. data.peel = 1;
  81. else if (!strcmp("symrefs", arg))
  82. data.symrefs = 1;
  83. else if (skip_prefix(arg, "ref-prefix ", &out))
  84. strvec_push(&data.prefixes, out);
  85. }
  86. if (request->status != PACKET_READ_FLUSH)
  87. die(_("expected flush after ls-refs arguments"));
  88. head_ref_namespaced(send_ref, &data);
  89. for_each_namespaced_ref(send_ref, &data);
  90. packet_flush(1);
  91. strvec_clear(&data.prefixes);
  92. return 0;
  93. }