sjef
sjef.h
Go to the documentation of this file.
1 #ifndef SJEF_SJEF_H
2 #define SJEF_SJEF_H
3 #ifdef __APPLE__
4 #if (__DARWIN_C_LEVEL < __DARWIN_C_FULL) && (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 201112L) && \
5  (!defined(__cplusplus) || __cplusplus < 201703L)
6 #include <boost/align/aligned_alloc.hpp>
7 using boost::alignment::aligned_alloc;
8 #endif
9 #endif
10 #include <filesystem>
11 #include <iostream>
12 #include <map>
13 #include <memory>
14 #include <mutex>
15 #include <ostream>
16 #include <set>
17 #include <sjef/util/Logger.h>
18 #include <string>
19 #include <thread>
20 #include <vector>
21 
22 namespace pugi {
23 class xpath_node_set;
24 }
25 namespace sjef {
26 namespace util {
27 class Job;
28 class Locker;
29 } // namespace util
30 class Backend;
31 using util::Locker;
32 using util::Logger;
33 struct pugi_xml_document;
34 static constexpr int recentMax = 128;
35 enum status : int { unknown = 0, running = 1, waiting = 2, completed = 3, unevaluated = 4, killed = 5, failed = 6 };
36 using mapstringstring_t = std::map<std::string, std::string>;
37 
38 class Project {
39 private:
40  std::string m_project_suffix;
41  std::filesystem::path m_filename;
43  std::vector<std::filesystem::path> m_reserved_files = std::vector<std::filesystem::path>{
44  sjef::Project::s_propertyFile};
45  std::unique_ptr<pugi_xml_document> m_properties;
46  mapstringstring_t m_suffixes;
47  std::map<std::string, Backend> m_backends;
48 
49  std::unique_ptr<pugi_xml_document> m_backend_doc;
50  // put the flag into a container to deal conveniently with std:atomic_flag's
51  // lack of move constructor
52  struct unmovables_container {
53  std::mutex m_property_set_mutex;
54  };
55  mutable unmovables_container m_unmovables;
56  mutable std::string m_backend;
57  mutable std::string m_xml_cached;
59  static const std::string s_propertyFile;
61  std::shared_ptr<Locker> m_locker;
62  mutable Logger m_warn{std::cerr, Logger::Levels::warning, {"sjef:: Error: ", "sjef:: Warning: ", "sjef:: Note:"}};
63  mutable Logger m_trace{std::cout, Logger::Levels::quiet};
64  friend class util::Job;
65  mutable std::unique_ptr<util::Job> m_job;
66 
67 public:
79  explicit Project(const std::filesystem::path& filename, bool construct = true, const std::string& default_suffix = "",
80  const mapstringstring_t& suffixes = {{"inp", "inp"}, {"out", "out"}, {"xml", "xml"}});
81  // explicit Project(const std::string& filename, bool construct = true, const std::string& default_suffix = "",
82  // const mapstringstring_t& suffixes = {{"inp", "inp"}, {"out", "out"}, {"xml", "xml"}}) :
83  // Project(std::filesystem::path(filename),construct,default_suffix,suffixes) {}
84  Project(const Project& source) = delete;
85  Project(const Project&& source) = delete;
86  virtual ~Project();
100  bool copy(const std::filesystem::path& destination_filename, bool force = false, bool keep_hash = false,
101  bool slave = false, int keep_run_directories = std::numeric_limits<int>::max(), bool history = true);
110  bool move(const std::filesystem::path& destination_filename, bool force = false, bool history = true);
114  bool trash();
119  static void erase(const std::filesystem::path& filename, const std::string& default_suffix = "");
127  bool import_file(const std::filesystem::path& file, bool overwrite = false);
128  bool import_file(const std::vector<std::string>& files, bool overwrite = false) {
129  bool result = true;
130  for (const auto& file : files)
131  result &= import_file(file, overwrite);
132  return result;
133  }
140  bool export_file(const std::filesystem::path& file, bool overwrite = false);
141  bool export_file(const std::vector<std::string>& files, bool overwrite = false) {
142  bool result = true;
143  for (const auto& file : files)
144  result &= export_file(file, overwrite);
145  return result;
146  }
153  void set_warnings(const Logger::Levels level = Logger::Levels::warning, std::ostream& stream = std::cerr,
154  std::vector<std::string> preambles = {"sjef:: Error: ", "sjef:: Warning: ", "sjef:: Note:"}) {
155  m_warn = Logger{stream, level, std::move(preambles)};
156  }
157  void set_verbosity(int verbosity, std::ostream& stream = std::cout) { m_trace = Logger(stream, verbosity); }
158 
169  bool run(int verbosity = 0, bool force = false, bool wait = false, const std::string& options="");
170  bool run(const std::string& name, int verbosity = 0, bool force = false, bool wait = false, const std::string& options="") {
172  return run(verbosity, force, wait);
173  }
174 
190  std::string status_message(int verbosity = 0) const;
197  void wait(unsigned int maximum_microseconds = 10000) const;
201  void kill(int verbosity = 0);
209  bool run_needed(int verbosity = 0) const;
217  std::string input_from_output(bool sync = true) const;
232  void rewrite_input_file(const std::string& input_file_name, const std::string& old_name);
251  std::string xml(int run = 0, bool sync = true) const;
265  std::string file_contents(const std::string& suffix = "", const std::string& name = "", int run = 0,
266  bool sync = true) const;
267 
272  void clean(int keep_run_directories = 1);
273 
279  void property_set(const std::string& property, const std::string& value);
284  void property_set(const mapstringstring_t& properties);
290  std::string property_get(const std::string& property) const;
296  mapstringstring_t property_get(const std::vector<std::string>& properties) const;
301  void property_delete(const std::string& property);
302  void property_delete(const std::vector<std::string>& properties);
307  std::vector<std::string> property_names() const;
321  std::filesystem::path filename(std::string suffix = "", const std::string& name = "", int run = -1) const;
322  std::string filename_string(std::string suffix = "", const std::string& name = "", int run = -1) const;
323  std::string run_directory_basename(int run = 0) const;
331  std::filesystem::path run_directory(int run = 0) const;
338  int run_verify(int run) const;
343  using run_list_t = std::vector<std::string>;
350  std::filesystem::path run_directory_new();
355  void run_delete(int run);
361  std::string name() const;
368  static int recent_find(const std::string& suffix, const std::filesystem::path& filename);
369  int recent_find(const std::filesystem::path& filename) const;
376  static std::string recent(const std::string& suffix, int number = 1);
377  std::string recent(int number = 1) const;
385  void change_backend(std::string backend = std::string{""}, bool force = false);
386 
387  const std::map<std::string, Backend>& backends() const { return m_backends; }
388  std::map<std::string, Backend>& backends() { return m_backends; }
389 
390 private:
391  Backend default_backend();
392  void throw_if_backend_invalid(std::string backend = "") const;
393  std::string get_project_suffix(const std::filesystem::path& filename, const std::string& default_suffix) const;
394  static void recent_edit(const std::filesystem::path& add, const std::filesystem::path& remove = "");
395  mutable std::filesystem::file_time_type m_property_file_modification_time;
396  mutable std::map<std::string, std::filesystem::file_time_type, std::less<>> m_input_file_modification_time;
397  std::set<std::string, std::less<>> m_run_directory_ignore;
398  void property_delete_locked(const std::string& property);
399  void check_property_file_locked() const;
400  void check_property_file() const;
401  void save_property_file_locked() const;
402  void save_property_file() const;
403  void load_property_file_locked() const;
404  bool properties_last_written_by_me(bool removeFile = false) const;
405  bool check_backends(const std::string& suffix) const;
406 
407 public:
408  std::filesystem::path propertyFile() const;
413  const std::string backend_cache() const;
414 
415 private:
416  std::string cache(const Backend& backend) const;
417  void force_file_names(const std::string& oldname);
418  static void backend_watcher(sjef::Project& project_, int min_wait_milliseconds, int max_wait_milliseconds = 0,
419  int poll_milliseconds = 1);
420  void shutdown_backend_watcher();
428  std::string referenced_file_contents(const std::string& line) const;
429 
430 public:
431  static const std::vector<std::string> suffix_keys;
432  /*
433  */
442  size_t project_hash();
448  size_t input_hash() const;
449 
456  std::string backend_get(const std::string& backend, const std::string& key) const;
457 
472  std::string backend_parameter_expand(const std::string& backend, std::string templ = "") const;
473 
481  mapstringstring_t backend_parameters(const std::string& backend, bool doc = false) const;
482 
483  void backend_parameter_set(const std::string& backend, const std::string& name, const std::string& value) {
484  property_set("Backend/" + backend + "/" + name, value);
485  }
486 
487  void backend_parameter_delete(const std::string& backend, const std::string& name) {
488  property_delete("Backend/" + backend + "/" + name);
489  }
490 
491  std::string backend_parameter_get(const std::string& backend, const std::string& name) const {
492  auto p = property_get("Backend/" + backend + "/" + name);
493  if (p.find("!") == std::string::npos)
494  return p;
495  return p.substr(0, p.find("!"));
496  }
497 
504  std::string backend_parameter_documentation(const std::string& backend, const std::string& name) const {
505  auto ps = backend_parameters(backend, true);
506  if (ps.count(name) == 0)
507  return "";
508  return ps.at(name);
509  }
510 
517  std::string backend_parameter_default(const std::string& backend, const std::string& name) const {
518  auto ps = backend_parameters(backend, false);
519  if (ps.count(name) == 0)
520  return "";
521  return ps.at(name);
522  }
523 
528  std::vector<std::string> backend_names() const;
529 
537  void add_backend(const std::string& name, const mapstringstring_t& fields);
538 
544  void delete_backend(const std::string& name);
545 
551  bool check_backend(const std::string& name) const;
552 
557  bool check_all_backends() const;
558 
566  void take_run_files(int run = 0, const std::string& fromname = "", const std::string& toname = "") const;
567 
573  void set_current_run(unsigned int run = 0);
574 
579  unsigned int current_run() const;
580 
587  pugi::xpath_node_set select_nodes(const std::string& xpath_query, int run = 0) const;
596  std::vector<std::string> xpath_search(const std::string& xpath_query, const std::string& attribute = "",
597  int run = 0) const;
598 
606  std::vector<std::string> xpath_xml(const std::string& xpath_query, int run = 0) const;
607 };
608 
617 bool check_backends(const std::string& suffix);
618 
633 std::filesystem::path expand_path(const std::filesystem::path& path, const std::string& suffix = "");
634 
643 std::string xmlRepair(const std::string& source, const mapstringstring_t& injections = {});
644 
649 std::string version() noexcept;
650 
651 class runtime_error : public std::runtime_error {
652  using std::runtime_error::runtime_error;
653 };
654 
655 } // namespace sjef
656 
657 #endif // SJEF_SJEF_H
Definition: sjef.h:38
void property_delete(const std::vector< std::string > &properties)
std::string filename_string(std::string suffix="", const std::string &name="", int run=-1) const
size_t input_hash() const
Construct a hash that is unique to the contents of the input file and anything it references.
bool export_file(const std::vector< std::string > &files, bool overwrite=false)
Definition: sjef.h:141
friend class util::Job
Definition: sjef.h:64
void rewrite_input_file(const std::string &input_file_name, const std::string &old_name)
std::string backend_get(const std::string &backend, const std::string &key) const
Obtain the value of a field in a backend.
int local_pid_from_output() const
Try to get the process id of the job from its output, if the running program happens to offer that.
std::string run_directory_basename(int run=0) const
run_list_t run_list() const
bool copy(const std::filesystem::path &destination_filename, bool force=false, bool keep_hash=false, bool slave=false, int keep_run_directories=std::numeric_limits< int >::max(), bool history=true)
Copy the project to another location.
std::filesystem::path run_directory_new()
Create a new run directory. Also copy into it the input file, and any of its dependencies.
bool check_backend(const std::string &name) const
Check whether the specification of a backend is valid.
bool run(const std::string &name, int verbosity=0, bool force=false, bool wait=false, const std::string &options="")
Definition: sjef.h:170
const std::string backend_cache() const
Get the location of the backend cache.
int recent_find(const std::filesystem::path &filename) const
std::string name() const
std::string backend_parameter_default(const std::string &backend, const std::string &name) const
Return the default value associated with a backend run parameter.
Definition: sjef.h:517
std::vector< std::string > xpath_search(const std::string &xpath_query, const std::string &attribute="", int run=0) const
Simple XPath search on the xml document. For each matching node found, return a string that contains ...
void backend_parameter_set(const std::string &backend, const std::string &name, const std::string &value)
Definition: sjef.h:483
void take_run_files(int run=0, const std::string &fromname="", const std::string &toname="") const
Copy files from a run directory to the main project.
bool import_file(const std::vector< std::string > &files, bool overwrite=false)
Definition: sjef.h:128
void delete_backend(const std::string &name)
Remove a backend from the project and from the user's global backend configuration for all projects o...
virtual ~Project()
bool import_file(const std::filesystem::path &file, bool overwrite=false)
Import one or more files into the project. In the case of a .xml output file, if the corresponding in...
sjef::status status() const
Obtain the status of the job started by run()
void custom_initialisation()
Perform any project initialisation specific to the project suffix.
std::string file_contents(const std::string &suffix="", const std::string &name="", int run=0, bool sync=true) const
Obtain the contents of a project file.
std::filesystem::path propertyFile() const
void property_delete(const std::string &property)
Remove a variable.
Project(const Project &source)=delete
void wait(unsigned int maximum_microseconds=10000) const
Wait unconditionally for status() to return neither 'waiting' nor 'running'.
void custom_run_preface()
Before launching a job, perform any required actions specific to the project suffix.
mapstringstring_t property_get(const std::vector< std::string > &properties) const
Get the values of several properties.
std::string xml(int run=0, bool sync=true) const
Get the xml output, completing any open tags if necessary.
unsigned int current_run() const
Get the focussed run directory.
mapstringstring_t backend_parameters(const std::string &backend, bool doc=false) const
Get all of the parameters referenced in the run_command of a backend.
std::string input_from_output(bool sync=true) const
If possible, construct the input embedded in the output file.
std::string backend_parameter_expand(const std::string &backend, std::string templ="") const
Perform parameter substitution for a backend run_command template.
bool trash()
Move the project to the trash folder.
bool check_all_backends() const
Check the specification of all backends for validity.
int run_verify(int run) const
Check a run exists, and resolve most recent.
bool move(const std::filesystem::path &destination_filename, bool force=false, bool history=true)
Move the project to another location.
std::string property_get(const std::string &property) const
Get the value of a property.
void clean(int keep_run_directories=1)
Remove run directories from project.
std::filesystem::path filename(std::string suffix="", const std::string &name="", int run=-1) const
Get the file name of the bundle, or a primary file of particular type, or a general file in the bundl...
std::string backend_parameter_get(const std::string &backend, const std::string &name) const
Definition: sjef.h:491
void set_verbosity(int verbosity, std::ostream &stream=std::cout)
Definition: sjef.h:157
static int recent_find(const std::string &suffix, const std::filesystem::path &filename)
Look for a project by name in the user-global recent project list.
void add_backend(const std::string &name, const mapstringstring_t &fields)
Introduce a new backend to the project and to the user's global backend configuration for all project...
void set_warnings(const Logger::Levels level=Logger::Levels::warning, std::ostream &stream=std::cerr, std::vector< std::string > preambles={"sjef:: Error: ", "sjef:: Warning: ", "sjef:: Note:"})
Set the warning/error diagnostic level and destination.
Definition: sjef.h:153
void change_backend(std::string backend=std::string{""}, bool force=false)
Change the active backend.
bool export_file(const std::filesystem::path &file, bool overwrite=false)
Export one or more files from the project.
Project(const Project &&source)=delete
std::map< std::string, Backend > & backends()
Definition: sjef.h:388
std::vector< std::string > backend_names() const
Get the names of all the backend objects associated with the object.
void run_delete(int run)
Delete a run directory.
bool run(int verbosity=0, bool force=false, bool wait=false, const std::string &options="")
Start a sjef job.
void property_set(const std::string &property, const std::string &value)
Set a property.
static const std::vector< std::string > suffix_keys
Definition: sjef.h:431
std::string recent(int number=1) const
static std::string recent(const std::string &suffix, int number=1)
Look for a project by rank in the user-global recent project list.
std::string status_message(int verbosity=0) const
static void erase(const std::filesystem::path &filename, const std::string &default_suffix="")
Erase a project from the file system, and remove it from the recent projects file.
void property_set(const mapstringstring_t &properties)
Set one or more properties.
bool run_needed(int verbosity=0) const
Check whether the job output is believed to be out of date with respect to the input and any other fi...
void backend_parameter_delete(const std::string &backend, const std::string &name)
Definition: sjef.h:487
std::string backend_parameter_documentation(const std::string &backend, const std::string &name) const
Return the documentation associated with a backend run parameter.
Definition: sjef.h:504
const std::map< std::string, Backend > & backends() const
Definition: sjef.h:387
void set_current_run(unsigned int run=0)
Set the focussed run directory.
sjef::status status_from_output() const
Obtain the job status, if possible, by examining the output.
std::vector< std::string > property_names() const
Get the names of all assigned properties.
void refresh_backends()
Reload the backends from the configuration file.
pugi::xpath_node_set select_nodes(const std::string &xpath_query, int run=0) const
General XPath search on the xml document. Needs the pugixml library to parse the result.
std::vector< std::string > xpath_xml(const std::string &xpath_query, int run=0) const
Simple XPath search on the xml document. For each matching node found, return a string that contains ...
std::filesystem::path run_directory(int run=0) const
Obtain the path of a run directory.
void kill(int verbosity=0)
Kill the job started by run()
Project(const std::filesystem::path &filename, bool construct=true, const std::string &default_suffix="", const mapstringstring_t &suffixes={{"inp", "inp"}, {"out", "out"}, {"xml", "xml"}})
Construct, or attach to, a Molpro project bundle.
size_t project_hash()
Return a globally-unique hash to identify the project. The hash is generated on first call to this fu...
std::vector< std::string > run_list_t
Obtain the list of run directory names.
Definition: sjef.h:343
Definition: sjef.h:651
A thread-safe class for an inter-thread/inter-process lock. The lock mechanism is based on a locked f...
Definition: Locker.h:28
Definition: sjef.h:22
Definition: sjef.h:25
bool check_backends(const std::string &suffix)
Check whether a backend specification file is valid. Only the top-level structure of the file is chec...
status
Definition: sjef.h:35
@ failed
Definition: sjef.h:35
@ killed
Definition: sjef.h:35
@ completed
Definition: sjef.h:35
@ waiting
Definition: sjef.h:35
@ running
Definition: sjef.h:35
@ unevaluated
Definition: sjef.h:35
@ unknown
Definition: sjef.h:35
std::string xmlRepair(const std::string &source, const mapstringstring_t &injections={})
Repair an xml dataset by completing any open tags.
std::map< std::string, std::string > mapstringstring_t
Definition: sjef.h:36
std::filesystem::path expand_path(const std::filesystem::path &path, const std::string &suffix="")
Edit a file path name.
std::string version() noexcept
Report the software version.