patch-ids.con commit hashmap.h: compare function has access to a data field (7663cdc)
   1#include "cache.h"
   2#include "diff.h"
   3#include "commit.h"
   4#include "sha1-lookup.h"
   5#include "patch-ids.h"
   6
   7static int patch_id_defined(struct commit *commit)
   8{
   9        /* must be 0 or 1 parents */
  10        return !commit->parents || !commit->parents->next;
  11}
  12
  13int commit_patch_id(struct commit *commit, struct diff_options *options,
  14                    struct object_id *oid, int diff_header_only)
  15{
  16        if (!patch_id_defined(commit))
  17                return -1;
  18
  19        if (commit->parents)
  20                diff_tree_oid(&commit->parents->item->object.oid,
  21                              &commit->object.oid, "", options);
  22        else
  23                diff_root_tree_oid(&commit->object.oid, "", options);
  24        diffcore_std(options);
  25        return diff_flush_patch_id(options, oid, diff_header_only);
  26}
  27
  28/*
  29 * When we cannot load the full patch-id for both commits for whatever
  30 * reason, the function returns -1 (i.e. return error(...)). Despite
  31 * the "cmp" in the name of this function, the caller only cares about
  32 * the return value being zero (a and b are equivalent) or non-zero (a
  33 * and b are different), and returning non-zero would keep both in the
  34 * result, even if they actually were equivalent, in order to err on
  35 * the side of safety.  The actual value being negative does not have
  36 * any significance; only that it is non-zero matters.
  37 */
  38static int patch_id_cmp(const void *unused_cmp_data,
  39                        struct patch_id *a,
  40                        struct patch_id *b,
  41                        struct diff_options *opt)
  42{
  43        if (is_null_oid(&a->patch_id) &&
  44            commit_patch_id(a->commit, opt, &a->patch_id, 0))
  45                return error("Could not get patch ID for %s",
  46                        oid_to_hex(&a->commit->object.oid));
  47        if (is_null_oid(&b->patch_id) &&
  48            commit_patch_id(b->commit, opt, &b->patch_id, 0))
  49                return error("Could not get patch ID for %s",
  50                        oid_to_hex(&b->commit->object.oid));
  51        return oidcmp(&a->patch_id, &b->patch_id);
  52}
  53
  54int init_patch_ids(struct patch_ids *ids)
  55{
  56        memset(ids, 0, sizeof(*ids));
  57        diff_setup(&ids->diffopts);
  58        ids->diffopts.detect_rename = 0;
  59        DIFF_OPT_SET(&ids->diffopts, RECURSIVE);
  60        diff_setup_done(&ids->diffopts);
  61        hashmap_init(&ids->patches, (hashmap_cmp_fn)patch_id_cmp,
  62                     NULL, 256);
  63        return 0;
  64}
  65
  66int free_patch_ids(struct patch_ids *ids)
  67{
  68        hashmap_free(&ids->patches, 1);
  69        return 0;
  70}
  71
  72static int init_patch_id_entry(struct patch_id *patch,
  73                               struct commit *commit,
  74                               struct patch_ids *ids)
  75{
  76        struct object_id header_only_patch_id;
  77
  78        patch->commit = commit;
  79        if (commit_patch_id(commit, &ids->diffopts, &header_only_patch_id, 1))
  80                return -1;
  81
  82        hashmap_entry_init(patch, sha1hash(header_only_patch_id.hash));
  83        return 0;
  84}
  85
  86struct patch_id *has_commit_patch_id(struct commit *commit,
  87                                     struct patch_ids *ids)
  88{
  89        struct patch_id patch;
  90
  91        if (!patch_id_defined(commit))
  92                return NULL;
  93
  94        memset(&patch, 0, sizeof(patch));
  95        if (init_patch_id_entry(&patch, commit, ids))
  96                return NULL;
  97
  98        return hashmap_get(&ids->patches, &patch, &ids->diffopts);
  99}
 100
 101struct patch_id *add_commit_patch_id(struct commit *commit,
 102                                     struct patch_ids *ids)
 103{
 104        struct patch_id *key;
 105
 106        if (!patch_id_defined(commit))
 107                return NULL;
 108
 109        key = xcalloc(1, sizeof(*key));
 110        if (init_patch_id_entry(key, commit, ids)) {
 111                free(key);
 112                return NULL;
 113        }
 114
 115        hashmap_add(&ids->patches, key);
 116        return key;
 117}