Skip to content
This repository has been archived by the owner on Oct 15, 2024. It is now read-only.

Commit

Permalink
Merge pull request #4515 from atmaxinger/merge-get-conflicts
Browse files Browse the repository at this point in the history
cmerge: add methods to get all conflicting keys
  • Loading branch information
markus2330 authored Feb 6, 2023
2 parents 08222cf + adb8158 commit 3e43445
Show file tree
Hide file tree
Showing 11 changed files with 574 additions and 129 deletions.
8 changes: 7 additions & 1 deletion doc/man/man7/elektra-libs.7
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1.pre1
.TH "ELEKTRA\-LIBS" "7" "July 2022" ""
.TH "ELEKTRA\-LIBS" "7" "October 2022" ""
.SH "NAME"
\fBelektra\-libs\fR \- libs overview
.IP "" 4
Expand Down Expand Up @@ -65,6 +65,12 @@ libelektra\-meta\.so
.fi
.P
\fBlibmeta \fImeta/meta\.c\fR\fR contains metadata operations as described in \fBMETADATA\.ini \fI/doc/METADATA\.ini\fR\fR\. Currently mainly contains legacy code and some generic metadata operations\.
.SS "Libmerge"
.nf
libelektra\-merge\.so
.fi
.P
\fBlibmerge \fImerge/\fR\fR provides functionality for 3\-way merges of keysets\.
.SS "Libelektra"
Is a legacy library that provides the same functionality as \fBlibelektra\-kdb\fR and \fBlibelektra\-core\fR\. The sources can be found in \fBlibelektra \fIelektra/\fR\fR\.
.SH "Other Libraries"
Expand Down
4 changes: 4 additions & 0 deletions doc/news/_preparation_next_release.md
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,10 @@ The text below summarizes updates to the [C (and C++)-based libraries](https://w
### io

- Check file flags for `elektraIoFdSetFlags`: file flags must be exactly one of: read only, write only or read write _(Richard Stöckl @Eiskasten)_

### Merge

- Add methods `elektraMergeGetConflictingKeys` and `elektraMergeIsKeyConflicting` to check which keys were causing a merge conflict _(Maximilian Irlinger @atmaxinger)_.
- <<TODO>>
- <<TODO>>

Expand Down
1 change: 1 addition & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ foreach (file ${TESTS})
endforeach (file ${TESTS})

target_link_elektra (cascading elektra-kdb)
target_link_elektra (cmerge elektra-merge)
target_link_elektra (ksCut elektra-kdb)
target_link_elektra (kdbget elektra-kdb)
target_link_elektra (kdbget_error elektra-kdb)
Expand Down
89 changes: 89 additions & 0 deletions examples/cmerge.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/**
* @file
*
* @brief
*
* @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
*/

#include <kdb.h>
#include <kdbmerge.h>
#include <stdio.h>

static void print_results (KeySet * result, Key * resultRoot, Key * informationKey)
{
KeySet * conflictingKeys = elektraMergeGetConflictingKeys (informationKey, resultRoot);

for (elektraCursor i = 0; i < ksGetSize (conflictingKeys); i++)
{
printf ("Conflict in key %s\n", keyName (ksAtCursor (conflictingKeys, i)));
}

printf ("Result:\n");

for (elektraCursor i = 0; i < ksGetSize (result); i++)
{
Key * k = ksAtCursor (result, i);
printf ("%s = %s\n", keyName (k), keyString (k));
}

if (result == NULL)
{
printf ("Aborted.\n");
}

ksDel (conflictingKeys);
}

int main (void)
{
Key * baseRoot = keyNew ("user:/screen", KEY_END);
KeySet * base = ksNew (1, keyNew ("user:/screen/background", KEY_VALUE, "blue", KEY_END), KS_END);

Key * theirRoot = keyDup (baseRoot, KEY_CP_ALL);
KeySet * their = ksNew (2, keyNew ("user:/screen/background", KEY_VALUE, "red", KEY_END),
keyNew ("user:/screen/brightness", KEY_VALUE, "100", KEY_END), KS_END);

Key * ourRoot = keyDup (baseRoot, KEY_CP_ALL);
KeySet * our = ksNew (2, keyNew ("user:/screen/background", KEY_VALUE, "purple", KEY_END),
keyNew ("user:/screen/standby", KEY_VALUE, "on", KEY_END), KS_END);

Key * resultRoot = keyDup (baseRoot, KEY_CP_ALL);
Key * informationKey = keyDup (baseRoot, KEY_CP_ALL);

// Strategy: Abort
// Will abort due to user:/screen/background changes in both their and our
printf ("Trying merge strategy ABORT\n");
KeySet * result = elektraMerge (our, ourRoot, their, theirRoot, base, baseRoot, resultRoot, MERGE_STRATEGY_ABORT, informationKey);
print_results (result, resultRoot, informationKey);

ksDel (result);

// Strategy: Our
// Will take value of our for user:/screen/background
printf ("\nTrying merge strategy OUR\n");
result = elektraMerge (our, ourRoot, their, theirRoot, base, baseRoot, resultRoot, MERGE_STRATEGY_OUR, informationKey);
print_results (result, resultRoot, informationKey);

ksDel (result);

// Strategy: Their
// Will take value of their for user:/screen/background
printf ("\nTrying merge strategy THEIR\n");
result = elektraMerge (our, ourRoot, their, theirRoot, base, baseRoot, resultRoot, MERGE_STRATEGY_THEIR, informationKey);
print_results (result, resultRoot, informationKey);

ksDel (result);

ksDel (base);
ksDel (their);
ksDel (our);

keyDel (baseRoot);
keyDel (theirRoot);
keyDel (ourRoot);
keyDel (informationKey);
keyDel (resultRoot);

return 0;
}
14 changes: 10 additions & 4 deletions src/bindings/swig/python/merge.i
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,23 @@
#include "kdbmerge.h"
%}


