summaryrefslogtreecommitdiff
path: root/builtin/sparse-checkout.c
diff options
context:
space:
mode:
Diffstat (limited to 'builtin/sparse-checkout.c')
-rw-r--r--builtin/sparse-checkout.c159
1 files changed, 96 insertions, 63 deletions
diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c
index 5c8ffb1f75..698d93a9ec 100644
--- a/builtin/sparse-checkout.c
+++ b/builtin/sparse-checkout.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "dir.h"
@@ -7,15 +8,10 @@
#include "object-name.h"
#include "parse-options.h"
#include "pathspec.h"
-#include "repository.h"
-#include "run-command.h"
#include "strbuf.h"
#include "string-list.h"
-#include "cache-tree.h"
#include "lockfile.h"
-#include "resolve-undo.h"
#include "unpack-trees.h"
-#include "wt-status.h"
#include "quote.h"
#include "setup.h"
#include "sparse-index.h"
@@ -100,10 +96,11 @@ static int sparse_checkout_list(int argc, const char **argv, const char *prefix)
printf("\n");
}
- return 0;
+ string_list_clear(&sl, 0);
+ } else {
+ write_patterns_to_file(stdout, &pl);
}
- write_patterns_to_file(stdout, &pl);
clear_pattern_list(&pl);
return 0;
@@ -209,11 +206,13 @@ static int update_working_directory(struct pattern_list *pl)
struct unpack_trees_options o;
struct lock_file lock_file = LOCK_INIT;
struct repository *r = the_repository;
+ struct pattern_list *old_pl;
/* If no branch has been checked out, there are no updates to make. */
if (is_index_unborn(r->index))
return UPDATE_SPARSITY_SUCCESS;
+ old_pl = r->index->sparse_checkout_patterns;
r->index->sparse_checkout_patterns = pl;
memset(&o, 0, sizeof(o));
@@ -245,7 +244,12 @@ static int update_working_directory(struct pattern_list *pl)
clean_tracked_sparse_directories(r);
- r->index->sparse_checkout_patterns = NULL;
+ if (r->index->sparse_checkout_patterns != pl) {
+ clear_pattern_list(r->index->sparse_checkout_patterns);
+ FREE_AND_NULL(r->index->sparse_checkout_patterns);
+ }
+ r->index->sparse_checkout_patterns = old_pl;
+
return result;
}
@@ -315,13 +319,14 @@ static void write_cone_to_file(FILE *fp, struct pattern_list *pl)
fprintf(fp, "%s/\n", pattern);
free(pattern);
}
+
+ string_list_clear(&sl, 0);
}
static int write_patterns_and_update(struct pattern_list *pl)
{
char *sparse_filename;
FILE *fp;
- int fd;
struct lock_file lk = LOCK_INIT;
int result;
@@ -330,31 +335,31 @@ static int write_patterns_and_update(struct pattern_list *pl)
if (safe_create_leading_directories(sparse_filename))
die(_("failed to create directory for sparse-checkout file"));
- fd = hold_lock_file_for_update(&lk, sparse_filename,
- LOCK_DIE_ON_ERROR);
- free(sparse_filename);
+ hold_lock_file_for_update(&lk, sparse_filename, LOCK_DIE_ON_ERROR);
result = update_working_directory(pl);
if (result) {
rollback_lock_file(&lk);
- clear_pattern_list(pl);
update_working_directory(NULL);
- return result;
+ goto out;
}
- fp = xfdopen(fd, "w");
+ fp = fdopen_lock_file(&lk, "w");
+ if (!fp)
+ die_errno(_("unable to fdopen %s"), get_lock_file_path(&lk));
if (core_sparse_checkout_cone)
write_cone_to_file(fp, pl);
else
write_patterns_to_file(fp, pl);
- fflush(fp);
- commit_lock_file(&lk);
+ if (commit_lock_file(&lk))
+ die_errno(_("unable to write %s"), sparse_filename);
+out:
clear_pattern_list(pl);
-
- return 0;
+ free(sparse_filename);
+ return result;
}
enum sparse_checkout_mode {
@@ -444,7 +449,6 @@ static int sparse_checkout_init(int argc, const char **argv, const char *prefix)
char *sparse_filename;
int res;
struct object_id oid;
- struct strbuf pattern = STRBUF_INIT;
static struct option builtin_sparse_checkout_init_options[] = {
OPT_BOOL(0, "cone", &init_opts.cone_mode,
@@ -475,6 +479,7 @@ static int sparse_checkout_init(int argc, const char **argv, const char *prefix)
/* If we already have a sparse-checkout file, use it. */
if (res >= 0) {
free(sparse_filename);
+ clear_pattern_list(&pl);
return update_working_directory(NULL);
}
@@ -495,10 +500,10 @@ static int sparse_checkout_init(int argc, const char **argv, const char *prefix)
return 0;
}
- strbuf_addstr(&pattern, "/*");
- add_pattern(strbuf_detach(&pattern, NULL), empty_base, 0, &pl, 0);
- strbuf_addstr(&pattern, "!/*/");
- add_pattern(strbuf_detach(&pattern, NULL), empty_base, 0, &pl, 0);
+ free(sparse_filename);
+
+ add_pattern("/*", empty_base, 0, &pl, 0);
+ add_pattern("!/*/", empty_base, 0, &pl, 0);
pl.use_cone_patterns = init_opts.cone_mode;
return write_patterns_and_update(&pl);
@@ -517,6 +522,7 @@ static void insert_recursive_pattern(struct pattern_list *pl, struct strbuf *pat
char *slash = strrchr(e->pattern, '/');
char *oldpattern = e->pattern;
size_t newlen;
+ struct pattern_entry *dup;
if (!slash || slash == e->pattern)
break;
@@ -527,8 +533,14 @@ static void insert_recursive_pattern(struct pattern_list *pl, struct strbuf *pat
e->pattern = xstrndup(oldpattern, newlen);
hashmap_entry_init(&e->ent, fspathhash(e->pattern));
- if (!hashmap_get_entry(&pl->parent_hashmap, e, ent, NULL))
+ dup = hashmap_get_entry(&pl->parent_hashmap, e, ent, NULL);
+ if (!dup) {
hashmap_add(&pl->parent_hashmap, &e->ent);
+ } else {
+ free(e->pattern);
+ free(e);
+ e = dup;
+ }
}
}
@@ -585,15 +597,15 @@ static void add_patterns_from_input(struct pattern_list *pl,
strbuf_to_cone_pattern(&line, pl);
}
}
+ strbuf_release(&line);
} else {
if (file) {
struct strbuf line = STRBUF_INIT;
- while (!strbuf_getline(&line, file)) {
- size_t len;
- char *buf = strbuf_detach(&line, &len);
- add_pattern(buf, empty_base, 0, pl, 0);
- }
+ while (!strbuf_getline(&line, file))
+ add_pattern(line.buf, empty_base, 0, pl, 0);
+
+ strbuf_release(&line);
} else {
for (i = 0; i < argc; i++)
add_pattern(argv[i], empty_base, 0, pl, 0);
@@ -657,7 +669,7 @@ static void add_patterns_literal(int argc, const char **argv,
add_patterns_from_input(pl, argc, argv, use_stdin ? stdin : NULL);
}
-static int modify_pattern_list(int argc, const char **argv, int use_stdin,
+static int modify_pattern_list(struct strvec *args, int use_stdin,
enum modify_type m)
{
int result;
@@ -667,13 +679,13 @@ static int modify_pattern_list(int argc, const char **argv, int use_stdin,
switch (m) {
case ADD:
if (core_sparse_checkout_cone)
- add_patterns_cone_mode(argc, argv, pl, use_stdin);
+ add_patterns_cone_mode(args->nr, args->v, pl, use_stdin);
else
- add_patterns_literal(argc, argv, pl, use_stdin);
+ add_patterns_literal(args->nr, args->v, pl, use_stdin);
break;
case REPLACE:
- add_patterns_from_input(pl, argc, argv,
+ add_patterns_from_input(pl, args->nr, args->v,
use_stdin ? stdin : NULL);
break;
}
@@ -694,12 +706,12 @@ static int modify_pattern_list(int argc, const char **argv, int use_stdin,
return result;
}
-static void sanitize_paths(int argc, const char **argv,
+static void sanitize_paths(struct strvec *args,
const char *prefix, int skip_checks)
{
int i;
- if (!argc)
+ if (!args->nr)
return;
if (prefix && *prefix && core_sparse_checkout_cone) {
@@ -709,8 +721,11 @@ static void sanitize_paths(int argc, const char **argv,
*/
int prefix_len = strlen(prefix);
- for (i = 0; i < argc; i++)
- argv[i] = prefix_path(prefix, prefix_len, argv[i]);
+ for (i = 0; i < args->nr; i++) {
+ char *prefixed_path = prefix_path(prefix, prefix_len, args->v[i]);
+ strvec_replace(args, i, prefixed_path);
+ free(prefixed_path);
+ }
}
if (skip_checks)
@@ -720,20 +735,20 @@ static void sanitize_paths(int argc, const char **argv,
die(_("please run from the toplevel directory in non-cone mode"));
if (core_sparse_checkout_cone) {
- for (i = 0; i < argc; i++) {
- if (argv[i][0] == '/')
+ for (i = 0; i < args->nr; i++) {
+ if (args->v[i][0] == '/')
die(_("specify directories rather than patterns (no leading slash)"));
- if (argv[i][0] == '!')
+ if (args->v[i][0] == '!')
die(_("specify directories rather than patterns. If your directory starts with a '!', pass --skip-checks"));
- if (strpbrk(argv[i], "*?[]"))
+ if (strpbrk(args->v[i], "*?[]"))
die(_("specify directories rather than patterns. If your directory really has any of '*?[]\\' in it, pass --skip-checks"));
}
}
- for (i = 0; i < argc; i++) {
+ for (i = 0; i < args->nr; i++) {
struct cache_entry *ce;
struct index_state *index = the_repository->index;
- int pos = index_name_pos(index, argv[i], strlen(argv[i]));
+ int pos = index_name_pos(index, args->v[i], strlen(args->v[i]));
if (pos < 0)
continue;
@@ -742,9 +757,9 @@ static void sanitize_paths(int argc, const char **argv,
continue;
if (core_sparse_checkout_cone)
- die(_("'%s' is not a directory; to treat it as a directory anyway, rerun with --skip-checks"), argv[i]);
+ die(_("'%s' is not a directory; to treat it as a directory anyway, rerun with --skip-checks"), args->v[i]);
else
- 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)."), argv[i]);
+ 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]);
}
}
@@ -768,6 +783,8 @@ static int sparse_checkout_add(int argc, const char **argv, const char *prefix)
N_("read patterns from standard in")),
OPT_END(),
};
+ struct strvec patterns = STRVEC_INIT;
+ int ret;
setup_work_tree();
if (!core_apply_sparse_checkout)
@@ -777,12 +794,16 @@ static int sparse_checkout_add(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix,
builtin_sparse_checkout_add_options,
- builtin_sparse_checkout_add_usage,
- PARSE_OPT_KEEP_UNKNOWN_OPT);
+ builtin_sparse_checkout_add_usage, 0);
+
+ for (int i = 0; i < argc; i++)
+ strvec_push(&patterns, argv[i]);
+ sanitize_paths(&patterns, prefix, add_opts.skip_checks);
- sanitize_paths(argc, argv, prefix, add_opts.skip_checks);
+ ret = modify_pattern_list(&patterns, add_opts.use_stdin, ADD);
- return modify_pattern_list(argc, argv, add_opts.use_stdin, ADD);
+ strvec_clear(&patterns);
+ return ret;
}
static char const * const builtin_sparse_checkout_set_usage[] = {
@@ -815,6 +836,8 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix)
PARSE_OPT_NONEG),
OPT_END(),
};
+ struct strvec patterns = STRVEC_INIT;
+ int ret;
setup_work_tree();
repo_read_index(the_repository);
@@ -824,8 +847,7 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix,
builtin_sparse_checkout_set_options,
- builtin_sparse_checkout_set_usage,
- PARSE_OPT_KEEP_UNKNOWN_OPT);
+ builtin_sparse_checkout_set_usage, 0);
if (update_modes(&set_opts.cone_mode, &set_opts.sparse_index))
return 1;
@@ -835,14 +857,19 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix)
* non-cone mode, if nothing is specified, manually select just the
* top-level directory (much as 'init' would do).
*/
- if (!core_sparse_checkout_cone && argc == 0) {
- argv = default_patterns;
- argc = default_patterns_nr;
+ if (!core_sparse_checkout_cone && !set_opts.use_stdin && argc == 0) {
+ for (int i = 0; i < default_patterns_nr; i++)
+ strvec_push(&patterns, default_patterns[i]);
} else {
- sanitize_paths(argc, argv, prefix, set_opts.skip_checks);
+ for (int i = 0; i < argc; i++)
+ strvec_push(&patterns, argv[i]);
+ sanitize_paths(&patterns, prefix, set_opts.skip_checks);
}
- return modify_pattern_list(argc, argv, set_opts.use_stdin, REPLACE);
+ ret = modify_pattern_list(&patterns, set_opts.use_stdin, REPLACE);
+
+ strvec_clear(&patterns);
+ return ret;
}
static char const * const builtin_sparse_checkout_reapply_usage[] = {
@@ -897,7 +924,6 @@ static int sparse_checkout_disable(int argc, const char **argv,
OPT_END(),
};
struct pattern_list pl;
- struct strbuf match_all = STRBUF_INIT;
/*
* We do not exit early if !core_apply_sparse_checkout; due to the
@@ -915,6 +941,11 @@ static int sparse_checkout_disable(int argc, const char **argv,
builtin_sparse_checkout_disable_options,
builtin_sparse_checkout_disable_usage, 0);
+ /*
+ * Disable the advice message for expanding a sparse index, as we
+ * are expecting to do that when disabling sparse-checkout.
+ */
+ give_advice_on_expansion = 0;
repo_read_index(the_repository);
memset(&pl, 0, sizeof(pl));
@@ -923,8 +954,7 @@ static int sparse_checkout_disable(int argc, const char **argv,
pl.use_cone_patterns = 0;
core_apply_sparse_checkout = 1;
- strbuf_addstr(&match_all, "/*");
- add_pattern(strbuf_detach(&match_all, NULL), empty_base, 0, &pl, 0);
+ add_pattern("/*", empty_base, 0, &pl, 0);
prepare_repo_settings(the_repository);
the_repository->settings.sparse_index = 0;
@@ -996,8 +1026,7 @@ static int sparse_checkout_check_rules(int argc, const char **argv, const char *
argc = parse_options(argc, argv, prefix,
builtin_sparse_checkout_check_rules_options,
- builtin_sparse_checkout_check_rules_usage,
- PARSE_OPT_KEEP_UNKNOWN_OPT);
+ builtin_sparse_checkout_check_rules_usage, 0);
if (check_rules_opts.rules_file && check_rules_opts.cone_mode < 0)
check_rules_opts.cone_mode = 1;
@@ -1018,10 +1047,14 @@ static int sparse_checkout_check_rules(int argc, const char **argv, const char *
ret = check_rules(&pl, check_rules_opts.null_termination);
clear_pattern_list(&pl);
+ free(check_rules_opts.rules_file);
return ret;
}
-int cmd_sparse_checkout(int argc, const char **argv, const char *prefix)
+int cmd_sparse_checkout(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo UNUSED)
{
parse_opt_subcommand_fn *fn = NULL;
struct option builtin_sparse_checkout_options[] = {