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 | } |