|
6 | 6 | #include "run-command.h"
|
7 | 7 | #include "remote.h"
|
8 | 8 | #include "url.h"
|
| 9 | +#include "string-list.h" |
9 | 10 |
|
10 | 11 | static char *server_capabilities;
|
11 | 12 | static const char *parse_feature_value(const char *, const char *, int *);
|
@@ -60,13 +61,69 @@ static void die_initial_contact(int got_at_least_one_head)
|
60 | 61 | "and the repository exists.");
|
61 | 62 | }
|
62 | 63 |
|
| 64 | +static void parse_one_symref_info(struct string_list *symref, const char *val, int len) |
| 65 | +{ |
| 66 | + char *sym, *target; |
| 67 | + struct string_list_item *item; |
| 68 | + |
| 69 | + if (!len) |
| 70 | + return; /* just "symref" */ |
| 71 | + /* e.g. "symref=HEAD:refs/heads/master" */ |
| 72 | + sym = xmalloc(len + 1); |
| 73 | + memcpy(sym, val, len); |
| 74 | + sym[len] = '\0'; |
| 75 | + target = strchr(sym, ':'); |
| 76 | + if (!target) |
| 77 | + /* just "symref=something" */ |
| 78 | + goto reject; |
| 79 | + *(target++) = '\0'; |
| 80 | + if (check_refname_format(sym, REFNAME_ALLOW_ONELEVEL) || |
| 81 | + check_refname_format(target, REFNAME_ALLOW_ONELEVEL)) |
| 82 | + /* "symref=bogus:pair */ |
| 83 | + goto reject; |
| 84 | + item = string_list_append(symref, sym); |
| 85 | + item->util = target; |
| 86 | + return; |
| 87 | +reject: |
| 88 | + free(sym); |
| 89 | + return; |
| 90 | +} |
| 91 | + |
| 92 | +static void annotate_refs_with_symref_info(struct ref *ref) |
| 93 | +{ |
| 94 | + struct string_list symref = STRING_LIST_INIT_DUP; |
| 95 | + const char *feature_list = server_capabilities; |
| 96 | + |
| 97 | + while (feature_list) { |
| 98 | + int len; |
| 99 | + const char *val; |
| 100 | + |
| 101 | + val = parse_feature_value(feature_list, "symref", &len); |
| 102 | + if (!val) |
| 103 | + break; |
| 104 | + parse_one_symref_info(&symref, val, len); |
| 105 | + feature_list = val + 1; |
| 106 | + } |
| 107 | + sort_string_list(&symref); |
| 108 | + |
| 109 | + for (; ref; ref = ref->next) { |
| 110 | + struct string_list_item *item; |
| 111 | + item = string_list_lookup(&symref, ref->name); |
| 112 | + if (!item) |
| 113 | + continue; |
| 114 | + ref->symref = xstrdup((char *)item->util); |
| 115 | + } |
| 116 | + string_list_clear(&symref, 0); |
| 117 | +} |
| 118 | + |
63 | 119 | /*
|
64 | 120 | * Read all the refs from the other end
|
65 | 121 | */
|
66 | 122 | struct ref **get_remote_heads(int in, char *src_buf, size_t src_len,
|
67 | 123 | struct ref **list, unsigned int flags,
|
68 | 124 | struct extra_have_objects *extra_have)
|
69 | 125 | {
|
| 126 | + struct ref **orig_list = list; |
70 | 127 | int got_at_least_one_head = 0;
|
71 | 128 |
|
72 | 129 | *list = NULL;
|
@@ -114,6 +171,9 @@ struct ref **get_remote_heads(int in, char *src_buf, size_t src_len,
|
114 | 171 | list = &ref->next;
|
115 | 172 | got_at_least_one_head = 1;
|
116 | 173 | }
|
| 174 | + |
| 175 | + annotate_refs_with_symref_info(*orig_list); |
| 176 | + |
117 | 177 | return list;
|
118 | 178 | }
|
119 | 179 |
|
|
0 commit comments