sparse-checkout: create helper methods

As we integrate the sparse index into more builtins, we occasionally need to check the sparse-checkout patterns to see if a path is within the sparse-checkout cone. Create some helper methods that help initialize the patterns and check for pattern matching to make this easier. The existing callers of commands like get_sparse_checkout_patterns() use a custom 'struct pattern_list' that is not necessarily the one in the 'struct index_state', so there are not many previous uses that could adopt these helpers. There are just two in builtin/add.c and sparse-index.c that can use path_in_sparse_checkout(). We add a path_in_cone_mode_sparse_checkout() as well that will only return false if the path is outside of the sparse-checkout definition _and_ the sparse-checkout patterns are in cone mode. Signed-off-by: Derrick Stolee <dstolee@microsoft.com> Reviewed-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Derrick Stolee committed Sep 8, 2021 at 01:42 UTC 02155c8c005d0f8ee20a38245e9a065e8b5cc7dc
4 files changed +64 -17
builtin/add.c
+1 -6
@@ -190,8 +190,6 @@ static int refresh(int verbose, const struct pathspec *pathspec)
190 struct string_list only_match_skip_worktree = STRING_LIST_INIT_NODUP;
191 int flags = REFRESH_IGNORE_SKIP_WORKTREE |
192 (verbose ? REFRESH_IN_PORCELAIN : REFRESH_QUIET);
193 - struct pattern_list pl = { 0 };
194 - int sparse_checkout_enabled = !get_sparse_checkout_patterns(&pl);
193
194 seen = xcalloc(pathspec->nr, 1);
195 refresh_index(&the_index, flags, pathspec, seen,
@@ -199,12 +197,9 @@ static int refresh(int verbose, const struct pathspec *pathspec)
197 for (i = 0; i < pathspec->nr; i++) {
198 if (!seen[i]) {
199 const char *path = pathspec->items[i].original;
202 - int dtype = DT_REG;
200
201 if (matches_skip_worktree(pathspec, i, &skip_worktree_seen) ||
205 - (sparse_checkout_enabled &&
206 - !path_matches_pattern_list(path, strlen(path), NULL,
207 - &dtype, &pl, &the_index))) {
202 + !path_in_sparse_checkout(path, &the_index)) {
203 string_list_append(&only_match_skip_worktree,
204 pathspec->items[i].original);
205 } else {
dir.c
+52
@@ -1439,6 +1439,58 @@ done:
1439 return result;
1440 }
1441
1442 +int init_sparse_checkout_patterns(struct index_state *istate)
1443 +{
1444 + if (!core_apply_sparse_checkout)
1445 + return 1;
1446 + if (istate->sparse_checkout_patterns)
1447 + return 0;
1448 +
1449 + CALLOC_ARRAY(istate->sparse_checkout_patterns, 1);
1450 +
1451 + if (get_sparse_checkout_patterns(istate->sparse_checkout_patterns) < 0) {
1452 + FREE_AND_NULL(istate->sparse_checkout_patterns);
1453 + return -1;
1454 + }
1455 +
1456 + return 0;
1457 +}
1458 +
1459 +static int path_in_sparse_checkout_1(const char *path,
1460 + struct index_state *istate,
1461 + int require_cone_mode)
1462 +{
1463 + const char *base;
1464 + int dtype = DT_REG;
1465 +
1466 + /*
1467 + * We default to accepting a path if there are no patterns or
1468 + * they are of the wrong type.
1469 + */
1470 + if (init_sparse_checkout_patterns(istate) ||
1471 + (require_cone_mode &&
1472 + !istate->sparse_checkout_patterns->use_cone_patterns))
1473 + return 1;
1474 +
1475 + base = strrchr(path, '/');
1476 + return path_matches_pattern_list(path, strlen(path), base ? base + 1 : path,
1477 + &dtype,
1478 + istate->sparse_checkout_patterns,
1479 + istate) > 0;
1480 +}
1481 +
1482 +int path_in_sparse_checkout(const char *path,
1483 + struct index_state *istate)
1484 +{
1485 + return path_in_sparse_checkout_1(path, istate, 0);
1486 +}
1487 +
1488 +int path_in_cone_mode_sparse_checkout(const char *path,
1489 + struct index_state *istate)
1490 +{
1491 + return path_in_sparse_checkout_1(path, istate, 1);
1492 +}
1493 +
1494 static struct path_pattern *last_matching_pattern_from_lists(
1495 struct dir_struct *dir, struct index_state *istate,
1496 const char *pathname, int pathlen,
dir.h
+8
@@ -394,6 +394,14 @@ enum pattern_match_result path_matches_pattern_list(const char *pathname,
394 const char *basename, int *dtype,
395 struct pattern_list *pl,
396 struct index_state *istate);
397 +
398 +int init_sparse_checkout_patterns(struct index_state *state);
399 +
400 +int path_in_sparse_checkout(const char *path,
401 + struct index_state *istate);
402 +int path_in_cone_mode_sparse_checkout(const char *path,
403 + struct index_state *istate);
404 +
405 struct dir_entry *dir_add_ignored(struct dir_struct *dir,
406 struct index_state *istate,
407 const char *pathname, int len);
sparse-index.c
+3 -11
@@ -33,19 +33,14 @@ static int convert_to_sparse_rec(struct index_state *istate,
33 {
34 int i, can_convert = 1;
35 int start_converted = num_converted;
36 - enum pattern_match_result match;
37 - int dtype = DT_UNKNOWN;
36 struct strbuf child_path = STRBUF_INIT;
39 - struct pattern_list *pl = istate->sparse_checkout_patterns;
37
38 /*
39 * Is the current path outside of the sparse cone?
40 * Then check if the region can be replaced by a sparse
41 * directory entry (everything is sparse and merged).
42 */
46 - match = path_matches_pattern_list(ct_path, ct_pathlen,
47 - NULL, &dtype, pl, istate);
48 - if (match != NOT_MATCHED)
43 + if (path_in_sparse_checkout(ct_path, istate))
44 can_convert = 0;
45
46 for (i = start; can_convert && i < end; i++) {
@@ -152,11 +147,8 @@ int convert_to_sparse(struct index_state *istate)
147 if (!istate->repo->settings.sparse_index)
148 return 0;
149
155 - if (!istate->sparse_checkout_patterns) {
156 - istate->sparse_checkout_patterns = xcalloc(1, sizeof(struct pattern_list));
157 - if (get_sparse_checkout_patterns(istate->sparse_checkout_patterns) < 0)
158 - return 0;
159 - }
150 + if (init_sparse_checkout_patterns(istate))
151 + return 0;
152
153 /*
154 * We need cone-mode patterns to use sparse-index. If a user edits