ckdb::KeySet * elektraMerge (ckdb::KeySet * our, ckdb::Key * ourRoot, ckdb::KeySet * their, ckdb::Key * theirRoot, ckdb::KeySet * base, ckdb::Key * baseRoot, ckdb::Key * resultKey,
int strategy, ckdb::Key * informationKey);
ckdb::MergeStrategy strategy, ckdb::Key * informationKey);
int elektraMergeGetConflicts (ckdb::Key * informationKey);

%inline %{
// we wrap the elektraMerge function, because I haven't found a way to correctly wrap the enum ...
ckdb::KeySet * elektraMergeWrap (ckdb::KeySet * our, ckdb::Key * ourRoot, ckdb::KeySet * their, ckdb::Key * theirRoot, ckdb::KeySet * base, ckdb::Key * baseRoot, ckdb::Key * resultKey,
int strategy, ckdb::Key * informationKey) {
return elektraMerge (our, ourRoot, their, theirRoot, base, baseRoot, resultKey, (ckdb::MergeStrategy) strategy, informationKey);
}
%}

%pythoncode {
from enum import Enum

class ConflictStrategy(Enum):
ABORT = 1
INTERACTIVE = 2
OUR = 3
THEIR = 4

Expand All @@ -46,6 +52,6 @@ class MergeResult:
class Merger:
def merge(self, base, ours, theirs, root, conflictStrategy):
informationKey = kdb.Key()
res = elektraMerge(ours.keys.getKeySet(), ours.root.getKey(), theirs.keys.getKeySet(), theirs.root.getKey(), base.keys.getKeySet(), base.root.getKey(), root.getKey(), conflictStrategy.value, informationKey.getKey())
res = elektraMergeWrap(ours.keys.getKeySet(), ours.root.getKey(), theirs.keys.getKeySet(), theirs.root.getKey(), base.keys.getKeySet(), base.root.getKey(), root.getKey(), conflictStrategy.value, informationKey.getKey())
return MergeResult(res, informationKey)
};
19 changes: 13 additions & 6 deletions src/include/kdbmerge.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,32 @@
#define KDBMERGE_H_

#include "kdb.h"
#include "kdbtypes.h"

#ifdef __cplusplus
namespace ckdb
{
extern "C" {
#endif

enum
/**
* The strategy to use when a merge conflict occurs
*/
enum MergeStrategy
{
MERGE_STRATEGY_ABORT = 1,
MERGE_STRATEGY_INTERACTIVE = 2,
MERGE_STRATEGY_OUR = 3,
MERGE_STRATEGY_THEIR = 4,
MERGE_STRATEGY_ABORT = 1, /*!< Abort merging if a conflict occurs */
// MERGE_STRATEGY_INTERACTIVE = 2, /*!< Perform an interactive conflict resolution. Currently not implemented */
MERGE_STRATEGY_OUR = 3, /*!< Prefer our keys in case of conflict */
MERGE_STRATEGY_THEIR = 4, /*!< Prefer their keys in case of conflict */
};

KeySet * elektraMerge (KeySet * our, Key * ourRoot, KeySet * their, Key * theirRoot, KeySet * base, Key * baseRoot, Key * resultKey,
int strategy, Key * informationKey);
enum MergeStrategy strategy, Key * informationKey);
int elektraMergeGetConflicts (Key * informationKey);

KeySet * elektraMergeGetConflictingKeys (Key * informationKey, Key * root);
bool elektraMergeIsKeyConflicting (Key * informationKey, Key * root, Key * key);

#ifdef __cplusplus
}
}
Expand Down
8 changes: 8 additions & 0 deletions src/libs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,14 @@ libelektra-meta.so
**[libmeta](meta/meta.c)** contains metadata operations as described in **[METADATA.ini](/doc/METADATA.ini)**.
Currently mainly contains legacy code and some generic metadata operations.

### Libmerge

```
libelektra-merge.so
```

**[libmerge](merge/)** provides functionality for 3-way merges of keysets.

### Libelektra

Is a legacy library that provides the same functionality as `libelektra-kdb` and `libelektra-core`.
Expand Down
Loading

0 comments on commit 3e43445

Please sign in to comment.