From a54f9284556b612796b7d7d47954feadbf3ecc89 Mon Sep 17 00:00:00 2001 From: "Scott E. Graves" Date: Mon, 15 Sep 2025 12:43:58 -0500 Subject: [PATCH] win32 fixes/refactor ui main --- repertory/repertory/include/ui/ui_main.hpp | 29 ++ repertory/repertory/main.cpp | 82 +----- .../repertory/src/ui/mgmt_app_config.cpp | 2 +- repertory/repertory/src/ui/ui_main.cpp | 259 ++++++++++++++++++ repertory/repertory/src/ui/ui_server.cpp | 3 +- 5 files changed, 293 insertions(+), 82 deletions(-) create mode 100644 repertory/repertory/include/ui/ui_main.hpp create mode 100644 repertory/repertory/src/ui/ui_main.cpp diff --git a/repertory/repertory/include/ui/ui_main.hpp b/repertory/repertory/include/ui/ui_main.hpp new file mode 100644 index 00000000..2ad0605f --- /dev/null +++ b/repertory/repertory/include/ui/ui_main.hpp @@ -0,0 +1,29 @@ +/* + Copyright <2018-2025> + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +#ifndef REPERTORY_INCLUDE_UI_MAIN_HPP_ +#define REPERTORY_INCLUDE_UI_MAIN_HPP_ + +namespace repertory::ui { +[[nodiscard]] auto ui_main(const std::vector &args) -> int +} // namespace repertory::ui + +#endif // REPERTORY_INCLUDE_UI_MAIN_HPP_ diff --git a/repertory/repertory/main.cpp b/repertory/repertory/main.cpp index c113065c..59337fe9 100644 --- a/repertory/repertory/main.cpp +++ b/repertory/repertory/main.cpp @@ -26,10 +26,8 @@ #include "cli/actions.hpp" #include "initialize.hpp" #include "types/repertory.hpp" -#include "ui/mgmt_app_config.hpp" -#include "ui/ui_server.hpp" +#include "ui/ui_main.hpp" #include "utils/cli_utils.hpp" -#include "utils/error_utils.hpp" #include "utils/polling.hpp" using namespace repertory; @@ -66,83 +64,7 @@ auto main(int argc, char **argv) -> int { utils::cli::options::version_option)) { cli::actions::version(args); } else if (utils::cli::has_option(args, utils::cli::options::ui_option)) { - ui::mgmt_app_config config{ - utils::cli::has_option(args, utils::cli::options::hidden_option), - utils::cli::has_option(args, utils::cli::options::launch_only_option), - }; - - std::string data; - auto res = utils::cli::parse_string_option( - args, utils::cli::options::ui_port_option, data); - if (res == exit_code::success && not data.empty()) { - config.set_api_port(utils::string::to_uint16(data)); - } - - if (not utils::file::change_to_process_directory()) { - ret = static_cast(exit_code::ui_failed); - } else { - const auto run_ui = [](auto *server) { - REPERTORY_USES_FUNCTION_NAME(); - - static std::atomic active_server{server}; - static const auto quit_handler = [](int /* sig */) { - REPERTORY_USES_FUNCTION_NAME(); - - auto *ptr = active_server.exchange(nullptr); - if (ptr == nullptr) { - return; - } - - try { - ptr->stop(); - } catch (const std::exception &ex) { - utils::error::raise_error(function_name, ex, "failed to stop ui"); - } - }; - - std::signal(SIGINT, quit_handler); -#if !defined(_WIN32) - std::signal(SIGQUIT, quit_handler); -#endif // !defined(_WIN32) - std::signal(SIGTERM, quit_handler); - - try { - server->start(); - } catch (const std::exception &ex) { - utils::error::raise_error(function_name, ex, "failed to start ui"); - } - - try { - server->stop(); - } catch (const std::exception &ex) { - utils::error::raise_error(function_name, ex, "failed to stop ui"); - } - - repertory::project_cleanup(); - }; - -#if defined(_WIN32) - ui::server server(&config); - run_ui(&server); -#else // !defined(_WIN32) - repertory::project_cleanup(); - - ret = utils::create_daemon([&]() -> int { - if (not repertory::project_initialize()) { - repertory::project_cleanup(); - return -1; - } - - if (not utils::file::change_to_process_directory()) { - return -1; - } - - ui::ui_server server(&config); - run_ui(&server); - return 0; - }); -#endif // defined(_WIN32) - } + ret = ui::ui_main(args); } else { auto prov = utils::cli::get_provider_type_from_args(args); diff --git a/repertory/repertory/src/ui/mgmt_app_config.cpp b/repertory/repertory/src/ui/mgmt_app_config.cpp index a1facdac..5a4f4f58 100644 --- a/repertory/repertory/src/ui/mgmt_app_config.cpp +++ b/repertory/repertory/src/ui/mgmt_app_config.cpp @@ -299,7 +299,7 @@ void mgmt_app_config::set_auto_start(bool auto_start) { function_name, utils::get_last_error_code(), "failed to create auto-start entry|name|repertory"); } - } else if (utils::remove_shortcut(REPERTORY_W)) { + } else if (utils::remove_shortcut(std::wstring{REPERTORY_W})) { utils::error::handle_info(function_name, "removed auto-start entry|name|repertory"); } else { diff --git a/repertory/repertory/src/ui/ui_main.cpp b/repertory/repertory/src/ui/ui_main.cpp new file mode 100644 index 00000000..f5dea6f8 --- /dev/null +++ b/repertory/repertory/src/ui/ui_main.cpp @@ -0,0 +1,259 @@ +/* + Copyright <2018-2025> + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +#include "ui/ui_main.hpp" + +#include "initialize.hpp" +#include "types/repertory.hpp" +#include "ui/mgmt_app_config.hpp" +#include "ui/ui_server.hpp" +#include "utils/cli_utils.hpp" +#include "utils/error_utils.hpp" + +namespace repertory::ui { +[[nodiscard]] auto ui_main(const std::vector &args) -> int { + mgmt_app_config config{ + utils::cli::has_option(args, utils::cli::options::hidden_option), + utils::cli::has_option(args, utils::cli::options::launch_only_option), + }; + + std::string data; + auto res = utils::cli::parse_string_option( + args, utils::cli::options::ui_port_option, data); + if (res == exit_code::success && not data.empty()) { + config.set_api_port(utils::string::to_uint16(data)); + } + + if (not utils::file::change_to_process_directory()) { + return static_cast(exit_code::ui_failed); + } + + const auto run_ui = [](auto *server) { + REPERTORY_USES_FUNCTION_NAME(); + + static std::atomic active_server{server}; + static const auto quit_handler = [](int /* sig */) { + REPERTORY_USES_FUNCTION_NAME(); + + auto *ptr = active_server.exchange(nullptr); + if (ptr == nullptr) { + return; + } + + try { + ptr->stop(); + } catch (const std::exception &ex) { + utils::error::raise_error(function_name, ex, "failed to stop ui"); + } + }; + + std::signal(SIGINT, quit_handler); +#if !defined(_WIN32) + std::signal(SIGQUIT, quit_handler); +#endif // !defined(_WIN32) + std::signal(SIGTERM, quit_handler); + + try { + server->start(); + } catch (const std::exception &ex) { + utils::error::raise_error(function_name, ex, "failed to start ui"); + } + + try { + server->stop(); + } catch (const std::exception &ex) { + utils::error::raise_error(function_name, ex, "failed to stop ui"); + } + + repertory::project_cleanup(); + }; + +#if defined(_WIN32) + server server(&config); + run_ui(&server); +#else // !defined(_WIN32) + repertory::project_cleanup(); + + return utils::create_daemon([&]() -> int { + if (not repertory::project_initialize()) { + repertory::project_cleanup(); + return -1; + } + + if (not utils::file::change_to_process_directory()) { + return -1; + } + + ui_server server(&config); + run_ui(&server); + return 0; + }); +#endif // defined(_WIN32) +} +} // namespace repertory + +using namespace repertory; + +auto main(int argc, char **argv) -> int { +#if defined(PROJECT_ENABLE_BACKWARD_CPP) + static backward::SignalHandling sh; +#endif // defined(PROJECT_ENABLE_BACKWARD_CPP) + + if (not repertory::project_initialize()) { + repertory::project_cleanup(); + return -1; + } + + std::vector args; + { + auto args_span = std::span(argv, static_cast(argc)); + std::ranges::copy(args_span, std::back_inserter(args)); + } + + int ret{0}; + + if (argc == 1) { +#if defined(__APPLE__) + args.push_back("-ui"); +#else // !defined(__APPLE__) + args.push_back("-h"); +#endif // defined(__APPLE__) + } + + if (utils::cli::has_option(args, utils::cli::options::help_option)) { + cli::actions::help(args); + } else if (utils::cli::has_option(args, + utils::cli::options::version_option)) { + cli::actions::version(args); + } else if (utils::cli::has_option(args, utils::cli::options::ui_option)) { + ret = ui_main(args); + } else { + auto prov = utils::cli::get_provider_type_from_args(args); + + std::string data_directory; + auto res = utils::cli::parse_string_option( + args, utils::cli::options::data_directory_option, data_directory); + + std::string password; + res = (res == exit_code::success) + ? utils::cli::parse_string_option( + args, utils::cli::options::password_option, password) + : res; + + std::string user; + res = (res == exit_code::success) + ? utils::cli::parse_string_option( + args, utils::cli::options::user_option, user) + : res; + + std::string remote_host; + std::uint16_t remote_port{}; + std::string unique_id; + if (res == exit_code::success) { + if (prov == provider_type::remote) { + std::string data; + res = utils::cli::parse_string_option( + args, utils::cli::options::remote_mount_option, data); + if (res == exit_code::success) { + const auto parts = utils::string::split(data, ':', false); + if (parts.size() != 2) { + std::cerr << "Invalid syntax for host/port '-rm " + "host:port,--remote_mount host:port'" + << std::endl; + res = exit_code::invalid_syntax; + } else { + unique_id = parts.at(0U) + ':' + parts.at(1U); + remote_host = parts.at(0U); + try { + remote_port = utils::string::to_uint16(parts.at(1U)); + data_directory = + data_directory.empty() + ? utils::path::combine( + app_config::default_data_directory(prov), + { + utils::string::replace_copy(unique_id, ':', + '_'), + }) + : utils::path::absolute(data_directory); + } catch (const std::exception &e) { + std::cerr << (e.what() == nullptr ? "Unable to parse port" + : e.what()) + << std::endl; + res = exit_code::invalid_syntax; + } + } + } + } else { + std::string data; + res = utils::cli::parse_string_option( + args, utils::cli::options::name_option, data); + if (res == exit_code::success) { + unique_id = utils::string::trim(data); + if (unique_id.empty()) { + std::cerr << "Configuration name for '" + << app_config::get_provider_display_name(prov) + << "' was not provided" << std::endl; + res = exit_code::invalid_syntax; + } + } + + if (res == exit_code::success) { + data_directory = + data_directory.empty() + ? utils::path::combine( + app_config::default_data_directory(prov), {unique_id}) + : utils::path::absolute(data_directory); + } + } + } + + int mount_result{}; + if (res == exit_code::success) { + res = exit_code::option_not_found; + for (std::size_t idx = 0U; + (res == exit_code::option_not_found) && + (idx < utils::cli::options::option_list.size()); + idx++) { + try { + res = cli::actions::perform_action( + utils::cli::options::option_list[idx], args, data_directory, prov, + unique_id, user, password); + } catch (const std::exception &ex) { + res = exit_code::exception; + } catch (...) { + res = exit_code::exception; + } + } + + if (res == exit_code::option_not_found) { + res = cli::actions::mount(args, data_directory, mount_result, prov, + remote_host, remote_port, unique_id); + } + } + + ret = ((res == exit_code::mount_result) ? mount_result + : static_cast(res)); + } + + repertory::project_cleanup(); + return ret; +} +} diff --git a/repertory/repertory/src/ui/ui_server.cpp b/repertory/repertory/src/ui/ui_server.cpp index 1ca6cf7f..bcf54dba 100644 --- a/repertory/repertory/src/ui/ui_server.cpp +++ b/repertory/repertory/src/ui/ui_server.cpp @@ -123,7 +123,8 @@ ui_server::ui_server(mgmt_app_config *config) "logs", })), #if defined(_WIN32) - repertory_binary_(utils::path::combine(".", {REPERTORY ".exe"})) + repertory_binary_( + utils::path::combine(".", {std::string{REPERTORY} + ".exe"})) #else // !defined(_WIN32) repertory_binary_(utils::path::combine(".", {REPERTORY})) #endif // defined(_WIN32)