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