diff --git a/src/commands/install.cpp b/src/commands/install.cpp index 097341a..694d4ec 100644 --- a/src/commands/install.cpp +++ b/src/commands/install.cpp @@ -4,6 +4,7 @@ #include "utils/directories.hpp" #include "templates.hpp" #include "shared_commands.hpp" +#include "utils/hash.hpp" #include #include @@ -17,7 +18,7 @@ namespace dropshell int install_handler(const CommandContext &ctx); - static std::vector install_name_list = {"install"}; + static std::vector install_name_list = {"install","reinstall","update"}; // Static registration struct InstallCommandRegister @@ -33,7 +34,7 @@ namespace dropshell 1, // min_args (after command) 2, // max_args (after command) "install SERVER [SERVICE]", - "Install/reinstall/update service(s). Safe/non-destructive.", + "Install/reinstall service(s). Safe/non-destructive way to update.", // heredoc R"( Install components on a server. This is safe to re-run (non-destructive) and used to update @@ -138,8 +139,78 @@ namespace dropshell } + std::string get_arch() + { + // determine the architecture of the system + std::string arch; + #ifdef __aarch64__ + arch = "arm64"; + #elif __x86_64__ + arch = "amd64"; + #endif + return arch; + } + + int update_dropshell() + { + // determine path to this executable + std::filesystem::path dropshell_path = std::filesystem::canonical("/proc/self/exe"); + std::filesystem::path parent_path = dropshell_path.parent_path(); + + // determine the architecture of the system + std::string arch = get_arch(); + + std::string url = "https://gitea.jde.nz/public/dropshell/releases/download/latest/dropshell." + arch; + + // download new version, preserve permissions and ownership + std::string bash_script; + bash_script += "docker run --rm -v " + parent_path.string() + ":/target"; + bash_script += " gitea.jde.nz/public/debian-curl:latest"; + bash_script += " sh -c \""; + bash_script += " curl -fsSL " + url + " -o /target/dropshell_temp &&"; + bash_script += " chmod --reference=/target/dropshell /target/dropshell_temp &&"; + bash_script += " chown --reference=/target/dropshell /target/dropshell_temp"; + bash_script += "\""; + + std::string cmd = "bash -c '" + bash_script + "'"; + int rval = system(cmd.c_str()); + if (rval != 0) + { + std::cerr << "Failed to download new version of dropshell." << std::endl; + return -1; + } + + // check if the new version is the same as the old version + uint64_t new_hash = hash_file(parent_path / "dropshell_temp"); + uint64_t old_hash = hash_file(parent_path / "dropshell"); + if (new_hash == old_hash) + { + std::cout << "Confirmed dropshell is the latest version." << std::endl; + return 0; + } + + std::string bash_script_2 = "docker run --rm -v " + parent_path.string() + ":/target gitea.jde.nz/public/debian-curl:latest " + + "sh -c \"mv /target/dropshell_temp /target/dropshell\""; + rval = system(bash_script_2.c_str()); + if (rval != 0) + { + std::cerr << "Failed to install new version of dropshell." << std::endl; + return -1; + } + + std::cout << "Successfully updated " << dropshell_path << " to the latest " << arch << " version." << std::endl; + + // execute the new version + execlp("bash", "bash", "-c", (parent_path / "dropshell").c_str(), "install", (char *)nullptr); + std::cerr << "Failed to execute new version of dropshell." << std::endl; + return -1; + } + + + int install_host() { + // update dropshell. // install the local dropshell agent. } diff --git a/src/commands/uninstall.cpp b/src/commands/uninstall.cpp index a1f57f3..c993897 100644 --- a/src/commands/uninstall.cpp +++ b/src/commands/uninstall.cpp @@ -19,18 +19,19 @@ namespace dropshell { CommandRegistry::instance().register_command({uninstall_name_list, uninstall_handler, - std_autocomplete, + std_autocomplete_allowallservices, false, // hidden - false, // requires_config + true, // requires_config + true, // requires_install 1, // min_args (after command) 2, // max_args (after command) "uninstall SERVER [SERVICE]", "Uninstall a service on a server. Does not remove configuration or user data.", // heredoc R"( - Uninstall a service on a server. Does not remove configuration or user data. - uninstall uninstall the given service on the given server. - uninstall uninstall all services on the given server. + Uninstall a service on a server. Does not remove configuration or user data. + uninstall SERVER [SERVICE|*] uninstall the given service (or all services) on the given server; + preserves configuration and user data. )"}); } } uninstall_command_register; diff --git a/src/commands/version.cpp b/src/commands/version.cpp new file mode 100644 index 0000000..cd6b4cb --- /dev/null +++ b/src/commands/version.cpp @@ -0,0 +1,45 @@ +#include "command_registry.hpp" +#include "version.hpp" +namespace dropshell { + + int version_handler(const CommandContext &ctx); + + static std::vector version_name_list = {"version","v","ver","-v","-ver","--version"}; + + void version_autocomplete(const CommandContext &ctx) + { + } + + // Static registration + struct UninstallCommandRegister + { + UninstallCommandRegister() + { + CommandRegistry::instance().register_command({version_name_list, + version_handler, + version_autocomplete, + false, // hidden + false, // requires_config + false, // requires_install + 0, // min_args (after command) + 0, // max_args (after command) + "version", + "Uninstall a service on a server. Does not remove configuration or user data.", + // heredoc + R"( + Uninstall a service on a server. Does not remove configuration or user data. + uninstall uninstall the given service on the given server. + uninstall uninstall all services on the given server. + )"}); + } + } uninstall_command_register; + + + int version_handler(const CommandContext &ctx) + { + std::cout << VERSION << std::endl; + return 0; + } + + +} // namespace dropshell \ No newline at end of file