From 40194eb9b5e3e32adfa10135ed538199bc475eac Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Mon, 26 Feb 2024 23:15:31 +0100 Subject: [PATCH 1/2] Refactored util pipe handling (#244) --- src/util/util.cc | 76 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 51 insertions(+), 25 deletions(-) diff --git a/src/util/util.cc b/src/util/util.cc index e8c139db..fb7361ac 100644 --- a/src/util/util.cc +++ b/src/util/util.cc @@ -28,29 +28,69 @@ namespace clanguml::util { static const auto WHITESPACE = " \n\r\t\f\v"; +namespace { +struct pipe_t { + explicit pipe_t(const std::string &command, int &result) + : result_{result} + , +#if defined(__linux) || defined(__unix) || defined(__APPLE__) + pipe_{popen(command.c_str(), "r")} +#elif defined(_WIN32) + pipe_{_popen(command.c_str(), "r")} +#endif + { + } + + ~pipe_t() { reset(); } + + operator bool() const { return pipe_ != nullptr; } + + FILE *get() const { return pipe_; } + + void reset() + { + if (pipe_ == nullptr) + return; + +#if defined(__linux) || defined(__unix) || defined(__APPLE__) + result_ = pclose(pipe_); +#elif defined(_WIN32) + result_ = _pclose(pipe_); +#endif + pipe_ = nullptr; + } + +private: + int &result_; + FILE *pipe_; +}; +} // namespace + std::string get_process_output(const std::string &command) { constexpr size_t kBufferSize{1024}; std::array buffer{}; - std::string result; + std::string output; + int result{EXIT_FAILURE}; -#if defined(__linux) || defined(__unix) || defined(__APPLE__) - std::unique_ptr pipe( - popen(command.c_str(), "r"), pclose); -#elif defined(_WIN32) - std::unique_ptr pipe( - _popen(command.c_str(), "r"), _pclose); -#endif + pipe_t pipe{command, result}; if (!pipe) { throw std::runtime_error("popen() failed!"); } while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) { - result += buffer.data(); + output += buffer.data(); } - return result; + pipe.reset(); + + if (result != EXIT_SUCCESS) { + throw std::runtime_error( + fmt::format("External command '{}' failed: {}", command, output)); + } + + return output; } void check_process_output(const std::string &command) @@ -59,21 +99,7 @@ void check_process_output(const std::string &command) std::array buffer{}; int result{EXIT_FAILURE}; std::string output; - auto finalize = [&result](FILE *f) { -#if defined(__linux) || defined(__unix) || defined(__APPLE__) - result = pclose(f); -#elif defined(_WIN32) - result = _pclose(f); -#endif - }; - -#if defined(__linux) || defined(__unix) || defined(__APPLE__) - std::unique_ptr pipe( - popen(command.c_str(), "r"), finalize); -#elif defined(_WIN32) - std::unique_ptr pipe( - _popen(command.c_str(), "r"), finalize); -#endif + pipe_t pipe{command, result}; if (!pipe) { throw std::runtime_error("popen() failed!"); From 674441f3cd482651ac5808485a5a209ddde7cfc4 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Tue, 27 Feb 2024 00:18:06 +0100 Subject: [PATCH 2/2] Fixed error when running clang-uml outside of a Git repository --- src/util/util.cc | 66 ++++++++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/src/util/util.cc b/src/util/util.cc index fb7361ac..a9553e8c 100644 --- a/src/util/util.cc +++ b/src/util/util.cc @@ -29,7 +29,8 @@ namespace clanguml::util { static const auto WHITESPACE = " \n\r\t\f\v"; namespace { -struct pipe_t { +class pipe_t { +public: explicit pipe_t(const std::string &command, int &result) : result_{result} , @@ -147,48 +148,59 @@ bool is_git_repository() if (!env.empty()) return true; - return contains( - trim(get_process_output("git rev-parse --git-dir")), ".git"); + std::string output; + + try { + output = get_process_output("git rev-parse --git-dir"); + } + catch (std::runtime_error &e) { + return false; + } + + return contains(trim(output), ".git"); +} + +std::string run_git_command( + const std::string &cmd, const std::string &env_override) +{ + auto env = get_env(env_override); + + if (!env.empty()) + return env; + + std::string output; + + try { + output = get_process_output(cmd); + } + catch (std::runtime_error &e) { + return {}; + } + + return trim(output); } std::string get_git_branch() { - auto env = get_env("CLANGUML_GIT_BRANCH"); - - if (!env.empty()) - return env; - - return trim(get_process_output("git rev-parse --abbrev-ref HEAD")); + return run_git_command( + "git rev-parse --abbrev-ref HEAD", "CLANGUML_GIT_BRANCH"); } std::string get_git_revision() { - auto env = get_env("CLANGUML_GIT_REVISION"); - - if (!env.empty()) - return env; - - return trim(get_process_output("git describe --tags --always")); + return run_git_command( + "git describe --tags --always", "CLANGUML_GIT_REVISION"); } std::string get_git_commit() { - auto env = get_env("CLANGUML_GIT_COMMIT"); - - if (!env.empty()) - return env; - - return trim(get_process_output("git rev-parse HEAD")); + return run_git_command("git rev-parse HEAD", "CLANGUML_GIT_COMMIT"); } std::string get_git_toplevel_dir() { - auto env = get_env("CLANGUML_GIT_TOPLEVEL_DIR"); - - if (!env.empty()) - return env; - - return trim(get_process_output("git rev-parse --show-toplevel")); + return run_git_command( + "git rev-parse --show-toplevel", "CLANGUML_GIT_TOPLEVEL_DIR"); } std::string get_os_name()