blame: move fake-commit-related methods to libgit
Signed-off-by: Jeff Smith <whydoubt@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Jeff Smith committed
May 24, 2017 at 00:15 UTC
072bf4321fb484a8eabb315c031f47883336fba2
3 files changed
+205
-199
blame.c
+202
-1
@@ -1,3 +1,6 @@
1
+#include "cache.h"
2
+#include "refs.h"
3
+#include "cache-tree.h"
4
#include "blame.h"
5
6
void blame_origin_decref(struct blame_origin *o)
@@ -28,7 +31,7 @@ void blame_origin_decref(struct blame_origin *o)
31
* get_origin() to obtain shared, refcounted copy instead of calling
32
* this function directly.
33
*/
31
-struct blame_origin *make_origin(struct commit *commit, const char *path)
34
+static struct blame_origin *make_origin(struct commit *commit, const char *path)
35
{
36
struct blame_origin *o;
37
FLEX_ALLOC_STR(o, path, path);
@@ -60,3 +63,201 @@ struct blame_origin *get_origin(struct commit *commit, const char *path)
63
}
64
return make_origin(commit, path);
65
}
66
+
67
+
68
+
69
+static void verify_working_tree_path(struct commit *work_tree, const char *path)
70
+{
71
+ struct commit_list *parents;
72
+ int pos;
73
+
74
+ for (parents = work_tree->parents; parents; parents = parents->next) {
75
+ const struct object_id *commit_oid = &parents->item->object.oid;
76
+ struct object_id blob_oid;
77
+ unsigned mode;
78
+
79
+ if (!get_tree_entry(commit_oid->hash, path, blob_oid.hash, &mode) &&
80
+ sha1_object_info(blob_oid.hash, NULL) == OBJ_BLOB)
81
+ return;
82
+ }
83
+
84
+ pos = cache_name_pos(path, strlen(path));
85
+ if (pos >= 0)
86
+ ; /* path is in the index */
87
+ else if (-1 - pos < active_nr &&
88
+ !strcmp(active_cache[-1 - pos]->name, path))
89
+ ; /* path is in the index, unmerged */
90
+ else
91
+ die("no such path '%s' in HEAD", path);
92
+}
93
+
94
+static struct commit_list **append_parent(struct commit_list **tail, const struct object_id *oid)
95
+{
96
+ struct commit *parent;
97
+
98
+ parent = lookup_commit_reference(oid->hash);
99
+ if (!parent)
100
+ die("no such commit %s", oid_to_hex(oid));
101
+ return &commit_list_insert(parent, tail)->next;
102
+}
103
+
104
+static void append_merge_parents(struct commit_list **tail)
105
+{
106
+ int merge_head;
107
+ struct strbuf line = STRBUF_INIT;
108
+
109
+ merge_head = open(git_path_merge_head(), O_RDONLY);
110
+ if (merge_head < 0) {
111
+ if (errno == ENOENT)
112
+ return;
113
+ die("cannot open '%s' for reading", git_path_merge_head());
114
+ }
115
+
116
+ while (!strbuf_getwholeline_fd(&line, merge_head, '\n')) {
117
+ struct object_id oid;
118
+ if (line.len < GIT_SHA1_HEXSZ || get_oid_hex(line.buf, &oid))
119
+ die("unknown line in '%s': %s", git_path_merge_head(), line.buf);
120
+ tail = append_parent(tail, &oid);
121
+ }
122
+ close(merge_head);
123
+ strbuf_release(&line);
124
+}
125
+
126
+/*
127
+ * This isn't as simple as passing sb->buf and sb->len, because we
128
+ * want to transfer ownership of the buffer to the commit (so we
129
+ * must use detach).
130
+ */
131
+static void set_commit_buffer_from_strbuf(struct commit *c, struct strbuf *sb)
132
+{
133
+ size_t len;
134
+ void *buf = strbuf_detach(sb, &len);
135
+ set_commit_buffer(c, buf, len);
136
+}
137
+
138
+/*
139
+ * Prepare a dummy commit that represents the work tree (or staged) item.
140
+ * Note that annotating work tree item never works in the reverse.
141
+ */
142
+struct commit *fake_working_tree_commit(struct diff_options *opt,
143
+ const char *path,
144
+ const char *contents_from)
145
+{
146
+ struct commit *commit;
147
+ struct blame_origin *origin;
148
+ struct commit_list **parent_tail, *parent;
149
+ struct object_id head_oid;
150
+ struct strbuf buf = STRBUF_INIT;
151
+ const char *ident;
152
+ time_t now;
153
+ int size, len;
154
+ struct cache_entry *ce;
155
+ unsigned mode;
156
+ struct strbuf msg = STRBUF_INIT;
157
+
158
+ read_cache();
159
+ time(&now);
160
+ commit = alloc_commit_node();
161
+ commit->object.parsed = 1;
162
+ commit->date = now;
163
+ parent_tail = &commit->parents;
164
+
165
+ if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL))
166
+ die("no such ref: HEAD");
167
+
168
+ parent_tail = append_parent(parent_tail, &head_oid);
169
+ append_merge_parents(parent_tail);
170
+ verify_working_tree_path(commit, path);
171
+
172
+ origin = make_origin(commit, path);
173
+
174
+ ident = fmt_ident("Not Committed Yet", "not.committed.yet", NULL, 0);
175
+ strbuf_addstr(&msg, "tree 0000000000000000000000000000000000000000\n");
176
+ for (parent = commit->parents; parent; parent = parent->next)
177
+ strbuf_addf(&msg, "parent %s\n",
178
+ oid_to_hex(&parent->item->object.oid));
179
+ strbuf_addf(&msg,
180
+ "author %s\n"
181
+ "committer %s\n\n"
182
+ "Version of %s from %s\n",
183
+ ident, ident, path,
184
+ (!contents_from ? path :
185
+ (!strcmp(contents_from, "-") ? "standard input" : contents_from)));
186
+ set_commit_buffer_from_strbuf(commit, &msg);
187
+
188
+ if (!contents_from || strcmp("-", contents_from)) {
189
+ struct stat st;
190
+ const char *read_from;
191
+ char *buf_ptr;
192
+ unsigned long buf_len;
193
+
194
+ if (contents_from) {
195
+ if (stat(contents_from, &st) < 0)
196
+ die_errno("Cannot stat '%s'", contents_from);
197
+ read_from = contents_from;
198
+ }
199
+ else {
200
+ if (lstat(path, &st) < 0)
201
+ die_errno("Cannot lstat '%s'", path);
202
+ read_from = path;
203
+ }
204
+ mode = canon_mode(st.st_mode);
205
+
206
+ switch (st.st_mode & S_IFMT) {
207
+ case S_IFREG:
208
+ if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
209
+ textconv_object(read_from, mode, &null_oid, 0, &buf_ptr, &buf_len))
210
+ strbuf_attach(&buf, buf_ptr, buf_len, buf_len + 1);
211
+ else if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size)
212
+ die_errno("cannot open or read '%s'", read_from);
213
+ break;
214
+ case S_IFLNK:
215
+ if (strbuf_readlink(&buf, read_from, st.st_size) < 0)
216
+ die_errno("cannot readlink '%s'", read_from);
217
+ break;
218
+ default:
219
+ die("unsupported file type %s", read_from);
220
+ }
221
+ }
222
+ else {
223
+ /* Reading from stdin */
224
+ mode = 0;
225
+ if (strbuf_read(&buf, 0, 0) < 0)
226
+ die_errno("failed to read from stdin");
227
+ }
228
+ convert_to_git(path, buf.buf, buf.len, &buf, 0);
229
+ origin->file.ptr = buf.buf;
230
+ origin->file.size = buf.len;
231
+ pretend_sha1_file(buf.buf, buf.len, OBJ_BLOB, origin->blob_oid.hash);
232
+
233
+ /*
234
+ * Read the current index, replace the path entry with
235
+ * origin->blob_sha1 without mucking with its mode or type
236
+ * bits; we are not going to write this index out -- we just
237
+ * want to run "diff-index --cached".
238
+ */
239
+ discard_cache();
240
+ read_cache();
241
+
242
+ len = strlen(path);
243
+ if (!mode) {
244
+ int pos = cache_name_pos(path, len);
245
+ if (0 <= pos)
246
+ mode = active_cache[pos]->ce_mode;
247
+ else
248
+ /* Let's not bother reading from HEAD tree */
249
+ mode = S_IFREG | 0644;
250
+ }
251
+ size = cache_entry_size(len);
252
+ ce = xcalloc(1, size);
253
+ oidcpy(&ce->oid, &origin->blob_oid);
254
+ memcpy(ce->name, path, len);
255
+ ce->ce_flags = create_ce_flags(0);
256
+ ce->ce_namelen = len;
257
+ ce->ce_mode = create_ce_mode(mode);
258
+ add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
259
+
260
+ cache_tree_invalidate_path(&the_index, path);
261
+
262
+ return commit;
263
+}
blame.h
+3
-1
@@ -6,6 +6,7 @@
6
#include "xdiff-interface.h"
7
#include "revision.h"
8
#include "prio-queue.h"
9
+#include "diff.h"
10
11
/*
12
* One blob in a commit that is being suspected
@@ -152,7 +153,8 @@ static inline struct blame_origin *blame_origin_incref(struct blame_origin *o)
153
}
154
extern void blame_origin_decref(struct blame_origin *o);
155
155
-extern struct blame_origin *make_origin(struct commit *commit, const char *path);
156
extern struct blame_origin *get_origin(struct commit *commit, const char *path);
157
158
+extern struct commit *fake_working_tree_commit(struct diff_options *opt, const char *path, const char *contents_from);
159
+
160
#endif /* BLAME_H */
builtin/blame.c
-197
@@ -16,7 +16,6 @@
16
#include "revision.h"
17
#include "quote.h"
18
#include "xdiff-interface.h"
19
-#include "cache-tree.h"
19
#include "string-list.h"
20
#include "mailmap.h"
21
#include "mergesort.h"
@@ -2006,202 +2005,6 @@ static int git_blame_config(const char *var, const char *value, void *cb)
2005
return git_default_config(var, value, cb);
2006
}
2007
2009
-static void verify_working_tree_path(struct commit *work_tree, const char *path)
2010
-{
2011
- struct commit_list *parents;
2012
- int pos;
2013
-
2014
- for (parents = work_tree->parents; parents; parents = parents->next) {
2015
- const struct object_id *commit_oid = &parents->item->object.oid;
2016
- struct object_id blob_oid;
2017
- unsigned mode;
2018
-
2019
- if (!get_tree_entry(commit_oid->hash, path, blob_oid.hash, &mode) &&
2020
- sha1_object_info(blob_oid.hash, NULL) == OBJ_BLOB)
2021
- return;
2022
- }
2023
-
2024
- pos = cache_name_pos(path, strlen(path));
2025
- if (pos >= 0)
2026
- ; /* path is in the index */
2027
- else if (-1 - pos < active_nr &&
2028
- !strcmp(active_cache[-1 - pos]->name, path))
2029
- ; /* path is in the index, unmerged */
2030
- else
2031
- die("no such path '%s' in HEAD", path);
2032
-}
2033
-
2034
-static struct commit_list **append_parent(struct commit_list **tail, const struct object_id *oid)
2035
-{
2036
- struct commit *parent;
2037
-
2038
- parent = lookup_commit_reference(oid->hash);
2039
- if (!parent)
2040
- die("no such commit %s", oid_to_hex(oid));
2041
- return &commit_list_insert(parent, tail)->next;
2042
-}
2043
-
2044
-static void append_merge_parents(struct commit_list **tail)
2045
-{
2046
- int merge_head;
2047
- struct strbuf line = STRBUF_INIT;
2048
-
2049
- merge_head = open(git_path_merge_head(), O_RDONLY);
2050
- if (merge_head < 0) {
2051
- if (errno == ENOENT)
2052
- return;
2053
- die("cannot open '%s' for reading", git_path_merge_head());
2054
- }
2055
-
2056
- while (!strbuf_getwholeline_fd(&line, merge_head, '\n')) {
2057
- struct object_id oid;
2058
- if (line.len < GIT_SHA1_HEXSZ || get_oid_hex(line.buf, &oid))
2059
- die("unknown line in '%s': %s", git_path_merge_head(), line.buf);
2060
- tail = append_parent(tail, &oid);
2061
- }
2062
- close(merge_head);
2063
- strbuf_release(&line);
2064
-}
2065
-
2066
-/*
2067
- * This isn't as simple as passing sb->buf and sb->len, because we
2068
- * want to transfer ownership of the buffer to the commit (so we
2069
- * must use detach).
2070
- */
2071
-static void set_commit_buffer_from_strbuf(struct commit *c, struct strbuf *sb)
2072
-{
2073
- size_t len;
2074
- void *buf = strbuf_detach(sb, &len);
2075
- set_commit_buffer(c, buf, len);
2076
-}
2077
-
2078
-/*
2079
- * Prepare a dummy commit that represents the work tree (or staged) item.
2080
- * Note that annotating work tree item never works in the reverse.
2081
- */
2082
-static struct commit *fake_working_tree_commit(struct diff_options *opt,
2083
- const char *path,
2084
- const char *contents_from)
2085
-{
2086
- struct commit *commit;
2087
- struct blame_origin *origin;
2088
- struct commit_list **parent_tail, *parent;
2089
- struct object_id head_oid;
2090
- struct strbuf buf = STRBUF_INIT;
2091
- const char *ident;
2092
- time_t now;
2093
- int size, len;
2094
- struct cache_entry *ce;
2095
- unsigned mode;
2096
- struct strbuf msg = STRBUF_INIT;
2097
-
2098
- read_cache();
2099
- time(&now);
2100
- commit = alloc_commit_node();
2101
- commit->object.parsed = 1;
2102
- commit->date = now;
2103
- parent_tail = &commit->parents;
2104
-
2105
- if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL))
2106
- die("no such ref: HEAD");
2107
-
2108
- parent_tail = append_parent(parent_tail, &head_oid);
2109
- append_merge_parents(parent_tail);
2110
- verify_working_tree_path(commit, path);
2111
-
2112
- origin = make_origin(commit, path);
2113
-
2114
- ident = fmt_ident("Not Committed Yet", "not.committed.yet", NULL, 0);
2115
- strbuf_addstr(&msg, "tree 0000000000000000000000000000000000000000\n");
2116
- for (parent = commit->parents; parent; parent = parent->next)
2117
- strbuf_addf(&msg, "parent %s\n",
2118
- oid_to_hex(&parent->item->object.oid));
2119
- strbuf_addf(&msg,
2120
- "author %s\n"
2121
- "committer %s\n\n"
2122
- "Version of %s from %s\n",
2123
- ident, ident, path,
2124
- (!contents_from ? path :
2125
- (!strcmp(contents_from, "-") ? "standard input" : contents_from)));
2126
- set_commit_buffer_from_strbuf(commit, &msg);
2127
-
2128
- if (!contents_from || strcmp("-", contents_from)) {
2129
- struct stat st;
2130
- const char *read_from;
2131
- char *buf_ptr;
2132
- unsigned long buf_len;
2133
-
2134
- if (contents_from) {
2135
- if (stat(contents_from, &st) < 0)
2136
- die_errno("Cannot stat '%s'", contents_from);
2137
- read_from = contents_from;
2138
- }
2139
- else {
2140
- if (lstat(path, &st) < 0)
2141
- die_errno("Cannot lstat '%s'", path);
2142
- read_from = path;
2143
- }
2144
- mode = canon_mode(st.st_mode);
2145
-
2146
- switch (st.st_mode & S_IFMT) {
2147
- case S_IFREG:
2148
- if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
2149
- textconv_object(read_from, mode, &null_oid, 0, &buf_ptr, &buf_len))
2150
- strbuf_attach(&buf, buf_ptr, buf_len, buf_len + 1);
2151
- else if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size)
2152
- die_errno("cannot open or read '%s'", read_from);
2153
- break;
2154
- case S_IFLNK:
2155
- if (strbuf_readlink(&buf, read_from, st.st_size) < 0)
2156
- die_errno("cannot readlink '%s'", read_from);
2157
- break;
2158
- default:
2159
- die("unsupported file type %s", read_from);
2160
- }
2161
- }
2162
- else {
2163
- /* Reading from stdin */
2164
- mode = 0;
2165
- if (strbuf_read(&buf, 0, 0) < 0)
2166
- die_errno("failed to read from stdin");
2167
- }
2168
- convert_to_git(path, buf.buf, buf.len, &buf, 0);
2169
- origin->file.ptr = buf.buf;
2170
- origin->file.size = buf.len;
2171
- pretend_sha1_file(buf.buf, buf.len, OBJ_BLOB, origin->blob_oid.hash);
2172
-
2173
- /*
2174
- * Read the current index, replace the path entry with
2175
- * origin->blob_sha1 without mucking with its mode or type
2176
- * bits; we are not going to write this index out -- we just
2177
- * want to run "diff-index --cached".
2178
- */
2179
- discard_cache();
2180
- read_cache();
2181
-
2182
- len = strlen(path);
2183
- if (!mode) {
2184
- int pos = cache_name_pos(path, len);
2185
- if (0 <= pos)
2186
- mode = active_cache[pos]->ce_mode;
2187
- else
2188
- /* Let's not bother reading from HEAD tree */
2189
- mode = S_IFREG | 0644;
2190
- }
2191
- size = cache_entry_size(len);
2192
- ce = xcalloc(1, size);
2193
- oidcpy(&ce->oid, &origin->blob_oid);
2194
- memcpy(ce->name, path, len);
2195
- ce->ce_flags = create_ce_flags(0);
2196
- ce->ce_namelen = len;
2197
- ce->ce_mode = create_ce_mode(mode);
2198
- add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
2199
-
2200
- cache_tree_invalidate_path(&the_index, path);
2201
-
2202
- return commit;
2203
-}
2204
-
2008
static struct commit *find_single_final(struct rev_info *revs,
2009
const char **name_p)
2010
{