diff options
-rw-r--r-- | src/checkout.c | 23 | ||||
-rw-r--r-- | src/config.c | 11 | ||||
-rw-r--r-- | src/config_cache.c | 31 | ||||
-rw-r--r-- | src/diff.c | 230 | ||||
-rw-r--r-- | src/diff_output.c | 17 | ||||
-rw-r--r-- | src/ignore.c | 38 | ||||
-rw-r--r-- | src/ignore.h | 2 | ||||
-rw-r--r-- | src/index.c | 17 | ||||
-rw-r--r-- | src/repository.h | 25 | ||||
-rw-r--r-- | tests-clar/diff/patch.c | 78 | ||||
-rw-r--r-- | tests-clar/diff/tree.c | 74 |
11 files changed, 396 insertions, 150 deletions
diff --git a/src/checkout.c b/src/checkout.c index 62a73d6d0..e29fccd05 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -1119,7 +1119,6 @@ static int checkout_data_init( git_checkout_opts *proposed) { int error = 0; - git_config *cfg; git_repository *repo = git_iterator_owner(target); memset(data, 0, sizeof(*data)); @@ -1132,9 +1131,6 @@ static int checkout_data_init( if ((error = git_repository__ensure_not_bare(repo, "checkout")) < 0) return error; - if ((error = git_repository_config__weakptr(&cfg, repo)) < 0) - return error; - data->repo = repo; GITERR_CHECK_VERSION( @@ -1147,7 +1143,10 @@ static int checkout_data_init( /* refresh config and index content unless NO_REFRESH is given */ 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; /* if we are checking out the index, don't reload, @@ -1184,19 +1183,13 @@ static int checkout_data_init( data->pfx = git_pathspec_prefix(&data->opts.paths); - error = git_config_get_bool(&data->can_symlink, cfg, "core.symlinks"); - if (error < 0) { - if (error != GIT_ENOTFOUND) - goto cleanup; - - /* If "core.symlinks" is not found anywhere, default to true. */ - data->can_symlink = true; - giterr_clear(); - error = 0; - } + if ((error = git_repository__cvar( + &data->can_symlink, repo, GIT_CVAR_SYMLINKS)) < 0) + goto cleanup; if (!data->opts.baseline) { data->opts_free_baseline = true; + error = checkout_lookup_head_tree(&data->opts.baseline, repo); if (error == GIT_EORPHANEDHEAD) { diff --git a/src/config.c b/src/config.c index 1283522ca..3c0bbe9a7 100644 --- a/src/config.c +++ b/src/config.c @@ -293,6 +293,9 @@ int git_config_refresh(git_config *cfg) error = file->refresh(file); } + if (!error && GIT_REFCOUNT_OWNER(cfg) != NULL) + git_repository__cvar_cache_clear(GIT_REFCOUNT_OWNER(cfg)); + return error; } @@ -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 error; git_config_backend *file; file_internal *internal; @@ -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); 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; } /*********** diff --git a/src/config_cache.c b/src/config_cache.c index 2f36df7d1..84de3a5ed 100644 --- a/src/config_cache.c +++ b/src/config_cache.c @@ -26,7 +26,7 @@ struct map_data { * files that have the text property set. Alternatives are lf, crlf * and native, which uses the platform's native line ending. The default * 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[] = { {GIT_CVAR_FALSE, NULL, GIT_EOL_UNSET}, @@ -37,7 +37,7 @@ static git_cvar_map _cvar_map_eol[] = { /* * 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 * not guaranteed to be normalized: files that contain CRLF in the * repository will not be touched. Use this setting if you want to have @@ -51,9 +51,22 @@ static git_cvar_map _cvar_map_autocrlf[] = { {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[] = { {"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) @@ -69,12 +82,16 @@ int git_repository__cvar(int *out, git_repository *repo, git_cvar_cached cvar) if (error < 0) return error; - error = git_config_get_mapped(out, - config, data->cvar_name, data->maps, data->map_count); + if (data->maps) + 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; - + } else if (error < 0) return error; diff --git a/src/diff.c b/src/diff.c index 37c89f3f1..881173cde 100644 --- a/src/diff.c +++ b/src/diff.c @@ -14,6 +14,8 @@ #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_SET(DIFF,FLAG,VAL) (DIFF)->opts.flags = \ + (VAL) ? ((DIFF)->opts.flags | (FLAG)) : ((DIFF)->opts.flags & ~(VAL)) static git_diff_delta *diff_delta__alloc( git_diff_list *diff, @@ -267,67 +269,158 @@ static int config_bool(git_config *cfg, const char *name, int defvalue) return val; } -static git_diff_list *git_diff_list_alloc( - git_repository *repo, const git_diff_options *opts) +static int config_int(git_config *cfg, const char *name, int defvalue) { - 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)); - if (diff == NULL) + if (!diff) return NULL; + assert(repo && old_iter && new_iter); + GIT_REFCOUNT_INC(diff); 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 || - git_pool_init(&diff->pool, 1, 0) < 0) - goto fail; + git_pool_init(&diff->pool, 1, 0) < 0) { + 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 */ if (git_repository_config__weakptr(&cfg, repo) < 0) - goto fail; - if (config_bool(cfg, "core.symlinks", 1)) + return -1; + + if (!git_repository__cvar(&val, repo, GIT_CVAR_SYMLINKS) && val) 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; - 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; - 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; + /* Don't set GIT_DIFFCAPS_USE_DEV - compile time option in core git */ - /* TODO: there are certain config settings where even if we were - * not given an options structure, we need the diff list to have one - * so that we can store the altered default values. - * - * - diff.ignoreSubmodules - * - diff.mnemonicprefix - * - diff.noprefix - */ + /* If not given explicit `opts`, check `diff.xyz` configs */ + if (!opts) { + diff->opts.context_lines = config_int(cfg, "diff.context", 3); - if (opts == NULL) { - /* Make sure we default to 3 lines */ - diff->opts.context_lines = 3; - return diff; + if (config_bool(cfg, "diff.ignoreSubmodules", 0)) + diff->opts.flags |= GIT_DIFF_IGNORE_SUBMODULES; } - memcpy(&diff->opts, opts, sizeof(git_diff_options)); - - if(opts->flags & GIT_DIFF_IGNORE_FILEMODE) - diff->diffcaps = diff->diffcaps & ~GIT_DIFFCAPS_TRUST_MODE_BITS; - - /* pathspec init will do nothing for empty pathspec */ - if (git_pathspec_init(&diff->pathspec, &opts->pathspec, &diff->pool) < 0) - goto fail; + /* if either prefix is not set, figure out appropriate value */ + if (!diff->opts.old_prefix || !diff->opts.new_prefix) { + const char *use_old = DIFF_OLD_PREFIX_DEFAULT; + const char *use_new = DIFF_NEW_PREFIX_DEFAULT; - /* 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, - opts->old_prefix ? opts->old_prefix : DIFF_OLD_PREFIX_DEFAULT); - diff->opts.new_prefix = diff_strdup_prefix(&diff->pool, - opts->new_prefix ? opts->new_prefix : DIFF_NEW_PREFIX_DEFAULT); + if (!diff->opts.old_prefix) + diff->opts.old_prefix = use_old; + if (!diff->opts.new_prefix) + 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) - goto fail; + return -1; if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_REVERSE)) { const char *swap = diff->opts.old_prefix; @@ -335,15 +428,7 @@ static git_diff_list *git_diff_list_alloc( diff->opts.new_prefix = swap; } - /* INCLUDE_TYPECHANGE_TREES implies INCLUDE_TYPECHANGE */ - 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; + return 0; } static void diff_list_free(git_diff_list *diff) @@ -607,37 +692,6 @@ static bool entry_is_prefixed( 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( git_diff_list **diff_ptr, git_repository *repo, @@ -648,20 +702,22 @@ int git_diff__from_iterators( int error = 0; const git_index_entry *oitem, *nitem; git_buf ignore_prefix = GIT_BUF_INIT; - git_diff_list *diff = git_diff_list_alloc(repo, opts); + git_diff_list *diff; *diff_ptr = NULL; - if (!diff || diff_list_init_from_iterators(diff, old_iter, new_iter) < 0) - goto fail; + diff = diff_list_alloc(repo, old_iter, new_iter); + GITERR_CHECK_ALLOC(diff); + /* make iterators have matching icase behavior */ if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE)) { if (git_iterator_set_ignore_case(old_iter, true) < 0 || git_iterator_set_ignore_case(new_iter, true) < 0) 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) goto fail; @@ -859,12 +915,20 @@ int git_diff_tree_to_tree( const git_diff_options *opts) { int error = 0; + git_iterator_flag_t iflag = GIT_ITERATOR_DONT_IGNORE_CASE; 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( - git_iterator_for_tree(&a, old_tree, 0, pfx, pfx), - git_iterator_for_tree(&b, new_tree, 0, pfx, pfx) + git_iterator_for_tree(&a, old_tree, iflag, pfx, pfx), + git_iterator_for_tree(&b, new_tree, iflag, pfx, pfx) ); return error; diff --git a/src/diff_output.c b/src/diff_output.c index 34a3e506c..b8bb73bf7 100644 --- a/src/diff_output.c +++ b/src/diff_output.c @@ -1114,11 +1114,20 @@ int git_diff_print_compact( 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 */ - git_oid_tostr(start_oid, sizeof(start_oid), &delta->old_file.oid); - git_oid_tostr(end_oid, sizeof(end_oid), &delta->new_file.oid); + if (git_repository__cvar(&abbrevlen, pi->diff->repo, GIT_CVAR_ABBREV) < 0) + return -1; + + 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 */ if (delta->old_file.mode == delta->new_file.mode) { diff --git a/src/ignore.c b/src/ignore.c index 17779522c..e150b9585 100644 --- a/src/ignore.c +++ b/src/ignore.c @@ -15,24 +15,14 @@ static int parse_ignore_file( git_attr_fnmatch *match = NULL; const char *scan = NULL; char *context = NULL; - bool 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); + int ignore_case = false; - 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) { context = ignores->key + 2; @@ -109,8 +99,6 @@ int git_ignore__for_path( { int error = 0; const char *workdir = git_repository_workdir(repo); - git_config *cfg = NULL; - int val; assert(ignores); @@ -118,17 +106,11 @@ int git_ignore__for_path( git_buf_init(&ignores->dir, 0); ignores->ign_internal = NULL; - /* Set the ignore_case flag appropriately */ - if ((error = git_repository_config(&cfg, repo)) < 0) + /* Read the ignore_case flag */ + if ((error = git_repository__cvar( + &ignores->ignore_case, repo, GIT_CVAR_IGNORECASE)) < 0) 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 || (error = git_vector_init(&ignores->ign_global, 2, NULL)) < 0 || (error = git_attr_cache__init(repo)) < 0) diff --git a/src/ignore.h b/src/ignore.h index 5af8e8e7d..e00e4a8c8 100644 --- a/src/ignore.h +++ b/src/ignore.h @@ -28,7 +28,7 @@ typedef struct { git_attr_file *ign_internal; git_vector ign_path; git_vector ign_global; - unsigned int ignore_case:1; + int ignore_case; } git_ignores; extern int git_ignore__for_path(git_repository *repo, const char *path, git_ignores *ign); diff --git a/src/index.c b/src/index.c index 2afd28158..d8ca78e52 100644 --- a/src/index.c +++ b/src/index.c @@ -330,7 +330,7 @@ void git_index_clear(git_index *index) git_vector_clear(&index->entries); git_index_reuc_clear(index); - + git_futils_filestamp_set(&index->stamp, NULL); git_tree_cache_free(index->tree); @@ -352,19 +352,18 @@ int git_index_set_caps(git_index *index, unsigned int caps) old_ignore_case = index->ignore_case; if (caps == GIT_INDEXCAP_FROM_OWNER) { - git_config *cfg; + git_repository *repo = INDEX_OWNER(index); int val; - if (INDEX_OWNER(index) == NULL || - git_repository_config__weakptr(&cfg, INDEX_OWNER(index)) < 0) - return create_index_error(-1, - "Cannot get repository config to set index caps"); + if (!repo) + return create_index_error( + -1, "Cannot access repository 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); - if (git_config_get_bool(&val, cfg, "core.filemode") == 0) + if (!git_repository__cvar(&val, repo, GIT_CVAR_FILEMODE)) 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); } else { diff --git a/src/repository.h b/src/repository.h index cc2f8c2b8..f7f9ecb1f 100644 --- a/src/repository.h +++ b/src/repository.h @@ -12,6 +12,7 @@ #include "git2/odb.h" #include "git2/repository.h" #include "git2/object.h" +#include "git2/config.h" #include "index.h" #include "cache.h" @@ -31,7 +32,13 @@ /** Cvar cache identifiers */ typedef enum { 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_cached; @@ -67,7 +74,21 @@ typedef enum { #else GIT_EOL_NATIVE = GIT_EOL_LF, #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; /* internal repository init flags */ diff --git a/tests-clar/diff/patch.c b/tests-clar/diff/patch.c index d41f3f12d..40b191dd5 100644 --- a/tests-clar/diff/patch.c +++ b/tests-clar/diff/patch.c @@ -135,6 +135,84 @@ void test_diff_patch__to_string(void) 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) { git_config *cfg; diff --git a/tests-clar/diff/tree.c b/tests-clar/diff/tree.c index 850feefde..f05c7869e 100644 --- a/tests-clar/diff/tree.c +++ b/tests-clar/diff/tree.c @@ -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_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); +} |