Line | Count | Source |
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 | | /* |
45 | | * We drop the 'const' modifier here intentionally. |
46 | | * |
47 | | * Even though eptr and entry_or_key are const, we want to |
48 | | * lazily compute their .patch_id members; see b3dfeebb (rebase: |
49 | | * avoid computing unnecessary patch IDs, 2016-07-29). So we cast |
50 | | * the constness away with container_of(). |
51 | | */ |
52 | 0 | struct diff_options *opt = (void *)cmpfn_data; |
53 | 0 | struct patch_id *a, *b; |
54 | |
|
55 | 0 | a = container_of(eptr, struct patch_id, ent); |
56 | 0 | b = container_of(entry_or_key, struct patch_id, ent); |
57 | |
|
58 | 0 | if (is_null_oid(&a->patch_id) && |
59 | 0 | commit_patch_id(a->commit, opt, &a->patch_id, 0)) |
60 | 0 | return error("Could not get patch ID for %s", |
61 | 0 | oid_to_hex(&a->commit->object.oid)); |
62 | 0 | if (is_null_oid(&b->patch_id) && |
63 | 0 | commit_patch_id(b->commit, opt, &b->patch_id, 0)) |
64 | 0 | return error("Could not get patch ID for %s", |
65 | 0 | oid_to_hex(&b->commit->object.oid)); |
66 | 0 | return !oideq(&a->patch_id, &b->patch_id); |
67 | 0 | } |
68 | | |
69 | | int init_patch_ids(struct repository *r, struct patch_ids *ids) |
70 | 0 | { |
71 | 0 | memset(ids, 0, sizeof(*ids)); |
72 | 0 | repo_diff_setup(r, &ids->diffopts); |
73 | 0 | ids->diffopts.detect_rename = 0; |
74 | 0 | ids->diffopts.flags.recursive = 1; |
75 | 0 | diff_setup_done(&ids->diffopts); |
76 | 0 | hashmap_init(&ids->patches, patch_id_neq, &ids->diffopts, 256); |
77 | 0 | return 0; |
78 | 0 | } |
79 | | |
80 | | int free_patch_ids(struct patch_ids *ids) |
81 | 0 | { |
82 | 0 | hashmap_clear_and_free(&ids->patches, struct patch_id, ent); |
83 | 0 | return 0; |
84 | 0 | } |
85 | | |
86 | | static int init_patch_id_entry(struct patch_id *patch, |
87 | | struct commit *commit, |
88 | | struct patch_ids *ids) |
89 | 0 | { |
90 | 0 | struct object_id header_only_patch_id; |
91 | |
|
92 | 0 | patch->commit = commit; |
93 | 0 | if (commit_patch_id(commit, &ids->diffopts, &header_only_patch_id, 1)) |
94 | 0 | return -1; |
95 | | |
96 | 0 | hashmap_entry_init(&patch->ent, oidhash(&header_only_patch_id)); |
97 | 0 | return 0; |
98 | 0 | } |
99 | | |
100 | | struct patch_id *patch_id_iter_first(struct commit *commit, |
101 | | struct patch_ids *ids) |
102 | 0 | { |
103 | 0 | struct patch_id patch; |
104 | |
|
105 | 0 | if (!patch_id_defined(commit)) |
106 | 0 | return NULL; |
107 | | |
108 | 0 | memset(&patch, 0, sizeof(patch)); |
109 | 0 | if (init_patch_id_entry(&patch, commit, ids)) |
110 | 0 | return NULL; |
111 | | |
112 | 0 | return hashmap_get_entry(&ids->patches, &patch, ent, NULL); |
113 | 0 | } |
114 | | |
115 | | struct patch_id *patch_id_iter_next(struct patch_id *cur, |
116 | | struct patch_ids *ids) |
117 | 0 | { |
118 | 0 | return hashmap_get_next_entry(&ids->patches, cur, ent); |
119 | 0 | } |
120 | | |
121 | | int has_commit_patch_id(struct commit *commit, |
122 | | struct patch_ids *ids) |
123 | 0 | { |
124 | 0 | return !!patch_id_iter_first(commit, ids); |
125 | 0 | } |
126 | | |
127 | | struct patch_id *add_commit_patch_id(struct commit *commit, |
128 | | struct patch_ids *ids) |
129 | 0 | { |
130 | 0 | struct patch_id *key; |
131 | |
|
132 | 0 | if (!patch_id_defined(commit)) |
133 | 0 | return NULL; |
134 | | |
135 | 0 | CALLOC_ARRAY(key, 1); |
136 | 0 | if (init_patch_id_entry(key, commit, ids)) { |
137 | 0 | free(key); |
138 | 0 | return NULL; |
139 | 0 | } |
140 | | |
141 | 0 | hashmap_add(&ids->patches, &key->ent); |
142 | 0 | return key; |
143 | 0 | } |