diff --git a/source/src/commands/backupdata.cpp b/source/src/commands/backupdata.cpp index 9b0837c..67fbbf9 100644 --- a/source/src/commands/backupdata.cpp +++ b/source/src/commands/backupdata.cpp @@ -84,7 +84,7 @@ namespace dropshell remote_command_script_file, remotefile(server, user).service_env(service)}, user)) { - error << "Error: Required service directories not found on remote server" << std::endl; + error << "Required service directories not found on remote server" << std::endl; info << "Is the service installed?" << std::endl; return false; } @@ -103,7 +103,7 @@ namespace dropshell std::string local_backups_dir = localpath::backups(); if (local_backups_dir.empty()) { - error << "Error: Local backups directory not found" << std::endl; + error << "Local backups directory not found" << std::endl; info << "Run 'dropshell edit' to configure DropShell" << std::endl; return false; } diff --git a/source/src/commands/edit.cpp b/source/src/commands/edit.cpp index 38a900a..41eb7b6 100644 --- a/source/src/commands/edit.cpp +++ b/source/src/commands/edit.cpp @@ -94,11 +94,11 @@ int edit_config() std::string config_file = localfile::dropshell_json(); if (!edit_file(config_file, false) || !std::filesystem::exists(config_file)) - return die("Error: Failed to edit config file."); + return die("Failed to edit config file."); gConfig().load_config(); if (!gConfig().is_config_set()) - return die("Error: Failed to load and parse edited config file!"); + return die("Failed to load and parse edited config file!"); gConfig().save_config(true); @@ -112,7 +112,7 @@ int edit_config() int edit_server(const std::string &server_name) { if (localpath::server(server_name).empty()) { - std::cerr << "Error: Server not found: " << server_name << std::endl; + error << "Server not found: " << server_name << std::endl; return -1; } diff --git a/source/src/commands/install.cpp b/source/src/commands/install.cpp index d6b48a5..06e4a84 100644 --- a/source/src/commands/install.cpp +++ b/source/src/commands/install.cpp @@ -334,7 +334,7 @@ complete -F _dropshell_completions ds info << "Installing agent for user " << user.user << " on " << server.get_server_name() << std::endl; std::string agent_path = remotepath(server.get_server_name(),user.user).agent(); - ASSERT(agent_path == user.dir+"/agent", "Agent path does not match user directory for "+user.user+"@" + server.get_server_name() + " : " + agent_path + " != " + user.dir); + ASSERT(agent_path == user.dir+"/agent", "Remote agent path does not match user directory for "+user.user+"@" + server.get_server_name() + " : " + agent_path + " != " + user.dir); ASSERT(!agent_path.empty(), "Agent path is empty for " + user.user + "@" + server.get_server_name()); // now create the agent. @@ -348,7 +348,7 @@ complete -F _dropshell_completions ds bool okay = execute_ssh_command(server.get_SSH_INFO(user.user), sCommand(agent_path, "agent-install.sh",{}), cMode::Defaults | cMode::NoBB64, nullptr); if (!okay) { - error << "ERROR: Failed to install remote agent on " << server.get_server_name() << std::endl; + error << "Failed to install remote agent on " << server.get_server_name() << std::endl; return 1; } diff --git a/source/src/commands/list.cpp b/source/src/commands/list.cpp index 0ecbc11..3ab1839 100644 --- a/source/src/commands/list.cpp +++ b/source/src/commands/list.cpp @@ -147,7 +147,7 @@ void list_servers() { void show_server_details(const std::string& server_name) { ServerConfig env(server_name); if (!env.is_valid()) { - error << "Error: Invalid server environment file: " << server_name << std::endl; + error << "Invalid server environment file: " << server_name << std::endl; return; } diff --git a/source/src/commands/restoredata.cpp b/source/src/commands/restoredata.cpp index ab76b15..1cb5636 100644 --- a/source/src/commands/restoredata.cpp +++ b/source/src/commands/restoredata.cpp @@ -60,7 +60,7 @@ namespace dropshell std::string local_backups_dir = localpath::backups(); if (local_backups_dir.empty() || !std::filesystem::exists(local_backups_dir)) { - error << "Error: Local backups directory not found: " << local_backups_dir << std::endl; + error << "Local backups directory not found: " << local_backups_dir << std::endl; return {}; } @@ -150,19 +150,19 @@ namespace dropshell std::string local_backups_dir = localpath::backups(); if (local_backups_dir.empty() || !std::filesystem::exists(local_backups_dir)) { - error << "Error: Local backups directory not found: " << local_backups_dir << std::endl; + error << "Local backups directory not found: " << local_backups_dir << std::endl; return 1; } std::string local_backup_file_path = (std::filesystem::path(local_backups_dir) / backup_details->get_filename()).string(); if (!std::filesystem::exists(local_backup_file_path)) { - error << "Error: Backup file not found at " << local_backup_file_path << std::endl; + error << "Backup file not found at " << local_backup_file_path << std::endl; return 1; } if (backup_details->get_template_name() != service_info.template_name) { - error << "Error: Backup template does not match service template. Can't restore." << std::endl; + error << "Backup template does not match service template. Can't restore." << std::endl; info << "Backup template: " << backup_details->get_template_name() << std::endl; info << "Service template: " << service_info.template_name << std::endl; return 1; diff --git a/source/src/commands/start.cpp b/source/src/commands/start.cpp index 2bc41bc..8720422 100644 --- a/source/src/commands/start.cpp +++ b/source/src/commands/start.cpp @@ -67,7 +67,7 @@ namespace dropshell { if (ctx.args.size() < 2) { - std::cerr << "Error: Server name and service name are both required" << std::endl; + error << "Server name and service name are both required" << std::endl; return 1; } diff --git a/source/src/config.cpp b/source/src/config.cpp index 16e412f..1019e05 100644 --- a/source/src/config.cpp +++ b/source/src/config.cpp @@ -37,7 +37,7 @@ bool config::load_config() { // load json config file. } catch (nlohmann::json::parse_error& ex) { - std::cerr << "Error: Failed to parse config file: " << ex.what() << std::endl; + error << "Failed to parse config file: " << ex.what() << std::endl; return false; } @@ -69,7 +69,7 @@ bool config::save_config(bool create_aux_directories) if (!mIsConfigSet) { std::string homedir = localpath::current_user_home(); - std::string dropshell_base = homedir + "/.local/dropshell_files"; + std::string dropshell_base = homedir + "/.dropshell"; mConfig["server_definition_paths"] = { dropshell_base + "/servers" @@ -81,6 +81,10 @@ bool config::save_config(bool create_aux_directories) "https://templates.dropshell.app" }; mConfig["template_upload_token"] = "SECRETTOKEN"; + + mConfig["backups_path"] = { + dropshell_base + "/backups" + }; } config_file << mConfig.dump(4); @@ -175,4 +179,10 @@ std::string config::get_template_upload_token() { return mConfig["template_upload_token"]; } +std::string config::get_backups_path() +{ + return mConfig["backups_path"]; +} + + } // namespace dropshell \ No newline at end of file diff --git a/source/src/config.hpp b/source/src/config.hpp index 090d706..dd2cfd0 100644 --- a/source/src/config.hpp +++ b/source/src/config.hpp @@ -28,6 +28,8 @@ class config { std::string get_template_upload_url(); std::string get_template_upload_token(); + std::string get_backups_path(); + private: nlohmann::json mConfig; bool mIsConfigSet; diff --git a/source/src/main.cpp b/source/src/main.cpp index 0d987fb..15bbc88 100644 --- a/source/src/main.cpp +++ b/source/src/main.cpp @@ -80,7 +80,7 @@ int main(int argc, char* argv[]) { } catch (const std::exception& e) { - std::cerr << "Error: " << e.what() << std::endl; + error << "Uncaught Exception: " << e.what() << std::endl; return 1; } } diff --git a/source/src/servers.cpp b/source/src/servers.cpp index 82c2b48..430fb66 100644 --- a/source/src/servers.cpp +++ b/source/src/servers.cpp @@ -104,7 +104,7 @@ namespace dropshell catch (const std::exception &e) { error << "Failed to parse " << server_json_path << std::endl; - error << "Error: " << e.what() << std::endl; + error << "Exception: " << e.what() << std::endl; mValid = false; } @@ -241,7 +241,7 @@ namespace dropshell bool okay = execute_ssh_command(sshinfo, scommand, cMode::Silent); if (!okay) { - std::cerr << "Error: Required items not found on remote server: " << file_names_str << std::endl; + error << "Required items not found on remote server: " << file_names_str << std::endl; return false; } return true; @@ -341,7 +341,7 @@ namespace dropshell std::map env_vars; if (!get_all_service_env_vars(mServerName, service_name, env_vars)) { - std::cerr << "Error: Failed to get all service env vars for " << service_name << std::endl; + error << "Failed to get all service env vars for " << service_name << std::endl; return std::nullopt; } @@ -358,7 +358,7 @@ namespace dropshell if (sc.empty()) { - std::cerr << "Error: Failed to construct command for " << service_name << " " << command << std::endl; + error << "Failed to construct command for " << service_name << " " << command << std::endl; return std::nullopt; } return sc; @@ -388,7 +388,7 @@ namespace dropshell ServerConfig env(server_name); if (!env.is_valid()) { - std::cerr << "Error: Invalid server environment file: " << entry.path().string() << std::endl; + error << "Invalid server environment file: " << entry.path().string() << std::endl; continue; } servers.push_back(env); @@ -406,7 +406,7 @@ namespace dropshell std::string server_existing_dir = localpath::server(server_name); if (!server_existing_dir.empty()) { - error << "Error: Server name already exists: " << server_name << std::endl; + error << "Server name already exists: " << server_name << std::endl; info << "Current server path: " << server_existing_dir << std::endl; return false; } @@ -415,7 +415,7 @@ namespace dropshell auto lsdp = gConfig().get_local_server_definition_paths(); if (lsdp.empty() || lsdp[0].empty()) { - error << "Error: Local server definition path not found" << std::endl; + error << "Local server definition path not found" << std::endl; info << "Run 'dropshell edit' to configure DropShell" << std::endl; return false; } @@ -434,7 +434,9 @@ namespace dropshell server_env_file << " \"USER\": \"" << user << "\"," << std::endl; server_env_file << " \"DIR\": \"" << "/home/" + user << "/.dropshell\"" << std::endl; server_env_file << " }" << std::endl; - server_env_file << " ]" << std::endl; + server_env_file << " ]," << std::endl; + server_env_file << " \"HAS_DOCKER\": \"true\"," << std::endl; + server_env_file << " \"DOCKER_ROOTLESS\": \"false\"" << std::endl; server_env_file << "}" << std::endl; server_env_file.close(); diff --git a/source/src/services.cpp b/source/src/services.cpp index 0258851..9aa5cd8 100644 --- a/source/src/services.cpp +++ b/source/src/services.cpp @@ -34,8 +34,8 @@ namespace dropshell std::vector local_server_definition_paths = gConfig().get_local_server_definition_paths(); if (local_server_definition_paths.empty()) { - std::cerr << "Error: No local server definition paths found" << std::endl; - std::cerr << "Run 'dropshell edit' to configure DropShell" << std::endl; + error << "No local server definition paths found" << std::endl; + info << "Run 'dropshell edit' to configure DropShell" << std::endl; return services; } @@ -158,7 +158,7 @@ namespace dropshell auto service_info = get_service_info(server_name, service_name); if (service_info.local_template_path.empty()) { - std::cerr << "Error: Service not found: " << service_name << std::endl; + error << "Service not found: " << service_name << std::endl; return commands; } @@ -183,7 +183,7 @@ namespace dropshell auto service_info = get_service_info(server_name, service_name); if (service_info.local_template_path.empty()) { - std::cerr << "Error: Service not found: " << service_name << std::endl; + error << "Service not found: " << service_name << std::endl; return backups; } @@ -211,7 +211,7 @@ namespace dropshell if (localpath::service(server_name, service_name).empty() || !fs::exists(localpath::service(server_name, service_name))) { - std::cerr << "Error: Service not found: " << service_name << " on server " << server_name << std::endl; + error << "Service not found: " << service_name << " on server " << server_name << std::endl; return false; } @@ -265,7 +265,7 @@ namespace dropshell template_info tinfo = gTemplateManager().get_template_info(it->second); if (!tinfo.is_set()) { - std::cerr << "Error: Template '" << it->second << "' not found" << std::endl; + error << "Template '" << it->second << "' not found" << std::endl; return false; } diff --git a/source/src/templates.cpp b/source/src/templates.cpp index f453734..5c803db 100644 --- a/source/src/templates.cpp +++ b/source/src/templates.cpp @@ -163,7 +163,7 @@ ASSERT(mLoaded && mSources.size() > 0, "Template manager not loaded, or no template sources found."); template_source_interface* source = get_source(template_name); if (!source) { - std::cerr << "Error: Template '" << template_name << "' not found" << std::endl; + error << "Template '" << template_name << "' not found" << std::endl; return false; } return source->template_command_exists(template_name, command); @@ -175,21 +175,21 @@ std::vector local_server_definition_paths = gConfig().get_local_server_definition_paths(); if (local_server_definition_paths.empty()) { - std::cerr << "Error: No local server definition paths found" << std::endl; - std::cerr << "Run 'dropshell edit' to configure DropShell" << std::endl; + error << "No local server definition paths found" << std::endl; + info << "Run 'dropshell edit' to configure DropShell" << std::endl; return false; } - auto info = get_template_info(template_name); - if (info.is_set()) { - std::cerr << "Error: Template '" << template_name << "' already exists at " << info.locationID() << std::endl; + auto tinfo = get_template_info(template_name); + if (tinfo.is_set()) { + error << "Template '" << template_name << "' already exists at " << tinfo.locationID() << std::endl; return false; } auto local_template_paths = gConfig().get_local_template_paths(); if (local_template_paths.empty()) { - std::cerr << "Error: No local template paths found" << std::endl; - std::cerr << "Run 'dropshell edit' to add one to the DropShell config" << std::endl; + error << "No local template paths found" << std::endl; + info << "Run 'dropshell edit' to add one to the DropShell config" << std::endl; return false; } std::string new_template_path = local_template_paths[0] + "/" + template_name; @@ -200,7 +200,7 @@ // 2. Copy the example template from the system templates directory auto example_info = gTemplateManager().get_template_info("example-nginx"); if (!example_info.is_set()) { - std::cerr << "Error: Example template not found" << std::endl; + error << "Example template not found" << std::endl; return false; } std::string example_template_path = example_info.local_template_path(); @@ -222,7 +222,7 @@ std::string replacement_line = "TEMPLATE=" + template_name; std::string service_env_path = new_template_path + "/config/" + filenames::template_info_env; if (!replace_line_in_file(service_env_path, search_string, replacement_line)) { - std::cerr << "Error: Failed to replace TEMPLATE= line in the " << filenames::template_info_env <<" file" << std::endl; + error << "Failed to replace TEMPLATE= line in the " << filenames::template_info_env <<" file" << std::endl; return false; } @@ -278,7 +278,7 @@ bool template_manager::required_file(std::string path, std::string template_name) { if (!std::filesystem::exists(path)) { - std::cerr << "Error: " << path << " file not found in template - REQUIRED." << template_name << std::endl; + error << path << " file not found in template - REQUIRED." << template_name << std::endl; return false; } return true; @@ -323,7 +323,7 @@ std::filesystem::path path = template_path + "/" + file; auto perms = std::filesystem::status(path).permissions(); if ((perms & std::filesystem::perms::owner_exec) == std::filesystem::perms::none) - std::cerr << "Error: " << file << " is not executable" << std::endl; + error << file << " is not executable" << std::endl; } } @@ -347,18 +347,18 @@ // determine template name. auto it = all_env_vars.find("TEMPLATE"); if (it == all_env_vars.end()) { - std::cerr << "Error: TEMPLATE variable not found in " << template_path << std::endl; + error << "TEMPLATE variable not found in " << template_path << std::endl; return false; } std::string env_template_name = it->second; if (env_template_name.empty()) { - std::cerr << "Error: TEMPLATE variable is empty in " << template_path << std::endl; + error << "TEMPLATE variable is empty in " << template_path << std::endl; return false; } if (env_template_name != template_name) { - std::cerr << "Error: TEMPLATE variable is wrong in " << template_path << std::endl; + error << "TEMPLATE variable is wrong in " << template_path << std::endl; return false; } diff --git a/source/src/utils/directories.cpp b/source/src/utils/directories.cpp index 441ad67..65c64c4 100644 --- a/source/src/utils/directories.cpp +++ b/source/src/utils/directories.cpp @@ -7,86 +7,85 @@ #include #include - namespace fs = std::filesystem; -namespace dropshell { +namespace dropshell +{ + namespace localfile + { -namespace localfile { - - std::string dropshell_json() { - // Try ~/.config/dropshell/dropshell.json - std::string homedir = localpath::current_user_home(); - if (!homedir.empty()) { - fs::path user_path = fs::path(homedir) / ".config" / "dropshell" / filenames::dropshell_json; - return user_path.string(); + std::string dropshell_json() + { + return localpath::dropshell_dir() + "/" + filenames::dropshell_json; } - return std::string(); - } - std::string server_json(const std::string &server_name) { - std::string serverpath = localpath::server(server_name); - return (serverpath.empty() ? "" : (fs::path(serverpath) / filenames::server_json).string()); - } + std::string server_json(const std::string &server_name) + { + std::string serverpath = localpath::server(server_name); + return (serverpath.empty() ? "" : (fs::path(serverpath) / filenames::server_json).string()); + } - std::string service_env(const std::string &server_name, const std::string &service_name) { - std::string servicepath = localpath::service(server_name, service_name); - return (servicepath.empty() ? "" : (fs::path(servicepath) / filenames::service_env).string()); - } + std::string service_env(const std::string &server_name, const std::string &service_name) + { + std::string servicepath = localpath::service(server_name, service_name); + return (servicepath.empty() ? "" : (fs::path(servicepath) / filenames::service_env).string()); + } - std::string template_info_env(const std::string &server_name, const std::string &service_name) + std::string template_info_env(const std::string &server_name, const std::string &service_name) + { + std::string servicepath = localpath::service(server_name, service_name); + return (servicepath.empty() ? "" : (fs::path(servicepath) / filenames::template_info_env).string()); + } + + std::string template_example() + { + return localpath::agent_local() + "/template_example"; + } + + std::string bb64() + { + return localpath::agent_local() + "/bb64"; + } + + } // namespace localfile + + // ------------------------------------------------------------------------------------------ + + namespace localpath { - std::string servicepath = localpath::service(server_name, service_name); - return (servicepath.empty() ? "" : (fs::path(servicepath) / filenames::template_info_env).string()); - } - std::string template_example() - { - return localpath::agent_local() + "/template_example"; - } + std::string dropshell_dir() + { + return current_user_home() + "/.dropshell"; + } - std::string bb64() - { - return localpath::agent_local() + "/bb64"; - } - -} // namespace localfile - - -// ------------------------------------------------------------------------------------------ - -namespace localpath { - std::string server(const std::string &server_name) { - for (std::filesystem::path dir : gConfig().get_local_server_definition_paths()) + std::string server(const std::string &server_name) + { + for (std::filesystem::path dir : gConfig().get_local_server_definition_paths()) if (fs::exists(dir / server_name)) return dir / server_name; return ""; } - std::string service(const std::string &server_name, const std::string &service_name) { + std::string service(const std::string &server_name, const std::string &service_name) + { std::string serverpath = localpath::server(server_name); - return ((serverpath.empty() || service_name.empty()) ? "" : (serverpath+"/"+service_name)); + return ((serverpath.empty() || service_name.empty()) ? "" : (serverpath + "/" + service_name)); } - std::string remote_versions(const std::string &server_name, const std::string &service_name) - { - std::string template_cache_path = localpath::template_cache(); - return ((template_cache_path.empty() || service_name.empty()) ? "" : - (template_cache_path+"/remote_versions/"+service_name+".json")); - } std::string agent_local() { - return current_user_home()+"/.local/dropshell_agent/agent-local"; + return dropshell_dir() + "/agent-local"; } std::string agent_remote() { - return current_user_home() + "/.local/dropshell_agent/agent-remote"; + return dropshell_dir() + "/agent-remote"; } std::string current_user_home() { - char * homedir = std::getenv("HOME"); + char *homedir = std::getenv("HOME"); if (homedir) { std::filesystem::path homedir_path(homedir); @@ -96,37 +95,32 @@ namespace localpath { return std::string(); } - std::string dropshell_files() - { - return current_user_home() + "/.local/dropshell_files"; - return std::string(); - } - std::string backups() { - return dropshell_files() + "/backups"; + if (!gConfig().is_config_set()) + return ""; + return gConfig().get_backups_path(); } std::string temp_files() { - return dropshell_files() + "/temp_files"; + return dropshell_dir() + "/temp_files"; } std::string template_cache() { - return dropshell_files() + "template_cache"; + return dropshell_dir() + "/template_cache"; } bool create_directories() { std::vector paths = { - dropshell_files(), + dropshell_dir(), agent_local(), agent_remote(), template_cache(), backups(), - temp_files() - }; + temp_files()}; for (auto &p : gConfig().get_local_server_definition_paths()) paths.push_back(p); @@ -139,7 +133,7 @@ namespace localpath { return false; } -} // namespace localpath + } // namespace localpath //------------------------------------------------------------------------------------------------ // remote paths @@ -159,21 +153,26 @@ namespace localpath { // |-- service.env (default service config) // |-- (other config files for specific server&service) - - remotefile::remotefile(const std::string &server_name, const std::string &user) : - mServer_name(server_name), mUser(user) {} + remotefile::remotefile(const std::string &server_name, const std::string &user) : mServer_name(server_name), mUser(user) {} std::string remotefile::service_env(const std::string &service_name) const { - return remotepath(mServer_name,mUser).service_config(service_name) + "/" + filenames::service_env; + return remotepath(mServer_name, mUser).service_config(service_name) + "/" + filenames::service_env; } - remotepath::remotepath(const std::string &server_name, const std::string &user) : mServer_name(server_name), mUser(user) {} std::string remotepath::DROPSHELL_DIR() const - { - return ServerConfig(mServer_name).get_user_dir(mUser); + { + try + { + return ServerConfig(mServer_name).get_user_dir(mUser); + } catch (const std::exception &e) + { + error << "Failed to get remote dropshell directory for " << mServer_name << "@" << mUser << std::endl; + error << "Exception: " << e.what() << std::endl; + return ""; + } } std::string remotepath::services() const @@ -218,22 +217,21 @@ namespace localpath { return (dsp.empty() ? "" : (dsp + "/agent")); } + // ------------------------------------------------------------------------------------------ + // Utility functions -// ------------------------------------------------------------------------------------------ -// Utility functions + std::string get_parent(const std::filesystem::path path) + { + if (path.empty()) + return std::string(); + return path.parent_path().string(); + } -std::string get_parent(const std::filesystem::path path) -{ - if (path.empty()) - return std::string(); - return path.parent_path().string(); -} - -std::string get_child(const std::filesystem::path path) -{ - if (path.empty()) - return std::string(); - return path.filename().string(); -} + std::string get_child(const std::filesystem::path path) + { + if (path.empty()) + return std::string(); + return path.filename().string(); + } } // namespace dropshell diff --git a/source/src/utils/directories.hpp b/source/src/utils/directories.hpp index 4a07648..49a4889 100644 --- a/source/src/utils/directories.hpp +++ b/source/src/utils/directories.hpp @@ -10,20 +10,15 @@ namespace dropshell { //------------------------------------------------------------------------------------------------ // local user config directories - - // ~/.config/dropshell/dropshell.json - - // ~/.local/dropshell_agent + + // ~/.dropshell + // |-- dropshell.json // |-- agent-local // |-- agent-install.sh // |-- bb64 (only used locally, as it's for the local machine's architecture!) // |-- template_example // |-- agent-remote // |-- (remote agent files, including _allservicesstatus.sh) - - // ~/.local/dropshell_files - // |-- backups - // |-- katie-_-squashkiwi-_-squashkiwi-test-_-2025-04-28_21-23-59.tgz // |-- temp_files // |-- template_cache // |-- templates @@ -35,6 +30,10 @@ namespace dropshell { // | |-- .template_info.env // | |-- (...other service config files...) + // backups_path + // |-- katie-_-squashkiwi-_-squashkiwi-test-_-2025-04-28_21-23-59.tgz + + // server_definition_path // |-- // |-- server.json @@ -53,7 +52,6 @@ namespace dropshell { } // namespace filenames. namespace localfile { - // ~/.config/dropshell/dropshell.json std::string dropshell_json(); std::string server_json(const std::string &server_name); std::string service_env(const std::string &server_name, const std::string &service_name); @@ -63,16 +61,15 @@ namespace dropshell { } // namespace localfile namespace localpath { + std::string dropshell_dir(); + std::string server(const std::string &server_name); std::string service(const std::string &server_name, const std::string &service_name); - std::string remote_versions(const std::string &server_name, const std::string &service_name); - std::string agent_local(); std::string agent_remote(); std::string current_user_home(); - std::string dropshell_files(); std::string backups(); std::string temp_files(); std::string template_cache(); diff --git a/source/src/utils/execute.cpp b/source/src/utils/execute.cpp index 39b854f..2843cf3 100644 --- a/source/src/utils/execute.cpp +++ b/source/src/utils/execute.cpp @@ -183,7 +183,7 @@ namespace dropshell if (!rval && !hasFlag(mode, cMode::Silent)) { - error << "Error: Failed to execute ssh command:" << std::endl; + error << "Failed to execute ssh command:" << std::endl; debug << ssh_cmd.str() + " " + remote_command.construct_cmd(remote_bb64_path) << std::endl; } return rval; diff --git a/source/src/utils/hash.cpp b/source/src/utils/hash.cpp index b4625c5..eabb17d 100644 --- a/source/src/utils/hash.cpp +++ b/source/src/utils/hash.cpp @@ -3,6 +3,8 @@ #define XXH_INLINE_ALL #include "contrib/xxhash.hpp" +#include "output.hpp" + #include #include #include @@ -13,7 +15,7 @@ uint64_t hash_file(const std::string &path) { // Create hash state XXH64_state_t* const state = XXH64_createState(); if (state == nullptr) { - std::cerr << "Failed to create hash state" << std::endl; + error << "Failed to create hash state" << std::endl; return 0; } @@ -24,7 +26,7 @@ uint64_t hash_file(const std::string &path) { // Open file std::ifstream file(path, std::ios::binary); if (!file.is_open()) { - std::cerr << "Failed to open file: " << path << std::endl; + error << "Failed to open file: " << path << std::endl; XXH64_freeState(state); return 0; } @@ -34,7 +36,7 @@ uint64_t hash_file(const std::string &path) { char buffer[buffer_size]; while (file.read(buffer, buffer_size)) { if (XXH64_update(state, buffer, file.gcount()) == XXH_ERROR) { - std::cerr << "Failed to update hash" << std::endl; + error << "Failed to update hash" << std::endl; XXH64_freeState(state); return 0; } @@ -43,7 +45,7 @@ uint64_t hash_file(const std::string &path) { // Handle any remaining bytes if (file.gcount() > 0) { if (XXH64_update(state, buffer, file.gcount()) == XXH_ERROR) { - std::cerr << "Failed to update hash" << std::endl; + error << "Failed to update hash" << std::endl; XXH64_freeState(state); return 0; } @@ -59,14 +61,14 @@ uint64_t hash_directory_recursive(const std::string &path) { // Create hash state XXH64_state_t* const state = XXH64_createState(); if (state == nullptr) { - std::cerr << "Failed to create hash state" << std::endl; + error << "Failed to create hash state" << std::endl; return 0; } // Initialize state with seed 0 XXH64_hash_t const seed = 0; /* or any other value */ if (XXH64_reset(state, seed) == XXH_ERROR) { - std::cerr << "Failed to reset hash state" << std::endl; + error << "Failed to reset hash state" << std::endl; XXH64_freeState(state); return 0; } @@ -81,7 +83,7 @@ uint64_t hash_directory_recursive(const std::string &path) { } } } catch (const std::filesystem::filesystem_error& e) { - std::cerr << "Filesystem error: " << e.what() << std::endl; + error << "Filesystem error: " << e.what() << std::endl; XXH64_freeState(state); return 0; } @@ -94,7 +96,7 @@ uint64_t hash_directory_recursive(const std::string &path) { uint64_t hash_path(const std::string &path) { if (!std::filesystem::exists(path)) { - std::cerr << "Path does not exist: " << path << std::endl; + error << "Path does not exist: " << path << std::endl; return 0; } @@ -103,28 +105,28 @@ uint64_t hash_path(const std::string &path) { } else if (std::filesystem::is_regular_file(path)) { return hash_file(path); } else { - std::cerr << "Path is neither a file nor a directory: " << path << std::endl; + error << "Path is neither a file nor a directory: " << path << std::endl; return 0; } } void hash_demo(const std::string & path) { - std::cout << "Hashing path: " << path << std::endl; + info << "Hashing path: " << path << std::endl; auto start = std::chrono::high_resolution_clock::now(); XXH64_hash_t hash = hash_path(path); auto end = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast(end - start); - std::cout << "Hash: " << hash << " (took " << duration.count() << "ms)" << std::endl; + info << "Hash: " << hash << " (took " << duration.count() << "ms)" << std::endl; } int hash_demo_raw(const std::string & path) { if (!std::filesystem::exists(path)) { - std::cout << 0 < segment_lines = split(segment, "\n"); + // remove empty lines + segment_lines.erase(std::remove_if(segment_lines.begin(), segment_lines.end(), [](const std::string& line) { + return trim(line).empty(); + }), segment_lines.end()); + // remove any lines that are just whitespace + segment_lines.erase(std::remove_if(segment_lines.begin(), segment_lines.end(), [](const std::string& line) { return trim(line).empty(); }), segment_lines.end()); + + // check that the segment has at least two lines + if (segment_lines.size() < 2) { + error << "Segment must contain at least two non-empty lines" << std::endl; + return false; } - std::string last_line = segment.substr(last_line_pos + 1); // Read the entire file into memory std::ifstream input_file(filepath); if (!input_file.is_open()) { - std::cerr << "Error: Unable to open file: " << filepath << std::endl; + error << "Unable to open file: " << filepath << std::endl; return false; } @@ -580,22 +598,21 @@ bool file_replace_or_add_segment(std::string filepath, std::string segment) } input_file.close(); + // Store original file size for verification + size_t original_size = file_lines.size(); + if (original_size == 0) { + warning << "File is empty" << std::endl; + } + // Try to find the matching block bool found_match = false; for (size_t i = 0; i < file_lines.size(); i++) { - if (match_line(file_lines[i], first_line)) { + if (match_line(file_lines[i], segment_lines[0])) { // Found potential start, look for end for (size_t j = i + 1; j < file_lines.size(); j++) { - if (match_line(file_lines[j], last_line)) { + if (match_line(file_lines[j], segment_lines[segment_lines.size() - 1])) { // Found matching block, replace it file_lines.erase(file_lines.begin() + i, file_lines.begin() + j + 1); - - // Split segment into lines and insert them - std::vector segment_lines; - std::istringstream segment_stream(segment); - while (std::getline(segment_stream, line)) { - segment_lines.push_back(line); - } file_lines.insert(file_lines.begin() + i, segment_lines.begin(), segment_lines.end()); found_match = true; @@ -608,16 +625,13 @@ bool file_replace_or_add_segment(std::string filepath, std::string segment) // If no match found, append the segment if (!found_match) { - std::istringstream segment_stream(segment); - while (std::getline(segment_stream, line)) { - file_lines.push_back(line); - } + file_lines.insert(file_lines.end(), segment_lines.begin(), segment_lines.end()); } // Write back to file std::ofstream output_file(filepath); if (!output_file.is_open()) { - std::cerr << "Error: Unable to open file for writing: " << filepath << std::endl; + error << "Unable to open file for writing: " << filepath << std::endl; return false; } @@ -626,6 +640,13 @@ bool file_replace_or_add_segment(std::string filepath, std::string segment) } output_file.close(); + // If everything succeeded, remove the backup + try { + std::filesystem::remove(backup_path); + } catch (const std::exception& e) { + warning << "Could not remove backup file: " << e.what() << std::endl; + } + return true; }