Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : */
8 :
9 : #include <iostream>
10 : #include <vector>
11 :
12 : #include <cmdline.hpp>
13 : #include <keysetio.hpp>
14 :
15 : #include <mergehelper.hpp>
16 : #include <merging/automergeconfiguration.hpp>
17 : #include <merging/importmergeconfiguration.hpp>
18 : #include <merging/interactivemergestrategy.hpp>
19 : #include <merging/onesidemergeconfiguration.hpp>
20 : #include <merging/overwritemergeconfiguration.hpp>
21 :
22 : using namespace kdb;
23 : using namespace kdb::tools::merging;
24 : using namespace std;
25 :
26 160 : MergeHelper::MergeHelper ()
27 : {
28 : // TODO: this is just a quickfix, find a better solution
29 : // without eager instantiating all the strategies. Maybe even automatically
30 : // discover all available strategies
31 : // comment markus: the factory could be part of libtools
32 320 : configurationMap.insert (make_pair ("preserve", new AutoMergeConfiguration ()));
33 :
34 320 : configurationMap.insert (make_pair ("ours", new OneSideMergeConfiguration (OURS)));
35 240 : configurationMap.insert (make_pair ("theirs", new OneSideMergeConfiguration (THEIRS)));
36 :
37 : // primarily used for import
38 320 : configurationMap.insert (make_pair ("cut", new OverwriteMergeConfiguration (THEIRS)));
39 320 : configurationMap.insert (make_pair ("import", new ImportMergeConfiguration ()));
40 80 : }
41 :
42 240 : MergeHelper::~MergeHelper ()
43 : {
44 160 : vector<MergeConfiguration *> configurations = getAllConfigurations ();
45 720 : for (auto & configuration : configurations)
46 : {
47 400 : delete (configuration);
48 : }
49 80 : }
50 :
51 80 : vector<MergeConfiguration *> MergeHelper::getAllConfigurations ()
52 : {
53 80 : vector<MergeConfiguration *> result;
54 640 : for (auto & elem : configurationMap)
55 : {
56 400 : result.push_back ((elem).second);
57 : }
58 :
59 80 : return result;
60 : }
61 :
62 0 : string MergeHelper::getConfigurationList ()
63 : {
64 0 : ostringstream oss;
65 0 : for (auto & elem : configurationMap)
66 : {
67 0 : oss << (elem).first << ",";
68 : }
69 :
70 0 : return oss.str ();
71 : }
72 :
73 80 : void MergeHelper::configureMerger (Cmdline const & cl, ThreeWayMerge & merger)
74 : {
75 80 : if (cl.interactive)
76 : {
77 0 : merger.addConflictStrategy (new InteractiveMergeStrategy (cin, cout));
78 0 : cout << "Chose interactive merge" << endl;
79 : }
80 : else
81 : {
82 240 : if (configurationMap.find (cl.strategy) == configurationMap.end ())
83 : {
84 0 : throw invalid_argument ("'" + cl.strategy +
85 0 : "' is not a valid strategy. Valid strategies are: " + getConfigurationList ());
86 : }
87 :
88 80 : MergeConfiguration * configuration = configurationMap[cl.strategy];
89 80 : configuration->configureMerger (merger);
90 : }
91 80 : }
92 :
93 80 : void MergeHelper::reportResult (Cmdline const & cl, MergeResult & result, ostream & out, ostream & err)
94 : {
95 80 : if (!result.hasConflicts ())
96 : {
97 80 : if (cl.verbose)
98 : {
99 0 : out << result.getMergedKeys ().size () << " keys in the result" << endl;
100 0 : out << result.getNumberOfEqualKeys () << " keys were equal" << endl;
101 0 : out << result.getNumberOfResolvedKeys () << " keys were resolved" << endl;
102 : }
103 : }
104 : else
105 : {
106 0 : KeySet conflicts = result.getConflictSet ();
107 :
108 0 : err << conflicts.size () << " conflicts were detected that could not be resolved automatically:" << endl;
109 0 : conflicts.rewind ();
110 0 : Key current;
111 0 : while ((current = conflicts.next ()))
112 : {
113 0 : string ourConflict = current.getMeta<string> ("conflict/operation/our");
114 0 : string theirConflict = current.getMeta<string> ("conflict/operation/their");
115 :
116 0 : err << current << endl;
117 0 : err << "ours: " << ourConflict << ", theirs: " << theirConflict << endl;
118 0 : err << endl;
119 : }
120 :
121 0 : err << "Merge unsuccessful." << endl;
122 : }
123 80 : }
124 :
125 :
126 0 : KeySet prependNamespace (KeySet const & resultKeys, std::string const & ns)
127 : {
128 0 : KeySet ret;
129 0 : for (auto const & k : resultKeys)
130 : {
131 0 : ret.append (prependNamespace (k, ns));
132 : }
133 0 : return ret;
134 : }
135 :
136 0 : Key prependNamespace (Key const & root, std::string const & ns)
137 : {
138 0 : Key ret = root.dup ();
139 0 : if (ret.isCascading ())
140 : {
141 0 : ret.setName (ns + root.getName ());
142 : }
143 0 : return ret;
144 : }
145 :
146 0 : void applyMeta (KeySet & imported, KeySet const & base)
147 : {
148 0 : for (auto k : imported)
149 : {
150 0 : Key b = base.lookup (k, 0);
151 0 : if (b)
152 : {
153 : k.copyAllMeta (b);
154 : }
155 : }
156 7164 : }
|