diff --git a/engine/src/simulation.cpp b/engine/src/simulation.cpp index a8511026..4ad51082 100644 --- a/engine/src/simulation.cpp +++ b/engine/src/simulation.cpp @@ -75,14 +75,13 @@ #include "simulation.hpp" -#include // for uint64_t -#include // for ofstream -#include // for future<>, async -#include // for stringstream -#include // for string -#include // for sleep_for - -#include // for is_directory, is_regular_file, ... +#include // for uint64_t +#include // for filesystem::path +#include // for ofstream +#include // for future<>, async +#include // for stringstream +#include // for string +#include // for sleep_for #include // for Controller #include // for AsyncAbort @@ -1608,7 +1607,7 @@ size_t Simulation::write_output(const SimulationResult& r) const { return; } - boost::filesystem::path filepath = r.get_output_filepath(*filename); + std::filesystem::path filepath = r.get_output_filepath(*filename); if (write_output_file(filepath, output)) { files_written++; } @@ -1624,7 +1623,7 @@ size_t Simulation::write_output(const SimulationResult& r) const { return files_written; } -bool Simulation::write_output_file(const boost::filesystem::path& filepath, +bool Simulation::write_output_file(const std::filesystem::path& filepath, const cloe::Json& j) const { if (!is_writable(filepath)) { return false; @@ -1641,15 +1640,15 @@ bool Simulation::write_output_file(const boost::filesystem::path& filepath, return true; } -bool Simulation::is_writable(const boost::filesystem::path& filepath) const { +bool Simulation::is_writable(const std::filesystem::path& filepath) const { // Make sure we're not clobbering anything if we shouldn't. auto native = filepath.native(); - if (boost::filesystem::exists(filepath)) { + if (std::filesystem::exists(filepath)) { if (!config_.engine.output_clobber_files) { logger()->error("Will not clobber file: {}", native); return false; } - if (!boost::filesystem::is_regular_file(filepath)) { + if (!std::filesystem::is_regular_file(filepath)) { logger()->error("Cannot clobber non-regular file: {}", native); return false; } @@ -1657,8 +1656,8 @@ bool Simulation::is_writable(const boost::filesystem::path& filepath) const { // Make sure the directory exists. auto dirpath = filepath.parent_path(); - if (!boost::filesystem::is_directory(dirpath)) { - bool ok = boost::filesystem::create_directories(dirpath); + if (!std::filesystem::is_directory(dirpath)) { + bool ok = std::filesystem::create_directories(dirpath); if (!ok) { logger()->error("Error creating leading directories: {}", dirpath.native()); return false; diff --git a/engine/src/simulation.hpp b/engine/src/simulation.hpp index 1399bb6f..c83abcad 100644 --- a/engine/src/simulation.hpp +++ b/engine/src/simulation.hpp @@ -49,7 +49,7 @@ struct SimulationResult { cloe::Json signals; // dump of all signals in DataBroker right before the simulation started std::vector signals_autocompletion; // pseudo lua file used for vscode autocompletion - std::optional output_dir; + std::optional output_dir; public: /** @@ -65,8 +65,8 @@ struct SimulationResult { * and output path are set automatically. Thus, if they are empty, then * that is because the user explicitly set them so. */ - boost::filesystem::path get_output_filepath(const boost::filesystem::path& filename) const { - boost::filesystem::path filepath; + std::filesystem::path get_output_filepath(const std::filesystem::path& filename) const { + std::filesystem::path filepath; if (filename.is_absolute()) { filepath = filename; } else if (output_dir) { @@ -136,12 +136,12 @@ class Simulation { /** * Write the given JSON output into the file. Return true if successful. */ - bool write_output_file(const boost::filesystem::path& filepath, const cloe::Json& j) const; + bool write_output_file(const std::filesystem::path& filepath, const cloe::Json& j) const; /** * Check if the given filepath may be opened, respecting clobber options. */ - bool is_writable(const boost::filesystem::path& filepath) const; + bool is_writable(const std::filesystem::path& filepath) const; /** * Set whether simulation progress should be reported. diff --git a/engine/src/stack.cpp b/engine/src/stack.cpp index 086b98ec..6b6b9b62 100644 --- a/engine/src/stack.cpp +++ b/engine/src/stack.cpp @@ -23,18 +23,18 @@ #include "stack.hpp" -#include // for transform, swap -#include // for map<> -#include // for shared_ptr<> -#include // for set<> -#include // for string +#include // for transform, swap +#include // for filesystem +#include // for map<> +#include // for shared_ptr<> +#include // for set<> +#include // for string -#include // for starts_with -#include // for path -namespace fs = boost::filesystem; +namespace fs = std::filesystem; #include // for join_vector -#include // for indent_string +#include // for indent_string +#include // for starts_with namespace cloe { @@ -87,7 +87,7 @@ void LoggingConf::apply() const { std::string PluginConf::canonical() const { // Handle builtins specially, these are in a URI form. - if (boost::starts_with(plugin_path.string(), "builtin://")) { + if (fable::starts_with(plugin_path.string(), "builtin://")) { return plugin_path.string(); } diff --git a/engine/src/stack.hpp b/engine/src/stack.hpp index b8e918aa..a650678c 100644 --- a/engine/src/stack.hpp +++ b/engine/src/stack.hpp @@ -23,17 +23,15 @@ #pragma once -#include // for map<> -#include // for shared_ptr<> -#include // for set<> -#include // for string -#include // for move -#include // for vector<> -#include // for optional<> - -#include // for path -#include // for Optional<> -#include // for Path +#include // for filesystem::path +#include // for map<> +#include // for shared_ptr<> +#include // for optional<> +#include // for set<> +#include // for string +#include // for move +#include // for vector<> + #include // for CustomDeserializer #include // for Factory @@ -83,7 +81,7 @@ inline auto id_path_prototype(std::string desc = "") { * IncludeConf is a relative or absolute filepath that should be included in * the stack configuration. */ -using IncludeConf = boost::filesystem::path; +using IncludeConf = std::filesystem::path; using IncludeSchema = decltype(schema::make_schema(static_cast(nullptr), "")); using IncludesSchema = schema::Vector; @@ -202,7 +200,7 @@ struct ServerConf : public Confable { */ struct PluginConf : public PersistentConfable { /** Filesystem path to file or directory. */ - boost::filesystem::path plugin_path{}; + std::filesystem::path plugin_path{}; /** Name to give plugin if path is to a single file. */ std::optional plugin_name{}; @@ -309,14 +307,14 @@ struct EngineConf : public Confable { bool triggers_ignore_source{false}; // Output: - std::optional registry_path{CLOE_DATA_HOME "/registry"}; - std::optional output_path{"${CLOE_SIMULATION_UUID}"}; - std::optional output_file_config{"config.json"}; - std::optional output_file_result{"result.json"}; - std::optional output_file_triggers{"triggers.json"}; - std::optional output_file_signals{"signals.json"}; - std::optional output_file_signals_autocompletion; - std::optional output_file_data_stream; + std::optional registry_path{CLOE_DATA_HOME "/registry"}; + std::optional output_path{"${CLOE_SIMULATION_UUID}"}; + std::optional output_file_config{"config.json"}; + std::optional output_file_result{"result.json"}; + std::optional output_file_triggers{"triggers.json"}; + std::optional output_file_signals{"signals.json"}; + std::optional output_file_signals_autocompletion; + std::optional output_file_data_stream; bool output_clobber_files{true}; /** @@ -390,8 +388,8 @@ struct EngineConf : public Confable { CONFABLE_SCHEMA(EngineConf) { // clang-format off using namespace schema; // NOLINT(build/namespaces) - auto dir_proto = []() { return make_prototype().not_file(); }; - auto file_proto = []() { return make_prototype().not_dir().resolve(false); }; + auto dir_proto = []() { return make_prototype().not_file(); }; + auto file_proto = []() { return make_prototype().not_dir().resolve(false); }; return Struct{ {"ignore", make_schema(&ignore_sections, "JSON pointers to sections that should be ignored").extend(true)}, {"security", Struct{ diff --git a/engine/src/stack_factory.cpp b/engine/src/stack_factory.cpp index a13ee1c3..a729dc74 100644 --- a/engine/src/stack_factory.cpp +++ b/engine/src/stack_factory.cpp @@ -27,8 +27,6 @@ #include // for string #include // for vector<> -#include // for path - #include // for split_string #include // for merge_config #include // for Environment @@ -49,7 +47,16 @@ Conf read_conf(const StackOptions& opt, const std::string& filepath) { // Prepare environment with extra variables: fable::Environment env(*opt.environment); if (!filepath.empty() && filepath != "-") { - std::string dirpath = boost::filesystem::canonical(filepath).parent_path().native(); + // We use weakly_canonical() because otherwise + // we get an error when calling cloe-engine like: + // + // cloe-engine run <(cat file.json) + std::string dirpath; + if (std::filesystem::is_other(filepath)) { + dirpath = std::filesystem::path(filepath).parent_path().native(); + } else { + dirpath = std::filesystem::weakly_canonical(filepath).parent_path().native(); + } env.set("THIS_STACKFILE_FILE", filepath); env.set("THIS_STACKFILE_DIR", dirpath); } @@ -106,7 +113,7 @@ Stack new_stack(const StackOptions& opt) { // Interpolate known variables, if requested. if (opt.interpolate_vars) { - auto interpolate_path = [&opt](std::optional& p) { + auto interpolate_path = [&opt](std::optional& p) { p = fable::interpolate_vars(p->native(), opt.environment.get()); }; interpolate_path(s.engine.registry_path); @@ -150,7 +157,7 @@ Stack new_stack(const StackOptions& opt) { // Merge system configurations: if (!opt.no_system_confs) { - auto mergefn = [&](const boost::filesystem::path& file) -> bool { + auto mergefn = [&](const std::filesystem::path& file) -> bool { s.logger()->info("Include conf {}", file.native()); merge_stack(opt, s, file.native()); return true; diff --git a/engine/src/utility/command.cpp b/engine/src/utility/command.cpp index 89596e54..c2b71828 100644 --- a/engine/src/utility/command.cpp +++ b/engine/src/utility/command.cpp @@ -48,7 +48,7 @@ CommandResult CommandExecuter::run_and_release(const cloe::Command& cmd) const { } try { if (!cmd.is_sync()) { - r.child = bp::child(cmd.executable(), cmd.args()); + r.child = bp::child(cmd.executable().native(), cmd.args()); if (cmd.is_detach()) { r.child->detach(); @@ -59,7 +59,7 @@ CommandResult CommandExecuter::run_and_release(const cloe::Command& cmd) const { // The syntax `(bp::std_out & bp::std_err) > is` is valid and works, but // was only found by rummaging through the source code. Ridiculous. - r.child = bp::child(cmd.executable(), cmd.args(), (bp::std_out & bp::std_err) > is); + r.child = bp::child(cmd.executable().native(), cmd.args(), (bp::std_out & bp::std_err) > is); std::string line; // After finished running output the rest of the lines. diff --git a/engine/src/utility/command.hpp b/engine/src/utility/command.hpp index dde4bddb..6127324b 100644 --- a/engine/src/utility/command.hpp +++ b/engine/src/utility/command.hpp @@ -27,6 +27,7 @@ #include // for optional<> #include // for string #include // for system_error +#include // for move #include // for vector<> #include // for child @@ -48,12 +49,12 @@ struct CommandResult { class CommandExecuter { public: explicit CommandExecuter(cloe::Logger logger, bool enabled = true) - : logger_(logger), enabled_(enabled) {} + : logger_(std::move(logger)), enabled_(enabled) {} - bool is_enabled() const { return enabled_; } + [[nodiscard]] bool is_enabled() const { return enabled_; } void set_enabled(bool v) { enabled_ = v; } - CommandResult run_and_release(const cloe::Command&) const; + CommandResult run_and_release(const cloe::Command&) const; // NOLINT void run(const cloe::Command&); @@ -65,7 +66,7 @@ class CommandExecuter { std::vector release_all(); - cloe::Logger logger() const { return logger_; } + [[nodiscard]] cloe::Logger logger() const { return logger_; } private: std::vector handles_; @@ -77,8 +78,8 @@ namespace actions { class Command : public cloe::Action { public: - Command(const std::string& name, const cloe::Command& cmd, CommandExecuter* exec) - : Action(name), command_(cmd), executer_(exec) { + Command(const std::string& name, cloe::Command cmd, CommandExecuter* exec) + : Action(name), command_(std::move(cmd)), executer_(exec) { assert(executer_ != nullptr); } @@ -86,7 +87,7 @@ class Command : public cloe::Action { return std::make_unique(name(), command_, executer_); } - cloe::CallbackResult operator()(const cloe::Sync&, cloe::TriggerRegistrar&) override; + cloe::CallbackResult operator()(const cloe::Sync& sync, cloe::TriggerRegistrar& registrar) override; protected: void to_json(cloe::Json& j) const override; @@ -103,9 +104,9 @@ class CommandFactory : public cloe::ActionFactory { : cloe::ActionFactory("command", "run a system command"), executer_(exec) { assert(executer_ != nullptr); } - cloe::TriggerSchema schema() const override; - cloe::ActionPtr make(const cloe::Conf& c) const override; - cloe::ActionPtr make(const std::string& s) const override; + [[nodiscard]] cloe::TriggerSchema schema() const override; + [[nodiscard]] cloe::ActionPtr make(const cloe::Conf& c) const override; + [[nodiscard]] cloe::ActionPtr make(const std::string& s) const override; private: CommandExecuter* executer_{nullptr};