Persist.cxx
Go to the documentation of this file.
1 #include "WireCellUtil/Persist.h"
2 #include "WireCellUtil/String.h"
3 #include "WireCellUtil/Logging.h"
5 
6 #include "libjsonnet++.h"
7 
8 #include <cstdlib> // for getenv, see get_path()
9 
10 
11 #include <boost/iostreams/copy.hpp>
12 #include <boost/iostreams/filter/bzip2.hpp>
13 #include <boost/iostreams/device/file.hpp>
14 #include <boost/iostreams/filtering_stream.hpp>
15 #include <boost/filesystem.hpp>
16 
17 #include <string>
18 #include <sstream>
19 #include <fstream>
20 
21 using spdlog::info;
22 using spdlog::error;
23 using namespace std;
24 using namespace WireCell;
25 
26 #define WIRECELL_PATH_VARNAME "WIRECELL_PATH"
27 
29 {
30  auto ind = filename.rfind(".");
31  if (ind == string::npos) {
32  return "";
33  }
34  return filename.substr(ind);
35 }
36 
37 void WireCell::Persist::dump(const std::string& filename, const Json::Value& jroot, bool pretty)
38 {
39  string ext = file_extension(filename);
40 
41  /// default to .json.bz2 regardless of extension.
42  std::fstream fp(filename.c_str(), std::ios::binary|std::ios::out);
43  boost::iostreams::filtering_stream<boost::iostreams::output> outfilt;
44  if (ext == ".bz2") {
45  outfilt.push(boost::iostreams::bzip2_compressor());
46  }
47  outfilt.push(fp);
48  if (pretty) {
49  Json::StyledWriter jwriter;
50  outfilt << jwriter.write(jroot);
51  }
52  else {
53  Json::FastWriter jwriter;
54  outfilt << jwriter.write(jroot);
55  }
56 }
57 // fixme: support pretty option for indentation
59 {
60  stringstream ss;
61  ss << cfg;
62  return ss.str();
63 }
64 
66 {
67  std::string fname = resolve(filename);
68  if (fname.empty()) {
69  THROW(IOError() << errmsg{"no such file: " + filename + ". Maybe you need to add to WIRECELL_PATH."});
70  }
71 
72  std::ifstream fstr(filename);
73  std::stringstream buf;
74  buf << fstr.rdbuf();
75  return buf.str();
76 }
77 
78 
80 {
81  return boost::filesystem::exists(filename);
82 }
83 
84 static std::vector<std::string> get_path()
85 {
86  std::vector<std::string> ret;
87  const char* cpath = std::getenv(WIRECELL_PATH_VARNAME);
88  if (!cpath) {
89  return ret;
90  }
91  for (auto path : String::split(cpath)) {
92  ret.push_back(path);
93  }
94  return ret;
95 }
96 
97 
98 
100 {
101  if (filename.empty()) {
102  return "";
103  }
104  if (filename[0] == '/') {
105  return filename;
106  }
107 
108  std::vector<boost::filesystem::path> tocheck{boost::filesystem::current_path(),};
109  for (auto pathname : get_path()) {
110  tocheck.push_back(boost::filesystem::path(pathname));
111  }
112  for (auto pobj : tocheck) {
113  boost::filesystem::path full = pobj / filename;
114  if (boost::filesystem::exists(full)) {
115  return boost::filesystem::canonical(full).string();
116  }
117  }
118  return "";
119 }
120 
122  const externalvars_t& extvar,
123  const externalvars_t& extcode)
124 {
125  string ext = file_extension(filename);
126  if (ext == ".jsonnet") { // use libjsonnet++ file interface
127  string text = evaluate_jsonnet_file(filename, extvar, extcode);
128  return json2object(text);
129  }
130 
131  std::string fname = resolve(filename);
132  if (fname.empty()) {
133  THROW(IOError() << errmsg{"no such file: " + filename + ". Maybe you need to add to WIRECELL_PATH."});
134  }
135 
136 
137  // use jsoncpp file interface
138  std::fstream fp(fname.c_str(), std::ios::binary|std::ios::in);
139  boost::iostreams::filtering_stream<boost::iostreams::input> infilt;
140  if (ext == ".bz2" ) {
141  info("loading compressed json file: {}", fname);
142  infilt.push(boost::iostreams::bzip2_decompressor());
143  }
144  infilt.push(fp);
145  std::string text;
146  Json::Value jroot;
147  infilt >> jroot;
148  //return update(jroot, extvar); fixme
149  return jroot;
150 }
151 
153  const externalvars_t& extvar,
154  const externalvars_t& extcode)
155 {
156  const std::string jtext = evaluate_jsonnet_text(text, extvar, extcode);
157  return json2object(jtext);
158 }
159 
160 // bundles few lines into function to avoid some copy-paste
162 {
163  Json::Value res;
164  stringstream ss(text);
165  ss >> res;
166  return res;
167 }
168 
169 
170 static void init_parser(jsonnet::Jsonnet& parser,
171  const Persist::externalvars_t& extvar,
172  const Persist::externalvars_t& extcode)
173 {
174  parser.init();
175  for (auto path : get_path()) {
176  parser.addImportPath(path);
177  }
178  for (auto& vv : extvar) {
179  parser.bindExtVar(vv.first, vv.second);
180  }
181  for (auto& vv : extcode) {
182  parser.bindExtCodeVar(vv.first, vv.second);
183  }
184 }
186  const externalvars_t& extvar,
187  const externalvars_t& extcode)
188 {
189  std::string fname = resolve(filename);
190  if (fname.empty()) {
191  THROW(IOError() << errmsg{"no such file: " + filename + ", maybe you need to add to WIRECELL_PATH."});
192  }
193 
194  jsonnet::Jsonnet parser;
195  init_parser(parser, extvar, extcode);
196 
197  std::string output;
198  const bool ok = parser.evaluateFile(fname, &output);
199  if (!ok) {
200  error(parser.lastError());
201  THROW(ValueError() << errmsg{parser.lastError()});
202  }
203  return output;
204 }
206  const externalvars_t& extvar,
207  const externalvars_t& extcode)
208 {
209  jsonnet::Jsonnet parser;
210  init_parser(parser, extvar, extcode);
211 
212  std::string output;
213  bool ok = parser.evaluateSnippet("<stdin>", text, &output);
214  if (!ok) {
215  error(parser.lastError());
216  THROW(ValueError() << errmsg{parser.lastError()});
217  }
218  return output;
219 }
220 
221 WireCell::Persist::Parser::Parser(const std::vector<std::string>& load_paths,
222  const externalvars_t& extvar,
223  const externalvars_t& extcode)
224 {
225  m_jsonnet.init();
226 
227  // Loading: 1) cwd, 2) passed in paths 3) environment
228  m_load_paths.push_back(boost::filesystem::current_path());
229  for (auto path : load_paths) {
230  m_load_paths.push_back(boost::filesystem::path(path));
231  }
232  for (auto path : get_path()) {
233  m_load_paths.push_back(boost::filesystem::path(path));
234  }
235  // load paths into jsonnet backwards to counteract its reverse ordering
236  for (auto pit = m_load_paths.rbegin(); pit != m_load_paths.rend(); ++pit) {
237  m_jsonnet.addImportPath(boost::filesystem::canonical(*pit).string());
238  }
239 
240 
241  // external variables
242  for (auto& vv : extvar) {
243  m_jsonnet.bindExtVar(vv.first, vv.second);
244  }
245  // external code
246  for (auto& vv : extcode) {
247  m_jsonnet.bindExtCodeVar(vv.first, vv.second);
248  }
249 }
250 
251 
252 
253 
254 ///
255 /// Below is a reimplimenatiaon of the above but in class form.....
256 ////
257 
259 {
260  if (filename.empty()) {
261  return "";
262  }
263  if (filename[0] == '/') {
264  return filename;
265  }
266 
267  for (auto pobj : m_load_paths) {
268  boost::filesystem::path full = pobj / filename;
269  if (boost::filesystem::exists(full)) {
270  return boost::filesystem::canonical(full).string();
271  }
272  }
273  return "";
274 }
275 
277 {
278  std::string fname = resolve(filename);
279  if (fname.empty()) {
280  THROW(IOError() << errmsg{"no such file: " + filename
281  + ". Maybe you need to add to WIRECELL_PATH."});
282  }
283  string ext = file_extension(filename);
284 
285  if (ext == ".jsonnet" or ext.empty()) { // use libjsonnet++ file interface
286  std::string output;
287  const bool ok = m_jsonnet.evaluateFile(fname, &output);
288  if (!ok) {
289  error(m_jsonnet.lastError());
290  THROW(ValueError() << errmsg{m_jsonnet.lastError()});
291  }
292  return json2object(output);
293  }
294 
295  // also support JSON, possibly compressed
296 
297  // use jsoncpp file interface
298  std::fstream fp(fname.c_str(), std::ios::binary|std::ios::in);
299  boost::iostreams::filtering_stream<boost::iostreams::input> infilt;
300  if (ext == ".bz2" ) {
301  info("loading compressed json file: {}", fname);
302  infilt.push(boost::iostreams::bzip2_decompressor());
303  }
304  infilt.push(fp);
305  std::string text;
306  Json::Value jroot;
307  infilt >> jroot;
308  //return update(jroot, extvar); fixme
309  return jroot;
310 }
311 
313 {
314  std::string output;
315  bool ok = m_jsonnet.evaluateSnippet("<stdin>", text, &output);
316  if (!ok) {
317  error(m_jsonnet.lastError());
318  THROW(ValueError() << errmsg{m_jsonnet.lastError()});
319  }
320  return json2object(output);
321 }
std::string evaluate_jsonnet_file(const std::string &filename, const externalvars_t &extvar=externalvars_t(), const externalvars_t &extcode=externalvars_t())
Definition: Persist.cxx:185
std::string resolve(const std::string &filename)
Below is a reimplimenatiaon of the above but in class form..... /.
Definition: Persist.cxx:258
static std::vector< std::string > get_path()
Definition: Persist.cxx:84
Thrown when an error involving accessing input or output has occurred.
Definition: Exceptions.h:46
std::string dumps(const Json::Value &top, bool pretty=false)
As above but dump to a JSON text string.
Definition: Persist.cxx:58
std::string evaluate_jsonnet_text(const std::string &text, const externalvars_t &extvar=externalvars_t(), const externalvars_t &extcode=externalvars_t())
Definition: Persist.cxx:205
Json::Value json2object(const std::string &text)
Definition: Persist.cxx:161
void info(const char *fmt, const Args &...args)
Definition: spdlog.h:189
std::string string
Definition: nybbler.cc:12
boost::error_info< struct tag_errmsg, std::string > errmsg
Definition: Exceptions.h:54
#define WIRECELL_PATH_VARNAME
Definition: Persist.cxx:26
error
Definition: include.cc:26
STL namespace.
std::map< std::string, std::string > externalvars_t
Definition: Persist.h:69
cfg
Definition: dbjson.py:29
string filename
Definition: train.py:213
Parser(const pathlist_t &load_paths=pathlist_t(), const externalvars_t &extvar=externalvars_t(), const externalvars_t &extcode=externalvars_t())
Definition: Persist.cxx:221
bool exists(std::string path)
static std::string file_extension(const std::string &filename)
Definition: Persist.cxx:28
GenericValue< UTF8<> > Value
GenericValue with UTF8 encoding.
Definition: document.h:2106
std::string getenv(std::string const &name)
Definition: getenv.cc:15
Json::Value load(const std::string &filename, const externalvars_t &extvar=externalvars_t(), const externalvars_t &extcode=externalvars_t())
Definition: Persist.cxx:121
#define THROW(e)
Definition: Exceptions.h:25
bool exists(const std::string &filename)
Return true file exists (no file resolution performed).
Definition: Persist.cxx:79
Thrown when a wrong value has been encountered.
Definition: Exceptions.h:37
Definition: Main.h:22
Json::Value loads(const std::string &text, const externalvars_t &extvar=externalvars_t(), const externalvars_t &extcode=externalvars_t())
Definition: Persist.cxx:152
Json::Value load(const std::string &filename)
Definition: Persist.cxx:276
void dump(const std::string &filename, const Json::Value &top, bool pretty=false)
Definition: Persist.cxx:37
static void init_parser(jsonnet::Jsonnet &parser, const Persist::externalvars_t &extvar, const Persist::externalvars_t &extcode)
Definition: Persist.cxx:170
void split(std::string const &s, char c, OutIter dest)
Definition: split.h:35
std::string slurp(const std::string &filename)
Definition: Persist.cxx:65
std::string resolve(const std::string &filename)
Definition: Persist.cxx:99
Json::Value loads(const std::string &text)
Definition: Persist.cxx:312
void error(const char *fmt, const Args &...args)
Definition: spdlog.h:201