]> git.ipfire.org Git - thirdparty/git.git/blame - builtin/sparse-checkout.c
The sixth batch
[thirdparty/git.git] / builtin / sparse-checkout.c
CommitLineData
03eae9af 1#define USE_THE_REPOSITORY_VARIABLE
41f43b82
PS
2#define DISABLE_SIGN_COMPARE_WARNINGS
3
94c0956b
DS
4#include "builtin.h"
5#include "config.h"
6#include "dir.h"
32a8f510 7#include "environment.h"
f394e093 8#include "gettext.h"
87bed179 9#include "object-file.h"
dabab1d6 10#include "object-name.h"
94c0956b 11#include "parse-options.h"
1a99fe80 12#include "path.h"
94c0956b 13#include "pathspec.h"
94c0956b 14#include "strbuf.h"
af09ce24 15#include "string-list.h"
e091228e 16#include "lockfile.h"
e091228e 17#include "unpack-trees.h"
d585f0e7 18#include "quote.h"
e38da487 19#include "setup.h"
122ba1f7 20#include "sparse-index.h"
7316dc5f 21#include "worktree.h"
94c0956b 22
416adc87
DS
23static const char *empty_base = "";
24
94c0956b 25static char const * const builtin_sparse_checkout_usage[] = {
00408ade 26 N_("git sparse-checkout (init | list | set | add | reapply | disable | check-rules) [<options>]"),
94c0956b
DS
27 NULL
28};
29
94c0956b
DS
30static void write_patterns_to_file(FILE *fp, struct pattern_list *pl)
31{
32 int i;
33
34 for (i = 0; i < pl->nr; i++) {
35 struct path_pattern *p = pl->patterns[i];
36
37 if (p->flags & PATTERN_FLAG_NEGATIVE)
38 fprintf(fp, "!");
39
40 fprintf(fp, "%s", p->pattern);
41
42 if (p->flags & PATTERN_FLAG_MUSTBEDIR)
43 fprintf(fp, "/");
44
45 fprintf(fp, "\n");
46 }
47}
48
75d3bee1 49static char const * const builtin_sparse_checkout_list_usage[] = {
959d670d 50 "git sparse-checkout list",
75d3bee1
JK
51 NULL
52};
53
6f33d8e2
KN
54static int sparse_checkout_list(int argc, const char **argv, const char *prefix,
55 struct repository *repo UNUSED)
94c0956b 56{
75d3bee1
JK
57 static struct option builtin_sparse_checkout_list_options[] = {
58 OPT_END(),
59 };
94c0956b
DS
60 struct pattern_list pl;
61 char *sparse_filename;
62 int res;
63
24fc2cde 64 setup_work_tree();
45c5e470
EN
65 if (!core_apply_sparse_checkout)
66 die(_("this worktree is not sparse"));
67
ecd2d3ef 68 argc = parse_options(argc, argv, prefix,
75d3bee1
JK
69 builtin_sparse_checkout_list_options,
70 builtin_sparse_checkout_list_usage, 0);
71
94c0956b
DS
72 memset(&pl, 0, sizeof(pl));
73
de11951b
DS
74 pl.use_cone_patterns = core_sparse_checkout_cone;
75
94c0956b 76 sparse_filename = get_sparse_checkout_filename();
1679d60b 77 res = add_patterns_from_file_to_list(sparse_filename, "", 0, &pl, NULL, 0);
94c0956b
DS
78 free(sparse_filename);
79
80 if (res < 0) {
81 warning(_("this worktree is not sparse (sparse-checkout file may not exist)"));
82 return 0;
83 }
84
de11951b
DS
85 if (pl.use_cone_patterns) {
86 int i;
87 struct pattern_entry *pe;
88 struct hashmap_iter iter;
89 struct string_list sl = STRING_LIST_INIT_DUP;
90
91 hashmap_for_each_entry(&pl.recursive_hashmap, &iter, pe, ent) {
92 /* pe->pattern starts with "/", skip it */
93 string_list_insert(&sl, pe->pattern + 1);
94 }
95
96 string_list_sort(&sl);
97
e55682ea
DS
98 for (i = 0; i < sl.nr; i++) {
99 quote_c_style(sl.items[i].string, NULL, stdout, 0);
100 printf("\n");
101 }
a544b7da
JK
102
103 string_list_clear(&sl, 0);
521e04e6
JK
104 } else {
105 write_patterns_to_file(stdout, &pl);
de11951b
DS
106 }
107
94c0956b
DS
108 clear_pattern_list(&pl);
109
110 return 0;
111}
112
55dfcf95
DS
113static void clean_tracked_sparse_directories(struct repository *r)
114{
115 int i, was_full = 0;
116 struct strbuf path = STRBUF_INIT;
117 size_t pathlen;
118 struct string_list_item *item;
119 struct string_list sparse_dirs = STRING_LIST_INIT_DUP;
120
121 /*
122 * If we are not using cone mode patterns, then we cannot
123 * delete directories outside of the sparse cone.
124 */
125 if (!r || !r->index || !r->worktree)
126 return;
127 if (init_sparse_checkout_patterns(r->index) ||
128 !r->index->sparse_checkout_patterns->use_cone_patterns)
129 return;
130
131 /*
132 * Use the sparse index as a data structure to assist finding
133 * directories that are safe to delete. This conversion to a
134 * sparse index will not delete directories that contain
135 * conflicted entries or submodules.
136 */
9fadb373 137 if (r->index->sparse_index == INDEX_EXPANDED) {
55dfcf95
DS
138 /*
139 * If something, such as a merge conflict or other concern,
140 * prevents us from converting to a sparse index, then do
141 * not try deleting files.
142 */
143 if (convert_to_sparse(r->index, SPARSE_INDEX_MEMORY_ONLY))
144 return;
145 was_full = 1;
146 }
147
148 strbuf_addstr(&path, r->worktree);
149 strbuf_complete(&path, '/');
150 pathlen = path.len;
151
152 /*
153 * Collect directories that have gone out of scope but also
154 * exist on disk, so there is some work to be done. We need to
155 * store the entries in a list before exploring, since that might
156 * expand the sparse-index again.
157 */
158 for (i = 0; i < r->index->cache_nr; i++) {
159 struct cache_entry *ce = r->index->cache[i];
160
161 if (S_ISSPARSEDIR(ce->ce_mode) &&
162 repo_file_exists(r, ce->name))
163 string_list_append(&sparse_dirs, ce->name);
164 }
165
166 for_each_string_list_item(item, &sparse_dirs) {
167 struct dir_struct dir = DIR_INIT;
168 struct pathspec p = { 0 };
169 struct strvec s = STRVEC_INIT;
170
171 strbuf_setlen(&path, pathlen);
172 strbuf_addstr(&path, item->string);
173
174 dir.flags |= DIR_SHOW_IGNORED_TOO;
175
176 setup_standard_excludes(&dir);
177 strvec_push(&s, path.buf);
178
179 parse_pathspec(&p, PATHSPEC_GLOB, 0, NULL, s.v);
180 fill_directory(&dir, r->index, &p);
181
182 if (dir.nr) {
183 warning(_("directory '%s' contains untracked files,"
184 " but is not in the sparse-checkout cone"),
185 item->string);
186 } else if (remove_dir_recursively(&path, 0)) {
187 /*
188 * Removal is "best effort". If something blocks
189 * the deletion, then continue with a warning.
190 */
191 warning(_("failed to remove directory '%s'"),
192 item->string);
193 }
194
0f03f04c
EN
195 strvec_clear(&s);
196 clear_pathspec(&p);
55dfcf95
DS
197 dir_clear(&dir);
198 }
199
200 string_list_clear(&sparse_dirs, 0);
201 strbuf_release(&path);
202
203 if (was_full)
204 ensure_full_index(r->index);
205}
206
e091228e 207static int update_working_directory(struct pattern_list *pl)
bab3c359 208{
f56f31af 209 enum update_sparsity_result result;
e091228e
DS
210 struct unpack_trees_options o;
211 struct lock_file lock_file = LOCK_INIT;
e091228e 212 struct repository *r = the_repository;
a14d49ca 213 struct pattern_list *old_pl;
bab3c359 214
b5bfc08a
EN
215 /* If no branch has been checked out, there are no updates to make. */
216 if (is_index_unborn(r->index))
217 return UPDATE_SPARSITY_SUCCESS;
218
a14d49ca 219 old_pl = r->index->sparse_checkout_patterns;
836e25c5
DS
220 r->index->sparse_checkout_patterns = pl;
221
e091228e
DS
222 memset(&o, 0, sizeof(o));
223 o.verbose_update = isatty(2);
e091228e 224 o.update = 1;
e091228e
DS
225 o.head_idx = -1;
226 o.src_index = r->index;
227 o.dst_index = r->index;
228 o.skip_sparse_checkout = 0;
e091228e 229
e091228e
DS
230 setup_work_tree();
231
e091228e
DS
232 repo_hold_locked_index(r, &lock_file, LOCK_DIE_ON_ERROR);
233
4ee5d50f 234 setup_unpack_trees_porcelain(&o, "sparse-checkout");
1147c56f 235 result = update_sparsity(&o, pl);
4ee5d50f 236 clear_unpack_trees_porcelain(&o);
e091228e 237
f56f31af
EN
238 if (result == UPDATE_SPARSITY_WARNINGS)
239 /*
240 * We don't do any special handling of warnings from untracked
241 * files in the way or dirty entries that can't be removed.
242 */
243 result = UPDATE_SPARSITY_SUCCESS;
244 if (result == UPDATE_SPARSITY_SUCCESS)
e091228e 245 write_locked_index(r->index, &lock_file, COMMIT_LOCK);
f56f31af 246 else
e091228e 247 rollback_lock_file(&lock_file);
bab3c359 248
55dfcf95
DS
249 clean_tracked_sparse_directories(r);
250
a14d49ca
JK
251 if (r->index->sparse_checkout_patterns != pl) {
252 clear_pattern_list(r->index->sparse_checkout_patterns);
253 FREE_AND_NULL(r->index->sparse_checkout_patterns);
254 }
255 r->index->sparse_checkout_patterns = old_pl;
256
bab3c359
DS
257 return result;
258}
259
d585f0e7
DS
260static char *escaped_pattern(char *pattern)
261{
262 char *p = pattern;
263 struct strbuf final = STRBUF_INIT;
264
265 while (*p) {
e53ffe27 266 if (is_glob_special(*p))
d585f0e7
DS
267 strbuf_addch(&final, '\\');
268
269 strbuf_addch(&final, *p);
270 p++;
271 }
272
273 return strbuf_detach(&final, NULL);
274}
275
af09ce24
DS
276static void write_cone_to_file(FILE *fp, struct pattern_list *pl)
277{
278 int i;
279 struct pattern_entry *pe;
280 struct hashmap_iter iter;
281 struct string_list sl = STRING_LIST_INIT_DUP;
e9de487a 282 struct strbuf parent_pattern = STRBUF_INIT;
af09ce24 283
e9de487a
DS
284 hashmap_for_each_entry(&pl->parent_hashmap, &iter, pe, ent) {
285 if (hashmap_get_entry(&pl->recursive_hashmap, pe, ent, NULL))
286 continue;
287
288 if (!hashmap_contains_parent(&pl->recursive_hashmap,
289 pe->pattern,
290 &parent_pattern))
291 string_list_insert(&sl, pe->pattern);
292 }
af09ce24
DS
293
294 string_list_sort(&sl);
295 string_list_remove_duplicates(&sl, 0);
296
297 fprintf(fp, "/*\n!/*/\n");
298
299 for (i = 0; i < sl.nr; i++) {
d585f0e7 300 char *pattern = escaped_pattern(sl.items[i].string);
af09ce24
DS
301
302 if (strlen(pattern))
303 fprintf(fp, "%s/\n!%s/*/\n", pattern, pattern);
d585f0e7 304 free(pattern);
af09ce24
DS
305 }
306
307 string_list_clear(&sl, 0);
308
e9de487a
DS
309 hashmap_for_each_entry(&pl->recursive_hashmap, &iter, pe, ent) {
310 if (!hashmap_contains_parent(&pl->recursive_hashmap,
311 pe->pattern,
312 &parent_pattern))
313 string_list_insert(&sl, pe->pattern);
314 }
315
316 strbuf_release(&parent_pattern);
af09ce24
DS
317
318 string_list_sort(&sl);
319 string_list_remove_duplicates(&sl, 0);
320
321 for (i = 0; i < sl.nr; i++) {
d585f0e7 322 char *pattern = escaped_pattern(sl.items[i].string);
af09ce24 323 fprintf(fp, "%s/\n", pattern);
d585f0e7 324 free(pattern);
af09ce24 325 }
2181fe6e
JK
326
327 string_list_clear(&sl, 0);
af09ce24
DS
328}
329
330static int write_patterns_and_update(struct pattern_list *pl)
331{
332 char *sparse_filename;
333 FILE *fp;
fb10ca5b 334 struct lock_file lk = LOCK_INIT;
e091228e
DS
335 int result;
336
fb10ca5b 337 sparse_filename = get_sparse_checkout_filename();
3c754067 338
1a99fe80 339 if (safe_create_leading_directories(the_repository, sparse_filename))
3c754067
DS
340 die(_("failed to create directory for sparse-checkout file"));
341
a71c4782 342 hold_lock_file_for_update(&lk, sparse_filename, LOCK_DIE_ON_ERROR);
e091228e 343
fb10ca5b 344 result = update_working_directory(pl);
e091228e 345 if (result) {
fb10ca5b 346 rollback_lock_file(&lk);
e091228e 347 update_working_directory(NULL);
d39cc718 348 goto out;
e091228e 349 }
af09ce24 350
a71c4782
JK
351 fp = fdopen_lock_file(&lk, "w");
352 if (!fp)
353 die_errno(_("unable to fdopen %s"), get_lock_file_path(&lk));
af09ce24
DS
354
355 if (core_sparse_checkout_cone)
356 write_cone_to_file(fp, pl);
357 else
358 write_patterns_to_file(fp, pl);
359
19ace71d
JK
360 if (commit_lock_file(&lk))
361 die_errno(_("unable to write %s"), sparse_filename);
e091228e 362
d39cc718 363out:
e091228e 364 clear_pattern_list(pl);
19ace71d 365 free(sparse_filename);
d39cc718 366 return result;
af09ce24
DS
367}
368
bab3c359
DS
369enum sparse_checkout_mode {
370 MODE_NO_PATTERNS = 0,
371 MODE_ALL_PATTERNS = 1,
af09ce24 372 MODE_CONE_PATTERNS = 2,
bab3c359
DS
373};
374
375static int set_config(enum sparse_checkout_mode mode)
376{
7316dc5f
DS
377 /* Update to use worktree config, if not already. */
378 if (init_worktree_config(the_repository)) {
379 error(_("failed to initialize worktree config"));
bab3c359
DS
380 return 1;
381 }
382
7316dc5f
DS
383 if (repo_config_set_worktree_gently(the_repository,
384 "core.sparseCheckout",
385 mode ? "true" : "false") ||
386 repo_config_set_worktree_gently(the_repository,
387 "core.sparseCheckoutCone",
388 mode == MODE_CONE_PATTERNS ?
389 "true" : "false"))
390 return 1;
af09ce24 391
dcc5fd5f 392 if (mode == MODE_NO_PATTERNS)
7316dc5f 393 return set_sparse_index_config(the_repository, 0);
dcc5fd5f 394
bab3c359
DS
395 return 0;
396}
397
00408ade 398static enum sparse_checkout_mode update_cone_mode(int *cone_mode) {
be61fd11
EN
399 /* If not specified, use previous definition of cone mode */
400 if (*cone_mode == -1 && core_apply_sparse_checkout)
401 *cone_mode = core_sparse_checkout_cone;
402
403 /* Set cone/non-cone mode appropriately */
404 core_apply_sparse_checkout = 1;
2d95707a 405 if (*cone_mode == 1 || *cone_mode == -1) {
be61fd11 406 core_sparse_checkout_cone = 1;
00408ade 407 return MODE_CONE_PATTERNS;
be61fd11 408 }
00408ade
WS
409 core_sparse_checkout_cone = 0;
410 return MODE_ALL_PATTERNS;
411}
412
413static int update_modes(int *cone_mode, int *sparse_index)
414{
415 int mode, record_mode;
416
417 /* Determine if we need to record the mode; ensure sparse checkout on */
418 record_mode = (*cone_mode != -1) || !core_apply_sparse_checkout;
419
420 mode = update_cone_mode(cone_mode);
be61fd11
EN
421 if (record_mode && set_config(mode))
422 return 1;
423
424 /* Set sparse-index/non-sparse-index mode if specified */
425 if (*sparse_index >= 0) {
426 if (set_sparse_index_config(the_repository, *sparse_index) < 0)
427 die(_("failed to modify sparse-index config"));
428
429 /* force an index rewrite */
430 repo_read_index(the_repository);
431 the_repository->index->updated_workdir = 1;
2d443389
DS
432
433 if (!*sparse_index)
434 ensure_full_index(the_repository->index);
be61fd11
EN
435 }
436
437 return 0;
438}
439
af09ce24 440static char const * const builtin_sparse_checkout_init_usage[] = {
959d670d 441 "git sparse-checkout init [--cone] [--[no-]sparse-index]",
af09ce24
DS
442 NULL
443};
444
445static struct sparse_checkout_init_opts {
446 int cone_mode;
122ba1f7 447 int sparse_index;
af09ce24
DS
448} init_opts;
449
6f33d8e2
KN
450static int sparse_checkout_init(int argc, const char **argv, const char *prefix,
451 struct repository *repo UNUSED)
bab3c359
DS
452{
453 struct pattern_list pl;
454 char *sparse_filename;
bab3c359 455 int res;
d89f09c8 456 struct object_id oid;
bab3c359 457
af09ce24
DS
458 static struct option builtin_sparse_checkout_init_options[] = {
459 OPT_BOOL(0, "cone", &init_opts.cone_mode,
460 N_("initialize the sparse-checkout in cone mode")),
122ba1f7
DS
461 OPT_BOOL(0, "sparse-index", &init_opts.sparse_index,
462 N_("toggle the use of a sparse index")),
af09ce24
DS
463 OPT_END(),
464 };
465
24fc2cde 466 setup_work_tree();
cff4e913 467 repo_read_index(the_repository);
cff4e913 468
be61fd11 469 init_opts.cone_mode = -1;
122ba1f7
DS
470 init_opts.sparse_index = -1;
471
ecd2d3ef 472 argc = parse_options(argc, argv, prefix,
af09ce24
DS
473 builtin_sparse_checkout_init_options,
474 builtin_sparse_checkout_init_usage, 0);
475
be61fd11 476 if (update_modes(&init_opts.cone_mode, &init_opts.sparse_index))
bab3c359
DS
477 return 1;
478
479 memset(&pl, 0, sizeof(pl));
480
481 sparse_filename = get_sparse_checkout_filename();
1679d60b 482 res = add_patterns_from_file_to_list(sparse_filename, "", 0, &pl, NULL, 0);
bab3c359
DS
483
484 /* If we already have a sparse-checkout file, use it. */
485 if (res >= 0) {
486 free(sparse_filename);
db83b64c 487 clear_pattern_list(&pl);
416adc87 488 return update_working_directory(NULL);
bab3c359
DS
489 }
490
d850b7a5 491 if (repo_get_oid(the_repository, "HEAD", &oid)) {
416adc87 492 FILE *fp;
bab3c359 493
416adc87 494 /* assume we are in a fresh repo, but update the sparse-checkout file */
1a99fe80 495 if (safe_create_leading_directories(the_repository, sparse_filename))
7f44842a
JT
496 die(_("unable to create leading directories of %s"),
497 sparse_filename);
416adc87
DS
498 fp = xfopen(sparse_filename, "w");
499 if (!fp)
500 die(_("failed to open '%s'"), sparse_filename);
bab3c359 501
416adc87
DS
502 free(sparse_filename);
503 fprintf(fp, "/*\n!/*/\n");
504 fclose(fp);
d89f09c8
DS
505 return 0;
506 }
507
008f59d2
JK
508 free(sparse_filename);
509
4d7f95ed
JK
510 add_pattern("/*", empty_base, 0, &pl, 0);
511 add_pattern("!/*/", empty_base, 0, &pl, 0);
dcc5fd5f 512 pl.use_cone_patterns = init_opts.cone_mode;
416adc87
DS
513
514 return write_patterns_and_update(&pl);
bab3c359
DS
515}
516
af09ce24 517static void insert_recursive_pattern(struct pattern_list *pl, struct strbuf *path)
f6039a94 518{
af09ce24
DS
519 struct pattern_entry *e = xmalloc(sizeof(*e));
520 e->patternlen = path->len;
521 e->pattern = strbuf_detach(path, NULL);
74318423 522 hashmap_entry_init(&e->ent, fspathhash(e->pattern));
f6039a94 523
af09ce24 524 hashmap_add(&pl->recursive_hashmap, &e->ent);
f6039a94 525
af09ce24
DS
526 while (e->patternlen) {
527 char *slash = strrchr(e->pattern, '/');
528 char *oldpattern = e->pattern;
529 size_t newlen;
6d107751 530 struct pattern_entry *dup;
af09ce24 531
391c3a10 532 if (!slash || slash == e->pattern)
af09ce24
DS
533 break;
534
535 newlen = slash - e->pattern;
536 e = xmalloc(sizeof(struct pattern_entry));
537 e->patternlen = newlen;
538 e->pattern = xstrndup(oldpattern, newlen);
74318423 539 hashmap_entry_init(&e->ent, fspathhash(e->pattern));
af09ce24 540
6d107751
JK
541 dup = hashmap_get_entry(&pl->parent_hashmap, e, ent, NULL);
542 if (!dup) {
af09ce24 543 hashmap_add(&pl->parent_hashmap, &e->ent);
6d107751
JK
544 } else {
545 free(e->pattern);
546 free(e);
547 e = dup;
548 }
af09ce24
DS
549 }
550}
551
552static void strbuf_to_cone_pattern(struct strbuf *line, struct pattern_list *pl)
553{
554 strbuf_trim(line);
555
556 strbuf_trim_trailing_dir_sep(line);
557
ef076599
DS
558 if (strbuf_normalize_path(line))
559 die(_("could not normalize path %s"), line->buf);
560
af09ce24
DS
561 if (!line->len)
562 return;
563
564 if (line->buf[0] != '/')
a91cc7fa 565 strbuf_insertstr(line, 0, "/");
af09ce24
DS
566
567 insert_recursive_pattern(pl, line);
f6039a94
DS
568}
569
6fb705ab 570static void add_patterns_from_input(struct pattern_list *pl,
1530ff35 571 int argc, const char **argv,
00408ade 572 FILE *file)
f6039a94 573{
f6039a94 574 int i;
af09ce24 575 if (core_sparse_checkout_cone) {
7bffca95
DS
576 struct strbuf line = STRBUF_INIT;
577
6fb705ab
DS
578 hashmap_init(&pl->recursive_hashmap, pl_hashmap_cmp, NULL, 0);
579 hashmap_init(&pl->parent_hashmap, pl_hashmap_cmp, NULL, 0);
580 pl->use_cone_patterns = 1;
af09ce24 581
00408ade 582 if (file) {
bd64de42 583 struct strbuf unquoted = STRBUF_INIT;
00408ade 584 while (!strbuf_getline(&line, file)) {
bd64de42
DS
585 if (line.buf[0] == '"') {
586 strbuf_reset(&unquoted);
587 if (unquote_c_style(&unquoted, line.buf, NULL))
588 die(_("unable to unquote C-style string '%s'"),
589 line.buf);
590
591 strbuf_swap(&unquoted, &line);
592 }
593
6fb705ab 594 strbuf_to_cone_pattern(&line, pl);
bd64de42
DS
595 }
596
597 strbuf_release(&unquoted);
af09ce24
DS
598 } else {
599 for (i = 0; i < argc; i++) {
600 strbuf_setlen(&line, 0);
601 strbuf_addstr(&line, argv[i]);
6fb705ab 602 strbuf_to_cone_pattern(&line, pl);
af09ce24 603 }
7bffca95 604 }
d765fa03 605 strbuf_release(&line);
7bffca95 606 } else {
00408ade 607 if (file) {
af09ce24
DS
608 struct strbuf line = STRBUF_INIT;
609
c3324649
JK
610 while (!strbuf_getline(&line, file))
611 add_pattern(line.buf, empty_base, 0, pl, 0);
612
613 strbuf_release(&line);
af09ce24
DS
614 } else {
615 for (i = 0; i < argc; i++)
6fb705ab 616 add_pattern(argv[i], empty_base, 0, pl, 0);
af09ce24 617 }
7bffca95 618 }
6fb705ab
DS
619}
620
4bf0c06c
DS
621enum modify_type {
622 REPLACE,
2631dc87 623 ADD,
4bf0c06c
DS
624};
625
2631dc87 626static void add_patterns_cone_mode(int argc, const char **argv,
1530ff35
EN
627 struct pattern_list *pl,
628 int use_stdin)
2631dc87
DS
629{
630 struct strbuf buffer = STRBUF_INIT;
631 struct pattern_entry *pe;
632 struct hashmap_iter iter;
633 struct pattern_list existing;
634 char *sparse_filename = get_sparse_checkout_filename();
635
00408ade
WS
636 add_patterns_from_input(pl, argc, argv,
637 use_stdin ? stdin : NULL);
2631dc87
DS
638
639 memset(&existing, 0, sizeof(existing));
640 existing.use_cone_patterns = core_sparse_checkout_cone;
641
642 if (add_patterns_from_file_to_list(sparse_filename, "", 0,
1679d60b 643 &existing, NULL, 0))
2631dc87
DS
644 die(_("unable to load existing sparse-checkout patterns"));
645 free(sparse_filename);
646
a3eca584
DS
647 if (!existing.use_cone_patterns)
648 die(_("existing sparse-checkout patterns do not use cone mode"));
649
2631dc87
DS
650 hashmap_for_each_entry(&existing.recursive_hashmap, &iter, pe, ent) {
651 if (!hashmap_contains_parent(&pl->recursive_hashmap,
652 pe->pattern, &buffer) ||
653 !hashmap_contains_parent(&pl->parent_hashmap,
654 pe->pattern, &buffer)) {
655 strbuf_reset(&buffer);
656 strbuf_addstr(&buffer, pe->pattern);
657 insert_recursive_pattern(pl, &buffer);
658 }
659 }
660
661 clear_pattern_list(&existing);
662 strbuf_release(&buffer);
663}
664
665static void add_patterns_literal(int argc, const char **argv,
1530ff35
EN
666 struct pattern_list *pl,
667 int use_stdin)
2631dc87
DS
668{
669 char *sparse_filename = get_sparse_checkout_filename();
670 if (add_patterns_from_file_to_list(sparse_filename, "", 0,
1679d60b 671 pl, NULL, 0))
2631dc87
DS
672 die(_("unable to load existing sparse-checkout patterns"));
673 free(sparse_filename);
00408ade 674 add_patterns_from_input(pl, argc, argv, use_stdin ? stdin : NULL);
2631dc87
DS
675}
676
58e7568c 677static int modify_pattern_list(struct strvec *args, int use_stdin,
1530ff35 678 enum modify_type m)
6fb705ab 679{
6fb705ab
DS
680 int result;
681 int changed_config = 0;
836e25c5 682 struct pattern_list *pl = xcalloc(1, sizeof(*pl));
6fb705ab 683
2631dc87
DS
684 switch (m) {
685 case ADD:
686 if (core_sparse_checkout_cone)
58e7568c 687 add_patterns_cone_mode(args->nr, args->v, pl, use_stdin);
2631dc87 688 else
58e7568c 689 add_patterns_literal(args->nr, args->v, pl, use_stdin);
2631dc87
DS
690 break;
691
692 case REPLACE:
58e7568c 693 add_patterns_from_input(pl, args->nr, args->v,
00408ade 694 use_stdin ? stdin : NULL);
2631dc87
DS
695 break;
696 }
f6039a94
DS
697
698 if (!core_apply_sparse_checkout) {
699 set_config(MODE_ALL_PATTERNS);
700 core_apply_sparse_checkout = 1;
701 changed_config = 1;
702 }
703
836e25c5 704 result = write_patterns_and_update(pl);
f6039a94
DS
705
706 if (result && changed_config)
707 set_config(MODE_NO_PATTERNS);
708
836e25c5
DS
709 clear_pattern_list(pl);
710 free(pl);
f6039a94
DS
711 return result;
712}
713
58e7568c 714static void sanitize_paths(struct strvec *args,
4ce50436 715 const char *prefix, int skip_checks)
bb8b5e9a 716{
4ce50436
EN
717 int i;
718
58e7568c 719 if (!args->nr)
bb8b5e9a
EN
720 return;
721
722 if (prefix && *prefix && core_sparse_checkout_cone) {
723 /*
724 * The args are not pathspecs, so unfortunately we
725 * cannot imitate how cmd_add() uses parse_pathspec().
726 */
bb8b5e9a
EN
727 int prefix_len = strlen(prefix);
728
58e7568c
PS
729 for (i = 0; i < args->nr; i++) {
730 char *prefixed_path = prefix_path(prefix, prefix_len, args->v[i]);
731 strvec_replace(args, i, prefixed_path);
732 free(prefixed_path);
733 }
bb8b5e9a
EN
734 }
735
4ce50436
EN
736 if (skip_checks)
737 return;
738
bb8b5e9a
EN
739 if (prefix && *prefix && !core_sparse_checkout_cone)
740 die(_("please run from the toplevel directory in non-cone mode"));
741
8dd7c473 742 if (core_sparse_checkout_cone) {
58e7568c
PS
743 for (i = 0; i < args->nr; i++) {
744 if (args->v[i][0] == '/')
8dd7c473 745 die(_("specify directories rather than patterns (no leading slash)"));
58e7568c 746 if (args->v[i][0] == '!')
8dd7c473 747 die(_("specify directories rather than patterns. If your directory starts with a '!', pass --skip-checks"));
58e7568c 748 if (strpbrk(args->v[i], "*?[]"))
8dd7c473
EN
749 die(_("specify directories rather than patterns. If your directory really has any of '*?[]\\' in it, pass --skip-checks"));
750 }
751 }
752
58e7568c 753 for (i = 0; i < args->nr; i++) {
4ce50436
EN
754 struct cache_entry *ce;
755 struct index_state *index = the_repository->index;
58e7568c 756 int pos = index_name_pos(index, args->v[i], strlen(args->v[i]));
4ce50436
EN
757
758 if (pos < 0)
759 continue;
760 ce = index->cache[pos];
761 if (S_ISSPARSEDIR(ce->ce_mode))
762 continue;
763
764 if (core_sparse_checkout_cone)
58e7568c 765 die(_("'%s' is not a directory; to treat it as a directory anyway, rerun with --skip-checks"), args->v[i]);
4ce50436 766 else
58e7568c 767 warning(_("pass a leading slash before paths such as '%s' if you want a single file (see NON-CONE PROBLEMS in the git-sparse-checkout manual)."), args->v[i]);
4ce50436 768 }
bb8b5e9a
EN
769}
770
0b624e03 771static char const * const builtin_sparse_checkout_add_usage[] = {
4ce50436 772 N_("git sparse-checkout add [--skip-checks] (--stdin | <patterns>)"),
0b624e03
EN
773 NULL
774};
775
776static struct sparse_checkout_add_opts {
4ce50436 777 int skip_checks;
0b624e03
EN
778 int use_stdin;
779} add_opts;
780
6f33d8e2
KN
781static int sparse_checkout_add(int argc, const char **argv, const char *prefix,
782 struct repository *repo UNUSED)
0b624e03
EN
783{
784 static struct option builtin_sparse_checkout_add_options[] = {
4ce50436
EN
785 OPT_BOOL_F(0, "skip-checks", &add_opts.skip_checks,
786 N_("skip some sanity checks on the given paths that might give false positives"),
787 PARSE_OPT_NONEG),
0b624e03
EN
788 OPT_BOOL(0, "stdin", &add_opts.use_stdin,
789 N_("read patterns from standard in")),
790 OPT_END(),
791 };
58e7568c
PS
792 struct strvec patterns = STRVEC_INIT;
793 int ret;
0b624e03 794
24fc2cde 795 setup_work_tree();
45c5e470
EN
796 if (!core_apply_sparse_checkout)
797 die(_("no sparse-checkout to add to"));
798
0b624e03
EN
799 repo_read_index(the_repository);
800
801 argc = parse_options(argc, argv, prefix,
802 builtin_sparse_checkout_add_options,
f8ab66f9 803 builtin_sparse_checkout_add_usage, 0);
0b624e03 804
58e7568c
PS
805 for (int i = 0; i < argc; i++)
806 strvec_push(&patterns, argv[i]);
807 sanitize_paths(&patterns, prefix, add_opts.skip_checks);
808
809 ret = modify_pattern_list(&patterns, add_opts.use_stdin, ADD);
bb8b5e9a 810
58e7568c
PS
811 strvec_clear(&patterns);
812 return ret;
0b624e03
EN
813}
814
815static char const * const builtin_sparse_checkout_set_usage[] = {
4ce50436 816 N_("git sparse-checkout set [--[no-]cone] [--[no-]sparse-index] [--skip-checks] (--stdin | <patterns>)"),
0b624e03
EN
817 NULL
818};
819
820static struct sparse_checkout_set_opts {
f2e3a218
EN
821 int cone_mode;
822 int sparse_index;
4ce50436 823 int skip_checks;
0b624e03
EN
824 int use_stdin;
825} set_opts;
826
6f33d8e2
KN
827static int sparse_checkout_set(int argc, const char **argv, const char *prefix,
828 struct repository *repo UNUSED)
4bf0c06c 829{
f2e3a218
EN
830 int default_patterns_nr = 2;
831 const char *default_patterns[] = {"/*", "!/*/", NULL};
832
4bf0c06c 833 static struct option builtin_sparse_checkout_set_options[] = {
f2e3a218
EN
834 OPT_BOOL(0, "cone", &set_opts.cone_mode,
835 N_("initialize the sparse-checkout in cone mode")),
836 OPT_BOOL(0, "sparse-index", &set_opts.sparse_index,
837 N_("toggle the use of a sparse index")),
4ce50436
EN
838 OPT_BOOL_F(0, "skip-checks", &set_opts.skip_checks,
839 N_("skip some sanity checks on the given paths that might give false positives"),
840 PARSE_OPT_NONEG),
f85751a1
EN
841 OPT_BOOL_F(0, "stdin", &set_opts.use_stdin,
842 N_("read patterns from standard in"),
843 PARSE_OPT_NONEG),
4bf0c06c
DS
844 OPT_END(),
845 };
58e7568c
PS
846 struct strvec patterns = STRVEC_INIT;
847 int ret;
4bf0c06c 848
24fc2cde 849 setup_work_tree();
4bf0c06c 850 repo_read_index(the_repository);
4bf0c06c 851
f2e3a218
EN
852 set_opts.cone_mode = -1;
853 set_opts.sparse_index = -1;
854
4bf0c06c
DS
855 argc = parse_options(argc, argv, prefix,
856 builtin_sparse_checkout_set_options,
f8ab66f9 857 builtin_sparse_checkout_set_usage, 0);
4bf0c06c 858
f2e3a218
EN
859 if (update_modes(&set_opts.cone_mode, &set_opts.sparse_index))
860 return 1;
861
862 /*
863 * Cone mode automatically specifies the toplevel directory. For
864 * non-cone mode, if nothing is specified, manually select just the
865 * top-level directory (much as 'init' would do).
866 */
53ded839 867 if (!core_sparse_checkout_cone && !set_opts.use_stdin && argc == 0) {
58e7568c
PS
868 for (int i = 0; i < default_patterns_nr; i++)
869 strvec_push(&patterns, default_patterns[i]);
bb8b5e9a 870 } else {
58e7568c
PS
871 for (int i = 0; i < argc; i++)
872 strvec_push(&patterns, argv[i]);
873 sanitize_paths(&patterns, prefix, set_opts.skip_checks);
f2e3a218
EN
874 }
875
58e7568c
PS
876 ret = modify_pattern_list(&patterns, set_opts.use_stdin, REPLACE);
877
878 strvec_clear(&patterns);
879 return ret;
4bf0c06c
DS
880}
881
75d3bee1 882static char const * const builtin_sparse_checkout_reapply_usage[] = {
959d670d 883 "git sparse-checkout reapply [--[no-]cone] [--[no-]sparse-index]",
75d3bee1
JK
884 NULL
885};
886
4e256731
EN
887static struct sparse_checkout_reapply_opts {
888 int cone_mode;
889 int sparse_index;
890} reapply_opts;
891
1c3502b1 892static int sparse_checkout_reapply(int argc, const char **argv,
6f33d8e2
KN
893 const char *prefix,
894 struct repository *repo UNUSED)
5644ca28 895{
75d3bee1 896 static struct option builtin_sparse_checkout_reapply_options[] = {
4e256731
EN
897 OPT_BOOL(0, "cone", &reapply_opts.cone_mode,
898 N_("initialize the sparse-checkout in cone mode")),
899 OPT_BOOL(0, "sparse-index", &reapply_opts.sparse_index,
900 N_("toggle the use of a sparse index")),
75d3bee1
JK
901 OPT_END(),
902 };
903
24fc2cde 904 setup_work_tree();
45c5e470
EN
905 if (!core_apply_sparse_checkout)
906 die(_("must be in a sparse-checkout to reapply sparsity patterns"));
907
f748012e
EN
908 reapply_opts.cone_mode = -1;
909 reapply_opts.sparse_index = -1;
910
ecd2d3ef 911 argc = parse_options(argc, argv, prefix,
75d3bee1
JK
912 builtin_sparse_checkout_reapply_options,
913 builtin_sparse_checkout_reapply_usage, 0);
914
5644ca28 915 repo_read_index(the_repository);
4e256731 916
4e256731
EN
917 if (update_modes(&reapply_opts.cone_mode, &reapply_opts.sparse_index))
918 return 1;
919
5644ca28
EN
920 return update_working_directory(NULL);
921}
922
75d3bee1 923static char const * const builtin_sparse_checkout_disable_usage[] = {
959d670d 924 "git sparse-checkout disable",
75d3bee1
JK
925 NULL
926};
927
1c3502b1 928static int sparse_checkout_disable(int argc, const char **argv,
6f33d8e2
KN
929 const char *prefix,
930 struct repository *repo UNUSED)
72918c1a 931{
75d3bee1
JK
932 static struct option builtin_sparse_checkout_disable_options[] = {
933 OPT_END(),
934 };
99dfa6f9 935 struct pattern_list pl;
72918c1a 936
45c5e470
EN
937 /*
938 * We do not exit early if !core_apply_sparse_checkout; due to the
939 * ability for users to manually muck things up between
940 * direct editing of .git/info/sparse-checkout
941 * running read-tree -m u HEAD or update-index --skip-worktree
942 * direct toggling of config options
943 * users might end up with an index with SKIP_WORKTREE bit set on
944 * some files and not know how to undo it. So, here we just
945 * forcibly return to a dense checkout regardless of initial state.
946 */
947
24fc2cde 948 setup_work_tree();
ecd2d3ef 949 argc = parse_options(argc, argv, prefix,
75d3bee1
JK
950 builtin_sparse_checkout_disable_options,
951 builtin_sparse_checkout_disable_usage, 0);
952
537e516a
DS
953 /*
954 * Disable the advice message for expanding a sparse index, as we
955 * are expecting to do that when disabling sparse-checkout.
956 */
957 give_advice_on_expansion = 0;
cff4e913 958 repo_read_index(the_repository);
cff4e913 959
99dfa6f9
DS
960 memset(&pl, 0, sizeof(pl));
961 hashmap_init(&pl.recursive_hashmap, pl_hashmap_cmp, NULL, 0);
962 hashmap_init(&pl.parent_hashmap, pl_hashmap_cmp, NULL, 0);
963 pl.use_cone_patterns = 0;
964 core_apply_sparse_checkout = 1;
72918c1a 965
4d7f95ed 966 add_pattern("/*", empty_base, 0, &pl, 0);
72918c1a 967
dcc5fd5f
DS
968 prepare_repo_settings(the_repository);
969 the_repository->settings.sparse_index = 0;
970
99dfa6f9 971 if (update_working_directory(&pl))
72918c1a
DS
972 die(_("error while refreshing working directory"));
973
99dfa6f9 974 clear_pattern_list(&pl);
72918c1a
DS
975 return set_config(MODE_NO_PATTERNS);
976}
977
00408ade
WS
978static char const * const builtin_sparse_checkout_check_rules_usage[] = {
979 N_("git sparse-checkout check-rules [-z] [--skip-checks]"
980 "[--[no-]cone] [--rules-file <file>]"),
981 NULL
982};
983
984static struct sparse_checkout_check_rules_opts {
985 int cone_mode;
986 int null_termination;
987 char *rules_file;
988} check_rules_opts;
989
990static int check_rules(struct pattern_list *pl, int null_terminated) {
991 struct strbuf line = STRBUF_INIT;
992 struct strbuf unquoted = STRBUF_INIT;
993 char *path;
994 int line_terminator = null_terminated ? 0 : '\n';
995 strbuf_getline_fn getline_fn = null_terminated ? strbuf_getline_nul
996 : strbuf_getline;
997 the_repository->index->sparse_checkout_patterns = pl;
998 while (!getline_fn(&line, stdin)) {
999 path = line.buf;
1000 if (!null_terminated && line.buf[0] == '"') {
1001 strbuf_reset(&unquoted);
1002 if (unquote_c_style(&unquoted, line.buf, NULL))
1003 die(_("unable to unquote C-style string '%s'"),
1004 line.buf);
1005
1006 path = unquoted.buf;
1007 }
1008
1009 if (path_in_sparse_checkout(path, the_repository->index))
1010 write_name_quoted(path, stdout, line_terminator);
1011 }
1012 strbuf_release(&line);
1013 strbuf_release(&unquoted);
1014
1015 return 0;
1016}
1017
6f33d8e2
KN
1018static int sparse_checkout_check_rules(int argc, const char **argv, const char *prefix,
1019 struct repository *repo UNUSED)
00408ade
WS
1020{
1021 static struct option builtin_sparse_checkout_check_rules_options[] = {
1022 OPT_BOOL('z', NULL, &check_rules_opts.null_termination,
1023 N_("terminate input and output files by a NUL character")),
1024 OPT_BOOL(0, "cone", &check_rules_opts.cone_mode,
1025 N_("when used with --rules-file interpret patterns as cone mode patterns")),
1026 OPT_FILENAME(0, "rules-file", &check_rules_opts.rules_file,
1027 N_("use patterns in <file> instead of the current ones.")),
1028 OPT_END(),
1029 };
1030
1031 FILE *fp;
1032 int ret;
1033 struct pattern_list pl = {0};
1034 char *sparse_filename;
1035 check_rules_opts.cone_mode = -1;
1036
1037 argc = parse_options(argc, argv, prefix,
1038 builtin_sparse_checkout_check_rules_options,
f8ab66f9 1039 builtin_sparse_checkout_check_rules_usage, 0);
00408ade
WS
1040
1041 if (check_rules_opts.rules_file && check_rules_opts.cone_mode < 0)
1042 check_rules_opts.cone_mode = 1;
1043
1044 update_cone_mode(&check_rules_opts.cone_mode);
1045 pl.use_cone_patterns = core_sparse_checkout_cone;
1046 if (check_rules_opts.rules_file) {
1047 fp = xfopen(check_rules_opts.rules_file, "r");
1048 add_patterns_from_input(&pl, argc, argv, fp);
1049 fclose(fp);
1050 } else {
1051 sparse_filename = get_sparse_checkout_filename();
1052 if (add_patterns_from_file_to_list(sparse_filename, "", 0, &pl,
1053 NULL, 0))
1054 die(_("unable to load existing sparse-checkout patterns"));
1055 free(sparse_filename);
1056 }
1057
1058 ret = check_rules(&pl, check_rules_opts.null_termination);
1059 clear_pattern_list(&pl);
14da2623 1060 free(check_rules_opts.rules_file);
00408ade
WS
1061 return ret;
1062}
1063
9b1cb507
JC
1064int cmd_sparse_checkout(int argc,
1065 const char **argv,
1066 const char *prefix,
6f33d8e2 1067 struct repository *repo)
94c0956b 1068{
1c3502b1
SG
1069 parse_opt_subcommand_fn *fn = NULL;
1070 struct option builtin_sparse_checkout_options[] = {
1071 OPT_SUBCOMMAND("list", &fn, sparse_checkout_list),
1072 OPT_SUBCOMMAND("init", &fn, sparse_checkout_init),
1073 OPT_SUBCOMMAND("set", &fn, sparse_checkout_set),
1074 OPT_SUBCOMMAND("add", &fn, sparse_checkout_add),
1075 OPT_SUBCOMMAND("reapply", &fn, sparse_checkout_reapply),
1076 OPT_SUBCOMMAND("disable", &fn, sparse_checkout_disable),
00408ade 1077 OPT_SUBCOMMAND("check-rules", &fn, sparse_checkout_check_rules),
94c0956b
DS
1078 OPT_END(),
1079 };
1080
94c0956b
DS
1081 argc = parse_options(argc, argv, prefix,
1082 builtin_sparse_checkout_options,
1c3502b1 1083 builtin_sparse_checkout_usage, 0);
94c0956b
DS
1084
1085 git_config(git_default_config, NULL);
1086
598b1e7d
DS
1087 prepare_repo_settings(the_repository);
1088 the_repository->settings.command_requires_full_index = 0;
1089
6f33d8e2 1090 return fn(argc, argv, prefix, repo);
94c0956b 1091}