Line data Source code
1 : /**
2 : * \file oks_diff_data.cpp
3 : *
4 : * This file is part of the OKS package.
5 : * Author: <Igor.Soloviev@cern.ch>
6 : *
7 : * This file contains the implementation of the OKS application to show
8 : * differences between two data files.
9 : *
10 : * Usage:
11 : *
12 : * oks_diff_data [--attributes] [--relationships] [--composite-parents]
13 : * [-all] [--help] [--version] [--schema-files schema_file(s)]
14 : * [--class-name name_of_class [--object-id id_of_object]]
15 : * --data-file1 data_file1 --data-file2 data_file2
16 : *
17 : * Options (if two objects differed):
18 : * \param --attributes produce a listing of differences for object's attributes
19 : * \param --relationships produce a listing of differences for object's relationships
20 : * \param --composite-parents produce a listing of object's composite parents
21 : * \param --all the same as '--attributes --relationships --composite-parents'
22 : *
23 : * General Options/Arguments:
24 : * \param --class-name class-name optional name of class which objects to be checked\n"
25 : * \param --object-id object-id optional id to check only this object (only used with --class-name)\n"
26 : * \param --schema-files schema-file optional list of schema files
27 : * \param --data-file1 data-file first compared datafile
28 : * \param --data-file2 data-file second compared datafile
29 : * \param --version print version
30 : * \param --verbose verbose mode
31 : * \param --help print help text
32 : */
33 :
34 :
35 : #include <iostream>
36 :
37 : #include <set>
38 :
39 : #include "oks/kernel.hpp"
40 : #include "oks/class.hpp"
41 : #include "oks/object.hpp"
42 : #include "oks/attribute.hpp"
43 : #include "oks/relationship.hpp"
44 :
45 : using namespace dunedaq;
46 : using namespace dunedaq::oks;
47 :
48 : std::string appTitle;
49 :
50 :
51 : static void
52 0 : printRecursion(int level)
53 : {
54 0 : while(level--) std::cout << " ";
55 0 : }
56 :
57 : static void
58 0 : ReportCompositeParents(OksObject *o, int recursionLevel = -1)
59 : {
60 0 : static std::set<OksRCR *, std::less<OksRCR *> > rcr_set;
61 :
62 0 : recursionLevel++;
63 :
64 0 : const std::list<OksRCR *> * rcr_list = o->reverse_composite_rels();
65 :
66 0 : if(rcr_list) {
67 0 : for(std::list<OksRCR *>::const_iterator i = rcr_list->begin(); i != rcr_list->end(); ++i) {
68 0 : OksRCR *rcr = *i;
69 :
70 0 : printRecursion(recursionLevel);
71 :
72 0 : std::cout << " " << rcr->obj << " ==\\" << rcr->relationship->get_name()
73 0 : << "\\==> " << o << std::endl;
74 :
75 0 : if(!rcr_set.empty() && rcr_set.find(rcr) != rcr_set.end()) {
76 0 : printRecursion(recursionLevel);
77 0 : std::cout << " The composite parent(s) of " << rcr->obj
78 0 : << " were reported in this loop (circular references)\n";
79 : }
80 : else {
81 0 : rcr_set.insert(rcr);
82 0 : ReportCompositeParents(rcr->obj, recursionLevel);
83 0 : rcr_set.erase(rcr);
84 : }
85 : }
86 : }
87 : else {
88 0 : printRecursion(recursionLevel);
89 0 : std::cout << " " << o << " has no composite parents\n";
90 : }
91 :
92 0 : recursionLevel--;
93 0 : }
94 :
95 : static void
96 0 : printShortUsage(const char *appName, std::ostream& s)
97 : {
98 0 : s << appTitle << "\n"
99 : "Usage: " << appName << " [-a] [-r] [-p] [-all] [-h] [-v] [-c class [-o object_id]] "
100 : "[-s schema_file(s)] -d1 data_file1 -d2 data_file2\n"
101 : "\n"
102 : " Options (if two objects differed):\n"
103 : "\t-a produce a listing of differences for object's attributes\n"
104 : "\t-r produce a listing of differences for object's relationships\n"
105 : "\t-p produce a listing of object's composite parents\n"
106 : "\t-all the same as \'-a -r -p\'\n"
107 : "\n"
108 : " General Options/Arguments:\n"
109 : "\t-c class-name optional name of class which objects to be checked\n"
110 : "\t-o object-id optional id to check only this object (only used with -c)\n"
111 : "\t-s schema-file optional list of schema files\n"
112 : "\t-d1 data-file first compared datafile\n"
113 : "\t-d2 data-file second compared datafile\n"
114 : "\t-v print version\n"
115 : "\t-b verbose mode\n"
116 : "\t-h print this text\n"
117 0 : "\n";
118 0 : }
119 :
120 :
121 : static void
122 0 : printUsage(const char *appName, std::ostream& s)
123 : {
124 0 : s << appTitle << "\n"
125 : "Usage: " << appName << " [--attributes] [--relationships] [--composite-parents] [--all] [--help] [--version]"
126 : " [--class-name name_of_class [--object-id id_of_object]]\n"
127 : " [--schema-files schema_file(s)] --data-file1 data_file1 --data-file2 data_file2\n"
128 : "\n"
129 : " Options (if two objects differed):\n"
130 : "\t--attributes produce a listing of differences for object's attributes\n"
131 : "\t--relationships produce a listing of differences for object's relationships\n"
132 : "\t--composite-parents produce a listing of object's composite parents\n"
133 : "\t-all the same as \'--attributes --relationships --composite-parents\'\n"
134 : "\n"
135 : " General Options/Arguments:\n"
136 : "\t--class-name class-name optional name of class which objects to be checked\n"
137 : "\t--object-id object-id optional id to check only this object (only used with --class-name)\n"
138 : "\t--schema-files schema-file optional list of schema files\n"
139 : "\t--data-file1 data-file first compared datafile\n"
140 : "\t--data-file2 data-file second compared datafile\n"
141 : "\t--version print version\n"
142 : "\t--verbose verbose mode\n"
143 : "\t--help print this text\n"
144 0 : "\n";
145 0 : }
146 :
147 :
148 : int
149 0 : main(int argc, const char * argv[])
150 : {
151 0 : appTitle = "OKS data files comparer. OKS kernel version ";
152 0 : appTitle += OksKernel::GetVersion();
153 :
154 0 : bool printAttributeDifferences = false;
155 0 : bool printRelationshipDifferences = false;
156 0 : bool printCompositeParentsMode = false;
157 0 : bool verboseMode = false;
158 :
159 0 : const char * appName = "oks_diff_data";
160 :
161 0 : if(argc == 1) {
162 0 : printUsage(appName, std::cerr);
163 0 : return 1;
164 : }
165 :
166 :
167 : // allocate enough space for list of schema files
168 :
169 0 : const char ** schemaFiles = new const char * [argc];
170 0 : schemaFiles[0] = 0;
171 :
172 0 : const char * dataFile1 = 0;
173 0 : const char * dataFile2 = 0;
174 :
175 0 : const char * class_name = 0;
176 0 : const char * object_id = 0;
177 :
178 0 : for(int i = 1; i < argc; i++) {
179 0 : if(!strcmp(argv[i], "-a") || !strcmp(argv[i], "--attributes"))
180 : printAttributeDifferences = true;
181 0 : else if(!strcmp(argv[i], "-r") || !strcmp(argv[i], "--relationships"))
182 : printRelationshipDifferences = true;
183 0 : else if(!strcmp(argv[i], "-p") || !strcmp(argv[i], "--composite-parents"))
184 : printCompositeParentsMode = true;
185 0 : else if(!strcmp(argv[i], "-all") || !strcmp(argv[i], "--all")) {
186 : printAttributeDifferences = true;
187 : printRelationshipDifferences = true;
188 : printCompositeParentsMode = true;
189 : }
190 0 : else if(!strcmp(argv[i], "-b") || !strcmp(argv[i], "--verbose"))
191 : verboseMode = true;
192 0 : else if(!strcmp(argv[i], "-h")) {
193 0 : printShortUsage(appName, std::cout);
194 0 : return 0;
195 : }
196 0 : else if(!strcmp(argv[i], "--help")) {
197 0 : printUsage(appName, std::cout);
198 0 : return 0;
199 : }
200 0 : else if(!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
201 0 : std::cout << appTitle << std::endl;
202 0 : return 0;
203 : }
204 0 : else if(!strcmp(argv[i], "-s") || !strcmp(argv[i], "--schema-files")) {
205 0 : for(int j = 0; j < argc - i - 1; ++j) {
206 0 : if(argv[i+1+j][0] != '-') schemaFiles[j] = argv[i+1+j];
207 : else {
208 0 : schemaFiles[j]=0;
209 0 : i+=j;
210 0 : break;
211 : }
212 : }
213 : }
214 0 : else if(!strcmp(argv[i], "-c") || !strcmp(argv[i], "--class-name")) {
215 0 : if(argv[i+1][0] != '-') class_name=argv[++i];
216 : }
217 0 : else if(!strcmp(argv[i], "-o") || !strcmp(argv[i], "--object-id")) {
218 0 : if(argv[i+1][0] != '-') object_id=argv[++i];
219 : }
220 0 : else if(!strcmp(argv[i], "-d1") || !strcmp(argv[i], "--data-file1")) {
221 0 : if(argv[i+1][0] != '-') dataFile1=argv[++i];
222 : }
223 0 : else if(!strcmp(argv[i], "-d2") || !strcmp(argv[i], "--data-file2")) {
224 0 : if(argv[i+1][0] != '-') dataFile2=argv[++i];
225 : }
226 : else {
227 0 : std::cerr << "ERROR: Unknown parameter: \"" << argv[i] << "\"\n\n";
228 0 : printUsage(appName, std::cerr);
229 0 : return 1;
230 : }
231 : }
232 :
233 :
234 : // check schema and data files
235 :
236 0 : if(dataFile1 == 0) {
237 0 : std::cerr << "ERROR: First data file is not defined.\n\n";
238 0 : printUsage(appName, std::cerr);
239 0 : return 1;
240 : }
241 :
242 0 : if(dataFile2 == 0) {
243 0 : std::cerr << "ERROR: Second data file is not defined.\n\n";
244 0 : printUsage(appName, std::cerr);
245 0 : return 1;
246 : }
247 :
248 :
249 : // check object id and class name
250 :
251 0 : if(object_id && !class_name) {
252 0 : std::cerr << "ERROR: object ID cannot be used without class name.\n\n";
253 0 : printUsage(appName, std::cerr);
254 0 : return 1;
255 : }
256 :
257 :
258 0 : int return_status = 0;
259 :
260 :
261 : // create two kernels and load the data
262 :
263 0 : OksKernel kernel1;
264 0 : OksKernel kernel2;
265 :
266 0 : try {
267 :
268 0 : if(!verboseMode) {
269 0 : kernel1.set_silence_mode(true);
270 0 : kernel2.set_silence_mode(true);
271 : }
272 :
273 0 : for(int i=0; schemaFiles[i] != 0; ++i) {
274 0 : const char *s_file = schemaFiles[i];
275 :
276 0 : kernel1.load_schema(s_file);
277 0 : kernel2.load_schema(s_file);
278 : }
279 :
280 0 : kernel1.load_data(dataFile1);
281 0 : kernel2.load_data(dataFile2);
282 :
283 0 : const OksClass::Map& classes = kernel1.classes();
284 0 : OksClass::Map::const_iterator class_iterator = classes.begin();
285 :
286 0 : if(classes.empty()) {
287 0 : std::cerr << "ERROR: No classes were found in loaded schema file(s), exiting ...\n";
288 0 : return 4;
289 : }
290 :
291 0 : std::cout << std::endl;
292 :
293 : int classDiffsCount = 0;
294 :
295 : OksClass *c1, *c2;
296 0 : for(;class_iterator != classes.end(); ++class_iterator) {
297 0 : c1 = class_iterator->second;
298 0 : std::string className(c1->get_name());
299 :
300 0 : if(class_name && className != class_name) {
301 0 : continue;
302 : }
303 :
304 0 : if(verboseMode) classDiffsCount = 0;
305 :
306 0 : if(verboseMode) {
307 0 : std::cout << "TESTING IN CLASS \"" << className << "\"... ";
308 0 : std::cout.flush();
309 : }
310 :
311 0 : if(!(c2 = kernel2.find_class(className))) {
312 0 : if(verboseMode && !classDiffsCount) std::cout << std::endl;
313 0 : std::cout << " DIFFERENCE " << ++classDiffsCount << "."
314 0 : " Database \'" << dataFile2 << "\' does not have class \"" << className << "\", skip testing ...\n";
315 0 : continue;
316 : }
317 :
318 0 : if(*c1 != *c2) {
319 0 : if(verboseMode && !classDiffsCount) std::cout << std::endl;
320 0 : std::cout << " DIFFERENCE " << ++classDiffsCount << "."
321 0 : " Class \"" << className << "\" is different in \"" << dataFile1 << "\" and \"" << dataFile2 << "\", skip testing ...\n";
322 0 : continue;
323 : }
324 :
325 0 : const OksObject::Map * objects1 = c1->objects();
326 0 : const OksObject::Map * objects2 = c2->objects();
327 0 : OksObject::Map::const_iterator object_iterator = objects1->begin();
328 :
329 0 : for(;object_iterator != objects1->end(); ++object_iterator) {
330 0 : const std::string * objUID = (*object_iterator).first;
331 0 : OksObject * o1 = (*object_iterator).second;
332 :
333 0 : if(object_id && o1->GetId() != object_id) {
334 0 : continue;
335 : }
336 :
337 0 : OksObject * o2 = c2->get_object(objUID);
338 :
339 0 : if(!o2) {
340 0 : if(verboseMode && !classDiffsCount) std::cout << std::endl;
341 0 : std::cout << " DIFFERENCE " << ++classDiffsCount << "."
342 0 : " There is no object " << o1 << " in the \"" << dataFile2 << "\" database file.\n";
343 0 : continue;
344 : }
345 :
346 0 : if(*o1 == *o2) continue;
347 :
348 0 : if(verboseMode && !classDiffsCount) std::cout << std::endl;
349 0 : std::cout << " DIFFERENCE " << ++classDiffsCount << ". The OBJECTS " << o1 << " differed:\n";
350 :
351 0 : int objDiffsCount = 0;
352 :
353 :
354 0 : const std::list<OksAttribute *> * alist = c1->all_attributes();
355 0 : const std::list<OksRelationship *> * rlist = c1->all_relationships();
356 :
357 0 : if(alist) {
358 0 : for(std::list<OksAttribute *>::const_iterator ai = alist->begin(); ai != alist->end(); ++ai) {
359 0 : OksAttribute * a = *ai;
360 0 : OksData * d1(o1->GetAttributeValue(a->get_name()));
361 0 : OksData * d2(o2->GetAttributeValue(a->get_name()));
362 :
363 0 : if(!(*d1 == *d2)) {
364 0 : ++objDiffsCount;
365 :
366 0 : if(printAttributeDifferences) {
367 0 : std::cout << " " << classDiffsCount << "." << objDiffsCount
368 : << " The ATTRIBUTE \"" << a->get_name() << "\" values differed:\n"
369 0 : " the value in the FILE \"" << dataFile1 << "\" is: " << *d1 << "\n"
370 0 : " the value in the FILE \"" << dataFile2 << "\" is: " << *d2 << std::endl;
371 : }
372 : }
373 : }
374 : }
375 :
376 :
377 0 : if(rlist) {
378 0 : for(std::list<OksRelationship *>::const_iterator ri = rlist->begin(); ri != rlist->end(); ++ri) {
379 0 : OksRelationship * r = *ri;
380 0 : OksData * d1(o1->GetRelationshipValue(r->get_name()));
381 0 : OksData * d2(o2->GetRelationshipValue(r->get_name()));
382 :
383 0 : if(!(*d1 == *d2)) {
384 0 : ++objDiffsCount;
385 :
386 0 : if(printRelationshipDifferences) {
387 0 : std::cout << " " << classDiffsCount << '.' << objDiffsCount
388 : << " The RELATIONSHIP \"" << r->get_name() << "\" values differed:\n"
389 0 : " the value in the FILE \"" << dataFile1 << "\" is: " << *d1 << "\n"
390 0 : " the value in the FILE \"" << dataFile2 << "\" is: " << *d2 << std::endl;
391 : }
392 : }
393 : }
394 : }
395 :
396 0 : if(objDiffsCount && printCompositeParentsMode) {
397 0 : std::cout << " COMPOSITE PARENT(S) of the OBJECTS " << o1 << ":\n";
398 0 : std::cout << " In the FILE \"" << dataFile1 << "\"\n"; ReportCompositeParents(o1);
399 0 : std::cout << " In the FILE \"" << dataFile2 << "\"\n"; ReportCompositeParents(o2);
400 : }
401 : }
402 :
403 :
404 0 : object_iterator = objects2->begin();
405 :
406 0 : for(;object_iterator != objects2->end(); ++object_iterator) {
407 0 : const std::string * objUID = (*object_iterator).first;
408 0 : OksObject * o1 = c1->get_object(objUID);
409 :
410 0 : if(!o1 && (!object_id || *objUID == object_id)) {
411 0 : if(!classDiffsCount) std::cout << std::endl;
412 0 : std::cout << " DIFFERENCE " << ++classDiffsCount << "."
413 0 : " There is no object " << (*object_iterator).second << " in the \"" << dataFile1 << "\" database file.\n";
414 : }
415 : }
416 :
417 0 : if(verboseMode && !classDiffsCount) {
418 0 : std::cout << " no differences were found\n";
419 : }
420 0 : }
421 : }
422 :
423 0 : catch (oks::exception & ex) {
424 0 : std::cerr << "Caught oks exception:\n" << ex << std::endl;
425 0 : return_status = 10;
426 0 : }
427 :
428 0 : catch (std::exception & e) {
429 0 : std::cerr << "Caught standard C++ exception: " << e.what() << std::endl;
430 0 : return_status = 10;
431 0 : }
432 :
433 0 : catch (...) {
434 0 : std::cerr << "Caught unknown exception" << std::endl;
435 0 : return_status = 10;
436 0 : }
437 :
438 0 : delete [] schemaFiles;
439 :
440 0 : if(verboseMode)
441 0 : std::cout << "\nExiting " << appName << "...\n";
442 :
443 : return return_status;
444 0 : }
|