Line data Source code
1 : #include <editor.hpp>
2 :
3 : #include <sys/stat.h>
4 : #include <sys/types.h>
5 : #include <unistd.h>
6 :
7 : #include <cmdline.hpp>
8 : #include <external.hpp>
9 : #include <kdb.hpp>
10 : #include <keysetio.hpp>
11 : #include <modules.hpp>
12 :
13 : #include <kdbmacros.h>
14 :
15 : #include <export.hpp>
16 : #include <import.hpp>
17 :
18 : #include <iostream>
19 : #include <string>
20 :
21 : #include <mergehelper.hpp>
22 : #include <merging/metamergestrategy.hpp>
23 : #include <merging/threewaymerge.hpp>
24 :
25 : using namespace kdb;
26 : using namespace kdb::tools;
27 : using namespace kdb::tools::merging;
28 : using namespace std;
29 :
30 156 : EditorCommand::EditorCommand ()
31 : {
32 78 : }
33 :
34 234 : EditorCommand::~EditorCommand ()
35 : {
36 156 : }
37 :
38 0 : void EditorCommand::tmpFile ()
39 : {
40 : #ifndef _WIN32
41 0 : const char * tmpvar = getenv ("TMPDIR");
42 0 : if (!tmpvar)
43 : {
44 0 : tmpvar = "/tmp";
45 : }
46 0 : filename = tmpvar;
47 0 : filename += "/elektra-test.XXXXXX";
48 0 : char * fn = static_cast<char *> (malloc (filename.length () + 1));
49 0 : strcpy (fn, filename.c_str ());
50 0 : int fd = mkstemp (fn);
51 0 : filename = std::string (fn);
52 0 : close (fd);
53 0 : free (fn);
54 : #endif
55 0 : }
56 :
57 0 : bool runAllEditors (std::string const & filename)
58 : {
59 : using namespace kdb;
60 0 : if (runEditor ("/usr/bin/sensible-editor", filename)) return true;
61 0 : if (runEditor ("/usr/bin/editor", filename)) return true;
62 0 : char * editor = getenv ("EDITOR");
63 0 : if (editor && runEditor (editor, filename)) return true;
64 0 : if (runEditor ("/usr/bin/vi", filename)) return true;
65 0 : if (runEditor ("/bin/vi", filename)) return true;
66 0 : return false;
67 : }
68 :
69 : class EditorNotAvailable : public std::exception
70 : {
71 : virtual const char * what () const throw () override
72 : {
73 : return "kdb-editor not available for windows (non-POSIX systems)";
74 : }
75 : };
76 :
77 0 : int EditorCommand::execute (Cmdline const & cl)
78 : {
79 : #ifdef _WIN32
80 : throw EditorNotAvailable ();
81 : #endif
82 :
83 0 : int argc = cl.arguments.size ();
84 0 : if (argc < 1)
85 : {
86 0 : throw invalid_argument ("wrong number of arguments, 1 needed");
87 : }
88 0 : Key root = cl.createKey (0);
89 :
90 0 : KeySet ours;
91 0 : KDB kdb;
92 0 : kdb.get (ours, root);
93 0 : KeySet oursToEdit = ours.cut (root);
94 0 : KeySet original = oursToEdit.dup ();
95 :
96 0 : if (cl.strategy == "validate")
97 : {
98 0 : prependNamespace (oursToEdit, cl.ns);
99 0 : oursToEdit.cut (prependNamespace (root, cl.ns));
100 : }
101 :
102 : // export it to file
103 0 : string format = cl.format;
104 0 : if (argc > 1) format = cl.arguments[1];
105 :
106 0 : Modules modules;
107 0 : PluginPtr plugin = modules.load (format);
108 :
109 0 : tmpFile ();
110 0 : if (cl.verbose) std::cout << "filename set to " << filename << std::endl;
111 0 : Key errorKey (root);
112 0 : errorKey.setString (filename);
113 : struct stat orig;
114 0 : stat (filename.c_str (), &orig);
115 :
116 0 : if (plugin->set (oursToEdit, errorKey) == -1)
117 : {
118 0 : printWarnings (cerr, errorKey, cl.verbose, cl.debug);
119 0 : printError (cerr, errorKey, cl.verbose, cl.debug);
120 : return 11;
121 : }
122 :
123 0 : printWarnings (cerr, errorKey, cl.verbose, cl.debug);
124 :
125 :
126 : // start editor
127 0 : if (cl.verbose) std::cout << "running editor with " << filename << std::endl;
128 0 : if (!cl.editor.empty ())
129 : {
130 0 : if (!runEditor (cl.editor, filename))
131 : {
132 0 : std::cerr << "Could not run editor " << cl.editor << std::endl;
133 : return 12;
134 : }
135 : }
136 : else
137 : {
138 0 : if (!runAllEditors (filename))
139 : {
140 0 : std::cerr << "Could not run any editor, please change /sw/elektra/kdb/#0/current/editor" << std::endl;
141 : return 12;
142 : }
143 : }
144 :
145 : struct stat modif;
146 0 : stat (filename.c_str (), &modif);
147 :
148 0 : if (ELEKTRA_STAT_SECONDS (orig) == ELEKTRA_STAT_SECONDS (modif) &&
149 0 : ELEKTRA_STAT_NANO_SECONDS (orig) == ELEKTRA_STAT_NANO_SECONDS (modif))
150 : {
151 0 : if (!cl.quiet) std::cout << "File was unchanged, will exit successfully";
152 : return 0;
153 : }
154 :
155 : // import from the file
156 0 : KeySet importedKeys;
157 0 : plugin->get (importedKeys, errorKey);
158 0 : importedKeys = importedKeys.cut (root);
159 :
160 0 : printWarnings (cerr, errorKey, cl.verbose, cl.debug);
161 0 : printError (cerr, errorKey, cl.verbose, cl.debug);
162 :
163 0 : if (cl.strategy == "validate")
164 : {
165 0 : applyMeta (importedKeys, original);
166 0 : kdb.set (importedKeys, root);
167 0 : printWarnings (cerr, root, cl.verbose, cl.debug);
168 0 : printError (cerr, root, cl.verbose, cl.debug);
169 : return 0;
170 : }
171 :
172 0 : ThreeWayMerge merger;
173 0 : MergeHelper helper;
174 :
175 0 : helper.configureMerger (cl, merger);
176 : MergeResult result = merger.mergeKeySet (
177 0 : MergeTask (BaseMergeKeys (oursToEdit, root), OurMergeKeys (oursToEdit, root), TheirMergeKeys (importedKeys, root), root));
178 :
179 0 : helper.reportResult (cl, result, cout, cerr);
180 :
181 0 : int ret = 13;
182 0 : if (!result.hasConflicts ())
183 : {
184 0 : if (cl.verbose)
185 : {
186 0 : cout << "The merged keyset with strategy " << cl.strategy << " is:" << endl;
187 0 : cout << result.getMergedKeys ();
188 : }
189 :
190 0 : KeySet resultKeys = result.getMergedKeys ();
191 0 : if (cl.verbose) std::cout << "about to write result keys " << resultKeys << std::endl;
192 0 : ours.append (resultKeys);
193 : try
194 : {
195 0 : kdb.set (ours, root);
196 0 : if (cl.verbose) std::cout << "successful, cleaning up " << filename << std::endl;
197 0 : unlink (filename.c_str ());
198 0 : ret = 0;
199 : }
200 0 : catch (KDBException const & e)
201 : {
202 0 : std::cout << "Import of configuration failed with the error:\n";
203 0 : std::cout << e.what ();
204 0 : std::cout << "\n\n";
205 0 : std::cout << "Your changes are not lost." << std::endl;
206 0 : std::cout << "Please fix, import and remove \"" << filename << '"' << std::endl;
207 0 : ret = 14;
208 : }
209 : }
210 : else
211 : {
212 0 : std::cout << "Import not successful, please import and remove \"" << filename << '"' << std::endl;
213 : }
214 :
215 0 : return ret;
216 7164 : }
|