diff --git a/src/config.cpp b/src/config.cpp index a2b3e2a..30e8def 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -43,7 +43,7 @@ bool config::load_config() { // load json config file. return true; } -bool config::save_config() +bool config::save_config(bool create_aux_directories) { std::string config_path = localfile::dropshell_json(); if (config_path.empty()) @@ -77,13 +77,25 @@ bool config::save_config() config_file << mConfig.dump(4); config_file.close(); - return true; - std::filesystem::create_directories(get_local_template_cache_path()); - std::filesystem::create_directories(get_local_backup_path()); - std::filesystem::create_directories(get_local_tempfiles_path()); - for (auto & p : get_local_server_definition_paths()) - std::filesystem::create_directories(p); + if (create_aux_directories) { + std::vector paths = { + get_local_template_cache_path(), + get_local_backup_path(), + get_local_tempfiles_path() + }; + for (auto & p : get_local_server_definition_paths()) + paths.push_back(p); + + for (auto & p : paths) + if (!std::filesystem::exists(p)) + { + std::cout << "Creating directory: " << p << std::endl; + std::filesystem::create_directories(p); + } + } + + return true; } diff --git a/src/config.hpp b/src/config.hpp index 5eb5830..aa70fe1 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -12,7 +12,7 @@ class config { ~config(); bool load_config(); - bool save_config(); + bool save_config(bool create_aux_directories); bool is_config_set() const; diff --git a/src/main.cpp b/src/main.cpp index 21bb619..13fdc81 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -134,6 +134,9 @@ int main(int argc, char* argv[]) { } if (cmd == "edit" && argc < 3) { + if (!gConfig().is_config_set()) + gConfig().save_config(false); + std::string config_file = localfile::dropshell_json(); if (!edit_file(config_file) || !std::filesystem::exists(config_file)) return die("Error: Failed to edit config file."); @@ -142,9 +145,8 @@ int main(int argc, char* argv[]) { if (!gConfig().is_config_set()) return die("Error: Failed to load and parse edited config file."); - gConfig().save_config(); - gConfig().load_config(); - std::cout << "Successfully edited config file." << std::endl; + gConfig().save_config(true); + std::cout << "Successfully edited config file at " << config_file << std::endl; return 0; } diff --git a/src/server_env_manager.cpp b/src/server_env_manager.cpp index 2fd0adb..13056c8 100644 --- a/src/server_env_manager.cpp +++ b/src/server_env_manager.cpp @@ -11,6 +11,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include // For potential shell-like expansion if needed namespace dropshell { @@ -24,7 +30,7 @@ server_env_manager::server_env_manager(const std::string& server_name) : mValid( // Check if file exists if (!std::filesystem::exists(server_env_path)) { - std::cerr << "Server environment file not found: " + server_env_path << std::endl; + std::cerr << "Server environment file not found: " + server_env_path << " for server " << server_name << std::endl; return; } @@ -179,6 +185,43 @@ bool server_env_manager::execute_local_command(const sCommand& command) { return false; } +bool server_env_manager::execute_local_command_interactive(const sCommand &command) +{ + std::string full_command = command.construct_rawcmd(); // Get the command string + + pid_t pid = fork(); + + if (pid == -1) { + // Fork failed + perror("fork failed"); + return false; + } else if (pid == 0) { + // Child process + std::vector commandvec = {"bash", "-c", full_command.c_str(),NULL}; + + std::cout << "Executing command: "; + for (auto & x : commandvec) std::cout << x << " "; + std::cout << std::endl; + + execvp(commandvec[0], const_cast(commandvec.data())); + // If execvp returns, it means an error occurred + perror("execvp failed"); + exit(EXIT_FAILURE); // Exit child process on error + + } else { + // Parent process + int status; + // Wait for the child process to complete + waitpid(pid, &status, 0); + + if (WIFEXITED(status)) { + return (WEXITSTATUS(status) == 0); + } + return false; // Child terminated abnormally + } + +} + bool server_env_manager::execute_local_command_and_capture_output(const sCommand& command, std::string &output) { std::string full_cmd = command.construct_safecmd() + " 2>&1"; @@ -219,7 +262,9 @@ std::string sCommand::construct_safecmd() const std::string sCommand::construct_rawcmd() const { - std::string rawcmd = "cd " + quote(mDir) + " && "; + std::string rawcmd; + if (!mDir.empty()) + rawcmd = "cd " + quote(mDir) + " && "; for (const auto& env_var : mVars) { rawcmd += env_var.first + "=" + quote(dequote(trim(env_var.second))) + " "; diff --git a/src/server_env_manager.hpp b/src/server_env_manager.hpp index 1ca65cc..8e1ac20 100644 --- a/src/server_env_manager.hpp +++ b/src/server_env_manager.hpp @@ -79,6 +79,7 @@ class server_env_manager { bool execute_ssh_command_and_capture_output(const sCommand& command, std::string & output, bool allocateTTY=false) const; static bool execute_local_command(const sCommand& command); + static bool execute_local_command_interactive(const sCommand& command); static bool execute_local_command_and_capture_output(const sCommand& command, std::string & output); private: diff --git a/src/service_runner.cpp b/src/service_runner.cpp index 303af35..777211e 100644 --- a/src/service_runner.cpp +++ b/src/service_runner.cpp @@ -423,10 +423,13 @@ void edit_server(const std::string &server_name) << "Once moved, reinstall all services with: dropshell install " << server_name; std::string config_file = serverpath + "/server.env"; - if (!edit_file(config_file)) + if (!edit_file(config_file)) { std::cerr << "Error: Failed to edit server.env" << std::endl; + std::cerr << "You can manually edit this file at: " << config_file << std::endl; + std::cerr << "After editing, " << aftertext.str() << std::endl; + } else - std::cout << aftertext.str() << std::endl; + std::cout << aftertext.str() << std::endl; } bool edit_file(const std::string &file_path) @@ -435,8 +438,23 @@ bool edit_file(const std::string &file_path) std::string parent_dir = get_parent(file_path); std::filesystem::create_directories(parent_dir); - std::string cmd = "nano -w " + file_path; - return server_env_manager::execute_local_command(cmd); + std::string editor_cmd; + const char* editor_env = std::getenv("EDITOR"); + + if (editor_env && std::strlen(editor_env) > 0) { + editor_cmd = std::string(editor_env) + " " + quote(file_path); + } else if (isatty(STDIN_FILENO)) { + // Check if stdin is connected to a terminal if EDITOR is not set + editor_cmd = "nano -w " + quote(file_path); + } else { + std::cerr << "Error: Standard input is not a terminal and EDITOR environment variable is not set." << std::endl; + std::cerr << "Try setting the EDITOR environment variable (e.g., export EDITOR=nano) or run in an interactive terminal." << std::endl; + std::cerr << "You can manually edit the file at: " << file_path << std::endl; + return false; + } + + std::cout << "Editing file: " << file_path << std::endl; + return server_env_manager::execute_local_command_interactive(editor_cmd); } void service_runner::interactive_ssh_service() diff --git a/src/utils/directories.cpp b/src/utils/directories.cpp index 56e2187..68d073b 100644 --- a/src/utils/directories.cpp +++ b/src/utils/directories.cpp @@ -46,9 +46,9 @@ namespace localfile { namespace localpath { std::string server(const std::string &server_name) { if (server_name.empty()) return ""; - for (auto &dir : gConfig().get_local_server_definition_paths()) - if (fs::exists(dir + server_name)) - return dir + server_name; + for (std::filesystem::path dir : gConfig().get_local_server_definition_paths()) + if (fs::exists(dir / server_name)) + return dir / server_name; return ""; }