refs: get rid of global list of hidden refs
We're about to add a new argument to git-rev-list(1) that allows it to add all references that are visible when taking `transfer.hideRefs` et al into account. This will require us to potentially parse multiple sets of hidden refs, which is not easily possible right now as there is only a single, global instance of the list of parsed hidden refs. Refactor `parse_hide_refs_config()` and `ref_is_hidden()` so that both take the list of hidden references as input and adjust callers to keep a local list, instead. This allows us to easily use multiple hidden-ref lists. Furthermore, it allows us to properly free this list before we exit. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Taylor Blau <me@ttaylorr.com>
Patrick Steinhardt committed
Nov 17, 2022 at 06:46 UTC
9b67eb6fbeb9666640f34cccf401cfea22f7bd22
5 files changed
+39
-31
builtin/receive-pack.c
+5
-3
@@ -80,6 +80,7 @@ static struct object_id push_cert_oid;
80
static struct signature_check sigcheck;
81
static const char *push_cert_nonce;
82
static const char *cert_nonce_seed;
83
+static struct string_list hidden_refs = STRING_LIST_INIT_DUP;
84
85
static const char *NONCE_UNSOLICITED = "UNSOLICITED";
86
static const char *NONCE_BAD = "BAD";
@@ -130,7 +131,7 @@ static enum deny_action parse_deny_action(const char *var, const char *value)
131
132
static int receive_pack_config(const char *var, const char *value, void *cb)
133
{
133
- int status = parse_hide_refs_config(var, value, "receive");
134
+ int status = parse_hide_refs_config(var, value, "receive", &hidden_refs);
135
136
if (status)
137
return status;
@@ -296,7 +297,7 @@ static int show_ref_cb(const char *path_full, const struct object_id *oid,
297
struct oidset *seen = data;
298
const char *path = strip_namespace(path_full);
299
299
- if (ref_is_hidden(path, path_full))
300
+ if (ref_is_hidden(path, path_full, &hidden_refs))
301
return 0;
302
303
/*
@@ -1794,7 +1795,7 @@ static void reject_updates_to_hidden(struct command *commands)
1795
strbuf_setlen(&refname_full, prefix_len);
1796
strbuf_addstr(&refname_full, cmd->ref_name);
1797
1797
- if (!ref_is_hidden(cmd->ref_name, refname_full.buf))
1798
+ if (!ref_is_hidden(cmd->ref_name, refname_full.buf, &hidden_refs))
1799
continue;
1800
if (is_null_oid(&cmd->new_oid))
1801
cmd->error_string = "deny deleting a hidden ref";
@@ -2591,6 +2592,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
2592
packet_flush(1);
2593
oid_array_clear(&shallow);
2594
oid_array_clear(&ref);
2595
+ string_list_clear(&hidden_refs, 0);
2596
free((void *)push_cert_nonce);
2597
return 0;
2598
}
ls-refs.c
+9
-4
@@ -6,6 +6,7 @@
6
#include "ls-refs.h"
7
#include "pkt-line.h"
8
#include "config.h"
9
+#include "string-list.h"
10
11
static int config_read;
12
static int advertise_unborn;
@@ -73,6 +74,7 @@ struct ls_refs_data {
74
unsigned symrefs;
75
struct strvec prefixes;
76
struct strbuf buf;
77
+ struct string_list hidden_refs;
78
unsigned unborn : 1;
79
};
80
@@ -84,7 +86,7 @@ static int send_ref(const char *refname, const struct object_id *oid,
86
87
strbuf_reset(&data->buf);
88
87
- if (ref_is_hidden(refname_nons, refname))
89
+ if (ref_is_hidden(refname_nons, refname, &data->hidden_refs))
90
return 0;
91
92
if (!ref_match(&data->prefixes, refname_nons))
@@ -137,14 +139,15 @@ static void send_possibly_unborn_head(struct ls_refs_data *data)
139
}
140
141
static int ls_refs_config(const char *var, const char *value,
140
- void *data UNUSED)
142
+ void *cb_data)
143
{
144
+ struct ls_refs_data *data = cb_data;
145
/*
146
* We only serve fetches over v2 for now, so respect only "uploadpack"
147
* config. This may need to eventually be expanded to "receive", but we
148
* don't yet know how that information will be passed to ls-refs.
149
*/
147
- return parse_hide_refs_config(var, value, "uploadpack");
150
+ return parse_hide_refs_config(var, value, "uploadpack", &data->hidden_refs);
151
}
152
153
int ls_refs(struct repository *r, struct packet_reader *request)
@@ -154,9 +157,10 @@ int ls_refs(struct repository *r, struct packet_reader *request)
157
memset(&data, 0, sizeof(data));
158
strvec_init(&data.prefixes);
159
strbuf_init(&data.buf, 0);
160
+ string_list_init_dup(&data.hidden_refs);
161
162
ensure_config_read();
159
- git_config(ls_refs_config, NULL);
163
+ git_config(ls_refs_config, &data);
164
165
while (packet_reader_read(request) == PACKET_READ_NORMAL) {
166
const char *arg = request->line;
@@ -195,6 +199,7 @@ int ls_refs(struct repository *r, struct packet_reader *request)
199
packet_fflush(stdout);
200
strvec_clear(&data.prefixes);
201
strbuf_release(&data.buf);
202
+ string_list_clear(&data.hidden_refs, 0);
203
return 0;
204
}
205
refs.c
+4
-10
@@ -1414,9 +1414,8 @@ char *shorten_unambiguous_ref(const char *refname, int strict)
1414
refname, strict);
1415
}
1416
1417
-static struct string_list *hide_refs;
1418
-
1419
-int parse_hide_refs_config(const char *var, const char *value, const char *section)
1417
+int parse_hide_refs_config(const char *var, const char *value, const char *section,
1418
+ struct string_list *hide_refs)
1419
{
1420
const char *key;
1421
if (!strcmp("transfer.hiderefs", var) ||
@@ -1431,21 +1430,16 @@ int parse_hide_refs_config(const char *var, const char *value, const char *secti
1430
len = strlen(ref);
1431
while (len && ref[len - 1] == '/')
1432
ref[--len] = '\0';
1434
- if (!hide_refs) {
1435
- CALLOC_ARRAY(hide_refs, 1);
1436
- hide_refs->strdup_strings = 1;
1437
- }
1433
string_list_append_nodup(hide_refs, ref);
1434
}
1435
return 0;
1436
}
1437
1443
-int ref_is_hidden(const char *refname, const char *refname_full)
1438
+int ref_is_hidden(const char *refname, const char *refname_full,
1439
+ const struct string_list *hide_refs)
1440
{
1441
int i;
1442
1447
- if (!hide_refs)
1448
- return 0;
1443
for (i = hide_refs->nr - 1; i >= 0; i--) {
1444
const char *match = hide_refs->items[i].string;
1445
const char *subject;
refs.h
+3
-2
@@ -808,7 +808,8 @@ int update_ref(const char *msg, const char *refname,
808
const struct object_id *new_oid, const struct object_id *old_oid,
809
unsigned int flags, enum action_on_err onerr);
810
811
-int parse_hide_refs_config(const char *var, const char *value, const char *);
811
+int parse_hide_refs_config(const char *var, const char *value, const char *,
812
+ struct string_list *);
813
814
/*
815
* Check whether a ref is hidden. If no namespace is set, both the first and
@@ -818,7 +819,7 @@ int parse_hide_refs_config(const char *var, const char *value, const char *);
819
* the ref is outside that namespace, the first parameter is NULL. The second
820
* parameter always points to the full ref name.
821
*/
821
-int ref_is_hidden(const char *, const char *);
822
+int ref_is_hidden(const char *, const char *, const struct string_list *);
823
824
/* Is this a per-worktree ref living in the refs/ namespace? */
825
int is_per_worktree_ref(const char *refname);
upload-pack.c
+18
-12
@@ -62,6 +62,7 @@ struct upload_pack_data {
62
struct object_array have_obj;
63
struct oid_array haves; /* v2 only */
64
struct string_list wanted_refs; /* v2 only */
65
+ struct string_list hidden_refs;
66
67
struct object_array shallows;
68
struct string_list deepen_not;
@@ -118,6 +119,7 @@ static void upload_pack_data_init(struct upload_pack_data *data)
119
{
120
struct string_list symref = STRING_LIST_INIT_DUP;
121
struct string_list wanted_refs = STRING_LIST_INIT_DUP;
122
+ struct string_list hidden_refs = STRING_LIST_INIT_DUP;
123
struct object_array want_obj = OBJECT_ARRAY_INIT;
124
struct object_array have_obj = OBJECT_ARRAY_INIT;
125
struct oid_array haves = OID_ARRAY_INIT;
@@ -130,6 +132,7 @@ static void upload_pack_data_init(struct upload_pack_data *data)
132
memset(data, 0, sizeof(*data));
133
data->symref = symref;
134
data->wanted_refs = wanted_refs;
135
+ data->hidden_refs = hidden_refs;
136
data->want_obj = want_obj;
137
data->have_obj = have_obj;
138
data->haves = haves;
@@ -151,6 +154,7 @@ static void upload_pack_data_clear(struct upload_pack_data *data)
154
{
155
string_list_clear(&data->symref, 1);
156
string_list_clear(&data->wanted_refs, 1);
157
+ string_list_clear(&data->hidden_refs, 0);
158
object_array_clear(&data->want_obj);
159
object_array_clear(&data->have_obj);
160
oid_array_clear(&data->haves);
@@ -842,8 +846,8 @@ static void deepen(struct upload_pack_data *data, int depth)
846
* Checking for reachable shallows requires that our refs be
847
* marked with OUR_REF.
848
*/
845
- head_ref_namespaced(check_ref, NULL);
846
- for_each_namespaced_ref(check_ref, NULL);
849
+ head_ref_namespaced(check_ref, data);
850
+ for_each_namespaced_ref(check_ref, data);
851
852
get_reachable_list(data, &reachable_shallows);
853
result = get_shallow_commits(&reachable_shallows,
@@ -1158,11 +1162,11 @@ static void receive_needs(struct upload_pack_data *data,
1162
1163
/* return non-zero if the ref is hidden, otherwise 0 */
1164
static int mark_our_ref(const char *refname, const char *refname_full,
1161
- const struct object_id *oid)
1165
+ const struct object_id *oid, const struct string_list *hidden_refs)
1166
{
1167
struct object *o = lookup_unknown_object(the_repository, oid);
1168
1165
- if (ref_is_hidden(refname, refname_full)) {
1169
+ if (ref_is_hidden(refname, refname_full, hidden_refs)) {
1170
o->flags |= HIDDEN_REF;
1171
return 1;
1172
}
@@ -1171,11 +1175,12 @@ static int mark_our_ref(const char *refname, const char *refname_full,
1175
}
1176
1177
static int check_ref(const char *refname_full, const struct object_id *oid,
1174
- int flag UNUSED, void *cb_data UNUSED)
1178
+ int flag UNUSED, void *cb_data)
1179
{
1180
const char *refname = strip_namespace(refname_full);
1181
+ struct upload_pack_data *data = cb_data;
1182
1178
- mark_our_ref(refname, refname_full, oid);
1183
+ mark_our_ref(refname, refname_full, oid, &data->hidden_refs);
1184
return 0;
1185
}
1186
@@ -1204,7 +1209,7 @@ static int send_ref(const char *refname, const struct object_id *oid,
1209
struct object_id peeled;
1210
struct upload_pack_data *data = cb_data;
1211
1207
- if (mark_our_ref(refname_nons, refname, oid))
1212
+ if (mark_our_ref(refname_nons, refname, oid, &data->hidden_refs))
1213
return 0;
1214
1215
if (capabilities) {
@@ -1327,7 +1332,7 @@ static int upload_pack_config(const char *var, const char *value, void *cb_data)
1332
if (parse_object_filter_config(var, value, data) < 0)
1333
return -1;
1334
1330
- return parse_hide_refs_config(var, value, "uploadpack");
1335
+ return parse_hide_refs_config(var, value, "uploadpack", &data->hidden_refs);
1336
}
1337
1338
static int upload_pack_protected_config(const char *var, const char *value, void *cb_data)
@@ -1375,8 +1380,8 @@ void upload_pack(const int advertise_refs, const int stateless_rpc,
1380
advertise_shallow_grafts(1);
1381
packet_flush(1);
1382
} else {
1378
- head_ref_namespaced(check_ref, NULL);
1379
- for_each_namespaced_ref(check_ref, NULL);
1383
+ head_ref_namespaced(check_ref, &data);
1384
+ for_each_namespaced_ref(check_ref, &data);
1385
}
1386
1387
if (!advertise_refs) {
@@ -1441,6 +1446,7 @@ static int parse_want(struct packet_writer *writer, const char *line,
1446
1447
static int parse_want_ref(struct packet_writer *writer, const char *line,
1448
struct string_list *wanted_refs,
1449
+ struct string_list *hidden_refs,
1450
struct object_array *want_obj)
1451
{
1452
const char *refname_nons;
@@ -1451,7 +1457,7 @@ static int parse_want_ref(struct packet_writer *writer, const char *line,
1457
struct strbuf refname = STRBUF_INIT;
1458
1459
strbuf_addf(&refname, "%s%s", get_git_namespace(), refname_nons);
1454
- if (ref_is_hidden(refname_nons, refname.buf) ||
1460
+ if (ref_is_hidden(refname_nons, refname.buf, hidden_refs) ||
1461
read_ref(refname.buf, &oid)) {
1462
packet_writer_error(writer, "unknown ref %s", refname_nons);
1463
die("unknown ref %s", refname_nons);
@@ -1508,7 +1514,7 @@ static void process_args(struct packet_reader *request,
1514
continue;
1515
if (data->allow_ref_in_want &&
1516
parse_want_ref(&data->writer, arg, &data->wanted_refs,
1511
- &data->want_obj))
1517
+ &data->hidden_refs, &data->want_obj))
1518
continue;
1519
/* process have line */
1520
if (parse_have(arg, &data->haves))