Your Name 97776b4642
Some checks failed
Dropshell Test / Build_and_Test (push) Has been cancelled
dropshell release 2025.0513.2220
2025-05-13 22:20:16 +12:00

180 lines
6.4 KiB
C++

#include "command_registry.hpp"
#include "config.hpp"
#include "utils/utils.hpp"
#include "utils/directories.hpp"
#include "shared_commands.hpp"
#include <unistd.h>
#include <cstring>
#include <iostream>
#include <sstream>
#include <filesystem>
#include "utils/assert.hpp"
namespace dropshell {
int edit_handler(const CommandContext& ctx);
static std::vector<std::string> edit_name_list={"edit"};
// Static registration
struct EditCommandRegister {
EditCommandRegister() {
CommandRegistry::instance().register_command({
edit_name_list,
edit_handler,
std_autocomplete,
false, // hidden
false, // requires_config
false, // requires_install
0, // min_args (after command)
2, // max_args (after command)
"edit [SERVER] [SERVICE]",
"Edit dropshell, server or service configuration",
// heredoc
R"(
Edit dropshell, server or service configuration.
edit edit the dropshell config.
edit <server> edit the server config.
edit <server> <service> edit the service config.
)"
});
}
} edit_command_register;
// ------------------------------------------------------------------------------------------------
// edit command implementation
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
// utility function to edit a file
// ------------------------------------------------------------------------------------------------
bool edit_file(const std::string &file_path, bool has_bb64)
{
// make sure parent directory exists.
std::string parent_dir = get_parent(file_path);
std::filesystem::create_directories(parent_dir);
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;
if (has_bb64) {
return execute_local_command(editor_cmd, nullptr, cMode::Interactive);
}
else {
// might not have bb64 at this early stage. Direct edit.
int ret = system(editor_cmd.c_str());
return EXITSTATUSCHECK(ret);
}
}
// ------------------------------------------------------------------------------------------------
// edit config
// ------------------------------------------------------------------------------------------------
int edit_config()
{
if (!gConfig().is_config_set())
gConfig().save_config(false); // save defaults.
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.");
gConfig().load_config();
if (!gConfig().is_config_set())
return die("Error: Failed to load and parse edited config file!");
gConfig().save_config(true);
std::cout << "Successfully edited config file at " << config_file << std::endl;
return 0;
}
// ------------------------------------------------------------------------------------------------
// edit server
// ------------------------------------------------------------------------------------------------
int edit_server(const std::string &server_name)
{
std::string serverpath = localpath::server(server_name);
if (serverpath.empty()) {
std::cerr << "Error: Server not found: " << server_name << std::endl;
return -1;
}
std::ostringstream aftertext;
aftertext << "If you have changed DROPSHELL_DIR, you should manually move the files to the new location NOW.\n"
<< "You can ssh in to the remote server with: dropshell ssh "<<server_name<<"\n"
<< "Once moved, reinstall all services with: dropshell install " << server_name;
std::string config_file = serverpath + "/server.env";
if (!edit_file(config_file, true)) {
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;
return 0;
}
// ------------------------------------------------------------------------------------------------
// edit service config
// ------------------------------------------------------------------------------------------------
int edit_service_config(const std::string &server, const std::string &service)
{
std::string config_file = localfile::service_env(server, service);
if (!std::filesystem::exists(config_file))
{
std::cerr << "Error: Service config file not found: " << config_file << std::endl;
return 1;
}
if (edit_file(config_file, true) && std::filesystem::exists(config_file))
std::cout << "To apply your changes, run:\n dropshell install " + server + " " + service << std::endl;
return 0;
}
// ------------------------------------------------------------------------------------------------
// edit command handler
// ------------------------------------------------------------------------------------------------
int edit_handler(const CommandContext& ctx) {
// edit dropshell config
if (ctx.args.size() < 1)
return edit_config();
// edit server config
if (ctx.args.size() < 2) {
edit_server(safearg(ctx.args,0));
return 0;
}
// edit service config
if (ctx.args.size() < 3) {
edit_service_config(safearg(ctx.args,0), safearg(ctx.args,1));
return 0;
}
std::cout << "Edit handler called with " << ctx.args.size() << " args\n";
return -1;
}
} // namespace dropshell