Line data Source code
1 : #include <stdlib.h>
2 :
3 : #include <iostream>
4 : #include <string>
5 :
6 : #include <boost/program_options.hpp>
7 :
8 : #include "conffwk/Configuration.hpp"
9 : #include "conffwk/ConfigObject.hpp"
10 : #include "conffwk/Schema.hpp"
11 :
12 : using namespace dunedaq::conffwk;
13 :
14 0 : ERS_DECLARE_ISSUE(
15 : config_dump,
16 : BadCommandLine,
17 : "bad command line: " << reason,
18 : ((const char*)reason)
19 : )
20 :
21 0 : ERS_DECLARE_ISSUE(
22 : config_dump,
23 : ConfigException,
24 : "caught dunedaq::conffwk::Exception exception",
25 : )
26 :
27 : struct SortByName
28 : {
29 : bool
30 0 : operator()(const ConfigObject *o1, const ConfigObject *o2) const
31 : {
32 0 : return o1->UID() < o2->UID();
33 : }
34 : };
35 :
36 : static void
37 0 : print_referenced_by(const ConfigObject &obj, const char *prefix)
38 : {
39 0 : std::vector<ConfigObject> values;
40 0 : obj.referenced_by(values, "*", false, 0, 0);
41 0 : if (values.size() == 0)
42 : {
43 0 : std::cout << prefix << "is not referenced by others objects\n";
44 : }
45 : else
46 : {
47 0 : std::cout << prefix << "is referenced by " << values.size() << " object" << (values.size() == 1 ? "" : "s") << ":\n";
48 0 : for (const auto &iobj : values)
49 0 : std::cout << prefix << " * " << iobj << std::endl;
50 :
51 : }
52 0 : }
53 :
54 : static void
55 0 : print_versions(const std::vector<dunedaq::conffwk::Version>& versions)
56 : {
57 0 : const auto len = versions.size();
58 0 : unsigned int idx = 1;
59 0 : for (const auto& x : versions)
60 : {
61 0 : char buf[50];
62 0 : std::time_t t(x.get_timestamp());
63 0 : std::strftime(buf, 50, "%F %T %Z", std::localtime(&t));
64 0 : std::cout << " * version [" << idx++ << '/' << len << "]\n"
65 0 : " id: " << x.get_id() << "\n"
66 0 : " user: " << x.get_user() << "\n"
67 : " date: " << buf << "\n"
68 0 : " comment: " << x.get_comment() << "\n"
69 0 : " files:\n";
70 :
71 0 : for (const auto& f : x.get_files())
72 0 : std::cout << " - \"" << f << "\"\n";
73 : }
74 0 : }
75 :
76 0 : int main(int argc, char *argv[])
77 : {
78 0 : const std::string any("*");
79 0 : std::string db_name, class_name, object_id, since, until;
80 :
81 0 : bool changes = false;
82 :
83 0 : bool skip_irrelevant = true;
84 0 : dunedaq::conffwk::Version::QueryType query_type = dunedaq::conffwk::Version::query_by_tag;
85 :
86 0 : bool direct_info = false;
87 0 : bool objects_details = false;
88 0 : bool contained_in = false;
89 0 : bool referenced_by = false;
90 :
91 0 : boost::program_options::options_description desc(
92 : "Dumps class and objects descriptions using abstract conffwk API.\n"
93 : "Without -c or -o options, the utility lists all classes.\n"
94 : "\n"
95 0 : "Options/Arguments");
96 :
97 0 : try
98 : {
99 0 : std::vector<std::string> vesrions_str;
100 0 : std::string class_name2;
101 :
102 0 : desc.add_options()
103 0 : (
104 : "database,d",
105 0 : boost::program_options::value<std::string>(&db_name)->required(),
106 : "database specification in format plugin-name:parameters"
107 : )
108 0 : (
109 : "changes,a",
110 : "print details of new repository versions or modified files"
111 : )
112 0 : (
113 : "versions,v",
114 0 : boost::program_options::value<std::vector<std::string>>(&vesrions_str)->multitoken()->zero_tokens(),
115 : "print details of versions from archive providing 4 parameters \"all|skip\" \"date|id|tag\" \"since\" \"until\""
116 : )
117 0 : (
118 : "class-direct-info,c",
119 0 : boost::program_options::value<std::string>(&class_name)->default_value("")->implicit_value(any),
120 : "print direct properties of all classes, or given class if name is provided"
121 : )
122 0 : (
123 : "class-all-info,C",
124 0 : boost::program_options::value<std::string>(&class_name2)->default_value("")->implicit_value(any),
125 : "similar to -c, but prints all properties of class (all attributes, all superclasses, etc.)"
126 : )
127 0 : (
128 : "list-objects,o",
129 : "list objects of class"
130 : )
131 0 : (
132 : "print-referenced-by,r",
133 : "print objects referencing given object (only with -o option)"
134 : )
135 0 : (
136 : "dump-objects,O",
137 0 : boost::program_options::value<std::string>(&object_id)->default_value("")->implicit_value(any),
138 : "dump all objects of class or details of given object, if id is provided (-c is required)"
139 : )
140 0 : (
141 : "show-contained-in,n",
142 : "when dump an object, print out the database file it belongs to"
143 : )
144 0 : (
145 : "help,h",
146 : "print help message"
147 : );
148 :
149 0 : boost::program_options::variables_map vm;
150 0 : boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm);
151 :
152 0 : if (vm.count("help"))
153 : {
154 0 : std::cout << desc << std::endl;
155 0 : return EXIT_SUCCESS;
156 : }
157 :
158 0 : boost::program_options::notify(vm);
159 :
160 0 : if (!class_name.empty())
161 0 : direct_info = true;
162 :
163 0 : if (!class_name2.empty())
164 : {
165 0 : if (!class_name.empty())
166 0 : throw std::runtime_error("cannot use -c and -C options simultaneously");
167 : else
168 0 : class_name = std::move(class_name2);
169 : }
170 :
171 0 : if (vm.count("changes"))
172 0 : changes = true;
173 :
174 0 : if (!vesrions_str.empty())
175 : {
176 0 : if (vesrions_str.size() != 4)
177 : {
178 0 : throw std::runtime_error("-v option must have 4 parameters, see help");
179 : }
180 : else
181 : {
182 0 : if (vesrions_str[0] == "all")
183 : skip_irrelevant = false;
184 0 : else if (vesrions_str[0] != "skip")
185 0 : throw std::runtime_error("first parameter of -v has to be \"all\" or \"skip\"");
186 :
187 0 : if (vesrions_str[1] == "date")
188 : query_type = dunedaq::conffwk::Version::query_by_date;
189 0 : else if (vesrions_str[1] == "id")
190 : query_type = dunedaq::conffwk::Version::query_by_id;
191 0 : else if (vesrions_str[1] != "tag")
192 0 : throw std::runtime_error("second versions parameter must be \"date\", \"id\" or \"tag\"");
193 :
194 0 : since = vesrions_str[2];
195 0 : until = vesrions_str[3];
196 : }
197 : }
198 :
199 0 : if (!object_id.empty())
200 0 : objects_details = true;
201 :
202 0 : if (vm.count("list-objects"))
203 : {
204 0 : objects_details = false;
205 0 : object_id = any;
206 : }
207 :
208 0 : if (vm.count("print-referenced-by"))
209 0 : referenced_by = true;
210 :
211 0 : if (vm.count("show-contained-in"))
212 0 : contained_in = true;
213 :
214 0 : if (class_name.empty() && !object_id.empty() && object_id != any)
215 0 : throw std::runtime_error("object id is set, but no class name given (use -c option)");
216 0 : }
217 0 : catch (std::exception &ex)
218 : {
219 0 : ers::fatal(config_dump::BadCommandLine(ERS_HERE, ex.what()));
220 0 : return EXIT_FAILURE;
221 0 : }
222 :
223 :
224 0 : try
225 : {
226 0 : Configuration conf(db_name);
227 :
228 : // get versions if any
229 0 : if (changes)
230 : {
231 0 : std::cout << "Changes:\n";
232 0 : print_versions(conf.get_changes());
233 0 : return EXIT_SUCCESS;
234 : }
235 :
236 0 : if (!since.empty())
237 : {
238 0 : std::cout << "Versions:\n";
239 0 : print_versions(conf.get_versions(since, until, query_type, skip_irrelevant));
240 0 : return EXIT_SUCCESS;
241 : }
242 :
243 0 : std::set<std::string> classes;
244 :
245 0 : if (!class_name.empty() && class_name != any)
246 0 : classes.insert(class_name);
247 : else
248 0 : for (const auto &i : conf.superclasses())
249 0 : classes.insert(*i.first);
250 :
251 : // if there are no options, just list classes
252 0 : if (class_name.empty() && object_id.empty())
253 : {
254 0 : std::cout << "The database schema has " << classes.size() << " class(es):\n";
255 0 : for (const auto &i : classes)
256 0 : std::cout << " - \'" << i << "\'\n";
257 0 : return EXIT_SUCCESS;
258 : }
259 :
260 : // only print details of classes
261 0 : if (!class_name.empty() && object_id.empty())
262 : {
263 0 : if (class_name == any)
264 0 : std::cout << "The database schema has " << classes.size() << " class(es):\n";
265 :
266 0 : for (const auto &i : classes)
267 0 : conf.get_class_info(i, direct_info).print(std::cout, " ");
268 :
269 0 : return EXIT_SUCCESS;
270 : }
271 :
272 0 : const char *prefix = "";
273 0 : const char *prefix2 = " ";
274 0 : const char *prefix3 = " ";
275 :
276 : // list or print all objects of class(es)
277 0 : if (object_id == any)
278 : {
279 0 : if (class_name.empty() || class_name == any)
280 : {
281 0 : std::cout << "The database schema has " << classes.size() << " class(es):\n";
282 : prefix = " ";
283 : prefix2 = " ";
284 : prefix3 = " ";
285 : }
286 :
287 0 : for (std::set<std::string>::const_iterator i = classes.begin(); i != classes.end(); ++i)
288 : {
289 0 : std::vector<ConfigObject> objects;
290 0 : conf.get(*i, objects);
291 0 : if (objects.empty())
292 : {
293 0 : std::cout << prefix << "The class \'" << *i << "\' has no objects\n";
294 : }
295 : else
296 : {
297 0 : std::cout << prefix << "The class \'" << *i << "\' has " << objects.size() << " object(s) including sub-classes:\n";
298 :
299 : // sort by ID for consistent output
300 0 : std::set<const ConfigObject*, SortByName> sorted_by_id;
301 :
302 0 : for (const auto &j : objects)
303 0 : sorted_by_id.insert(&j);
304 :
305 0 : for (const auto &j : sorted_by_id)
306 0 : if (j->class_name() == *i)
307 : {
308 0 : if (objects_details)
309 0 : j->print_ref(std::cout, conf, prefix2, contained_in);
310 : else
311 0 : std::cout << prefix << " - \'" << j->UID() << "\'\n";
312 :
313 0 : if (referenced_by)
314 0 : print_referenced_by(*j, prefix3);
315 : }
316 : else
317 : {
318 0 : std::cout << prefix << " - \'" << j->UID() << "\' (database class name = \'" << j->class_name() << "\')\n";
319 : }
320 0 : }
321 0 : }
322 : }
323 : else
324 : {
325 0 : ConfigObject obj;
326 0 : conf.get(class_name, object_id, obj);
327 0 : obj.print_ref(std::cout, conf, "", contained_in);
328 0 : if (referenced_by)
329 0 : print_referenced_by(obj, prefix2);
330 0 : }
331 0 : }
332 0 : catch (dunedaq::conffwk::Exception &ex)
333 : {
334 0 : ers::fatal(config_dump::ConfigException(ERS_HERE, ex));
335 0 : return EXIT_FAILURE;
336 0 : }
337 :
338 0 : return EXIT_SUCCESS;
339 0 : }
|