@@ -985,6 +985,7 @@ LIB_OBJS += sha1-name.o
LIB_OBJS += shallow.o
LIB_OBJS += sideband.o
LIB_OBJS += sigchain.o
+LIB_OBJS += sparse-checkout.o
LIB_OBJS += split-index.o
LIB_OBJS += stable-qsort.o
LIB_OBJS += strbuf.o
@@ -9,11 +9,11 @@
#include "string-list.h"
#include "cache.h"
#include "cache-tree.h"
-#include "lockfile.h"
#include "resolve-undo.h"
#include "unpack-trees.h"
#include "wt-status.h"
#include "quote.h"
+#include "sparse-checkout.h"
static const char *empty_base = "";
@@ -22,30 +22,6 @@ static char const * const builtin_sparse_checkout_usage[] = {
NULL
};
-static char *get_sparse_checkout_filename(void)
-{
- return git_pathdup("info/sparse-checkout");
-}
-
-static void write_patterns_to_file(FILE *fp, struct pattern_list *pl)
-{
- int i;
-
- for (i = 0; i < pl->nr; i++) {
- struct path_pattern *p = pl->patterns[i];
-
- if (p->flags & PATTERN_FLAG_NEGATIVE)
- fprintf(fp, "!");
-
- fprintf(fp, "%s", p->pattern);
-
- if (p->flags & PATTERN_FLAG_MUSTBEDIR)
- fprintf(fp, "/");
-
- fprintf(fp, "\n");
- }
-}
-
static int sparse_checkout_list(int argc, const char **argv)
{
struct pattern_list pl;
@@ -92,153 +68,6 @@ static int sparse_checkout_list(int argc, const char **argv)
return 0;
}
-static int update_working_directory(struct pattern_list *pl)
-{
- enum update_sparsity_result result;
- struct unpack_trees_options o;
- struct lock_file lock_file = LOCK_INIT;
- struct repository *r = the_repository;
-
- memset(&o, 0, sizeof(o));
- o.verbose_update = isatty(2);
- o.update = 1;
- o.head_idx = -1;
- o.src_index = r->index;
- o.dst_index = r->index;
- o.skip_sparse_checkout = 0;
- o.pl = pl;
-
- setup_work_tree();
-
- repo_hold_locked_index(r, &lock_file, LOCK_DIE_ON_ERROR);
-
- setup_unpack_trees_porcelain(&o, "sparse-checkout");
- result = update_sparsity(&o);
- clear_unpack_trees_porcelain(&o);
-
- if (result == UPDATE_SPARSITY_WARNINGS)
- /*
- * We don't do any special handling of warnings from untracked
- * files in the way or dirty entries that can't be removed.
- */
- result = UPDATE_SPARSITY_SUCCESS;
- if (result == UPDATE_SPARSITY_SUCCESS)
- write_locked_index(r->index, &lock_file, COMMIT_LOCK);
- else
- rollback_lock_file(&lock_file);
-
- return result;
-}
-
-static char *escaped_pattern(char *pattern)
-{
- char *p = pattern;
- struct strbuf final = STRBUF_INIT;
-
- while (*p) {
- if (is_glob_special(*p))
- strbuf_addch(&final, '\\');
-
- strbuf_addch(&final, *p);
- p++;
- }
-
- return strbuf_detach(&final, NULL);
-}
-
-static void write_cone_to_file(FILE *fp, struct pattern_list *pl)
-{
- int i;
- struct pattern_entry *pe;
- struct hashmap_iter iter;
- struct string_list sl = STRING_LIST_INIT_DUP;
- struct strbuf parent_pattern = STRBUF_INIT;
-
- hashmap_for_each_entry(&pl->parent_hashmap, &iter, pe, ent) {
- if (hashmap_get_entry(&pl->recursive_hashmap, pe, ent, NULL))
- continue;
-
- if (!hashmap_contains_parent(&pl->recursive_hashmap,
- pe->pattern,
- &parent_pattern))
- string_list_insert(&sl, pe->pattern);
- }
-
- string_list_sort(&sl);
- string_list_remove_duplicates(&sl, 0);
-
- fprintf(fp, "/*\n!/*/\n");
-
- for (i = 0; i < sl.nr; i++) {
- char *pattern = escaped_pattern(sl.items[i].string);
-
- if (strlen(pattern))
- fprintf(fp, "%s/\n!%s/*/\n", pattern, pattern);
- free(pattern);
- }
-
- string_list_clear(&sl, 0);
-
- hashmap_for_each_entry(&pl->recursive_hashmap, &iter, pe, ent) {
- if (!hashmap_contains_parent(&pl->recursive_hashmap,
- pe->pattern,
- &parent_pattern))
- string_list_insert(&sl, pe->pattern);
- }
-
- strbuf_release(&parent_pattern);
-
- string_list_sort(&sl);
- string_list_remove_duplicates(&sl, 0);
-
- for (i = 0; i < sl.nr; i++) {
- char *pattern = escaped_pattern(sl.items[i].string);
- fprintf(fp, "%s/\n", pattern);
- free(pattern);
- }
-}
-
-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;
-
- sparse_filename = get_sparse_checkout_filename();
-
- 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);
-
- result = update_working_directory(pl);
- if (result) {
- rollback_lock_file(&lk);
- free(sparse_filename);
- clear_pattern_list(pl);
- update_working_directory(NULL);
- return result;
- }
-
- fp = xfdopen(fd, "w");
-
- if (core_sparse_checkout_cone)
- write_cone_to_file(fp, pl);
- else
- write_patterns_to_file(fp, pl);
-
- fflush(fp);
- commit_lock_file(&lk);
-
- free(sparse_filename);
- clear_pattern_list(pl);
-
- return 0;
-}
-
enum sparse_checkout_mode {
MODE_NO_PATTERNS = 0,
MODE_ALL_PATTERNS = 1,
@@ -339,58 +168,6 @@ static int sparse_checkout_init(int argc, const char **argv)
return write_patterns_and_update(&pl);
}
-static void insert_recursive_pattern(struct pattern_list *pl, struct strbuf *path)
-{
- struct pattern_entry *e = xmalloc(sizeof(*e));
- e->patternlen = path->len;
- e->pattern = strbuf_detach(path, NULL);
- hashmap_entry_init(&e->ent,
- ignore_case ?
- strihash(e->pattern) :
- strhash(e->pattern));
-
- hashmap_add(&pl->recursive_hashmap, &e->ent);
-
- while (e->patternlen) {
- char *slash = strrchr(e->pattern, '/');
- char *oldpattern = e->pattern;
- size_t newlen;
-
- if (slash == e->pattern)
- break;
-
- newlen = slash - e->pattern;
- e = xmalloc(sizeof(struct pattern_entry));
- e->patternlen = newlen;
- e->pattern = xstrndup(oldpattern, newlen);
- hashmap_entry_init(&e->ent,
- ignore_case ?
- strihash(e->pattern) :
- strhash(e->pattern));
-
- if (!hashmap_get_entry(&pl->parent_hashmap, e, ent, NULL))
- hashmap_add(&pl->parent_hashmap, &e->ent);
- }
-}
-
-static void strbuf_to_cone_pattern(struct strbuf *line, struct pattern_list *pl)
-{
- strbuf_trim(line);
-
- strbuf_trim_trailing_dir_sep(line);
-
- if (strbuf_normalize_path(line))
- die(_("could not normalize path %s"), line->buf);
-
- if (!line->len)
- return;
-
- if (line->buf[0] != '/')
- strbuf_insertstr(line, 0, "/");
-
- insert_recursive_pattern(pl, line);
-}
-
static char const * const builtin_sparse_checkout_set_usage[] = {
N_("git sparse-checkout (set|add) (--stdin | <patterns>)"),
NULL
new file mode 100644
@@ -0,0 +1,233 @@
+#include "cache.h"
+#include "config.h"
+#include "dir.h"
+#include "lockfile.h"
+#include "quote.h"
+#include "repository.h"
+#include "sparse-checkout.h"
+#include "strbuf.h"
+#include "string-list.h"
+#include "unpack-trees.h"
+
+char *get_sparse_checkout_filename(void)
+{
+ return git_pathdup("info/sparse-checkout");
+}
+
+void write_patterns_to_file(FILE *fp, struct pattern_list *pl)
+{
+ int i;
+
+ for (i = 0; i < pl->nr; i++) {
+ struct path_pattern *p = pl->patterns[i];
+
+ if (p->flags & PATTERN_FLAG_NEGATIVE)
+ fprintf(fp, "!");
+
+ fprintf(fp, "%s", p->pattern);
+
+ if (p->flags & PATTERN_FLAG_MUSTBEDIR)
+ fprintf(fp, "/");
+
+ fprintf(fp, "\n");
+ }
+}
+
+int update_working_directory(struct pattern_list *pl)
+{
+ enum update_sparsity_result result;
+ struct unpack_trees_options o;
+ struct lock_file lock_file = LOCK_INIT;
+ struct repository *r = the_repository;
+
+ memset(&o, 0, sizeof(o));
+ o.verbose_update = isatty(2);
+ o.update = 1;
+ o.head_idx = -1;
+ o.src_index = r->index;
+ o.dst_index = r->index;
+ o.skip_sparse_checkout = 0;
+ o.pl = pl;
+
+ setup_work_tree();
+
+ repo_hold_locked_index(r, &lock_file, LOCK_DIE_ON_ERROR);
+
+ setup_unpack_trees_porcelain(&o, "sparse-checkout");
+ result = update_sparsity(&o);
+ clear_unpack_trees_porcelain(&o);
+
+ if (result == UPDATE_SPARSITY_WARNINGS)
+ /*
+ * We don't do any special handling of warnings from untracked
+ * files in the way or dirty entries that can't be removed.
+ */
+ result = UPDATE_SPARSITY_SUCCESS;
+ if (result == UPDATE_SPARSITY_SUCCESS)
+ write_locked_index(r->index, &lock_file, COMMIT_LOCK);
+ else
+ rollback_lock_file(&lock_file);
+
+ return result;
+}
+
+static char *escaped_pattern(char *pattern)
+{
+ char *p = pattern;
+ struct strbuf final = STRBUF_INIT;
+
+ while (*p) {
+ if (is_glob_special(*p))
+ strbuf_addch(&final, '\\');
+
+ strbuf_addch(&final, *p);
+ p++;
+ }
+
+ return strbuf_detach(&final, NULL);
+}
+
+static void write_cone_to_file(FILE *fp, struct pattern_list *pl)
+{
+ int i;
+ struct pattern_entry *pe;
+ struct hashmap_iter iter;
+ struct string_list sl = STRING_LIST_INIT_DUP;
+ struct strbuf parent_pattern = STRBUF_INIT;
+
+ hashmap_for_each_entry(&pl->parent_hashmap, &iter, pe, ent) {
+ if (hashmap_get_entry(&pl->recursive_hashmap, pe, ent, NULL))
+ continue;
+
+ if (!hashmap_contains_parent(&pl->recursive_hashmap,
+ pe->pattern,
+ &parent_pattern))
+ string_list_insert(&sl, pe->pattern);
+ }
+
+ string_list_sort(&sl);
+ string_list_remove_duplicates(&sl, 0);
+
+ fprintf(fp, "/*\n!/*/\n");
+
+ for (i = 0; i < sl.nr; i++) {
+ char *pattern = escaped_pattern(sl.items[i].string);
+
+ if (strlen(pattern))
+ fprintf(fp, "%s/\n!%s/*/\n", pattern, pattern);
+ free(pattern);
+ }
+
+ string_list_clear(&sl, 0);
+
+ hashmap_for_each_entry(&pl->recursive_hashmap, &iter, pe, ent) {
+ if (!hashmap_contains_parent(&pl->recursive_hashmap,
+ pe->pattern,
+ &parent_pattern))
+ string_list_insert(&sl, pe->pattern);
+ }
+
+ strbuf_release(&parent_pattern);
+
+ string_list_sort(&sl);
+ string_list_remove_duplicates(&sl, 0);
+
+ for (i = 0; i < sl.nr; i++) {
+ char *pattern = escaped_pattern(sl.items[i].string);
+ fprintf(fp, "%s/\n", pattern);
+ free(pattern);
+ }
+}
+
+int write_patterns_and_update(struct pattern_list *pl)
+{
+ char *sparse_filename;
+ FILE *fp;
+ int fd;
+ struct lock_file lk = LOCK_INIT;
+ int result;
+
+ sparse_filename = get_sparse_checkout_filename();
+
+ 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);
+
+ result = update_working_directory(pl);
+ if (result) {
+ rollback_lock_file(&lk);
+ free(sparse_filename);
+ clear_pattern_list(pl);
+ update_working_directory(NULL);
+ return result;
+ }
+
+ fp = xfdopen(fd, "w");
+
+ if (core_sparse_checkout_cone)
+ write_cone_to_file(fp, pl);
+ else
+ write_patterns_to_file(fp, pl);
+
+ fflush(fp);
+ commit_lock_file(&lk);
+
+ free(sparse_filename);
+ clear_pattern_list(pl);
+
+ return 0;
+}
+
+void insert_recursive_pattern(struct pattern_list *pl, struct strbuf *path)
+{
+ struct pattern_entry *e = xmalloc(sizeof(*e));
+ e->patternlen = path->len;
+ e->pattern = strbuf_detach(path, NULL);
+ hashmap_entry_init(&e->ent,
+ ignore_case ?
+ strihash(e->pattern) :
+ strhash(e->pattern));
+
+ hashmap_add(&pl->recursive_hashmap, &e->ent);
+
+ while (e->patternlen) {
+ char *slash = strrchr(e->pattern, '/');
+ char *oldpattern = e->pattern;
+ size_t newlen;
+
+ if (slash == e->pattern)
+ break;
+
+ newlen = slash - e->pattern;
+ e = xmalloc(sizeof(struct pattern_entry));
+ e->patternlen = newlen;
+ e->pattern = xstrndup(oldpattern, newlen);
+ hashmap_entry_init(&e->ent,
+ ignore_case ?
+ strihash(e->pattern) :
+ strhash(e->pattern));
+
+ if (!hashmap_get_entry(&pl->parent_hashmap, e, ent, NULL))
+ hashmap_add(&pl->parent_hashmap, &e->ent);
+ }
+}
+
+void strbuf_to_cone_pattern(struct strbuf *line, struct pattern_list *pl)
+{
+ strbuf_trim(line);
+
+ strbuf_trim_trailing_dir_sep(line);
+
+ if (strbuf_normalize_path(line))
+ die(_("could not normalize path %s"), line->buf);
+
+ if (!line->len)
+ return;
+
+ if (line->buf[0] != '/')
+ strbuf_insertstr(line, 0, "/");
+
+ insert_recursive_pattern(pl, line);
+}
new file mode 100644
@@ -0,0 +1,16 @@
+#ifndef SPARSE_CHECKOUT_H
+#define SPARSE_CHECKOUT_H
+
+#include "cache.h"
+#include "repository.h"
+
+struct pattern_list;
+
+char *get_sparse_checkout_filename(void);
+void write_patterns_to_file(FILE *fp, struct pattern_list *pl);
+int update_working_directory(struct pattern_list *pl);
+int write_patterns_and_update(struct pattern_list *pl);
+void insert_recursive_pattern(struct pattern_list *pl, struct strbuf *path);
+void strbuf_to_cone_pattern(struct strbuf *line, struct pattern_list *pl);
+
+#endif