Merge branch 'bw/server-options'
authorJunio C Hamano <gitster@pobox.com>
Wed, 23 May 2018 05:38:15 +0000 (14:38 +0900)
committerJunio C Hamano <gitster@pobox.com>
Wed, 23 May 2018 05:38:15 +0000 (14:38 +0900)
The transport protocol v2 is getting updated further.

* bw/server-options:
fetch: send server options when using protocol v2
ls-remote: send server options when using protocol v2
serve: introduce the server-option capability

1  2 
Documentation/git-ls-remote.txt
builtin/ls-remote.c
connect.c
fetch-pack.c
transport.c
index 6ad1e34afca4cd569798bfcbae9f99d038693b64,e5defb1b2d75ff3cd9ad0c3c3c805bf96e82583d..b9fd3770a6ce19c341c421e07b68985d89d94df5
@@@ -10,7 -10,7 +10,7 @@@ SYNOPSI
  --------
  [verse]
  'git ls-remote' [--heads] [--tags] [--refs] [--upload-pack=<exec>]
 -            [-q | --quiet] [--exit-code] [--get-url]
 +            [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]
              [--symref] [<repository> [<refs>...]]
  
  DESCRIPTION
@@@ -60,16 -60,14 +60,24 @@@ OPTION
        upload-pack only shows the symref HEAD, so it will be the only
        one shown by ls-remote.
  
 +--sort=<key>::
 +      Sort based on the key given. Prefix `-` to sort in descending order
 +      of the value. Supports "version:refname" or "v:refname" (tag names
 +      are treated as versions). The "version:refname" sort order can also
 +      be affected by the "versionsort.suffix" configuration variable.
 +      See linkgit:git-for-each-ref[1] for more sort options, but be aware
 +      keys like `committerdate` that require access to the objects
 +      themselves will not work for refs whose objects have not yet been
 +      fetched from the remote, and will give a `missing object` error.
 +
