Line data Source code
1 : /**
2 : * \file oks_dump.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 dump
8 : * contents of the OKS database files.
9 : *
10 : */
11 :
12 : #include "oks/kernel.hpp"
13 : #include "oks/query.hpp"
14 : #include "oks/exceptions.hpp"
15 :
16 : #include <vector>
17 : #include <iostream>
18 :
19 : #include <string.h>
20 : #include <stdlib.h>
21 :
22 : using namespace dunedaq::oks;
23 :
24 : enum __OksDumpExitStatus__ {
25 : __Success__ = 0,
26 : __BadCommandLine__,
27 : __BadOksFile__,
28 : __BadQuery__,
29 : __NoSuchClass__,
30 : __FoundDanglingReferences__,
31 : __ExceptionCaught__
32 : };
33 :
34 :
35 : static void
36 0 : printUsage(std::ostream& s)
37 : {
38 0 : s << "Usage: oks_dump\n"
39 : " [--files-only | --files-stat-only | --schema-files-only | --schema-files-stat-only | --data-files-only | --data-files-stat-only]\n"
40 : " [--class name-of-class [--query query [--print-references recursion-depth [class-name*] [--]] [--print-referenced_by [name] [--]]]]\n"
41 : " [--path object-from object-to query]\n"
42 : " [--allow-duplicated-objects-via-inheritance]\n"
43 : " [--version]\n"
44 : " [--help]\n"
45 : " [--input-from-files] database-file [database-file(s)]\n"
46 : "\n"
47 : "Options:\n"
48 : " -f | --files-only print list of oks files names\n"
49 : " -F | --files-stat-only print list of oks files with statistic details (size, number of items\n"
50 : " -s | --schema-files-only print list of schema oks files names\n"
51 : " -S | --schema-files-stat-only print list of oks schema files with statistic details\n"
52 : " -d | --data-files-only print list of data oks files names\n"
53 : " -D | --data-files-stat-only print list of oks data files with statistic details\n"
54 : " -c | --class class_name dump given class (all objects or matching some query)\n"
55 : " -q | --query query print objects matching query (can only be used with class)\n"
56 : " -r | --print-references N C1 C2 ... CX print objects referenced by found objects (can only be used with query), where:\n"
57 : " * the parameter N defines recursion depth for referenced objects (> 0)\n"
58 : " * the optional set of names {C1 .. CX} defines [sub-]classes for above objects\n"
59 : " -b | --print-referenced_by [name] print objects referencing found objects (can only be used with query), where:\n"
60 : " * the optional parameter name defines name of relationship\n"
61 : " -p | --path obj query print path from object \'obj\' to object of query expression\n"
62 : " -i | --input-from-files read oks files to be loaded from file(s) instead of command line\n"
63 : " (to avoid problems with long command line, when there is huge number of files)\n"
64 : " -a | --allow-duplicated-objects-via-inheritance do not stop if there are duplicated object via inheritance hierarchy\n"
65 : " -v | --version print version\n"
66 : " -h | --help print this text\n"
67 : "\n"
68 : "Description:\n"
69 : " Dumps contents of the OKS database.\n"
70 : "\n"
71 : "Return Status:\n"
72 : " 0 - no problems found\n"
73 : " 1 - bad command line parameter\n"
74 : " 2 - bad oks file(s)\n"
75 : " 3 - bad query passed via -q or -p options\n"
76 : " 4 - cannot find class passed via -c option\n"
77 : " 5 - loaded objects have dangling references\n"
78 : " 6 - caught an exception\n"
79 0 : "\n";
80 0 : }
81 :
82 : static void
83 0 : no_param(const char * s)
84 : {
85 0 : Oks::error_msg("oks_dump") << "no parameter(s) for command line argument \'" << s << "\' provided\n\n";
86 0 : exit(EXIT_FAILURE);
87 : }
88 :
89 : OksObject*
90 0 : find_object(char * s, OksKernel& k)
91 : {
92 0 : char * id = s;
93 :
94 0 : if((s = strchr(id, '@')) == 0) return 0;
95 :
96 0 : *s = '\0';
97 0 : s++;
98 :
99 0 : if(OksClass * c = k.find_class(s)) {
100 0 : if(OksObject * o = c->get_object(id)) {
101 : return o;
102 : }
103 : else {
104 0 : Oks::error_msg("oks_dump::find_object()") << "cannot find object \"" << id << '@' << s << "\"\n";
105 : }
106 : }
107 : else {
108 0 : Oks::error_msg("oks_dump::find_object()") << "cannot find class \"" << s << "\"\n";
109 : }
110 :
111 : return 0;
112 : }
113 :
114 : int
115 0 : main(int argc, char **argv)
116 : {
117 0 : if(argc == 1) {
118 0 : printUsage(std::cerr);
119 0 : return __BadCommandLine__;
120 : }
121 :
122 0 : OksKernel kernel;
123 0 : kernel.set_test_duplicated_objects_via_inheritance_mode(true);
124 :
125 0 : try {
126 :
127 0 : int dump_files_only = 0; // 0 - none, 12 - data, 1 - schema, 2 - schema & data
128 0 : const char * class_name = 0;
129 0 : const char * query = 0;
130 0 : const char * object_from = 0;
131 0 : const char * path_query = 0;
132 0 : long recursion_depth = 0;
133 0 : bool print_referenced_by = false;
134 0 : const char * ref_by_rel_name = "*";
135 0 : std::vector<std::string> ref_classes;
136 0 : bool input_from_files = false;
137 0 : bool print_files_stat = false;
138 :
139 0 : for(int i = 1; i < argc; i++) {
140 0 : const char * cp = argv[i];
141 :
142 0 : if(!strcmp(cp, "-h") || !strcmp(cp, "--help")) {
143 0 : printUsage(std::cout);
144 : return __Success__;
145 : }
146 0 : else if(!strcmp(cp, "-v") || !strcmp(cp, "--version")) {
147 0 : std::cout << "OKS kernel version " << OksKernel::GetVersion() << std::endl;
148 : return __Success__;
149 : }
150 0 : else if(!strcmp(cp, "-a") || !strcmp(cp, "--allow-duplicated-objects-via-inheritance")) {
151 0 : kernel.set_test_duplicated_objects_via_inheritance_mode(false);
152 : }
153 0 : else if(!strcmp(cp, "-f") || !strcmp(cp, "--files-only")) {
154 : dump_files_only = 2;
155 : }
156 0 : else if(!strcmp(cp, "-F") || !strcmp(cp, "--files-stat-only")) {
157 : dump_files_only = 2;
158 : print_files_stat = true;
159 : }
160 0 : else if(!strcmp(cp, "-s") || !strcmp(cp, "--schema-files-only")) {
161 : dump_files_only = 1;
162 : }
163 0 : else if(!strcmp(cp, "-S") || !strcmp(cp, "--schema-files-stat-only")) {
164 : dump_files_only = 1;
165 : print_files_stat = true;
166 : }
167 0 : else if(!strcmp(cp, "-d") || !strcmp(cp, "--data-files-only")) {
168 : dump_files_only = 12;
169 : }
170 0 : else if(!strcmp(cp, "-D") || !strcmp(cp, "--data-files-stat-only")) {
171 : dump_files_only = 12;
172 : print_files_stat = true;
173 : }
174 0 : else if(!strcmp(cp, "-c") || !strcmp(cp, "--class")) {
175 0 : if(++i == argc) { no_param(cp); } else { class_name = argv[i]; }
176 : }
177 0 : else if(!strcmp(cp, "-q") || !strcmp(cp, "--query")) {
178 0 : if(++i == argc) { no_param(cp); } else { query = argv[i]; }
179 : }
180 0 : else if(!strcmp(cp, "-i") || !strcmp(cp, "--input-from-files")) {
181 : input_from_files = true;
182 : }
183 0 : else if(!strcmp(cp, "-r") || !strcmp(cp, "--print-references")) {
184 0 : if(++i == argc) { no_param(cp); } else { recursion_depth = atol(argv[i]); }
185 0 : int j = 0;
186 0 : for(; j < argc - i - 1; ++j) {
187 0 : if(argv[i+1+j][0] != '-') { ref_classes.push_back(argv[i+1+j]); } else { break; }
188 : }
189 0 : i += j;
190 0 : }
191 0 : else if(!strcmp(cp, "-b") || !strcmp(cp, "--print-referenced_by")) {
192 0 : print_referenced_by = true;
193 0 : if((i+1) < argc && argv[i+1][0] != '-') {
194 0 : ref_by_rel_name = argv[++i];
195 : }
196 : }
197 0 : else if(!strcmp(cp, "-p") || !strcmp(cp, "--path")) {
198 0 : if(++i > argc - 1) { no_param(cp); } else { object_from = argv[i]; path_query = argv[++i];}
199 : }
200 0 : else if(strcmp(cp, "--")) {
201 0 : if(input_from_files) {
202 0 : std::ifstream f(cp);
203 0 : if(f.good()) {
204 0 : while(f.good() && !f.eof()) {
205 0 : std::string file_name;
206 0 : std::getline(f, file_name);
207 0 : if(!file_name.empty() && kernel.load_file(file_name) == 0) {
208 0 : Oks::error_msg("oks_dump") << "\tCan not load file \"" << file_name << "\", exiting...\n";
209 0 : return __BadOksFile__;
210 : }
211 0 : }
212 : }
213 : else {
214 0 : Oks::error_msg("oks_dump") << "\tCan not open file \"" << cp << "\" for reading, exiting...\n";
215 : return __BadCommandLine__;
216 : }
217 0 : }
218 : else {
219 0 : if(kernel.load_file(cp) == 0) {
220 0 : Oks::error_msg("oks_dump") << "\tCan not load file \"" << cp << "\", exiting...\n";
221 : return __BadOksFile__;
222 : }
223 : }
224 : }
225 : }
226 :
227 0 : if(kernel.schema_files().empty()) {
228 0 : Oks::error_msg("oks_dump") << "\tAt least one oks file have to be provided, exiting...\n";
229 : return __BadCommandLine__;
230 : }
231 :
232 0 : if(query && !class_name) {
233 0 : Oks::error_msg("oks_dump") << "\tQuery can only be executed when class name is provided (use -c option), exiting...\n";
234 : return __BadCommandLine__;
235 : }
236 :
237 0 : if(dump_files_only) {
238 0 : long total_size = 0;
239 0 : long total_items = 0;
240 0 : const OksFile::Map * files [2] = {&kernel.schema_files(), &kernel.data_files()};
241 0 : for(int j = (dump_files_only / 10); j < (dump_files_only % 10); ++j) {
242 0 : if(!files[j]->empty()) {
243 0 : for(OksFile::Map::const_iterator i = files[j]->begin(); i != files[j]->end(); ++i) {
244 0 : if(print_files_stat) {
245 0 : total_size += i->second->get_size();
246 0 : total_items += i->second->get_number_of_items();
247 0 : std::cout << *(i->first) << " (" << i->second->get_number_of_items() << " items, " << i->second->get_size() << " bytes)" << std::endl;
248 : }
249 : else {
250 0 : std::cout << *(i->first) << std::endl;
251 : }
252 : }
253 : }
254 : }
255 :
256 0 : if(print_files_stat) {
257 0 : std::cout << "Total number of items: " << total_items << "\n"
258 0 : "Total size of files: " << total_size << " bytes" << std::endl;
259 : }
260 : }
261 0 : else if(class_name && *class_name) {
262 0 : if(OksClass * c = kernel.find_class(class_name)) {
263 0 : if(query && *query) {
264 0 : OksQuery * q = new OksQuery(c, query);
265 0 : if(q->good()) {
266 0 : OksObject::List * objs = c->execute_query(q);
267 0 : size_t num = (objs ? objs->size() : 0);
268 0 : std::cout << "Found " << num << " matching query \"" << query << "\" in class \"" << class_name << "\"";
269 0 : if(num) {
270 0 : std::cout << ':' << std::endl;
271 0 : while(!objs->empty()) {
272 0 : OksObject * o = objs->front();
273 0 : objs->pop_front();
274 :
275 0 : if(recursion_depth > 0 || print_referenced_by) {
276 0 : if(recursion_depth) {
277 0 : ClassSet all_ref_classes;
278 0 : kernel.get_all_classes(ref_classes, all_ref_classes);
279 0 : OksObject::FSet refs;
280 0 : o->references(refs, recursion_depth, false, &all_ref_classes);
281 0 : std::cout << o << " references " << refs.size() << " object(s)" << std::endl;
282 0 : for(OksObject::FSet::const_iterator i = refs.begin(); i != refs.end(); ++i) {
283 0 : std::cout << " - " << *i << std::endl;
284 : }
285 0 : }
286 0 : if(print_referenced_by) {
287 0 : if(OksObject::FList * ref_by_objs = o->get_all_rels(ref_by_rel_name)) {
288 0 : std::cout << o << " is referenced by " << ref_by_objs->size() << " object(s) via relationship \"" << ref_by_rel_name << "\":" << std::endl;
289 :
290 0 : for(OksObject::FList::const_iterator i = ref_by_objs->begin(); i != ref_by_objs->end(); ++i) {
291 0 : std::cout << " - " << *i << std::endl;
292 : }
293 :
294 0 : delete ref_by_objs;
295 : }
296 : else {
297 0 : std::cout << o << " is not referenced by any object via relationship \"" << ref_by_rel_name << '\"' << std::endl;
298 : }
299 : }
300 : }
301 : else {
302 0 : std::cout << *o << std::endl;
303 : }
304 : }
305 0 : delete objs;
306 : }
307 : else {
308 0 : std::cout << std::endl;
309 : }
310 : }
311 : else {
312 0 : Oks::error_msg("oks_dump") << "\tFailed to parse query \"" << query << "\" in class \"" << class_name << "\"\n";
313 : return __BadQuery__;
314 : }
315 0 : delete q;
316 : }
317 : else {
318 0 : std::cout << *c << std::endl;
319 : }
320 : }
321 : else {
322 0 : Oks::error_msg("oks_dump") << "\tCan not find class \"" << class_name << "\"\n";
323 : return __NoSuchClass__;
324 : }
325 : }
326 0 : else if(object_from && *object_from && path_query && *path_query) {
327 0 : OksObject * obj_from = find_object((char *)object_from, kernel);
328 0 : try {
329 0 : QueryPath q(path_query, kernel);
330 0 : OksObject::List * objs = obj_from->find_path(q);
331 :
332 0 : size_t num = (objs ? objs->size() : 0);
333 0 : std::cout << "Found " << num << " objects in the path \"" << q << "\" from object " << obj_from << ":" << std::endl;
334 :
335 0 : if(num) {
336 0 : while(!objs->empty()) {
337 0 : OksObject * o = objs->front();
338 0 : objs->pop_front();
339 0 : std::cout << *o << std::endl;
340 : }
341 0 : delete objs;
342 : }
343 0 : }
344 0 : catch ( bad_query_syntax& e ) {
345 0 : Oks::error_msg("oks_dump") << "\tFailed to parse query: " << e.what() << std::endl;
346 0 : return __BadQuery__;
347 0 : }
348 0 : }
349 : else {
350 0 : std::cout << kernel;
351 : }
352 :
353 0 : if(!kernel.get_bind_classes_status().empty())
354 : {
355 0 : Oks::error_msg("oks_dump") << "The schema contains dangling references to non-loaded classes:\n" << kernel.get_bind_classes_status();
356 : }
357 :
358 0 : if(!kernel.get_bind_objects_status().empty())
359 : {
360 0 : Oks::error_msg("oks_dump") << "\tThe data contain dangling references to non-loaded objects\n";
361 : }
362 :
363 0 : if(!kernel.get_bind_classes_status().empty() || !kernel.get_bind_objects_status().empty())
364 : {
365 : return __FoundDanglingReferences__;
366 : }
367 0 : }
368 0 : catch (exception & ex) {
369 0 : std::cerr << "Caught oks exception:\n" << ex << std::endl;
370 0 : return __ExceptionCaught__;
371 0 : }
372 0 : catch (std::exception & e) {
373 0 : std::cerr << "Caught standard C++ exception: " << e.what() << std::endl;
374 0 : return __ExceptionCaught__;
375 0 : }
376 0 : catch (...) {
377 0 : std::cerr << "Caught unknown exception" << std::endl;
378 0 : return __ExceptionCaught__;
379 0 : }
380 :
381 0 : return __Success__;
382 0 : }
|