Merge branch 'jk/uploadpack-packobjectshook-fix'
authorJunio C Hamano <gitster@pobox.com>
Tue, 30 Oct 2018 06:43:50 +0000 (15:43 +0900)
committerJunio C Hamano <gitster@pobox.com>
Tue, 30 Oct 2018 06:43:50 +0000 (15:43 +0900)
Code clean-up that results in a small bugfix.

* jk/uploadpack-packobjectshook-fix:
upload-pack: fix broken if/else chain in config callback

1  2 
upload-pack.c
diff --combined upload-pack.c
index 5dc317c3b437952963f974b0faaaffdb0176fbca,a47e4c2692e24085fdbf7f523b334bd193f17305..3f906ccb40e11ccafbeee9a318f5c040ab591689
@@@ -3,8 -3,6 +3,8 @@@
  #include "refs.h"
  #include "pkt-line.h"
  #include "sideband.h"
 +#include "repository.h"
 +#include "object-store.h"
  #include "tag.h"
  #include "object.h"
  #include "commit.h"
  #include "quote.h"
  #include "upload-pack.h"
  #include "serve.h"
 +#include "commit-graph.h"
 +#include "commit-reach.h"
  
  /* Remember to update object flag allocation in object.h */
  #define THEY_HAVE     (1u << 11)
  #define OUR_REF               (1u << 12)
  #define WANTED                (1u << 13)
  #define COMMON_KNOWN  (1u << 14)
 -#define REACHABLE     (1u << 15)
  
  #define SHALLOW               (1u << 16)
  #define NOT_SHALLOW   (1u << 17)
@@@ -67,7 -64,6 +67,7 @@@ static const char *pack_objects_hook
  
  static int filter_capability_requested;
  static int allow_filter;
 +static int allow_ref_in_want;
  static struct list_objects_filter_options filter_options;
  
  static void reset_timeout(void)
