Commit 2370b4d7 by Vicent Martí

Merge pull request #1499 from arrbee/fix-diff-config-usage

Support more diff config options and use the config cache more
parents bd0a07f4 687db88f
...@@ -1119,7 +1119,6 @@ static int checkout_data_init( ...@@ -1119,7 +1119,6 @@ static int checkout_data_init(
git_checkout_opts *proposed) git_checkout_opts *proposed)
{ {
int error = 0; int error = 0;
git_config *cfg;
git_repository *repo = git_iterator_owner(target); git_repository *repo = git_iterator_owner(target);
memset(data, 0, sizeof(*data)); memset(data, 0, sizeof(*data));
...@@ -1132,9 +1131,6 @@ static int checkout_data_init( ...@@ -1132,9 +1131,6 @@ static int checkout_data_init(
if ((error = git_repository__ensure_not_bare(repo, "checkout")) < 0) if ((error = git_repository__ensure_not_bare(repo, "checkout")) < 0)
return error; return error;
if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
return error;
data->repo = repo; data->repo = repo;
GITERR_CHECK_VERSION( GITERR_CHECK_VERSION(
...@@ -1147,7 +1143,10 @@ static int checkout_data_init( ...@@ -1147,7 +1143,10 @@ static int checkout_data_init(
/* refresh config and index content unless NO_REFRESH is given */ /* refresh config and index content unless NO_REFRESH is given */
if ((data->opts.checkout_strategy & GIT_CHECKOUT_NO_REFRESH) == 0) { if ((data->opts.checkout_strategy & GIT_CHECKOUT_NO_REFRESH) == 0) {
if ((error = git_config_refresh(cfg)) < 0) git_config *cfg;
if ((error = git_repository_config__weakptr(&cfg, repo)) < 0 ||
(error = git_config_refresh(cfg)) < 0)
goto cleanup; goto cleanup;
/* if we are checking out the index, don't reload, /* if we are checking out the index, don't reload,
...@@ -1184,19 +1183,13 @@ static int checkout_data_init( ...@@ -1184,19 +1183,13 @@ static int checkout_data_init(
data->pfx = git_pathspec_prefix(&data->opts.paths); data->pfx = git_pathspec_prefix(&data->opts.paths);
error = git_config_get_bool(&data->can_symlink, cfg, "core.symlinks"); if ((error = git_repository__cvar(
if (error < 0) { &data->can_symlink, repo, GIT_CVAR_SYMLINKS)) < 0)
if (error != GIT_ENOTFOUND) goto cleanup;
goto cleanup;
/* If "core.symlinks" is not found anywhere, default to true. */
data->can_symlink = true;
giterr_clear();
error = 0;
}
if (!data->opts.baseline) { if (!data->opts.baseline) {
data->opts_free_baseline = true; data->opts_free_baseline = true;
error = checkout_lookup_head_tree(&data->opts.baseline, repo); error = checkout_lookup_head_tree(&data->opts.baseline, repo);
if (error == GIT_EORPHANEDHEAD) { if (error == GIT_EORPHANEDHEAD) {
......
...@@ -293,6 +293,9 @@ int git_config_refresh(git_config *cfg) ...@@ -293,6 +293,9 @@ int git_config_refresh(git_config *cfg)
error = file->refresh(file); error = file->refresh(file);
} }
if (!error && GIT_REFCOUNT_OWNER(cfg) != NULL)
git_repository__cvar_cache_clear(GIT_REFCOUNT_OWNER(cfg));
return error; return error;
} }
...@@ -360,6 +363,7 @@ int git_config_set_bool(git_config *cfg, const char *name, int value) ...@@ -360,6 +363,7 @@ int git_config_set_bool(git_config *cfg, const char *name, int value)
int git_config_set_string(git_config *cfg, const char *name, const char *value) int git_config_set_string(git_config *cfg, const char *name, const char *value)
{ {
int error;
git_config_backend *file; git_config_backend *file;
file_internal *internal; file_internal *internal;
...@@ -371,7 +375,12 @@ int git_config_set_string(git_config *cfg, const char *name, const char *value) ...@@ -371,7 +375,12 @@ int git_config_set_string(git_config *cfg, const char *name, const char *value)
internal = git_vector_get(&cfg->files, 0); internal = git_vector_get(&cfg->files, 0);
file = internal->file; file = internal->file;
return file->set(file, name, value); error = file->set(file, name, value);
if (!error && GIT_REFCOUNT_OWNER(cfg) != NULL)
git_repository__cvar_cache_clear(GIT_REFCOUNT_OWNER(cfg));
return error;
} }
/*********** /***********
......
...@@ -26,7 +26,7 @@ struct map_data { ...@@ -26,7 +26,7 @@ struct map_data {
* files that have the text property set. Alternatives are lf, crlf * files that have the text property set. Alternatives are lf, crlf
* and native, which uses the platform's native line ending. The default * and native, which uses the platform's native line ending. The default
* value is native. See gitattributes(5) for more information on * value is native. See gitattributes(5) for more information on
* end-of-line conversion. * end-of-line conversion.
*/ */
static git_cvar_map _cvar_map_eol[] = { static git_cvar_map _cvar_map_eol[] = {
{GIT_CVAR_FALSE, NULL, GIT_EOL_UNSET}, {GIT_CVAR_FALSE, NULL, GIT_EOL_UNSET},
...@@ -37,7 +37,7 @@ static git_cvar_map _cvar_map_eol[] = { ...@@ -37,7 +37,7 @@ static git_cvar_map _cvar_map_eol[] = {
/* /*
* core.autocrlf * core.autocrlf
* Setting this variable to "true" is almost the same as setting * Setting this variable to "true" is almost the same as setting
* the text attribute to "auto" on all files except that text files are * the text attribute to "auto" on all files except that text files are
* not guaranteed to be normalized: files that contain CRLF in the * not guaranteed to be normalized: files that contain CRLF in the
* repository will not be touched. Use this setting if you want to have * repository will not be touched. Use this setting if you want to have
...@@ -51,9 +51,22 @@ static git_cvar_map _cvar_map_autocrlf[] = { ...@@ -51,9 +51,22 @@ static git_cvar_map _cvar_map_autocrlf[] = {
{GIT_CVAR_STRING, "input", GIT_AUTO_CRLF_INPUT} {GIT_CVAR_STRING, "input", GIT_AUTO_CRLF_INPUT}
}; };
/*
* Generic map for integer values
*/
static git_cvar_map _cvar_map_int[] = {
{GIT_CVAR_INT32, NULL, 0},
};
static struct map_data _cvar_maps[] = { static struct map_data _cvar_maps[] = {
{"core.autocrlf", _cvar_map_autocrlf, ARRAY_SIZE(_cvar_map_autocrlf), GIT_AUTO_CRLF_DEFAULT}, {"core.autocrlf", _cvar_map_autocrlf, ARRAY_SIZE(_cvar_map_autocrlf), GIT_AUTO_CRLF_DEFAULT},
{"core.eol", _cvar_map_eol, ARRAY_SIZE(_cvar_map_eol), GIT_EOL_DEFAULT} {"core.eol", _cvar_map_eol, ARRAY_SIZE(_cvar_map_eol), GIT_EOL_DEFAULT},
{"core.symlinks", NULL, 0, GIT_SYMLINKS_DEFAULT },
{"core.ignorecase", NULL, 0, GIT_IGNORECASE_DEFAULT },
{"core.filemode", NULL, 0, GIT_FILEMODE_DEFAULT },
{"core.ignorestat", NULL, 0, GIT_IGNORESTAT_DEFAULT },
{"core.trustctime", NULL, 0, GIT_TRUSTCTIME_DEFAULT },
{"core.abbrev", _cvar_map_int, 1, GIT_ABBREV_DEFAULT },
}; };
int git_repository__cvar(int *out, git_repository *repo, git_cvar_cached cvar) int git_repository__cvar(int *out, git_repository *repo, git_cvar_cached cvar)
...@@ -69,12 +82,16 @@ int git_repository__cvar(int *out, git_repository *repo, git_cvar_cached cvar) ...@@ -69,12 +82,16 @@ int git_repository__cvar(int *out, git_repository *repo, git_cvar_cached cvar)
if (error < 0) if (error < 0)
return error; return error;
error = git_config_get_mapped(out, if (data->maps)
config, data->cvar_name, data->maps, data->map_count); error = git_config_get_mapped(
out, config, data->cvar_name, data->maps, data->map_count);
else
error = git_config_get_bool(out, config, data->cvar_name);
if (error == GIT_ENOTFOUND) if (error == GIT_ENOTFOUND) {
giterr_clear();
*out = data->default_value; *out = data->default_value;
}
else if (error < 0) else if (error < 0)
return error; return error;
......
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
#define DIFF_FLAG_IS_SET(DIFF,FLAG) (((DIFF)->opts.flags & (FLAG)) != 0) #define DIFF_FLAG_IS_SET(DIFF,FLAG) (((DIFF)->opts.flags & (FLAG)) != 0)
#define DIFF_FLAG_ISNT_SET(DIFF,FLAG) (((DIFF)->opts.flags & (FLAG)) == 0) #define DIFF_FLAG_ISNT_SET(DIFF,FLAG) (((DIFF)->opts.flags & (FLAG)) == 0)
#define DIFF_FLAG_SET(DIFF,FLAG,VAL) (DIFF)->opts.flags = \
(VAL) ? ((DIFF)->opts.flags | (FLAG)) : ((DIFF)->opts.flags & ~(VAL))
static git_diff_delta *diff_delta__alloc( static git_diff_delta *diff_delta__alloc(
git_diff_list *diff, git_diff_list *diff,
...@@ -267,67 +269,158 @@ static int config_bool(git_config *cfg, const char *name, int defvalue) ...@@ -267,67 +269,158 @@ static int config_bool(git_config *cfg, const char *name, int defvalue)
return val; return val;
} }
static git_diff_list *git_diff_list_alloc( static int config_int(git_config *cfg, const char *name, int defvalue)
git_repository *repo, const git_diff_options *opts)
{ {
git_config *cfg; int val = defvalue;
if (git_config_get_int32(&val, cfg, name) < 0)
giterr_clear();
return val;
}
static const char *diff_mnemonic_prefix(
git_iterator_type_t type, bool left_side)
{
const char *pfx = "";
switch (type) {
case GIT_ITERATOR_TYPE_EMPTY: pfx = "c"; break;
case GIT_ITERATOR_TYPE_TREE: pfx = "c"; break;
case GIT_ITERATOR_TYPE_INDEX: pfx = "i"; break;
case GIT_ITERATOR_TYPE_WORKDIR: pfx = "w"; break;
case GIT_ITERATOR_TYPE_FS: pfx = left_side ? "1" : "2"; break;
default: break;
}
/* note: without a deeper look at pathspecs, there is no easy way
* to get the (o)bject / (w)ork tree mnemonics working...
*/
return pfx;
}
static git_diff_list *diff_list_alloc(
git_repository *repo,
git_iterator *old_iter,
git_iterator *new_iter)
{
git_diff_options dflt = GIT_DIFF_OPTIONS_INIT;
git_diff_list *diff = git__calloc(1, sizeof(git_diff_list)); git_diff_list *diff = git__calloc(1, sizeof(git_diff_list));
if (diff == NULL) if (!diff)
return NULL; return NULL;
assert(repo && old_iter && new_iter);
GIT_REFCOUNT_INC(diff); GIT_REFCOUNT_INC(diff);
diff->repo = repo; diff->repo = repo;
diff->old_src = old_iter->type;
diff->new_src = new_iter->type;
memcpy(&diff->opts, &dflt, sizeof(diff->opts));
if (git_vector_init(&diff->deltas, 0, git_diff_delta__cmp) < 0 || if (git_vector_init(&diff->deltas, 0, git_diff_delta__cmp) < 0 ||
git_pool_init(&diff->pool, 1, 0) < 0) git_pool_init(&diff->pool, 1, 0) < 0) {
goto fail; git_diff_list_free(diff);
return NULL;
}
/* Use case-insensitive compare if either iterator has
* the ignore_case bit set */
if (!git_iterator_ignore_case(old_iter) &&
!git_iterator_ignore_case(new_iter))
{
diff->opts.flags &= ~GIT_DIFF_DELTAS_ARE_ICASE;
diff->strcomp = git__strcmp;
diff->strncomp = git__strncmp;
diff->pfxcomp = git__prefixcmp;
diff->entrycomp = git_index_entry__cmp;
} else {
diff->opts.flags |= GIT_DIFF_DELTAS_ARE_ICASE;
diff->strcomp = git__strcasecmp;
diff->strncomp = git__strncasecmp;
diff->pfxcomp = git__prefixcmp_icase;
diff->entrycomp = git_index_entry__cmp_icase;
}
return diff;
}
static int diff_list_apply_options(
git_diff_list *diff,
const git_diff_options *opts)
{
git_config *cfg;
git_repository *repo = diff->repo;
git_pool *pool = &diff->pool;
int val;
if (opts) {
/* copy user options (except case sensitivity info from iterators) */
bool icase = DIFF_FLAG_IS_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE);
memcpy(&diff->opts, opts, sizeof(diff->opts));
DIFF_FLAG_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE, icase);
/* initialize pathspec from options */
if (git_pathspec_init(&diff->pathspec, &opts->pathspec, pool) < 0)
return -1;
}
/* flag INCLUDE_TYPECHANGE_TREES implies INCLUDE_TYPECHANGE */
if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_TYPECHANGE_TREES))
diff->opts.flags |= GIT_DIFF_INCLUDE_TYPECHANGE;
/* load config values that affect diff behavior */ /* load config values that affect diff behavior */
if (git_repository_config__weakptr(&cfg, repo) < 0) if (git_repository_config__weakptr(&cfg, repo) < 0)
goto fail; return -1;
if (config_bool(cfg, "core.symlinks", 1))
if (!git_repository__cvar(&val, repo, GIT_CVAR_SYMLINKS) && val)
diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_HAS_SYMLINKS; diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_HAS_SYMLINKS;
if (config_bool(cfg, "core.ignorestat", 0))
if (!git_repository__cvar(&val, repo, GIT_CVAR_IGNORESTAT) && val)
diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_ASSUME_UNCHANGED; diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_ASSUME_UNCHANGED;
if (config_bool(cfg, "core.filemode", 1))
if ((diff->opts.flags & GIT_DIFF_IGNORE_FILEMODE) == 0 &&
!git_repository__cvar(&val, repo, GIT_CVAR_FILEMODE) && val)
diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_TRUST_MODE_BITS; diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_TRUST_MODE_BITS;
if (config_bool(cfg, "core.trustctime", 1))
if (!git_repository__cvar(&val, repo, GIT_CVAR_TRUSTCTIME) && val)
diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_TRUST_CTIME; diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_TRUST_CTIME;
/* Don't set GIT_DIFFCAPS_USE_DEV - compile time option in core git */ /* Don't set GIT_DIFFCAPS_USE_DEV - compile time option in core git */
/* TODO: there are certain config settings where even if we were /* If not given explicit `opts`, check `diff.xyz` configs */
* not given an options structure, we need the diff list to have one if (!opts) {
* so that we can store the altered default values. diff->opts.context_lines = config_int(cfg, "diff.context", 3);
*
* - diff.ignoreSubmodules
* - diff.mnemonicprefix
* - diff.noprefix
*/
if (opts == NULL) { if (config_bool(cfg, "diff.ignoreSubmodules", 0))
/* Make sure we default to 3 lines */ diff->opts.flags |= GIT_DIFF_IGNORE_SUBMODULES;
diff->opts.context_lines = 3;
return diff;
} }
memcpy(&diff->opts, opts, sizeof(git_diff_options)); /* if either prefix is not set, figure out appropriate value */
if (!diff->opts.old_prefix || !diff->opts.new_prefix) {
if(opts->flags & GIT_DIFF_IGNORE_FILEMODE) const char *use_old = DIFF_OLD_PREFIX_DEFAULT;
diff->diffcaps = diff->diffcaps & ~GIT_DIFFCAPS_TRUST_MODE_BITS; const char *use_new = DIFF_NEW_PREFIX_DEFAULT;
/* pathspec init will do nothing for empty pathspec */
if (git_pathspec_init(&diff->pathspec, &opts->pathspec, &diff->pool) < 0)
goto fail;
/* TODO: handle config diff.mnemonicprefix, diff.noprefix */ if (config_bool(cfg, "diff.noprefix", 0)) {
use_old = use_new = "";
} else if (config_bool(cfg, "diff.mnemonicprefix", 0)) {
use_old = diff_mnemonic_prefix(diff->old_src, true);
use_new = diff_mnemonic_prefix(diff->new_src, false);
}
diff->opts.old_prefix = diff_strdup_prefix(&diff->pool, if (!diff->opts.old_prefix)
opts->old_prefix ? opts->old_prefix : DIFF_OLD_PREFIX_DEFAULT); diff->opts.old_prefix = use_old;
diff->opts.new_prefix = diff_strdup_prefix(&diff->pool, if (!diff->opts.new_prefix)
opts->new_prefix ? opts->new_prefix : DIFF_NEW_PREFIX_DEFAULT); diff->opts.new_prefix = use_new;
}
/* strdup prefix from pool so we're not dependent on external data */
diff->opts.old_prefix = diff_strdup_prefix(pool, diff->opts.old_prefix);
diff->opts.new_prefix = diff_strdup_prefix(pool, diff->opts.new_prefix);
if (!diff->opts.old_prefix || !diff->opts.new_prefix) if (!diff->opts.old_prefix || !diff->opts.new_prefix)
goto fail; return -1;
if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_REVERSE)) { if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_REVERSE)) {
const char *swap = diff->opts.old_prefix; const char *swap = diff->opts.old_prefix;
...@@ -335,15 +428,7 @@ static git_diff_list *git_diff_list_alloc( ...@@ -335,15 +428,7 @@ static git_diff_list *git_diff_list_alloc(
diff->opts.new_prefix = swap; diff->opts.new_prefix = swap;
} }
/* INCLUDE_TYPECHANGE_TREES implies INCLUDE_TYPECHANGE */ return 0;
if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_TYPECHANGE_TREES))
diff->opts.flags |= GIT_DIFF_INCLUDE_TYPECHANGE;
return diff;
fail:
git_diff_list_free(diff);
return NULL;
} }
static void diff_list_free(git_diff_list *diff) static void diff_list_free(git_diff_list *diff)
...@@ -607,37 +692,6 @@ static bool entry_is_prefixed( ...@@ -607,37 +692,6 @@ static bool entry_is_prefixed(
item->path[pathlen] == '/'); item->path[pathlen] == '/');
} }
static int diff_list_init_from_iterators(
git_diff_list *diff,
git_iterator *old_iter,
git_iterator *new_iter)
{
diff->old_src = old_iter->type;
diff->new_src = new_iter->type;
/* Use case-insensitive compare if either iterator has
* the ignore_case bit set */
if (!git_iterator_ignore_case(old_iter) &&
!git_iterator_ignore_case(new_iter))
{
diff->opts.flags &= ~GIT_DIFF_DELTAS_ARE_ICASE;
diff->strcomp = git__strcmp;
diff->strncomp = git__strncmp;
diff->pfxcomp = git__prefixcmp;
diff->entrycomp = git_index_entry__cmp;
} else {
diff->opts.flags |= GIT_DIFF_DELTAS_ARE_ICASE;
diff->strcomp = git__strcasecmp;
diff->strncomp = git__strncasecmp;
diff->pfxcomp = git__prefixcmp_icase;
diff->entrycomp = git_index_entry__cmp_icase;
}
return 0;
}
int git_diff__from_iterators( int git_diff__from_iterators(
git_diff_list **diff_ptr, git_diff_list **diff_ptr,
git_repository *repo, git_repository *repo,
...@@ -648,20 +702,22 @@ int git_diff__from_iterators( ...@@ -648,20 +702,22 @@ int git_diff__from_iterators(
int error = 0; int error = 0;
const git_index_entry *oitem, *nitem; const git_index_entry *oitem, *nitem;
git_buf ignore_prefix = GIT_BUF_INIT; git_buf ignore_prefix = GIT_BUF_INIT;
git_diff_list *diff = git_diff_list_alloc(repo, opts); git_diff_list *diff;
*diff_ptr = NULL; *diff_ptr = NULL;
if (!diff || diff_list_init_from_iterators(diff, old_iter, new_iter) < 0) diff = diff_list_alloc(repo, old_iter, new_iter);
goto fail; GITERR_CHECK_ALLOC(diff);
/* make iterators have matching icase behavior */
if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE)) { if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE)) {
if (git_iterator_set_ignore_case(old_iter, true) < 0 || if (git_iterator_set_ignore_case(old_iter, true) < 0 ||
git_iterator_set_ignore_case(new_iter, true) < 0) git_iterator_set_ignore_case(new_iter, true) < 0)
goto fail; goto fail;
} }
if (git_iterator_current(&oitem, old_iter) < 0 || if (diff_list_apply_options(diff, opts) < 0 ||
git_iterator_current(&oitem, old_iter) < 0 ||
git_iterator_current(&nitem, new_iter) < 0) git_iterator_current(&nitem, new_iter) < 0)
goto fail; goto fail;
...@@ -859,12 +915,20 @@ int git_diff_tree_to_tree( ...@@ -859,12 +915,20 @@ int git_diff_tree_to_tree(
const git_diff_options *opts) const git_diff_options *opts)
{ {
int error = 0; int error = 0;
git_iterator_flag_t iflag = GIT_ITERATOR_DONT_IGNORE_CASE;
assert(diff && repo); assert(diff && repo);
/* for tree to tree diff, be case sensitive even if the index is
* currently case insensitive, unless the user explicitly asked
* for case insensitivity
*/
if (opts && (opts->flags & GIT_DIFF_DELTAS_ARE_ICASE) != 0)
iflag = GIT_ITERATOR_IGNORE_CASE;
DIFF_FROM_ITERATORS( DIFF_FROM_ITERATORS(
git_iterator_for_tree(&a, old_tree, 0, pfx, pfx), git_iterator_for_tree(&a, old_tree, iflag, pfx, pfx),
git_iterator_for_tree(&b, new_tree, 0, pfx, pfx) git_iterator_for_tree(&b, new_tree, iflag, pfx, pfx)
); );
return error; return error;
......
...@@ -1114,11 +1114,20 @@ int git_diff_print_compact( ...@@ -1114,11 +1114,20 @@ int git_diff_print_compact(
static int print_oid_range(diff_print_info *pi, const git_diff_delta *delta) static int print_oid_range(diff_print_info *pi, const git_diff_delta *delta)
{ {
char start_oid[8], end_oid[8]; int abbrevlen;
char start_oid[GIT_OID_HEXSZ+1], end_oid[GIT_OID_HEXSZ+1];
/* TODO: Determine a good actual OID range to print */ if (git_repository__cvar(&abbrevlen, pi->diff->repo, GIT_CVAR_ABBREV) < 0)
git_oid_tostr(start_oid, sizeof(start_oid), &delta->old_file.oid); return -1;
git_oid_tostr(end_oid, sizeof(end_oid), &delta->new_file.oid);
abbrevlen += 1; /* for NUL byte */
if (abbrevlen < 2)
abbrevlen = 2;
else if (abbrevlen > (int)sizeof(start_oid))
abbrevlen = (int)sizeof(start_oid);
git_oid_tostr(start_oid, abbrevlen, &delta->old_file.oid);
git_oid_tostr(end_oid, abbrevlen, &delta->new_file.oid);
/* TODO: Match git diff more closely */ /* TODO: Match git diff more closely */
if (delta->old_file.mode == delta->new_file.mode) { if (delta->old_file.mode == delta->new_file.mode) {
......
...@@ -15,24 +15,14 @@ static int parse_ignore_file( ...@@ -15,24 +15,14 @@ static int parse_ignore_file(
git_attr_fnmatch *match = NULL; git_attr_fnmatch *match = NULL;
const char *scan = NULL; const char *scan = NULL;
char *context = NULL; char *context = NULL;
bool ignore_case = false; int ignore_case = false;
git_config *cfg = NULL;
int val;
/* Prefer to have the caller pass in a git_ignores as the parsedata object.
* If they did not, then we can (much more slowly) find the value of
* ignore_case by using the repository object. */
if (parsedata != NULL) {
ignore_case = ((git_ignores *)parsedata)->ignore_case;
} else {
if ((error = git_repository_config(&cfg, repo)) < 0)
return error;
if (git_config_get_bool(&val, cfg, "core.ignorecase") == 0)
ignore_case = (val != 0);
git_config_free(cfg); /* Prefer to have the caller pass in a git_ignores as the parsedata
} * object. If they did not, then look up the value of ignore_case */
if (parsedata != NULL)
ignore_case = ((git_ignores *)parsedata)->ignore_case;
else if (git_repository__cvar(&ignore_case, repo, GIT_CVAR_IGNORECASE) < 0)
return error;
if (ignores->key && git__suffixcmp(ignores->key, "/" GIT_IGNORE_FILE) == 0) { if (ignores->key && git__suffixcmp(ignores->key, "/" GIT_IGNORE_FILE) == 0) {
context = ignores->key + 2; context = ignores->key + 2;
...@@ -109,8 +99,6 @@ int git_ignore__for_path( ...@@ -109,8 +99,6 @@ int git_ignore__for_path(
{ {
int error = 0; int error = 0;
const char *workdir = git_repository_workdir(repo); const char *workdir = git_repository_workdir(repo);
git_config *cfg = NULL;
int val;
assert(ignores); assert(ignores);
...@@ -118,17 +106,11 @@ int git_ignore__for_path( ...@@ -118,17 +106,11 @@ int git_ignore__for_path(
git_buf_init(&ignores->dir, 0); git_buf_init(&ignores->dir, 0);
ignores->ign_internal = NULL; ignores->ign_internal = NULL;
/* Set the ignore_case flag appropriately */ /* Read the ignore_case flag */
if ((error = git_repository_config(&cfg, repo)) < 0) if ((error = git_repository__cvar(
&ignores->ignore_case, repo, GIT_CVAR_IGNORECASE)) < 0)
goto cleanup; goto cleanup;
if (git_config_get_bool(&val, cfg, "core.ignorecase") == 0)
ignores->ignore_case = (val != 0);
else
ignores->ignore_case = 0;
git_config_free(cfg);
if ((error = git_vector_init(&ignores->ign_path, 8, NULL)) < 0 || if ((error = git_vector_init(&ignores->ign_path, 8, NULL)) < 0 ||
(error = git_vector_init(&ignores->ign_global, 2, NULL)) < 0 || (error = git_vector_init(&ignores->ign_global, 2, NULL)) < 0 ||
(error = git_attr_cache__init(repo)) < 0) (error = git_attr_cache__init(repo)) < 0)
......
...@@ -28,7 +28,7 @@ typedef struct { ...@@ -28,7 +28,7 @@ typedef struct {
git_attr_file *ign_internal; git_attr_file *ign_internal;
git_vector ign_path; git_vector ign_path;
git_vector ign_global; git_vector ign_global;
unsigned int ignore_case:1; int ignore_case;
} git_ignores; } git_ignores;
extern int git_ignore__for_path(git_repository *repo, const char *path, git_ignores *ign); extern int git_ignore__for_path(git_repository *repo, const char *path, git_ignores *ign);
......
...@@ -330,7 +330,7 @@ void git_index_clear(git_index *index) ...@@ -330,7 +330,7 @@ void git_index_clear(git_index *index)
git_vector_clear(&index->entries); git_vector_clear(&index->entries);
git_index_reuc_clear(index); git_index_reuc_clear(index);
git_futils_filestamp_set(&index->stamp, NULL); git_futils_filestamp_set(&index->stamp, NULL);
git_tree_cache_free(index->tree); git_tree_cache_free(index->tree);
...@@ -352,19 +352,18 @@ int git_index_set_caps(git_index *index, unsigned int caps) ...@@ -352,19 +352,18 @@ int git_index_set_caps(git_index *index, unsigned int caps)
old_ignore_case = index->ignore_case; old_ignore_case = index->ignore_case;
if (caps == GIT_INDEXCAP_FROM_OWNER) { if (caps == GIT_INDEXCAP_FROM_OWNER) {
git_config *cfg; git_repository *repo = INDEX_OWNER(index);
int val; int val;
if (INDEX_OWNER(index) == NULL || if (!repo)
git_repository_config__weakptr(&cfg, INDEX_OWNER(index)) < 0) return create_index_error(
return create_index_error(-1, -1, "Cannot access repository to set index caps");
"Cannot get repository config to set index caps");
if (git_config_get_bool(&val, cfg, "core.ignorecase") == 0) if (!git_repository__cvar(&val, repo, GIT_CVAR_IGNORECASE))
index->ignore_case = (val != 0); index->ignore_case = (val != 0);
if (git_config_get_bool(&val, cfg, "core.filemode") == 0) if (!git_repository__cvar(&val, repo, GIT_CVAR_FILEMODE))
index->distrust_filemode = (val == 0); index->distrust_filemode = (val == 0);
if (git_config_get_bool(&val, cfg, "core.symlinks") == 0) if (!git_repository__cvar(&val, repo, GIT_CVAR_SYMLINKS))
index->no_symlinks = (val == 0); index->no_symlinks = (val == 0);
} }
else { else {
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "git2/odb.h" #include "git2/odb.h"
#include "git2/repository.h" #include "git2/repository.h"
#include "git2/object.h" #include "git2/object.h"
#include "git2/config.h"
#include "index.h" #include "index.h"
#include "cache.h" #include "cache.h"
...@@ -31,7 +32,13 @@ ...@@ -31,7 +32,13 @@
/** Cvar cache identifiers */ /** Cvar cache identifiers */
typedef enum { typedef enum {
GIT_CVAR_AUTO_CRLF = 0, /* core.autocrlf */ GIT_CVAR_AUTO_CRLF = 0, /* core.autocrlf */
GIT_CVAR_EOL, /* core.eol */ GIT_CVAR_EOL, /* core.eol */
GIT_CVAR_SYMLINKS, /* core.symlinks */
GIT_CVAR_IGNORECASE, /* core.ignorecase */
GIT_CVAR_FILEMODE, /* core.filemode */
GIT_CVAR_IGNORESTAT, /* core.ignorestat */
GIT_CVAR_TRUSTCTIME, /* core.trustctime */
GIT_CVAR_ABBREV, /* core.abbrev */
GIT_CVAR_CACHE_MAX GIT_CVAR_CACHE_MAX
} git_cvar_cached; } git_cvar_cached;
...@@ -67,7 +74,21 @@ typedef enum { ...@@ -67,7 +74,21 @@ typedef enum {
#else #else
GIT_EOL_NATIVE = GIT_EOL_LF, GIT_EOL_NATIVE = GIT_EOL_LF,
#endif #endif
GIT_EOL_DEFAULT = GIT_EOL_NATIVE GIT_EOL_DEFAULT = GIT_EOL_NATIVE,
/* core.symlinks: bool */
GIT_SYMLINKS_DEFAULT = GIT_CVAR_TRUE,
/* core.ignorecase */
GIT_IGNORECASE_DEFAULT = GIT_CVAR_FALSE,
/* core.filemode */
GIT_FILEMODE_DEFAULT = GIT_CVAR_TRUE,
/* core.ignorestat */
GIT_IGNORESTAT_DEFAULT = GIT_CVAR_FALSE,
/* core.trustctime */
GIT_TRUSTCTIME_DEFAULT = GIT_CVAR_TRUE,
/* core.abbrev */
GIT_ABBREV_DEFAULT = 7,
} git_cvar_value; } git_cvar_value;
/* internal repository init flags */ /* internal repository init flags */
......
...@@ -135,6 +135,84 @@ void test_diff_patch__to_string(void) ...@@ -135,6 +135,84 @@ void test_diff_patch__to_string(void)
git_tree_free(one); git_tree_free(one);
} }
void test_diff_patch__config_options(void)
{
const char *one_sha = "26a125e"; /* current HEAD */
git_tree *one;
git_config *cfg;
git_diff_list *diff;
git_diff_patch *patch;
char *text;
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
char *onefile = "staged_changes_modified_file";
const char *expected1 = "diff --git c/staged_changes_modified_file i/staged_changes_modified_file\nindex 70bd944..906ee77 100644\n--- c/staged_changes_modified_file\n+++ i/staged_changes_modified_file\n@@ -1 +1,2 @@\n staged_changes_modified_file\n+staged_changes_modified_file\n";
const char *expected2 = "diff --git i/staged_changes_modified_file w/staged_changes_modified_file\nindex 906ee77..011c344 100644\n--- i/staged_changes_modified_file\n+++ w/staged_changes_modified_file\n@@ -1,2 +1,3 @@\n staged_changes_modified_file\n staged_changes_modified_file\n+staged_changes_modified_file\n";
const char *expected3 = "diff --git staged_changes_modified_file staged_changes_modified_file\nindex 906ee77..011c344 100644\n--- staged_changes_modified_file\n+++ staged_changes_modified_file\n@@ -1,2 +1,3 @@\n staged_changes_modified_file\n staged_changes_modified_file\n+staged_changes_modified_file\n";
const char *expected4 = "diff --git staged_changes_modified_file staged_changes_modified_file\nindex 70bd9443ada0..906ee7711f4f 100644\n--- staged_changes_modified_file\n+++ staged_changes_modified_file\n@@ -1 +1,2 @@\n staged_changes_modified_file\n+staged_changes_modified_file\n";
g_repo = cl_git_sandbox_init("status");
cl_git_pass(git_repository_config(&cfg, g_repo));
one = resolve_commit_oid_to_tree(g_repo, one_sha);
opts.pathspec.count = 1;
opts.pathspec.strings = &onefile;
cl_git_pass(git_config_set_string(cfg, "diff.mnemonicprefix", "true"));
cl_git_pass(git_diff_tree_to_index(&diff, g_repo, one, NULL, &opts));
cl_assert_equal_i(1, (int)git_diff_num_deltas(diff));
cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 0));
cl_git_pass(git_diff_patch_to_str(&text, patch));
cl_assert_equal_s(expected1, text);
git__free(text);
git_diff_patch_free(patch);
git_diff_list_free(diff);
cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
cl_assert_equal_i(1, (int)git_diff_num_deltas(diff));
cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 0));
cl_git_pass(git_diff_patch_to_str(&text, patch));
cl_assert_equal_s(expected2, text);
git__free(text);
git_diff_patch_free(patch);
git_diff_list_free(diff);
cl_git_pass(git_config_set_string(cfg, "diff.noprefix", "true"));
cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
cl_assert_equal_i(1, (int)git_diff_num_deltas(diff));
cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 0));
cl_git_pass(git_diff_patch_to_str(&text, patch));
cl_assert_equal_s(expected3, text);
git__free(text);
git_diff_patch_free(patch);
git_diff_list_free(diff);
cl_git_pass(git_config_set_int32(cfg, "core.abbrev", 12));
cl_git_pass(git_diff_tree_to_index(&diff, g_repo, one, NULL, &opts));
cl_assert_equal_i(1, (int)git_diff_num_deltas(diff));
cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 0));
cl_git_pass(git_diff_patch_to_str(&text, patch));
cl_assert_equal_s(expected4, text);
git__free(text);
git_diff_patch_free(patch);
git_diff_list_free(diff);
git_tree_free(one);
git_config_free(cfg);
}
void test_diff_patch__hunks_have_correct_line_numbers(void) void test_diff_patch__hunks_have_correct_line_numbers(void)
{ {
git_config *cfg; git_config *cfg;
......
...@@ -454,3 +454,77 @@ void test_diff_tree__issue_1397(void) ...@@ -454,3 +454,77 @@ void test_diff_tree__issue_1397(void)
cl_assert_equal_i(0, expect.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(0, expect.file_status[GIT_DELTA_ADDED]);
cl_assert_equal_i(0, expect.file_status[GIT_DELTA_TYPECHANGE]); cl_assert_equal_i(0, expect.file_status[GIT_DELTA_TYPECHANGE]);
} }
static void set_config_int(git_repository *repo, const char *name, int value)
{
git_config *cfg;
cl_git_pass(git_repository_config(&cfg, repo));
cl_git_pass(git_config_set_int32(cfg, name, value));
git_config_free(cfg);
}
void test_diff_tree__diff_configs(void)
{
const char *a_commit = "d70d245e";
const char *b_commit = "7a9e0b02";
g_repo = cl_git_sandbox_init("diff");
cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL);
cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL);
cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, NULL));
cl_git_pass(git_diff_foreach(
diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &expect));
cl_assert_equal_i(2, expect.files);
cl_assert_equal_i(2, expect.file_status[GIT_DELTA_MODIFIED]);
cl_assert_equal_i(6, expect.hunks);
cl_assert_equal_i(55, expect.lines);
cl_assert_equal_i(33, expect.line_ctxt);
cl_assert_equal_i(7, expect.line_adds);
cl_assert_equal_i(15, expect.line_dels);
git_diff_list_free(diff);
diff = NULL;
set_config_int(g_repo, "diff.context", 1);
memset(&expect, 0, sizeof(expect));
cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, NULL));
cl_git_pass(git_diff_foreach(
diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &expect));
cl_assert_equal_i(2, expect.files);
cl_assert_equal_i(2, expect.file_status[GIT_DELTA_MODIFIED]);
cl_assert_equal_i(7, expect.hunks);
cl_assert_equal_i(34, expect.lines);
cl_assert_equal_i(12, expect.line_ctxt);
cl_assert_equal_i(7, expect.line_adds);
cl_assert_equal_i(15, expect.line_dels);
git_diff_list_free(diff);
diff = NULL;
set_config_int(g_repo, "diff.context", 0);
set_config_int(g_repo, "diff.noprefix", 1);
memset(&expect, 0, sizeof(expect));
cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, NULL));
cl_git_pass(git_diff_foreach(
diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &expect));
cl_assert_equal_i(2, expect.files);
cl_assert_equal_i(2, expect.file_status[GIT_DELTA_MODIFIED]);
cl_assert_equal_i(7, expect.hunks);
cl_assert_equal_i(22, expect.lines);
cl_assert_equal_i(0, expect.line_ctxt);
cl_assert_equal_i(7, expect.line_adds);
cl_assert_equal_i(15, expect.line_dels);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment