[ui] Add auto-mount on first launch functionality #52
This commit is contained in:
		| @@ -43,6 +43,17 @@ enum class launchctl_type : std::uint8_t { | ||||
|   bootstrap, | ||||
|   kickstart, | ||||
| }; | ||||
|  | ||||
| struct plist_cfg final { | ||||
|   std::vector<std::string> args; | ||||
|   bool keep_alive{false}; | ||||
|   std::string label; | ||||
|   std::string plist_path; | ||||
|   bool run_at_load{false}; | ||||
|   std::string stderr_log{"/tmp/stderr.log"}; | ||||
|   std::string stdout_log{"/tmp/stdout.log"}; | ||||
|   std::string working_dir{"/tmp"}; | ||||
| }; | ||||
| #endif // defined(__APPLE__) | ||||
|  | ||||
| [[nodiscard]] auto create_daemon(std::function<int()> main_func) -> int; | ||||
| @@ -57,12 +68,9 @@ void windows_create_to_unix(const UINT32 &create_options, | ||||
|                             const UINT32 &granted_access, std::uint32_t &flags, | ||||
|                             remote::file_mode &mode); | ||||
| #if defined(__APPLE__) | ||||
| [[nodiscard]] auto generate_launchd_plist( | ||||
|     const std::string &label, std::string plist_path, | ||||
|     const std::vector<std::string> &args, bool run_at_load = false, | ||||
|     bool keep_alive = false, const std::string &working_dir = "/tmp", | ||||
|     const std::string &stdout_log = "/tmp/stdout.log", | ||||
|     const std::string &stderr_log = "/tmp/stderr.log") -> bool; | ||||
| [[nodiscard]] auto generate_launchd_plist(const plist_cfg &cfg, | ||||
|                                           bool overwrite_existing = true) | ||||
|     -> bool; | ||||
|  | ||||
| [[nodiscard]] auto launchctl_command(std::string_view label, | ||||
|                                      launchctl_type type) -> int; | ||||
|   | ||||
| @@ -448,13 +448,19 @@ auto fuse_base::mount([[maybe_unused]] std::vector<std::string> orig_args, | ||||
|     orig_args[0U] = utils::path::combine(".", {"repertory"}); | ||||
|     orig_args.insert(std::next(orig_args.begin()), "-f"); | ||||
|  | ||||
|     if (not utils::generate_launchd_plist( | ||||
|             label_, utils::path::combine("~", {"/Library/LaunchAgents"}), | ||||
|             orig_args, false, false, utils::path::absolute("."), | ||||
|             fmt::format("/tmp/repertory_{}_{}.out", | ||||
|                         provider_type_to_string(prov), unique_id), | ||||
|             fmt::format("/tmp/repertory_{}_{}.err", | ||||
|                         provider_type_to_string(prov), unique_id))) { | ||||
|     utils::plist_cfg cfg{}; | ||||
|     cfg.args = orig_args; | ||||
|     cfg.keep_alive = false; | ||||
|     cfg.label = label_; | ||||
|     cfg.plist_path = utils::path::combine("~", {"/Library/LaunchAgents"}); | ||||
|     cfg.run_at_load = false; | ||||
|     cfg.stderr_log = fmt::format("/tmp/repertory_{}_{}.err", | ||||
|                                  provider_type_to_string(prov), unique_id); | ||||
|     cfg.stdout_log = fmt::format("/tmp/repertory_{}_{}.out", | ||||
|                                  provider_type_to_string(prov), unique_id); | ||||
|     cfg.working_dir = utils::path::absolute("."); | ||||
|  | ||||
|     if (not utils::generate_launchd_plist(cfg, true)) { | ||||
|       std::cerr << fmt::format("FATAL: Failed to generate plist|{}", label_) | ||||
|                 << std::endl; | ||||
|       return -1; | ||||
|   | ||||
| @@ -308,12 +308,13 @@ auto create_daemon(std::function<int()> main_func) -> int { | ||||
| } | ||||
|  | ||||
| #if defined(__APPLE__) | ||||
| auto generate_launchd_plist(const std::string &label, std::string plist_path, | ||||
|                             const std::vector<std::string> &args, | ||||
|                             bool run_at_load, bool keep_alive, | ||||
|                             const std::string &working_dir, | ||||
|                             const std::string &stdout_log, | ||||
|                             const std::string &stderr_log) -> bool { | ||||
| auto generate_launchd_plist(const plist_cfg &cfg, bool overwrite_existing) | ||||
|     -> bool { | ||||
|   auto file = utils::path::combine(cfg.plist_path, {cfg.label + ".plist"}); | ||||
|   if (utils::file::file{file}.exists() && not overwrite_existing) { | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   pugi::xml_document doc; | ||||
|   auto decl = doc.append_child(pugi::node_declaration); | ||||
|   decl.append_attribute("version") = "1.0"; | ||||
| @@ -325,11 +326,11 @@ auto generate_launchd_plist(const std::string &label, std::string plist_path, | ||||
|   auto dict = plist.append_child("dict"); | ||||
|  | ||||
|   dict.append_child("key").text().set("Label"); | ||||
|   dict.append_child("string").text().set(label.c_str()); | ||||
|   dict.append_child("string").text().set(cfg.label.c_str()); | ||||
|  | ||||
|   dict.append_child("key").text().set("ProgramArguments"); | ||||
|   auto array = dict.append_child("array"); | ||||
|   for (const auto &arg : args) { | ||||
|   for (const auto &arg : cfg.args) { | ||||
|     array.append_child("string").text().set(arg.c_str()); | ||||
|   } | ||||
|  | ||||
| @@ -347,23 +348,22 @@ auto generate_launchd_plist(const std::string &label, std::string plist_path, | ||||
|   } | ||||
|  | ||||
|   dict.append_child("key").text().set("WorkingDirectory"); | ||||
|   dict.append_child("string").text().set(working_dir.c_str()); | ||||
|   dict.append_child("string").text().set(cfg.working_dir.c_str()); | ||||
|  | ||||
|   dict.append_child("key").text().set("KeepAlive"); | ||||
|   dict.append_child(keep_alive ? "true" : "false"); | ||||
|   dict.append_child(cfg.keep_alive ? "true" : "false"); | ||||
|  | ||||
|   dict.append_child("key").text().set("RunAtLoad"); | ||||
|   dict.append_child(run_at_load ? "true" : "false"); | ||||
|   dict.append_child(cfg.run_at_load ? "true" : "false"); | ||||
|  | ||||
|   dict.append_child("key").text().set("StandardOutPath"); | ||||
|   dict.append_child("string").text().set(stdout_log.c_str()); | ||||
|   dict.append_child("string").text().set(cfg.stdout_log.c_str()); | ||||
|  | ||||
|   dict.append_child("key").text().set("StandardErrorPath"); | ||||
|   dict.append_child("string").text().set(stderr_log.c_str()); | ||||
|   dict.append_child("string").text().set(cfg.stderr_log.c_str()); | ||||
|  | ||||
|   return doc.save_file( | ||||
|       utils::path::combine(plist_path, {label + ".plist"}).c_str(), "  ", | ||||
|       pugi::format_indent | pugi::format_write_bom); | ||||
|   return doc.save_file(file.c_str(), "  ", | ||||
|                        pugi::format_indent | pugi::format_write_bom); | ||||
| } | ||||
|  | ||||
| auto launchctl_command(std::string_view label, launchctl_type type) -> int { | ||||
|   | ||||
| @@ -224,60 +224,79 @@ void mgmt_app_config::set_auto_start(bool auto_start) { | ||||
|       opts.icon_path = utils::path::combine(".", {"repertory.png"}); | ||||
|       opts.terminal = true; | ||||
|  | ||||
|       if (not utils::create_autostart_entry(opts)) { | ||||
|       if (utils::create_autostart_entry(opts, false)) { | ||||
|         utils::error::handle_info(function_name, | ||||
|                                   "created auto-start entry|name|repertory"); | ||||
|       } else { | ||||
|         utils::error::raise_error( | ||||
|             function_name, utils::get_last_error_code(), | ||||
|             fmt::format("failed to create auto-start entry")); | ||||
|             "failed to create auto-start entry|name|repertory"); | ||||
|       } | ||||
|     } else if (not utils::remove_autostart_entry("repertory")) { | ||||
|     } else if (utils::remove_autostart_entry("repertory")) { | ||||
|       utils::error::handle_info(function_name, | ||||
|                                 "removed auto-start entry|name|repertory"); | ||||
|     } else { | ||||
|       utils::error::raise_error( | ||||
|           function_name, utils::get_last_error_code(), | ||||
|           fmt::format("failed to remove auto-start entry")); | ||||
|           "failed to remove auto-start entry|name|repertory"); | ||||
|     } | ||||
| #endif // defined(__linux__) | ||||
|  | ||||
| #if defined(_WIN32) | ||||
|     if (auto_start) { | ||||
|       if (not utils::create_shortcut( | ||||
|               utils::path::combine(L".", {L"repertory"}), {L"-ui", L"-lo"}, | ||||
|               utils::path::absolute(L"."), L"repertory")) { | ||||
|       if (utils::create_shortcut(utils::path::combine(L".", {L"repertory"}), | ||||
|                                  {L"-ui", L"-lo"}, utils::path::absolute(L"."), | ||||
|                                  L"repertory", false)) { | ||||
|         utils::error::handle_info(function_name, | ||||
|                                   "created auto-start entry|name|repertory"); | ||||
|       } else { | ||||
|         utils::error::raise_error( | ||||
|             function_name, utils::get_last_error_code(), | ||||
|             fmt::format("failed to create auto-start entry")); | ||||
|             "failed to create auto-start entry|name|repertory"); | ||||
|       } | ||||
|     } else if (not utils::remove_shortcut(L"repertory")) { | ||||
|     } else if (utils::remove_shortcut(L"repertory")) { | ||||
|       utils::error::handle_info(function_name, | ||||
|                                 "removed auto-start entry|name|repertory"); | ||||
|     } else { | ||||
|       utils::error::raise_error( | ||||
|           function_name, utils::get_last_error_code(), | ||||
|           fmt::format("failed to remove auto-start entry")); | ||||
|           "failed to remove auto-start entry|name|repertory"); | ||||
|     } | ||||
| #endif // defined(_WIN32) | ||||
|  | ||||
| #if defined(__APPLE__) | ||||
|     auto label = "com.fifthgrid.blockstorage.repertory.ui"; | ||||
|     auto plist_file = utils::file::file{ | ||||
|     auto plist_path = utils::file::file{ | ||||
|         utils::path::combine("~", {"/Library/LaunchAgents", label}), | ||||
|     }; | ||||
|     if (auto_start) { | ||||
|       if (not plist_file.exists()) { | ||||
|         std::vector<std::string> args = { | ||||
|             utils::path::combine(".", {"repertory"}), | ||||
|             "-ui", | ||||
|             "-lo", | ||||
|         }; | ||||
|  | ||||
|         if (not utils::generate_launchd_plist( | ||||
|                 label, utils::path::combine("~", {"/Library/LaunchAgents"}), | ||||
|                 args, true, false, utils::path::absolute("."), | ||||
|                 "/tmp/repertory_ui.out", "/tmp/repertory_ui.err")) { | ||||
|           utils::error::raise_error( | ||||
|               function_name, utils::get_last_error_code(), | ||||
|               fmt::format("failed to create auto-start entry")); | ||||
|         } | ||||
|       utils::plist_cfg cfg{}; | ||||
|       cfg.args = { | ||||
|           utils::path::combine(".", {"repertory"}), | ||||
|           "-ui", | ||||
|           "-lo", | ||||
|       }; | ||||
|       cfg.keep_alive = false; | ||||
|       cfg.label = "com.fifthgrid.blockstorage.repertory.ui"; | ||||
|       cfg.plist_path = plist_path; | ||||
|       cfg.run_at_load = true; | ||||
|       cfg.stderr_log = "/tmp/repertory_ui.err"; | ||||
|       cfg.stdout_log = "/tmp/repertory_ui.out"; | ||||
|       cfg.working_dir = utils::path::absolute("."); | ||||
|       if (utils::generate_launchd_plist(cfg, false)) { | ||||
|         utils::error::handle_info(function_name, | ||||
|                                   "created auto-start entry|name|repertory"); | ||||
|       } else { | ||||
|         utils::error::raise_error( | ||||
|             function_name, utils::get_last_error_code(), | ||||
|             "failed to create auto-start entry|name|repertory"); | ||||
|       } | ||||
|     } else if (not plist_file.remove()) { | ||||
|     } else if (plist_path.remove()) { | ||||
|       utils::error::handle_info(function_name, | ||||
|                                 "removed auto-start entry|name|repertory"); | ||||
|     } else { | ||||
|       utils::error::raise_error( | ||||
|           function_name, utils::get_last_error_code(), | ||||
|           fmt::format("failed to remove auto-start entry")); | ||||
|           "failed to remove auto-start entry|name|repertory"); | ||||
|     } | ||||
| #endif // defined(__APPLE__) | ||||
|   } else { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user