Coverage Report

Created: 2024-09-08 06:23

/src/git/patch-ids.c
Line
Count
Source (jump to first uncovered line)
1
#include "git-compat-util.h"
2
#include "diff.h"
3
#include "commit.h"
4
#include "hash.h"
5
#include "hex.h"
6
#include "patch-ids.h"
7
8
static int patch_id_defined(struct commit *commit)
9
0
{
10
  /* must be 0 or 1 parents */
11
0
  return !commit->parents || !commit->parents->next;
12
0
}
13
14
int commit_patch_id(struct commit *commit, struct diff_options *options,
15
        struct object_id *oid, int diff_header_only)
16
0
{
17
0
  if (!patch_id_defined(commit))
18
0
    return -1;
19
20
0
  if (commit->parents)
21
0
    diff_tree_oid(&commit->parents->item->object.oid,
22
0
            &commit->object.oid, "", options);
23
0
  else
24
0
    diff_root_tree_oid(&commit->object.oid, "", options);
25
0
  diffcore_std(options);
26
0
  return diff_flush_patch_id(options, oid, diff_header_only);
27
0
}
28
29
/*
30
 * When we cannot load the full patch-id for both commits for whatever
31
 * reason, the function returns -1 (i.e. return error(...)). Despite
32
 * the "neq" in the name of this function, the caller only cares about
33
 * the return value being zero (a and b are equivalent) or non-zero (a
34
 * and b are different), and returning non-zero would keep both in the
35
 * result, even if they actually were equivalent, in order to err on
36
 * the side of safety.  The actual value being negative does not have
37
 * any significance; only that it is non-zero matters.
38
 */
39
static int patch_id_neq(const void *cmpfn_data,
40
      const struct hashmap_entry *eptr,
41
      const struct hashmap_entry *entry_or_key,
42
      const void *keydata UNUSED)
43
0
{
44
  /* NEEDSWORK: const correctness? */
45
0
  struct diff_options *opt = (void *)cmpfn_data;
46
0
  struct patch_id *a, *b;
47
48
0
  a = container_of(eptr, struct patch_id, ent);
49
0
  b = container_of(entry_or_key, struct patch_id, ent);
50
51
0
  if (is_null_oid(&a->patch_id) &&
52
0
      commit_patch_id(a->commit, opt, &a->patch_id, 0))
53
0
    return error("Could not get patch ID for %s",
54
0
      oid_to_hex(&a->commit->object.oid));
55
0
  if (is_null_oid(&b->patch_id) &&
56
0
      commit_patch_id(b->commit, opt, &b->patch_id, 0))
57
0
    return error("Could not get patch ID for %s",
58
0
      oid_to_hex(&b->commit->object.oid));
59
0
  return !oideq(&a->patch_id, &b->patch_id);
60
0
}
61
62
int init_patch_ids(struct repository *r, struct patch_ids *ids)
63
0
{
64
0
  memset(ids, 0, sizeof(*ids));
65
0
  repo_diff_setup(r, &ids->diffopts);
66
0
  ids->diffopts.detect_rename = 0;
67
0
  ids->diffopts.flags.recursive = 1;
68
0
  diff_setup_done(&ids->diffopts);
69
0
  hashmap_init(&ids->patches, patch_id_neq, &ids->diffopts, 256);
70
0
  return 0;
71
0
}
72
73
int free_patch_ids(struct patch_ids *ids)
74
0
{
75
0
  hashmap_clear_and_free(&ids->patches, struct patch_id, ent);
76
0
  return 0;
77
0
}
78
79
static int init_patch_id_entry(struct patch_id *patch,
80
             struct commit *commit,
81
             struct patch_ids *ids)
82
0
{
83
0
  struct object_id header_only_patch_id;
84
85
0
  patch->commit = commit;
86
0
  if (commit_patch_id(commit, &ids->diffopts, &header_only_patch_id, 1))
87
0
    return -1;
88
89
0
  hashmap_entry_init(&patch->ent, oidhash(&header_only_patch_id));
90
0
  return 0;
91
0
}
92
93
struct patch_id *patch_id_iter_first(struct commit *commit,
94
             struct patch_ids *ids)
95
0
{
96
0
  struct patch_id patch;
97
98
0
  if (!patch_id_defined(commit))
99
0
    return NULL;
100
101
0
  memset(&patch, 0, sizeof(patch));
102
0
  if (init_patch_id_entry(&patch, commit, ids))
103
0
    return NULL;
104
105
0
  return hashmap_get_entry(&ids->patches, &patch, ent, NULL);
106
0
}
107
108
struct patch_id *patch_id_iter_next(struct patch_id *cur,
109
            struct patch_ids *ids)
110
0
{
111
0
  return hashmap_get_next_entry(&ids->patches, cur, ent);
112
0
}
113
114
int has_commit_patch_id(struct commit *commit,
115
      struct patch_ids *ids)
116
0
{
117
0
  return !!patch_id_iter_first(commit, ids);
118
0
}
119
120
struct patch_id *add_commit_patch_id(struct commit *commit,
121
             struct patch_ids *ids)
122
0
{
123
0
  struct patch_id *key;
124
125
0
  if (!patch_id_defined(commit))
126
0
    return NULL;
127
128
0
  CALLOC_ARRAY(key, 1);
129
0
  if (init_patch_id_entry(key, commit, ids)) {
130
0
    free(key);
131
0
    return NULL;
132
0
  }
133
134
0
  hashmap_add(&ids->patches, &key->ent);
135
0
  return key;
136
0
}