+ -o <option>::
+ --server-option=<option>::
+       Transmit the given string to the server when communicating using
+       protocol version 2.  The given string must not contain a NUL or LF
+       character.
+       When multiple `--server-option=<option>` are given, they are all
+       sent to the other side in the order listed on the command line.
  <repository>::
        The "remote" repository to query.  This parameter can be
        either a URL or the name of a remote (see the GIT URLS and
@@@ -100,10 -98,6 +108,10 @@@ EXAMPLE
        c5db5456ae3b0873fc659c19fafdde22313cc441        refs/tags/v0.99.2
        7ceca275d047c90c0c7d5afb13ab97efdf51bd6e        refs/tags/v0.99.3
  
 +SEE ALSO
 +--------
 +linkgit:git-check-ref-format[1].
 +
  GIT
  ---
  Part of the linkgit:git[1] suite
diff --combined builtin/ls-remote.c
index ca3f04a839e79ecf361df5a1997da05c5d59a62d,3150bfb926128cc1c02839f3fd64bddae245fe6e..1a25df7ee15b45df142679286afdb0e8c55647dc
@@@ -1,7 -1,6 +1,7 @@@
  #include "builtin.h"
  #include "cache.h"
  #include "transport.h"
 +#include "ref-filter.h"
  #include "remote.h"
  #include "refs.h"
  
@@@ -46,13 -45,11 +46,14 @@@ int cmd_ls_remote(int argc, const char 
        const char *uploadpack = NULL;
        const char **pattern = NULL;
        struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
 +      int i;
+       struct string_list server_options = STRING_LIST_INIT_DUP;
  
        struct remote *remote;
        struct transport *transport;
        const struct ref *ref;
 +      struct ref_array ref_array;
 +      static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;
  
        struct option options[] = {
                OPT__QUIET(&quiet, N_("do not print remote URL")),
                OPT_BIT(0, "refs", &flags, N_("do not show peeled tags"), REF_NORMAL),
                OPT_BOOL(0, "get-url", &get_url,
                         N_("take url.<base>.insteadOf into account")),
 +              OPT_CALLBACK(0 , "sort", sorting_tail, N_("key"),
 +                           N_("field name to sort on"), &parse_opt_ref_sorting),
                OPT_SET_INT_F(0, "exit-code", &status,
                              N_("exit with exit code 2 if no matching refs are found"),
                              2, PARSE_OPT_NOCOMPLETE),
                OPT_BOOL(0, "symref", &show_symref_target,
                         N_("show underlying ref in addition to the object pointed by it")),
+               OPT_STRING_LIST('o', "server-option", &server_options, N_("server-specific"), N_("option to transmit")),
                OPT_END()
        };
  
 +      memset(&ref_array, 0, sizeof(ref_array));
 +
        argc = parse_options(argc, argv, prefix, options, ls_remote_usage,
                             PARSE_OPT_STOP_AT_NON_OPTION);
        dest = argv[0];
  
        if (get_url) {
                printf("%s\n", *remote->url);
 +              UNLEAK(sorting);
                return 0;
        }
  
        transport = transport_get(remote, NULL);
        if (uploadpack != NULL)
                transport_set_option(transport, TRANS_OPT_UPLOADPACK, uploadpack);
+       if (server_options.nr)
+               transport->server_options = &server_options;
  
        ref = transport_get_remote_refs(transport, &ref_prefixes);
 -      if (transport_disconnect(transport))
 +      if (transport_disconnect(transport)) {
 +              UNLEAK(sorting);
                return 1;
 +      }
  
        if (!dest && !quiet)
                fprintf(stderr, "From %s\n", *remote->url);
        for ( ; ref; ref = ref->next) {
 +              struct ref_array_item *item;
                if (!check_ref_type(ref, flags))
                        continue;
                if (!tail_match(pattern, ref->name))
                        continue;
 +              item = ref_array_push(&ref_array, ref->name, &ref->old_oid);
 +              item->symref = xstrdup_or_null(ref->symref);
 +      }
 +
 +      if (sorting)
 +              ref_array_sort(sorting, &ref_array);
 +
 +      for (i = 0; i < ref_array.nr; i++) {
 +              const struct ref_array_item *ref = ref_array.items[i];
                if (show_symref_target && ref->symref)
 -                      printf("ref: %s\t%s\n", ref->symref, ref->name);
 -              printf("%s\t%s\n", oid_to_hex(&ref->old_oid), ref->name);
 +                      printf("ref: %s\t%s\n", ref->symref, ref->refname);
 +              printf("%s\t%s\n", oid_to_hex(&ref->objectname), ref->refname);
                status = 0; /* we found something */
        }
 +
 +      UNLEAK(sorting);
 +      UNLEAK(ref_array);
        return status;
  }
diff --combined connect.c
index b34dc80451fb375b112c1338a0aa3326a0a168ad,3000768c75a075a7eaabc7e98615f4f54f645aab..31aa9c843311b4e0b01e7378a85709083b071311
+++ b/connect.c
@@@ -48,7 -48,7 +48,7 @@@ int check_ref_type(const struct ref *re
        return check_ref(ref->name, flags);
  }
  
 -static void die_initial_contact(int unexpected)
 +static NORETURN void die_initial_contact(int unexpected)
  {
        /*
         * A hang-up after seeing some response from the other end
@@@ -408,7 -408,8 +408,8 @@@ out
  
  struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
                             struct ref **list, int for_push,
-                            const struct argv_array *ref_prefixes)
+                            const struct argv_array *ref_prefixes,
+                            const struct string_list *server_options)
  {
        int i;
        *list = NULL;
        if (server_supports_v2("agent", 0))
                packet_write_fmt(fd_out, "agent=%s", git_user_agent_sanitized());
  
+       if (server_options && server_options->nr &&
+           server_supports_v2("server-option", 1))
+               for (i = 0; i < server_options->nr; i++)
+                       packet_write_fmt(fd_out, "server-option=%s",
+                                        server_options->items[i].string);
        packet_delim(fd_out);
        /* When pushing we don't want to request the peeled tags */
        if (!for_push)
diff --combined fetch-pack.c
index f93723fec41c772db0c0d6f5a8bb2239c9d370bd,199eb8a1d8865adc3e9ec9c9d4e3b0ece02f5b53..490c38f833419cde65b97f75f454a7d148fff6a2
@@@ -6,7 -6,7 +6,7 @@@
  #include "pkt-line.h"
  #include "commit.h"
  #include "tag.h"
 -#include "exec_cmd.h"
 +#include "exec-cmd.h"
  #include "pack.h"
  #include "sideband.h"
  #include "fetch-pack.h"
@@@ -1174,6 -1174,13 +1174,13 @@@ static int send_fetch_request(int fd_ou
                packet_buf_write(&req_buf, "command=fetch");
        if (server_supports_v2("agent", 0))
                packet_buf_write(&req_buf, "agent=%s", git_user_agent_sanitized());
+       if (args->server_options && args->server_options->nr &&
+           server_supports_v2("server-option", 1)) {
+               int i;
+               for (i = 0; i < args->server_options->nr; i++)
+                       packet_write_fmt(fd_out, "server-option=%s",
+                                        args->server_options->items[i].string);
+       }
  
        packet_buf_delim(&req_buf);
        if (args->use_thin_pack)
diff --combined transport.c
index 37410d8aad9dd70df282c133ea9939bba5589efd,6bce2b20ca04661c6410c32f972d15060957ddd1..2c4de32b3335312a4ba8c79e82606d1b8339570b
  #include "transport-internal.h"
  #include "protocol.h"
  #include "object-store.h"
 +#include "color.h"
 +
 +static int transport_use_color = -1;
 +static char transport_colors[][COLOR_MAXLEN] = {
 +      GIT_COLOR_RESET,
 +      GIT_COLOR_RED           /* REJECTED */
 +};
 +
 +enum color_transport {
 +      TRANSPORT_COLOR_RESET = 0,
 +      TRANSPORT_COLOR_REJECTED = 1
 +};
 +
 +static int transport_color_config(void)
 +{
 +      const char *keys[] = {
 +              "color.transport.reset",
 +              "color.transport.rejected"
 +      }, *key = "color.transport";
 +      char *value;
 +      int i;
 +      static int initialized;
 +
 +      if (initialized)
 +              return 0;
 +      initialized = 1;
 +
 +      if (!git_config_get_string(key, &value))
 +              transport_use_color = git_config_colorbool(key, value);
 +
 +      if (!want_color_stderr(transport_use_color))
 +              return 0;
 +
 +      for (i = 0; i < ARRAY_SIZE(keys); i++)
 +              if (!git_config_get_string(keys[i], &value)) {
 +                      if (!value)
 +                              return config_error_nonbool(keys[i]);
 +                      if (color_parse(value, transport_colors[i]) < 0)
 +                              return -1;
 +              }
 +
 +      return 0;
 +}
 +
 +static const char *transport_get_color(enum color_transport ix)
 +{
 +      if (want_color_stderr(transport_use_color))
 +              return transport_colors[ix];
 +      return "";
 +}
  
  static void set_upstreams(struct transport *transport, struct ref *refs,
        int pretend)
@@@ -268,7 -218,7 +268,7 @@@ static struct ref *get_refs_via_connect
        switch (data->version) {
        case protocol_v2:
                get_remote_refs(data->fd[1], &reader, &refs, for_push,
-                               ref_prefixes);
+                               ref_prefixes, transport->server_options);
                break;
        case protocol_v1:
        case protocol_v0:
@@@ -316,6 -266,7 +316,7 @@@ static int fetch_refs_via_pack(struct t
        args.no_dependents = data->options.no_dependents;
        args.filter_options = data->options.filter_options;
        args.stateless_rpc = transport->stateless_rpc;
+       args.server_options = transport->server_options;
  
        if (!data->got_remote_heads)
                refs_tmp = get_refs_via_connect(transport, 0, NULL);
@@@ -423,13 -374,7 +424,13 @@@ static void print_ref_status(char flag
                else
                        fprintf(stdout, "%s\n", summary);
        } else {
 -              fprintf(stderr, " %c %-*s ", flag, summary_width, summary);
 +              const char *red = "", *reset = "";
 +              if (push_had_errors(to)) {
 +                      red = transport_get_color(TRANSPORT_COLOR_REJECTED);
 +                      reset = transport_get_color(TRANSPORT_COLOR_RESET);
 +              }
 +              fprintf(stderr, " %s%c %-*s%s ", red, flag, summary_width,
 +                      summary, reset);
                if (from)
                        fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name));
                else
@@@ -578,9 -523,6 +579,9 @@@ void transport_print_push_status(const 
        char *head;
        int summary_width = transport_summary_width(refs);
  
 +      if (transport_color_config() < 0)
 +              warning(_("could not parse transport.color.* config"));
 +
        head = resolve_refdup("HEAD", RESOLVE_REF_READING, NULL, NULL);
  
        if (verbose) {
@@@ -647,9 -589,6 +648,9 @@@ static int git_transport_push(struct tr
        struct send_pack_args args;
        int ret = 0;
  
 +      if (transport_color_config() < 0)
 +              return -1;
 +
        if (!data->got_remote_heads)
                get_refs_via_connect(transport, 1, NULL);
  
@@@ -1098,9 -1037,6 +1099,9 @@@ int transport_push(struct transport *tr
        *reject_reasons = 0;
        transport_verify_remote_names(refspec_nr, refspec);
  
 +      if (transport_color_config() < 0)
 +              return -1;
 +
        if (transport->vtable->push_refs) {
                struct ref *remote_refs;
                struct ref *local_refs = get_local_heads();