mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-01 23:50:11 +00:00
Add config level support in the config API
Added `struct git_config_entry`: a git_config_entry contains the key, the value, and the config file level from which a config element was found. Added `git_config_open_level`: build a single-level focused config object from a multi-level one. We are now storing `git_config_entry`s in the khash of the config_file
This commit is contained in:
parent
f8ede94808
commit
a1abe66aca
@ -19,6 +19,28 @@
|
||||
*/
|
||||
GIT_BEGIN_DECL
|
||||
|
||||
/**
|
||||
* Priority level of a config file.
|
||||
* These priority levels correspond to the natural escalation logic
|
||||
* (from higher to lower) when searching for config entries in git.git.
|
||||
*
|
||||
* git_config_open_default() and git_repository_config() honor those
|
||||
* priority levels as well.
|
||||
*/
|
||||
enum {
|
||||
GIT_CONFIG_LEVEL_SYSTEM = 1, /**< System-wide configuration file. */
|
||||
GIT_CONFIG_LEVEL_XDG = 2, /**< XDG compatible configuration file (.config/git/config). */
|
||||
GIT_CONFIG_LEVEL_GLOBAL = 3, /**< User-specific configuration file, also called Global configuration file. */
|
||||
GIT_CONFIG_LEVEL_LOCAL = 4, /**< Repository specific configuration file. */
|
||||
GIT_CONFIG_HIGHEST_LEVEL = -1, /**< Represents the highest level of a config file. */
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
const char *value;
|
||||
unsigned int level;
|
||||
} git_config_entry;
|
||||
|
||||
/**
|
||||
* Generic backend that implements the interface to
|
||||
* access a configuration file
|
||||
@ -27,13 +49,13 @@ struct git_config_file {
|
||||
struct git_config *cfg;
|
||||
|
||||
/* Open means open the file/database and parse if necessary */
|
||||
int (*open)(struct git_config_file *);
|
||||
int (*get)(struct git_config_file *, const char *key, const char **value);
|
||||
int (*get_multivar)(struct git_config_file *, const char *key, const char *regexp, int (*fn)(const char *, void *), void *data);
|
||||
int (*open)(struct git_config_file *, unsigned int level);
|
||||
int (*get)(struct git_config_file *, const char *key, const git_config_entry **entry);
|
||||
int (*get_multivar)(struct git_config_file *, const char *key, const char *regexp, int (*fn)(const git_config_entry *, void *), void *data);
|
||||
int (*set)(struct git_config_file *, const char *key, const char *value);
|
||||
int (*set_multivar)(git_config_file *cfg, const char *name, const char *regexp, const char *value);
|
||||
int (*del)(struct git_config_file *, const char *key);
|
||||
int (*foreach)(struct git_config_file *, const char *, int (*fn)(const char *, const char *, void *), void *data);
|
||||
int (*foreach)(struct git_config_file *, const char *, int (*fn)(const git_config_entry *, void *), void *data);
|
||||
void (*free)(struct git_config_file *);
|
||||
};
|
||||
|
||||
@ -100,9 +122,9 @@ GIT_EXTERN(int) git_config_find_xdg(char *xdg_config_path, size_t length);
|
||||
GIT_EXTERN(int) git_config_find_system(char *system_config_path, size_t length);
|
||||
|
||||
/**
|
||||
* Open the global and system configuration files
|
||||
* Open the global, XDG and system configuration files
|
||||
*
|
||||
* Utility wrapper that finds the global and system configuration files
|
||||
* Utility wrapper that finds the global, XDG and system configuration files
|
||||
* and opens them into a single prioritized config object that can be
|
||||
* used when accessing default config data outside a repository.
|
||||
*
|
||||
@ -143,14 +165,21 @@ GIT_EXTERN(int) git_config_new(git_config **out);
|
||||
*
|
||||
* Further queries on this config object will access each
|
||||
* of the config file instances in order (instances with
|
||||
* a higher priority will be accessed first).
|
||||
* a higher priority level will be accessed first).
|
||||
*
|
||||
* @param cfg the configuration to add the file to
|
||||
* @param file the configuration file (backend) to add
|
||||
* @param priority the priority the backend should have
|
||||
* @return 0 or an error code
|
||||
* @param level the priority level of the backend
|
||||
* @param force if a config file already exists for the given
|
||||
* priority level, replace it
|
||||
* @return 0 on success, GIT_EEXISTS when adding more than one file
|
||||
* for a given priority level (and force_replace set to 0), or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_add_file(git_config *cfg, git_config_file *file, int priority);
|
||||
GIT_EXTERN(int) git_config_add_file(
|
||||
git_config *cfg,
|
||||
git_config_file *file,
|
||||
unsigned int level,
|
||||
int force);
|
||||
|
||||
/**
|
||||
* Add an on-disk config file instance to an existing config
|
||||
@ -164,14 +193,21 @@ GIT_EXTERN(int) git_config_add_file(git_config *cfg, git_config_file *file, int
|
||||
*
|
||||
* Further queries on this config object will access each
|
||||
* of the config file instances in order (instances with
|
||||
* a higher priority will be accessed first).
|
||||
* a higher priority level will be accessed first).
|
||||
*
|
||||
* @param cfg the configuration to add the file to
|
||||
* @param path path to the configuration file (backend) to add
|
||||
* @param priority the priority the backend should have
|
||||
* @return 0 or an error code
|
||||
* @param level the priority level of the backend
|
||||
* @param force if a config file already exists for the given
|
||||
* priority level, replace it
|
||||
* @return 0 on success, GIT_EEXISTS when adding more than one file
|
||||
* for a given priority level (and force_replace set to 0), or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_add_file_ondisk(git_config *cfg, const char *path, int priority);
|
||||
GIT_EXTERN(int) git_config_add_file_ondisk(
|
||||
git_config *cfg,
|
||||
const char *path,
|
||||
unsigned int level,
|
||||
int force);
|
||||
|
||||
|
||||
/**
|
||||
@ -188,6 +224,24 @@ GIT_EXTERN(int) git_config_add_file_ondisk(git_config *cfg, const char *path, in
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_open_ondisk(git_config **cfg, const char *path);
|
||||
|
||||
/**
|
||||
* Build a single-level focused config object from a multi-level one.
|
||||
*
|
||||
* The returned config object can be used to perform get/set/delete operations
|
||||
* on a single specific level.
|
||||
*
|
||||
* Getting several times the same level from the same parent multi-level config
|
||||
* will return different config instances, but containing the same config_file
|
||||
* instance.
|
||||
*
|
||||
* @return 0, GIT_ENOTFOUND if the passed level cannot be found in the
|
||||
* multi-level parent config, or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_open_level(
|
||||
git_config **cfg_out,
|
||||
git_config *cfg_parent,
|
||||
unsigned int level);
|
||||
|
||||
/**
|
||||
* Free the configuration and its associated memory and files
|
||||
*
|
||||
@ -195,9 +249,26 @@ GIT_EXTERN(int) git_config_open_ondisk(git_config **cfg, const char *path);
|
||||
*/
|
||||
GIT_EXTERN(void) git_config_free(git_config *cfg);
|
||||
|
||||
/**
|
||||
* Get the git_config_entry of a config variable.
|
||||
*
|
||||
* The git_config_entry is owned by the config and should not be freed by the
|
||||
* user.
|
||||
|
||||
* @param out pointer to the variable git_config_entry
|
||||
* @param cfg where to look for the variable
|
||||
* @param name the variable's name
|
||||
* @return 0 or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_get_config_entry(const git_config_entry **out, git_config *cfg, const char *name);
|
||||
|
||||
/**
|
||||
* Get the value of an integer config variable.
|
||||
*
|
||||
* All config files will be looked into, in the order of their
|
||||
* defined level. A higher level means a higher priority. The
|
||||
* first occurence of the variable will be returned here.
|
||||
*
|
||||
* @param out pointer to the variable where the value should be stored
|
||||
* @param cfg where to look for the variable
|
||||
* @param name the variable's name
|
||||
@ -208,6 +279,10 @@ GIT_EXTERN(int) git_config_get_int32(int32_t *out, git_config *cfg, const char *
|
||||
/**
|
||||
* Get the value of a long integer config variable.
|
||||
*
|
||||
* All config files will be looked into, in the order of their
|
||||
* defined level. A higher level means a higher priority. The
|
||||
* first occurence of the variable will be returned here.
|
||||
*
|
||||
* @param out pointer to the variable where the value should be stored
|
||||
* @param cfg where to look for the variable
|
||||
* @param name the variable's name
|
||||
@ -221,6 +296,10 @@ GIT_EXTERN(int) git_config_get_int64(int64_t *out, git_config *cfg, const char *
|
||||
* This function uses the usual C convention of 0 being false and
|
||||
* anything else true.
|
||||
*
|
||||
* All config files will be looked into, in the order of their
|
||||
* defined level. A higher level means a higher priority. The
|
||||
* first occurence of the variable will be returned here.
|
||||
*
|
||||
* @param out pointer to the variable where the value should be stored
|
||||
* @param cfg where to look for the variable
|
||||
* @param name the variable's name
|
||||
@ -234,6 +313,10 @@ GIT_EXTERN(int) git_config_get_bool(int *out, git_config *cfg, const char *name)
|
||||
* The string is owned by the variable and should not be freed by the
|
||||
* user.
|
||||
*
|
||||
* All config files will be looked into, in the order of their
|
||||
* defined level. A higher level means a higher priority. The
|
||||
* first occurence of the variable will be returned here.
|
||||
*
|
||||
* @param out pointer to the variable's value
|
||||
* @param cfg where to look for the variable
|
||||
* @param name the variable's name
|
||||
@ -253,10 +336,11 @@ GIT_EXTERN(int) git_config_get_string(const char **out, git_config *cfg, const c
|
||||
* @param fn the function to be called on each value of the variable
|
||||
* @param data opaque pointer to pass to the callback
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_get_multivar(git_config *cfg, const char *name, const char *regexp, int (*fn)(const char *, void *), void *data);
|
||||
GIT_EXTERN(int) git_config_get_multivar(git_config *cfg, const char *name, const char *regexp, int (*fn)(const git_config_entry *, void *), void *data);
|
||||
|
||||
/**
|
||||
* Set the value of an integer config variable.
|
||||
* Set the value of an integer config variable in the config file
|
||||
* with the highest level (usually the local one).
|
||||
*
|
||||
* @param cfg where to look for the variable
|
||||
* @param name the variable's name
|
||||
@ -266,7 +350,8 @@ GIT_EXTERN(int) git_config_get_multivar(git_config *cfg, const char *name, const
|
||||
GIT_EXTERN(int) git_config_set_int32(git_config *cfg, const char *name, int32_t value);
|
||||
|
||||
/**
|
||||
* Set the value of a long integer config variable.
|
||||
* Set the value of a long integer config variable in the config file
|
||||
* with the highest level (usually the local one).
|
||||
*
|
||||
* @param cfg where to look for the variable
|
||||
* @param name the variable's name
|
||||
@ -276,7 +361,8 @@ GIT_EXTERN(int) git_config_set_int32(git_config *cfg, const char *name, int32_t
|
||||
GIT_EXTERN(int) git_config_set_int64(git_config *cfg, const char *name, int64_t value);
|
||||
|
||||
/**
|
||||
* Set the value of a boolean config variable.
|
||||
* Set the value of a boolean config variable in the config file
|
||||
* with the highest level (usually the local one).
|
||||
*
|
||||
* @param cfg where to look for the variable
|
||||
* @param name the variable's name
|
||||
@ -286,7 +372,8 @@ GIT_EXTERN(int) git_config_set_int64(git_config *cfg, const char *name, int64_t
|
||||
GIT_EXTERN(int) git_config_set_bool(git_config *cfg, const char *name, int value);
|
||||
|
||||
/**
|
||||
* Set the value of a string config variable.
|
||||
* Set the value of a string config variable in the config file
|
||||
* with the highest level (usually the local one).
|
||||
*
|
||||
* A copy of the string is made and the user is free to use it
|
||||
* afterwards.
|
||||
@ -298,9 +385,8 @@ GIT_EXTERN(int) git_config_set_bool(git_config *cfg, const char *name, int value
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_set_string(git_config *cfg, const char *name, const char *value);
|
||||
|
||||
|
||||
/**
|
||||
* Set a multivar
|
||||
* Set a multivar in the local config file.
|
||||
*
|
||||
* @param cfg where to look for the variable
|
||||
* @param name the variable's name
|
||||
@ -310,7 +396,8 @@ GIT_EXTERN(int) git_config_set_string(git_config *cfg, const char *name, const c
|
||||
GIT_EXTERN(int) git_config_set_multivar(git_config *cfg, const char *name, const char *regexp, const char *value);
|
||||
|
||||
/**
|
||||
* Delete a config variable
|
||||
* Delete a config variable from the config file
|
||||
* with the highest level (usually the local one).
|
||||
*
|
||||
* @param cfg the configuration
|
||||
* @param name the variable to delete
|
||||
@ -332,7 +419,7 @@ GIT_EXTERN(int) git_config_delete(git_config *cfg, const char *name);
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_foreach(
|
||||
git_config *cfg,
|
||||
int (*callback)(const char *var_name, const char *value, void *payload),
|
||||
int (*callback)(const git_config_entry *, void *payload),
|
||||
void *payload);
|
||||
|
||||
/**
|
||||
@ -351,7 +438,7 @@ GIT_EXTERN(int) git_config_foreach(
|
||||
GIT_EXTERN(int) git_config_foreach_match(
|
||||
git_config *cfg,
|
||||
const char *regexp,
|
||||
int (*callback)(const char *var_name, const char *value, void *payload),
|
||||
int (*callback)(const git_config_entry *entry, void *payload),
|
||||
void *payload);
|
||||
|
||||
/**
|
||||
@ -390,6 +477,57 @@ GIT_EXTERN(int) git_config_foreach_match(
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_get_mapped(int *out, git_config *cfg, const char *name, git_cvar_map *maps, size_t map_n);
|
||||
|
||||
/**
|
||||
* Maps a string value to an integer constant
|
||||
*
|
||||
* @param out place to store the result of the parsing
|
||||
* @param maps array of `git_cvar_map` objects specifying the possible mappings
|
||||
* @param map_n number of mapping objects in `maps`
|
||||
* @param value value to parse
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_lookup_map_value(
|
||||
int *out,
|
||||
git_cvar_map *maps,
|
||||
size_t map_n,
|
||||
const char *value);
|
||||
|
||||
/**
|
||||
* Parse a string value as a bool.
|
||||
*
|
||||
* Valid values for true are: 'true', 'yes', 'on', 1 or any
|
||||
* number different from 0
|
||||
* Valid values for false are: 'false', 'no', 'off', 0
|
||||
*
|
||||
* @param out place to store the result of the parsing
|
||||
* @param value value to parse
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_parse_bool(int *out, const char *value);
|
||||
|
||||
/**
|
||||
* Parse a string value as an int64.
|
||||
*
|
||||
* An optional value suffix of 'k', 'm', or 'g' will
|
||||
* cause the value to be multiplied by 1024, 1048576,
|
||||
* or 1073741824 prior to output.
|
||||
*
|
||||
* @param out place to store the result of the parsing
|
||||
* @param value value to parse
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_parse_int64(int64_t *out, const char *value);
|
||||
|
||||
/**
|
||||
* Parse a string value as an int32.
|
||||
*
|
||||
* An optional value suffix of 'k', 'm', or 'g' will
|
||||
* cause the value to be multiplied by 1024, 1048576,
|
||||
* or 1073741824 prior to output.
|
||||
*
|
||||
* @param out place to store the result of the parsing
|
||||
* @param value value to parse
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_parse_int32(int32_t *out, const char *value);
|
||||
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
#endif
|
||||
|
502
src/config.c
502
src/config.c
@ -17,21 +17,29 @@
|
||||
#include <ctype.h>
|
||||
|
||||
typedef struct {
|
||||
git_refcount rc;
|
||||
|
||||
git_config_file *file;
|
||||
int priority;
|
||||
unsigned int level;
|
||||
} file_internal;
|
||||
|
||||
static void file_internal_free(file_internal *internal)
|
||||
{
|
||||
git_config_file *file;
|
||||
|
||||
file = internal->file;
|
||||
file->free(file);
|
||||
git__free(internal);
|
||||
}
|
||||
|
||||
static void config_free(git_config *cfg)
|
||||
{
|
||||
unsigned int i;
|
||||
git_config_file *file;
|
||||
file_internal *internal;
|
||||
|
||||
for(i = 0; i < cfg->files.length; ++i){
|
||||
internal = git_vector_get(&cfg->files, i);
|
||||
file = internal->file;
|
||||
file->free(file);
|
||||
git__free(internal);
|
||||
GIT_REFCOUNT_DEC(internal, file_internal_free);
|
||||
}
|
||||
|
||||
git_vector_free(&cfg->files);
|
||||
@ -51,7 +59,7 @@ static int config_backend_cmp(const void *a, const void *b)
|
||||
const file_internal *bk_a = (const file_internal *)(a);
|
||||
const file_internal *bk_b = (const file_internal *)(b);
|
||||
|
||||
return bk_b->priority - bk_a->priority;
|
||||
return bk_b->level - bk_a->level;
|
||||
}
|
||||
|
||||
int git_config_new(git_config **out)
|
||||
@ -73,20 +81,25 @@ int git_config_new(git_config **out)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_config_add_file_ondisk(git_config *cfg, const char *path, int priority)
|
||||
int git_config_add_file_ondisk(
|
||||
git_config *cfg,
|
||||
const char *path,
|
||||
unsigned int level,
|
||||
int force)
|
||||
{
|
||||
git_config_file *file = NULL;
|
||||
int res;
|
||||
|
||||
if (git_config_file__ondisk(&file, path) < 0)
|
||||
return -1;
|
||||
|
||||
if (git_config_add_file(cfg, file, priority) < 0) {
|
||||
if ((res = git_config_add_file(cfg, file, level, force)) < 0) {
|
||||
/*
|
||||
* free manually; the file is not owned by the config
|
||||
* instance yet and will not be freed on cleanup
|
||||
*/
|
||||
file->free(file);
|
||||
return -1;
|
||||
return res;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -97,7 +110,7 @@ int git_config_open_ondisk(git_config **cfg, const char *path)
|
||||
if (git_config_new(cfg) < 0)
|
||||
return -1;
|
||||
|
||||
if (git_config_add_file_ondisk(*cfg, path, 1) < 0) {
|
||||
if (git_config_add_file_ondisk(*cfg, path, GIT_CONFIG_LEVEL_LOCAL, 0) < 0) {
|
||||
git_config_free(*cfg);
|
||||
return -1;
|
||||
}
|
||||
@ -105,30 +118,152 @@ int git_config_open_ondisk(git_config **cfg, const char *path)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_config_add_file(git_config *cfg, git_config_file *file, int priority)
|
||||
static int find_internal_file_by_level(
|
||||
file_internal **internal_out,
|
||||
git_config *cfg,
|
||||
int level)
|
||||
{
|
||||
int pos = -1;
|
||||
file_internal *internal;
|
||||
unsigned int i;
|
||||
|
||||
assert(cfg->files.length);
|
||||
|
||||
/* when passing GIT_CONFIG_HIGHEST_LEVEL, the idea is to get the config file
|
||||
* which has the highest level. As config files are stored in a vector
|
||||
* sorted by decreasing order of level, getting the file at position 0
|
||||
* will do the job.
|
||||
*/
|
||||
if (level == GIT_CONFIG_HIGHEST_LEVEL) {
|
||||
pos = 0;
|
||||
} else {
|
||||
git_vector_foreach(&cfg->files, i, internal) {
|
||||
if (internal->level == (unsigned int)level)
|
||||
pos = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos == -1) {
|
||||
giterr_set(GITERR_CONFIG,
|
||||
"No config file exists for the given level '%i'", level);
|
||||
return GIT_ENOTFOUND;
|
||||
}
|
||||
|
||||
*internal_out = git_vector_get(&cfg->files, pos);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int duplicate_level(void **old_raw, void *new_raw)
|
||||
{
|
||||
file_internal **old = (file_internal **)old_raw;
|
||||
|
||||
GIT_UNUSED(new_raw);
|
||||
|
||||
giterr_set(GITERR_CONFIG, "A file with the same level (%i) has already been added to the config", (*old)->level);
|
||||
return GIT_EEXISTS;
|
||||
}
|
||||
|
||||
static void try_remove_existing_file_internal(
|
||||
git_config *cfg,
|
||||
unsigned int level)
|
||||
{
|
||||
int pos = -1;
|
||||
file_internal *internal;
|
||||
unsigned int i;
|
||||
|
||||
git_vector_foreach(&cfg->files, i, internal) {
|
||||
if (internal->level == level)
|
||||
pos = i;
|
||||
}
|
||||
|
||||
if (pos == -1)
|
||||
return;
|
||||
|
||||
internal = git_vector_get(&cfg->files, pos);
|
||||
|
||||
if (git_vector_remove(&cfg->files, pos) < 0)
|
||||
return;
|
||||
|
||||
GIT_REFCOUNT_DEC(internal, file_internal_free);
|
||||
}
|
||||
|
||||
static int git_config__add_internal(
|
||||
git_config *cfg,
|
||||
file_internal *internal,
|
||||
unsigned int level,
|
||||
int force)
|
||||
{
|
||||
int result;
|
||||
|
||||
/* delete existing config file for level if it exists */
|
||||
if (force)
|
||||
try_remove_existing_file_internal(cfg, level);
|
||||
|
||||
if ((result = git_vector_insert_sorted(&cfg->files,
|
||||
internal, &duplicate_level)) < 0)
|
||||
return result;
|
||||
|
||||
git_vector_sort(&cfg->files);
|
||||
internal->file->cfg = cfg;
|
||||
|
||||
GIT_REFCOUNT_INC(internal);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_config_open_level(
|
||||
git_config **cfg_out,
|
||||
git_config *cfg_parent,
|
||||
unsigned int level)
|
||||
{
|
||||
git_config *cfg;
|
||||
file_internal *internal;
|
||||
int res;
|
||||
|
||||
if ((res = find_internal_file_by_level(&internal, cfg_parent, level)) < 0)
|
||||
return res;
|
||||
|
||||
if ((res = git_config_new(&cfg)) < 0)
|
||||
return res;
|
||||
|
||||
if ((res = git_config__add_internal(cfg, internal, level, true)) < 0) {
|
||||
git_config_free(cfg);
|
||||
return res;
|
||||
}
|
||||
|
||||
*cfg_out = cfg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_config_add_file(
|
||||
git_config *cfg,
|
||||
git_config_file *file,
|
||||
unsigned int level,
|
||||
int force)
|
||||
{
|
||||
file_internal *internal;
|
||||
int result;
|
||||
|
||||
assert(cfg && file);
|
||||
|
||||
if ((result = file->open(file)) < 0)
|
||||
if ((result = file->open(file, level)) < 0)
|
||||
return result;
|
||||
|
||||
internal = git__malloc(sizeof(file_internal));
|
||||
GITERR_CHECK_ALLOC(internal);
|
||||
|
||||
memset(internal, 0x0, sizeof(file_internal));
|
||||
|
||||
internal->file = file;
|
||||
internal->priority = priority;
|
||||
internal->level = level;
|
||||
|
||||
if (git_vector_insert(&cfg->files, internal) < 0) {
|
||||
if ((result = git_config__add_internal(cfg, internal, level, force)) < 0) {
|
||||
git__free(internal);
|
||||
return -1;
|
||||
return result;
|
||||
}
|
||||
|
||||
git_vector_sort(&cfg->files);
|
||||
internal->file->cfg = cfg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -137,7 +272,7 @@ int git_config_add_file(git_config *cfg, git_config_file *file, int priority)
|
||||
*/
|
||||
|
||||
int git_config_foreach(
|
||||
git_config *cfg, int (*fn)(const char *, const char *, void *), void *data)
|
||||
git_config *cfg, int (*fn)(const git_config_entry *, void *), void *data)
|
||||
{
|
||||
return git_config_foreach_match(cfg, NULL, fn, data);
|
||||
}
|
||||
@ -145,7 +280,7 @@ int git_config_foreach(
|
||||
int git_config_foreach_match(
|
||||
git_config *cfg,
|
||||
const char *regexp,
|
||||
int (*fn)(const char *, const char *, void *),
|
||||
int (*fn)(const git_config_entry *, void *),
|
||||
void *data)
|
||||
{
|
||||
int ret = 0;
|
||||
@ -164,10 +299,8 @@ int git_config_foreach_match(
|
||||
|
||||
int git_config_delete(git_config *cfg, const char *name)
|
||||
{
|
||||
file_internal *internal;
|
||||
git_config_file *file;
|
||||
|
||||
assert(cfg->files.length);
|
||||
file_internal *internal;
|
||||
|
||||
internal = git_vector_get(&cfg->files, 0);
|
||||
file = internal->file;
|
||||
@ -198,10 +331,8 @@ 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)
|
||||
{
|
||||
file_internal *internal;
|
||||
git_config_file *file;
|
||||
|
||||
assert(cfg->files.length);
|
||||
file_internal *internal;
|
||||
|
||||
internal = git_vector_get(&cfg->files, 0);
|
||||
file = internal->file;
|
||||
@ -209,105 +340,9 @@ int git_config_set_string(git_config *cfg, const char *name, const char *value)
|
||||
return file->set(file, name, value);
|
||||
}
|
||||
|
||||
static int parse_int64(int64_t *out, const char *value)
|
||||
{
|
||||
const char *num_end;
|
||||
int64_t num;
|
||||
|
||||
if (git__strtol64(&num, value, &num_end, 0) < 0)
|
||||
return -1;
|
||||
|
||||
switch (*num_end) {
|
||||
case 'g':
|
||||
case 'G':
|
||||
num *= 1024;
|
||||
/* fallthrough */
|
||||
|
||||
case 'm':
|
||||
case 'M':
|
||||
num *= 1024;
|
||||
/* fallthrough */
|
||||
|
||||
case 'k':
|
||||
case 'K':
|
||||
num *= 1024;
|
||||
|
||||
/* check that that there are no more characters after the
|
||||
* given modifier suffix */
|
||||
if (num_end[1] != '\0')
|
||||
return -1;
|
||||
|
||||
/* fallthrough */
|
||||
|
||||
case '\0':
|
||||
*out = num;
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int parse_int32(int32_t *out, const char *value)
|
||||
{
|
||||
int64_t tmp;
|
||||
int32_t truncate;
|
||||
|
||||
if (parse_int64(&tmp, value) < 0)
|
||||
return -1;
|
||||
|
||||
truncate = tmp & 0xFFFFFFFF;
|
||||
if (truncate != tmp)
|
||||
return -1;
|
||||
|
||||
*out = truncate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***********
|
||||
* Getters
|
||||
***********/
|
||||
int git_config_lookup_map_value(
|
||||
git_cvar_map *maps, size_t map_n, const char *value, int *out)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!value)
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
for (i = 0; i < map_n; ++i) {
|
||||
git_cvar_map *m = maps + i;
|
||||
|
||||
switch (m->cvar_type) {
|
||||
case GIT_CVAR_FALSE:
|
||||
case GIT_CVAR_TRUE: {
|
||||
int bool_val;
|
||||
|
||||
if (git__parse_bool(&bool_val, value) == 0 &&
|
||||
bool_val == (int)m->cvar_type) {
|
||||
*out = m->map_value;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case GIT_CVAR_INT32:
|
||||
if (parse_int32(out, value) == 0)
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case GIT_CVAR_STRING:
|
||||
if (strcasecmp(value, m->str_match) == 0) {
|
||||
*out = m->map_value;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return GIT_ENOTFOUND;
|
||||
}
|
||||
|
||||
int git_config_get_mapped(
|
||||
int *out,
|
||||
git_config *cfg,
|
||||
@ -318,16 +353,10 @@ int git_config_get_mapped(
|
||||
const char *value;
|
||||
int ret;
|
||||
|
||||
ret = git_config_get_string(&value, cfg, name);
|
||||
if (ret < 0)
|
||||
if ((ret = git_config_get_string(&value, cfg, name)) < 0)
|
||||
return ret;
|
||||
|
||||
if (!git_config_lookup_map_value(maps, map_n, value, out))
|
||||
return 0;
|
||||
|
||||
giterr_set(GITERR_CONFIG,
|
||||
"Failed to map the '%s' config variable with a valid value", name);
|
||||
return -1;
|
||||
return git_config_lookup_map_value(out, maps, map_n, value);
|
||||
}
|
||||
|
||||
int git_config_get_int64(int64_t *out, git_config *cfg, const char *name)
|
||||
@ -335,16 +364,10 @@ int git_config_get_int64(int64_t *out, git_config *cfg, const char *name)
|
||||
const char *value;
|
||||
int ret;
|
||||
|
||||
ret = git_config_get_string(&value, cfg, name);
|
||||
if (ret < 0)
|
||||
if ((ret = git_config_get_string(&value, cfg, name)) < 0)
|
||||
return ret;
|
||||
|
||||
if (parse_int64(out, value) < 0) {
|
||||
giterr_set(GITERR_CONFIG, "Failed to parse '%s' as an integer", value);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return git_config_parse_int64(out, value);
|
||||
}
|
||||
|
||||
int git_config_get_int32(int32_t *out, git_config *cfg, const char *name)
|
||||
@ -352,16 +375,10 @@ int git_config_get_int32(int32_t *out, git_config *cfg, const char *name)
|
||||
const char *value;
|
||||
int ret;
|
||||
|
||||
ret = git_config_get_string(&value, cfg, name);
|
||||
if (ret < 0)
|
||||
if ((ret = git_config_get_string(&value, cfg, name)) < 0)
|
||||
return ret;
|
||||
|
||||
if (parse_int32(out, value) < 0) {
|
||||
giterr_set(GITERR_CONFIG, "Failed to parse '%s' as a 32-bit integer", value);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return git_config_parse_int32(out, value);
|
||||
}
|
||||
|
||||
int git_config_get_bool(int *out, git_config *cfg, const char *name)
|
||||
@ -369,20 +386,24 @@ int git_config_get_bool(int *out, git_config *cfg, const char *name)
|
||||
const char *value;
|
||||
int ret;
|
||||
|
||||
ret = git_config_get_string(&value, cfg, name);
|
||||
if (ret < 0)
|
||||
if ((ret = git_config_get_string(&value, cfg, name)) < 0)
|
||||
return ret;
|
||||
|
||||
if (git__parse_bool(out, value) == 0)
|
||||
return 0;
|
||||
return git_config_parse_bool(out, value);
|
||||
}
|
||||
|
||||
if (parse_int32(out, value) == 0) {
|
||||
*out = !!(*out);
|
||||
return 0;
|
||||
}
|
||||
static int get_string_at_file(const char **out, git_config_file *file, const char *name)
|
||||
{
|
||||
const git_config_entry *entry;
|
||||
int res;
|
||||
|
||||
giterr_set(GITERR_CONFIG, "Failed to parse '%s' as a boolean value", value);
|
||||
return -1;
|
||||
*out = NULL;
|
||||
|
||||
res = file->get(file, name, &entry);
|
||||
if (res != GIT_ENOTFOUND)
|
||||
*out = entry->value;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int git_config_get_string(const char **out, git_config *cfg, const char *name)
|
||||
@ -392,6 +413,23 @@ int git_config_get_string(const char **out, git_config *cfg, const char *name)
|
||||
|
||||
assert(cfg->files.length);
|
||||
|
||||
git_vector_foreach(&cfg->files, i, internal) {
|
||||
int res = get_string_at_file(out, internal->file, name);
|
||||
|
||||
if (res != GIT_ENOTFOUND)
|
||||
return res;
|
||||
}
|
||||
|
||||
return GIT_ENOTFOUND;
|
||||
}
|
||||
|
||||
int git_config_get_config_entry(const git_config_entry **out, git_config *cfg, const char *name)
|
||||
{
|
||||
file_internal *internal;
|
||||
unsigned int i;
|
||||
|
||||
assert(cfg->files.length);
|
||||
|
||||
*out = NULL;
|
||||
|
||||
git_vector_foreach(&cfg->files, i, internal) {
|
||||
@ -405,7 +443,7 @@ int git_config_get_string(const char **out, git_config *cfg, const char *name)
|
||||
}
|
||||
|
||||
int git_config_get_multivar(git_config *cfg, const char *name, const char *regexp,
|
||||
int (*fn)(const char *value, void *data), void *data)
|
||||
int (*fn)(const git_config_entry *entry, void *data), void *data)
|
||||
{
|
||||
file_internal *internal;
|
||||
git_config_file *file;
|
||||
@ -431,20 +469,13 @@ int git_config_get_multivar(git_config *cfg, const char *name, const char *regex
|
||||
|
||||
int git_config_set_multivar(git_config *cfg, const char *name, const char *regexp, const char *value)
|
||||
{
|
||||
file_internal *internal;
|
||||
git_config_file *file;
|
||||
int ret = GIT_ENOTFOUND;
|
||||
size_t i;
|
||||
file_internal *internal;
|
||||
|
||||
for (i = cfg->files.length; i > 0; --i) {
|
||||
internal = git_vector_get(&cfg->files, i - 1);
|
||||
file = internal->file;
|
||||
ret = file->set_multivar(file, name, regexp, value);
|
||||
if (ret < 0 && ret != GIT_ENOTFOUND)
|
||||
return ret;
|
||||
}
|
||||
internal = git_vector_get(&cfg->files, 0);
|
||||
file = internal->file;
|
||||
|
||||
return 0;
|
||||
return file->set_multivar(file, name, regexp, value);
|
||||
}
|
||||
|
||||
int git_config_find_global_r(git_buf *path)
|
||||
@ -541,13 +572,16 @@ int git_config_open_default(git_config **out)
|
||||
error = git_config_new(&cfg);
|
||||
|
||||
if (!error && !git_config_find_global_r(&buf))
|
||||
error = git_config_add_file_ondisk(cfg, buf.ptr, 3);
|
||||
error = git_config_add_file_ondisk(cfg, buf.ptr,
|
||||
GIT_CONFIG_LEVEL_GLOBAL, 0);
|
||||
|
||||
if (!error && !git_config_find_xdg_r(&buf))
|
||||
error = git_config_add_file_ondisk(cfg, buf.ptr, 2);
|
||||
error = git_config_add_file_ondisk(cfg, buf.ptr,
|
||||
GIT_CONFIG_LEVEL_XDG, 0);
|
||||
|
||||
if (!error && !git_config_find_system_r(&buf))
|
||||
error = git_config_add_file_ondisk(cfg, buf.ptr, 1);
|
||||
error = git_config_add_file_ondisk(cfg, buf.ptr,
|
||||
GIT_CONFIG_LEVEL_SYSTEM, 0);
|
||||
|
||||
git_buf_free(&buf);
|
||||
|
||||
@ -560,3 +594,129 @@ int git_config_open_default(git_config **out)
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/***********
|
||||
* Parsers
|
||||
***********/
|
||||
int git_config_lookup_map_value(
|
||||
int *out,
|
||||
git_cvar_map *maps,
|
||||
size_t map_n,
|
||||
const char *value)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!value)
|
||||
goto fail_parse;
|
||||
|
||||
for (i = 0; i < map_n; ++i) {
|
||||
git_cvar_map *m = maps + i;
|
||||
|
||||
switch (m->cvar_type) {
|
||||
case GIT_CVAR_FALSE:
|
||||
case GIT_CVAR_TRUE: {
|
||||
int bool_val;
|
||||
|
||||
if (git__parse_bool(&bool_val, value) == 0 &&
|
||||
bool_val == (int)m->cvar_type) {
|
||||
*out = m->map_value;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case GIT_CVAR_INT32:
|
||||
if (git_config_parse_int32(out, value) == 0)
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case GIT_CVAR_STRING:
|
||||
if (strcasecmp(value, m->str_match) == 0) {
|
||||
*out = m->map_value;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fail_parse:
|
||||
giterr_set(GITERR_CONFIG, "Failed to map '%s'", value);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int git_config_parse_bool(int *out, const char *value)
|
||||
{
|
||||
if (git__parse_bool(out, value) == 0)
|
||||
return 0;
|
||||
|
||||
if (git_config_parse_int32(out, value) == 0) {
|
||||
*out = !!(*out);
|
||||
return 0;
|
||||
}
|
||||
|
||||
giterr_set(GITERR_CONFIG, "Failed to parse '%s' as a boolean value", value);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int git_config_parse_int64(int64_t *out, const char *value)
|
||||
{
|
||||
const char *num_end;
|
||||
int64_t num;
|
||||
|
||||
if (git__strtol64(&num, value, &num_end, 0) < 0)
|
||||
goto fail_parse;
|
||||
|
||||
switch (*num_end) {
|
||||
case 'g':
|
||||
case 'G':
|
||||
num *= 1024;
|
||||
/* fallthrough */
|
||||
|
||||
case 'm':
|
||||
case 'M':
|
||||
num *= 1024;
|
||||
/* fallthrough */
|
||||
|
||||
case 'k':
|
||||
case 'K':
|
||||
num *= 1024;
|
||||
|
||||
/* check that that there are no more characters after the
|
||||
* given modifier suffix */
|
||||
if (num_end[1] != '\0')
|
||||
return -1;
|
||||
|
||||
/* fallthrough */
|
||||
|
||||
case '\0':
|
||||
*out = num;
|
||||
return 0;
|
||||
|
||||
default:
|
||||
goto fail_parse;
|
||||
}
|
||||
|
||||
fail_parse:
|
||||
giterr_set(GITERR_CONFIG, "Failed to parse '%s' as an integer", value);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int git_config_parse_int32(int32_t *out, const char *value)
|
||||
{
|
||||
int64_t tmp;
|
||||
int32_t truncate;
|
||||
|
||||
if (git_config_parse_int64(&tmp, value) < 0)
|
||||
goto fail_parse;
|
||||
|
||||
truncate = tmp & 0xFFFFFFFF;
|
||||
if (truncate != tmp)
|
||||
goto fail_parse;
|
||||
|
||||
*out = truncate;
|
||||
return 0;
|
||||
|
||||
fail_parse:
|
||||
giterr_set(GITERR_CONFIG, "Failed to parse '%s' as a 32-bit integer", value);
|
||||
return -1;
|
||||
}
|
||||
|
@ -27,9 +27,4 @@ extern int git_config_find_global_r(git_buf *global_config_path);
|
||||
extern int git_config_find_xdg_r(git_buf *system_config_path);
|
||||
extern int git_config_find_system_r(git_buf *system_config_path);
|
||||
|
||||
extern int git_config_parse_bool(int *out, const char *bool_string);
|
||||
|
||||
extern int git_config_lookup_map_value(
|
||||
git_cvar_map *maps, size_t map_n, const char *value, int *out);
|
||||
|
||||
#endif
|
||||
|
@ -22,15 +22,9 @@ GIT__USE_STRMAP;
|
||||
|
||||
typedef struct cvar_t {
|
||||
struct cvar_t *next;
|
||||
char *key; /* TODO: we might be able to get rid of this */
|
||||
char *value;
|
||||
git_config_entry *entry;
|
||||
} cvar_t;
|
||||
|
||||
typedef struct {
|
||||
struct cvar_t *head;
|
||||
struct cvar_t *tail;
|
||||
} cvar_t_list;
|
||||
|
||||
#define CVAR_LIST_HEAD(list) ((list)->head)
|
||||
|
||||
#define CVAR_LIST_TAIL(list) ((list)->tail)
|
||||
@ -84,7 +78,7 @@ typedef struct {
|
||||
char *file_path;
|
||||
} diskfile_backend;
|
||||
|
||||
static int config_parse(diskfile_backend *cfg_file);
|
||||
static int config_parse(diskfile_backend *cfg_file, unsigned int level);
|
||||
static int parse_variable(diskfile_backend *cfg, char **var_name, char **var_value);
|
||||
static int config_write(diskfile_backend *cfg, const char *key, const regex_t *preg, const char *value);
|
||||
static char *escape_value(const char *ptr);
|
||||
@ -100,8 +94,9 @@ static void cvar_free(cvar_t *var)
|
||||
if (var == NULL)
|
||||
return;
|
||||
|
||||
git__free(var->key);
|
||||
git__free(var->value);
|
||||
git__free((char*)var->entry->name);
|
||||
git__free((char *)var->entry->value);
|
||||
git__free(var->entry);
|
||||
git__free(var);
|
||||
}
|
||||
|
||||
@ -150,7 +145,7 @@ static void free_vars(git_strmap *values)
|
||||
git_strmap_free(values);
|
||||
}
|
||||
|
||||
static int config_open(git_config_file *cfg)
|
||||
static int config_open(git_config_file *cfg, unsigned int level)
|
||||
{
|
||||
int res;
|
||||
diskfile_backend *b = (diskfile_backend *)cfg;
|
||||
@ -165,7 +160,7 @@ static int config_open(git_config_file *cfg)
|
||||
if (res == GIT_ENOTFOUND)
|
||||
return 0;
|
||||
|
||||
if (res < 0 || config_parse(b) < 0) {
|
||||
if (res < 0 || config_parse(b, level) < 0) {
|
||||
free_vars(b->values);
|
||||
b->values = NULL;
|
||||
git_buf_free(&b->reader.buffer);
|
||||
@ -191,7 +186,7 @@ static void backend_free(git_config_file *_backend)
|
||||
static int file_foreach(
|
||||
git_config_file *backend,
|
||||
const char *regexp,
|
||||
int (*fn)(const char *, const char *, void *),
|
||||
int (*fn)(const git_config_entry *, void *),
|
||||
void *data)
|
||||
{
|
||||
diskfile_backend *b = (diskfile_backend *)backend;
|
||||
@ -220,7 +215,7 @@ static int file_foreach(
|
||||
continue;
|
||||
|
||||
/* abort iterator on non-zero return value */
|
||||
if (fn(key, var->value, data)) {
|
||||
if (fn(var->entry, data)) {
|
||||
giterr_clear();
|
||||
result = GIT_EUSER;
|
||||
goto cleanup;
|
||||
@ -263,8 +258,8 @@ static int config_set(git_config_file *cfg, const char *name, const char *value)
|
||||
}
|
||||
|
||||
/* don't update if old and new values already match */
|
||||
if ((!existing->value && !value) ||
|
||||
(existing->value && value && !strcmp(existing->value, value)))
|
||||
if ((!existing->entry->value && !value) ||
|
||||
(existing->entry->value && value && !strcmp(existing->entry->value, value)))
|
||||
return 0;
|
||||
|
||||
if (value) {
|
||||
@ -274,10 +269,10 @@ static int config_set(git_config_file *cfg, const char *name, const char *value)
|
||||
GITERR_CHECK_ALLOC(esc_value);
|
||||
}
|
||||
|
||||
git__free(existing->value);
|
||||
existing->value = tmp;
|
||||
git__free((void *)existing->entry->value);
|
||||
existing->entry->value = tmp;
|
||||
|
||||
ret = config_write(b, existing->key, NULL, esc_value);
|
||||
ret = config_write(b, existing->entry->name, NULL, esc_value);
|
||||
|
||||
git__free(esc_value);
|
||||
return ret;
|
||||
@ -285,15 +280,17 @@ static int config_set(git_config_file *cfg, const char *name, const char *value)
|
||||
|
||||
var = git__malloc(sizeof(cvar_t));
|
||||
GITERR_CHECK_ALLOC(var);
|
||||
|
||||
memset(var, 0x0, sizeof(cvar_t));
|
||||
var->entry = git__malloc(sizeof(git_config_entry));
|
||||
GITERR_CHECK_ALLOC(var->entry);
|
||||
memset(var->entry, 0x0, sizeof(git_config_entry));
|
||||
|
||||
var->key = key;
|
||||
var->value = NULL;
|
||||
var->entry->name = key;
|
||||
var->entry->value = NULL;
|
||||
|
||||
if (value) {
|
||||
var->value = git__strdup(value);
|
||||
GITERR_CHECK_ALLOC(var->value);
|
||||
var->entry->value = git__strdup(value);
|
||||
GITERR_CHECK_ALLOC(var->entry->value);
|
||||
esc_value = escape_value(value);
|
||||
GITERR_CHECK_ALLOC(esc_value);
|
||||
}
|
||||
@ -317,7 +314,7 @@ static int config_set(git_config_file *cfg, const char *name, const char *value)
|
||||
/*
|
||||
* Internal function that actually gets the value in string form
|
||||
*/
|
||||
static int config_get(git_config_file *cfg, const char *name, const char **out)
|
||||
static int config_get(git_config_file *cfg, const char *name, const git_config_entry **out)
|
||||
{
|
||||
diskfile_backend *b = (diskfile_backend *)cfg;
|
||||
char *key;
|
||||
@ -333,7 +330,7 @@ static int config_get(git_config_file *cfg, const char *name, const char **out)
|
||||
if (!git_strmap_valid_index(b->values, pos))
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
*out = ((cvar_t *)git_strmap_value_at(b->values, pos))->value;
|
||||
*out = ((cvar_t *)git_strmap_value_at(b->values, pos))->entry;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -342,7 +339,7 @@ static int config_get_multivar(
|
||||
git_config_file *cfg,
|
||||
const char *name,
|
||||
const char *regex_str,
|
||||
int (*fn)(const char *, void *),
|
||||
int (*fn)(const git_config_entry *, void *),
|
||||
void *data)
|
||||
{
|
||||
cvar_t *var;
|
||||
@ -376,10 +373,10 @@ static int config_get_multivar(
|
||||
/* and throw the callback only on the variables that
|
||||
* match the regex */
|
||||
do {
|
||||
if (regexec(®ex, var->value, 0, NULL, 0) == 0) {
|
||||
if (regexec(®ex, var->entry->value, 0, NULL, 0) == 0) {
|
||||
/* early termination by the user is not an error;
|
||||
* just break and return successfully */
|
||||
if (fn(var->value, data) < 0)
|
||||
if (fn(var->entry, data) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
@ -391,7 +388,7 @@ static int config_get_multivar(
|
||||
do {
|
||||
/* early termination by the user is not an error;
|
||||
* just break and return successfully */
|
||||
if (fn(var->value, data) < 0)
|
||||
if (fn(var->entry, data) < 0)
|
||||
break;
|
||||
|
||||
var = var->next;
|
||||
@ -434,12 +431,12 @@ static int config_set_multivar(
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (regexec(&preg, var->value, 0, NULL, 0) == 0) {
|
||||
if (regexec(&preg, var->entry->value, 0, NULL, 0) == 0) {
|
||||
char *tmp = git__strdup(value);
|
||||
GITERR_CHECK_ALLOC(tmp);
|
||||
|
||||
git__free(var->value);
|
||||
var->value = tmp;
|
||||
git__free((void *)var->entry->value);
|
||||
var->entry->value = tmp;
|
||||
replaced = 1;
|
||||
}
|
||||
|
||||
@ -453,14 +450,18 @@ static int config_set_multivar(
|
||||
if (!replaced) {
|
||||
newvar = git__malloc(sizeof(cvar_t));
|
||||
GITERR_CHECK_ALLOC(newvar);
|
||||
|
||||
memset(newvar, 0x0, sizeof(cvar_t));
|
||||
newvar->entry = git__malloc(sizeof(git_config_entry));
|
||||
GITERR_CHECK_ALLOC(newvar->entry);
|
||||
memset(newvar->entry, 0x0, sizeof(git_config_entry));
|
||||
|
||||
newvar->key = git__strdup(var->key);
|
||||
GITERR_CHECK_ALLOC(newvar->key);
|
||||
newvar->entry->name = git__strdup(var->entry->name);
|
||||
GITERR_CHECK_ALLOC(newvar->entry->name);
|
||||
|
||||
newvar->value = git__strdup(value);
|
||||
GITERR_CHECK_ALLOC(newvar->value);
|
||||
newvar->entry->value = git__strdup(value);
|
||||
GITERR_CHECK_ALLOC(newvar->entry->value);
|
||||
|
||||
newvar->entry->level = var->entry->level;
|
||||
|
||||
var->next = newvar;
|
||||
}
|
||||
@ -501,7 +502,7 @@ static int config_delete(git_config_file *cfg, const char *name)
|
||||
|
||||
git_strmap_delete_at(b->values, pos);
|
||||
|
||||
result = config_write(b, var->key, NULL, NULL);
|
||||
result = config_write(b, var->entry->name, NULL, NULL);
|
||||
|
||||
cvar_free(var);
|
||||
return result;
|
||||
@ -898,7 +899,7 @@ static int strip_comments(char *line, int in_quotes)
|
||||
return quote_count;
|
||||
}
|
||||
|
||||
static int config_parse(diskfile_backend *cfg_file)
|
||||
static int config_parse(diskfile_backend *cfg_file, unsigned int level)
|
||||
{
|
||||
int c;
|
||||
char *current_section = NULL;
|
||||
@ -946,8 +947,10 @@ static int config_parse(diskfile_backend *cfg_file)
|
||||
|
||||
var = git__malloc(sizeof(cvar_t));
|
||||
GITERR_CHECK_ALLOC(var);
|
||||
|
||||
memset(var, 0x0, sizeof(cvar_t));
|
||||
var->entry = git__malloc(sizeof(git_config_entry));
|
||||
GITERR_CHECK_ALLOC(var->entry);
|
||||
memset(var->entry, 0x0, sizeof(git_config_entry));
|
||||
|
||||
git__strtolower(var_name);
|
||||
git_buf_printf(&buf, "%s.%s", current_section, var_name);
|
||||
@ -956,13 +959,14 @@ static int config_parse(diskfile_backend *cfg_file)
|
||||
if (git_buf_oom(&buf))
|
||||
return -1;
|
||||
|
||||
var->key = git_buf_detach(&buf);
|
||||
var->value = var_value;
|
||||
var->entry->name = git_buf_detach(&buf);
|
||||
var->entry->value = var_value;
|
||||
var->entry->level = level;
|
||||
|
||||
/* Add or append the new config option */
|
||||
pos = git_strmap_lookup_index(cfg_file->values, var->key);
|
||||
pos = git_strmap_lookup_index(cfg_file->values, var->entry->name);
|
||||
if (!git_strmap_valid_index(cfg_file->values, pos)) {
|
||||
git_strmap_insert(cfg_file->values, var->key, var, result);
|
||||
git_strmap_insert(cfg_file->values, var->entry->name, var, result);
|
||||
if (result < 0)
|
||||
break;
|
||||
result = 0;
|
||||
|
@ -9,9 +9,9 @@
|
||||
|
||||
#include "git2/config.h"
|
||||
|
||||
GIT_INLINE(int) git_config_file_open(git_config_file *cfg)
|
||||
GIT_INLINE(int) git_config_file_open(git_config_file *cfg, unsigned int level)
|
||||
{
|
||||
return cfg->open(cfg);
|
||||
return cfg->open(cfg, level);
|
||||
}
|
||||
|
||||
GIT_INLINE(void) git_config_file_free(git_config_file *cfg)
|
||||
@ -20,7 +20,7 @@ GIT_INLINE(void) git_config_file_free(git_config_file *cfg)
|
||||
}
|
||||
|
||||
GIT_INLINE(int) git_config_file_get_string(
|
||||
const char **out, git_config_file *cfg, const char *name)
|
||||
const git_config_entry **out, git_config_file *cfg, const char *name)
|
||||
{
|
||||
return cfg->get(cfg, name, out);
|
||||
}
|
||||
@ -39,7 +39,7 @@ GIT_INLINE(int) git_config_file_delete(
|
||||
|
||||
GIT_INLINE(int) git_config_file_foreach(
|
||||
git_config_file *cfg,
|
||||
int (*fn)(const char *key, const char *value, void *data),
|
||||
int (*fn)(const git_config_entry *entry, void *data),
|
||||
void *data)
|
||||
{
|
||||
return cfg->foreach(cfg, NULL, fn, data);
|
||||
@ -48,7 +48,7 @@ GIT_INLINE(int) git_config_file_foreach(
|
||||
GIT_INLINE(int) git_config_file_foreach_match(
|
||||
git_config_file *cfg,
|
||||
const char *regexp,
|
||||
int (*fn)(const char *key, const char *value, void *data),
|
||||
int (*fn)(const git_config_entry *entry, void *data),
|
||||
void *data)
|
||||
{
|
||||
return cfg->foreach(cfg, regexp, fn, data);
|
||||
|
@ -637,12 +637,12 @@ struct cb_data {
|
||||
regex_t *preg;
|
||||
};
|
||||
|
||||
static int remote_list_cb(const char *name, const char *value, void *data_)
|
||||
static int remote_list_cb(const git_config_entry *entry, void *data_)
|
||||
{
|
||||
struct cb_data *data = (struct cb_data *)data_;
|
||||
size_t nmatch = 2;
|
||||
regmatch_t pmatch[2];
|
||||
GIT_UNUSED(value);
|
||||
const char *name = entry->name;
|
||||
|
||||
if (!regexec(data->preg, name, nmatch, pmatch, 0)) {
|
||||
char *remote_name = git__strndup(&name[pmatch[1].rm_so], pmatch[1].rm_eo - pmatch[1].rm_so);
|
||||
|
@ -461,23 +461,23 @@ static int load_config(
|
||||
&config_path, repo->path_repository, GIT_CONFIG_FILENAME_INREPO) < 0)
|
||||
goto on_error;
|
||||
|
||||
if (git_config_add_file_ondisk(cfg, config_path.ptr, 4) < 0)
|
||||
if (git_config_add_file_ondisk(cfg, config_path.ptr, GIT_CONFIG_LEVEL_LOCAL, 0) < 0)
|
||||
goto on_error;
|
||||
|
||||
git_buf_free(&config_path);
|
||||
|
||||
if (global_config_path != NULL) {
|
||||
if (git_config_add_file_ondisk(cfg, global_config_path, 3) < 0)
|
||||
if (git_config_add_file_ondisk(cfg, global_config_path, GIT_CONFIG_LEVEL_GLOBAL, 0) < 0)
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
if (xdg_config_path != NULL) {
|
||||
if (git_config_add_file_ondisk(cfg, xdg_config_path, 2) < 0)
|
||||
if (git_config_add_file_ondisk(cfg, xdg_config_path, GIT_CONFIG_LEVEL_XDG, 0) < 0)
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
if (system_config_path != NULL) {
|
||||
if (git_config_add_file_ondisk(cfg, system_config_path, 1) < 0)
|
||||
if (git_config_add_file_ondisk(cfg, system_config_path, GIT_CONFIG_LEVEL_SYSTEM, 0) < 0)
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ static int submodule_get(git_submodule **, git_repository *, const char *, const
|
||||
static void submodule_release(git_submodule *sm, int decr);
|
||||
static int submodule_load_from_index(git_repository *, const git_index_entry *);
|
||||
static int submodule_load_from_head(git_repository*, const char*, const git_oid*);
|
||||
static int submodule_load_from_config(const char *, const char *, void *);
|
||||
static int submodule_load_from_config(const git_config_entry *, void *);
|
||||
static int submodule_load_from_wd_lite(git_submodule *, const char *, void *);
|
||||
static int submodule_update_config(git_submodule *, const char *, const char *, bool, bool);
|
||||
static void submodule_mode_mismatch(git_repository *, const char *, unsigned int);
|
||||
@ -974,11 +974,12 @@ static int submodule_config_error(const char *property, const char *value)
|
||||
}
|
||||
|
||||
static int submodule_load_from_config(
|
||||
const char *key, const char *value, void *data)
|
||||
const git_config_entry *entry, void *data)
|
||||
{
|
||||
git_repository *repo = data;
|
||||
git_strmap *smcfg = repo->submodules;
|
||||
const char *namestart, *property, *alternate = NULL;
|
||||
const char *key = entry->name, *value = entry->value;
|
||||
git_buf name = GIT_BUF_INIT;
|
||||
git_submodule *sm;
|
||||
bool is_path;
|
||||
@ -1055,7 +1056,7 @@ static int submodule_load_from_config(
|
||||
else if (strcasecmp(property, "update") == 0) {
|
||||
int val;
|
||||
if (git_config_lookup_map_value(
|
||||
_sm_update_map, ARRAY_SIZE(_sm_update_map), value, &val) < 0)
|
||||
&val, _sm_update_map, ARRAY_SIZE(_sm_update_map), value) < 0)
|
||||
return submodule_config_error("update", value);
|
||||
sm->update_default = sm->update = (git_submodule_update_t)val;
|
||||
}
|
||||
@ -1066,7 +1067,7 @@ static int submodule_load_from_config(
|
||||
else if (strcasecmp(property, "ignore") == 0) {
|
||||
int val;
|
||||
if (git_config_lookup_map_value(
|
||||
_sm_ignore_map, ARRAY_SIZE(_sm_ignore_map), value, &val) < 0)
|
||||
&val, _sm_ignore_map, ARRAY_SIZE(_sm_ignore_map), value) < 0)
|
||||
return submodule_config_error("ignore", value);
|
||||
sm->ignore_default = sm->ignore = (git_submodule_ignore_t)val;
|
||||
}
|
||||
@ -1204,7 +1205,7 @@ static git_config_file *open_gitmodules(
|
||||
if (git_config_file__ondisk(&mods, path.ptr) < 0)
|
||||
mods = NULL;
|
||||
/* open should only fail here if the file is malformed */
|
||||
else if (git_config_file_open(mods) < 0) {
|
||||
else if (git_config_file_open(mods, GIT_CONFIG_LEVEL_LOCAL) < 0) {
|
||||
git_config_file_free(mods);
|
||||
mods = NULL;
|
||||
}
|
||||
|
59
tests-clar/config/configlevel.c
Normal file
59
tests-clar/config/configlevel.c
Normal file
@ -0,0 +1,59 @@
|
||||
#include "clar_libgit2.h"
|
||||
|
||||
void test_config_configlevel__adding_the_same_level_twice_returns_EEXISTS(void)
|
||||
{
|
||||
int error;
|
||||
git_config *cfg;
|
||||
|
||||
cl_git_pass(git_config_new(&cfg));
|
||||
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config9"),
|
||||
GIT_CONFIG_LEVEL_LOCAL, 0));
|
||||
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config15"),
|
||||
GIT_CONFIG_LEVEL_GLOBAL, 0));
|
||||
error = git_config_add_file_ondisk(cfg, cl_fixture("config/config16"),
|
||||
GIT_CONFIG_LEVEL_GLOBAL, 0);
|
||||
|
||||
cl_git_fail(error);
|
||||
cl_assert_equal_i(GIT_EEXISTS, error);
|
||||
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
||||
void test_config_configlevel__can_replace_a_config_file_at_an_existing_level(void)
|
||||
{
|
||||
git_config *cfg;
|
||||
const char *s;
|
||||
|
||||
cl_git_pass(git_config_new(&cfg));
|
||||
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config18"),
|
||||
GIT_CONFIG_LEVEL_LOCAL, 1));
|
||||
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config19"),
|
||||
GIT_CONFIG_LEVEL_LOCAL, 1));
|
||||
|
||||
cl_git_pass(git_config_get_string(&s, cfg, "core.stringglobal"));
|
||||
cl_assert_equal_s("don't find me!", s);
|
||||
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
||||
void test_config_configlevel__can_read_from_a_single_level_focused_file_after_parent_config_has_been_freed(void)
|
||||
{
|
||||
git_config *cfg;
|
||||
git_config *single_level_cfg;
|
||||
const char *s;
|
||||
|
||||
cl_git_pass(git_config_new(&cfg));
|
||||
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config18"),
|
||||
GIT_CONFIG_LEVEL_GLOBAL, 0));
|
||||
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config19"),
|
||||
GIT_CONFIG_LEVEL_LOCAL, 0));
|
||||
|
||||
cl_git_pass(git_config_open_level(&single_level_cfg, cfg, GIT_CONFIG_LEVEL_LOCAL));
|
||||
|
||||
git_config_free(cfg);
|
||||
|
||||
cl_git_pass(git_config_get_string(&s, single_level_cfg, "core.stringglobal"));
|
||||
cl_assert_equal_s("don't find me!", s);
|
||||
|
||||
git_config_free(single_level_cfg);
|
||||
}
|
@ -12,13 +12,11 @@ void test_config_multivar__cleanup(void)
|
||||
cl_fixture_cleanup("config");
|
||||
}
|
||||
|
||||
static int mv_read_cb(const char *name, const char *value, void *data)
|
||||
static int mv_read_cb(const git_config_entry *entry, void *data)
|
||||
{
|
||||
int *n = (int *) data;
|
||||
|
||||
GIT_UNUSED(value);
|
||||
|
||||
if (!strcmp(name, _name))
|
||||
if (!strcmp(entry->name, _name))
|
||||
(*n)++;
|
||||
|
||||
return 0;
|
||||
@ -37,11 +35,11 @@ void test_config_multivar__foreach(void)
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
||||
static int cb(const char *val, void *data)
|
||||
static int cb(const git_config_entry *entry, void *data)
|
||||
{
|
||||
int *n = (int *) data;
|
||||
|
||||
GIT_UNUSED(val);
|
||||
GIT_UNUSED(entry);
|
||||
|
||||
(*n)++;
|
||||
|
||||
|
@ -9,21 +9,16 @@
|
||||
void test_config_new__write_new_config(void)
|
||||
{
|
||||
const char *out;
|
||||
struct git_config_file *file;
|
||||
git_config *config;
|
||||
|
||||
cl_git_pass(git_config_file__ondisk(&file, TEST_CONFIG));
|
||||
cl_git_pass(git_config_new(&config));
|
||||
cl_git_pass(git_config_add_file(config, file, 0));
|
||||
cl_git_pass(git_config_open_ondisk(&config, TEST_CONFIG));
|
||||
|
||||
cl_git_pass(git_config_set_string(config, "color.ui", "auto"));
|
||||
cl_git_pass(git_config_set_string(config, "core.editor", "ed"));
|
||||
|
||||
git_config_free(config);
|
||||
|
||||
cl_git_pass(git_config_file__ondisk(&file, TEST_CONFIG));
|
||||
cl_git_pass(git_config_new(&config));
|
||||
cl_git_pass(git_config_add_file(config, file, 0));
|
||||
cl_git_pass(git_config_open_ondisk(&config, TEST_CONFIG));
|
||||
|
||||
cl_git_pass(git_config_get_string(&out, config, "color.ui"));
|
||||
cl_assert_equal_s(out, "auto");
|
||||
|
@ -191,22 +191,24 @@ void test_config_read__escaping_quotes(void)
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
||||
static int count_cfg_entries(
|
||||
const char *var_name, const char *value, void *payload)
|
||||
static int count_cfg_entries_and_compare_levels(
|
||||
const git_config_entry *entry, void *payload)
|
||||
{
|
||||
int *count = payload;
|
||||
GIT_UNUSED(var_name);
|
||||
GIT_UNUSED(value);
|
||||
|
||||
if (!strcmp(entry->value, "7") || !strcmp(entry->value, "17"))
|
||||
cl_assert(entry->level == GIT_CONFIG_LEVEL_GLOBAL);
|
||||
else
|
||||
cl_assert(entry->level == GIT_CONFIG_LEVEL_SYSTEM);
|
||||
|
||||
(*count)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cfg_callback_countdown(
|
||||
const char *var_name, const char *value, void *payload)
|
||||
static int cfg_callback_countdown(const git_config_entry *entry, void *payload)
|
||||
{
|
||||
int *count = payload;
|
||||
GIT_UNUSED(var_name);
|
||||
GIT_UNUSED(value);
|
||||
GIT_UNUSED(entry);
|
||||
(*count)--;
|
||||
if (*count == 0)
|
||||
return -100;
|
||||
@ -218,11 +220,15 @@ void test_config_read__foreach(void)
|
||||
git_config *cfg;
|
||||
int count, ret;
|
||||
|
||||
cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config9")));
|
||||
cl_git_pass(git_config_new(&cfg));
|
||||
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config9"),
|
||||
GIT_CONFIG_LEVEL_SYSTEM, 0));
|
||||
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config15"),
|
||||
GIT_CONFIG_LEVEL_GLOBAL, 0));
|
||||
|
||||
count = 0;
|
||||
cl_git_pass(git_config_foreach(cfg, count_cfg_entries, &count));
|
||||
cl_assert_equal_i(5, count);
|
||||
cl_git_pass(git_config_foreach(cfg, count_cfg_entries_and_compare_levels, &count));
|
||||
cl_assert_equal_i(7, count);
|
||||
|
||||
count = 3;
|
||||
cl_git_fail(ret = git_config_foreach(cfg, cfg_callback_countdown, &count));
|
||||
@ -231,6 +237,14 @@ void test_config_read__foreach(void)
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
||||
static int count_cfg_entries(const git_config_entry *entry, void *payload)
|
||||
{
|
||||
int *count = payload;
|
||||
GIT_UNUSED(entry);
|
||||
(*count)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void test_config_read__foreach_match(void)
|
||||
{
|
||||
git_config *cfg;
|
||||
@ -282,31 +296,129 @@ void test_config_read__whitespace_not_required_around_assignment(void)
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
BEGIN_TEST(config10, "a repo's config overrides the global config")
|
||||
git_repository *repo;
|
||||
void test_config_read__read_git_config_entry(void)
|
||||
{
|
||||
git_config *cfg;
|
||||
int32_t version;
|
||||
const git_config_entry *entry;
|
||||
|
||||
cl_git_pass(git_config_new(&cfg));
|
||||
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config9"),
|
||||
GIT_CONFIG_LEVEL_SYSTEM, 0));
|
||||
|
||||
cl_git_pass(git_config_get_config_entry(&entry, cfg, "core.dummy2"));
|
||||
cl_assert_equal_s("core.dummy2", entry->name);
|
||||
cl_assert_equal_s("42", entry->value);
|
||||
cl_assert_equal_i(GIT_CONFIG_LEVEL_SYSTEM, entry->level);
|
||||
|
||||
cl_git_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
|
||||
cl_git_pass(git_repository_config(&cfg, repo, GLOBAL_CONFIG, NULL));
|
||||
cl_git_pass(git_config_get_int32(cfg, "core.repositoryformatversion", &version));
|
||||
cl_assert(version == 0);
|
||||
git_config_free(cfg);
|
||||
git_repository_free(repo);
|
||||
END_TEST
|
||||
}
|
||||
|
||||
BEGIN_TEST(config11, "fall back to the global config")
|
||||
git_repository *repo;
|
||||
/*
|
||||
* At the beginning of the test:
|
||||
* - config9 has: core.dummy2=42
|
||||
* - config15 has: core.dummy2=7
|
||||
* - config16 has: core.dummy2=28
|
||||
*/
|
||||
void test_config_read__local_config_overrides_global_config_overrides_system_config(void)
|
||||
{
|
||||
git_config *cfg;
|
||||
int32_t num;
|
||||
int32_t i;
|
||||
|
||||
cl_git_pass(git_config_new(&cfg));
|
||||
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config9"),
|
||||
GIT_CONFIG_LEVEL_SYSTEM, 0));
|
||||
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config15"),
|
||||
GIT_CONFIG_LEVEL_GLOBAL, 0));
|
||||
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config16"),
|
||||
GIT_CONFIG_LEVEL_LOCAL, 0));
|
||||
|
||||
cl_git_pass(git_config_get_int32(&i, cfg, "core.dummy2"));
|
||||
cl_assert_equal_i(28, i);
|
||||
|
||||
cl_git_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
|
||||
cl_git_pass(git_repository_config(&cfg, repo, GLOBAL_CONFIG, NULL));
|
||||
cl_git_pass(git_config_get_int32(cfg, "core.something", &num));
|
||||
cl_assert(num == 2);
|
||||
git_config_free(cfg);
|
||||
git_repository_free(repo);
|
||||
END_TEST
|
||||
#endif
|
||||
|
||||
cl_git_pass(git_config_new(&cfg));
|
||||
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config9"),
|
||||
GIT_CONFIG_LEVEL_SYSTEM, 0));
|
||||
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config15"),
|
||||
GIT_CONFIG_LEVEL_GLOBAL, 0));
|
||||
|
||||
cl_git_pass(git_config_get_int32(&i, cfg, "core.dummy2"));
|
||||
cl_assert_equal_i(7, i);
|
||||
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
||||
/*
|
||||
* At the beginning of the test:
|
||||
* - config9 has: core.global does not exist
|
||||
* - config15 has: core.global=17
|
||||
* - config16 has: core.global=29
|
||||
*
|
||||
* And also:
|
||||
* - config9 has: core.system does not exist
|
||||
* - config15 has: core.system does not exist
|
||||
* - config16 has: core.system=11
|
||||
*/
|
||||
void test_config_read__fallback_from_local_to_global_and_from_global_to_system(void)
|
||||
{
|
||||
git_config *cfg;
|
||||
int32_t i;
|
||||
|
||||
cl_git_pass(git_config_new(&cfg));
|
||||
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config9"),
|
||||
GIT_CONFIG_LEVEL_SYSTEM, 0));
|
||||
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config15"),
|
||||
GIT_CONFIG_LEVEL_GLOBAL, 0));
|
||||
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config16"),
|
||||
GIT_CONFIG_LEVEL_LOCAL, 0));
|
||||
|
||||
cl_git_pass(git_config_get_int32(&i, cfg, "core.global"));
|
||||
cl_assert_equal_i(17, i);
|
||||
cl_git_pass(git_config_get_int32(&i, cfg, "core.system"));
|
||||
cl_assert_equal_i(11, i);
|
||||
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
||||
/*
|
||||
* At the beginning of the test, config18 has:
|
||||
* int32global = 28
|
||||
* int64global = 9223372036854775803
|
||||
* boolglobal = true
|
||||
* stringglobal = I'm a global config value!
|
||||
*
|
||||
* And config19 has:
|
||||
* int32global = -1
|
||||
* int64global = -2
|
||||
* boolglobal = false
|
||||
* stringglobal = don't find me!
|
||||
*
|
||||
*/
|
||||
void test_config_read__simple_read_from_specific_level(void)
|
||||
{
|
||||
git_config *cfg, *cfg_specific;
|
||||
int i;
|
||||
int64_t l, expected = +9223372036854775803;
|
||||
const char *s;
|
||||
|
||||
cl_git_pass(git_config_new(&cfg));
|
||||
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config18"),
|
||||
GIT_CONFIG_LEVEL_GLOBAL, 0));
|
||||
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config19"),
|
||||
GIT_CONFIG_LEVEL_SYSTEM, 0));
|
||||
|
||||
cl_git_pass(git_config_open_level(&cfg_specific, cfg, GIT_CONFIG_LEVEL_GLOBAL));
|
||||
|
||||
cl_git_pass(git_config_get_int32(&i, cfg_specific, "core.int32global"));
|
||||
cl_assert_equal_i(28, i);
|
||||
cl_git_pass(git_config_get_int64(&l, cfg_specific, "core.int64global"));
|
||||
cl_assert(l == expected);
|
||||
cl_git_pass(git_config_get_bool(&i, cfg_specific, "core.boolglobal"));
|
||||
cl_assert_equal_b(true, i);
|
||||
cl_git_pass(git_config_get_string(&s, cfg_specific, "core.stringglobal"));
|
||||
cl_assert_equal_s("I'm a global config value!", s);
|
||||
|
||||
git_config_free(cfg_specific);
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
@ -4,11 +4,13 @@
|
||||
#include "fileops.h"
|
||||
#include "posix.h"
|
||||
|
||||
#define TEST_CONFIG "git-test-config"
|
||||
|
||||
void test_config_stress__initialize(void)
|
||||
{
|
||||
git_filebuf file = GIT_FILEBUF_INIT;
|
||||
|
||||
cl_git_pass(git_filebuf_open(&file, "git-test-config", 0));
|
||||
cl_git_pass(git_filebuf_open(&file, TEST_CONFIG, 0));
|
||||
|
||||
git_filebuf_printf(&file, "[color]\n\tui = auto\n");
|
||||
git_filebuf_printf(&file, "[core]\n\teditor = \n");
|
||||
@ -18,19 +20,16 @@ void test_config_stress__initialize(void)
|
||||
|
||||
void test_config_stress__cleanup(void)
|
||||
{
|
||||
p_unlink("git-test-config");
|
||||
p_unlink(TEST_CONFIG);
|
||||
}
|
||||
|
||||
void test_config_stress__dont_break_on_invalid_input(void)
|
||||
{
|
||||
const char *editor, *color;
|
||||
struct git_config_file *file;
|
||||
git_config *config;
|
||||
|
||||
cl_assert(git_path_exists("git-test-config"));
|
||||
cl_git_pass(git_config_file__ondisk(&file, "git-test-config"));
|
||||
cl_git_pass(git_config_new(&config));
|
||||
cl_git_pass(git_config_add_file(config, file, 0));
|
||||
cl_assert(git_path_exists(TEST_CONFIG));
|
||||
cl_git_pass(git_config_open_ondisk(&config, TEST_CONFIG));
|
||||
|
||||
cl_git_pass(git_config_get_string(&color, config, "color.ui"));
|
||||
cl_git_pass(git_config_get_string(&editor, config, "core.editor"));
|
||||
@ -40,13 +39,10 @@ void test_config_stress__dont_break_on_invalid_input(void)
|
||||
|
||||
void test_config_stress__comments(void)
|
||||
{
|
||||
struct git_config_file *file;
|
||||
git_config *config;
|
||||
const char *str;
|
||||
|
||||
cl_git_pass(git_config_file__ondisk(&file, cl_fixture("config/config12")));
|
||||
cl_git_pass(git_config_new(&config));
|
||||
cl_git_pass(git_config_add_file(config, file, 0));
|
||||
cl_git_pass(git_config_open_ondisk(&config, cl_fixture("config/config12")));
|
||||
|
||||
cl_git_pass(git_config_get_string(&str, config, "some.section.other"));
|
||||
cl_assert(!strcmp(str, "hello! \" ; ; ; "));
|
||||
@ -62,21 +58,16 @@ void test_config_stress__comments(void)
|
||||
|
||||
void test_config_stress__escape_subsection_names(void)
|
||||
{
|
||||
struct git_config_file *file;
|
||||
git_config *config;
|
||||
const char *str;
|
||||
|
||||
cl_assert(git_path_exists("git-test-config"));
|
||||
cl_git_pass(git_config_file__ondisk(&file, "git-test-config"));
|
||||
cl_git_pass(git_config_new(&config));
|
||||
cl_git_pass(git_config_add_file(config, file, 0));
|
||||
cl_git_pass(git_config_open_ondisk(&config, TEST_CONFIG));
|
||||
|
||||
cl_git_pass(git_config_set_string(config, "some.sec\\tion.other", "foo"));
|
||||
git_config_free(config);
|
||||
|
||||
cl_git_pass(git_config_file__ondisk(&file, "git-test-config"));
|
||||
cl_git_pass(git_config_new(&config));
|
||||
cl_git_pass(git_config_add_file(config, file, 0));
|
||||
cl_git_pass(git_config_open_ondisk(&config, TEST_CONFIG));
|
||||
|
||||
cl_git_pass(git_config_get_string(&str, config, "some.sec\\tion.other"));
|
||||
cl_assert(!strcmp("foo", str));
|
||||
|
@ -3,12 +3,14 @@
|
||||
void test_config_write__initialize(void)
|
||||
{
|
||||
cl_fixture_sandbox("config/config9");
|
||||
cl_fixture_sandbox("config/config15");
|
||||
cl_fixture_sandbox("config/config17");
|
||||
}
|
||||
|
||||
void test_config_write__cleanup(void)
|
||||
{
|
||||
cl_fixture_cleanup("config9");
|
||||
cl_fixture_cleanup("config15");
|
||||
cl_fixture_cleanup("config17");
|
||||
}
|
||||
|
||||
@ -69,6 +71,40 @@ void test_config_write__delete_value(void)
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
||||
/*
|
||||
* At the beginning of the test:
|
||||
* - config9 has: core.dummy2=42
|
||||
* - config15 has: core.dummy2=7
|
||||
*/
|
||||
void test_config_write__delete_value_at_specific_level(void)
|
||||
{
|
||||
git_config *cfg, *cfg_specific;
|
||||
int32_t i;
|
||||
|
||||
cl_git_pass(git_config_open_ondisk(&cfg, "config15"));
|
||||
cl_git_pass(git_config_get_int32(&i, cfg, "core.dummy2"));
|
||||
cl_assert(i == 7);
|
||||
git_config_free(cfg);
|
||||
|
||||
cl_git_pass(git_config_new(&cfg));
|
||||
cl_git_pass(git_config_add_file_ondisk(cfg, "config9",
|
||||
GIT_CONFIG_LEVEL_LOCAL, 0));
|
||||
cl_git_pass(git_config_add_file_ondisk(cfg, "config15",
|
||||
GIT_CONFIG_LEVEL_GLOBAL, 0));
|
||||
|
||||
cl_git_pass(git_config_open_level(&cfg_specific, cfg, GIT_CONFIG_LEVEL_GLOBAL));
|
||||
|
||||
cl_git_pass(git_config_delete(cfg_specific, "core.dummy2"));
|
||||
git_config_free(cfg);
|
||||
|
||||
cl_git_pass(git_config_open_ondisk(&cfg, "config15"));
|
||||
cl_assert(git_config_get_int32(&i, cfg, "core.dummy2") == GIT_ENOTFOUND);
|
||||
cl_git_pass(git_config_set_int32(cfg, "core.dummy2", 7));
|
||||
|
||||
git_config_free(cfg_specific);
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
||||
void test_config_write__write_subsection(void)
|
||||
{
|
||||
git_config *cfg;
|
||||
@ -139,7 +175,45 @@ void test_config_write__escape_value(void)
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
||||
void test_config_write__add_value_in_file_with_no_clrf_at_the_end(void)
|
||||
void test_config_write__add_value_at_specific_level(void)
|
||||
{
|
||||
git_config *cfg, *cfg_specific;
|
||||
int i;
|
||||
int64_t l, expected = +9223372036854775803;
|
||||
const char *s;
|
||||
|
||||
// open config15 as global level config file
|
||||
cl_git_pass(git_config_new(&cfg));
|
||||
cl_git_pass(git_config_add_file_ondisk(cfg, "config9",
|
||||
GIT_CONFIG_LEVEL_LOCAL, 0));
|
||||
cl_git_pass(git_config_add_file_ondisk(cfg, "config15",
|
||||
GIT_CONFIG_LEVEL_GLOBAL, 0));
|
||||
|
||||
cl_git_pass(git_config_open_level(&cfg_specific, cfg, GIT_CONFIG_LEVEL_GLOBAL));
|
||||
|
||||
cl_git_pass(git_config_set_int32(cfg_specific, "core.int32global", 28));
|
||||
cl_git_pass(git_config_set_int64(cfg_specific, "core.int64global", expected));
|
||||
cl_git_pass(git_config_set_bool(cfg_specific, "core.boolglobal", true));
|
||||
cl_git_pass(git_config_set_string(cfg_specific, "core.stringglobal", "I'm a global config value!"));
|
||||
git_config_free(cfg_specific);
|
||||
git_config_free(cfg);
|
||||
|
||||
// open config15 as local level config file
|
||||
cl_git_pass(git_config_open_ondisk(&cfg, "config15"));
|
||||
|
||||
cl_git_pass(git_config_get_int32(&i, cfg, "core.int32global"));
|
||||
cl_assert_equal_i(28, i);
|
||||
cl_git_pass(git_config_get_int64(&l, cfg, "core.int64global"));
|
||||
cl_assert(l == expected);
|
||||
cl_git_pass(git_config_get_bool(&i, cfg, "core.boolglobal"));
|
||||
cl_assert_equal_b(true, i);
|
||||
cl_git_pass(git_config_get_string(&s, cfg, "core.stringglobal"));
|
||||
cl_assert_equal_s("I'm a global config value!", s);
|
||||
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
||||
void test_config_write__add_value_at_file_with_no_clrf_at_the_end(void)
|
||||
{
|
||||
git_config *cfg;
|
||||
int i;
|
||||
|
3
tests-clar/resources/config/config15
Normal file
3
tests-clar/resources/config/config15
Normal file
@ -0,0 +1,3 @@
|
||||
[core]
|
||||
dummy2 = 7
|
||||
global = 17
|
3
tests-clar/resources/config/config16
Normal file
3
tests-clar/resources/config/config16
Normal file
@ -0,0 +1,3 @@
|
||||
[core]
|
||||
dummy2 = 28
|
||||
system = 11
|
5
tests-clar/resources/config/config18
Normal file
5
tests-clar/resources/config/config18
Normal file
@ -0,0 +1,5 @@
|
||||
[core]
|
||||
int32global = 28
|
||||
int64global = 9223372036854775803
|
||||
boolglobal = true
|
||||
stringglobal = I'm a global config value!
|
5
tests-clar/resources/config/config19
Normal file
5
tests-clar/resources/config/config19
Normal file
@ -0,0 +1,5 @@
|
||||
[core]
|
||||
int32global = -1
|
||||
int64global = -2
|
||||
boolglobal = false
|
||||
stringglobal = don't find me!
|
@ -73,12 +73,10 @@ void test_submodule_modify__add(void)
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
||||
static int delete_one_config(
|
||||
const char *var_name, const char *value, void *payload)
|
||||
static int delete_one_config(const git_config_entry *entry, void *payload)
|
||||
{
|
||||
git_config *cfg = payload;
|
||||
GIT_UNUSED(value);
|
||||
return git_config_delete(cfg, var_name);
|
||||
return git_config_delete(cfg, entry->name);
|
||||
}
|
||||
|
||||
static int init_one_submodule(
|
||||
|
Loading…
Reference in New Issue
Block a user