]> git.proxmox.com Git - libgit2.git/commitdiff
config: perform unlocking via git_transaction
authorCarlos Martín Nieto <cmn@dwim.me>
Sun, 12 Jul 2015 10:50:23 +0000 (12:50 +0200)
committerCarlos Martín Nieto <cmn@dwim.me>
Wed, 12 Aug 2015 02:09:38 +0000 (04:09 +0200)
This makes the API for commiting or discarding changes the same as for
references.

CHANGELOG.md
include/git2/config.h
src/config.c
src/config.h
src/transaction.c
src/transaction.h [new file with mode: 0644]
tests/config/write.c

index 4442d0a3f3f46410df3ddc7904717df1c73efd75..5dd4b34474a19189d4dd83d118db624aa533d02c 100644 (file)
@@ -9,11 +9,10 @@ v0.23 + 1
 
 ### API additions
 
-* `git_config_lock()` and `git_config_unlock()` have been added, which
-  allow for transactional/atomic complex updates to the configuration,
-  removing the opportunity for concurrent operations and not
-  committing any changes until the unlock.
-
+* `git_config_lock()` has been added, which allow for
+  transactional/atomic complex updates to the configuration, removing
+  the opportunity for concurrent operations and not committing any
+  changes until the unlock.
 
 ### API removals
 
index 2550f8edbd2edbaa6a7f55b3724140bcf00de559..05c3ad622bb7d01741eca5dab515e802e221a024 100644 (file)
@@ -696,25 +696,16 @@ GIT_EXTERN(int) git_config_backend_foreach_match(
  * updates made after locking will not be visible to a reader until
  * the file is unlocked.
  *
- * @param cfg the configuration in which to lock
- * @return 0 or an error code
- */
-GIT_EXTERN(int) git_config_lock(git_config *cfg);
-
-/**
- * Unlock the backend with the highest priority
+ * You can apply the changes by calling `git_transaction_commit()`
+ * before freeing the transaction. Either of these actions will unlock
+ * the config.
  *
- * 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
+ * @param tx the resulting transaction, use this to commit or undo the
+ * changes
+ * @param cfg the configuration in which to lock
  * @return 0 or an error code
  */
-GIT_EXTERN(int) git_config_unlock(git_config *cfg, int commit);
-
+GIT_EXTERN(int) git_config_lock(git_transaction **tx, git_config *cfg);
 
 /** @} */
 GIT_END_DECL
index 937d00dcb6e0690c7a63fb49fe54f635b5848a83..2df1fc80e30bd7db5a42be3412b034f1cbdfcbaf 100644 (file)
@@ -1144,8 +1144,9 @@ int git_config_open_default(git_config **out)
        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;
        file_internal *internal;
 
@@ -1156,7 +1157,10 @@ int git_config_lock(git_config *cfg)
        }
        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)
index f257cc90faf5713f351325976f1c3f811c414b2a..ba745331a0236431f5b0639a3e8f4c3124e11e44 100644 (file)
@@ -88,4 +88,19 @@ extern int git_config__cvar(
  */
 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);
+
+/**
+ * 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
index e8331891cb7de968d80529b5c4fc223e8381f539..e9639bf970ec42114334e1c9c81d57abd6d22704 100644 (file)
@@ -12,6 +12,7 @@
 #include "pool.h"
 #include "reflog.h"
 #include "signature.h"
+#include "config.h"
 
 #include "git2/transaction.h"
 #include "git2/signature.h"
 
 GIT__USE_STRMAP
 
+typedef enum {
+       TRANSACTION_NONE,
+       TRANSACTION_REFS,
+       TRANSACTION_CONFIG,
+} transaction_t;
+
 typedef struct {
        const char *name;
        void *payload;
@@ -39,13 +46,29 @@ typedef struct {
 } transaction_node;
 
 struct git_transaction {
+       transaction_t type;
        git_repository *repo;
        git_refdb *db;
+       git_config *cfg;
 
        git_strmap *locks;
        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 error;
@@ -71,6 +94,7 @@ int git_transaction_new(git_transaction **out, git_repository *repo)
        if ((error = git_repository_refdb(&tx->db, repo)) < 0)
                goto on_error;
 
+       tx->type = TRANSACTION_REFS;
        memcpy(&tx->pool, &pool, sizeof(git_pool));
        tx->repo = repo;
        *out = tx;
@@ -305,6 +329,14 @@ int git_transaction_commit(git_transaction *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++) {
                if (!git_strmap_has_data(tx->locks, pos))
                        continue;
@@ -332,6 +364,16 @@ void git_transaction_free(git_transaction *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 */
        for (pos = kh_begin(tx->locks); pos < kh_end(tx->locks); pos++) {
                if (!git_strmap_has_data(tx->locks, pos))
diff --git a/src/transaction.h b/src/transaction.h
new file mode 100644 (file)
index 0000000..780c068
--- /dev/null
@@ -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
index e43c26bd9c1e2c1d9477748563620ea32b1f1d3d..3d9b1a16aa472e9754ede425b48efa06b8a66469 100644 (file)
@@ -637,6 +637,7 @@ void test_config_write__locking(void)
 {
        git_config *cfg, *cfg2;
        git_config_entry *entry;
+       git_transaction *tx;
        const char *filename = "locked-file";
 
        /* 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_assert_equal_s("value", entry->value);
        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 */
        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);
        cl_git_fail_with(GIT_ENOTFOUND, git_config_get_entry(&entry, cfg, "section2.name3"));
 
-       git_config_unlock(cfg, true);
-       git_config_free(cfg);
+       cl_git_pass(git_transaction_commit(tx));
+       git_transaction_free(tx);
 
        /* Now that we've unlocked it, we should see both updates */
        cl_git_pass(git_config_open_ondisk(&cfg, filename));