]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (C) the libgit2 contributors. All rights reserved. | |
3 | * | |
4 | * This file is part of libgit2, distributed under the GNU GPL v2 with | |
5 | * a Linking Exception. For full terms see the included COPYING file. | |
6 | */ | |
7 | ||
8 | #include "status.h" | |
9 | ||
10 | #include "git2.h" | |
11 | #include "futils.h" | |
12 | #include "hash.h" | |
13 | #include "vector.h" | |
14 | #include "tree.h" | |
15 | #include "git2/status.h" | |
16 | #include "repository.h" | |
17 | #include "ignore.h" | |
18 | #include "index.h" | |
19 | #include "wildmatch.h" | |
20 | ||
21 | #include "git2/diff.h" | |
22 | #include "diff.h" | |
23 | #include "diff_generate.h" | |
24 | ||
25 | static unsigned int index_delta2status(const git_diff_delta *head2idx) | |
26 | { | |
27 | git_status_t st = GIT_STATUS_CURRENT; | |
28 | ||
29 | switch (head2idx->status) { | |
30 | case GIT_DELTA_ADDED: | |
31 | case GIT_DELTA_COPIED: | |
32 | st = GIT_STATUS_INDEX_NEW; | |
33 | break; | |
34 | case GIT_DELTA_DELETED: | |
35 | st = GIT_STATUS_INDEX_DELETED; | |
36 | break; | |
37 | case GIT_DELTA_MODIFIED: | |
38 | st = GIT_STATUS_INDEX_MODIFIED; | |
39 | break; | |
40 | case GIT_DELTA_RENAMED: | |
41 | st = GIT_STATUS_INDEX_RENAMED; | |
42 | ||
43 | if (!git_oid_equal(&head2idx->old_file.id, &head2idx->new_file.id)) | |
44 | st |= GIT_STATUS_INDEX_MODIFIED; | |
45 | break; | |
46 | case GIT_DELTA_TYPECHANGE: | |
47 | st = GIT_STATUS_INDEX_TYPECHANGE; | |
48 | break; | |
49 | case GIT_DELTA_CONFLICTED: | |
50 | st = GIT_STATUS_CONFLICTED; | |
51 | break; | |
52 | default: | |
53 | break; | |
54 | } | |
55 | ||
56 | return st; | |
57 | } | |
58 | ||
59 | static unsigned int workdir_delta2status( | |
60 | git_diff *diff, git_diff_delta *idx2wd) | |
61 | { | |
62 | git_status_t st = GIT_STATUS_CURRENT; | |
63 | ||
64 | switch (idx2wd->status) { | |
65 | case GIT_DELTA_ADDED: | |
66 | case GIT_DELTA_COPIED: | |
67 | case GIT_DELTA_UNTRACKED: | |
68 | st = GIT_STATUS_WT_NEW; | |
69 | break; | |
70 | case GIT_DELTA_UNREADABLE: | |
71 | st = GIT_STATUS_WT_UNREADABLE; | |
72 | break; | |
73 | case GIT_DELTA_DELETED: | |
74 | st = GIT_STATUS_WT_DELETED; | |
75 | break; | |
76 | case GIT_DELTA_MODIFIED: | |
77 | st = GIT_STATUS_WT_MODIFIED; | |
78 | break; | |
79 | case GIT_DELTA_IGNORED: | |
80 | st = GIT_STATUS_IGNORED; | |
81 | break; | |
82 | case GIT_DELTA_RENAMED: | |
83 | st = GIT_STATUS_WT_RENAMED; | |
84 | ||
85 | if (!git_oid_equal(&idx2wd->old_file.id, &idx2wd->new_file.id)) { | |
86 | /* if OIDs don't match, we might need to calculate them now to | |
87 | * discern between RENAMED vs RENAMED+MODIFIED | |
88 | */ | |
89 | if (git_oid_is_zero(&idx2wd->old_file.id) && | |
90 | diff->old_src == GIT_ITERATOR_WORKDIR && | |
91 | !git_diff__oid_for_file( | |
92 | &idx2wd->old_file.id, diff, idx2wd->old_file.path, | |
93 | idx2wd->old_file.mode, idx2wd->old_file.size)) | |
94 | idx2wd->old_file.flags |= GIT_DIFF_FLAG_VALID_ID; | |
95 | ||
96 | if (git_oid_is_zero(&idx2wd->new_file.id) && | |
97 | diff->new_src == GIT_ITERATOR_WORKDIR && | |
98 | !git_diff__oid_for_file( | |
99 | &idx2wd->new_file.id, diff, idx2wd->new_file.path, | |
100 | idx2wd->new_file.mode, idx2wd->new_file.size)) | |
101 | idx2wd->new_file.flags |= GIT_DIFF_FLAG_VALID_ID; | |
102 | ||
103 | if (!git_oid_equal(&idx2wd->old_file.id, &idx2wd->new_file.id)) | |
104 | st |= GIT_STATUS_WT_MODIFIED; | |
105 | } | |
106 | break; | |
107 | case GIT_DELTA_TYPECHANGE: | |
108 | st = GIT_STATUS_WT_TYPECHANGE; | |
109 | break; | |
110 | case GIT_DELTA_CONFLICTED: | |
111 | st = GIT_STATUS_CONFLICTED; | |
112 | break; | |
113 | default: | |
114 | break; | |
115 | } | |
116 | ||
117 | return st; | |
118 | } | |
119 | ||
120 | static bool status_is_included( | |
121 | git_status_list *status, | |
122 | git_diff_delta *head2idx, | |
123 | git_diff_delta *idx2wd) | |
124 | { | |
125 | if (!(status->opts.flags & GIT_STATUS_OPT_EXCLUDE_SUBMODULES)) | |
126 | return 1; | |
127 | ||
128 | /* if excluding submodules and this is a submodule everywhere */ | |
129 | if (head2idx) { | |
130 | if (head2idx->status != GIT_DELTA_ADDED && | |
131 | head2idx->old_file.mode != GIT_FILEMODE_COMMIT) | |
132 | return 1; | |
133 | if (head2idx->status != GIT_DELTA_DELETED && | |
134 | head2idx->new_file.mode != GIT_FILEMODE_COMMIT) | |
135 | return 1; | |
136 | } | |
137 | if (idx2wd) { | |
138 | if (idx2wd->status != GIT_DELTA_ADDED && | |
139 | idx2wd->old_file.mode != GIT_FILEMODE_COMMIT) | |
140 | return 1; | |
141 | if (idx2wd->status != GIT_DELTA_DELETED && | |
142 | idx2wd->new_file.mode != GIT_FILEMODE_COMMIT) | |
143 | return 1; | |
144 | } | |
145 | ||
146 | /* only get here if every valid mode is GIT_FILEMODE_COMMIT */ | |
147 | return 0; | |
148 | } | |
149 | ||
150 | static git_status_t status_compute( | |
151 | git_status_list *status, | |
152 | git_diff_delta *head2idx, | |
153 | git_diff_delta *idx2wd) | |
154 | { | |
155 | git_status_t st = GIT_STATUS_CURRENT; | |
156 | ||
157 | if (head2idx) | |
158 | st |= index_delta2status(head2idx); | |
159 | ||
160 | if (idx2wd) | |
161 | st |= workdir_delta2status(status->idx2wd, idx2wd); | |
162 | ||
163 | return st; | |
164 | } | |
165 | ||
166 | static int status_collect( | |
167 | git_diff_delta *head2idx, | |
168 | git_diff_delta *idx2wd, | |
169 | void *payload) | |
170 | { | |
171 | git_status_list *status = payload; | |
172 | git_status_entry *status_entry; | |
173 | ||
174 | if (!status_is_included(status, head2idx, idx2wd)) | |
175 | return 0; | |
176 | ||
177 | status_entry = git__malloc(sizeof(git_status_entry)); | |
178 | GIT_ERROR_CHECK_ALLOC(status_entry); | |
179 | ||
180 | status_entry->status = status_compute(status, head2idx, idx2wd); | |
181 | status_entry->head_to_index = head2idx; | |
182 | status_entry->index_to_workdir = idx2wd; | |
183 | ||
184 | return git_vector_insert(&status->paired, status_entry); | |
185 | } | |
186 | ||
187 | GIT_INLINE(int) status_entry_cmp_base( | |
188 | const void *a, | |
189 | const void *b, | |
190 | int (*strcomp)(const char *a, const char *b)) | |
191 | { | |
192 | const git_status_entry *entry_a = a; | |
193 | const git_status_entry *entry_b = b; | |
194 | const git_diff_delta *delta_a, *delta_b; | |
195 | ||
196 | delta_a = entry_a->index_to_workdir ? entry_a->index_to_workdir : | |
197 | entry_a->head_to_index; | |
198 | delta_b = entry_b->index_to_workdir ? entry_b->index_to_workdir : | |
199 | entry_b->head_to_index; | |
200 | ||
201 | if (!delta_a && delta_b) | |
202 | return -1; | |
203 | if (delta_a && !delta_b) | |
204 | return 1; | |
205 | if (!delta_a && !delta_b) | |
206 | return 0; | |
207 | ||
208 | return strcomp(delta_a->new_file.path, delta_b->new_file.path); | |
209 | } | |
210 | ||
211 | static int status_entry_icmp(const void *a, const void *b) | |
212 | { | |
213 | return status_entry_cmp_base(a, b, git__strcasecmp); | |
214 | } | |
215 | ||
216 | static int status_entry_cmp(const void *a, const void *b) | |
217 | { | |
218 | return status_entry_cmp_base(a, b, git__strcmp); | |
219 | } | |
220 | ||
221 | static git_status_list *git_status_list_alloc(git_index *index) | |
222 | { | |
223 | git_status_list *status = NULL; | |
224 | int (*entrycmp)(const void *a, const void *b); | |
225 | ||
226 | if (!(status = git__calloc(1, sizeof(git_status_list)))) | |
227 | return NULL; | |
228 | ||
229 | entrycmp = index->ignore_case ? status_entry_icmp : status_entry_cmp; | |
230 | ||
231 | if (git_vector_init(&status->paired, 0, entrycmp) < 0) { | |
232 | git__free(status); | |
233 | return NULL; | |
234 | } | |
235 | ||
236 | return status; | |
237 | } | |
238 | ||
239 | static int status_validate_options(const git_status_options *opts) | |
240 | { | |
241 | if (!opts) | |
242 | return 0; | |
243 | ||
244 | GIT_ERROR_CHECK_VERSION(opts, GIT_STATUS_OPTIONS_VERSION, "git_status_options"); | |
245 | ||
246 | if (opts->show > GIT_STATUS_SHOW_WORKDIR_ONLY) { | |
247 | git_error_set(GIT_ERROR_INVALID, "unknown status 'show' option"); | |
248 | return -1; | |
249 | } | |
250 | ||
251 | if ((opts->flags & GIT_STATUS_OPT_NO_REFRESH) != 0 && | |
252 | (opts->flags & GIT_STATUS_OPT_UPDATE_INDEX) != 0) { | |
253 | git_error_set(GIT_ERROR_INVALID, "updating index from status " | |
254 | "is not allowed when index refresh is disabled"); | |
255 | return -1; | |
256 | } | |
257 | ||
258 | return 0; | |
259 | } | |
260 | ||
261 | int git_status_list_new( | |
262 | git_status_list **out, | |
263 | git_repository *repo, | |
264 | const git_status_options *opts) | |
265 | { | |
266 | git_index *index = NULL; | |
267 | git_status_list *status = NULL; | |
268 | git_diff_options diffopt = GIT_DIFF_OPTIONS_INIT; | |
269 | git_diff_find_options findopt = GIT_DIFF_FIND_OPTIONS_INIT; | |
270 | git_tree *head = NULL; | |
271 | git_status_show_t show = | |
272 | opts ? opts->show : GIT_STATUS_SHOW_INDEX_AND_WORKDIR; | |
273 | int error = 0; | |
274 | unsigned int flags = opts ? opts->flags : GIT_STATUS_OPT_DEFAULTS; | |
275 | ||
276 | *out = NULL; | |
277 | ||
278 | if (status_validate_options(opts) < 0) | |
279 | return -1; | |
280 | ||
281 | if ((error = git_repository__ensure_not_bare(repo, "status")) < 0 || | |
282 | (error = git_repository_index(&index, repo)) < 0) | |
283 | return error; | |
284 | ||
285 | if (opts != NULL && opts->baseline != NULL) { | |
286 | head = opts->baseline; | |
287 | } else { | |
288 | /* if there is no HEAD, that's okay - we'll make an empty iterator */ | |
289 | if ((error = git_repository_head_tree(&head, repo)) < 0) { | |
290 | if (error != GIT_ENOTFOUND && error != GIT_EUNBORNBRANCH) | |
291 | goto done; | |
292 | git_error_clear(); | |
293 | } | |
294 | } | |
295 | ||
296 | /* refresh index from disk unless prevented */ | |
297 | if ((flags & GIT_STATUS_OPT_NO_REFRESH) == 0 && | |
298 | git_index_read_safely(index) < 0) | |
299 | git_error_clear(); | |
300 | ||
301 | status = git_status_list_alloc(index); | |
302 | GIT_ERROR_CHECK_ALLOC(status); | |
303 | ||
304 | if (opts) { | |
305 | memcpy(&status->opts, opts, sizeof(git_status_options)); | |
306 | memcpy(&diffopt.pathspec, &opts->pathspec, sizeof(diffopt.pathspec)); | |
307 | } | |
308 | ||
309 | diffopt.flags = GIT_DIFF_INCLUDE_TYPECHANGE; | |
310 | findopt.flags = GIT_DIFF_FIND_FOR_UNTRACKED; | |
311 | ||
312 | if ((flags & GIT_STATUS_OPT_INCLUDE_UNTRACKED) != 0) | |
313 | diffopt.flags = diffopt.flags | GIT_DIFF_INCLUDE_UNTRACKED; | |
314 | if ((flags & GIT_STATUS_OPT_INCLUDE_IGNORED) != 0) | |
315 | diffopt.flags = diffopt.flags | GIT_DIFF_INCLUDE_IGNORED; | |
316 | if ((flags & GIT_STATUS_OPT_INCLUDE_UNMODIFIED) != 0) | |
317 | diffopt.flags = diffopt.flags | GIT_DIFF_INCLUDE_UNMODIFIED; | |
318 | if ((flags & GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS) != 0) | |
319 | diffopt.flags = diffopt.flags | GIT_DIFF_RECURSE_UNTRACKED_DIRS; | |
320 | if ((flags & GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH) != 0) | |
321 | diffopt.flags = diffopt.flags | GIT_DIFF_DISABLE_PATHSPEC_MATCH; | |
322 | if ((flags & GIT_STATUS_OPT_RECURSE_IGNORED_DIRS) != 0) | |
323 | diffopt.flags = diffopt.flags | GIT_DIFF_RECURSE_IGNORED_DIRS; | |
324 | if ((flags & GIT_STATUS_OPT_EXCLUDE_SUBMODULES) != 0) | |
325 | diffopt.flags = diffopt.flags | GIT_DIFF_IGNORE_SUBMODULES; | |
326 | if ((flags & GIT_STATUS_OPT_UPDATE_INDEX) != 0) | |
327 | diffopt.flags = diffopt.flags | GIT_DIFF_UPDATE_INDEX; | |
328 | if ((flags & GIT_STATUS_OPT_INCLUDE_UNREADABLE) != 0) | |
329 | diffopt.flags = diffopt.flags | GIT_DIFF_INCLUDE_UNREADABLE; | |
330 | if ((flags & GIT_STATUS_OPT_INCLUDE_UNREADABLE_AS_UNTRACKED) != 0) | |
331 | diffopt.flags = diffopt.flags | GIT_DIFF_INCLUDE_UNREADABLE_AS_UNTRACKED; | |
332 | ||
333 | if ((flags & GIT_STATUS_OPT_RENAMES_FROM_REWRITES) != 0) | |
334 | findopt.flags = findopt.flags | | |
335 | GIT_DIFF_FIND_AND_BREAK_REWRITES | | |
336 | GIT_DIFF_FIND_RENAMES_FROM_REWRITES | | |
337 | GIT_DIFF_BREAK_REWRITES_FOR_RENAMES_ONLY; | |
338 | ||
339 | if (opts != NULL && opts->rename_threshold != 0) | |
340 | findopt.rename_threshold = opts->rename_threshold; | |
341 | ||
342 | if (show != GIT_STATUS_SHOW_WORKDIR_ONLY) { | |
343 | if ((error = git_diff_tree_to_index( | |
344 | &status->head2idx, repo, head, index, &diffopt)) < 0) | |
345 | goto done; | |
346 | ||
347 | if ((flags & GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX) != 0 && | |
348 | (error = git_diff_find_similar(status->head2idx, &findopt)) < 0) | |
349 | goto done; | |
350 | } | |
351 | ||
352 | if (show != GIT_STATUS_SHOW_INDEX_ONLY) { | |
353 | if ((error = git_diff_index_to_workdir( | |
354 | &status->idx2wd, repo, index, &diffopt)) < 0) { | |
355 | goto done; | |
356 | } | |
357 | ||
358 | if ((flags & GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR) != 0 && | |
359 | (error = git_diff_find_similar(status->idx2wd, &findopt)) < 0) | |
360 | goto done; | |
361 | } | |
362 | ||
363 | error = git_diff__paired_foreach( | |
364 | status->head2idx, status->idx2wd, status_collect, status); | |
365 | if (error < 0) | |
366 | goto done; | |
367 | ||
368 | if (flags & GIT_STATUS_OPT_SORT_CASE_SENSITIVELY) | |
369 | git_vector_set_cmp(&status->paired, status_entry_cmp); | |
370 | if (flags & GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY) | |
371 | git_vector_set_cmp(&status->paired, status_entry_icmp); | |
372 | ||
373 | if ((flags & | |
374 | (GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX | | |
375 | GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR | | |
376 | GIT_STATUS_OPT_SORT_CASE_SENSITIVELY | | |
377 | GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY)) != 0) | |
378 | git_vector_sort(&status->paired); | |
379 | ||
380 | done: | |
381 | if (error < 0) { | |
382 | git_status_list_free(status); | |
383 | status = NULL; | |
384 | } | |
385 | ||
386 | *out = status; | |
387 | ||
388 | if (opts == NULL || opts->baseline != head) | |
389 | git_tree_free(head); | |
390 | git_index_free(index); | |
391 | ||
392 | return error; | |
393 | } | |
394 | ||
395 | size_t git_status_list_entrycount(git_status_list *status) | |
396 | { | |
397 | GIT_ASSERT_ARG_WITH_RETVAL(status, 0); | |
398 | ||
399 | return status->paired.length; | |
400 | } | |
401 | ||
402 | const git_status_entry *git_status_byindex(git_status_list *status, size_t i) | |
403 | { | |
404 | GIT_ASSERT_ARG_WITH_RETVAL(status, NULL); | |
405 | ||
406 | return git_vector_get(&status->paired, i); | |
407 | } | |
408 | ||
409 | void git_status_list_free(git_status_list *status) | |
410 | { | |
411 | if (status == NULL) | |
412 | return; | |
413 | ||
414 | git_diff_free(status->head2idx); | |
415 | git_diff_free(status->idx2wd); | |
416 | ||
417 | git_vector_free_deep(&status->paired); | |
418 | ||
419 | git__memzero(status, sizeof(*status)); | |
420 | git__free(status); | |
421 | } | |
422 | ||
423 | int git_status_foreach_ext( | |
424 | git_repository *repo, | |
425 | const git_status_options *opts, | |
426 | git_status_cb cb, | |
427 | void *payload) | |
428 | { | |
429 | git_status_list *status; | |
430 | const git_status_entry *status_entry; | |
431 | size_t i; | |
432 | int error = 0; | |
433 | ||
434 | if ((error = git_status_list_new(&status, repo, opts)) < 0) { | |
435 | return error; | |
436 | } | |
437 | ||
438 | git_vector_foreach(&status->paired, i, status_entry) { | |
439 | const char *path = status_entry->head_to_index ? | |
440 | status_entry->head_to_index->old_file.path : | |
441 | status_entry->index_to_workdir->old_file.path; | |
442 | ||
443 | if ((error = cb(path, status_entry->status, payload)) != 0) { | |
444 | git_error_set_after_callback(error); | |
445 | break; | |
446 | } | |
447 | } | |
448 | ||
449 | git_status_list_free(status); | |
450 | ||
451 | return error; | |
452 | } | |
453 | ||
454 | int git_status_foreach(git_repository *repo, git_status_cb cb, void *payload) | |
455 | { | |
456 | return git_status_foreach_ext(repo, NULL, cb, payload); | |
457 | } | |
458 | ||
459 | struct status_file_info { | |
460 | char *expected; | |
461 | unsigned int count; | |
462 | unsigned int status; | |
463 | int wildmatch_flags; | |
464 | int ambiguous; | |
465 | }; | |
466 | ||
467 | static int get_one_status(const char *path, unsigned int status, void *data) | |
468 | { | |
469 | struct status_file_info *sfi = data; | |
470 | int (*strcomp)(const char *a, const char *b); | |
471 | ||
472 | sfi->count++; | |
473 | sfi->status = status; | |
474 | ||
475 | strcomp = (sfi->wildmatch_flags & WM_CASEFOLD) ? git__strcasecmp : git__strcmp; | |
476 | ||
477 | if (sfi->count > 1 || | |
478 | (strcomp(sfi->expected, path) != 0 && | |
479 | wildmatch(sfi->expected, path, sfi->wildmatch_flags) != 0)) | |
480 | { | |
481 | sfi->ambiguous = true; | |
482 | return GIT_EAMBIGUOUS; /* git_error_set will be done by caller */ | |
483 | } | |
484 | ||
485 | return 0; | |
486 | } | |
487 | ||
488 | int git_status_file( | |
489 | unsigned int *status_flags, | |
490 | git_repository *repo, | |
491 | const char *path) | |
492 | { | |
493 | int error; | |
494 | git_status_options opts = GIT_STATUS_OPTIONS_INIT; | |
495 | struct status_file_info sfi = {0}; | |
496 | git_index *index; | |
497 | ||
498 | GIT_ASSERT_ARG(status_flags); | |
499 | GIT_ASSERT_ARG(repo); | |
500 | GIT_ASSERT_ARG(path); | |
501 | ||
502 | if ((error = git_repository_index__weakptr(&index, repo)) < 0) | |
503 | return error; | |
504 | ||
505 | if ((sfi.expected = git__strdup(path)) == NULL) | |
506 | return -1; | |
507 | if (index->ignore_case) | |
508 | sfi.wildmatch_flags = WM_CASEFOLD; | |
509 | ||
510 | opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR; | |
511 | opts.flags = GIT_STATUS_OPT_INCLUDE_IGNORED | | |
512 | GIT_STATUS_OPT_RECURSE_IGNORED_DIRS | | |
513 | GIT_STATUS_OPT_INCLUDE_UNTRACKED | | |
514 | GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS | | |
515 | GIT_STATUS_OPT_INCLUDE_UNMODIFIED | | |
516 | GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH; | |
517 | opts.pathspec.count = 1; | |
518 | opts.pathspec.strings = &sfi.expected; | |
519 | ||
520 | error = git_status_foreach_ext(repo, &opts, get_one_status, &sfi); | |
521 | ||
522 | if (error < 0 && sfi.ambiguous) { | |
523 | git_error_set(GIT_ERROR_INVALID, | |
524 | "ambiguous path '%s' given to git_status_file", sfi.expected); | |
525 | error = GIT_EAMBIGUOUS; | |
526 | } | |
527 | ||
528 | if (!error && !sfi.count) { | |
529 | git_error_set(GIT_ERROR_INVALID, | |
530 | "attempt to get status of nonexistent file '%s'", path); | |
531 | error = GIT_ENOTFOUND; | |
532 | } | |
533 | ||
534 | *status_flags = sfi.status; | |
535 | ||
536 | git__free(sfi.expected); | |
537 | ||
538 | return error; | |
539 | } | |
540 | ||
541 | int git_status_should_ignore( | |
542 | int *ignored, | |
543 | git_repository *repo, | |
544 | const char *path) | |
545 | { | |
546 | return git_ignore_path_is_ignored(ignored, repo, path); | |
547 | } | |
548 | ||
549 | int git_status_options_init(git_status_options *opts, unsigned int version) | |
550 | { | |
551 | GIT_INIT_STRUCTURE_FROM_TEMPLATE( | |
552 | opts, version, git_status_options, GIT_STATUS_OPTIONS_INIT); | |
553 | return 0; | |
554 | } | |
555 | ||
556 | #ifndef GIT_DEPRECATE_HARD | |
557 | int git_status_init_options(git_status_options *opts, unsigned int version) | |
558 | { | |
559 | return git_status_options_init(opts, version); | |
560 | } | |
561 | #endif | |
562 | ||
563 | int git_status_list_get_perfdata( | |
564 | git_diff_perfdata *out, const git_status_list *status) | |
565 | { | |
566 | GIT_ASSERT_ARG(out); | |
567 | ||
568 | GIT_ERROR_CHECK_VERSION(out, GIT_DIFF_PERFDATA_VERSION, "git_diff_perfdata"); | |
569 | ||
570 | out->stat_calls = 0; | |
571 | out->oid_calculations = 0; | |
572 | ||
573 | if (status->head2idx) { | |
574 | out->stat_calls += status->head2idx->perf.stat_calls; | |
575 | out->oid_calculations += status->head2idx->perf.oid_calculations; | |
576 | } | |
577 | if (status->idx2wd) { | |
578 | out->stat_calls += status->idx2wd->perf.stat_calls; | |
579 | out->oid_calculations += status->idx2wd->perf.oid_calculations; | |
580 | } | |
581 | ||
582 | return 0; | |
583 | } | |
584 |