Skip to content

Commit a754dde

Browse files
committed
Merge branch 'ej/cat-file-remote-object-info' into seen
"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 bc60f67 + 802a553 commit a754dde

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
@@ -168,6 +168,13 @@ info <object>::
168168
Print object info for object reference `<object>`. This corresponds to the
169169
output of `--batch-check`.
170170

171+
remote-object-info <remote> <object>...::
172+
Print object info for object references `<object>` at specified
173+
`<remote>` without downloading objects from the remote.
174+
Raise an error when the `object-info` capability is not supported by the remote.
175+
Raise an error when no object references are provided.
176+
This command may be combined with `--buffer`.
177+
171178
flush::
172179
Used with `--buffer` to execute all preceding commands that were issued
173180
since the beginning or since the last flush was issued. When `--buffer`
@@ -309,21 +316,23 @@ newline. The available atoms are:
309316
The full hex representation of the object name.
310317

311318
`objecttype`::
312-
The type of the object (the same as `cat-file -t` reports).
319+
The type of the object (the same as `cat-file -t` reports). See
320+
`CAVEATS` below. Not supported by `remote-object-info`.
313321

314322
`objectsize`::
315323
The size, in bytes, of the object (the same as `cat-file -s`
316324
reports).
317325

318326
`objectsize:disk`::
319327
The size, in bytes, that the object takes up on disk. See the
320-
note about on-disk sizes in the `CAVEATS` section below.
328+
note about on-disk sizes in the `CAVEATS` section below. Not
329+
supported by `remote-object-info`.
321330

322331
`deltabase`::
323332
If the object is stored as a delta on-disk, this expands to the
324333
full hex representation of the delta base object name.
325334
Otherwise, expands to the null OID (all zeroes). See `CAVEATS`
326-
below.
335+
below. Not supported by `remote-object-info`.
327336

328337
`rest`::
329338
If this atom is used in the output string, input lines are split
@@ -333,7 +342,10 @@ newline. The available atoms are:
333342
line) are output in place of the `%(rest)` atom.
334343

