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