Skip to content

Commit 603f6b9

Browse files
committed
Merge branch 'ej/cat-file-remote-object-info' into jch
"git cat-file --batch" and friends can optionally ask a remote server about objects it does not have. * ej/cat-file-remote-object-info: cat-file: add remote-object-info to batch-command transport: add client support for object-info serve: advertise object-info feature fetch-pack: move fetch initialization fetch-pack: refactor packet writing t1006: split test utility functions into new "lib-cat-file.sh" cat-file: add declaration of variable i inside its for loop git-compat-util: add strtoul_ul() with error handling
2 parents a600c96 + 802a553 commit 603f6b9

21 files changed

+1067
-68
lines changed

Documentation/git-cat-file.adoc

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,13 @@ info <object>::
149149
Print object info for object reference `<object>`. This corresponds to the
150150
output of `--batch-check`.
151151

152+
remote-object-info <remote> <object>...::
153+
Print object info for object references `<object>` at specified
154+
`<remote>` without downloading objects from the remote.
155+
Raise an error when the `object-info` capability is not supported by the remote.
156+
Raise an error when no object references are provided.
157+
This command may be combined with `--buffer`.
158+
152159
flush::
153160
Used with `--buffer` to execute all preceding commands that were issued
154161
since the beginning or since the last flush was issued. When `--buffer`
@@ -290,21 +297,23 @@ newline. The available atoms are:
290297
The full hex representation of the object name.
291298

292299
`objecttype`::
293-
The type of the object (the same as `cat-file -t` reports).
300+
The type of the object (the same as `cat-file -t` reports). See
301+
`CAVEATS` below. Not supported by `remote-object-info`.
294302

295303
`objectsize`::
296304
The size, in bytes, of the object (the same as `cat-file -s`
297305
reports).
298306

299307
`objectsize:disk`::
300308
The size, in bytes, that the object takes up on disk. See the
301-
note about on-disk sizes in the `CAVEATS` section below.
309+
note about on-disk sizes in the `CAVEATS` section below. Not
310+
supported by `remote-object-info`.
302311

303312
`deltabase`::
304313
If the object is stored as a delta on-disk, this expands to the
305314
full hex representation of the delta base object name.
306315
Otherwise, expands to the null OID (all zeroes). See `CAVEATS`
307-
below.
316+
below. Not supported by `remote-object-info`.
308317

309318
`rest`::
310319
If this atom is used in the output string, input lines are split
@@ -314,7 +323,10 @@ newline. The available atoms are:
314323
line) are output in place of the `%(rest)` atom.
315324

