Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
G
git2
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
git2
Commits
d2c4d1c6
Commit
d2c4d1c6
authored
May 12, 2014
by
Russell Belfer
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2188 from libgit2/cmn/config-snapshot
Configuration snapshotting
parents
e18d5e52
ac99d86b
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
594 additions
and
266 deletions
+594
-266
include/git2/config.h
+27
-1
include/git2/repository.h
+13
-1
include/git2/sys/config.h
+3
-1
src/branch.c
+8
-7
src/config.c
+32
-0
src/config_file.c
+383
-228
src/diff_driver.c
+3
-2
src/pack-objects.c
+4
-2
src/remote.c
+3
-2
src/repository.c
+20
-12
src/signature.c
+1
-1
tests/config/multivar.c
+3
-3
tests/config/refresh.c
+3
-6
tests/config/snapshot.c
+64
-0
tests/config/write.c
+27
-0
No files found.
include/git2/config.h
View file @
d2c4d1c6
...
...
@@ -226,6 +226,22 @@ GIT_EXTERN(int) git_config_open_level(
*/
GIT_EXTERN
(
int
)
git_config_open_global
(
git_config
**
out
,
git_config
*
config
);
/**
* Create a snapshot of the configuration
*
* Create a snapshot of the current state of a configuration, which
* allows you to look into a consistent view of the configuration for
* looking up complex values (e.g. a remote, submodule).
*
* The string returned when querying such a config object is valid
* until it is freed.
*
* @param out pointer in which to store the snapshot config object
* @param config configuration to snapshot
* @return 0 or an error code
*/
GIT_EXTERN
(
int
)
git_config_snapshot
(
git_config
**
out
,
git_config
*
config
);
/**
* Reload changed config files
...
...
@@ -312,7 +328,8 @@ GIT_EXTERN(int) git_config_get_bool(int *out, const git_config *cfg, const char
* Get the value of a string config variable.
*
* The string is owned by the variable and should not be freed by the
* user.
* user. The pointer will be valid until the next operation on this
* config object.
*
* All config files will be looked into, in the order of their
* defined level. A higher level means a higher priority. The
...
...
@@ -353,6 +370,9 @@ GIT_EXTERN(int) git_config_multivar_iterator_new(git_config_iterator **out, cons
/**
* Return the current entry and advance the iterator
*
* The pointers returned by this function are valid until the iterator
* is freed.
*
* @param entry pointer to store the entry
* @param iter the iterator
* @return 0 or an error code. GIT_ITEROVER if the iteration has completed
...
...
@@ -451,6 +471,9 @@ GIT_EXTERN(int) git_config_delete_multivar(git_config *cfg, const char *name, co
* If the callback returns a non-zero value, the function stops iterating
* and returns that value to the caller.
*
* The pointers passed to the callback are only valid as long as the
* iteration is ongoing.
*
* @param cfg where to get the variables from
* @param callback the function to call on each variable
* @param payload the data to pass to the callback
...
...
@@ -491,6 +514,9 @@ GIT_EXTERN(int) git_config_iterator_glob_new(git_config_iterator **out, const gi
* regular expression that filters which config keys are passed to the
* callback.
*
* The pointers passed to the callback are only valid as long as the
* iteration is ongoing.
*
* @param cfg where to get the variables from
* @param regexp regular expression to match against config names
* @param callback the function to call on each variable
...
...
include/git2/repository.h
View file @
d2c4d1c6
...
...
@@ -408,13 +408,25 @@ GIT_EXTERN(int) git_repository_is_bare(git_repository *repo);
* The configuration file must be freed once it's no longer
* being used by the user.
*
* @param out Pointer to store the loaded config
file
* @param out Pointer to store the loaded config
uration
* @param repo A repository object
* @return 0, or an error code
*/
GIT_EXTERN
(
int
)
git_repository_config
(
git_config
**
out
,
git_repository
*
repo
);
/**
* Get a snapshot of the repository's configuration
*
* Convenience function to take a snapshot from the repository's
* configuration.
*
* @param out Pointer to store the loaded configuration
* @param repo the repository
* @return 0, or an error code
*/
GIT_EXTERN
(
int
)
git_repository_config_snapshot
(
git_config
**
out
,
git_repository
*
repo
);
/**
* Get the Object Database for this repository.
*
* If a custom ODB has not been set, the default
...
...
include/git2/sys/config.h
View file @
d2c4d1c6
...
...
@@ -57,13 +57,15 @@ struct git_config_backend {
/* Open means open the file/database and parse if necessary */
int
(
*
open
)(
struct
git_config_backend
*
,
git_config_level_t
level
);
int
(
*
get
)(
const
struct
git_config_backend
*
,
const
char
*
key
,
const
git_config_entry
**
entry
);
int
(
*
get
)(
struct
git_config_backend
*
,
const
char
*
key
,
const
git_config_entry
**
entry
);
int
(
*
set
)(
struct
git_config_backend
*
,
const
char
*
key
,
const
char
*
value
);
int
(
*
set_multivar
)(
git_config_backend
*
cfg
,
const
char
*
name
,
const
char
*
regexp
,
const
char
*
value
);
int
(
*
del
)(
struct
git_config_backend
*
,
const
char
*
key
);
int
(
*
del_multivar
)(
struct
git_config_backend
*
,
const
char
*
key
,
const
char
*
regexp
);
int
(
*
iterator
)(
git_config_iterator
**
,
struct
git_config_backend
*
);
int
(
*
refresh
)(
struct
git_config_backend
*
);
/** Produce a read-only version of this backend */
int
(
*
snapshot
)(
struct
git_config_backend
**
,
struct
git_config_backend
*
);
void
(
*
free
)(
struct
git_config_backend
*
);
};
#define GIT_CONFIG_BACKEND_VERSION 1
...
...
src/branch.c
View file @
d2c4d1c6
...
...
@@ -306,17 +306,13 @@ int git_branch_name(
static
int
retrieve_upstream_configuration
(
const
char
**
out
,
git_repository
*
repo
,
const
git_config
*
config
,
const
char
*
canonical_branch_name
,
const
char
*
format
)
{
git_config
*
config
;
git_buf
buf
=
GIT_BUF_INIT
;
int
error
;
if
(
git_repository_config__weakptr
(
&
config
,
repo
)
<
0
)
return
-
1
;
if
(
git_buf_printf
(
&
buf
,
format
,
canonical_branch_name
+
strlen
(
GIT_REFS_HEADS_DIR
))
<
0
)
return
-
1
;
...
...
@@ -336,6 +332,7 @@ int git_branch_upstream_name(
int
error
=
-
1
;
git_remote
*
remote
=
NULL
;
const
git_refspec
*
refspec
;
git_config
*
config
;
assert
(
out
&&
refname
);
...
...
@@ -344,12 +341,15 @@ int git_branch_upstream_name(
if
(
!
git_reference__is_branch
(
refname
))
return
not_a_local_branch
(
refname
);
if
((
error
=
git_repository_config_snapshot
(
&
config
,
repo
))
<
0
)
return
error
;
if
((
error
=
retrieve_upstream_configuration
(
&
remote_name
,
repo
,
refname
,
"branch.%s.remote"
))
<
0
)
&
remote_name
,
config
,
refname
,
"branch.%s.remote"
))
<
0
)
goto
cleanup
;
if
((
error
=
retrieve_upstream_configuration
(
&
merge_name
,
repo
,
refname
,
"branch.%s.merge"
))
<
0
)
&
merge_name
,
config
,
refname
,
"branch.%s.merge"
))
<
0
)
goto
cleanup
;
if
(
!*
remote_name
||
!*
merge_name
)
{
...
...
@@ -378,6 +378,7 @@ int git_branch_upstream_name(
error
=
git_buf_set
(
out
,
git_buf_cstr
(
&
buf
),
git_buf_len
(
&
buf
));
cleanup:
git_config_free
(
config
);
git_remote_free
(
remote
);
git_buf_free
(
&
buf
);
return
error
;
...
...
src/config.c
View file @
d2c4d1c6
...
...
@@ -137,6 +137,38 @@ int git_config_open_ondisk(git_config **out, const char *path)
return
error
;
}
int
git_config_snapshot
(
git_config
**
out
,
git_config
*
in
)
{
int
error
;
size_t
i
;
file_internal
*
internal
;
git_config
*
config
;
*
out
=
NULL
;
if
(
git_config_new
(
&
config
)
<
0
)
return
-
1
;
git_vector_foreach
(
&
in
->
files
,
i
,
internal
)
{
git_config_backend
*
b
;
if
((
error
=
internal
->
file
->
snapshot
(
&
b
,
internal
->
file
))
<
0
)
goto
on_error
;
if
((
error
=
git_config_add_backend
(
config
,
b
,
internal
->
level
,
0
))
<
0
)
{
b
->
free
(
b
);
goto
on_error
;
}
}
*
out
=
config
;
return
error
;
on_error:
git_config_free
(
config
);
return
error
;
}
static
int
find_internal_file_by_level
(
file_internal
**
internal_out
,
const
git_config
*
cfg
,
...
...
src/config_file.c
View file @
d2c4d1c6
...
...
@@ -26,7 +26,7 @@ GIT__USE_STRMAP;
typedef
struct
cvar_t
{
struct
cvar_t
*
next
;
git_config_entry
*
entry
;
int
included
;
/* whether this is part of [include] */
bool
included
;
/* whether this is part of [include] */
}
cvar_t
;
typedef
struct
git_config_file_iter
{
...
...
@@ -87,28 +87,54 @@ struct reader {
};
typedef
struct
{
git_atomic
refcount
;
git_strmap
*
values
;
}
refcounted_strmap
;
typedef
struct
{
git_config_backend
parent
;
/* mutex to coordinate accessing the values */
git_mutex
values_mutex
;
refcounted_strmap
*
values
;
int
readonly
;
}
diskfile_header
;
git_strmap
*
values
;
typedef
struct
{
diskfile_header
header
;
git_config_level_t
level
;
git_array_t
(
struct
reader
)
readers
;
char
*
file_path
;
git_config_level_t
level
;
}
diskfile_backend
;
static
int
config_parse
(
diskfile_backend
*
cfg_file
,
struct
reader
*
reader
,
git_config_level_t
level
,
int
depth
);
typedef
struct
{
diskfile_header
header
;
diskfile_backend
*
snapshot_from
;
}
diskfile_readonly_backend
;
static
int
config_parse
(
git_strmap
*
values
,
diskfile_backend
*
cfg_file
,
struct
reader
*
reader
,
git_config_level_t
level
,
int
depth
);
static
int
parse_variable
(
struct
reader
*
reader
,
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
);
int
git_config_file__snapshot
(
git_config_backend
**
out
,
diskfile_backend
*
in
);
static
int
config_snapshot
(
git_config_backend
**
out
,
git_config_backend
*
in
);
static
void
set_parse_error
(
struct
reader
*
reader
,
int
col
,
const
char
*
error_str
)
{
giterr_set
(
GITERR_CONFIG
,
"Failed to parse config file: %s (in %s:%d, column %d)"
,
error_str
,
reader
->
file_path
,
reader
->
line_number
,
col
);
}
static
int
config_error_readonly
(
void
)
{
giterr_set
(
GITERR_CONFIG
,
"this backend is read-only"
);
return
-
1
;
}
static
void
cvar_free
(
cvar_t
*
var
)
{
if
(
var
==
NULL
)
...
...
@@ -120,18 +146,6 @@ static void cvar_free(cvar_t *var)
git__free
(
var
);
}
static
int
cvar_length
(
cvar_t
*
var
)
{
int
length
=
0
;
while
(
var
)
{
length
++
;
var
=
var
->
next
;
}
return
length
;
}
int
git_config_file_normalize_section
(
char
*
start
,
char
*
end
)
{
char
*
scan
;
...
...
@@ -155,6 +169,30 @@ int git_config_file_normalize_section(char *start, char *end)
return
0
;
}
/* Add or append the new config option */
static
int
append_entry
(
git_strmap
*
values
,
cvar_t
*
var
)
{
git_strmap_iter
pos
;
cvar_t
*
existing
;
int
error
=
0
;
pos
=
git_strmap_lookup_index
(
values
,
var
->
entry
->
name
);
if
(
!
git_strmap_valid_index
(
values
,
pos
))
{
git_strmap_insert
(
values
,
var
->
entry
->
name
,
var
,
error
);
}
else
{
existing
=
git_strmap_value_at
(
values
,
pos
);
while
(
existing
->
next
!=
NULL
)
{
existing
=
existing
->
next
;
}
existing
->
next
=
var
;
}
if
(
error
>
0
)
error
=
0
;
return
error
;
}
static
void
free_vars
(
git_strmap
*
values
)
{
cvar_t
*
var
=
NULL
;
...
...
@@ -172,6 +210,58 @@ static void free_vars(git_strmap *values)
git_strmap_free
(
values
);
}
static
void
refcounted_strmap_free
(
refcounted_strmap
*
map
)
{
if
(
!
map
)
return
;
if
(
git_atomic_dec
(
&
map
->
refcount
)
!=
0
)
return
;
free_vars
(
map
->
values
);
git__free
(
map
);
}
/**
* Take the current values map from the backend and increase its
* refcount. This is its own function to make sure we use the mutex to
* avoid the map pointer from changing under us.
*/
static
refcounted_strmap
*
refcounted_strmap_take
(
diskfile_header
*
h
)
{
refcounted_strmap
*
map
;
git_mutex_lock
(
&
h
->
values_mutex
);
map
=
h
->
values
;
git_atomic_inc
(
&
map
->
refcount
);
git_mutex_unlock
(
&
h
->
values_mutex
);
return
map
;
}
static
int
refcounted_strmap_alloc
(
refcounted_strmap
**
out
)
{
refcounted_strmap
*
map
;
int
error
;
map
=
git__calloc
(
1
,
sizeof
(
refcounted_strmap
));
if
(
!
map
)
{
giterr_set_oom
();
return
-
1
;
}
git_atomic_set
(
&
map
->
refcount
,
1
);
if
((
error
=
git_strmap_alloc
(
&
map
->
values
))
<
0
)
{
git__free
(
map
);
return
error
;
}
*
out
=
map
;
return
error
;
}
static
int
config_open
(
git_config_backend
*
cfg
,
git_config_level_t
level
)
{
int
res
;
...
...
@@ -180,13 +270,14 @@ static int config_open(git_config_backend *cfg, git_config_level_t level)
b
->
level
=
level
;
if
((
res
=
git_strmap_alloc
(
&
b
->
values
))
<
0
)
if
((
res
=
refcounted_strmap_alloc
(
&
b
->
header
.
values
))
<
0
)
return
res
;
git_mutex_init
(
&
b
->
header
.
values_mutex
);
git_array_init
(
b
->
readers
);
reader
=
git_array_alloc
(
b
->
readers
);
if
(
!
reader
)
{
git_strmap_free
(
b
->
values
);
refcounted_strmap_free
(
b
->
header
.
values
);
return
-
1
;
}
memset
(
reader
,
0
,
sizeof
(
struct
reader
));
...
...
@@ -202,9 +293,9 @@ static int config_open(git_config_backend *cfg, git_config_level_t level)
if
(
res
==
GIT_ENOTFOUND
)
return
0
;
if
(
res
<
0
||
(
res
=
config_parse
(
b
,
reader
,
level
,
0
))
<
0
)
{
free_vars
(
b
->
values
);
b
->
values
=
NULL
;
if
(
res
<
0
||
(
res
=
config_parse
(
b
->
header
.
values
->
values
,
b
,
reader
,
level
,
0
))
<
0
)
{
refcounted_strmap_free
(
b
->
header
.
values
);
b
->
header
.
values
=
NULL
;
}
reader
=
git_array_get
(
b
->
readers
,
0
);
...
...
@@ -213,44 +304,60 @@ static int config_open(git_config_backend *cfg, git_config_level_t level)
return
res
;
}
/* The meat of the refresh, as we want to use it in different places */
static
int
config__refresh
(
git_config_backend
*
cfg
)
{
refcounted_strmap
*
values
=
NULL
,
*
tmp
;
diskfile_backend
*
b
=
(
diskfile_backend
*
)
cfg
;
struct
reader
*
reader
=
NULL
;
int
error
=
0
;
if
((
error
=
refcounted_strmap_alloc
(
&
values
))
<
0
)
goto
out
;
reader
=
git_array_get
(
b
->
readers
,
git_array_size
(
b
->
readers
)
-
1
);
if
((
error
=
config_parse
(
values
->
values
,
b
,
reader
,
b
->
level
,
0
))
<
0
)
goto
out
;
git_mutex_lock
(
&
b
->
header
.
values_mutex
);
tmp
=
b
->
header
.
values
;
b
->
header
.
values
=
values
;
values
=
tmp
;
git_mutex_unlock
(
&
b
->
header
.
values_mutex
);
out:
refcounted_strmap_free
(
values
);
git_buf_free
(
&
reader
->
buffer
);
return
error
;
}
static
int
config_refresh
(
git_config_backend
*
cfg
)
{
int
res
=
0
,
updated
=
0
,
any_updated
=
0
;
int
error
=
0
,
updated
=
0
,
any_updated
=
0
;
diskfile_backend
*
b
=
(
diskfile_backend
*
)
cfg
;
git_strmap
*
old_values
;
struct
reader
*
reader
=
NULL
;
uint32_t
i
;
for
(
i
=
0
;
i
<
git_array_size
(
b
->
readers
);
i
++
)
{
reader
=
git_array_get
(
b
->
readers
,
i
);
res
=
git_futils_readbuffer_updated
(
error
=
git_futils_readbuffer_updated
(
&
reader
->
buffer
,
reader
->
file_path
,
&
reader
->
file_mtime
,
&
reader
->
file_size
,
&
updated
);
if
(
res
<
0
)
return
(
res
==
GIT_ENOTFOUND
)
?
0
:
res
;
if
(
error
<
0
)
return
(
error
==
GIT_ENOTFOUND
)
?
0
:
error
;
if
(
updated
)
any_updated
=
1
;
}
if
(
!
any_updated
)
return
(
res
==
GIT_ENOTFOUND
)
?
0
:
res
;
/* need to reload - store old values and prep for reload */
old_values
=
b
->
values
;
if
((
res
=
git_strmap_alloc
(
&
b
->
values
))
<
0
)
{
b
->
values
=
old_values
;
}
else
if
((
res
=
config_parse
(
b
,
reader
,
b
->
level
,
0
))
<
0
)
{
free_vars
(
b
->
values
);
b
->
values
=
old_values
;
}
else
{
free_vars
(
old_values
);
}
return
(
error
==
GIT_ENOTFOUND
)
?
0
:
error
;
git_buf_free
(
&
reader
->
buffer
);
return
res
;
return
config__refresh
(
cfg
);
}
static
void
backend_free
(
git_config_backend
*
_backend
)
...
...
@@ -268,13 +375,14 @@ static void backend_free(git_config_backend *_backend)
git_array_clear
(
backend
->
readers
);
git__free
(
backend
->
file_path
);
free_vars
(
backend
->
values
);
refcounted_strmap_free
(
backend
->
header
.
values
);
git__free
(
backend
);
}
static
void
config_iterator_free
(
git_config_iterator
*
iter
)
{
iter
->
backend
->
free
(
iter
->
backend
);
git__free
(
iter
);
}
...
...
@@ -283,12 +391,13 @@ static int config_iterator_next(
git_config_iterator
*
iter
)
{
git_config_file_iter
*
it
=
(
git_config_file_iter
*
)
iter
;
diskfile_backend
*
b
=
(
diskfile_backend
*
)
it
->
parent
.
backend
;
diskfile_header
*
h
=
(
diskfile_header
*
)
it
->
parent
.
backend
;
git_strmap
*
values
=
h
->
values
->
values
;
int
err
=
0
;
cvar_t
*
var
;
if
(
it
->
next_var
==
NULL
)
{
err
=
git_strmap_next
((
void
**
)
&
var
,
&
(
it
->
iter
),
b
->
values
);
err
=
git_strmap_next
((
void
**
)
&
var
,
&
(
it
->
iter
),
values
);
}
else
{
var
=
it
->
next_var
;
}
...
...
@@ -308,15 +417,28 @@ static int config_iterator_new(
git_config_iterator
**
iter
,
struct
git_config_backend
*
backend
)
{
diskfile_backend
*
b
=
(
diskfile_backend
*
)
backend
;
git_config_file_iter
*
it
=
git__calloc
(
1
,
sizeof
(
git_config_file_iter
));
diskfile_header
*
h
;
git_config_file_iter
*
it
;
git_config_backend
*
snapshot
;
diskfile_backend
*
b
=
(
diskfile_backend
*
)
backend
;
int
error
;
GIT_UNUSED
(
b
);
if
((
error
=
config_snapshot
(
&
snapshot
,
backend
))
<
0
)
return
error
;
if
((
error
=
snapshot
->
open
(
snapshot
,
b
->
level
))
<
0
)
return
error
;
it
=
git__calloc
(
1
,
sizeof
(
git_config_file_iter
));
GITERR_CHECK_ALLOC
(
it
);
it
->
parent
.
backend
=
backend
;
it
->
iter
=
git_strmap_begin
(
b
->
values
);
h
=
(
diskfile_header
*
)
snapshot
;
/* strmap_begin() is currently a macro returning 0 */
GIT_UNUSED
(
h
);
it
->
parent
.
backend
=
snapshot
;
it
->
iter
=
git_strmap_begin
(
h
->
values
);
it
->
next_var
=
NULL
;
it
->
parent
.
next
=
config_iterator_next
;
...
...
@@ -328,8 +450,9 @@ static int config_iterator_new(
static
int
config_set
(
git_config_backend
*
cfg
,
const
char
*
name
,
const
char
*
value
)
{
cvar_t
*
var
=
NULL
,
*
old_var
=
NULL
;
diskfile_backend
*
b
=
(
diskfile_backend
*
)
cfg
;
refcounted_strmap
*
map
;
git_strmap
*
values
;
char
*
key
,
*
esc_value
=
NULL
;
khiter_t
pos
;
int
rval
,
ret
;
...
...
@@ -337,93 +460,82 @@ static int config_set(git_config_backend *cfg, const char *name, const char *val
if
((
rval
=
git_config__normalize_name
(
name
,
&
key
))
<
0
)
return
rval
;
map
=
refcounted_strmap_take
(
&
b
->
header
);
values
=
map
->
values
;
/*
* Try to find it in the existing values and update it if it
* only has one value.
*/
pos
=
git_strmap_lookup_index
(
b
->
values
,
key
);
if
(
git_strmap_valid_index
(
b
->
values
,
pos
))
{
cvar_t
*
existing
=
git_strmap_value_at
(
b
->
values
,
pos
);
char
*
tmp
=
NULL
;
git__free
(
key
);
pos
=
git_strmap_lookup_index
(
values
,
key
);
if
(
git_strmap_valid_index
(
values
,
pos
))
{
cvar_t
*
existing
=
git_strmap_value_at
(
values
,
pos
);
if
(
existing
->
next
!=
NULL
)
{
giterr_set
(
GITERR_CONFIG
,
"Multivar incompatible with simple set"
);
return
-
1
;
ret
=
-
1
;
goto
out
;
}
/* don't update if old and new values already match */
if
((
!
existing
->
entry
->
value
&&
!
value
)
||
(
existing
->
entry
->
value
&&
value
&&
!
strcmp
(
existing
->
entry
->
value
,
value
)))
return
0
;
if
(
value
)
{
tmp
=
git__strdup
(
value
);
GITERR_CHECK_ALLOC
(
tmp
);
esc_value
=
escape_value
(
value
);
GITERR_CHECK_ALLOC
(
esc_value
);
(
existing
->
entry
->
value
&&
value
&&
!
strcmp
(
existing
->
entry
->
value
,
value
)))
{
ret
=
0
;
goto
out
;
}
git__free
((
void
*
)
existing
->
entry
->
value
);
existing
->
entry
->
value
=
tmp
;
ret
=
config_write
(
b
,
existing
->
entry
->
name
,
NULL
,
esc_value
);
git__free
(
esc_value
);
return
ret
;
}
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
->
entry
->
name
=
key
;
var
->
entry
->
value
=
NULL
;
/* No early returns due to sanity checks, let's write it out and refresh */
if
(
value
)
{
var
->
entry
->
value
=
git__strdup
(
value
);
GITERR_CHECK_ALLOC
(
var
->
entry
->
value
);
esc_value
=
escape_value
(
value
);
GITERR_CHECK_ALLOC
(
esc_value
);
}
if
((
ret
=
config_write
(
b
,
key
,
NULL
,
esc_value
))
<
0
)
{
git__free
(
esc_value
);
cvar_free
(
var
);
return
ret
;
}
if
((
ret
=
config_write
(
b
,
key
,
NULL
,
esc_value
))
<
0
)
goto
out
;
git__free
(
esc_value
);
git_strmap_insert2
(
b
->
values
,
key
,
var
,
old_var
,
rval
);
if
(
rval
<
0
)
return
-
1
;
if
(
old_var
!=
NULL
)
cvar_free
(
old_var
);
ret
=
config_refresh
(
cfg
);
return
0
;
out:
refcounted_strmap_free
(
map
);
git__free
(
esc_value
);
git__free
(
key
);
return
ret
;
}
/*
* Internal function that actually gets the value in string form
*/
static
int
config_get
(
const
git_config_backend
*
cfg
,
const
char
*
key
,
const
git_config_entry
**
out
)
static
int
config_get
(
git_config_backend
*
cfg
,
const
char
*
key
,
const
git_config_entry
**
out
)
{
diskfile_backend
*
b
=
(
diskfile_backend
*
)
cfg
;
khiter_t
pos
=
git_strmap_lookup_index
(
b
->
values
,
key
);
diskfile_header
*
h
=
(
diskfile_header
*
)
cfg
;
refcounted_strmap
*
map
;
git_strmap
*
values
;
khiter_t
pos
;
cvar_t
*
var
;
int
error
;
if
(
!
h
->
readonly
&&
((
error
=
config_refresh
(
cfg
))
<
0
))
return
error
;
map
=
refcounted_strmap_take
(
h
);
values
=
map
->
values
;
pos
=
git_strmap_lookup_index
(
values
,
key
);
/* no error message; the config system will write one */
if
(
!
git_strmap_valid_index
(
b
->
values
,
pos
))
if
(
!
git_strmap_valid_index
(
values
,
pos
))
{
refcounted_strmap_free
(
map
);
return
GIT_ENOTFOUND
;
}
var
=
git_strmap_value_at
(
b
->
values
,
pos
);
var
=
git_strmap_value_at
(
values
,
pos
);
while
(
var
->
next
)
var
=
var
->
next
;
refcounted_strmap_free
(
map
);
*
out
=
var
->
entry
;
return
0
;
}
...
...
@@ -431,9 +543,9 @@ static int config_get(const git_config_backend *cfg, const char *key, const git_
static
int
config_set_multivar
(
git_config_backend
*
cfg
,
const
char
*
name
,
const
char
*
regexp
,
const
char
*
value
)
{
int
replaced
=
0
;
cvar_t
*
var
,
*
newvar
;
diskfile_backend
*
b
=
(
diskfile_backend
*
)
cfg
;
refcounted_strmap
*
map
;
git_strmap
*
values
;
char
*
key
;
regex_t
preg
;
int
result
;
...
...
@@ -444,62 +556,33 @@ static int config_set_multivar(
if
((
result
=
git_config__normalize_name
(
name
,
&
key
))
<
0
)
return
result
;
pos
=
git_strmap_lookup_index
(
b
->
values
,
key
);
if
(
!
git_strmap_valid_index
(
b
->
values
,
pos
))
{
map
=
refcounted_strmap_take
(
&
b
->
header
);
values
=
b
->
header
.
values
->
values
;
pos
=
git_strmap_lookup_index
(
values
,
key
);
if
(
!
git_strmap_valid_index
(
values
,
pos
))
{
/* If we don't have it, behave like a normal set */
result
=
config_set
(
cfg
,
name
,
value
);
refcounted_strmap_free
(
map
);
git__free
(
key
);
return
result
;
}
var
=
git_strmap_value_at
(
b
->
values
,
pos
);
result
=
regcomp
(
&
preg
,
regexp
,
REG_EXTENDED
);
if
(
result
<
0
)
{
git__free
(
key
);
giterr_set_regex
(
&
preg
,
result
);
regfree
(
&
preg
);
return
-
1
;
}
for
(;;)
{
if
(
regexec
(
&
preg
,
var
->
entry
->
value
,
0
,
NULL
,
0
)
==
0
)
{
char
*
tmp
=
git__strdup
(
value
);
GITERR_CHECK_ALLOC
(
tmp
);
git__free
((
void
*
)
var
->
entry
->
value
);
var
->
entry
->
value
=
tmp
;
replaced
=
1
;
}
if
(
var
->
next
==
NULL
)
break
;
var
=
var
->
next
;
result
=
-
1
;
goto
out
;
}
/* If we've reached the end of the variables and we haven't found it yet, we need to append it */
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
));
/* If we do have it, set call config_write() and reload */
if
((
result
=
config_write
(
b
,
key
,
&
preg
,
value
))
<
0
)
goto
out
;
newvar
->
entry
->
name
=
git__strdup
(
var
->
entry
->
name
);
GITERR_CHECK_ALLOC
(
newvar
->
entry
->
name
);
newvar
->
entry
->
value
=
git__strdup
(
value
);
GITERR_CHECK_ALLOC
(
newvar
->
entry
->
value
);
newvar
->
entry
->
level
=
var
->
entry
->
level
;
var
->
next
=
newvar
;
}
result
=
config_write
(
b
,
key
,
&
preg
,
value
);
result
=
config_refresh
(
cfg
);
out:
refcounted_strmap_free
(
map
);
git__free
(
key
);
regfree
(
&
preg
);
...
...
@@ -510,6 +593,7 @@ static int config_delete(git_config_backend *cfg, const char *name)
{
cvar_t
*
var
;
diskfile_backend
*
b
=
(
diskfile_backend
*
)
cfg
;
refcounted_strmap
*
map
;
git_strmap
*
values
;
char
*
key
;
int
result
;
khiter_t
pos
;
...
...
@@ -517,35 +601,37 @@ static int config_delete(git_config_backend *cfg, const char *name)
if
((
result
=
git_config__normalize_name
(
name
,
&
key
))
<
0
)
return
result
;
pos
=
git_strmap_lookup_index
(
b
->
values
,
key
);
map
=
refcounted_strmap_take
(
&
b
->
header
);
values
=
b
->
header
.
values
->
values
;
pos
=
git_strmap_lookup_index
(
values
,
key
);
git__free
(
key
);
if
(
!
git_strmap_valid_index
(
b
->
values
,
pos
))
{
if
(
!
git_strmap_valid_index
(
values
,
pos
))
{
refcounted_strmap_free
(
map
);
giterr_set
(
GITERR_CONFIG
,
"Could not find key '%s' to delete"
,
name
);
return
GIT_ENOTFOUND
;
}
var
=
git_strmap_value_at
(
b
->
values
,
pos
);
var
=
git_strmap_value_at
(
values
,
pos
);
refcounted_strmap_free
(
map
);
if
(
var
->
next
!=
NULL
)
{
giterr_set
(
GITERR_CONFIG
,
"Cannot delete multivar with a single delete"
);
return
-
1
;
}
git_strmap_delete_at
(
b
->
values
,
pos
);
result
=
config_write
(
b
,
var
->
entry
->
name
,
NULL
,
NULL
);
if
((
result
=
config_write
(
b
,
var
->
entry
->
name
,
NULL
,
NULL
))
<
0
)
return
result
;
cvar_free
(
var
);
return
result
;
return
config_refresh
(
cfg
);
}
static
int
config_delete_multivar
(
git_config_backend
*
cfg
,
const
char
*
name
,
const
char
*
regexp
)
{
cvar_t
*
var
,
*
prev
=
NULL
,
*
new_head
=
NULL
;
cvar_t
**
to_delete
;
int
to_delete_idx
;
diskfile_backend
*
b
=
(
diskfile_backend
*
)
cfg
;
refcounted_strmap
*
map
;
git_strmap
*
values
;
char
*
key
;
regex_t
preg
;
int
result
;
...
...
@@ -554,66 +640,45 @@ static int config_delete_multivar(git_config_backend *cfg, const char *name, con
if
((
result
=
git_config__normalize_name
(
name
,
&
key
))
<
0
)
return
result
;
pos
=
git_strmap_lookup_index
(
b
->
values
,
key
);
map
=
refcounted_strmap_take
(
&
b
->
header
);
values
=
b
->
header
.
values
->
values
;
if
(
!
git_strmap_valid_index
(
b
->
values
,
pos
))
{
giterr_set
(
GITERR_CONFIG
,
"Could not find key '%s' to delete"
,
name
);
pos
=
git_strmap_lookup_index
(
values
,
key
);
if
(
!
git_strmap_valid_index
(
values
,
pos
))
{
refcounted_strmap_free
(
map
);
git__free
(
key
);
giterr_set
(
GITERR_CONFIG
,
"Could not find key '%s' to delete"
,
name
);
return
GIT_ENOTFOUND
;
}
var
=
git_strmap_value_at
(
b
->
values
,
pos
);
refcounted_strmap_free
(
map
);
result
=
regcomp
(
&
preg
,
regexp
,
REG_EXTENDED
);
if
(
result
<
0
)
{
git__free
(
key
);
giterr_set_regex
(
&
preg
,
result
);
re
gfree
(
&
preg
)
;
return
-
1
;
re
sult
=
-
1
;
goto
out
;
}
to_delete
=
git__calloc
(
cvar_length
(
var
),
sizeof
(
cvar_t
*
));
GITERR_CHECK_ALLOC
(
to_delete
);
to_delete_idx
=
0
;
if
((
result
=
config_write
(
b
,
key
,
&
preg
,
NULL
))
<
0
)
goto
out
;
while
(
var
!=
NULL
)
{
cvar_t
*
next
=
var
->
next
;
if
(
regexec
(
&
preg
,
var
->
entry
->
value
,
0
,
NULL
,
0
)
==
0
)
{
// If we are past the head, reattach previous node to next one,
// otherwise set the new head for the strmap.
if
(
prev
!=
NULL
)
{
prev
->
next
=
next
;
}
else
{
new_head
=
next
;
}
to_delete
[
to_delete_idx
++
]
=
var
;
}
else
{
prev
=
var
;
}
var
=
next
;
}
if
(
new_head
!=
NULL
)
{
git_strmap_set_value_at
(
b
->
values
,
pos
,
new_head
);
}
else
{
git_strmap_delete_at
(
b
->
values
,
pos
);
}
if
(
to_delete_idx
>
0
)
result
=
config_write
(
b
,
key
,
&
preg
,
NULL
);
while
(
to_delete_idx
--
>
0
)
cvar_free
(
to_delete
[
to_delete_idx
]);
result
=
config_refresh
(
cfg
);
out:
git__free
(
key
);
git__free
(
to_delete
);
regfree
(
&
preg
);
return
result
;
}
static
int
config_snapshot
(
git_config_backend
**
out
,
git_config_backend
*
in
)
{
diskfile_backend
*
b
=
(
diskfile_backend
*
)
in
;
return
git_config_file__snapshot
(
out
,
b
);
}
int
git_config_file__ondisk
(
git_config_backend
**
out
,
const
char
*
path
)
{
diskfile_backend
*
backend
;
...
...
@@ -621,20 +686,119 @@ int git_config_file__ondisk(git_config_backend **out, const char *path)
backend
=
git__calloc
(
1
,
sizeof
(
diskfile_backend
));
GITERR_CHECK_ALLOC
(
backend
);
backend
->
parent
.
version
=
GIT_CONFIG_BACKEND_VERSION
;
backend
->
header
.
parent
.
version
=
GIT_CONFIG_BACKEND_VERSION
;
backend
->
file_path
=
git__strdup
(
path
);
GITERR_CHECK_ALLOC
(
backend
->
file_path
);
backend
->
parent
.
open
=
config_open
;
backend
->
parent
.
get
=
config_get
;
backend
->
parent
.
set
=
config_set
;
backend
->
parent
.
set_multivar
=
config_set_multivar
;
backend
->
parent
.
del
=
config_delete
;
backend
->
parent
.
del_multivar
=
config_delete_multivar
;
backend
->
parent
.
iterator
=
config_iterator_new
;
backend
->
parent
.
refresh
=
config_refresh
;
backend
->
parent
.
free
=
backend_free
;
backend
->
header
.
parent
.
open
=
config_open
;
backend
->
header
.
parent
.
get
=
config_get
;
backend
->
header
.
parent
.
set
=
config_set
;
backend
->
header
.
parent
.
set_multivar
=
config_set_multivar
;
backend
->
header
.
parent
.
del
=
config_delete
;
backend
->
header
.
parent
.
del_multivar
=
config_delete_multivar
;
backend
->
header
.
parent
.
iterator
=
config_iterator_new
;
backend
->
header
.
parent
.
refresh
=
config_refresh
;
backend
->
header
.
parent
.
snapshot
=
config_snapshot
;
backend
->
header
.
parent
.
free
=
backend_free
;
*
out
=
(
git_config_backend
*
)
backend
;
return
0
;
}
static
int
config_set_readonly
(
git_config_backend
*
cfg
,
const
char
*
name
,
const
char
*
value
)
{
GIT_UNUSED
(
cfg
);
GIT_UNUSED
(
name
);
GIT_UNUSED
(
value
);
return
config_error_readonly
();
}
static
int
config_set_multivar_readonly
(
git_config_backend
*
cfg
,
const
char
*
name
,
const
char
*
regexp
,
const
char
*
value
)
{
GIT_UNUSED
(
cfg
);
GIT_UNUSED
(
name
);
GIT_UNUSED
(
regexp
);
GIT_UNUSED
(
value
);
return
config_error_readonly
();
}
static
int
config_delete_multivar_readonly
(
git_config_backend
*
cfg
,
const
char
*
name
,
const
char
*
regexp
)
{
GIT_UNUSED
(
cfg
);
GIT_UNUSED
(
name
);
GIT_UNUSED
(
regexp
);
return
config_error_readonly
();
}
static
int
config_delete_readonly
(
git_config_backend
*
cfg
,
const
char
*
name
)
{
GIT_UNUSED
(
cfg
);
GIT_UNUSED
(
name
);
return
config_error_readonly
();
}
static
int
config_refresh_readonly
(
git_config_backend
*
cfg
)
{
GIT_UNUSED
(
cfg
);
return
config_error_readonly
();
}
static
void
backend_readonly_free
(
git_config_backend
*
_backend
)
{
diskfile_backend
*
backend
=
(
diskfile_backend
*
)
_backend
;
if
(
backend
==
NULL
)
return
;
refcounted_strmap_free
(
backend
->
header
.
values
);
git__free
(
backend
);
}
static
int
config_readonly_open
(
git_config_backend
*
cfg
,
git_config_level_t
level
)
{
diskfile_readonly_backend
*
b
=
(
diskfile_readonly_backend
*
)
cfg
;
diskfile_backend
*
src
=
b
->
snapshot_from
;
refcounted_strmap
*
src_map
;
/* We're just copying data, don't care about the level */
GIT_UNUSED
(
level
);
src_map
=
refcounted_strmap_take
(
&
src
->
header
);
b
->
header
.
values
=
src_map
;
return
0
;
}
int
git_config_file__snapshot
(
git_config_backend
**
out
,
diskfile_backend
*
in
)
{
diskfile_readonly_backend
*
backend
;
backend
=
git__calloc
(
1
,
sizeof
(
diskfile_readonly_backend
));
GITERR_CHECK_ALLOC
(
backend
);
backend
->
header
.
parent
.
version
=
GIT_CONFIG_BACKEND_VERSION
;
backend
->
snapshot_from
=
in
;
backend
->
header
.
readonly
=
1
;
backend
->
header
.
parent
.
version
=
GIT_CONFIG_BACKEND_VERSION
;
backend
->
header
.
parent
.
open
=
config_readonly_open
;
backend
->
header
.
parent
.
get
=
config_get
;
backend
->
header
.
parent
.
set
=
config_set_readonly
;
backend
->
header
.
parent
.
set_multivar
=
config_set_multivar_readonly
;
backend
->
header
.
parent
.
del
=
config_delete_readonly
;
backend
->
header
.
parent
.
del_multivar
=
config_delete_multivar_readonly
;
backend
->
header
.
parent
.
iterator
=
config_iterator_new
;
backend
->
header
.
parent
.
refresh
=
config_refresh_readonly
;
backend
->
header
.
parent
.
free
=
backend_readonly_free
;
*
out
=
(
git_config_backend
*
)
backend
;
...
...
@@ -1014,16 +1178,15 @@ static int included_path(git_buf *out, const char *dir, const char *path)
return
git_path_join_unrooted
(
out
,
path
,
dir
,
NULL
);
}
static
int
config_parse
(
diskfile_backend
*
cfg_file
,
struct
reader
*
reader
,
git_config_level_t
level
,
int
depth
)
static
int
config_parse
(
git_strmap
*
values
,
diskfile_backend
*
cfg_file
,
struct
reader
*
reader
,
git_config_level_t
level
,
int
depth
)
{
int
c
;
char
*
current_section
=
NULL
;
char
*
var_name
;
char
*
var_value
;
cvar_t
*
var
,
*
existing
;
cvar_t
*
var
;
git_buf
buf
=
GIT_BUF_INIT
;
int
result
=
0
;
khiter_t
pos
;
uint32_t
reader_idx
;
if
(
depth
>=
MAX_INCLUDE_DEPTH
)
{
...
...
@@ -1088,21 +1251,13 @@ static int config_parse(diskfile_backend *cfg_file, struct reader *reader, git_c
var
->
entry
->
level
=
level
;
var
->
included
=
!!
depth
;
/* Add or append the new config option */
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
->
entry
->
name
,
var
,
result
);
if
(
result
<
0
)
break
;
if
((
result
=
append_entry
(
values
,
var
))
<
0
)
break
;
else
result
=
0
;
}
else
{
existing
=
git_strmap_value_at
(
cfg_file
->
values
,
pos
);
while
(
existing
->
next
!=
NULL
)
{
existing
=
existing
->
next
;
}
existing
->
next
=
var
;
}
/* Add or append the new config option */
if
(
!
git__strcmp
(
var
->
entry
->
name
,
"include.path"
))
{
struct
reader
*
r
;
git_buf
path
=
GIT_BUF_INIT
;
...
...
@@ -1131,7 +1286,7 @@ static int config_parse(diskfile_backend *cfg_file, struct reader *reader, git_c
&
r
->
file_size
,
NULL
))
<
0
)
break
;
result
=
config_parse
(
cfg_file
,
r
,
level
,
depth
+
1
);
result
=
config_parse
(
values
,
cfg_file
,
r
,
level
,
depth
+
1
);
r
=
git_array_get
(
cfg_file
->
readers
,
index
);
git_buf_free
(
&
r
->
buffer
);
...
...
@@ -1374,7 +1529,7 @@ static int config_write(diskfile_backend *cfg, const char *key, const regex_t *p
* this, but instead we'll handle it gracefully with an error. */
if
(
value
==
NULL
)
{
giterr_set
(
GITERR_CONFIG
,
"
R
ace condition when writing a config file (a cvar has been removed)"
);
"
r
ace condition when writing a config file (a cvar has been removed)"
);
goto
rewrite_fail
;
}
...
...
src/diff_driver.c
View file @
d2c4d1c6
...
...
@@ -219,7 +219,7 @@ static int git_diff_driver_load(
git_diff_driver
*
drv
=
NULL
;
size_t
namelen
=
strlen
(
driver_name
);
khiter_t
pos
;
git_config
*
cfg
;
git_config
*
cfg
,
*
repo_cfg
;
git_buf
name
=
GIT_BUF_INIT
;
const
git_config_entry
*
ce
;
bool
found_driver
=
false
;
...
...
@@ -234,7 +234,7 @@ static int git_diff_driver_load(
}
/* if you can't read config for repo, just use default driver */
if
(
git_repository_config_
_weakptr
(
&
cfg
,
repo
)
<
0
)
{
if
(
git_repository_config_
snapshot
(
&
cfg
,
repo
)
<
0
)
{
giterr_clear
();
goto
done
;
}
...
...
@@ -321,6 +321,7 @@ static int git_diff_driver_load(
done:
git_buf_free
(
&
name
);
git_config_free
(
cfg
);
if
(
!*
out
)
{
int
error2
=
git_diff_driver_builtin
(
out
,
reg
,
driver_name
);
...
...
src/pack-objects.c
View file @
d2c4d1c6
...
...
@@ -90,8 +90,8 @@ static int packbuilder_config(git_packbuilder *pb)
int
ret
;
int64_t
val
;
if
(
git_repository_config__weakptr
(
&
config
,
pb
->
repo
)
<
0
)
return
-
1
;
if
(
(
ret
=
git_repository_config_snapshot
(
&
config
,
pb
->
repo
)
)
<
0
)
return
ret
;
#define config_get(KEY,DST,DFLT) do { \
ret = git_config_get_int64(&val, config, KEY); \
...
...
@@ -109,6 +109,8 @@ static int packbuilder_config(git_packbuilder *pb)
#undef config_get
git_config_free
(
config
);
return
0
;
}
...
...
src/remote.c
View file @
d2c4d1c6
...
...
@@ -356,8 +356,8 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name)
if
((
error
=
ensure_remote_name_is_valid
(
name
))
<
0
)
return
error
;
if
(
git_repository_config__weakptr
(
&
config
,
repo
)
<
0
)
return
-
1
;
if
(
(
error
=
git_repository_config_snapshot
(
&
config
,
repo
)
)
<
0
)
return
error
;
remote
=
git__malloc
(
sizeof
(
git_remote
));
GITERR_CHECK_ALLOC
(
remote
);
...
...
@@ -437,6 +437,7 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name)
*
out
=
remote
;
cleanup:
git_config_free
(
config
);
git_buf_free
(
&
buf
);
if
(
error
<
0
)
...
...
src/repository.c
View file @
d2c4d1c6
...
...
@@ -169,13 +169,9 @@ int git_repository_new(git_repository **out)
return
0
;
}
static
int
load_config_data
(
git_repository
*
repo
)
static
int
load_config_data
(
git_repository
*
repo
,
const
git_config
*
config
)
{
int
is_bare
;
git_config
*
config
;
if
(
git_repository_config__weakptr
(
&
config
,
repo
)
<
0
)
return
-
1
;
/* Try to figure out if it's bare, default to non-bare if it's not set */
if
(
git_config_get_bool
(
&
is_bare
,
config
,
"core.bare"
)
<
0
)
...
...
@@ -186,19 +182,15 @@ static int load_config_data(git_repository *repo)
return
0
;
}
static
int
load_workdir
(
git_repository
*
repo
,
git_buf
*
parent_path
)
static
int
load_workdir
(
git_repository
*
repo
,
git_
config
*
config
,
git_
buf
*
parent_path
)
{
int
error
;
git_config
*
config
;
const
git_config_entry
*
ce
;
git_buf
worktree
=
GIT_BUF_INIT
;
if
(
repo
->
is_bare
)
return
0
;
if
((
error
=
git_repository_config__weakptr
(
&
config
,
repo
))
<
0
)
return
error
;
if
((
error
=
git_config__lookup_entry
(
&
ce
,
config
,
"core.worktree"
,
false
))
<
0
)
return
error
;
...
...
@@ -451,6 +443,7 @@ int git_repository_open_ext(
int
error
;
git_buf
path
=
GIT_BUF_INIT
,
parent
=
GIT_BUF_INIT
;
git_repository
*
repo
;
git_config
*
config
;
if
(
repo_ptr
)
*
repo_ptr
=
NULL
;
...
...
@@ -465,15 +458,20 @@ int git_repository_open_ext(
repo
->
path_repository
=
git_buf_detach
(
&
path
);
GITERR_CHECK_ALLOC
(
repo
->
path_repository
);
if
((
error
=
git_repository_config_snapshot
(
&
config
,
repo
))
<
0
)
return
error
;
if
((
flags
&
GIT_REPOSITORY_OPEN_BARE
)
!=
0
)
repo
->
is_bare
=
1
;
else
if
((
error
=
load_config_data
(
repo
))
<
0
||
(
error
=
load_workdir
(
repo
,
&
parent
))
<
0
)
else
if
((
error
=
load_config_data
(
repo
,
config
))
<
0
||
(
error
=
load_workdir
(
repo
,
config
,
&
parent
))
<
0
)
{
git_config_free
(
config
);
git_repository_free
(
repo
);
return
error
;
}
git_config_free
(
config
);
git_buf_free
(
&
parent
);
*
repo_ptr
=
repo
;
return
0
;
...
...
@@ -627,6 +625,16 @@ int git_repository_config(git_config **out, git_repository *repo)
return
0
;
}
int
git_repository_config_snapshot
(
git_config
**
out
,
git_repository
*
repo
)
{
git_config
*
weak
;
if
(
git_repository_config__weakptr
(
&
weak
,
repo
)
<
0
)
return
-
1
;
return
git_config_snapshot
(
out
,
weak
);
}
void
git_repository_set_config
(
git_repository
*
repo
,
git_config
*
config
)
{
assert
(
repo
&&
config
);
...
...
src/signature.c
View file @
d2c4d1c6
...
...
@@ -144,7 +144,7 @@ int git_signature_default(git_signature **out, git_repository *repo)
git_config
*
cfg
;
const
char
*
user_name
,
*
user_email
;
if
((
error
=
git_repository_config
(
&
cfg
,
repo
))
<
0
)
if
((
error
=
git_repository_config
_snapshot
(
&
cfg
,
repo
))
<
0
)
return
error
;
if
(
!
(
error
=
git_config_get_string
(
&
user_name
,
cfg
,
"user.name"
))
&&
...
...
tests/config/multivar.c
View file @
d2c4d1c6
...
...
@@ -231,13 +231,13 @@ void test_config_multivar__delete(void)
n
=
0
;
cl_git_pass
(
git_config_get_multivar_foreach
(
cfg
,
_name
,
NULL
,
cb
,
&
n
));
cl_assert
(
n
==
2
);
cl_assert
_equal_i
(
2
,
n
);
cl_git_pass
(
git_config_delete_multivar
(
cfg
,
_name
,
"github"
));
n
=
0
;
cl_git_pass
(
git_config_get_multivar_foreach
(
cfg
,
_name
,
NULL
,
cb
,
&
n
));
cl_assert
(
n
==
1
);
cl_assert
_equal_i
(
1
,
n
);
git_config_free
(
cfg
);
...
...
@@ -245,7 +245,7 @@ void test_config_multivar__delete(void)
n
=
0
;
cl_git_pass
(
git_config_get_multivar_foreach
(
cfg
,
_name
,
NULL
,
cb
,
&
n
));
cl_assert
(
n
==
1
);
cl_assert
_equal_i
(
1
,
n
);
git_config_free
(
cfg
);
}
...
...
tests/config/refresh.c
View file @
d2c4d1c6
...
...
@@ -26,9 +26,6 @@ void test_config_refresh__update_value(void)
cl_git_rewritefile
(
TEST_FILE
,
"[section]
\n\t
value = 10
\n\n
"
);
cl_git_pass
(
git_config_get_int32
(
&
v
,
cfg
,
"section.value"
));
cl_assert_equal_i
(
1
,
v
);
cl_git_pass
(
git_config_refresh
(
cfg
));
cl_git_pass
(
git_config_get_int32
(
&
v
,
cfg
,
"section.value"
));
...
...
@@ -53,9 +50,9 @@ void test_config_refresh__delete_value(void)
cl_git_rewritefile
(
TEST_FILE
,
"[section]
\n\t
newval = 10
\n\n
"
);
cl_git_
pass
(
git_config_get_int32
(
&
v
,
cfg
,
"section.value"
));
cl_assert_equal_i
(
1
,
v
);
cl_git_
fail
(
git_config_get_int32
(
&
v
,
cfg
,
"section.newval"
));
cl_git_
fail_with
(
GIT_ENOTFOUND
,
git_config_get_int32
(
&
v
,
cfg
,
"section.value"
));
cl_git_
pass
(
git_config_get_int32
(
&
v
,
cfg
,
"section.newval"
));
cl_git_pass
(
git_config_refresh
(
cfg
));
...
...
tests/config/snapshot.c
0 → 100644
View file @
d2c4d1c6
#include "clar_libgit2.h"
void
test_config_snapshot__create_snapshot
(
void
)
{
int32_t
tmp
;
git_config
*
cfg
,
*
snapshot
;
const
char
*
filename
=
"config-ext-change"
;
cl_git_mkfile
(
filename
,
"[old]
\n
value = 5
\n
"
);
cl_git_pass
(
git_config_open_ondisk
(
&
cfg
,
filename
));
cl_git_pass
(
git_config_get_int32
(
&
tmp
,
cfg
,
"old.value"
));
cl_assert_equal_i
(
5
,
tmp
);
cl_git_pass
(
git_config_snapshot
(
&
snapshot
,
cfg
));
/* Change the value on the file itself (simulate external process) */
cl_git_mkfile
(
filename
,
"[old]
\n
value = 56
\n
"
);
cl_git_pass
(
git_config_get_int32
(
&
tmp
,
cfg
,
"old.value"
));
cl_assert_equal_i
(
56
,
tmp
);
cl_git_pass
(
git_config_get_int32
(
&
tmp
,
snapshot
,
"old.value"
));
cl_assert_equal_i
(
5
,
tmp
);
git_config_free
(
snapshot
);
git_config_free
(
cfg
);
}
static
int
count_me
(
const
git_config_entry
*
entry
,
void
*
payload
)
{
int
*
n
=
(
int
*
)
payload
;
GIT_UNUSED
(
entry
);
(
*
n
)
++
;
return
0
;
}
void
test_config_snapshot__multivar
(
void
)
{
int
count
=
0
;
git_config
*
cfg
,
*
snapshot
;
const
char
*
filename
=
"config-file"
;
cl_git_mkfile
(
filename
,
"[old]
\n
value = 5
\n
value = 6
\n
"
);
cl_git_pass
(
git_config_open_ondisk
(
&
cfg
,
filename
));
cl_git_pass
(
git_config_get_multivar_foreach
(
cfg
,
"old.value"
,
NULL
,
count_me
,
&
count
));
cl_assert_equal_i
(
2
,
count
);
cl_git_pass
(
git_config_snapshot
(
&
snapshot
,
cfg
));
git_config_free
(
cfg
);
count
=
0
;
cl_git_pass
(
git_config_get_multivar_foreach
(
snapshot
,
"old.value"
,
NULL
,
count_me
,
&
count
));
cl_assert_equal_i
(
2
,
count
);
git_config_free
(
snapshot
);
}
tests/config/write.c
View file @
d2c4d1c6
...
...
@@ -304,3 +304,30 @@ void test_config_write__updating_a_locked_config_file_returns_ELOCKED(void)
git_config_free
(
cfg
);
}
void
test_config_write__outside_change
(
void
)
{
int32_t
tmp
;
git_config
*
cfg
;
const
char
*
filename
=
"config-ext-change"
;
cl_git_mkfile
(
filename
,
"[old]
\n
value = 5
\n
"
);
cl_git_pass
(
git_config_open_ondisk
(
&
cfg
,
filename
));
cl_git_pass
(
git_config_get_int32
(
&
tmp
,
cfg
,
"old.value"
));
/* Change the value on the file itself (simulate external process) */
cl_git_mkfile
(
filename
,
"[old]
\n
value = 6
\n
"
);
cl_git_pass
(
git_config_set_int32
(
cfg
,
"new.value"
,
7
));
cl_git_pass
(
git_config_get_int32
(
&
tmp
,
cfg
,
"old.value"
));
cl_assert_equal_i
(
6
,
tmp
);
cl_git_pass
(
git_config_refresh
(
cfg
));
cl_git_pass
(
git_config_get_int32
(
&
tmp
,
cfg
,
"old.value"
));
cl_assert_equal_i
(
6
,
tmp
);
git_config_free
(
cfg
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment