{"thread":{"id":"14621","subject":"[PATCH 03/12] Introduce sparse prefix","startedAt":"2008-07-23T14:56:03Z","lastAt":"2008-07-23T14:56:03Z","messageCount":1,"participants":["Nguyễn Thái Ngọc Duy"],"isPatch":true,"patchVersion":1,"patchTotal":12},"messages":[{"id":"84508","messageId":"20080723145603.GA29079@laptop","threadId":"14621","inReplyTo":null,"subject":"[PATCH 03/12] Introduce sparse prefix","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2008-07-23T14:56:03Z","receivedAt":"2008-07-23T14:56:03Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Sparse prefix is actually a list of prefixes separated by colons,\nthat will limit worktree usage within it.\n\nThis patch adds core.sparsecheckout and\n\"git rev-parse --show-sparse-prefix\". This also adds manipulation\nfunctions that will get used later.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin-rev-parse.c |    4 +\n cache.h             |   13 +++\n config.c            |    7 ++\n environment.c       |  221 +++++++++++++++++++++++++++++++++++++++++++++++++++\n 4 files changed, 245 insertions(+), 0 deletions(-)\n\ndiff --git a/builtin-rev-parse.c b/builtin-rev-parse.c\nindex aa71f4a..4200f14 100644\n--- a/builtin-rev-parse.c\n+++ b/builtin-rev-parse.c\n@@ -499,6 +499,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)\n \t\t\t\t\tputs(prefix);\n \t\t\t\tcontinue;\n \t\t\t}\n+\t\t\tif (!strcmp(arg, \"--show-sparse-prefix\")) {\n+\t\t\t\tputs(get_sparse_prefix_str());\n+\t\t\t\tcontinue;\n+\t\t\t}\n \t\t\tif (!strcmp(arg, \"--show-cdup\")) {\n \t\t\t\tconst char *pfx = prefix;\n \t\t\t\tif (!is_inside_work_tree()) {\ndiff --git a/cache.h b/cache.h\nindex 38985aa..4687096 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -319,6 +319,19 @@ extern const char *get_git_work_tree(void);\n extern const char *read_gitfile_gently(const char *path);\n extern void set_git_work_tree(const char *tree);\n \n+extern int sparse_checkout_enabled();\n+extern char **get_sparse_prefix(void);\n+extern const char *get_sparse_prefix_str(void);\n+extern char **save_sparse_prefix();\n+extern char **restore_sparse_prefix(char **prefix);\n+extern int outside_sparse_prefix(const char *prefix);\n+extern int index_outside_sparse_prefix(const char *prefix);\n+extern void set_sparse_prefix(const char *prefix);\n+extern char **split_prefix(const char *env);\n+extern char **combine_prefix_list(char **p1, char **p2);\n+extern void free_prefix_list(char **prefix_list);\n+extern int outside_prefix_list(char **iprefix, const char *prefix);\n+\n #define ALTERNATE_DB_ENVIRONMENT \"GIT_ALTERNATE_OBJECT_DIRECTORIES\"\n \n extern const char **get_pathspec(const char *prefix, const char **pathspec);\ndiff --git a/config.c b/config.c\nindex 1e066c7..e7b457b 100644\n--- a/config.c\n+++ b/config.c\n@@ -467,6 +467,13 @@ static int git_default_core_config(const char *var, const char *value)\n \t\treturn 0;\n \t}\n \n+\tif (!strcmp(var, \"core.sparsecheckout\")) {\n+\t\tif (!value)\n+\t\t\treturn config_error_nonbool(var);\n+\t\tset_sparse_prefix(value);\n+\t\treturn 0;\n+\t}\n+\n \t/* Add other config variables here and to Documentation/config.txt. */\n \treturn 0;\n }\ndiff --git a/environment.c b/environment.c\nindex 4a88a17..94e39b8 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -46,9 +46,132 @@ enum rebase_setup_type autorebase = AUTOREBASE_NEVER;\n char *git_work_tree_cfg;\n static char *work_tree;\n \n+static char **sparse_prefix;\n+\n static const char *git_dir;\n static char *git_object_dir, *git_index_file, *git_refs_dir, *git_graft_file;\n \n+static char *append_slash(const char *prefix, int len)\n+{\n+\tchar *new_prefix;\n+\n+\tif (!*prefix)\n+\t\treturn NULL;\n+\n+\tif (prefix[len-1] == '/')\n+\t\treturn xstrndup(prefix, len);\n+\n+\tnew_prefix = xmalloc(len+2);\n+\tmemcpy(new_prefix, prefix, len);\n+\tnew_prefix[len] = '/';\n+\tnew_prefix[len+1] = '\\0';\n+\treturn new_prefix;\n+}\n+\n+/* this should be sorted as same order as index */\n+static int prefix_compare(const void *prefix1_, const void *prefix2_)\n+{\n+\tconst char *prefix1 = *(const char**)prefix1_;\n+\tconst char *prefix2 = *(const char**)prefix2_;\n+\tint len1 = strlen(prefix1);\n+\tint len2 = strlen(prefix2);\n+\tint len = len1 < len2 ? len1 : len2;\n+\tint cmp = memcmp(prefix1, prefix2, len);\n+\tif (cmp)\n+\t\treturn cmp;\n+\tif (len1 < len2)\n+\t\treturn -1;\n+\tif (len1 > len2)\n+\t\treturn 1;\n+\treturn 0;\n+}\n+\n+void free_prefix_list(char **prefix_list)\n+{\n+\tchar **prefix = prefix_list;\n+\n+\tif (!prefix)\n+\t\treturn;\n+\n+\twhile (*prefix) {\n+\t\tfree(*prefix);\n+\t\tprefix++;\n+\t}\n+\tfree(prefix_list);\n+}\n+\n+char **split_prefix(const char *env)\n+{\n+\tint prefix_nr = 0;\n+\tint prefix_alloc = 0;\n+\tchar **prefix_list = NULL;\n+\n+\tif (!env)\n+\t\treturn NULL;\n+\n+\tdo {\n+\t\tconst char *sep = strchr(env, ':');\n+\t\tint len = sep ? sep - env : strlen(env);\n+\t\tif (prefix_alloc <= prefix_nr+1) {\n+\t\t\tprefix_alloc = alloc_nr(prefix_alloc);\n+\t\t\tprefix_list = xrealloc(prefix_list,\n+\t\t\t\t\t\tprefix_alloc * sizeof(*prefix_list));\n+\t\t}\n+\t\tprefix_list[prefix_nr++] = append_slash(env, len);\n+\t\tenv += sep ? len+1 : len;\n+\t} while (*env);\n+\tprefix_list[prefix_nr] = NULL;\n+\tqsort(prefix_list, prefix_nr, sizeof(*prefix_list), prefix_compare);\n+\treturn prefix_list;\n+}\n+\n+char **combine_prefix_list(char **p1, char **p2)\n+{\n+\tint len1 = 0, len2 = 0;\n+\tchar **p, **p12, *last_prefix;\n+\tchar **result, **result_p;\n+\n+\t/*\n+\t * if either of them is null, full access,\n+\t * combining them would give full access as well\n+\t */\n+\tif (!p1 || !p2)\n+\t\treturn NULL;\n+\n+\tfor (p = p1; *p; p++)\n+\t\tlen1++;\n+\tfor (p = p2; *p; p++)\n+\t\tlen2++;\n+\n+\tp12 = xmalloc((len1+len2+1)*sizeof(*p12));\n+\tresult = xmalloc((len1+len2+1)*sizeof(*result));\n+\tmemcpy(p12, p1, len1*sizeof(*p12));\n+\tmemcpy(p12+len1, p2, (len2+1)*sizeof(*p12));\n+\tqsort(p12, len1+len2, sizeof(*p12), prefix_compare);\n+\n+\tp = p12;\n+\tlast_prefix = *p;\n+\tp++;\n+\tresult_p = result;\n+\t*result_p = xstrdup(last_prefix);\n+\tresult_p++;\n+\twhile (*p) {\n+\t\tif (!strcmp(*p, last_prefix)) {\n+\t\t\tp++;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (!prefixcmp(*p, last_prefix)) {\n+\t\t\tp++;\n+\t\t\tcontinue;\n+\t\t}\n+\t\t*result_p = xstrdup(*p);\n+\t\tresult_p++;\n+\t\tp++;\n+\t}\n+\t*result_p = NULL;\n+\treturn result;\n+}\n+\n static void setup_git_env(void)\n {\n \tgit_dir = getenv(GIT_DIR_ENVIRONMENT);\n@@ -122,6 +245,104 @@ const char *get_git_work_tree(void)\n \treturn work_tree;\n }\n \n+void set_sparse_prefix(const char *flat_sparse_prefix)\n+{\n+\tfree_prefix_list(sparse_prefix);\n+\tsparse_prefix = split_prefix(flat_sparse_prefix);\n+}\n+\n+char **get_sparse_prefix()\n+{\n+\treturn sparse_prefix;\n+}\n+\n+const char *get_sparse_prefix_str()\n+{\n+\tstatic char **sparse_prefix = NULL;\n+\tstatic char *sparse_prefix_str = NULL;\n+\tint len;\n+\tchar **prefix;\n+\n+\tif (sparse_prefix == get_sparse_prefix())\n+\t\treturn sparse_prefix ? sparse_prefix_str : \"\";\n+\n+\tsparse_prefix = get_sparse_prefix();\n+\n+\tif (!sparse_prefix)\n+\t\treturn \"\";\n+\n+\tlen = 0;\n+\tfor (prefix = sparse_prefix; *prefix; prefix++)\n+\t\tlen += strlen(*prefix)+1;\n+\tif (sparse_prefix_str)\n+\t\tfree(sparse_prefix_str);\n+\tsparse_prefix_str = xmalloc(len);\n+\n+\tprefix = sparse_prefix;\n+\tlen = strlen(*prefix);\n+\tif ((*prefix)[len-1] == '/')\n+\t\tlen--;\n+\tmemcpy(sparse_prefix_str, *prefix, len);\n+\tprefix++;\n+\twhile (*prefix) {\n+\t\tint len2 = strlen(*prefix);\n+\t\tsparse_prefix_str[len++] = ':';\n+\t\tif ((*prefix)[len2-1] == '/')\n+\t\t\tlen2--;\n+\t\tmemcpy(sparse_prefix_str+len, *prefix, len2);\n+\t\tlen += len2;\n+\t\tprefix++;\n+\t}\n+\tsparse_prefix_str[len] = 0;\n+\treturn sparse_prefix_str;\n+}\n+\n+char **save_sparse_prefix()\n+{\n+\tchar **prefix = sparse_prefix;\n+\tsparse_prefix = NULL;\n+\treturn prefix;\n+}\n+\n+char **restore_sparse_prefix(char **prefix)\n+{\n+\tchar **old_prefix = sparse_prefix;\n+\tsparse_prefix = prefix;\n+\treturn old_prefix;\n+}\n+\n+int outside_prefix_list(char **iprefix, const char *prefix)\n+{\n+\tif (!iprefix)\n+\t\treturn 0;\n+\n+\twhile (*iprefix) {\n+\t\tif (!prefixcmp(prefix, *iprefix))\n+\t\t\treturn 0;\n+\t\tiprefix++;\n+\t}\n+\treturn 1;\n+}\n+\n+int sparse_checkout_enabled()\n+{\n+\tstatic int disable_sparse_checkout = -1;\n+\tif (disable_sparse_checkout == -1)\n+\t\tdisable_sparse_checkout = getenv(\"GIT_SPARSE_CHECKOUT_INDEX_ONLY\") != NULL;\n+\treturn !disable_sparse_checkout && get_sparse_prefix();\n+}\n+\n+\n+int outside_sparse_prefix(const char *prefix)\n+{\n+\treturn sparse_checkout_enabled() && outside_prefix_list(sparse_prefix, prefix);\n+}\n+\n+int index_outside_sparse_prefix(const char *prefix)\n+{\n+\treturn outside_prefix_list(sparse_prefix, prefix);\n+}\n+\n char *get_object_directory(void)\n {\n \tif (!git_object_dir)\n-- \n1.5.5.GIT\n"}]}