335344
If no format is specified, the default format is `%(objectname)
336-
%(objecttype) %(objectsize)`.
345+
%(objecttype) %(objectsize)`, except for `remote-object-info` commands which use
346+
`%(objectname) %(objectsize)` for now because "%(objecttype)" is not supported yet.
347+
WARNING: When "%(objecttype)" is supported, the default format WILL be unified, so
348+
DO NOT RELY on the current default format to stay the same!!!
337349

338350
If `--batch` is specified, or if `--batch-command` is used with the `contents`
339351
command, the object information is followed by the object contents (consisting
@@ -422,6 +434,10 @@ scripting purposes.
422434
CAVEATS
423435
-------
424436
437+
Note that since %(objecttype), %(objectsize:disk) and %(deltabase) are
438+
currently not supported by the `remote-object-info` command, we will raise
439+
an error and exit when they appear in the format string.
440+
425441
Note that the sizes of objects on disk are reported accurately, but care
426442
should be taken in drawing conclusions about which refs or objects are
427443
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
@@ -1031,6 +1031,7 @@ LIB_OBJS += ewah/ewah_rlw.o
10311031
LIB_OBJS += exec-cmd.o
10321032
LIB_OBJS += fetch-negotiator.o
10331033
LIB_OBJS += fetch-pack.o
1034+
LIB_OBJS += fetch-object-info.o
10341035
LIB_OBJS += fmt-merge-msg.o
10351036
LIB_OBJS += fsck.o
10361037
LIB_OBJS += fsmonitor.o

builtin/cat-file.c

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

3345
enum batch_mode {
3446
BATCH_MODE_CONTENTS,
@@ -51,6 +63,8 @@ struct batch_options {
5163
};
5264

5365
static const char *force_path;
66+
static struct object_info *remote_object_info;
67+
static struct oid_array object_info_oids = OID_ARRAY_INIT;
5468

5569
static struct string_list mailmap = STRING_LIST_INIT_NODUP;
5670
static int use_mailmap;
@@ -628,6 +642,61 @@ static void batch_one_object(const char *obj_name,
628642
object_context_release(&ctx);
629643
}
630644

645+
static int get_remote_info(struct batch_options *opt, int argc, const char **argv)
646+
{
647+
int retval = 0;
648+
struct remote *remote = NULL;
649+
struct object_id oid;
650+
struct string_list object_info_options = STRING_LIST_INIT_NODUP;
651+
static struct transport *gtransport;
652+
653+
/*
654+
* Change the format to "%(objectname) %(objectsize)" when
655+
* remote-object-info command is used. Once we start supporting objecttype
656+
* the default format should change to DEFAULT_FORMAT.
657+
*/
658+
if (!opt->format)
659+
opt->format = "%(objectname) %(objectsize)";
660+
661+
remote = remote_get(argv[0]);
662+
if (!remote)
663+
die(_("must supply valid remote when using remote-object-info"));
664+
665+
oid_array_clear(&object_info_oids);
666+
for (size_t i = 1; i < argc; i++) {
667+
if (get_oid_hex(argv[i], &oid))
668+
die(_("Not a valid object name %s"), argv[i]);
669+
oid_array_append(&object_info_oids, &oid);
670+
}
671+
if (!object_info_oids.nr)
672+
die(_("remote-object-info requires objects"));
673+
674+
gtransport = transport_get(remote, NULL);
675+
if (gtransport->smart_options) {
676+
CALLOC_ARRAY(remote_object_info, object_info_oids.nr);
677+
gtransport->smart_options->object_info = 1;
678+
gtransport->smart_options->object_info_oids = &object_info_oids;
679+
680+
/* 'objectsize' is the only option currently supported */
681+
if (!strstr(opt->format, "%(objectsize)"))
682+
die(_("%s is currently not supported with remote-object-info"), opt->format);
683+
684+
string_list_append(&object_info_options, "size");
685+
686+
if (object_info_options.nr > 0) {
687+
gtransport->smart_options->object_info_options = &object_info_options;
688+
gtransport->smart_options->object_info_data = remote_object_info;
689+
retval = transport_fetch_refs(gtransport, NULL);
690+
}
691+
} else {
692+
retval = -1;
693+
}
694+
695+
string_list_clear(&object_info_options, 0);
696+
transport_disconnect(gtransport);
697+
return retval;
698+
}
699+
631700
struct object_cb_data {
632701
struct batch_options *opt;
633702
struct expand_data *expand;
@@ -695,28 +764,68 @@ static void parse_cmd_info(struct batch_options *opt,
695764
batch_one_object(line, output, opt, data);
696765
}
697766

767+
static void parse_cmd_remote_object_info(struct batch_options *opt,
768+
const char *line, struct strbuf *output,
769+
struct expand_data *data)
770+
{
771+
int count;
772+
const char **argv;
773+
char *line_to_split;
774+
775+
if (strlen(line) >= MAX_REMOTE_OBJ_INFO_LINE)
776+
die(_("remote-object-info command input overflow "
777+
"(no more than %d objects are allowed)"),
778+
MAX_ALLOWED_OBJ_LIMIT);
779+
780+
line_to_split = xstrdup(line);
781+
count = split_cmdline(line_to_split, &argv);
782+
if (count < 0)
783+
die(_("split remote-object-info command"));
784+
785+
if (get_remote_info(opt, count, argv))
786+
goto cleanup;
787+
788+
data->skip_object_info = 1;
789+
for (size_t i = 0; i < object_info_oids.nr; i++) {
790+
data->oid = object_info_oids.oid[i];
791+
if (remote_object_info[i].sizep) {
792+
/*
793+
* When reaching here, it means remote-object-info can retrieve
794+
* information from server without downloading them.
795+
*/
796+
data->size = *remote_object_info[i].sizep;
797+
opt->batch_mode = BATCH_MODE_INFO;
798+
batch_object_write(argv[i+1], output, opt, data, NULL, 0);
799+
}
800+
}
801+
data->skip_object_info = 0;
802+
803+
cleanup:
804+
for (size_t i = 0; i < object_info_oids.nr; i++)
805+
free_object_info_contents(&remote_object_info[i]);
806+
free(line_to_split);
807+
free(argv);
808+
free(remote_object_info);
809+
}
810+
698811
static void dispatch_calls(struct batch_options *opt,
699812
struct strbuf *output,
700813
struct expand_data *data,
701814
struct queued_cmd *cmd,
702815
int nr)
703816
{
704-
int i;
705-
706817
if (!opt->buffer_output)
707818
die(_("flush is only for --buffer mode"));
708819

709-
for (i = 0; i < nr; i++)
820+
for (size_t i = 0; i < nr; i++)
710821
cmd[i].fn(opt, cmd[i].line, output, data);
711822

712823
fflush(stdout);
713824
}
714825

715826
static void free_cmds(struct queued_cmd *cmd, size_t *nr)
716827
{
717-
size_t i;
718-
719-
for (i = 0; i < *nr; i++)
828+
for (size_t i = 0; i < *nr; i++)
720829
FREE_AND_NULL(cmd[i].line);
721830

722831
*nr = 0;
@@ -730,6 +839,7 @@ static const struct parse_cmd {
730839
} commands[] = {
731840
{ "contents", parse_cmd_contents, 1},
732841
{ "info", parse_cmd_info, 1},
842+
{ "remote-object-info", parse_cmd_remote_object_info, 1},
733843
{ "flush", NULL, 0},
734844
};
735845

@@ -742,7 +852,6 @@ static void batch_objects_command(struct batch_options *opt,
742852
size_t alloc = 0, nr = 0;
743853

744854
while (strbuf_getdelim_strip_crlf(&input, stdin, opt->input_delim) != EOF) {
745-
int i;
746855
const struct parse_cmd *cmd = NULL;
747856
const char *p = NULL, *cmd_end;
748857
struct queued_cmd call = {0};
@@ -752,7 +861,7 @@ static void batch_objects_command(struct batch_options *opt,
752861
if (isspace(*input.buf))
753862
die(_("whitespace before command: '%s'"), input.buf);
754863

755-
for (i = 0; i < ARRAY_SIZE(commands); i++) {
864+
for (size_t i = 0; i < ARRAY_SIZE(commands); i++) {
756865
if (!skip_prefix(input.buf, commands[i].name, &cmd_end))
757866
continue;
758867

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)