316325
If no format is specified, the default format is `%(objectname)
317-
%(objecttype) %(objectsize)`.
326+
%(objecttype) %(objectsize)`, except for `remote-object-info` commands which use
327+
`%(objectname) %(objectsize)` for now because "%(objecttype)" is not supported yet.
328+
WARNING: When "%(objecttype)" is supported, the default format WILL be unified, so
329+
DO NOT RELY on the current default format to stay the same!!!
318330

319331
If `--batch` is specified, or if `--batch-command` is used with the `contents`
320332
command, the object information is followed by the object contents (consisting
@@ -396,6 +408,10 @@ scripting purposes.
396408
CAVEATS
397409
-------
398410
411+
Note that since %(objecttype), %(objectsize:disk) and %(deltabase) are
412+
currently not supported by the `remote-object-info` command, we will raise
413+
an error and exit when they appear in the format string.
414+
399415
Note that the sizes of objects on disk are reported accurately, but care
400416
should be taken in drawing conclusions about which refs or objects are
401417
responsible for disk usage. The size of a packed non-delta object may be

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,6 +1030,7 @@ LIB_OBJS += ewah/ewah_rlw.o
10301030
LIB_OBJS += exec-cmd.o
10311031
LIB_OBJS += fetch-negotiator.o
10321032
LIB_OBJS += fetch-pack.o
1033+
LIB_OBJS += fetch-object-info.o
10331034
LIB_OBJS += fmt-merge-msg.o
10341035
LIB_OBJS += fsck.o
10351036
LIB_OBJS += fsmonitor.o

builtin/cat-file.c

Lines changed: 117 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,18 @@
2727
#include "promisor-remote.h"
2828
#include "mailmap.h"
2929
#include "write-or-die.h"
30+
#include "alias.h"
31+
#include "remote.h"
32+
#include "transport.h"
33+
34+
/* Maximum length for a remote URL. While no universal standard exists,
35+
* 8K is assumed to be a reasonable limit.
36+
*/
37+
#define MAX_REMOTE_URL_LEN (8*1024)
38+
/* Maximum number of objects allowed in a single remote-object-info request. */
39+
#define MAX_ALLOWED_OBJ_LIMIT 10000
40+
/* Maximum input size permitted for the remote-object-info command. */
41+
#define MAX_REMOTE_OBJ_INFO_LINE (MAX_REMOTE_URL_LEN + MAX_ALLOWED_OBJ_LIMIT * (GIT_MAX_HEXSZ + 1))
3042

3143
enum batch_mode {
3244
BATCH_MODE_CONTENTS,
@@ -48,6 +60,8 @@ struct batch_options {
4860
};
4961

5062
static const char *force_path;
63+
static struct object_info *remote_object_info;
64+
static struct oid_array object_info_oids = OID_ARRAY_INIT;
5165

5266
static struct string_list mailmap = STRING_LIST_INIT_NODUP;
5367
static int use_mailmap;
@@ -579,6 +593,61 @@ static void batch_one_object(const char *obj_name,
579593
object_context_release(&ctx);
580594
}
581595

596+
static int get_remote_info(struct batch_options *opt, int argc, const char **argv)
597+
{
598+
int retval = 0;
599+
struct remote *remote = NULL;
600+
struct object_id oid;
601+
struct string_list object_info_options = STRING_LIST_INIT_NODUP;
602+
static struct transport *gtransport;
603+
604+
/*
605+
* Change the format to "%(objectname) %(objectsize)" when
606+
* remote-object-info command is used. Once we start supporting objecttype
607+
* the default format should change to DEFAULT_FORMAT.
608+
*/
609+
if (!opt->format)
610+
opt->format = "%(objectname) %(objectsize)";
611+
612+
remote = remote_get(argv[0]);
613+
if (!remote)
614+
die(_("must supply valid remote when using remote-object-info"));
615+
616+
oid_array_clear(&object_info_oids);
617+
for (size_t i = 1; i < argc; i++) {
618+
if (get_oid_hex(argv[i], &oid))
619+
die(_("Not a valid object name %s"), argv[i]);
620+
oid_array_append(&object_info_oids, &oid);
621+
}
622+
if (!object_info_oids.nr)
623+
die(_("remote-object-info requires objects"));
624+
625+
gtransport = transport_get(remote, NULL);
626+
if (gtransport->smart_options) {
627+
CALLOC_ARRAY(remote_object_info, object_info_oids.nr);
628+
gtransport->smart_options->object_info = 1;
629+
gtransport->smart_options->object_info_oids = &object_info_oids;
630+
631+
/* 'objectsize' is the only option currently supported */
632+
if (!strstr(opt->format, "%(objectsize)"))
633+
die(_("%s is currently not supported with remote-object-info"), opt->format);
634+
635+
string_list_append(&object_info_options, "size");
636+
637+
if (object_info_options.nr > 0) {
638+
gtransport->smart_options->object_info_options = &object_info_options;
639+
gtransport->smart_options->object_info_data = remote_object_info;
640+
retval = transport_fetch_refs(gtransport, NULL);
641+
}
642+
} else {
643+
retval = -1;
644+
}
645+
646+
string_list_clear(&object_info_options, 0);
647+
transport_disconnect(gtransport);
648+
return retval;
649+
}
650+
582651
struct object_cb_data {
583652
struct batch_options *opt;
584653
struct expand_data *expand;
@@ -670,28 +739,68 @@ static void parse_cmd_info(struct batch_options *opt,
670739
batch_one_object(line, output, opt, data);
671740
}
672741

742+
static void parse_cmd_remote_object_info(struct batch_options *opt,
743+
const char *line, struct strbuf *output,
744+
struct expand_data *data)
745+
{
746+
int count;
747+
const char **argv;
748+
char *line_to_split;
749+
750+
if (strlen(line) >= MAX_REMOTE_OBJ_INFO_LINE)
751+
die(_("remote-object-info command input overflow "
752+
"(no more than %d objects are allowed)"),
753+
MAX_ALLOWED_OBJ_LIMIT);
754+
755+
line_to_split = xstrdup(line);
756+
count = split_cmdline(line_to_split, &argv);
757+
if (count < 0)
758+
die(_("split remote-object-info command"));
759+
760+
if (get_remote_info(opt, count, argv))
761+
goto cleanup;
762+
763+
data->skip_object_info = 1;
764+
for (size_t i = 0; i < object_info_oids.nr; i++) {
765+
data->oid = object_info_oids.oid[i];
766+
if (remote_object_info[i].sizep) {
767+
/*
768+
* When reaching here, it means remote-object-info can retrieve
769+
* information from server without downloading them.
770+
*/
771+
data->size = *remote_object_info[i].sizep;
772+
opt->batch_mode = BATCH_MODE_INFO;
773+
batch_object_write(argv[i+1], output, opt, data, NULL, 0);
774+
}
775+
}
776+
data->skip_object_info = 0;
777+
778+
cleanup:
779+
for (size_t i = 0; i < object_info_oids.nr; i++)
780+
free_object_info_contents(&remote_object_info[i]);
781+
free(line_to_split);
782+
free(argv);
783+
free(remote_object_info);
784+
}
785+
673786
static void dispatch_calls(struct batch_options *opt,
674787
struct strbuf *output,
675788
struct expand_data *data,
676789
struct queued_cmd *cmd,
677790
int nr)
678791
{
679-
int i;
680-
681792
if (!opt->buffer_output)
682793
die(_("flush is only for --buffer mode"));
683794

684-
for (i = 0; i < nr; i++)
795+
for (size_t i = 0; i < nr; i++)
685796
cmd[i].fn(opt, cmd[i].line, output, data);
686797

687798
fflush(stdout);
688799
}
689800

690801
static void free_cmds(struct queued_cmd *cmd, size_t *nr)
691802
{
692-
size_t i;
693-
694-
for (i = 0; i < *nr; i++)
803+
for (size_t i = 0; i < *nr; i++)
695804
FREE_AND_NULL(cmd[i].line);
696805

697806
*nr = 0;
@@ -705,6 +814,7 @@ static const struct parse_cmd {
705814
} commands[] = {
706815
{ "contents", parse_cmd_contents, 1},
707816
{ "info", parse_cmd_info, 1},
817+
{ "remote-object-info", parse_cmd_remote_object_info, 1},
708818
{ "flush", NULL, 0},
709819
};
710820

@@ -717,7 +827,6 @@ static void batch_objects_command(struct batch_options *opt,
717827
size_t alloc = 0, nr = 0;
718828

719829
while (strbuf_getdelim_strip_crlf(&input, stdin, opt->input_delim) != EOF) {
720-
int i;
721830
const struct parse_cmd *cmd = NULL;
722831
const char *p = NULL, *cmd_end;
723832
struct queued_cmd call = {0};
@@ -727,7 +836,7 @@ static void batch_objects_command(struct batch_options *opt,
727836
if (isspace(*input.buf))
728837
die(_("whitespace before command: '%s'"), input.buf);
729838

730-
for (i = 0; i < ARRAY_SIZE(commands); i++) {
839+
for (size_t i = 0; i < ARRAY_SIZE(commands); i++) {
731840
if (!skip_prefix(input.buf, commands[i].name, &cmd_end))
732841
continue;
733842

connect.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,40 @@ int server_supports(const char *feature)
697697
return !!server_feature_value(feature, NULL);
698698
}
699699

700+
void write_command_and_capabilities(struct strbuf *req_buf, const char *command,
701+
const struct string_list *server_options)
702+
{
703+
const char *hash_name;
704+
int advertise_sid;
705+
706+
git_config_get_bool("transfer.advertisesid", &advertise_sid);
707+
708+
ensure_server_supports_v2(command);
709+
packet_buf_write(req_buf, "command=%s", command);
710+
if (server_supports_v2("agent"))
711+
packet_buf_write(req_buf, "agent=%s", git_user_agent_sanitized());
712+
if (advertise_sid && server_supports_v2("session-id"))
713+
packet_buf_write(req_buf, "session-id=%s", trace2_session_id());
714+
if (server_options && server_options->nr) {
715+
ensure_server_supports_v2("server-option");
716+
for (size_t i = 0; i < server_options->nr; i++)
717+
packet_buf_write(req_buf, "server-option=%s",
718+
server_options->items[i].string);
719+
}
720+
721+
if (server_feature_v2("object-format", &hash_name)) {
722+
const int hash_algo = hash_algo_by_name(hash_name);
723+
if (hash_algo_by_ptr(the_hash_algo) != hash_algo)
724+
die(_("mismatched algorithms: client %s; server %s"),
725+
the_hash_algo->name, hash_name);
726+
packet_buf_write(req_buf, "object-format=%s", the_hash_algo->name);
727+
} else if (hash_algo_by_ptr(the_hash_algo) != GIT_HASH_SHA1) {
728+
die(_("the server does not support algorithm '%s'"),
729+
the_hash_algo->name);
730+
}
731+
packet_buf_delim(req_buf);
732+
}
733+
700734
enum protocol {
701735
PROTO_LOCAL = 1,
702736
PROTO_FILE,

connect.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,12 @@ void check_stateless_delimiter(int stateless_rpc,
3030
struct packet_reader *reader,
3131
const char *error);
3232

33+
/*
34+
* Writes a command along with the requested
35+
* server capabilities/features into a request buffer.
36+
*/
37+
struct string_list;
38+
void write_command_and_capabilities(struct strbuf *req_buf, const char *command,
39+
const struct string_list *server_options);
40+
3341
#endif

0 commit comments

Comments
 (0)