mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-04 15:20:50 +00:00
config: perform unlocking via git_transaction
This makes the API for commiting or discarding changes the same as for references.
This commit is contained in:
parent
36f784b538
commit
5340d63d38
@ -9,11 +9,10 @@ v0.23 + 1
|
|||||||
|
|
||||||
### API additions
|
### API additions
|
||||||
|
|
||||||
* `git_config_lock()` and `git_config_unlock()` have been added, which
|
* `git_config_lock()` has been added, which allow for
|
||||||
allow for transactional/atomic complex updates to the configuration,
|
transactional/atomic complex updates to the configuration, removing
|
||||||
removing the opportunity for concurrent operations and not
|
the opportunity for concurrent operations and not committing any
|
||||||
committing any changes until the unlock.
|
changes until the unlock.
|
||||||
|
|
||||||
|
|
||||||
### API removals
|
### API removals
|
||||||
|
|
||||||
|
@ -696,25 +696,16 @@ GIT_EXTERN(int) git_config_backend_foreach_match(
|
|||||||
* updates made after locking will not be visible to a reader until
|
* updates made after locking will not be visible to a reader until
|
||||||
* the file is unlocked.
|
* the file is unlocked.
|
||||||
*
|
*
|
||||||
|
* You can apply the changes by calling `git_transaction_commit()`
|
||||||
|
* before freeing the transaction. Either of these actions will unlock
|
||||||
|
* the config.
|
||||||
|
*
|
||||||
|
* @param tx the resulting transaction, use this to commit or undo the
|
||||||
|
* changes
|
||||||
* @param cfg the configuration in which to lock
|
* @param cfg the configuration in which to lock
|
||||||
* @return 0 or an error code
|
* @return 0 or an error code
|
||||||
*/
|
*/
|
||||||
GIT_EXTERN(int) git_config_lock(git_config *cfg);
|
GIT_EXTERN(int) git_config_lock(git_transaction **tx, git_config *cfg);
|
||||||
|
|
||||||
/**
|
|
||||||
* Unlock the backend with the highest priority
|
|
||||||
*
|
|
||||||
* Unlocking will allow other writers to updat the configuration
|
|
||||||
* file. Optionally, any changes performed since the lock will be
|
|
||||||
* applied to the configuration.
|
|
||||||
*
|
|
||||||
* @param cfg the configuration
|
|
||||||
* @param commit boolean which indicates whether to commit any changes
|
|
||||||
* done since locking
|
|
||||||
* @return 0 or an error code
|
|
||||||
*/
|
|
||||||
GIT_EXTERN(int) git_config_unlock(git_config *cfg, int commit);
|
|
||||||
|
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
GIT_END_DECL
|
GIT_END_DECL
|
||||||
|
@ -1144,8 +1144,9 @@ int git_config_open_default(git_config **out)
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
int git_config_lock(git_config *cfg)
|
int git_config_lock(git_transaction **out, git_config *cfg)
|
||||||
{
|
{
|
||||||
|
int error;
|
||||||
git_config_backend *file;
|
git_config_backend *file;
|
||||||
file_internal *internal;
|
file_internal *internal;
|
||||||
|
|
||||||
@ -1156,7 +1157,10 @@ int git_config_lock(git_config *cfg)
|
|||||||
}
|
}
|
||||||
file = internal->file;
|
file = internal->file;
|
||||||
|
|
||||||
return file->lock(file);
|
if ((error = file->lock(file)) < 0)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
return git_transaction_config_new(out, cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
int git_config_unlock(git_config *cfg, int commit)
|
int git_config_unlock(git_config *cfg, int commit)
|
||||||
|
15
src/config.h
15
src/config.h
@ -88,4 +88,19 @@ extern int git_config__cvar(
|
|||||||
*/
|
*/
|
||||||
int git_config_lookup_map_enum(git_cvar_t *type_out, const char **str_out,
|
int git_config_lookup_map_enum(git_cvar_t *type_out, const char **str_out,
|
||||||
const git_cvar_map *maps, size_t map_n, int enum_val);
|
const git_cvar_map *maps, size_t map_n, int enum_val);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unlock the backend with the highest priority
|
||||||
|
*
|
||||||
|
* Unlocking will allow other writers to updat the configuration
|
||||||
|
* file. Optionally, any changes performed since the lock will be
|
||||||
|
* applied to the configuration.
|
||||||
|
*
|
||||||
|
* @param cfg the configuration
|
||||||
|
* @param commit boolean which indicates whether to commit any changes
|
||||||
|
* done since locking
|
||||||
|
* @return 0 or an error code
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(int) git_config_unlock(git_config *cfg, int commit);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "pool.h"
|
#include "pool.h"
|
||||||
#include "reflog.h"
|
#include "reflog.h"
|
||||||
#include "signature.h"
|
#include "signature.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
#include "git2/transaction.h"
|
#include "git2/transaction.h"
|
||||||
#include "git2/signature.h"
|
#include "git2/signature.h"
|
||||||
@ -20,6 +21,12 @@
|
|||||||
|
|
||||||
GIT__USE_STRMAP
|
GIT__USE_STRMAP
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
TRANSACTION_NONE,
|
||||||
|
TRANSACTION_REFS,
|
||||||
|
TRANSACTION_CONFIG,
|
||||||
|
} transaction_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *name;
|
const char *name;
|
||||||
void *payload;
|
void *payload;
|
||||||
@ -39,13 +46,29 @@ typedef struct {
|
|||||||
} transaction_node;
|
} transaction_node;
|
||||||
|
|
||||||
struct git_transaction {
|
struct git_transaction {
|
||||||
|
transaction_t type;
|
||||||
git_repository *repo;
|
git_repository *repo;
|
||||||
git_refdb *db;
|
git_refdb *db;
|
||||||
|
git_config *cfg;
|
||||||
|
|
||||||
git_strmap *locks;
|
git_strmap *locks;
|
||||||
git_pool pool;
|
git_pool pool;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int git_transaction_config_new(git_transaction **out, git_config *cfg)
|
||||||
|
{
|
||||||
|
git_transaction *tx;
|
||||||
|
assert(out && cfg);
|
||||||
|
|
||||||
|
tx = git__calloc(1, sizeof(git_transaction));
|
||||||
|
GITERR_CHECK_ALLOC(tx);
|
||||||
|
|
||||||
|
tx->type = TRANSACTION_CONFIG;
|
||||||
|
tx->cfg = cfg;
|
||||||
|
*out = tx;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int git_transaction_new(git_transaction **out, git_repository *repo)
|
int git_transaction_new(git_transaction **out, git_repository *repo)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
@ -71,6 +94,7 @@ int git_transaction_new(git_transaction **out, git_repository *repo)
|
|||||||
if ((error = git_repository_refdb(&tx->db, repo)) < 0)
|
if ((error = git_repository_refdb(&tx->db, repo)) < 0)
|
||||||
goto on_error;
|
goto on_error;
|
||||||
|
|
||||||
|
tx->type = TRANSACTION_REFS;
|
||||||
memcpy(&tx->pool, &pool, sizeof(git_pool));
|
memcpy(&tx->pool, &pool, sizeof(git_pool));
|
||||||
tx->repo = repo;
|
tx->repo = repo;
|
||||||
*out = tx;
|
*out = tx;
|
||||||
@ -305,6 +329,14 @@ int git_transaction_commit(git_transaction *tx)
|
|||||||
|
|
||||||
assert(tx);
|
assert(tx);
|
||||||
|
|
||||||
|
if (tx->type == TRANSACTION_CONFIG) {
|
||||||
|
error = git_config_unlock(tx->cfg, true);
|
||||||
|
git_config_free(tx->cfg);
|
||||||
|
tx->cfg = NULL;
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
for (pos = kh_begin(tx->locks); pos < kh_end(tx->locks); pos++) {
|
for (pos = kh_begin(tx->locks); pos < kh_end(tx->locks); pos++) {
|
||||||
if (!git_strmap_has_data(tx->locks, pos))
|
if (!git_strmap_has_data(tx->locks, pos))
|
||||||
continue;
|
continue;
|
||||||
@ -332,6 +364,16 @@ void git_transaction_free(git_transaction *tx)
|
|||||||
|
|
||||||
assert(tx);
|
assert(tx);
|
||||||
|
|
||||||
|
if (tx->type == TRANSACTION_CONFIG) {
|
||||||
|
if (tx->cfg) {
|
||||||
|
git_config_unlock(tx->cfg, false);
|
||||||
|
git_config_free(tx->cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
git__free(tx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* start by unlocking the ones we've left hanging, if any */
|
/* start by unlocking the ones we've left hanging, if any */
|
||||||
for (pos = kh_begin(tx->locks); pos < kh_end(tx->locks); pos++) {
|
for (pos = kh_begin(tx->locks); pos < kh_end(tx->locks); pos++) {
|
||||||
if (!git_strmap_has_data(tx->locks, pos))
|
if (!git_strmap_has_data(tx->locks, pos))
|
||||||
|
14
src/transaction.h
Normal file
14
src/transaction.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) the libgit2 contributors. All rights reserved.
|
||||||
|
*
|
||||||
|
* This file is part of libgit2, distributed under the GNU GPL v2 with
|
||||||
|
* a Linking Exception. For full terms see the included COPYING file.
|
||||||
|
*/
|
||||||
|
#ifndef INCLUDE_transaction_h__
|
||||||
|
#define INCLUDE_transaction_h__
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
int git_transaction_config_new(git_transaction **out, git_config *cfg);
|
||||||
|
|
||||||
|
#endif
|
@ -637,6 +637,7 @@ void test_config_write__locking(void)
|
|||||||
{
|
{
|
||||||
git_config *cfg, *cfg2;
|
git_config *cfg, *cfg2;
|
||||||
git_config_entry *entry;
|
git_config_entry *entry;
|
||||||
|
git_transaction *tx;
|
||||||
const char *filename = "locked-file";
|
const char *filename = "locked-file";
|
||||||
|
|
||||||
/* Open the config and lock it */
|
/* Open the config and lock it */
|
||||||
@ -645,7 +646,7 @@ void test_config_write__locking(void)
|
|||||||
cl_git_pass(git_config_get_entry(&entry, cfg, "section.name"));
|
cl_git_pass(git_config_get_entry(&entry, cfg, "section.name"));
|
||||||
cl_assert_equal_s("value", entry->value);
|
cl_assert_equal_s("value", entry->value);
|
||||||
git_config_entry_free(entry);
|
git_config_entry_free(entry);
|
||||||
cl_git_pass(git_config_lock(cfg));
|
cl_git_pass(git_config_lock(&tx, cfg));
|
||||||
|
|
||||||
/* Change entries in the locked backend */
|
/* Change entries in the locked backend */
|
||||||
cl_git_pass(git_config_set_string(cfg, "section.name", "other value"));
|
cl_git_pass(git_config_set_string(cfg, "section.name", "other value"));
|
||||||
@ -665,8 +666,8 @@ void test_config_write__locking(void)
|
|||||||
git_config_entry_free(entry);
|
git_config_entry_free(entry);
|
||||||
cl_git_fail_with(GIT_ENOTFOUND, git_config_get_entry(&entry, cfg, "section2.name3"));
|
cl_git_fail_with(GIT_ENOTFOUND, git_config_get_entry(&entry, cfg, "section2.name3"));
|
||||||
|
|
||||||
git_config_unlock(cfg, true);
|
cl_git_pass(git_transaction_commit(tx));
|
||||||
git_config_free(cfg);
|
git_transaction_free(tx);
|
||||||
|
|
||||||
/* Now that we've unlocked it, we should see both updates */
|
/* Now that we've unlocked it, we should see both updates */
|
||||||
cl_git_pass(git_config_open_ondisk(&cfg, filename));
|
cl_git_pass(git_config_open_ondisk(&cfg, filename));
|
||||||
|
Loading…
Reference in New Issue
Block a user