Skip to content

Commit 0558133

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 cat-file: add declaration of variable i inside its for loop
2 parents b09427b + e3c1991 commit 0558133

20 files changed

+1023
-68
lines changed

Documentation/git-cat-file.txt

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+
Error when the `object-info` capability is not supported by the server.
156+
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 the 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 error
413+
and exit when they are 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
@@ -1021,6 +1021,7 @@ LIB_OBJS += ewah/ewah_rlw.o
10211021
LIB_OBJS += exec-cmd.o
10221022
LIB_OBJS += fetch-negotiator.o
10231023
LIB_OBJS += fetch-pack.o
1024+
LIB_OBJS += fetch-object-info.o
10241025
LIB_OBJS += fmt-merge-msg.o
10251026
LIB_OBJS += fsck.o
10261027
LIB_OBJS += fsmonitor.o

builtin/cat-file.c

Lines changed: 102 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@
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"
3033

3134
enum batch_mode {
3235
BATCH_MODE_CONTENTS,
@@ -45,9 +48,12 @@ struct batch_options {
4548
char input_delim;
4649
char output_delim;
4750
const char *format;
51+
int use_remote_info;
4852
};
4953

5054
static const char *force_path;
55+
static struct object_info *remote_object_info;
56+
static struct oid_array object_info_oids = OID_ARRAY_INIT;
5157

5258
static struct string_list mailmap = STRING_LIST_INIT_NODUP;
5359
static int use_mailmap;
@@ -579,6 +585,59 @@ static void batch_one_object(const char *obj_name,
579585
object_context_release(&ctx);
580586
}
581587

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

732+
static void parse_cmd_remote_object_info(struct batch_options *opt,
733+
const char *line, struct strbuf *output,
734+
struct expand_data *data)
735+
{
736+
int count;
737+
const char **argv;
738+
739+
char *line_to_split = xstrdup_or_null(line);
740+
count = split_cmdline(line_to_split, &argv);
741+
if (get_remote_info(opt, count, argv))
742+
goto cleanup;
743+
744+
opt->use_remote_info = 1;
745+
data->skip_object_info = 1;
746+
for (size_t i = 0; i < object_info_oids.nr; i++) {
747+
748+
data->oid = object_info_oids.oid[i];
749+
750+
if (remote_object_info[i].sizep) {
751+
/*
752+
* When reaching here, it means remote-object-info can retrieve
753+
* information from server without downloading them.
754+
*/
755+
data->size = *remote_object_info[i].sizep;
756+
opt->batch_mode = BATCH_MODE_INFO;
757+
batch_object_write(argv[i+1], output, opt, data, NULL, 0);
758+
}
759+
}
760+
opt->use_remote_info = 0;
761+
data->skip_object_info = 0;
762+
763+
cleanup:
764+
for (size_t i = 0; i < object_info_oids.nr; i++)
765+
free_object_info_contents(&remote_object_info[i]);
766+
free(line_to_split);
767+
free(argv);
768+
free(remote_object_info);
769+
}
770+
673771
static void dispatch_calls(struct batch_options *opt,
674772
struct strbuf *output,
675773
struct expand_data *data,
676774
struct queued_cmd *cmd,
677775
int nr)
678776
{
679-
int i;
680-
681777
if (!opt->buffer_output)
682778
die(_("flush is only for --buffer mode"));
683779

684-
for (i = 0; i < nr; i++)
780+
for (size_t i = 0; i < nr; i++)
685781
cmd[i].fn(opt, cmd[i].line, output, data);
686782

687783
fflush(stdout);
688784
}
689785

690786
static void free_cmds(struct queued_cmd *cmd, size_t *nr)
691787
{
692-
size_t i;
693-
694-
for (i = 0; i < *nr; i++)
788+
for (size_t i = 0; i < *nr; i++)
695789
FREE_AND_NULL(cmd[i].line);
696790

697791
*nr = 0;
@@ -705,6 +799,7 @@ static const struct parse_cmd {
705799
} commands[] = {
706800
{ "contents", parse_cmd_contents, 1},
707801
{ "info", parse_cmd_info, 1},
802+
{ "remote-object-info", parse_cmd_remote_object_info, 1},
708803
{ "flush", NULL, 0},
709804
};
710805

@@ -717,7 +812,6 @@ static void batch_objects_command(struct batch_options *opt,
717812
size_t alloc = 0, nr = 0;
718813

719814
while (strbuf_getdelim_strip_crlf(&input, stdin, opt->input_delim) != EOF) {
720-
int i;
721815
const struct parse_cmd *cmd = NULL;
722816
const char *p = NULL, *cmd_end;
723817
struct queued_cmd call = {0};
@@ -727,7 +821,7 @@ static void batch_objects_command(struct batch_options *opt,
727821
if (isspace(*input.buf))
728822
die(_("whitespace before command: '%s'"), input.buf);
729823

730-
for (i = 0; i < ARRAY_SIZE(commands); i++) {
824+
for (size_t i = 0; i < ARRAY_SIZE(commands); i++) {
731825
if (!skip_prefix(input.buf, commands[i].name, &cmd_end))
732826
continue;
733827

connect.c

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

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

connect.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#ifndef CONNECT_H
22
#define CONNECT_H
33

4+
#include "string-list.h"
45
#include "protocol.h"
56

67
#define CONNECT_VERBOSE (1u << 0)
@@ -30,4 +31,11 @@ void check_stateless_delimiter(int stateless_rpc,
3031
struct packet_reader *reader,
3132
const char *error);
3233

34+
/**
35+
* write_command_and_capabilities writes a command along with the requested
36+
* server capabilities/features into a request buffer.
37+
*/
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)