@@@ -314,7 -310,7 +314,7 @@@ static int got_oid(const char *hex, str
        if (!has_object_file(oid))
                return -1;
  
 -      o = parse_object(oid);
 +      o = parse_object(the_repository, oid);
        if (!o)
                die("oops (%s)", oid_to_hex(oid));
        if (o->type == OBJ_COMMIT) {
        return 0;
  }
  
 -static int reachable(struct commit *want)
 -{
 -      struct prio_queue work = { compare_commits_by_commit_date };
 -
 -      prio_queue_put(&work, want);
 -      while (work.nr) {
 -              struct commit_list *list;
 -              struct commit *commit = prio_queue_get(&work);
 -
 -              if (commit->object.flags & THEY_HAVE) {
 -                      want->object.flags |= COMMON_KNOWN;
 -                      break;
 -              }
 -              if (!commit->object.parsed)
 -                      parse_object(&commit->object.oid);
 -              if (commit->object.flags & REACHABLE)
 -                      continue;
 -              commit->object.flags |= REACHABLE;
 -              if (commit->date < oldest_have)
 -                      continue;
 -              for (list = commit->parents; list; list = list->next) {
 -                      struct commit *parent = list->item;
 -                      if (!(parent->object.flags & REACHABLE))
 -                              prio_queue_put(&work, parent);
 -              }
 -      }
 -      want->object.flags |= REACHABLE;
 -      clear_commit_marks(want, REACHABLE);
 -      clear_prio_queue(&work);
 -      return (want->object.flags & COMMON_KNOWN);
 -}
 -
  static int ok_to_give_up(void)
  {
 -      int i;
 +      uint32_t min_generation = GENERATION_NUMBER_ZERO;
  
        if (!have_obj.nr)
                return 0;
  
 -      for (i = 0; i < want_obj.nr; i++) {
 -              struct object *want = want_obj.objects[i].item;
 -
 -              if (want->flags & COMMON_KNOWN)
 -                      continue;
 -              want = deref_tag(want, "a want line", 0);
 -              if (!want || want->type != OBJ_COMMIT) {
 -                      /* no way to tell if this is reachable by
 -                       * looking at the ancestry chain alone, so
 -                       * leave a note to ourselves not to worry about
 -                       * this object anymore.
 -                       */
 -                      want_obj.objects[i].item->flags |= COMMON_KNOWN;
 -                      continue;
 -              }
 -              if (!reachable((struct commit *)want))
 -                      return 0;
 -      }
 -      return 1;
 +      return can_all_from_reach_with_flag(&want_obj, THEY_HAVE,
 +                                          COMMON_KNOWN, oldest_have,
 +                                          min_generation);
  }
  
  static int get_common_commits(void)
@@@ -444,7 -488,6 +444,7 @@@ static int do_reachable_revlist(struct 
        struct object *o;
        char namebuf[GIT_MAX_HEXSZ + 2]; /* ^ + hash + LF */
        int i;
 +      const unsigned hexsz = the_hash_algo->hexsz;
  
        cmd->argv = argv;
        cmd->git_cmd = 1;
                goto error;
  
        namebuf[0] = '^';
 -      namebuf[GIT_SHA1_HEXSZ + 1] = '\n';
 +      namebuf[hexsz + 1] = '\n';
        for (i = get_max_object_index(); 0 < i; ) {
                o = get_indexed_object(--i);
                if (!o)
                        o->flags &= ~TMP_MARK;
                if (!is_our_ref(o))
                        continue;
 -              memcpy(namebuf + 1, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ);
 -              if (write_in_full(cmd->in, namebuf, GIT_SHA1_HEXSZ + 2) < 0)
 +              memcpy(namebuf + 1, oid_to_hex(&o->oid), hexsz);
 +              if (write_in_full(cmd->in, namebuf, hexsz + 2) < 0)
                        goto error;
        }
 -      namebuf[GIT_SHA1_HEXSZ] = '\n';
 +      namebuf[hexsz] = '\n';
        for (i = 0; i < src->nr; i++) {
                o = src->objects[i].item;
                if (is_our_ref(o)) {
                }
                if (reachable && o->type == OBJ_COMMIT)
                        o->flags |= TMP_MARK;
 -              memcpy(namebuf, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ);
 -              if (write_in_full(cmd->in, namebuf, GIT_SHA1_HEXSZ + 1) < 0)
 +              memcpy(namebuf, oid_to_hex(&o->oid), hexsz);
 +              if (write_in_full(cmd->in, namebuf, hexsz + 1) < 0)
                        goto error;
        }
        close(cmd->in);
@@@ -525,7 -568,7 +525,7 @@@ static int get_reachable_list(struct ob
                if (parse_oid_hex(namebuf, &sha1, &p) || *p != '\n')
                        break;
  
 -              o = lookup_object(sha1.hash);
 +              o = lookup_object(the_repository, sha1.hash);
                if (o && o->type == OBJ_COMMIT) {
                        o->flags &= ~TMP_MARK;
                }
@@@ -615,7 -658,7 +615,7 @@@ static void send_shallow(struct commit_
                if (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) {
                        packet_write_fmt(1, "shallow %s",
                                         oid_to_hex(&object->oid));
 -                      register_shallow(&object->oid);
 +                      register_shallow(the_repository, &object->oid);
                        shallow_nr++;
                }
                result = result->next;
@@@ -652,14 -695,14 +652,14 @@@ static void send_unshallow(const struc
                        add_object_array(object, NULL, &extra_edge_obj);
                }
                /* make sure commit traversal conforms to client */
 -              register_shallow(&object->oid);
 +              register_shallow(the_repository, &object->oid);
        }
  }
  
  static void deepen(int depth, int deepen_relative,
                   struct object_array *shallows)
  {
 -      if (depth == INFINITE_DEPTH && !is_repository_shallow()) {
 +      if (depth == INFINITE_DEPTH && !is_repository_shallow(the_repository)) {
                int i;
  
                for (i = 0; i < shallows->nr; i++) {
@@@ -694,7 -737,6 +694,7 @@@ static void deepen_by_rev_list(int ac, 
  {
        struct commit_list *result;
  
 +      close_commit_graph(the_repository);
        result = get_shallow_commits_by_rev_list(ac, av, SHALLOW, NOT_SHALLOW);
        send_shallow(result);
        free_commit_list(result);
@@@ -740,8 -782,7 +740,8 @@@ static int send_shallow_list(int depth
                if (shallows->nr > 0) {
                        int i;
                        for (i = 0; i < shallows->nr; i++)
 -                              register_shallow(&shallows->objects[i].item->oid);
 +                              register_shallow(the_repository,
 +                                               &shallows->objects[i].item->oid);
                }
        }
  
@@@ -757,7 -798,7 +757,7 @@@ static int process_shallow(const char *
                struct object *object;
                if (get_oid_hex(arg, &oid))
                        die("invalid shallow line: %s", line);
 -              object = parse_object(&oid);
 +              object = parse_object(the_repository, &oid);
                if (!object)
                        return 1;
                if (object->type != OBJ_COMMIT)
@@@ -883,7 -924,7 +883,7 @@@ static void receive_needs(void
                if (allow_filter && parse_feature_request(features, "filter"))
                        filter_capability_requested = 1;
  
 -              o = parse_object(&oid_buf);
 +              o = parse_object(the_repository, &oid_buf);
                if (!o) {
                        packet_write_fmt(1,
                                         "ERR upload-pack: not our ref %s",
@@@ -1029,14 -1070,15 +1029,17 @@@ static int upload_pack_config(const cha
                keepalive = git_config_int(var, value);
                if (!keepalive)
                        keepalive = -1;
-       } else if (current_config_scope() != CONFIG_SCOPE_REPO) {
-               if (!strcmp("uploadpack.packobjectshook", var))
-                       return git_config_string(&pack_objects_hook, var, value);
        } else if (!strcmp("uploadpack.allowfilter", var)) {
                allow_filter = git_config_bool(var, value);
 +      } else if (!strcmp("uploadpack.allowrefinwant", var)) {
 +              allow_ref_in_want = git_config_bool(var, value);
        }
+       if (current_config_scope() != CONFIG_SCOPE_REPO) {
+               if (!strcmp("uploadpack.packobjectshook", var))
+                       return git_config_string(&pack_objects_hook, var, value);
+       }
        return parse_hide_refs_config(var, value, "uploadpack");
  }
  
@@@ -1075,7 -1117,6 +1078,7 @@@ void upload_pack(struct upload_pack_opt
  
  struct upload_pack_data {
        struct object_array wants;
 +      struct string_list wanted_refs;
        struct oid_array haves;
  
        struct object_array shallows;
  static void upload_pack_data_init(struct upload_pack_data *data)
  {
        struct object_array wants = OBJECT_ARRAY_INIT;
 +      struct string_list wanted_refs = STRING_LIST_INIT_DUP;
        struct oid_array haves = OID_ARRAY_INIT;
        struct object_array shallows = OBJECT_ARRAY_INIT;
        struct string_list deepen_not = STRING_LIST_INIT_DUP;
  
        memset(data, 0, sizeof(*data));
        data->wants = wants;
 +      data->wanted_refs = wanted_refs;
        data->haves = haves;
        data->shallows = shallows;
        data->deepen_not = deepen_not;
  static void upload_pack_data_clear(struct upload_pack_data *data)
  {
        object_array_clear(&data->wants);
 +      string_list_clear(&data->wanted_refs, 1);
        oid_array_clear(&data->haves);
        object_array_clear(&data->shallows);
        string_list_clear(&data->deepen_not, 0);
@@@ -1130,7 -1168,7 +1133,7 @@@ static int parse_want(const char *line
                        die("git upload-pack: protocol error, "
                            "expected to get oid, not '%s'", line);
  
 -              o = parse_object(&oid);
 +              o = parse_object(the_repository, &oid);
                if (!o) {
                        packet_write_fmt(1,
                                         "ERR upload-pack: not our ref %s",
        return 0;
  }
  
 +static int parse_want_ref(const char *line, struct string_list *wanted_refs)
 +{
 +      const char *arg;
 +      if (skip_prefix(line, "want-ref ", &arg)) {
 +              struct object_id oid;
 +              struct string_list_item *item;
 +              struct object *o;
 +
 +              if (read_ref(arg, &oid)) {
 +                      packet_write_fmt(1, "ERR unknown ref %s", arg);
 +                      die("unknown ref %s", arg);
 +              }
 +
 +              item = string_list_append(wanted_refs, arg);
 +              item->util = oiddup(&oid);
 +
 +              o = parse_object_or_die(&oid, arg);
 +              if (!(o->flags & WANTED)) {
 +                      o->flags |= WANTED;
 +                      add_object_array(o, NULL, &want_obj);
 +              }
 +
 +              return 1;
 +      }
 +
 +      return 0;
 +}
 +
  static int parse_have(const char *line, struct oid_array *haves)
  {
        const char *arg;
@@@ -1203,8 -1213,6 +1206,8 @@@ static void process_args(struct packet_
                /* process want */
                if (parse_want(arg))
                        continue;
 +              if (allow_ref_in_want && parse_want_ref(arg, &data->wanted_refs))
 +                      continue;
                /* process have line */
                if (parse_have(arg, &data->haves))
                        continue;
@@@ -1272,7 -1280,7 +1275,7 @@@ static int process_haves(struct oid_arr
  
                oid_array_append(common, oid);
  
 -              o = parse_object(oid);
 +              o = parse_object(the_repository, oid);
                if (!o)
                        die("oops (%s)", oid_to_hex(oid));
                if (o->type == OBJ_COMMIT) {
@@@ -1347,37 -1355,18 +1350,37 @@@ static int process_haves_and_send_acks(
        return ret;
  }
  
 +static void send_wanted_ref_info(struct upload_pack_data *data)
 +{
 +      const struct string_list_item *item;
 +
 +      if (!data->wanted_refs.nr)
 +              return;
 +
 +      packet_write_fmt(1, "wanted-refs\n");
 +
 +      for_each_string_list_item(item, &data->wanted_refs) {
 +              packet_write_fmt(1, "%s %s\n",
 +                               oid_to_hex(item->util),
 +                               item->string);
 +      }
 +
 +      packet_delim(1);
 +}
 +
  static void send_shallow_info(struct upload_pack_data *data)
  {
        /* No shallow info needs to be sent */
        if (!data->depth && !data->deepen_rev_list && !data->shallows.nr &&
 -          !is_repository_shallow())
 +          !is_repository_shallow(the_repository))
                return;
  
        packet_write_fmt(1, "shallow-info\n");
  
        if (!send_shallow_list(data->depth, data->deepen_rev_list,
                               data->deepen_since, &data->deepen_not,
 -                             &data->shallows) && is_repository_shallow())
 +                             &data->shallows) &&
 +          is_repository_shallow(the_repository))
                deepen(INFINITE_DEPTH, data->deepen_relative, &data->shallows);
  
        packet_delim(1);
@@@ -1432,7 -1421,6 +1435,7 @@@ int upload_pack_v2(struct repository *r
                                state = FETCH_DONE;
                        break;
                case FETCH_SEND_PACK:
 +                      send_wanted_ref_info(&data);
                        send_shallow_info(&data);
  
                        packet_write_fmt(1, "packfile\n");
@@@ -1453,22 -1441,12 +1456,22 @@@ int upload_pack_advertise(struct reposi
  {
        if (value) {
                int allow_filter_value;
 +              int allow_ref_in_want;
 +
                strbuf_addstr(value, "shallow");
 +
                if (!repo_config_get_bool(the_repository,
                                         "uploadpack.allowfilter",
                                         &allow_filter_value) &&
                    allow_filter_value)
                        strbuf_addstr(value, " filter");
 +
 +              if (!repo_config_get_bool(the_repository,
 +                                       "uploadpack.allowrefinwant",
 +                                       &allow_ref_in_want) &&
 +                  allow_ref_in_want)
 +                      strbuf_addstr(value, " ref-in-want");
        }
 +
        return 1;
  }